在kubernetes裡使用seccomp限制容器的系統呼叫

人生的哲理發表於2024-05-30

目錄
  • 一.系統環境
  • 二.前言
  • 三.系統呼叫簡介
  • 四.使用seccomp限制docker容器系統呼叫
  • 五.在kubernetes裡使用seccomp限制容器的系統呼叫
    • 5.1 配置seccomp允許pod進行所有系統呼叫
    • 5.2 配置seccomp禁止pod進行所有系統呼叫
    • 5.3 配置seccomp允許pod進行50個系統呼叫
  • 六.總結

一.系統環境

本文主要基於Kubernetes1.22.2和Linux作業系統Ubuntu 18.04。

伺服器版本 docker軟體版本 Kubernetes(k8s)叢集版本 CPU架構
Ubuntu 18.04.5 LTS Docker version 20.10.14 v1.22.2 x86_64

Kubernetes叢集架構:k8scludes1作為master節點,k8scludes2,k8scludes3作為worker節點。

伺服器 作業系統版本 CPU架構 程序 功能描述
k8scludes1/192.168.110.128 Ubuntu 18.04.5 LTS x86_64 docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico k8s master節點
k8scludes2/192.168.110.129 Ubuntu 18.04.5 LTS x86_64 docker,kubelet,kube-proxy,calico k8s worker節點
k8scludes3/192.168.110.130 Ubuntu 18.04.5 LTS x86_64 docker,kubelet,kube-proxy,calico k8s worker節點

二.前言

隨著容器化技術的普及,應用程式的部署和執行變得越來越便捷。然而,容器的安全性也成為了一個日益重要的問題。在Kubernetes中,Seccomp(Secure Computing Mode)提供了一種強大的機制來限制容器可以執行的系統呼叫,從而提高系統的安全性。

使用seccomp限制容器的系統呼叫的前提是已經有一套可以正常執行的Kubernetes叢集,關於Kubernetes(k8s)叢集的安裝部署,可以檢視部落格《Ubuntu 安裝部署Kubernetes(k8s)叢集》https://www.cnblogs.com/renshengdezheli/p/17632858.html。

三.系統呼叫簡介

系統呼叫是應用程式請求作業系統提供服務的一種方式。攻擊者可能會利用應用程式的系統呼叫許可權執行惡意操作,例如建立新的程序、訪問敏感檔案等。透過限制容器可以使用的系統呼叫,我們可以降低攻擊者的利用面,提高系統的安全性。

Seccomp 代表安全計算(Secure Computing)模式,自 2.6.12 版本以來,一直是 Linux 核心的一個特性。 它可以用來沙箱化程序的許可權,限制程序從使用者態到核心態的呼叫。 Kubernetes 能使你自動將載入到節點上的 seccomp 配置檔案應用到你的 Pod 和容器。

四.使用seccomp限制docker容器系統呼叫

建立目錄存放檔案。

root@k8scludes1:~# mkdir systemsafe   

root@k8scludes1:~# cd systemsafe/

當我們執行一個命令的時候,會存在各種系統呼叫syscall,strace 跟蹤程式執行時的系統呼叫和所接收的訊號,strace是追蹤工具,執行strace -fqc cat /etc/hosts 可以檢視執行cat /etc/hosts 的時候執行了哪些系統呼叫。

root@k8scludes1:~/systemsafe# strace -fqc cat /etc/hosts
127.0.0.1	localhost
127.0.1.1	tom
192.168.110.128 k8scludes1
192.168.110.129 k8scludes2
192.168.110.130 k8scludes3

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 34.67    0.000095          14         7           mmap
 14.23    0.000039          10         4           mprotect
 13.14    0.000036           9         4           openat
 10.22    0.000028          14         2           munmap
  6.57    0.000018           6         3           read
  5.11    0.000014          14         1           write
  4.74    0.000013           2         6           close
  4.38    0.000012           2         5           fstat
  3.65    0.000010           3         3         3 access
  2.19    0.000006           2         3           brk
  0.73    0.000002           2         1           fadvise64
  0.36    0.000001           1         1           arch_prctl
  0.00    0.000000           0         1           execve
