k8s安全机制:Pod Security Policy与Secruity Context

“ 💋 戏 子. ✟ 发表于: 2024-01-18   最后更新时间: 2024-01-19 20:52:23  
{{totalSubscript}} 订阅, 328 游览

一、介绍

1.PSP

Pod Security Policy是一个准入控制器。通过RBAC授予users和service accounts启动或更新pods时使用服务器资源的权限。是集群范围内的资源对象,不属于命名空间范围。

2.Security Context

kubernetes可以为pod设置应用程序运行所需的权限或者访问控制等安全设置,涉及多种Linux Kernel安全相关的系统参数,这些安全设置被称为Security Context,在Pod或Container级别通过securityContext字段进行设置(如果在Pod和Container级别都设置了相同的安全字段,则同期将使用Container级别的设置)。摘自《kubernetes权威指南第五版》

3.二者的关联

管理员设置集群范围的PodSecurityPolicy策略会对Pod的SecurityContext安全设置进行校验,对于不满足PodSecurityPolicy策略的Pod,系统将禁止创建。
简单来说,SecurityContext是pod中一段具体的配置,PodSecurityPolicy是用来校验SecurityContext符不符合要求

Note: PodSecurityPolicy 在 Kubernetes v1.21 中被弃用,在 Kubernetes v1.25 中被移除。代替方案是PodSecurityStandard,下面会介绍

4.psp控制项说明

4.1特权模式

privilege:是否允许容器以特权模式运行

4.2宿主机命名空间(namespace)相关

  • hostPID:是否允许容器共享宿主机的进程ID命名空间
  • hostIPC:是否允许容器共享宿主机的IPC命名空间
  • hostNetwork:否允许Pod使用宿主机的网络命名空间,使用hostNetwork的pod将可以访问宿主机的各个网卡
  • hostPorts:是否允许Pod使用宿主机的端口号,可以通过hostPortRange字段设置允许使用的端口号范围,以[min,max]设置最小端口号和最大端口号

4.3存储卷和文件系统相关

  • Volumes:允许pod使用的存储卷类型,设置为“*”表示不受限制
  • FSGroup:
  • AllowedHostPaths:允许pod使用宿主机的hostPath路径名称,可以通过pathPrefix字段设置路径的前缀,并设置是否仅允许以只读模式挂载,举个栗子:
    apiVersion:policy/v1beta1
    kind:PodSecurityPolicy
    metadata:
    name: allow-hostpath-volumes
    spec:
    。。。。
    volumes:
     - flexVolume
    allowedFlexVolumes:
     - driver: example/lvm
     - driver: example/cifs
    
  • ReadOnlyRootFilesystem:根目录只读权限

4.4FlexVolume驱动相关

allowedFlexVolumes用于对类型为flexVolume的存储卷设置允许使用的驱动类型,控制表示没有限制。

4.5用户和组的相关配置

  • RunAsUser:设置运行容器的UID,rule可被设置为MustRunAs、MustRunAsNonRoot、RunAsAny

    MustRunAs:需要设置UID的范围,要求Pod或Container的securityContext.runAsUser设置的值必须属于该UID范围,如未设置,则系统将自动设置securityContext.runAsUse的值为UID的最小值。
    MustRunAsNonRoot:必须以非root用户运行容器
    RunAsAny:不限制UserID的范围,Pod或Container的securityContext.runAsUser可被设置为任意UID

  • RunAsGroup:设置运行容器的GID,rule可被设置为MustRunAs、MustRunAsNonRoot、RunAsAny
  • SupplementalGroups:设置运行容器的用户允许属于的额外GIDrule可被设置为MustRunAs、MustRunAsNonRoot、RunAsAny

4.6提升权限的相关配置

  • AllowPrivilegeEscalation:默认值为true,允许容器提权
  • DefaultAllowPrivilegeEscalation:设置AllowPrivilegeEscalation的默认值

4.7linux能力相关配置

这块比较难,需要了解Linux Capabilities

  • AllowedCapabilities:设置容器可以使用的linux能力列表,设置为“*”表示允许使用linux的所有能力
  • RequiredDropCapabilities:设置必须从容器中删除的linux能力列表
  • DefaultAddCapabilities:设置默认为容器添加的linux能力列表

