From 485cf6bb23e8f4bee7a4617ad235dbd9b6f7f69c Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Sun, 27 Feb 2022 10:00:16 +0800 Subject: [PATCH] [zh] Translate the migrating from PSP page --- .../migrate-from-psp.md | 669 ++++++++++++++++-- 1 file changed, 622 insertions(+), 47 deletions(-) diff --git a/content/zh/docs/tasks/configure-pod-container/migrate-from-psp.md b/content/zh/docs/tasks/configure-pod-container/migrate-from-psp.md index db9141bd13..9c0715c99f 100644 --- a/content/zh/docs/tasks/configure-pod-container/migrate-from-psp.md +++ b/content/zh/docs/tasks/configure-pod-container/migrate-from-psp.md @@ -33,61 +33,636 @@ admission controller. This can be done effectively using a combination of dry-ru --> - 确保 `PodSecurity` [特性门控](/docs/reference/command-line-tools-reference/feature-gates/)被启用。 + +本页面假定你已经熟悉 [Pod 安全性准入](/zh/docs/concepts/security/pod-security-admission/)的基本概念。 + -## 步骤 {#steps} +## 方法概览 {#overall-approach} + +你可以采取多种策略来完成从 PodSecurityPolicy 到 Pod 安全性准入 +(Pod Security Admission)的迁移。 +下面是一种可能的迁移路径,其目标是尽可能降低生产环境不可用的风险, +以及安全性仍然不足的风险。 + + + +0. 确定 Pod 安全性准入是否对于你的使用场景而言比较合适。 +1. 审查名字空间访问权限。 +2. 简化、标准化 PodSecurityPolicy。 +3. 更新名字空间: + 1. 确定合适的 Pod 安全性级别; + 2. 验证该 Pod 安全性级别可工作; + 3. 实施该 Pod 安全性级别; + 4. 绕过 PodSecurityPolicy。 +4. 审阅名字空间创建过程。 +5. 禁用 PodSecurityPolicy。 --- **如果你的集群中配置了变更式的 PodSecurityPolicy,将它们删除。** - - 复制所有变更式 PSP 复制到非变更式版本中。 - - 更新所有授权使用那些变更式 PSP 的 ClusterRole,使之也能为非变更式版本鉴权。 - - 检视使用了变更式 PSP 的 Pod,与拥有该代码的人一起将其迁移到合法的、非变更式的资源。 - - 删除变更式 PSP。 +## 0. 确定是否 Pod 安全性准入适合你 {#is-psa-right-for-you} -- **为每个名字空间选择一个兼容的策略级别。** - 要分析名字空间中已有的资源才能作出此决定。 - - 审阅不同 [Pod 安全标准](/zh/docs/concepts/security/pod-security-standards)的需求。 - - 评估禁用 PSP 控制器所带来的特权级变化。 - - 当 PodSecurityPolicy 中的设置介于两种策略级别之间时,考虑: - - 选择一个安全许可*略弱*的 PodSecurity 级别,可能需要调整负载本身, - 使之能够在较严格的策略下工作。 - - 选择一个安全许可*略强*的 PodSecurity 级别,从而避免干扰或变更负载本身。 - 不过这样做可能会让负载的作者在名字空间中拥有超出预期的权限。 - -- **在 `warn` 和 `audit` 模式下应用所选的策略。** - 这样做会让你了解 Pod 会如何对新的策略作出反应,同时不会破坏现有负载。 - 反复调试你的[Pod 配置](/zh/docs/concepts/security/pod-security-admission#configuring-pods) - 直到它们与所选的策略匹配。 -- 用 `enforce` 模式下应用策略。 -- 在 `--enable-admission-plugins` 标志中去除 `PodSecurityPolicy`。 +Pod 安全性准入被设计用来直接满足最常见的安全性需求,并提供一组可用于多个集群的安全性级别。 +不过,这一机制比 PodSecurityPolicy 的灵活度要低。 +值得注意的是,PodSecurityPolicy 所支持的以下特性是 Pod 安全性准入所不支持的: + + +- **设置默认的安全性约束** - Pod 安全性准入是一个非变更性质的准入控制器, + 这就意味着它不会在对 Pod 进行合法性检查之前更改其配置。如果你之前依赖于 PSP 的这方面能力, + 你或者需要更改你的负载以满足 Pod 安全性约束,或者需要使用一个 + [变更性质的准入 Webhook](/zh/docs/reference/access-authn-authz/extensible-admission-controllers/) + 来执行相应的变更。进一步的细节可参见后文的[简化和标准化 PodSecurityPolicy](#simplify-psps)。 + +- **对策略定义的细粒度控制** - Pod 安全性准入仅支持 + [三种标准级别](/zh/docs/concepts/security/pod-security-standards/)。 + 如果你需要对特定的约束施加更多的控制,你就需要使用一个 + [验证性质的准入 Webhook](/zh/docs/reference/access-authn-authz/extensible-admission-controllers/) + 以实施这列策略。 + +- **粒度小于名字空间的策略** - PodSecurityPolicy 允许你为不同的服务账户或用户绑定不同策略, + 即使这些服务账户或用户隶属于同一个名字空间。这一方法有很多缺陷,不建议使用。 + 不过如果你的确需要这种功能,你就需要使用第三方的 Webhook。 + 唯一的例外是当你只需要完全针对某用户或者 + [RuntimeClasses](/zh/docs/concepts/containers/runtime-class/) 赋予豁免规则时, + Pod 安全性准入的确也为豁免规则暴露一些 + [静态配置](/zh/docs/concepts/security/pod-security-admission/#exemptions)。 + + +即便 Pod 安全性准入无法满足你的所有需求,该机制也是设计用作其他策略实施机制的 +_补充_,因此可以和其他准入 Webhook 一起运行,进而提供一种有用的兜底机制。 + + +## 1. 审查名字空间访问权限 {#review-namespace-permissions} + + +Pod 安全性准入是通过[名字空间上的标签](/zh/docs/concepts/security/pod-security-admission/#pod-security-admission-labels-for-namespaces) +来控制的。这也就是说,任何能够更新(或通过 patch 部分更新或创建) +名字空间的人都可以更改该名字空间的 Pod 安全性级别,而这可能会被利用来绕过约束性更强的策略。 +在继续执行迁移操作之前,请确保只有被信任的、有特权的用户具有这类名字空间访问权限。 +不建议将这类强大的访问权限授予不应获得权限提升的用户,不过如果你必须这样做, +你需要使用一个 +[准入 Webhook](/zh/docs/reference/access-authn-authz/extensible-admission-controllers/) +来针对为 Namespace 对象设置 Pod 安全性级别设置额外的约束。 + + +## 2. 简化、标准化 PodSecurityPolicy {#simplify-psps} + + +在本节中,你会削减变更性质的 PodSecurityPolicy,去掉 Pod 安全性标准范畴之外的选项。 +针对要修改的、已存在的 PodSecurityPolicy,你应该将这里所建议的更改写入到其离线副本中。 +所克隆的 PSP 应该与原来的副本名字不同,并且按字母序要排到原副本之前 +(例如,可以向 PSP 名字前加一个 `0`)。 +先不要在 Kubernetes 中创建新的策略 - 这类操作会在后文的[推出更新的策略](#psp-update-rollout) +部分讨论。 + + +### 2.a. 去掉纯粹变更性质的字段 {#eliminating-mutaging-fields} + + +如果某个 PodSecurityPolicy 能够变更字段,你可能会在关掉 PodSecurityPolicy +时发现有些 Pod 无法满足 Pod 安全性级别。为避免这类状况, +你应该在执行切换操作之前去掉所有 PSP 的变更操作。 +不幸的是,PSP 没有对变更性和验证性字段做清晰的区分,所以这一迁移操作也不够简单直接。 + + +你可以先去掉那些纯粹变更性质的字段,留下验证策略中的其他内容。 +这些字段(也列举于[将 PodSecurityPolicy 映射到 Pod 安全性标准](/zh/docs/reference/access-authn-authz/psp-to-pod-security-standards/)参考中) +包括: + + +- `.spec.defaultAllowPrivilegeEscalation` +- `.spec.runtimeClass.defaultRuntimeClassName` +- `.metadata.annotations['seccomp.security.alpha.kubernetes.io/defaultProfileName']` +- `.metadata.annotations['apparmor.security.beta.kubernetes.io/defaultProfileName']` +- `.spec.defaultAddCapabilities` - 尽管理论上是一个混合了变更性与验证性功能的字段, + 这里的设置应该被合并到 `.spec.allowedCapabilities` 中,后者会执行相同的验证操作, + 但不会执行任何变更动作。 + +{{< caution >}} + +删除这些字段可能导致负载缺少所需的配置信息,进而导致一些问题。 +参见后文[退出更新的策略](#psp-update-rollout)以获得如何安全地将这些变更上线的建议。 +{{< /caution >}} + + +### 2.b. 去掉 Pod 安全性标准未涉及的选项 {#eliminate-non-standard-options} + + +PodSecurityPolicy 中有一些字段未被 Pod 安全性准入机制覆盖。如果你必须使用这些选项, +你需要在 Pod 安全性准入之外部署 +[准入 Webhook](/zh/docs/reference/access-authn-authz/extensible-admission-controllers/) +以补充这一能力,而这类操作不在本指南范围。 + + +首先,你可以去掉 Pod 安全性标准所未覆盖的那些验证性字段。这些字段(也列举于 +[将 PodSecurityPolicy 映射到 Pod 安全性标准](/zh/docs/reference/access-authn-authz/psp-to-pod-security-standards/)参考中,标记为“无意见”)有: + +- `.spec.allowedHostPaths` +- `.spec.allowedFlexVolumes` +- `.spec.allowedCSIDrivers` +- `.spec.forbiddenSysctls` +- `.spec.runtimeClass` + + +你也可以去掉以下字段,这些字段与 POSIX/UNIX 用户组控制有关。 + +{{< caution >}} + +如果这些字段中存在使用 `MustRunAs` 策略的情况,则意味着对应字段是变更性质的。 +去掉相应的字段可能导致负载无法设置所需的用户组,进而带来一些问题。 +关于如何安全地将这类变更上线的相关建议,请参阅后文的[推出更新的策略](#psp-update-rollout)部分。 +{{< /caution >}} + +- `.spec.runAsGroup` +- `.spec.supplementalGroups` +- `.spec.fsGroup` + + +剩下的变更性字段是为了适当支持 Pod 安全性标准所需要的,因而需要逐个处理: + + +- `.spec.requiredDropCapabilities` - 需要此字段来为 Restricted 配置去掉 `ALL` 设置。 +- `.spec.seLinux` - (仅针对带有 `MustRunAs` 规则的变更性设置)需要此字段来满足 + Baseline 和 Restricted 配置所需要的 SELinux 需求。 +- `.spec.runAsUser` - (仅针对带有 `RunAsAny` 规则的非变更性设置)需要此字段来为 + Restricted 配置保证 `RunAsNonRoot`。 +- `.spec.allowPrivilegeEscalation` - (如果设置为 `false` 则为变更性设置) + 需要此字段来支持 Restricted 配置。 + + +### 2.c. 推出更新的 PSP {#psp-update-rollout} + + +接下来,你可以将更新后的策略推出到你的集群上。在继续操作时,你要非常小心, +因为去掉变更性质的选项可能导致有些工作负载缺少必需的配置。 + +针对更新后的每个 PodSecurityPolicy: + + +1. 识别运行于原 PSP 之下的 Pod。可以通过 `kubernetes.io/psp` 注解来完成。 + 例如,使用 kubectl: + + ```shell + PSP_NAME="original" # 设置你要检查的 PSP 的名称 + kubectl get pods --all-namespaces -o jsonpath="{range .items[?(@.metadata.annotations.kubernetes\.io\/psp=='$PSP_NAME')]}{.metadata.namespace} {.metadata.name}{'\n'}{end}" + ``` + + +2. 比较运行中的 Pod 与原来的 Pod 规约,确定 PodSecurityPolicy 是否更改过这些 Pod。 + 对于通过[工作负载资源](/zh/docs/concepts/workloads/controllers/)所创建的 Pod, + 你可以比较 Pod 和控制器资源中的 PodTemplate。如果发现任何变更,则原来的 Pod + 或者 PodTemplate 需要被更新以加上所希望的配置。要审查的字段包括: + + - `.metadata.annotations['container.apparmor.security.beta.kubernetes.io/*']` + (将 `*` 替换为每个容器的名称) + - `.spec.runtimeClassName` + - `.spec.securityContext.fsGroup` + - `.spec.securityContext.seccompProfile` + - `.spec.securityContext.seLinuxOptions` + - `.spec.securityContext.supplementalGroups` + + - 对于容器,在 `.spec.containers[*]` 和 `.spec.initContainers[*]` 之下,检查下面字段: + - `.securityContext.allowPrivilegeEscalation` + - `.securityContext.capabilities.add` + - `.securityContext.capabilities.drop` + - `.securityContext.readOnlyRootFilesystem` + - `.securityContext.runAsGroup` + - `.securityContext.runAsNonRoot` + - `.securityContext.runAsUser` + - `.securityContext.seccompProfile` + - `.securityContext.seLinuxOptions` + +3. 创建新的 PodSecurityPolicy。如果存在 Role 或 ClusterRole 对象为用户授权了在所有 PSP + 上使用 `use` 动词的权限,则所使用的的会是新创建的 PSP 而不是其变更性的副本。 +4. 更新你的鉴权配置,为访问新的 PSP 授权。在 RBAC 机制下,这意味着需要更新所有为原 PSP + 授予 `use` 访问权限的 Role 或 ClusterRole 对象,使之也对更新后的 PSP 授权。 + + +5. 验证:经过一段时间后,重新执行步骤 1 中所给的命令,查看是否有 Pod 仍在使用原来的 PSP。 + 注意,在新的策略被推出到集群之后,Pod 需要被重新创建才可以执行全面验证。 +6. (可选)一旦你已经验证原来的 PSP 不再被使用,你就可以删除这些 PSP。 + + +## 3. 更新名字空间 {#update-namespace} + + +下面的步骤需要在集群中的所有名字空间上执行。所列步骤中的命令使用变量 +`$NAMESPACE` 来引用所更新的名字空间。 + + +### 3.a. 识别合适的 Pod 安全级别 {#identify-appropriate-level} + + +首先请回顾 [Pod 安全性标准](/zh/docs/concepts/security/pod-security-standards/)内容, +并了解三个安全级别。 + +为你的名字空间选择 Pod 安全性级别有几种方法: + + +1. **根据名字空间的安全性需求来确定** - 如果你熟悉某名字空间的预期访问级别, + 你可以根据这类需求来选择合适的安全级别,就像大家在为新集群确定安全级别一样。 + +2. **根据现有的 PodSecurityPolicy 来确定** - 基于 + [将 PodSecurityPolicy 映射到 Pod 安全性标准](/zh/docs/reference/access-authn-authz/psp-to-pod-security-standards/) + 参考资料,你可以将各个 PSP 映射到某个 Pod 安全性标准级别。如果你的 PSP 不是基于 + Pod 安全性标准的,你可能或者需要选择一个至少与该 PSP 一样宽松的级别, + 或者选择一个至少与其一样严格的级别。使用下面的命令你可以查看被 Pod 使用的 PSP 有哪些: + + ```sh + kubectl get pods -n $NAMESPACE -o jsonpath="{.items[*].metadata.annotations.kubernetes\.io\/psp}" | tr " " "\n" | sort -u + ``` + +3. **根据现有 Pod 来确定** - 使用[检查 Pod 安全性级别](#verify-pss-level)小节所述策略, + 你可以测试 Baseline 和 Restricted 级别,检查它们是否对于现有负载而言足够宽松, + 并选择二者之间特权级较低的合法级别。 + +{{< caution >}} + +上面的第二和第三种方案是基于 _现有_ Pod 的,因此可能错失那些当前未处于运行状态的 +Pod,例如 CronJobs、缩容到零的负载,或者其他尚未全面铺开的负载。 +{{< /caution >}} + + +### 3.b. 检查 Pod 安全性级别 {#verify-pss-level} + + +一旦你已经为名字空间选择了 Pod 安全性级别(或者你正在尝试多个不同级别), +先进行测试是个不错的主意(如果使用 Privileged 级别,则可略过此步骤)。 +Pod 安全性包含若干工具可用来测试和安全地推出安全性配置。 + + +首先,你可以试运行新策略,这个过程可以针对所应用的策略评估当前在名字空间中运行的 +Pod,但不会令新策略马上生效: + +```sh +# $LEVEL 是要试运行的级别,可以是 "baseline" 或 "restricted" +kubectl label --dry-run=server --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL +``` + + +此命令会针对在所提议的级别下不再合法的所有 _现存_ Pod 返回警告信息。 + + +第二种办法在抓取当前未运行的负载方面表现的更好:audit 模式。 +运行于 audit 模式(而非 enforcing 模式)下时,违反策略级别的 Pod 会被记录到审计日志中, +经过一段时间后可以在日志中查看到,但这些 Pod 不会被拒绝。 +warning 模式的工作方式与此类似,不过会立即向用户返回告警信息。 +你可以使用下面的命令为名字空间设置 audit 模式的级别: + +```sh +kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/audit=$LEVEL +``` + + +当以上两种方法输出意料之外的违例状况时,你就需要或者更新发生违例的负载以满足策略需求, +或者放宽名字空间上的 Pod 安全性级别。 + + +### 3.c. 实施 Pod 安全性级别 {#enforce-pod-security-level} + + +当你对可以安全地在名字空间上实施的级别比较满意时,你可以更新名字空间来实施所期望的级别: + +```sh +kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL +``` + + +### 3.d. 绕过 PodSecurityPolicy {#bypass-psp} + + +最后,你可以通过将 +{{< example file="policy/privileged-psp.yaml" >}}完全特权的 PSP{{< /example >}} +绑定到某名字空间中所有服务账户上,在名字空间层面绕过所有 PodSecurityPolicy。 + +```sh +# 下面集群范围的命令只需要执行一次 +kubectl apply -f privileged-psp.yaml +kubectl create clusterrole privileged-psp --verb use --resource podsecuritypolicies.policy --resource-name privileged + +# 逐个名字空间地禁用 +kubectl create -n $NAMESPACE rolebinding disable-psp --clusterrole privileged-psp --group system:serviceaccounts:$NAMESPACE +``` + + +由于特权 PSP 是非变更性的,PSP 准入控制器总是优选非变更性的 PSP, +上面的操作会确保对应名字空间中的所有 Pod 不再会被 PodSecurityPolicy +所更改或限制。 + + +按上述操作逐个名字空间地禁用 PodSecurityPolicy 这种做法的好处是, +如果出现问题,你可以很方便地通过删除 RoleBinding 来回滚所作的更改。 +你所要做的只是确保之前存在的 PodSecurityPolicy 还在。 + +```sh +# 撤销 PodSecurityPolicy 的禁用 +kubectl delete -n $NAMESPACE rolebinding disable-psp +``` + + +## 4. 审阅名字空间创建过程 {#review-namespace-creation-process} + + +现在,现有的名字空间都已被更新,强制实施 Pod 安全性准入, +你应该确保你用来管控新名字空间创建的流程与/或策略也被更新,这样合适的 Pod +安全性配置会被应用到新的名字空间上。 + + +你也可以静态配置 Pod 安全性准入控制器,为尚未打标签的名字空间设置默认的 +enforce、audit 与/或 warn 级别。详细信息可参阅 +[配置准入控制器](/zh/docs/tasks/configure-pod-container/enforce-standards-admission-controller/#configure-the-admission-controller) +页面。 + + +## 5. 禁用 PodSecurityPolicy {#disable-psp} + + +最后,你已为禁用 PodSecurityPolicy 做好准备。要禁用 PodSecurityPolicy, +你需要更改 API 服务器上的准入配置: +[我如何关闭某个准入控制器?](/zh/docs/reference/access-authn-authz/admission-controllers/#how-do-i-turn-off-an-admission-controller) + + +如果需要验证 PodSecurityPolicy 准入控制器不再被启用,你可以通过扮演某个无法访问任何 +PodSecurityPolicy 的用户来执行测试(参见 +[PodSecurityPolicy 示例](/zh/docs/concepts/policy/pod-security-policy/#example)), +或者通过检查 API 服务器的日志来进行验证。在启动期间,API +服务器会输出日志行,列举所挂载的准入控制器插件。 + +``` +I0218 00:59:44.903329 13 plugins.go:158] Loaded 16 mutating admission controller(s) successfully in the following order: NamespaceLifecycle,LimitRanger,ServiceAccount,NodeRestriction,TaintNodesByCondition,Priority,DefaultTolerationSeconds,ExtendedResourceToleration,PersistentVolumeLabel,DefaultStorageClass,StorageObjectInUseProtection,RuntimeClass,DefaultIngressClass,MutatingAdmissionWebhook. +I0218 00:59:44.903350 13 plugins.go:161] Loaded 14 validating admission controller(s) successfully in the following order: LimitRanger,ServiceAccount,PodSecurity,Priority,PersistentVolumeClaimResize,RuntimeClass,CertificateApproval,CertificateSigning,CertificateSubjectRestriction,DenyServiceExternalIPs,ValidatingAdmissionWebhook,ResourceQuota. +``` + + +你应该会看到 `PodSecurity`(在 validating admission controllers 列表中), +并且两个列表中都不应该包含 `PodSecurityPolicy`。 + + +一旦你确定 PSP 准入控制器已被禁用(并且这种状况已经持续了一段时间, +这样你才会比较确定不需要回滚),你就可以放心地删除你的 PodSecurityPolicy +以及所关联的所有 Role、ClusterRole、RoleBinding、ClusterRoleBinding 等对象 +(仅需要确保他们不再授予其他不相关的访问权限)。