------ ----------- ----------- --------- --------- ----------------
100.00    0.000274                    41         3 total

檢視執行ping www.baidu.com的時候執行了哪些系統呼叫。

root@k8scludes1:~/systemsafe# strace -fqc ping www.baidu.com
PING www.a.shifen.com (14.215.177.38) 56(84) bytes of data.
64 bytes from 14.215.177.38 (14.215.177.38): icmp_seq=6 ttl=128 time=53.4 ms
64 bytes from 14.215.177.38 (14.215.177.38): icmp_seq=7 ttl=128 time=31.8 ms
^C% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 11.70    0.001336         167         8           write
  8.91    0.001018          54        19           read
  8.54    0.000976         108         9           sendto
  7.52    0.000859          86        10           recvmsg
  7.41    0.000847          61        14         1 poll
 ......
  0.27    0.000031          31         1           uname
  0.27    0.000031          31         1           geteuid
  0.25    0.000028          28         1           rt_sigprocmask
  0.04    0.000005           5         1           arch_prctl
  0.04    0.000004           4         1           setuid
  0.00    0.000000           0         1           execve
------ ----------- ----------- --------- --------- ----------------
100.00    0.011423                   242        14 total
--- www.a.shifen.com ping statistics ---
7 packets transmitted, 7 received, 0% packet loss, time 6009ms
rtt min/avg/max/mdev = 31.827/296.919/767.191/313.549 ms

我們可以禁用某個系統呼叫,比如把read系統呼叫給禁了,則和read相關的操作都沒法執行。

宿主機的作業系統並沒有限制系統呼叫, 如果能執行所有的系統呼叫,則容器裡可以執行所有的操作。

設定容器可以使用哪些系統呼叫,哪些不能用,可以使用profile檔案控制,預設的profile禁用了44個系統呼叫(總共300多個系統呼叫),預設的profile可以去https://github.com/moby/moby/blob/master/profiles/seccomp/default.json 檢視。

注意:建立seccomp profile配置檔案很麻煩,並且很大程度上是基於反覆試驗,反覆測試你需要禁止的系統呼叫和允許的系統呼叫。

下載預設的profile檔案。

root@k8scludes1:~/systemsafe# wget https://raw.githubusercontent.com/moby/moby/master/profiles/seccomp/default.json

#上面那個網址下載不了的話,使用如下網址
root@k8scludes1:~/systemsafe# wget https://github.com/moby/moby/blob/master/profiles/seccomp/default.json

下載nginx映象。

root@k8scludes1:~/systemsafe# docker pull nginx

root@k8scludes1:~/systemsafe# docker images | grep nginx
nginx                                                             latest    605c77e624dd   4 months ago    141MB

使用docker建立一個nginx容器,關於docker容器的詳細操作,請檢視部落格《一文搞懂docker容器基礎:docker映象管理,docker容器管理》。

root@k8scludes1:~/systemsafe# docker run -dit --name=nginxweb --restart=always nginx
b92aeecb455216a42fdaf9be475ae2fdef197b8d7bfde31407d7acc5d3dd96c4

建立docker 容器的時候沒有指定使用哪個seccomp profile,則預設使用預設的seccomp profile。

root@k8scludes1:~/systemsafe# docker ps | grep nginxweb
b92aeecb4552   nginx                                               "/docker-entrypoint.…"   15 seconds ago   Up 14 seconds   80/tcp    nginxweb

刪除docker容器。

root@k8scludes1:~/systemsafe# docker rm -f nginxweb
nginxweb

預設的profile可以去https://raw.githubusercontent.com/moby/moby/master/profiles/seccomp/default.json 或者https://github.com/moby/moby/blob/master/profiles/seccomp/default.json檢視。

--security-opt seccomp可以指定docker容器使用哪個seccomp profile檔案,nginxweb容器使用剛才下載的default.json作為seccomp profile檔案。