4.8SELinux相关配置

通过seLinux字段设置SELinux参数rule可被设置为MustRunAs、RunAsAny

4.9其他Linux相关配置

  • AllowedProcMountTypes
  • AppArmor
  • Seccomp
  • Sysctl

    二、PSP的工作机制

    1.开启psp准入控制

    [root@k8s-master ~]# vim /etc/kubernetes/manifests/kube-apiserver.yaml
    ......
    spec:
    containers:
    - command:
     - kube-apiserver
     - --advertise-address=192.168.0.37
     - --allow-privileged=true
     - --authorization-mode=Node,RBAC
     - --client-ca-file=/etc/kubernetes/pki/ca.crt
     - --enable-admission-plugins=NodeRestriction,PodNodeSelector,PodSecurityPolicy
    ......
    
    修改之后保存退出,kube-apiserver会自动重启。

    2.创建Pod

    [root@k8s-master test]# vim test-pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
    name: nginx
    spec:
    containers:
    - name: nginx
     image: nginx
    [root@k8s-master test]# kubectl create -f test-pod.yaml
    Error from server (Forbidden): error when creating "test-pod.yaml": pods "nginx" is forbidden: PodSecurityPolicy: no providers available to validate pod request
    
    此时创建pod会失败
    [root@k8s-master test]# journalctl -f -u kubelet
    -- Logs begin at Wed 2023-02-08 10:40:25 CST. --
    Apr 27 17:01:31 k8s-master kubelet[3621]: E0427 17:01:31.752259    3621 kubelet.go:1661] Failed creating a mirror pod for "kube-apiserver-k8s-master_kube-system(b53d99a0c0acc014c351c2a89eef045d)": pods "kube-apiserver-k8s-master" is forbidden: PodSecurityPolicy: no providers available to validate pod request
    Apr 27 17:03:00 k8s-master kubelet[3621]: E0427 17:03:00.752741    3621 kubelet.go:1661] Failed creating a mirror pod for "kube-apiserver-k8s-master_kube-system(b53d99a0c0acc014c351c2a89eef045d)": pods "kube-apiserver-k8s-master" is forbidden: PodSecurityPolicy: no providers available to validate pod reques
    [root@k8s-master test]# kubectl get pod -n kube-system
    NAME                                       READY   STATUS    RESTARTS   AGE
    calico-kube-controllers-577f77cb5c-9b84g   1/1     Running   0          35d
    calico-node-6p7b4                          1/1     Running   1          35d
    calico-node-fpp6m                          1/1     Running   0          35d
    calico-node-lkcft                          1/1     Running   0          35d
    calico-node-qtcn6                          1/1     Running   1          35d
    calicoctl                                  1/1     Running   0          35d
    coredns-7f89b7bc75-n5255                   1/1     Running   0          35d
    coredns-7f89b7bc75-s5xh7                   1/1     Running   0          35d
    eip-nfs-nfs-7cd8fcb6f9-2xzfc               1/1     Running   14         35d
    etcd-k8s-master                            1/1     Running   0          35d
    kube-controller-manager-k8s-master         1/1     Running   9          35d
    kube-proxy-26vvr                           1/1     Running   0          16d
    kube-proxy-4vhwc                           1/1     Running   0          16d
    kube-proxy-mjdgf                           1/1     Running   0          16d
    kube-proxy-txpk4                           1/1     Running   0          16d
    kube-scheduler-k8s-master                  1/1     Running   8          35d
    metrics-server-c7d74c45-gl4lg              1/1     Running   0          31d
    

Note:开启PodSecurityPolicy准入控制器后,系统中还没有任何PodSecurityPolicy策略时,k8s默认不允许创建任何Pod,需要创建适合的PSP策略和相应的RBAC赋权策略,Pod才能创建成功

3.创建PSP

[root@k8s-master test]# vim psp.yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: psp
spec:
  privileged: false            ## 禁止特权模式启动
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  volumes:
  - '*'
