# 官方提供@yunTaoScripts PSP 🔥🔥

loading

利用k8s集群自带的功能来提升集群安全性。基于准入控制器实现。pod security policy -> pod安全策略,用于限定我们创建特定类型的pod。

  • 启用特权pod
root@vms33:~# cat pod1-privilege.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pod1-privi
  name: pod1-privi
spec:
  nodeName: vms34.rhce.cc
  terminationGracePeriodSeconds: 0
  imagePullSecrets:
  - name: my-secret
  containers:
  - image: 192.168.26.150/baseos/nginx:v1
    imagePullPolicy: IfNotPresent
    name: pod1-privi
    securityContext:
      privileged: true
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
root@pod1-privi:/# cat /proc/sys/vm/swappiness 
60
root@pod1-privi:/# echo 1 > /proc/sys/vm/swappiness  

如果没有特权模式,这一步执行失败

root@pod1-noprivi:/# echo 1 > /proc/sys/vm/swappiness 
bash: /proc/sys/vm/swappiness: Read-only file system

1.25 后将无法使用psp

root@vms33:~# kubectl get psp
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
NAME         PRIV    CAPS      SELINUX    RUNASUSER   FSGROUP     SUPGROUP    READONLYROOTFS   VOLUMES
controller   false             RunAsAny   MustRunAs   MustRunAs   MustRunAs   true             configMap,secret,emptyDir
speaker      true    NET_RAW   RunAsAny   RunAsAny    RunAsAny    RunAsAny    true             configMap,secret,emptyDir
  • 删除自带psp 规则
root@vms33:~# kubectl get psp -oyaml > psp.bak.yaml
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
root@vms33:~# kubectl delete -f psp.bak.yaml 
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy "controller" deleted
podsecuritypolicy.policy "speaker" deleted
root@vms33:~# kubectl get psp
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
No resources found

# 启用PSP准入控制器

root@vms33:~# grep enable-admission /etc/kubernetes/manifests/kube-apiserver.yaml 
    - --enable-admission-plugins=NodeRestriction,PodSecurityPolicy
root@vms33:~# kubectl apply -f pod1.yaml 
Error from server (Forbidden): error when creating "pod1.yaml": pods "pod1" is forbidden: PodSecurityPolicy: no providers available to validate pod request

一定要创建psp 规则

  • 启用PSP 功能后,如果没有创建psp规则,任何用户不可以创建pod。

# 创建 psp 规则

# 不允许提权pod 创建

root@vms33:~# cat psp1.yaml 
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: example
spec:
  privileged: false  # 不允许提权的 Pod!
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  volumes:
  - '*'
  • 创建pod
root@vms33:~# kubectl apply -f pod1-privilege.yaml 
Error from server (Forbidden): error when creating "pod1-privilege.yaml": pods "pod1-privi" is forbidden: PodSecurityPolicy: unable to admit pod: [spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed]
root@vms33:~# kubectl apply -f pod1-noprivilege.yaml 
pod/pod1-noprivi created
root@vms33:~# kubectl get pod
NAME           READY   STATUS    RESTARTS   AGE
pod1-noprivi   1/1     Running   0          7s

非root 用户 可能没有权限访问psp,因此无法创建pod

  • 给 john 授权使用psp
root@vms33:~# kubectl create clusterrole use-psp --verb use --resource psp --resource-name example
root@vms33:~# kubectl create clusterrolebinding cbind-use-psp --clusterrole use-psp --user john
clusterrolebinding.rbac.authorization.k8s.io/cbind-use-psp created

# 允许使用宿主机网络空间(默认禁止)

root@vms33:~# kubectl apply -f pod1-noprivilege-hostnetwok.yaml 
Error from server (Forbidden): error when creating "pod1-noprivilege-hostnetwok.yaml": pods "pod1-noprivi-host" is forbidden: PodSecurityPolicy: unable to admit pod: [spec.securityContext.hostNetwork: Invalid value: true: Host network is not allowed to be used]
  • 允许hostNetwok PSP
root@vms33:~# grep host psp2.yaml 
  hostNetwork: true
root@vms33:~# cat psp2.yaml 
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: psp2
spec:
  hostNetwork: true  # 允许使用主机网络
  privileged: false  # 不允许提权的 Pod!
  # 以下内容负责填充一些必需字段。
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  volumes:
  - '*'
root@vms33:~# cat pod1-noprivilege-hostnetwok.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pod1-noprivi-host
  name: pod1-noprivi-host
