34.B站薪享宏福笔记——第十二章(4)安全参数

12 B站薪享宏福笔记——第十二章

                                    —— Kubernetes 中必备的工具组件

12.4 安全参数

            —— 限制对应的权限集

12.4.1 节点名字空间共享

(1)共享主机网络 hostNetwork

注意:node01、node02 端口已被 Ingress-nginx 占用,master01 没有安装 Ingress-nginx,所以可以使用 master01 进行实验

# node01、node02 都安装了 ingress-nginx ,主机 80 端口被占用
[root@k8s-master01 12.4]# kubectl get pod -o wide -n ingress
NAME                                           READY   STATUS    RESTARTS        AGE   IP              NODE         NOMINATED NODE   READINESS GATES
ingress-nginx-controller-gwr9q                 1/1     Running   21 (175m ago)   17d   192.168.66.13   k8s-node02   <none>           <none>
ingress-nginx-controller-zzzr5                 1/1     Running   20 (175m ago)   17d   192.168.66.12   k8s-node01   <none>           <none>
ingress-nginx-defaultbackend-89db9d699-cvcrn   1/1     Running   16 (175m ago)   18d   10.244.85.195   k8s-node01   <none>           <none>
jaeger-ddb59666b-dd4vj                         1/1     Running   16 (175m ago)   18d   10.244.85.234   k8s-node01   <none>           <none>
# master01 上因为有污点,所以 daemonset 控制器没有安装 ingress-nginx 到 master01
[root@k8s-master01 12.4]# ss -na|grep '0.0.0.0:80'
# node01、node02 上 80 端口被占用
[root@k8s-node01 ~]# ss -na|grep '0.0.0.0:80'
tcp   LISTEN    0      4096                                                                              0.0.0.0:80                         0.0.0.0:*            
[root@k8s-master01 12.4]# cat 1.hostnetwork.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: hostnetwork-pod
spec:
 hostNetwork: true
 nodeName: k8s-master01 
 containers:
 - name: myapp-container
   image: myapp:v1.0
   ports:
   - containerPort: 80
4.期望:主机网络模式(当前 Pod 与当前所在节点共享网络):开启、固定 Pod 所在节点的名称、容器组:容器名、基于镜像版本、端口:容器端口:80(即 Pod 使用主机网络的 80 端口)
[root@k8s-master01 12.4]# kubectl apply -f 1.hostnetwork.yaml 
pod/hostnetwork-pod created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME              READY   STATUS    RESTARTS   AGE   IP              NODE           NOMINATED NODE   READINESS GATES
hostnetwork-pod   1/1     Running   0          9s    192.168.66.11   k8s-master01   <none>           <none>
[root@k8s-master01 12.4]# ss -tnulp|grep :80
tcp   LISTEN 0      511                             0.0.0.0:80         0.0.0.0:*    users:(("nginx",pid=113109,fd=6),("nginx",pid=113098,fd=6))

使用浏览器访问:192.168.66.11、192.168.66.11/hostname.html 可以使用主机的网络进行访问

image

image

(2)启动主机端口 hostPort

注意:确定 8080 端口没有被占用,主机端口实际是主机进行了 dnet 转换,将主机端口经过路由,再转入容器端口

[root@k8s-master01 12.4]# cat 2.hostport.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: pod-with-hostport
spec:
 containers:
 - name: myapp-container
   image: myapp:v1.0
   ports:
   - containerPort: 80
     hostPort: 8080
4.期望:容器组:容器名、基于镜像版本、端口:容器端口:80、主机端口:8080(即 经过 dnet转换,将主机的 8080 端口的访问 转入 容器的 80 端口)
[root@k8s-master01 12.4]# kubectl apply -f 2.hostport.yaml 
pod/pod-with-hostport created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME                READY   STATUS    RESTARTS   AGE   IP              NODE           NOMINATED NODE   READINESS GATES
hostnetwork-pod     1/1     Running   0          17m   192.168.66.11   k8s-master01   <none>           <none>
pod-with-hostport   1/1     Running   0          5s    10.244.58.202   k8s-node02     <none>           <none>

上面查得 Pod 运行在 node02 节点上,所以使用 node02 节点的 IP 地址,通过浏览器访问:192.168.66.13:8080、192.168.66.13:8080/hostname.html 可以使用主机的端口进行访问

image

image

(3)共享主机 PID 和 IPC hostPID and hostIPC

注意:通过共享主机 PID 和 IPC ,Pod 可以和主机进行进程间通信

[root@k8s-master01 12.4]# cat 3.pid_ipc.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: hostpid-hostipc-pod
spec:
 hostPID: true
 hostIPC: true
 containers:
 - name: myapp-container
   image: myapp:v1.0
