设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 数据 创业者 手机
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

如何优雅的给 Kubernetes Pod 启用安全策略

发布时间:2022-07-09 12:56 所属栏目:118 来源:互联网
导读:文中的演示和示例均在 v1.18.17 集群中通过验证。 Pod Security Policies Pod Security Policies (下文简称 psp 或 pod 安全策略)是一种集群级别的全局资源,能够对 pod 的创建和更新进行细粒度的授权控制。具体来说,一个 psp 对象定义了一组安全性条件,
  文中的演示和示例均在 v1.18.17 集群中通过验证。
 
  Pod Security Policies
  Pod Security Policies (下文简称 psp 或 pod 安全策略)是一种集群级别的全局资源,能够对 pod 的创建和更新进行细粒度的授权控制。具体来说,一个 psp 对象定义了一组安全性条件,一个 pod 的 spec 字段必须满足这些条件以及适用相关字段的默认值,其创建或更新请求才会被 apiserver 所接受。
 
  具体的 pod 字段和安全条件可见文档 what-is-a-pod-security-policy[1] 。
 
  启用 Pod Security Policies
  Kubernetes 默认不开启 pod 安全策略功能,在集群中启用 pod 安全策略的步骤大体上分为三步:
 
  授予用户访问安全策略资源的权限,通常会授权给整个命名空间的 service account。
  在集群中创建指定的安全策略资源。
  启用 apiserver 的 admission-controller 插件。
  注意步骤 1、2 的顺序不重要,因为它们不会产生实际影响。
 
  但步骤 3 推荐在最后一步执行,否则一旦启用 admission-controller 插件,如果集群中没有可用的 pod 安全策略或者未对安全策略资源预先授权,所有 pod 的创建都会被拒绝,包括 kube-system 命名空间下的系统管理组件如 apiserver(但由于是受 kubelet 管理的静态 pod 实际上容器依然会运行)。
 
  RBAC 身份认证
 
  创建可访问所有安全策略资源的 ClusterRole:
  复制
  apiVersion: rbac.authorization.k8s.io/v1
  kind: ClusterRole
  metadata:
   name: all-psp
  rules:
  - apiGroups: ['policy']
   resources: ['podsecuritypolicies']
   verbs:     ['use']

  通过 ClusterRoleBinding 将创建的角色绑定到指定命名空间下的所有 service account(也可以授权给指定的 sa 或者用户):
  复制
  apiVersion: rbac.authorization.k8s.io/v1
  kind: ClusterRoleBinding
  metadata:
   name: cluster-psp-bind
  roleRef:
   kind: ClusterRole
   name: all-psp
   apiGroup: rbac.authorization.k8s.io
  subjects:
  # 授权给指定命名空间下的所有 service account(推荐做法):
  - kind: Group
   apiGroup: rbac.authorization.k8s.io
   name: system:nodes
   namespace: kube-system
  - kind: Group
   apiGroup: rbac.authorization.k8s.io
   name: system:serviceaccounts:kube-system
  - kind: Group
   apiGroup: rbac.authorization.k8s.io
   name: system:serviceaccounts:security-test
  # 也可授权给指定的 service account 或者用户(不推荐):
  - kind: ServiceAccount
   name: <authorized service account name>
   namespace: <authorized pod namespace>
  - kind: User
   apiGroup: rbac.authorization.k8s.io
   name: <authorized user name>
  # 授权给所有的 service accounts:
  - kind: Group
   apiGroup: rbac.authorization.k8s.io
   name: system:serviceaccounts
  # 授权给所有已认证的用户:
  - kind: Group
   apiGroup: rbac.authorization.k8s.io
   name: system:authenticated

  创建安全策略资源
 
  在集群中创建一个 PodSecurityPolicy 资源。宽松权限版本:
  复制
  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'

  严格权限版本:
  复制
  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'
     apparmor.security.beta.kubernetes.io/defaultProfileName:  'runtime/default'
  spec:
   privileged: false
   # Required to prevent escalations to root.
   allowPrivilegeEscalation: false
   requiredDropCapabilities:
     - ALL
   # Allow core volume types.
   volumes:
     - 'configMap'
     - 'emptyDir'
     - 'projected'
     - 'secret'
     - 'downwardAPI'
     # Assume that ephemeral CSI drivers & persistentVolumes set up by the cluster admin are safe to use.
     - 'csi'
     - 'persistentVolumeClaim'
     - 'ephemeral'
   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

  启用 admission controller 插件
 
  启用 admission controller 的 psp 插件有两种方式:
 
  在已存在的集群中通过修改 apiserver 的静态 manifest 文件,为 apiserver 增加启动参数 enable-admission-plugins=PodSecurityPolicy。kubelet 会自动检测到变更并重启 apiserver。下面的示例使用 sed 对原有参数进行了替换:
  复制
  $ sed -i 's/enable-admission-plugins=NodeRestriction/enable-admission-plugins=NodeRestriction,PodSecurityPolicy/' /etc/kubernetes/manifests/kube-apiserver.yaml
  1.
  或者在初始化集群时,在 kubeadm 配置文件中添加额外参数。
  复制
  apiVersion: kubeadm.k8s.io/v1beta2
  kind: ClusterConfiguration
  apiServer:
  extraArgs:
  enable-admission-plugins: "PodSecurityPolicy"
  1.
  2.
  3.
  4.
  5.
  验证 psp 的安全限制
  我们在上文授权过的 security-test 命名空间进行测试,验证 psp 对 pod 的限制条件。
 
  首先确保在集群中应用了严格版本的 psp 资源,然后尝试通过 deployment 创建一个需要使用 hostNetwork 的 pod:
 
  复制
  apiVersion: apps/v1
  kind: Deployment
  metadata:
   name: nginx-hostnetwork
  spec:
   selector:
     matchLabels:
       run: nginx
   template:
     metadata:
       labels:
         run: nginx
     spec:
       hostNetwork: true
       containers:
       - image: nginx
         imagePullPolicy: Always
         name: nginx-privileged

  创建并查看结果:
 
  复制
  $ kubectl create -f hostnetwork-pod.yaml -n security-test
  deployment.apps/nginx-hostnetwork created
  $ kubectl get deploy -n security-test nginx-hostnetwork
  NAME                READY   UP-TO-DATE   AVAILABLE   AGE
  nginx-hostnetwork   0/1     0            0           17s
  $ kubectl -n security-test get event | grep "pod security policy"
  103s        Warning   FailedCreate             deployment/nginx-hostnetwork                                Error creating: pods "nginx-hostnetwork-" is forbidden: unable to validate against any pod security policy: [spec.securityContext.hostNetwork: Invalid value: true: Host network is not allowed to be used]

  局限性
  如果有 pod 违反了安全策略,解决方案是要么调整 pod 的规格,要么修改 pod 安全策略资源。psp 资源是全局生效的,不能针对不同的命名空间设置不同的安全策略级别,这是一个很明显的局限性。
 
  另外对 psp 的授权机制也比较复杂。如果没有授权或者未创建安全策略,结果是所有 pod 被拒绝,这也导致在集群中默认开启该功能的操作难度很大。
 
  从 Kubernetes v1.21 开始,Pod Security Policy 将被弃用,并将在 v1.25 中删除。Kubernetes 引入了 Pod Security Admission 作为其替代者,我们将在下文中详细解析。
 
  Pod Security Admission
  为什么要替换 psp
  KEP-2579[2] 详细阐述了使用 Pod Security Admission 替代 Pod Security Policy 的三点主要理由:
 
  将策略与用户或 service account 绑定的模型削弱了安全性。
  功能无法流畅切换,在没有安全策略的情况下无法关闭。
  API 不一致且缺乏灵活性。
  新的 Pod Security Admission 机制在易用性和灵活性上都有了很大提升,从使用角度有以下四点显着不同:
 
  可以在集群中默认开启,只要不添加约束条件就不会触发对 pod 的校验。
  只在命名空间级别生效,可以为不同命名空间通过添加标签的方式设置不同的安全限制。
  可以为特定的用户、命名空间或者运行时设置豁免规则。
  根据实践预设了三种安全等级,不需要由用户单独去设置每一个安全条件。
  工作方式
  Pod Security Admission 将原来 Pod Security Policy 的安全条件划分成三种预设的安全等级:
 
  privileged: 不受限,向 pod 提供所有可用的权限。
  baseline:最低限度的限制策略,防止已知的特权升级。
  restricted:严格限制策略,遵循当前 Pod 加固的最佳实践。
  三种等级从宽松到严格递增,各自包含了不同限度的安全条件[3],适用于不同的 pod 工作场景。此外还可以将安全等级设置为固定的 Kubernetes 版本,这样即使集群升级到了新的版本且新版本的安全等级定义发生变化,依然可以按旧版本的安全条件对 pod 进行约束。
 
  当 pod 与安全等级冲突时,我们可通过三种模式来选择不同的处理方式:
 
  enforce:只允许符合安全等级要求的 pod,拒绝与安全等级冲突的 pod。
  audit:只将安全等级冲突记录在集群 event 中,不会拒绝 pod。
  warn:与安全等级冲突时会向用户返回一个警告信息,但不会拒绝 pod。
  audit 和 warn 模式是独立的,如果同时需要两者的功能必须分别设置两种模式。
 
  应用安全策略不再需要创建单独的集群资源,只需要为命名空间设置控制标签:
 
  复制
  pod-security.kubernetes.io/<mode>: <level>
  pod-security.kubernetes.io/<mode>-version: <version>
  1.
  2.
  下文会有更完整的示例。
 
  在旧版本启用 psa
  虽然 Pod Security Admission 是一个在 Kubernetes v1.22 引入的功能,但旧版本可以通过安装 PodSecurity admission webhook 来启用该功能,具体步骤如下:
 
  复制
  $ git clone https://github.com/kubernetes/pod-security-admission.git
  $ cd pod-security-admission/webhook
  $ make certs
  $ kubectl apply -k .
  1.
  2.
  3.
  4.
  以上来自官方文档的步骤在 v1.18.17 会有两个兼容性问题,具体问题和解决方案如下:
 
  kubectl 内置的 kustomize 版本不支持 "replacements" 字段:
  复制
  $ kubectl apply -k .
     error: json: unknown field "replacements"
  1.
  2.
   解决方案:安装最新版本的 kusomize 然后在同一目录执行
 
  复制
  $ kustomize build . | kubectl apply -f -
  1.
  manifest/50-deployment.yaml 文件中定义的 Deployment.spec.template.spec.containers[0].securityContext 字段在 v1.19 版本才开始引入,因此 v1.18 需要将该字段修改为对应的 annotation 版本,详见 Seccomp[4]:
  复制
  error: error validating "STDIN": error validating data: ValidationError(Deployment.spec.template.spec.containers[0].securityContext): unknown field "seccompProfile" in io.k8s.api.core.v1.SecurityContext; if you choose to ignore these errors, turn validation off with --validate=false
  1.
  验证 psa 的安全限制
  首先创建一个新的命名空间 psa-test 用于测试,并将其定义强制应用 baseline 安全等级,并对 restricted 等级进行警告和审计:
 
  复制
  apiVersion: v1
  kind: Namespace
  metadata:
   name: psa-test
   labels:
     pod-security.kubernetes.io/enforce: baseline
     pod-security.kubernetes.io/enforce-version: v1.18
     # We are setting these to our _desired_ `enforce` level.
     pod-security.kubernetes.io/audit: restricted
     pod-security.kubernetes.io/audit-version: v1.18
     pod-security.kubernetes.io/warn: restricted
     pod-security.kubernetes.io/warn-version: v1.18

  接着在该命名空间中创建上文示例中用过的 deployment:
 
  复制
  $ kubectl create -f hostnetwork-pod.yaml -n psa-test
  deployment.apps/nginx-hostnetwork created
  $ kubectl get deploy -n psa-test nginx-hostnetwork
  NAME                READY   UP-TO-DATE   AVAILABLE   AGE
  nginx-hostnetwork   0/1     0            0           17s
  $ kubectl -n psa-test get event | grep PodSecurity
  104s        Warning   FailedCreate        replicaset/nginx-hostnetwork-644cdd6598   Error creating:。

(编辑:ASP站长网)

    网友评论
    推荐文章
      热点阅读