root@k8scludes1:~/systemsafe# docker run -dit --name=nginxweb --restart=always --security-opt seccomp=./default.json nginx
29e9718746acffaa2ce0d435f4f8951773d3df6d18c3bc04035479f1b9a4ef37

nginx容器正常執行,因為都是允許了預設的系統呼叫(其中44個syscall是不被允許的)。

root@k8scludes1:~/systemsafe# docker ps | grep nginxweb
29e9718746ac   nginx                                               "/docker-entrypoint.…"   13 seconds ago   Up 11 seconds   80/tcp    nginxweb

刪除docker容器。

root@k8scludes1:~/systemsafe# docker rm -f nginxweb
nginxweb

建立允許所有系統呼叫的seccomp配置檔案,"defaultAction": "SCMP_ACT_ALLOW" 允許所有的系統呼叫。

系統呼叫的Action有如下:

  • SCMP_ACT_KILL:當一個程序進行相應的系統呼叫時,核心傳送一個SIGSYS訊號終止該程序,程序不會收到這個訊號
  • SCMP_ACT_TRAP:當一個程序進行相應的系統呼叫時,該程序會收到SIGSYS訊號並改變其行為
  • SCMP_ACT_ERRNO:當程序進行相應的系統呼叫時,系統呼叫失敗,程序會收到errno的返回值
  • SCMP_ACT_TRACE:當一個程序進行相應的系統呼叫時,該程序將被跟蹤
  • SCMP_ACT_ALLOW:允許程序執行相應的系統呼叫行為
  • SCMP_ACT_LOG:記錄所有資訊
root@k8scludes1:~/systemsafe# cat allowall.json 
{
        "defaultAction": "SCMP_ACT_ALLOW"
}

建立禁止所有系統呼叫的seccomp配置檔案,"defaultAction": "SCMP_ACT_ERRNO" 禁止所有系統呼叫。

root@k8scludes1:~/systemsafe# vim denyall.json 

root@k8scludes1:~/systemsafe# cat denyall.json 
{
        "defaultAction": "SCMP_ACT_ERRNO"
}

建立允許所有系統呼叫的容器nginxweballow,現在nginxweballow這個容器可以使用所有的系統呼叫,許可權過高,有安全隱患。

注意 --security-opt seccomp=./allowall.json 等價於 --security-opt seccomp:unconfined 。

root@k8scludes1:~/systemsafe# docker run -dit --name=nginxweballow --restart=always --security-opt seccomp=./allowall.json nginx
1f12060e25a9724c755106b731bf727c4ee0b01a83b9c5c9e179e12198eac954

root@k8scludes1:~/systemsafe# docker ps | grep nginxweballow
1f12060e25a9   nginx                                               "/docker-entrypoint.…"   12 seconds ago   Up 11 seconds   80/tcp    nginxweballow

刪除nginxweballow。

root@k8scludes1:~/systemsafe# docker rm -f nginxweballow
nginxweballow

建立禁止所有系統呼叫的容器nginxwebdeny,任何的系統呼叫都不被允許,容器nginxwebdeny 建立失敗。

root@k8scludes1:~/systemsafe# docker run -dit --name=nginxwebdeny --restart=always --security-opt seccomp=./denyall.json nginx
9154203049da171f3c5d7ae93a1b9be486ca0783b6ea9373dcb8544df1d84ff6
docker: Error response from daemon: cannot start a stopped process: unknown.

檢視nginx映象的歷史資訊,可以發現,nginx容器需要執行"nginx" "-g" "daemon“守護程序,任何的系統呼叫都被禁止,nginx程序也啟動不了,所以建立容器失敗。