4.期望:主机PID:开启、主机IPC:开启、容器组:容器名、基于镜像版本
[root@k8s-master01 12.4]# kubectl apply -f 3.pid_ipc.yaml 
pod/hostpid-hostipc-pod created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME                  READY   STATUS    RESTARTS   AGE   IP              NODE           NOMINATED NODE   READINESS GATES
hostnetwork-pod       1/1     Running   0          37m   192.168.66.11   k8s-master01   <none>           <none>
hostpid-hostipc-pod   1/1     Running   0          6s    10.244.85.238   k8s-node01     <none>           <none>
pod-with-hostport     1/1     Running   0          20m   10.244.58.202   k8s-node02     <none>           <none>
# Pod 中 1号进程 默认应该是启动命令本身(此 Pod 是基于 nginx 封装,所以 1号进程 应该是 nginx )
# 但是此时 Pod 中 1号进程是 systemd,是 物理机 将 PID/IPC 共享到此 Pod 内部的原因
[root@k8s-master01 12.4]# kubectl exec -it hostpid-hostipc-pod -- /bin/sh
/ # ps -ef|wc -l
207
/ # ps -ef|head
PID   USER     TIME   COMMAND
    1 root       0:02 /usr/lib/systemd/systemd --switched-root --system --deserialize 31
    2 root       0:00 [kthreadd]
    3 root       0:00 [pool_workqueue_]
    4 root       0:00 [kworker/R-rcu_g]
    5 root       0:00 [kworker/R-rcu_p]
    6 root       0:00 [kworker/R-slub_]
    7 root       0:00 [kworker/R-netns]
    9 root       0:00 [kworker/0:0H-ev]
   10 root       0:00 [kworker/u512:0-]
/ # exit
# 消除实验影响
[root@k8s-master01 12.4]# kubectl delete pod --all
pod "hostnetwork-pod" deleted
pod "hostpid-hostipc-pod" deleted
pod "pod-with-hostport" deleted

12.4.2 节点安全上下文(pod 级)

(1)概念

  指定容器中运行进程的用户(用户 ID)

  阻止容器使用 root 用户运行(容器的默认运行用户通常在其镜像中指定,所以可能需要阻止容器以 root 用户运行。如果阻止了 root 用户,但容器中没有创建对应普通用户或用普通用户运行,也可能使容器或 Pod 运行失败)

  使用特权模式运行容器,使其对宿主节点的内核具有完全的访问权限(有些服务需要特权模式运行,例如:cAdvisor:猫头鹰监控,需要特权模式运行)

  与以上相反,通过添加或禁用内核功能,配置细粒度的内核访问权限(权限细分)

  设置 SELinux 选项,加强对容器的限制

  阻止进程写入容器的根文件系统(超越权限)

(2)使用特定用户运行 pod

# 当不指定使用的特定用户运行时,容器启动会使用自带的用户
[root@k8s-master01 12.4]# cat 4.pod.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: user-id-pod-1
spec:
 containers:
 - name: alpine-container
   image: alpine
   command: ["/bin/sleep", "9999"]
[root@k8s-master01 12.4]# kubectl apply -f 4.pod.yaml 
pod/user-id-pod-1 created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
user-id-pod-1   1/1     Running   0          14s   10.244.58.208   k8s-node02   <none>           <none>
# 默认使用了镜像中的 root 用户启动容器
[root@k8s-master01 12.4]# kubectl exec -it user-id-pod-1 -- /bin/sh
/ # id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
/ # exit
[root@k8s-master01 12.4]# cat 5.user.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: user-id-pod-2
spec:
 containers:
 - name: alpine-container
   image: alpine
   command: ["/bin/sleep", "9999"]
   securityContext:
     runAsUser: 405
4.期望:容器组:容器名、基于镜像版本、启动命令、安全上下文:使用用户:405(alpine 用户自带的用户,已有)
[root@k8s-master01 12.4]# kubectl apply -f 5.user.yaml 
pod/user-id-pod-2 created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
user-id-pod-1   1/1     Running   0          10m   10.244.58.208   k8s-node02   <none>           <none>
user-id-pod-2   1/1     Running   0          10s   10.244.85.242   k8s-node01   <none>           <none>
# 固定用户后,可以使用固定的用户启动命令
[root@k8s-master01 12.4]# kubectl exec -it user-id-pod-2 -- /bin/sh
/ $ id
uid=405(guest) gid=100(users) groups=100(users)
/ $ exit
# 消除实验影响
[root@k8s-master01 12.4]# kubectl delete pod --all
pod "user-id-pod-1" deleted
pod "user-id-pod-2" deleted

(3)阻止容器以 root 用户运行

注意:特殊情况下,即使容器镜像使用的是普通用户,也可能需要明确指定 runAsUser,这可能是由于容器镜像中的用户与宿主机上的 用户UID 不匹配导致的,这种情况下,即使容器中的用户是普通用户,Kubernetes 也可能会认为其是 root 用户,因为它的 UID 可能与宿主机上的 root 用户的UID 匹配。

因此,即使容器中的用户是普通用户,也建议明确指定 runAsUser,以确保容器以正确的用户身份运行

