亚马逊AWS官方博客

将 Pod 安全策略与 Amazon EKS 集群结合使用

对于要求的功能,我们已使用Kubernetes 1.13 将其启用:Amazon Elastic Container Service for Kubernetes (EKS) 现支持 Pod 安全策略。在本篇博文中,我们将从集群管理员和开发人员的角度,审视 PSP 是什么,如何在 Kubernetes 控制平面中启用它们以及如何使用它们。

什么是 Pod 安全策略,我为何要关心?

作为集群管理员,您可能想知道如何在集群中强制执行有关 pod 运行时属性的特定策略。例如,您可能希望阻止开发人员使用未定义用户的容器运行 pod(因此,以 root 身份运行)。您可能在 pod 规范中创建了关于开发人员设置安全上下文的文档,对此开发人员可能遵循……也可能选择不遵循。无论如何,您都需要一种在集群范围内强制执行此类策略的机制。

解决方法是将 Pod 安全策略 (PSP) 作为深度防御策略的一部分。

需要注意的是,pod 的安全上下文定义了各种权限和访问控制设置,例如自主访问控制(比如基于特定用户 ID 访问文件)、功能(比如通过定义 AppArmor 配置文件)、配置 SECCOMP(通过过滤某些系统调用),以及允许您实施强制访问控制(通过 SELinux)。

另一方面,PSP 是集群范围的资源,使您可以作为集群管理员在集群中强制使用安全上下文。PSP 由 API 服务器的准入控制器强制执行。简而言之:如果 pod 规范不符合您在 PSP 中定义的内容,则 API 服务器将拒绝启动它。要使 PSP 正常工作,必须启用相应的 准入插件,并且必须授予用户权限。EKS 1.13 集群现在默认启用 PSP 准入插件,因此 EKS 用户无需进行任何操作。

通常,您希望根据最小权限原则定义 PSP:从强制执行的无根容器到只读根文件系统,到对可从主机安装的项目的限制(pod 中的容器在其上运行的 EC2 实例)。

使用

新的 EKS 1.13 集群创建了一个名为 eks.privileged 的默认策略,该策略对可接入系统的 pod 类型没有限制(相当于在禁用 PodSecurityPolicy 控制器的情况下运行集群)。

要查看 EKS 集群中现有的 pod 安全策略,请执行以下操作:

$ kubectl get psp
NAME             PRIV   CAPS   SELINUX    RUNASUSER   FSGROUP    SUPGROUP   READONLYROOTFS   VOLUMES
eks.privileged   true   *      RunAsAny   RunAsAny    RunAsAny   RunAsAny   false            *

现在,描述我们为您定义的默认策略:

$ kubectl describe psp eks.privileged

正如您在下面的输出中看到的那样 – 一切正常! 此策略允许任何类型的 pod 规范:

Name:  eks.privileged

Settings:
  Allow Privileged:                       true
  Allow Privilege Escalation:             true
  Default Add Capabilities:               <none>
  Required Drop Capabilities:             <none>
  Allowed Capabilities:                   *
  Allowed Volume Types:                   *
  Allow Host Network:                     true
  Allow Host Ports:                       0-65535
  Allow Host PID:                         true
  Allow Host IPC:                         true
  Read Only Root Filesystem:              false
  SELinux Context Strategy: RunAsAny
    User:                                 <none>
    Role:                                 <none>
    Type:                                 <none>
    Level:                                <none>
  Run As User Strategy: RunAsAny
    Ranges:                               <none>
  FSGroup Strategy: RunAsAny
    Ranges:                               <none>
  Supplemental Groups Strategy: RunAsAny
    Ranges:                               <none>

请注意,任何经过身份验证的用户都可以按照当前配置在此 EKS 集群上创建任何 pod,证明如下:

$ kubectl describe clusterrolebindings eks:podsecuritypolicy:authenticated

上述命令输出显示集群角色 eks:podsecuritypolicy:privileged 被分配给任何 system:authenticated 用户:

Name:         eks:podsecuritypolicy:authenticated
Labels:       eks.amazonaws.com/component=pod-security-policy
              kubernetes.io/cluster-service=true
Annotations:  kubectl.kubernetes.io/last-applied-configuration: ...

Role:
  Kind:  ClusterRole
  Name:  eks:podsecuritypolicy:privileged
Subjects:
  Kind   Name                  Namespace
  ----   ----                  ---------
  Group  system:authenticated

请注意,如果有多个 PSP 可用,Kubernetes 准入控制器会选择第一个成功验证的策略。策略按其名称的字母顺序排序,不改变 pod 的策略优先于变形策略。

现在让我们创建一个新的 PSP,我们称之为 eks.restrictive。首先,创建一个专用命名空间以及一个服务帐户。我们将对非管理员用户使用此服务帐户:

$ kubectl create ns psp-eks-restrictive
namespace/psp-eks-restrictive created

$ kubectl -n psp-eks-restrictive create sa eks-test-user
serviceaccount/eks-test-user created

$ kubectl -n psp-eks-restrictive create rolebinding eks-test-editor \
             --clusterrole=edit \
             --serviceaccount=psp-eks-restrictive:eks-test-user