root@k8scludes1:~/systemsafe# docker history nginx
IMAGE          CREATED        CREATED BY                                      SIZE      COMMENT
605c77e624dd   4 months ago   /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B        
<missing>      4 months ago   /bin/sh -c #(nop)  STOPSIGNAL SIGQUIT           0B        
<missing>      4 months ago   /bin/sh -c #(nop)  EXPOSE 80                    0B        
<missing>      4 months ago   /bin/sh -c #(nop)  ENTRYPOINT ["/docker-entr…   0B        
<missing>      4 months ago   /bin/sh -c #(nop) COPY file:09a214a3e07c919a…   4.61kB    
<missing>      4 months ago   /bin/sh -c #(nop) COPY file:0fd5fca330dcd6a7…   1.04kB    
<missing>      4 months ago   /bin/sh -c #(nop) COPY file:0b866ff3fc1ef5b0…   1.96kB    
<missing>      4 months ago   /bin/sh -c #(nop) COPY file:65504f71f5855ca0…   1.2kB     
<missing>      4 months ago   /bin/sh -c set -x     && addgroup --system -…   61.1MB    
<missing>      4 months ago   /bin/sh -c #(nop)  ENV PKG_RELEASE=1~bullseye   0B        
<missing>      4 months ago   /bin/sh -c #(nop)  ENV NJS_VERSION=0.7.1        0B        
<missing>      4 months ago   /bin/sh -c #(nop)  ENV NGINX_VERSION=1.21.5     0B        
<missing>      4 months ago   /bin/sh -c #(nop)  LABEL maintainer=NGINX Do…   0B        
<missing>      4 months ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B        
<missing>      4 months ago   /bin/sh -c #(nop) ADD file:09675d11695f65c55…   80.4MB  

五.在kubernetes裡使用seccomp限制容器的系統呼叫

5.1 配置seccomp允許pod進行所有系統呼叫

在kubernetes叢集裡,seccomp的配置檔案預設放在/var/lib/kubelet/seccomp/目錄下。

root@k8scludes1:~/systemsafe# mkdir -p /var/lib/kubelet/seccomp/profiles

root@k8scludes1:~/systemsafe# cd /var/lib/kubelet/seccomp/profiles

建立允許所有系統呼叫的seccomp配置檔案。

root@k8scludes1:/var/lib/kubelet/seccomp/profiles# vim allowall_syscall 

root@k8scludes1:/var/lib/kubelet/seccomp/profiles# cat allowall_syscall 
{
        "defaultAction": "SCMP_ACT_ALLOW"
}

建立禁止所有系統呼叫的seccomp配置檔案。

root@k8scludes1:/var/lib/kubelet/seccomp/profiles# vim denyall_syscall 

root@k8scludes1:/var/lib/kubelet/seccomp/profiles# cat denyall_syscall 
{
        "defaultAction": "SCMP_ACT_ERRNO"
}

系統呼叫的Action有如下:

  • SCMP_ACT_KILL:當一個程序進行相應的系統呼叫時,核心傳送一個SIGSYS訊號終止該程序,程序不會收到這個訊號
  • SCMP_ACT_TRAP:當一個程序進行相應的系統呼叫時,該程序會收到SIGSYS訊號並改變其行為
  • SCMP_ACT_ERRNO:當程序進行相應的系統呼叫時,系統呼叫失敗,程序會收到errno的返回值
  • SCMP_ACT_TRACE:當一個程序進行相應的系統呼叫時,該程序將被跟蹤
  • SCMP_ACT_ALLOW:允許程序執行相應的系統呼叫行為
  • SCMP_ACT_LOG:記錄所有資訊

建立允許50個系統呼叫的seccomp配置檔案,"defaultAction": "SCMP_ACT_ERRNO"表示預設的規則是禁止,syscalls裡面的系統呼叫才是允許的。

root@k8scludes1:/var/lib/kubelet/seccomp/profiles# vim fine-grained_syscall