# 错误启动示范
[root@k8s-master01 12.4]# cat 6.non_root.yaml apiVersion: v1 kind: Pod metadata: name: non-root-user-pod-false spec: containers: - name: myapp-container image: myapp:v1.0 securityContext: runAsNonRoot: true [root@k8s-master01 12.4]# kubectl apply -f 6.non_root.yaml pod/non-root-user-pod-false created [root@k8s-master01 12.4]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES non-root-user-pod-false 0/1 CreateContainerConfigError 0 7s 10.244.58.212 k8s-node02 <none> <none> # 不使用镜像的 root 用户,有时可能会因为启动用户问题导致 pod 启动失败
[root@k8s
-master01 12.4]# kubectl describe pod non-root-user-pod-false .......... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 34s default-scheduler Successfully assigned default/non-root-user-pod-false to k8s-node02 Normal Pulled 5s (x5 over 33s) kubelet Container image "myapp:v1.0" already present on machine Warning Failed 5s (x5 over 33s) kubelet Error: container has runAsNonRoot and image will run as root (pod: "non-root-user-pod-false_default(24bf44c5-0e9c-466f-928c-d4de26f9ce25)", container: myapp-container)
[root@k8s-master01 12.4]# cat 7.non_root_user.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: non-root-user-pod-true
spec:
 containers:
 - name: alpine-container
   image: alpine
   command: ["/bin/sleep", "9999"]
   securityContext:
     runAsNonRoot: true
     runAsUser: 405
4.期望:容器组:容器名、基于镜像版本、启动命令、安全上下文:不使用 root 用户运行:开启、使用运行的用户:405
[root@k8s-master01 12.4]# kubectl apply -f 7.non_root_user.yaml 
pod/non-root-user-pod-true created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME                      READY   STATUS                       RESTARTS   AGE     IP              NODE         NOMINATED NODE   READINESS GATES
non-root-user-pod-false   0/1     CreateContainerConfigError   0          3m47s   10.244.58.212   k8s-node02   <none>           <none>
non-root-user-pod-true    1/1     Running                      0          5s      10.244.58.209   k8s-node02   <none>           <none>
[root@k8s-master01 12.4]# kubectl exec -it non-root-user-pod-true -- /bin/sh
/ $ id
uid=405(guest) gid=100(users) groups=100(users)
/ $ exit
# 消除实验影响
[root@k8s-master01 12.4]# kubectl delete pod --all
pod "non-root-user-pod-false" deleted
pod "non-root-user-pod-true" deleted

(4)使用特权模式运行 pod

# 非特权用户,权限受到限制
[root@k8s-master01 12.4]# cat 8.pod.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: privileged-pod-1
spec:
 containers:
 - name: privileged-container
   image: myapp:v1.0
[root@k8s-master01 12.4]# kubectl apply -f 8.pod.yaml 
pod/privileged-pod-1 created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME               READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
privileged-pod-1   1/1     Running   0          4s    10.244.58.218   k8s-node02   <none>           <none>
# /dev 下 权限受到限制,存放的是设备文件
[root@k8s-master01 12.4]# kubectl exec -it privileged-pod-1 -- /bin/sh
/ # ls /dev
core             full             null             pts              shm              stdin            termination-log  urandom
fd               mqueue           ptmx             random           stderr           stdout           tty              zero
/ # exit
[root@k8s-master01 12.4]# cat 9.privileged.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: privileged-pod-2
spec:
 containers:
 - name: privileged-container
   image: myapp:v1.0
   securityContext:
     privileged: true
4.期望:容器组:容器名、基于镜像版本、安全上下文:特权模式:开启
[root@k8s-master01 12.4]# kubectl apply -f 9.privileged.yaml 
pod/privileged-pod-2 created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME               READY   STATUS    RESTARTS   AGE    IP              NODE         NOMINATED NODE   READINESS GATES
privileged-pod-1   1/1     Running   0          5m3s   10.244.58.218   k8s-node02   <none>           <none>
privileged-pod-2   1/1     Running   0          5s     10.244.85.243   k8s-node01   <none>           <none>
# /dev 下设备文件明显变多,能使用的设备变多,比如 cpu、磁盘、port 等
[root@k8s-master01 12.4]# kubectl exec -it privileged-pod-2 -- /bin/sh
/ # ls /dev
autofs           fuse             nvram            snapshot         tty14            tty27            tty4             tty52            tty8             vcs              vcsu
bsg              hidraw0          port             snd              tty15            tty28            tty40            tty53            tty9             vcs1             vcsu1
bus              hpet             ppp              sr0              tty16            tty29            tty41            tty54            ttyS0            vcs2             vcsu2
core             hwrng            ptmx             stderr           tty17            tty3             tty42            tty55            ttyS1            vcs3             vcsu3
cpu              input            pts              stdin            tty18            tty30            tty43            tty56            ttyS2            vcs4             vcsu4
cpu_dma_latency  kmsg             random           stdout           tty19            tty31            tty44            tty57            ttyS3            vcs5             vcsu5
dm-0             loop-control     rfkill           termination-log  tty2             tty32            tty45            tty58            udmabuf          vcs6             vcsu6
dm-1             mapper           rtc0             tty              tty20            tty33            tty46            tty59            uhid             vcsa             vfio
dma_heap         mcelog           sda              tty0             tty21            tty34            tty47            tty6             uinput           vcsa1            vga_arbiter
dmmidi           mem              sda1             tty1             tty22            tty35            tty48            tty60            urandom          vcsa2            vhci
dri              midi             sda2             tty10            tty23            tty36            tty49            tty61            usbmon0          vcsa3            vhost-net
fb0              mqueue           sg0              tty11            tty24            tty37            tty5             tty62            usbmon1          vcsa4            vhost-vsock
fd               net              sg1              tty12            tty25            tty38            tty50            tty63            usbmon2          vcsa5            vmci
full             null             shm              tty13            tty26            tty39            tty51            tty7             userfaultfd      vcsa6            zero
/ # exit
# 消除实验影响
[root@k8s-master01 12.4]# kubectl delete pod --all
pod "privileged-pod-1" deleted
pod "privileged-pod-2" deleted