spec:
  hostNetwork: true
  nodeName: vms34.rhce.cc
  terminationGracePeriodSeconds: 0
  imagePullSecrets:
  - name: my-secret
  containers:
  - image: 192.168.26.150/baseos/nginx:v1
    imagePullPolicy: IfNotPresent
    name: pod1-noprivi-host
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

# 限制只能挂载特定类型的卷。

spec:
  privileged: false
  # 防止权限升级到 root
  allowPrivilegeEscalation: false
  requiredDropCapabilities:
    - ALL
  # 允许的核心卷类型.
  volumes:
    - 'configMap'
    - 'emptyDir'
    - 'projected'
    - 'secret'
    - 'downwardAPI'

# 限制只能挂载特定目录。

  volumes:
    - 'configMap'
    - 'emptyDir'
    - 'projected'
    - 'secret'
    - 'downwardAPI'
  allowedHostPaths:
    # 下面的设置允许 "/foo"、"/foo/"、"/foo/bar" 等路径,但禁止
    # "/fool"、"/etc/foo" 这些路径。
    # "/foo/../" 总会被当作非法路径。
    - pathPrefix: "/foo"
      readOnly: true # 仅允许只读模式挂载

# 限制只能某个用户启动

runAsUser:
  # 要求容器在没有 root 权限的情况下运行
  rule: 'MustRunAsNonRoot'

supplementalGroups:
  rule: 'MustRunAs'
  ranges:
    # 禁止添加 root 组
    - min: 1
      max: 65535

# 限制hostPort 端口范围

  • pod 使用hostPort 时的 范围限制
spec:
  privileged: true
  allowPrivilegeEscalation: true
  allowedCapabilities:
  - '*'
  volumes:
  - '*'
  hostNetwork: true
  hostPorts:  ###端口映射范围
  - min: 0
    max: 65535

# 允许rs 控制器 访问psp

root@vms33:~# kubectl create deployment dp1 --image nginx 
deployment.apps/dp1 created

root@vms33:~# kubectl get deployments.apps 
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
dp1    0/1     0            0           14s
root@vms33:~# kubectl get event
LAST SEEN   TYPE      REASON              OBJECT                      MESSAGE
2s          Warning   FailedCreate        replicaset/dp1-5fb8655b4f   Error creating: pods "dp1-5fb8655b4f-" is forbidden: PodSecurityPolicy: unable to admit pod: []
23s         Normal    ScalingReplicaSet   deployment/dp1              Scaled up replica set dp1-5fb8655b4f to 1

无法创建deployment 原因

deployment 首先会创建rs 控制器。每个控制器都有一个sa,用于各种操作。但是启用psp后,rs控制器的 sa 不具备访问psp 规则的权限,因此无法创建pod。

root@vms33:~# kubectl get psp psp2 -oyaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: psp2
  resourceVersion: "698032"
  uid: a3ce138f-0e88-4888-bdac-1cce1512d0e9
spec:
  allowPrivilegeEscalation: true
  fsGroup:
    rule: RunAsAny
  hostNetwork: true
  runAsUser:
    rule: RunAsAny
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  volumes:
  - '*'
root@vms33:~# kubectl get clusterrole use-psp -oyaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: "2022-09-17T12:33:44Z"
  name: use-psp
  resourceVersion: "696044"
  uid: 0ca44b28-3c33-422e-8fcd-ddc0ae013f0c
rules:
- apiGroups:
  - policy
  resourceNames:
  - example
  resources:
  - podsecuritypolicies
  verbs:
  - use
root@vms33:~# kubectl get sa -n kube-system  | grep replicaset
replicaset-controller                0         23d
  • 给命名空间单个sa 授权
root@vms33:~# kubectl create clusterrolebinding cbind-rs-usepsp --clusterrole use-psp --serviceaccount kube-system:replicaset-controller
  • 给kube-system命名空间所有sa授权
root@vms33:~# kubectl create clusterrolebinding cbind-rs-usep-all-sa --clusterrole use-psp --group system:serviceaccounts
  • 此时 rs 可以访问到psp,所以可以创建pod
root@vms33:~# kubectl get deployments.apps dp1 
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
dp1    3/3     3            3           12m

psp生效范围

PSP 全局生效,没有命名空间限制

# 限制用户在特定ns满足psp规则

思路:

  • 首先创建psp1 ,拒绝特权pod。
  • 创建psp2,允许特权pod。
  • 给john 授权rolebinding访问psp2。

找出所有授权给john 的 clusterrolebinding,并删除。

root@vms33:~# kubectl get clusterrolebindings.rbac.authorization.k8s.io  -owide| grep john
最后修改时间: 12/31/2022, 12:00:03 PM