[root@k8s-master test]# kubectl apply -f psp.yaml
podsecuritypolicy.policy/psp created
[root@k8s-master test]# kubectl get psp
NAME   PRIV    CAPS   SELINUX    RUNASUSER   FSGROUP    SUPGROUP   READONLYROOTFS   VOLUMES
psp    false          RunAsAny   RunAsAny    RunAsAny   RunAsAny   false            *

再次创建Pod就能成功

[root@k8s-master test]# kubectl apply -f test-pod.yaml
pod/nginx created
[root@k8s-master test]# kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          12s

修改pod为特权模式就会失败

[root@k8s-master test]# vim test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    securityContext:
      privileged: true
[root@k8s-master test]# kubectl apply -f test-pod.yaml
Error from server (Forbidden): error when creating "test-pod.yaml": pods "nginx" is forbidden: PodSecurityPolicy: unable to admit pod: [spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed]

Note:这个示例用的sa是default sa,整个示例没有RBAC授权过程,但是自建的sa必须要授权,关于这一点我查了很久没有结果,那就当default sa有特殊权限吧,这个问题不用再纠结,下面会演示自建sa然后RBAC授权的过程

4.创建命名空间和SA

[root@k8s-master test]# kubectl create namespace test
namespace/test created
[root@k8s-master test]# kubectl create sa -n test test-user
serviceaccount/test-user created

授权clusterrole‘edit’权限,使sa test-user有权限创建pod

[root@k8s-master test]# kubectl get clusterrole | grep edit
edit                                                                   2023-10-09T03:14:14Z
system:aggregate-to-edit                                               2023-10-09T03:14:14Z
[root@k8s-master test]# kubectl create rolebinding -n test test-user --clusterrole=edit --serviceaccount=test:test-user
rolebinding.rbac.authorization.k8s.io/test-user created

用新建的sa发布测试

[root@k8s-master test]# kubectl --as=system:serviceaccount:test:test-user -n test apply -f app-nginx.yaml
Error from server (Forbidden): error when retrieving current configuration of:
Resource: "apps/v1, Resource=deployments", GroupVersionKind: "apps/v1, Kind=Deployment"
Name: "nginx-app", Namespace: "test"
from server for: "app-nginx.yaml": deployments.apps "nginx-app" is forbidden: User "system:serviceaccount:test:test-user" cannot get resource "deployments" in API group "apps" in the namespace "test"
[root@k8s-master test]# kubectl auth can-i use psp/psp --as=system:serviceaccount:test:test-user -n test
Warning: resource 'podsecuritypolicies' is not namespace scoped in group 'policy'
no                ## 授权验证,目前无权限

上面的报错可以看出,目前test-user这个sa不能使用psp这个Pod Security Policy,需要做role和rolebinding授权

5.创建role和rolebinding授权

[root@k8s-master test]# cat psp-rbac.yaml
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: test
  name: psp-role
rules:
- apiGroups: ["policy"]
  resources: ["podsecuritypolicies"]
  resourceNames: ["psp"]
  verbs: ["use"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: psp-rolebinding
  namespace: test
subjects:
- kind: ServiceAccount
  name: test-user
  namespace: test
roleRef:
  kind: Role
  name: psp-role
  apiGroup: rbac.authorization.k8s.io
[root@k8s-master test]# kubectl apply -f psp-rbac.yaml
role.rbac.authorization.k8s.io/psp-role created
rolebinding.rbac.authorization.k8s.io/psp-rolebinding created
[root@k8s-master test]# kubectl auth can-i use psp/psp --as=system:serviceaccount:test:test-user -n test
Warning: resource 'podsecuritypolicies' is not namespace scoped in group 'policy'
yes                ## 授权验证成功
[root@k8s-master  test]# kubectl get rolebinding -n test
NAME              ROLE               AGE
psp-rolebinding   Role/psp-role      20m
test-user         ClusterRole/edit   2m51s

6.创建pod测试

[root@k8s-master test]# kubectl --as=system:serviceaccount:test:test-user -n test apply -f app-nginx.yaml
pod/nginx-app created
[root@k8s-master test]# kubectl get pod -n test -o wide
NAME        READY   STATUS    RESTARTS   AGE    IP               NODE                      NOMINATED NODE   READINESS GATES
nginx-app   1/1     Running   0          116s   100.64.168.169   izbp1a1yp5oxc1e2haou4wz   <none>           <none>

查看pod 注解,发现自动注入一条psp信息

[root@k8s-master test]# kubectl get pod nginx-app -n test -o custom-columns=ANNOTATIONS:.metadata.annotations
ANNOTATIONS
map[cni.projectcalico.org/podIP:100.64.168.169/32 kubectl.kubernetes.io/last-applied-configuration:{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"nginx-app","namespace":"test"},"spec":{"containers":[{"image":"nginx","name":"nginx"}]}}
 kubernetes.io/psp:psp]