root@k8scludes1:/var/lib/kubelet/seccomp/profiles# cat fine-grained_syscall
{
    "defaultAction": "SCMP_ACT_ERRNO",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "accept4",
                "epoll_wait",
                "pselect6",
                "futex",
                "madvise",
                "epoll_ctl",
                "getsockname",
                "setsockopt",
                "vfork",
                "mmap",
                "read",
                "write",
                "close",
                "arch_prctl",
                "sched_getaffinity",
                "munmap",
                "brk",
                "rt_sigaction",
                "rt_sigprocmask",
                "sigaltstack",
                "gettid",
                "clone",
                "bind",
                "socket",
                "openat",
                "readlinkat",
                "exit_group",
                "epoll_create1",
                "listen",
                "rt_sigreturn",
                "sched_yield",
                "clock_gettime",
                "connect",
                "dup2",
                "epoll_pwait",
                "execve",
                "exit",
                "fcntl",
                "getpid",
                "getuid",
                "ioctl",
                "mprotect",
                "nanosleep",
                "open",
                "poll",
                "recvfrom",
                "sendto",
                "set_tid_address",
                "setitimer",
                "writev"
            ],
            "action": "SCMP_ACT_ALLOW"
        }
    ]
}

現在有三個不同的seccomp配置檔案。

root@k8scludes1:/var/lib/kubelet/seccomp/profiles# ls
allowall_syscall  denyall_syscall  fine-grained_syscall

檢視node節點的標籤。

root@k8scludes1:/var/lib/kubelet/seccomp/profiles# kubectl get nodes --show-labels
NAME         STATUS   ROLES                  AGE   VERSION   LABELS
k8scludes1   Ready    control-plane,master   30d   v1.22.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8scludes1,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
k8scludes2   Ready    <none>                 30d   v1.22.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8scludes2,kubernetes.io/os=linux
k8scludes3   Ready    <none>                 30d   v1.22.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8scludes3,kubernetes.io/os=linux

給k8scludes3節點設定一個標籤yy=xx。

root@k8scludes1:/var/lib/kubelet/seccomp/profiles# kubectl label nodes k8scludes3 yy=xx  

檢視標籤為yy=xx的節點,此次建立pod要執行在k8scludes3節點上。

root@k8scludes1:/var/lib/kubelet/seccomp/profiles# kubectl get node -l yy=xx
NAME         STATUS   ROLES    AGE   VERSION
k8scludes3   Ready    <none>   30d   v1.22.2

在k8scludes3節點上拉取映象hashicorp/http-echo:0.2.3。

root@k8scludes3:~# docker pull hashicorp/http-echo:0.2.3
0.2.3: Pulling from hashicorp/http-echo
86399148984b: Pull complete 
Digest: sha256:ba27d460cd1f22a1a4331bdf74f4fccbc025552357e8a3249c40ae216275de96
Status: Downloaded newer image for hashicorp/http-echo:0.2.3
docker.io/hashicorp/http-echo:0.2.3

編輯pod配置檔案,在k8scludes3節點上建立pod。

localhostProfile: profiles/allowall_syscall 指定pod使用allowall_syscall這個seccomp配置檔案。

使用的映象為hashicorp/http-echo:0.2.3,需要提前在k8scludes3節點上拉取該映象。

如果allowall_syscall檔案在/var/lib/kubelet/seccomp/profiles目錄下,則寫為profiles/allowall_syscall,如果allowall_syscall檔案在/var/lib/kubelet/seccomp/目錄下,則寫為allowall_syscall。

root@k8scludes1:/var/lib/kubelet/seccomp/profiles# cd ~/systemsafe/

root@k8scludes1:~/systemsafe# vim pod2.yaml 

root@k8scludes1:~/systemsafe# cat pod2.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: audit-pod
  labels:
    app: audit-pod
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: profiles/allowall_syscall
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  #nodeSelector:yy: xx 表示pod執行在標籤為yy=xx的節點上
  nodeSelector:
    yy: xx
  containers:
  - name: test-container
    image: hashicorp/http-echo:0.2.3
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent
    args:
    - "-text=just made some syscalls!"
    securityContext:
      allowPrivilegeEscalation: false

建立pod。

root@k8scludes1:~/systemsafe# kubectl apply -f pod2.yaml 
pod/audit-pod created

pod建立失敗。