(5)为容器单独添加内核功能

注意:不是修改了 Pod IP地址 就可以直接在集群中使用的,因为 网络插件 calico 底层是由 ipvsadm/iptables 对原 Pod 的 IP地址进行路由,手动新修改了 IP 地址后,将会路由不到 

# 上一个实验的 Pod 是标准无特权的 Pod ,用来作对比
[root@k8s-master01 12.4]# cat 8.pod.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: privileged-pod-1
spec:
 containers:
 - name: privileged-container
   image: myapp:v1.0
[root@k8s-master01 12.4]# kubectl apply -f 8.pod.yaml 
pod/privileged-pod-1 created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME               READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
privileged-pod-1   1/1     Running   0          4s    10.244.58.222   k8s-node02   <none>           <none>
# 这里 Pod 内虽是 root 用户,但是不能修改 IP ,因为 Pod 内的 root 是被宿主机使用namespace 隔离后的 伪root 用户
[root@k8s-master01 12.4]# kubectl exec -it privileged-pod-1 -- /bin/sh
/ # id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr DE:42:4A:15:BD:C7  
          inet addr:10.244.58.222  Bcast:0.0.0.0  Mask:255.255.255.255
          inet6 addr: fe80::dc42:4aff:fe15:bdc7/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:5 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:1 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:446 (446.0 B)  TX bytes:656 (656.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # ifconfig eth0 10.244.58.222 netmask 255.255.255.255
ifconfig: SIOCSIFADDR: Operation not permitted
/ # exit
[root@k8s-master01 12.4]# cat 10.system.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: sys-time-pod
spec:
 containers:
 - name: sys-time-container
   image: myapp:v1.0
   securityContext:
     capabilities:
       add: ["NET_ADMIN"]
4.期望:容器组:容器名、基于镜像版本、安全上下文:能力:添加:网络管理员
[root@k8s-master01 12.4]# kubectl apply -f 10.system.yaml 
pod/sys-time-pod created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME               READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
privileged-pod-1   1/1     Running   0          13m   10.244.58.222   k8s-node02   <none>           <none>
sys-time-pod       1/1     Running   0          4s    10.244.58.248   k8s-node02   <none>           <none>
# 下面虽然修改了 Pod IP 地址,但是因为没有网络插件的路由,所以不能通过手动修改的 IP地址访问,这里只是用以体现拥有了添加的 网络管理员权限
[root@k8s-master01 12.4]# kubectl exec -it sys-time-pod -- /bin/sh
/ # id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr F2:E4:D5:94:E1:EE  
          inet addr:10.244.58.248  Bcast:0.0.0.0  Mask:255.255.255.255
          inet6 addr: fe80::f0e4:d5ff:fe94:e1ee/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:5 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:1 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:446 (446.0 B)  TX bytes:656 (656.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # ifconfig eth0 10.244.58.201 netmask 255.255.255.255
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr F2:E4:D5:94:E1:EE  
          inet addr:10.244.58.201  Bcast:10.255.255.255  Mask:255.255.255.255
          inet6 addr: fe80::f0e4:d5ff:fe94:e1ee/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:5 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9 errors:0 dropped:1 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:446 (446.0 B)  TX bytes:726 (726.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ #  exit
# 两个 IP 都访问不通,原 IP 被修改,calico 的路由规则入站时,流量被拒绝,而手动修改的 IP,没有 calico 添加的路由策略,没办法入站
[root@k8s-master01 12.4]# curl 10.244.58.248   # 原 Pod IP
^C
[root@k8s-master01 12.4]# curl 10.244.58.201   # 现 Pod IP
^C
# capabilities 能力 能够添加的权限,使用 capsh 命令(需安装 libcap 工具包):
[root@k8s-master01 12.4]# capsh --print
Current: =ep
Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read,cap_perfmon,cap_bpf,cap_checkpoint_restore
Ambient set =
Current IAB: 
Securebits: 00/0x0/1'b0 (no-new-privs=0)
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
 secure-no-ambient-raise: no (unlocked)
uid=0(root) euid=0(root)
gid=0(root)
groups=0(root)
Guessed mode: UNCERTAIN (0)
# 消除实验影响
[root@k8s-master01 12.4]# kubectl delete pod --all
pod "privileged-pod-1" deleted
pod "sys-time-pod" deleted

(6)在容器中禁用内核功能

# 第 4 个实验的 Pod 是标准无特权的 Pod ,用来作对比
[root@k8s-master01 12.4]# cat 8.pod.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: privileged-pod-1
spec:
 containers:
 - name: privileged-container
   image: myapp:v1.0
[root@k8s-master01 12.4]# kubectl apply -f 8.pod.yaml 
pod/privileged-pod-1 created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME               READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
privileged-pod-1   1/1     Running   0          5s    10.244.58.226   k8s-node02   <none>           <none>
# 创建文件,可以修改文件的用户和用户组
[root@k8s-master01 12.4]# kubectl exec -it privileged-pod-1 -- /bin/sh
/ # cd 
~ # touch 1.txt
~ # cat /etc/passwd
root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
operator:x:11:0:operator:/root:/bin/sh
man:x:13:15:man:/usr/man:/sbin/nologin
postmaster:x:14:12:postmaster:/var/spool/mail:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin
squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin
xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
postgres:x:70:70::/var/lib/postgresql:/bin/sh
cyrus:x:85:12::/usr/cyrus:/sbin/nologin
vpopmail:x:89:89::/var/vpopmail:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
nginx:x:100:101:Linux User,,,:/var/cache/nginx:/sbin/nologin
~ # chown nobody:nobody 1.txt
~ # ls -ltr
total 0
-rw-r--r--    1 nobody   nobody           0 Aug 12 08:39 1.txt
~ # exit
[root@k8s-master01 12.4]# cat 11.non_chown.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: disable-chown-pod
spec:
 containers:
 - name: nginx-container
   image: myapp:v1.0
   securityContext:
     capabilities:
       drop:
       - CHOWN
4.期望:容器组:容器名、基于镜像版本、安全上下文:能力:删除:chown 命令
[root@k8s-master01 12.4]# kubectl apply -f 11.non_chown.yaml 
pod/disable-chown-pod created
# 这里与老师视频不一样,视频中 容器启动命令会自动修改文件的 用户与用户组,因为已经删除了 chown ,所以启动时报错,这个镜像容器启动时没有更改文件命令,所以能够启动,但是进入 Pod 中,确实不能修改用户与用户组了,显示受限
# 如果像视频中一样,可以 kubectl describe 、kubectl logs 查看
[root@k8s
-master01 12.4]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES disable-chown-pod 1/1 Running 0 57s 10.244.58.215 k8s-node02 <none> <none> privileged-pod-1 1/1 Running 0 8m53s 10.244.58.226 k8s-node02 <none> <none> [root@k8s-master01 12.4]# kubectl exec -it disable-chown-pod -- /bin/sh / # cd ~ # touch 1.txt ~ # chown nobody:nobody 1.txt chown: 1.txt: Operation not permitted ~ # exit command terminated with exit code 1
# 消除实验影响
[root@k8s-master01 12.4]# kubectl delete pod --all
pod "disable-chown-pod" deleted
pod "privileged-pod-1" deleted

(7)阻止对容器根文件系统的写入

# 本实验不需要做对比,因为之前的 Pod 是默认使用 root 用户运行,所以一定可以创建文件
[root@k8s-master01 12.4]# cat 12.readonly_file.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: pod-with-readonly-filesystem
spec:
 containers:
 - name: main
   image: alpine
   command: ["/bin/sleep", "9999"]
   securityContext:
     readOnlyRootFilesystem: true
   volumeMounts:
   - name: my-volume
     mountPath: /volume
     readOnly: false
 volumes:
 - name: my-volume
   emptyDir:
4.期望:
    容器组:容器名、基于镜像版本、启动命令、安全上下文:只读 roo 文件系统:开启、挂载卷:卷名、挂载容器目录、只读:不开启(即 不只读,是读写权限 )
    定义卷:卷名、空目录
[root@k8s-master01 12.4]# kubectl apply -f 12.readonly_file.yaml 
pod/pod-with-readonly-filesystem created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
pod-with-readonly-filesystem   1/1     Running   0          7s    10.244.58.214   k8s-node02   <none>           <none>
# 只对某一个卷内可以进行读写,其他都是只读,提高文件安全性
[root@k8s-master01 12.4]# kubectl exec -it pod-with-readonly-filesystem -- /bin/sh
/ # ls
bin     dev     etc     home    lib     media   mnt     opt     proc    root    run     sbin    srv     sys     tmp     usr     var     volume
/ # touch 1.txt
touch: 1.txt: Read-only file system
/ # touch /root/1.txt
touch: /root/1.txt: Read-only file system
/ # touch /volume/1.txt
/ # exit
# 消除实验影响
[root@k8s-master01 12.4]# kubectl delete pod --all
pod "pod-with-readonly-filesystem" deleted

(8)文件组与附加组 fsGroup 与 supplementalGroups

注意:对文件进行更改时,文件的组和附加组会成为文件的用户组,注意只有 fsGroup,没有 fsUser

[root@k8s-master01 12.4]# cat 13.group.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: pod-with-shared-volume-fsgroup
spec:
 securityContext:
   fsGroup: 555
   supplementalGroups: [666, 777]
 containers:
 - name: first
   image: alpine
   command: ["/bin/sleep", '9999']
   securityContext:
     runAsUser: 1111
   volumeMounts:
   - name: shared-volume
     mountPath: /volume
     readOnly: false
 - name: second
   image: alpine
   command: ["/bin/sleep", '9999']
   securityContext:
     runAsUser: 2222
   volumeMounts:
   - name: shared-volume
     mountPath: /volume
     readOnly: false
 volumes:
 - name: shared-volume
   emptyDir:
4.期望:Pod 安全上下文:文件组:555、附加组:666777
           容器组:容器名1、基于镜像版本、启动命令、容器安全上下文:运行使用用户:1111、卷挂载:卷名、挂载容器路径、只读:否(即不只读,是读写方式)
                  容器名2、基于镜像版本、启动命令、容器安全上下文:运行使用用户:2222、卷挂载:卷名、挂载容器路径、只读:否(即不只读,是读写方式)
           定义卷:卷名、空目录       
[root@k8s-master01 12.4]# kubectl apply -f 13.group.yaml 
pod/pod-with-shared-volume-fsgroup created
[root@k8s-master01 12.4]# kubectl get pod -o wide
NAME                             READY   STATUS    RESTARTS   AGE     IP              NODE         NOMINATED NODE   READINESS GATES
pod-with-shared-volume-fsgroup   2/2     Running   0          2m32s   10.244.58.224   k8s-node02   <none>           <none>
# 当前容器中 用户是 1111,用户组是 root,但是当创建文件时,文件的用户组是 555
# 文件组可以在同 Pod 中,跨容器去修改同 Pod 中的其他容器内文件,另外一个容器的用户在本容器的用户组内
# 附加组可以跨 Pod 修改文件,将其它 Pod的用户信息添加到本 Pod 的附加组中,本 Pod 可以跨 Pod 去修改文件或两Pod 共同使用文件
[root@k8s-master01 12.4]# kubectl exec -it pod-with-shared-volume-fsgroup -c first -- /bin/sh
~ $ id
uid=1111 gid=0(root) groups=0(root),555,666,777
~ $ cd /volume/
/volume $ touch 1.txt
/volume $ ls -ltr
total 0
-rw-r--r--    1 1111     555              0 Aug 12 14:33 1.txt
/volume $ exit
# 消除实验影响
[root@k8s-master01 12.4]# kubectl delete pod --all
pod "pod-with-shared-volume-fsgroup" deleted

12.4.3 PodSecurityAdmission(namespace 级)

 (1)概念

从 Kubernetes v1.21 开始,Pod Security Policy(对 Pod 安全进行策略定义的功能,PSP) 将被弃用,并将在 v1.25 中删除,Kubernetes 在 v1.22 版本引入了 Pod Security Admission(PSA) 作为其替代者(两者没有关联,不是继承关系)

Pod Security Admission(PSA) 机制在易用性和灵活性上都有了很大提升,从使用角度有以下三点显著不同:

  可以在集群中默认开启,只要不设置约束条件就不会触发对 Pod 的校验

  只在命名空间级别生效,可以为不同的命名空间通过添加标签的方式设置不同的安全限制

  根据实践预设了三种安全等级,不需要由用户单独去设置每一项安全条件(官方根据大量使用场景,确定预置了三种安全等级)

(2)PSA 安全策略分类

为了广泛的覆盖安全应用场景,Pod Security Standards 渐进式的定义了三种不同的 Pod 安全标准策略:

策略 描述
Privileged 不受限制的策略,提供最大可能范围的权限许可,此策略允许已知的特权提升
Baseline 限制性最弱的策略,禁止已知的策略提升,允许使用默认(规定最少)的Pod 配置
Restricted

限制性非常强的策略,遵循当前的保护 Pod 的最佳实践(官方推荐,同时规则也是最多的)

 

 

 

 

 

(3)PSA 设定模式

在 Kubernetes 集群中开启了 pod Security admission 后,就可以通过给 namespace 设置 label 的方式来实施 Pod Security Standards,其中有三种设定模式可选用

模式 描述
enforce 违反安全标准策略的 Pod 将被拒绝
audit 违反安全标准策略触发向审计日志中记录的事件添加审计注释,但其行为被允许
warn 违反安全标准策略将触发面向用户的警告,但其行为被允许

 

 

 

 

 

(4)Label 模板设置

设定模式及安全标准策略等级

  pod-security.kubernetes.io/<MODE>.<LEVEL>

  MODE 必须是 enforce,audit 或 warn 其中之一

  LEVEL 必须是 privileged,baseline 或 restricted 其中之一

此选项是非必填的,用来锁定使用哪个版本的安全标准(类似法律需要更新迭代)

  pod-security.kubernetes.io/<MODE>-version:<VERSION>

  MODE 必须是 enforce,audit 或 warn 其中之一

  VERSION 必须是一个有效的 kubernetes minor version(例如 v1.23) 或者 latest

(5)pod Security Standards 示例演示 - Baseline

  Baseline(基线) 策略目标是应用于常见的容器化应用,禁止已知的特权提升,在官方的介绍中此策略针对的是应用运维人员和非关键性应用开发人员,在该策略中包括(即基线的限制):必须禁止共享宿主命名空间、禁止容器特权、限制 Linux 能力、禁止 hostPath 卷、限制宿主机端口、设定 AppArmor、SElinux、Seccomp、Sysctls 等安全策略

AppArmor、SElinux、Seccomp、Sysctls:(系统内核级)

  AppArmor(Application Armor):是一种 Linux 内核安全模块,它允许系统管理员为每个程序指定安全策略,以限制程序的行为,这些策略定义了哪些文件、目录和网络资源可以由应用程序访问,以及程序在系统上运行时应该具有哪些权限

  SELinux(Security-Enhanced Linux):SELinux 是 Linux 内核的一个安全子系统,它提供了强大的访问控制机制,可以强制实施安全策略。SELinux 使用安全上下文来定义对象(如文件、进程等)的安全策略,并根据这些安全策略来控制对这些对象的访问

  Seccomp(Secure Computing Mode):Seccomp 是 Linux内核的一个安全特性,它允许程序在沙盒环境中运行,并限制其可以执行的系统调用

  Sysctls(System Control Parameters):Sysctls 是 Linux内核的一个功能,它允许系统管理员动态地配置内核参数,这些参数可以控制系统的各种行为,如网络栈参数、内存管理参数等。

违反 Baseline 策略存在的风险:

  特权容器可以看到宿主机设备

  挂载 procfs 后可以看到宿主机进程,打破了进程隔离

  可以打破网络隔离

  挂载运行时 socket 后,可以不受限制的与运行时通信

(6)pod Security Standards 示例演示 - Restricted

  Restricted [rɪˈstrɪktɪd] 策略目标是实施当前保护 Pod 的最佳实践,在官方介绍中此策略主要针对运维人员和安全性很重要的应用开发人员,以及不太被信任的用户,该策略包含所有的 baseline 策略的内容,额外增加:限制可以通过 PersistentVolumes 定义的非核心卷类型禁止(通过 SetUID 或 SetGID 文件模式)获得特权提升、必须要求容器以非 root 用户运行Containers 不可以将 runAsUser 设置为 0、容器组必须弃用 ALL capabilities 并且只允许添加 NET_BIND_SERVICE 能力

  Restricted 策略进一步的限制在容器内获取 root 权限,linux 内核功能。例如针对 kubernetes 网络的中间人攻击需要拥有 Linux 系统内核的 CAP_NET_RAW 权限来发送 ARP 包

(7)PSA 当前局限性

  posSecurity admission 只是对 pod 进行安全标准的检查,不支持对 pod 进行修改,不能为 pod 设置默认的安全配置(不符合安全策略创建时提示错了,但不会自动调整符合的安全策略)

  podSecurity admission 只支持官方定义的三种安全标准策略,不支持灵活的自定义安全标准策略,这使得不能完全将 PSP(Pod Security Policy) 规则迁移到 PSA,需要进行具体的安全规则考量(不能灵活自定义)

12.4.4 Baseline(基线)实验

(1)创建带有基线的名称空间

创建名为 my-baseline-namespace 的 namespace,并设定 enforce 和 warn 两种模式都对应 Baseline 等级的 Pod 安全标准策略
[root@k8s-master01 12.4]# cat 14.baseline.yaml 
apiVersion: v1
kind: Namespace
metadata:
 name: my-baseline-namespace
 labels:
   pod-security.kubernetes.io/enforce: baseline  
   pod-security.kubernetes.io/enforce-version: v1.29
3.元数据:名称空间名字、标签:开启的PSA模式:baseline 基线、kubernetes 版本:v1.29
[root@k8s-master01 12.4]# kubectl apply -f 14.baseline.yaml 
namespace/my-baseline-namespace created
[root@k8s-master01 12.4]# kubectl get namespace
NAME                    STATUS   AGE
........
my-baseline-namespace   Active   7s
........

(2)创建违反基线的 Pod

[root@k8s-master01 12.4]# cat 15.pod.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: hostnamespaces1
 namespace: my-baseline-namespace
spec:
 containers:
 - image: myapp:v1.0
   name: myapp
   securityContext:
     privileged: true
 hostPID: true
4.期望:容器组:基于镜像版本、容器名、安全上下文:特权模式:开启
       共享主机Pid:开启
# 应用时报错,因为违反了 策略
[root@k8s-master01 12.4]# kubectl apply -f 15.pod.yaml 
Error from server (Forbidden): error when creating "15.pod.yaml": pods "hostnamespaces1" is forbidden: violates PodSecurity "baseline:v1.29": host namespaces (hostPID=true), privileged (container "myapp" must not set securityContext.privileged=true)

(3)创建不违反基线的 Pod

# 创建不违反 baseline 策略的 pod,设定 Pod 的 hostPID=false,securityContext.privileged=false(不违反基线规则,或者不写也可以)
[root@k8s-master01 12.4]# cat 16.pod.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: hostnamespaces2
 namespace: my-baseline-namespace
spec:
 containers:
 - image: myapp:v1.0
   name: myapp
   securityContext:
     privileged: false
 hostPID: false
[root@k8s-master01 12.4]# kubectl apply -f 16.pod.yaml 
pod/hostnamespaces2 created
[root@k8s-master01 12.4]# kubectl get pod -o wide -n my-baseline-namespace 
NAME              READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
hostnamespaces2   1/1     Running   0          17s   10.244.58.227   k8s-node02   <none>           <none>
# 消除实验影响
[root@k8s-master01 12.4]# kubectl delete pod --all -n my-baseline-namespace 
pod "hostnamespaces2" deleted

12.4.5 Restricted(限制)实验

注意:在不同的版本上,策略会发生变化(类似因之前发布的法律有漏洞,后面会颁布新的法律,新的法律可以修改不同应用场景)

(1)创建带有 Restricted 的名称空间

# 创建名为 my-restricted-namespace 的 namespace,并设定 enforce 模式对应 Restricted 等级的 Pod 安全标准策略
[root@k8s-master01 12.4]# cat 17.restricted.yaml 
apiVersion: v1
kind: Namespace
metadata:
 name: my-restricted-namespace
 labels:
   pod-security.kubernetes.io/enforce: restricted
   pod-security.kubernetes.io/enforce-version: v1.29
3.元数据:名称空间名字、标签:开启的PSA模式: restricted 策略、kubernetes 版本:v1.29
[root@k8s-master01 12.4]# kubectl apply -f 17.restricted.yaml 
namespace/my-restricted-namespace created
[root@k8s-master01 12.4]# kubectl get namespace
NAME                      STATUS   AGE
..........
my-restricted-namespace   Active   8s
..........

(2)创建违反 Restricted 策略的 Pod

# 创建基础 pod,也被拒绝
[root@k8s-master01 12.4]# cat 18.pod.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: pod
 namespace: my-restricted-namespace
spec:
 containers:
 - image: myapp:v1.0
   name: myapp
[root@k8s-master01 12.4]# kubectl apply -f 18.pod.yaml 
Error from server (Forbidden): error when creating "18.pod.yaml": pods "pod" is forbidden: violates PodSecurity "restricted:v1.29": allowPrivilegeEscalation != false (container "myapp" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "myapp" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "myapp" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "myapp" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")

(3)创建不违反 Restricted 策略的 Pod

# 创建不违反 restricted 策略的 pod,默认 Pod 中有些权限已经违反了 restricted 的策略,应用会报错
[root@k8s-master01 12.4]# cat 19.pod.yaml apiVersion: v1 kind: Pod metadata: name: runasnonroot0 namespace: my-restricted-namespace spec: containers: - name: myapp image: alpine securityContext: runAsNonRoot: true runAsUser: 102 allowPrivilegeEscalation: false capabilities: drop: - ALL securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault
4.期望:容器组:容器名、基于镜像版本、容器安全上下文、不使用 root  运行:开启、运行使用用户:102 用户、允许额外扩展添加动作:关闭、capabilities 策略:删除:所有策略
       Pod 安全上下文:不使用 root  运行:开启、限制容器的配置文件:类型:默认类型
[root@k8s-master01 12.4]# kubectl apply -f 19.pod.yaml 
pod/runasnonroot0 created
# 消除实验影响
[root@k8s-master01 12.4]# kubectl delete pod --all -n my-restricted-namespace
pod "runasnonroot0" deleted

———————————————————————————————————————————————————————————————————————————

                                                                                                                         无敌小马爱学习

posted on 2025-08-06 15:11  马俊南  阅读(32)  评论(0)    收藏  举报