rolebinding.rbac.authorization.k8s.io/eks-test-editor created

接下来,创建两个别名,以突出显示管理员和非管理员用户之间的区别:

$ alias kubectl-admin='kubectl -n psp-eks-restrictive'
$ alias kubectl-dev='kubectl --as=system:serviceaccount:psp-eks-restrictive:eks-test-user -n psp-eks-restrictive'

现在,使用集群管理员角色,创建一个不允许使用主机联网创建 pod 的策略:

$ cat > /tmp/eks.restrictive-psp.yaml <<EOF
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: eks.restrictive
spec:
  hostNetwork: false
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  volumes:
  - '*'
EOF

$ kubectl-admin apply -f /tmp/eks.restrictive-psp.yaml
podsecuritypolicy.policy/eks.restrictive created

另外,不要忘记删除默认的(宽容的策略)eks.privileged

$ kubectl delete psp eks.privileged
$ kubectl delete clusterrole eks:podsecuritypolicy:privileged
$ kubectl delete clusterrolebindings eks:podsecuritypolicy:authenticated

警告
在添加自己的 PSP 之前删除默认 EKS 策略 可能会损害集群。删除默认策略时,除满足新命名空间中安全上下文的 pod 外,无法在集群上创建任何 pod。对于现有集群,请确保在删除默认策略之前,创建涵盖所有正在运行的 pod 和命名空间的多个限制策略

现在,确认已创建策略:

$ kubectl get psp
NAME              PRIV    CAPS   SELINUX    RUNASUSER   FSGROUP    SUPGROUP   READONLYROOTFS   VOLUMES
eks.restrictive   false          RunAsAny   RunAsAny    RunAsAny   RunAsAny   false            *

最后,作为非特权用户(模拟开发人员),尝试创建违反策略的 pod:

$ kubectl-dev apply -f- <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: busybox
spec:
  containers:
    - name: busybox
      image: busybox
      command: [ "sh", "-c", "sleep 1h" ]
EOF

正如您所预期的那样,您会得到以下结果:

Error from server (Forbidden): error when creating "STDIN": pods "busybox" is forbidden: unable to validate against any pod security policy: []

上述操作失败,因为我们尚未授予开发人员适当的权限。换句话说,没有对开发者用户 eks-test-user 进行角色绑定。因此,让我们通过为 pod 安全策略 eks.restrictive 创建角色 psp:unprivileged 对其进行更改:

$ kubectl-admin create role psp:unprivileged \
  --verb=use \
  --resource=podsecuritypolicy \
  --resource-name=eks.restrictive

role.rbac.authorization.k8s.io/psp:unprivileged created

现在,创建 rolebinding 以授予 eks-test-user 有关 eks.restrictive策略的 use 动词。

$ kubectl-admin create rolebinding eks-test-user:psp:unprivileged \
  --role=psp:unprivileged \
  --serviceaccount=psp-eks-restrictive:eks-test-user

rolebinding.rbac.authorization.k8s.io/eks-test-user:psp:unprivileged created

验证 eks-test-user 是否可以使用 eks.restrictive

$ kubectl-user auth can-i use podsecuritypolicy/eks.restrictive
yes

此时,开发人员 eks.restrictive 用户应该能够创建一个 pod:

$ kubectl-user apply -f- <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: busybox
spec:
  containers:
    - name: busybox
      image: busybox
      command: [ "sh", "-c", "sleep 1h" ]
EOF
pod/busybox created

好的,有效! 但是,由于我们在上述 eks.restrictive 中定义的内容,我们应拒绝基于主机联网的 pod 创建:

$ kubectl-user apply -f- <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: privileged
spec:
  hostNetwork: true
  containers:
    - name: busybox
      image: busybox
      command: [ "sh", "-c", "sleep 1h" ]
EOF

Error from server (Forbidden): error when creating "STDIN": pods "privileged" is forbidden: unable to validate against any pod security policy: [spec.securityContext.hostNetwork: Invalid value: true: Host network is not allowed to be used]

非常好! 这证实了PSP eks.restrictive 按预期工作,限制开发人员创建特权 pod。

新增功能

对于使用 Kubernetes 1.13 版的所有新 EKS 集群,PSP 现在可用。对于已从先前版本升级的集群,在升级过程中会自动创建完全允许的 PSP。您的主要任务是定义适合您的环境的合理 PSP,并按上述方法启用它们。从合理的角度看,我的意思是(例如)与生产环境相比,您可以选择在开发/测试环境中减少限制。或者,同样可能的是,不同的项目或团队需要保护级别不同可能,因此 PSP 也不同。

最后一点:作为集群管理员,请务必向开发人员介绍一般的安全上下文,特别是 PSP。将 CI/CD 管道测试 PSP 作为冒烟测试,以及其他与安全相关的主题的一部分,例如通过 RBAC 角色和绑定定义的测试权限。

您可以在 Amazon EKS 文档中了解有关 PSP 的更多信息。请在下面留下任何评论,或通过 Twitter 与我联系!

— Michael