root@k8scludes1:~/systemsafe# kubectl get pod -o wide
NAME      READY   STATUS                 RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
audit-pod   0/1     CreateContainerError   0          10s   10.244.218.138   k8scludes2   <none>           <none>

檢視日誌。

root@k8scludes1:~/systemsafe# kubectl logs audit-pod 
Error from server (BadRequest): container "test-container" in pod "audit-pod" is waiting to start: CreateContainerError

檢視pod的描述資訊,最後一行表名找不到/var/lib/kubelet/seccomp/allowall_syscall檔案,看來需要把seccomp配置檔案放到k8scludes3節點的/var/lib/kubelet/seccomp/目錄下。

root@k8scludes1:~/systemsafe# kubectl describe pod audit-pod
Name:         podtest
Namespace:    systemsafe
Priority:     0
Node:         k8scludes2/192.168.110.129
......
Events:
  Type     Reason          Age                From               Message
  ----     ------          ----               ----               -------
  Normal   Scheduled       83s                default-scheduler  Successfully assigned systemsafe/podtest to k8scludes2
  Normal   SandboxChanged  80s                kubelet            Pod sandbox changed, it will be killed and re-created.
  Normal   Pulled          0s (x10 over 81s)  kubelet            Container image "hashicorp/http-echo:0.2.3" already present on machine
  Warning  Failed          0s (x10 over 81s)  kubelet            Error: failed to generate security options for container "test-container": failed to generate seccomp security options for container: cannot load seccomp profile "/var/lib/kubelet/seccomp/allowall_syscall": open /var/lib/kubelet/seccomp/allowall_syscall: no such file or directory

刪除pod。

root@k8scludes1:~/systemsafe# kubectl delete pod  audit-pod
pod "audit-pod" deleted

root@k8scludes1:~/systemsafe# kubectl get pod 
No resources found in systemsafe namespace.

在k8scludes3節點建立seccomp配置檔案目錄/var/lib/kubelet/seccomp/profiles。

root@k8scludes3:~# mkdir -p /var/lib/kubelet/seccomp/profiles

root@k8scludes3:~# cd /var/lib/kubelet/seccomp/profiles

root@k8scludes3:/var/lib/kubelet/seccomp/profiles# pwd
/var/lib/kubelet/seccomp/profiles

還是建立這三個檔案。

root@k8scludes3:/var/lib/kubelet/seccomp/profiles# ls
allowall_syscall  denyall_syscall  fine-grained_syscall

再次建立audit-pod。

root@k8scludes1:~/systemsafe# kubectl apply -f pod2.yaml
pod/audit-pod created

這次pod建立成功。

root@k8scludes1:~/systemsafe# kubectl get pod -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
audit-pod   1/1     Running   0          14s   10.244.1.100   k8scludes3   <none>           <none>

建立一個服務,服務型別為NodePort,服務埠為5678,關於服務service的詳細操作,請檢視部落格《Kubernetes(k8s)服務service:service的發現和service的釋出》。

root@k8scludes1:~/systemsafe# kubectl expose pod audit-pod --type NodePort --port 5678
service/audit-pod exposed

檢視服務,5678埠對映為31163埠。

root@k8scludes1:~/systemsafe# kubectl get svc -o wide
NAME        TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE   SELECTOR
audit-pod   NodePort   10.107.213.89   <none>        5678:31163/TCP   9s    app=audit-pod

訪問svc ,訪問方式為:物理機IP:埠。

#訪問成功
root@k8scludes1:~/systemsafe# curl 192.168.110.128:31163
just made some syscalls!

刪除pod。

root@k8scludes1:~/systemsafe# kubectl delete pod audit-pod 
pod "audit-pod" deleted

root@k8scludes1:~/systemsafe# kubectl get pod
No resources found in systemsafe namespace.

5.2 配置seccomp禁止pod進行所有系統呼叫

編輯pod配置檔案,在k8scludes3節點上建立pod,這次pod使用denyall_syscall檔案。

