一、实验环境

在这里插入图片描述

底层系统为ubuntu18.04,然后在每个node上安装k8s,并构建集群。Master node的IP地址为192.168.26.71/24,两个Worker node的IP地址为192.168.26.72/24、192.168.26.73/24。

二、PSP基础

1.PSP概述
Pod 安全策略(Pod Security Policy)是集群级别的资源(默认不属于任何Namespace,但也可以在创建PSP规则时指定绑定到具体的Namespace),它能够控制Pod的各个安全方面。包括如下的内容:
在这里插入图片描述
只有当我们部署pod时满足了上述的要求后,才能够正常部署。PSP由设置和策略组成,它们能够控制 Pod 访问的安全特征。这些设置分为如下三类:

  1. 基于布尔值控制 :这种类型的字段默认为最严格限制的值;
  2. 基于被允许的值集合控制 :这种类型的字段会与这组值进行对比,以确认值被允许;
  3. 基于策略控制 :设置项通过一种策略提供的机制来生成该值,这种机制能够确保指定的值落在被允许的这组值中。

此外,我们需要注意的是,由于部署的困难,PodSecurityPolicy 在 Kubernetes v1.21 版本中被弃用,将在 v1.25 中删除,后续由简化的PodSecurity代替PSP,描述地址如下:https://kubernetes.io/blog/2021/04/06/podsecuritypolicy-deprecation-past-present-and-future/.。 目前,如果我们想要使用PSP,需要在集群中的准入控制器(admission controller)处添加才行。

2.PSP工作流程
无论是我们通过user account还是service account(例如Deployment控制器会使用)创建pod,请求都会通过准入控制器。如果我们在准入控制器处开启了PSP,并没有设置任何的规则,那么K8s账号(包括admin)发送的请求都会被拒绝。而当我们创建了PSP规则,那么K8s账号发送的请求必须在满足PSP的规则后才能够对Pod进行操作,否则请求依旧会被拒绝。

需要注意的是,如果我们没有给自己创建的User Account或者Service Account赋予访问对应PSP的权限,用户发送的操作请求是无法到达PSP的,那么请求将被拒绝;由于默认的K8s admin的账号拥有着所有的权限,所以可以访问集群中所有的PSP。
在这里插入图片描述

所以在PSP开启的情况,如果我们想要部署一个pod,则需要满足如下条件:

  1. 使用的K8s用户被赋予了create pod的权限;
  2. 使用的K8s用户需要有访问PSP的权限;
  3. 部署的Pod能够通过访问的PSP的检查。

3.开启PSP
首先,在保证K8s集群正常工作的情况下,启用PSP。否则如果K8s集群的系统pod还没有正常启动,PSP规则又开启了,那么所有K8s集群中的系统pod都无法启动,集群将无法正常工作。

在Master上编辑/etc/kubernetes/manifests/kube-apiserver.yaml文件,然后我们需要在command下的enable-admission-plugins下添加PodSecurityPolicy

command:
   - --enable-admission-plugins=NodeRestriction,PodSecurityPolicy

然后重启kubelet,并查看是否启动成功:

systemctl restart kubelet.service

root@vms71:~/psp# 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@vms71:~/psp# kubectl delete psp controller
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy "controller" deleted
root@vms71:~/psp# kubectl delete psp speaker
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy "speaker" deleted

接下来,我们试着使用admin账号创建一个pod,查看结果:

root@vms71:~/psp# kubectl run pod1 --image=nginx --image-pull-policy=IfNotPresent
Error from server (Forbidden): pods "pod1" is forbidden: PodSecurityPolicy: no providers available to validate pod request

可以看到,就算我们使用管理员账户,也无法创建对应的pod,报错提示我们 PodSecurityPolicy: no providers available to validate pod request,说明请求已经被PodSecurityPolicy阻止了。

三、实践一:限制部署Privileged的pod

实验使用的K8s账号是前面笔记中创建的testuser,认证文件为kc1,链接如下https://blog.csdn.net/tushanpeipei/article/details/121877797?spm=1001.2014.3001.5501,目前testuser没有任何权限。

现在我们先使用管理员账号创建一个限制部署Privileged pod的PSP,yaml文件如下:

root@vms71:~/psp# cat privileged.yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: deny-privilege
spec:
  privileged: false  # Don't allow privileged pods!
  # The rest fills in some required fields.
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  volumes:
  - '*'
root@vms71:~/psp# kubectl apply -f privileged.yaml
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy/deny-privilege created

可以看到,这个文件并没有对其他内容有很大的限制,比如说我们在pod中做卷挂载可以是任意的类型、也没有对pod中的UID、GID进行限制等。但是我们可以看到其中privileged的值设置为了false,表示不允许以特权的方式创建pod。

紧接着,我们继续使用如下的yaml文件为testuser创建一个clusterrole:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: null
  name: crole-pod
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - delete
  - list
  - create
  - watch

在这个clusterrole中,允许了对于pods资源的一些操作。接下来我们需要将创建的clusterrole和testuser绑定起来,命令如下:

kubectl create clusterrolebinding crolebinding-pod --clusterrole=crole-pod --user=testuser

