PodSecurityPolicy可以对Pod的创建更新进行细粒度的授权。

注意:controller-manager 必须以非超级用户运行,和在安全的api端口运行,要不然请求会绕过身份验证和授权模块,创建特权容器和psp策略都将被允许。

官方文档:

https://kubernetes.io/docs/concepts/policy/pod-security-policy/

最少的限制:相当于不使用Pod安全策略

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: privileged
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
spec:
  privileged: true
  allowPrivilegeEscalation: true
  allowedCapabilities:
  - '*'
  volumes:
  - '*'
  hostNetwork: true
  hostPorts:
  - min: 0
    max: 65535
  hostIPC: true
  hostPID: true
  runAsUser:
    rule: 'RunAsAny'
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'RunAsAny'
  fsGroup:
    rule: 'RunAsAny'

禁止以root用户运行:阻止用户升级到root用户。

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: restricted
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default,runtime/default'
    apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
    seccomp.security.alpha.kubernetes.io/defaultProfileName:  'runtime/default'
    apparmor.security.beta.kubernetes.io/defaultProfileName:  'runtime/default'
spec:
  privileged: false
  # Required to prevent escalations to root.
  allowPrivilegeEscalation: false
  # This is redundant with non-root + disallow privilege escalation,
  # but we can provide it for defense in depth.
  requiredDropCapabilities:
    - ALL
  # Allow core volume types.
  volumes:
    - 'configMap'
    - 'emptyDir'
    - 'projected'
    - 'secret'
    - 'downwardAPI'
    # Assume that persistentVolumes set up by the cluster admin are safe to use.
    - 'persistentVolumeClaim'
  hostNetwork: false
  hostIPC: false
  hostPID: false
  runAsUser:
    # Require the container to run without root privileges.
    rule: 'MustRunAsNonRoot'
  seLinux:
    # This policy assumes the nodes are using AppArmor rather than SELinux.
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'MustRunAs'
    ranges:
      # Forbid adding the root group.
      - min: 1
        max: 65535
  fsGroup:
    rule: 'MustRunAs'
    ranges:
      # Forbid adding the root group.
      - min: 1
        max: 65535
  readOnlyRootFilesystem: false


使用PSP安全策略


        psp策略定义好之后还需要再创建role,把psp策略绑定到role上,再将role绑定到serviceaccount,再在Pod中使用serviceaccount。


还有几个必要条件:

1、在apiserver启动参数  --enable-admission-plugins  中要加上  PodSecurityPolicy  选项,默认是没有启用的。

2、在 controller-manager 的启动参数中开启   --use-service-account-credentials=true  选项,这个选项默认是开启的,会自动为k8s中每一个控制器创建一个serviceaccount,例如运行 deployment 的时候默认就会使用名称为 deployment-controller 的 serviceaccount 来创建Pod。

参考:

https://www.qikqiak.com/post/setup-psp-in-k8s/

PSP.png

        如果想给某个 deployment 或某个Pod单独设置一个策略可以单独创建serviceaccount、psp、role、rouebinding这些资源,然后在Pod中使用这个serviceaccount 即可。

示例:

        创建一个deployment 和一个 serviceaccount,并在deployment中使用这个serviceaccount,然后再创建psp策略,再为psp创建权限role,然后用 rolebinding 将 role 和 serviceaccount绑定。这样修改psp策略就可以控制Pod的权限了。

psp-test.yaml:

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: privileged
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
spec:
  privileged: true
  allowPrivilegeEscalation: true
  allowedCapabilities:
  - '*'
  volumes:
  - '*'
  hostNetwork: false # 修改true 或 false来控制Pod是否可用 hostNetwork
  hostPorts:
  - min: 0
    max: 65535
  hostIPC: true
  hostPID: true
  runAsUser:
    rule: 'RunAsAny'
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'RunAsAny'
  fsGroup:
    rule: 'RunAsAny'
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: psp-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: psp-role
rules:
- apiGroups: ['policy']
  resources: ['podsecuritypolicies']
  verbs:     ['use']
  resourceNames:
  - privileged
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: psp-rolebinding
roleRef:
  kind: ClusterRole
  name: psp-role
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: psp-sa
  namespace: default
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: psp-nginx
  namespace: default
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
      hostNetwork: true
      serviceAccount: psp-sa

创建上面的资源并应用:

kubectl apply -f psp-test.yaml

如下可以看到deployment虽然创建了,但是READY数为0,并没有Pod被创建,因为这个Pod需要使用到hostNetwork,但是策略中是禁止使用的,所以创建不成功。

~]# kubectl get deployments.apps 
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
psp-nginx   0/1     0            0           21m

修改psp策略:hostNetwork的false改为true。

kubectl delete deployments.apps psp-nginx

删除之前的deployment再重新创建这个deployment。

kubectl apply -f psp-test.yaml

再次创建资源后查看:可以看到Pod已近被创建了。

~]# kubectl get pods 
NAME                         READY   STATUS              RESTARTS   AGE
psp-nginx-7cd85768f8-dn98v   0/1     ContainerCreating   0          22s