7.测试特权模式

[root@k8s-master test]# kubectl delete -f app-nginx.yaml
pod "nginx-app" deleted

添加特权配置

[root@k8s-master test]# cat app-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-app
  namespace: test
spec:
  containers:
  - name: nginx
    image: nginx
    securityContext:
      privileged: true
[root@k8s-master test]# kubectl --as=system:serviceaccount:test:test-user -n test apply -f app-nginx.yaml
pod/nginx-app created
Error from server(Forbidden): error when creating "app-nginx.yaml": pods "nginx-app" is forbidden: unable to validate against any pod security polic: [spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed]

三、Pod Security Standard介绍

1.为什么要用Pod Security Standard

自从首次引入 PodSecurityPolicy 以来, PSP 存在一些严重的可用性问题, 只有做出断裂式的改变才能解决。PodSecurityPolicy (PSP) 在 Kubernetes 1.21 中被弃用, 在Kubernetes v1.25会被移除。替代方案Pod Security Standard(Pod安全标准)。
使用 Pod 安全标准的 PSP 来获得和目前 PSP 替代策略相似的功能。 如果你将基线策略或限制策略绑定到 system:serviceaccounts 组来设置集群默认值, 然后使用 ServiceAccount 绑定 在某些命名空间下根据需要制定更宽松的策略,就可以避免许多 PSP 陷阱并轻松迁移到 PSP 替代策略。 如果你的需求比这复杂得多,那么建议将精力花在采用比上面提到的功能更全的某个外部准入控制器。
Pod 安全性准入(Pod Security Admission)在 Kubernetes v1.22 作为 Alpha 特性发布, 在 Kubernetes v1.23 中作为 Beta 特性默认可用。从 1.25 版本起, 此特性进阶至正式发布(Generally Available)。

2.Pod Security Standard的策略

Pod 安全性标准定义了三种不同的策略(Policy),以广泛覆盖安全应用场景。 这些策略是叠加式的(Cumulative),安全级别从高度宽松至高度受限。 本指南概述了每个策略的要求
|Profile | 描述 |
|--|--|
| Privileged | 不受限制的策略,提供最大可能范围的权限许可。此策略允许已知的特权提升。 |
|Baseline |限制性最弱的策略,禁止已知的策略提升。允许使用默认的(规定最少)Pod 配置。 |
| Restricted | 限制性非常强的策略,遵循当前的保护 Pod 的最佳实践。 |

3.Profile 细节

3.1Privileged

Privileged 策略是有目的地开放且完全无限制的策略。 此类策略通常针对由特权较高、受信任的用户所管理的系统级或基础设施级负载。
Privileged 策略定义中限制较少。默认允许的(Allow-by-default)实施机制(例如 gatekeeper) 可以缺省设置为 Privileged。 与此不同,对于默认拒绝(Deny-by-default)的实施机制(如 Pod 安全策略)而言, Privileged 策略应该禁止所有限制.

3.2Baseline

Baseline 策略的目标是便于常见的容器化应用采用,同时禁止已知的特权提升。 此策略针对的是应用运维人员和非关键性应用的开发人员。

3.3Restricted

Restricted 策略旨在实施当前保护 Pod 的最佳实践,尽管这样作可能会牺牲一些兼容性。 该类策略主要针对运维人员和安全性很重要的应用的开发人员,以及不太被信任的用户。

pod安全标准就大概介绍这么多,更多信息参考k8s官网,这里就不当文档搬运工了~~~
https://kubernetes.io/docs/concepts/security/pod-security-admission/

更新于 2024-01-19

查看shares更多相关的文章或提一个关于shares的问题,也可以与我们一起分享文章