使用testuser以非特权的形式创建pod,可以看到不能够正常创建,这是因为testuser没有权限访问我们设置的PSP。

root@vms71:~/psp# kubectl run pod1 --image=nginx --image-pull-policy=IfNotPresent --kubeconfig=kc1
Error from server (Forbidden): pods "pod1" is forbidden: PodSecurityPolicy: unable to admit pod: []

所以我们还应该设置一个clusterrole,设置能够访问我们设置PSP规则的权限,并绑定到testuser上。如下是对应的yaml文件创建思路和内容:

root@vms71:~/psp# kubectl create clusterrole psp-deny-privilege --verb=use --resource=psp --resource-name=deny-privilege --dry-run=client -o yaml > cluster-role-psp-deny-privilege.yaml
root@vms71:~/psp# cat cluster-role-psp-deny-privilege.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: null
  name: psp-deny-privilege
rules:
- apiGroups:
  - policy
  resourceNames:
  - deny-privilege
  resources:
  - podsecuritypolicies
  verbs:
  - use

使用上述的yaml文件创建psp-deny-privilege的clusterrole后,创建一个clusterrolebinding,绑定到testuser:

kubectl create clusterrolebinding crolebinding-psp-privilege --clusterrole=psp-deny-privilege --user=testuser

现在我们重新使用testuser创建pod,查看是否能够成功:

root@vms71:~/psp# kubectl run pod1 --image=nginx --image-pull-policy=IfNotPresent --kubeconfig=kc1
pod/pod1 created

可以看到,现在已经能够正常创建了。那个,接下来我们以特权的方式来创建一个pod,yaml文件如下:

apiVersion: v1
kind: Pod
metadata:
	name: privileged
spec:
	containers:
	- name: pod1
	image: nginx
	securityContext:
	privileged: true

再次使用testuser创建用户,结果如下:

root@vms71:~/psp# kubectl apply -f privileged-pod.yaml --kubeconfig=kc1
Error from server (Forbidden): error when creating "privileged-pod.yaml": pods "privileged" is forbidden: PodSecurityPolicy: unable to admit pod: [spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed]

error信息显示Invalid value: true: Privileged containers are not allowed],说明设置的PSP规则阻止了创建特权pod的请求。

四、实践二:使用Deployment部署pod

我们可以使用K8s的user调动Deployment控制器或者其他控制器部署pod时。而这些控制器在收到了我们的请求后,也会利用自己的Service Accounts完成后续操作。具体步骤如下图所示:
在这里插入图片描述
那么,如果Deployment控制器的SA没有被赋予访问运行Deployment操作的PSP规则的权限,就算我们使用admin这个默认的账号也无法完成Deployment的操作。验证步骤如下:

目前,整个环境中依旧存在deny-privilege部署的PSP:

root@vms71:~/psp# 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
deny-privilege   false          RunAsAny   RunAsAny    RunAsAny   RunAsAny   false            *

然后我们使用admin账号使用如下的Deployment的yaml文件创建Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: web1
  name: web1
spec:
  replicas: 3
  selector:
    matchLabels:
      app1: web1
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app1: web1
        app2: web1
    spec:
      containers:
      - image: nginx
        name: nginx
        imagePullPolicy: IfNotPresent
        resources: {}
status: {}

应用此yaml文件后,虽然显示web1部署成功,但是我们查看pod和Deployment,可以看到pod并没有部署:

root@vms71:~/psp# kubectl get deployments.apps web1
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
web1   0/3     0            0           10s
root@vms71:~/psp# kubectl get pods
No resources found in default namespace.

原因就是因为Deployment控制器的SA没有权限去访问PSP。所以,现在我们需要给Deployment控制器的SA赋予访问PSP的权限。首先,创建clusterrole设置访问PSP的权限,yaml文件如下:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: null
  name: psp-deny-privilege
rules:
- apiGroups:
  - policy
  resourceNames:
  - deny-privilege
  resources:
  - podsecuritypolicies
  verbs:
  - use

然后使用clusterrolebinding将创建的clusterrole与Kube-system命名空间内所有的SA(包括Deployment控制器的SA)做绑定:

kubectl create clusterrolebinding crolebinding-psp-privilege --clusterrole=psp-deny-privilege --group=system:serviceaccounts -n kube-system 

完成配置后,重新应用development的yaml文件,查看pod是否能够正常部署:

root@vms71:~/psp# kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
web1-6748654d8d-6f26l   1/1     Running   0          5s
web1-6748654d8d-6zzb8   1/1     Running   0          5s
web1-6748654d8d-ph89j   1/1     Running   0          5s
root@vms71:~/psp# kubectl get deployments.apps web1
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
web1   3/3     3            3           10s

可以看到,目前Deployment已经能够成功部署pod了,测试成功。

五、其他PSP策略

如下是来自K8s官网的一个具有约束性的策略,要求用户以非特权账号运行,禁止可能的向 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

具体字段的解释请参考:https://kubernetes.io/zh/docs/concepts/policy/pod-security-policy/#example-policies

整理资料来源:
K8s pod-security-policy:https://kubernetes.io/zh/docs/concepts/policy/pod-security-policy/
Sysdig:https://sysdig.com/blog/psp-in-production/
《老段CKS课程》

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