localhostProfile: profiles/denyall_syscall指定pod使用denyall_syscall這個seccomp配置檔案。

root@k8scludes1:~/systemsafe# vim pod2.yaml 

root@k8scludes1:~/systemsafe# cat pod2.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: audit-pod
  labels:
    app: audit-pod
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: profiles/denyall_syscall
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  #nodeSelector:yy: xx 表示pod執行在標籤為yy=xx的節點上
  nodeSelector:
    yy: xx
  containers:
  - name: test-container
    image: hashicorp/http-echo:0.2.3
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent
    args:
    - "-text=just made some syscalls!"
    securityContext:
      allowPrivilegeEscalation: false

建立pod。

root@k8scludes1:~/systemsafe# kubectl apply -f pod2.yaml 
pod/audit-pod created

pod建立失敗。

root@k8scludes1:~/systemsafe# kubectl get pod -o wide
NAME        READY   STATUS             RESTARTS     AGE   IP             NODE         NOMINATED NODE   READINESS GATES
audit-pod   0/1     CrashLoopBackOff   1 (5s ago)   7s    10.244.1.115   k8scludes3   <none>           <none>

檢視pod日誌,因為禁止了所有系統呼叫,連日誌都沒有,pod也執行不起來。

root@k8scludes1:~/systemsafe# kubectl logs audit-pod 

root@k8scludes1:~/systemsafe# kubectl get pod 
NAME        READY   STATUS             RESTARTS      AGE
audit-pod   0/1     CrashLoopBackOff   5 (69s ago)   3m59s

刪除pod。

root@k8scludes1:~/systemsafe# kubectl delete pod audit-pod 
pod "audit-pod" deleted

root@k8scludes1:~/systemsafe# kubectl get pod 
No resources found in systemsafe namespace.

5.3 配置seccomp允許pod進行50個系統呼叫

編輯pod配置檔案,在k8scludes3節點上建立pod,這次pod使用fine-grained_syscall檔案。

localhostProfile: profiles/fine-grained_syscall指定pod使用fine-grained_syscall這個seccomp配置檔案。

fine-grained_syscall這個配置檔案允許50個系統呼叫。

建立pod。

root@k8scludes1:~/systemsafe# vim pod2.yaml 

#這次使用fine-grained_syscall檔案
root@k8scludes1:~/systemsafe# grep localhostProfile pod2.yaml 
      localhostProfile: profiles/fine-grained_syscall

root@k8scludes1:~/systemsafe# kubectl apply -f pod2.yaml 
pod/audit-pod created

pod建立成功。

root@k8scludes1:~/systemsafe# kubectl get pod -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
audit-pod   1/1     Running   0          6s    10.244.1.107   k8scludes3   <none>           <none>

訪問svc服務。

root@k8scludes1:~/systemsafe# kubectl get svc
NAME        TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
audit-pod   NodePort   10.107.213.89   <none>        5678:31163/TCP   16m

root@k8scludes1:~/systemsafe# curl 192.168.110.128:31163
just made some syscalls!

檢視日誌。

root@k8scludes1:~/systemsafe# kubectl logs audit-pod 
2022/05/16 10:43:31 Server is listening on :5678
2022/05/16 10:44:17 192.168.110.128:31163 10.244.9.0:13880 "GET / HTTP/1.1" 200 25 "curl/7.58.0" 36.059µs

root@k8scludes1:~/systemsafe# tail -10f /var/log/syslog | grep 'http-echo'
^C

刪除pod。

root@k8scludes1:~/systemsafe# kubectl delete pod audit-pod 
pod "audit-pod" deleted

六.總結

透過使用Seccomp限制容器的系統呼叫,我們可以顯著提高容器的安全性。在這篇部落格中,我們學習瞭如何在Kubernetes環境中應用Seccomp來限制容器的系統呼叫。透過設定Seccomp配置檔案並在Docker容器和Kubernetes Pod中應用該配置,我們可以有效地限制容器的許可權,從而保護宿主機的安全。

相關文章