本文介绍如何使用部署安全措施对 Azure Kubernetes Service (AKS) 群集强制实施最佳做法。
概述
注意事项
默认情况下,在 AKS 自动中启用部署安全措施。
在整个开发生命周期中,如果 Kubernetes 资源的初始部署存在配置错误,则常会出现漏洞和其他问题。 为了减轻 Kubernetes 开发的负担,Azure Kubernetes Service(AKS)提供部署保障。 部署防护措施通过 Azure Policy 控制在 AKS 群集中强制执行 Kubernetes 最佳实践。
部署保障提供两个级别的配置:
-
Warn:在代码终端中显示警告消息,提醒你有不合规的群集配置,但仍允许请求通过。 -
Enforce:如果部署不遵循最佳做法,则通过拒绝和变更部署来强制实施合规配置。
为“警告”或“强制”配置部署安全措施后,部署安全措施会在创建或更新时以编程方式评估 Kubernetes 资源,以满足合规性要求。 部署保障还通过 Azure Policy 的符合性仪表板在 Azure portal 或 CLI 或终端中显示每个资源级别的工作负荷的聚合符合性信息。 运行不符合的工作负荷表示群集未遵循最佳做法,并且群集上的工作负荷面临群集配置导致的问题的风险。
先决条件
注意事项
群集管理员不需要Azure Policy权限来启用或禁用部署保护。 但是,需要安装Azure Policy加载项。
- 需要为 AKS 启用Azure Policy加载项。 有关详细信息,请参阅 AKS 群集上的 Enable Azure Policy。 这包括在订阅中注册
Microsoft.PolicyInsights资源供应商。
部署保障策略
下表列出了启用部署保护时,哪些策略会生效,以及它们所针对的 Kubernetes 资源。 您可以在 Azure 门户中查看 当前可用的部署安全措施,它们被定义为 Azure 策略,或在 适用于 Azure Kubernetes 服务的 Azure 策略内置定义 中查看。 此集合背后的意图是创建适用于大多数用户和用例的常见和通用最佳做法列表。
| 部署安全措施策略 | 变更后的结果(如果有) |
|---|---|
| 无法编辑单个节点 | 空值 |
| 必须定义 Kubernetes 群集容器 CPU 和内存资源请求 | 设置默认 CPU 和内存请求并强制实施最小值。 有关详细信息,请参阅 资源请求可变器。 |
| 必须具有反关联规则或 topologySpreadConstraintsSet | 添加 Pod 反关联规则和拓扑分布约束,以提高工作负荷分布。 有关详细信息,请参阅 反相关性和拓扑分散变异器。 |
| 无特定于 AKS 的标签 | 空值 |
| Kubernetes 群集容器应只使用允许的映像 | 空值 |
| 保留的系统池标记 | 如果未设置,则从用户节点池中删除 CriticalAddonsOnly 污点。 AKS 使用 CriticalAddonsOnly 污点让客户 Pod 远离系统池。 此配置可确保 AKS 组件与客户 Pod 之间的明确分离,并防止驱逐不能容忍 CriticalAddonsOnly 污点的客户 Pod。 |
| 确保群集容器已配置就绪情况或运行情况探测 | 空值 |
| Kubernetes 群集应使用容器存储接口 (CSI) 驱动程序的存储类 | 空值 |
| Kubernetes 群集服务应使用唯一选择器 | 空值 |
| Kubernetes 群集容器映像不应包含最新的映像标记 | 空值 |
如果要提交部署保障的想法或请求,请在 AKS GitHub 存储库中提出问题并将 [Deployment Safeguards request] 添加到标题开头。
资源请求可变器
将部署保护措施设置为 Enforce 级别时,资源请求可变器会自动设置 CPU 和内存请求以及未定义这些请求的容器的限制,或者其值低于最低阈值。
默认值
如果未指定任何资源,则 mutator 将设置以下默认值:
| 资源 | 请求 | 限度 |
|---|---|---|
| CPU | 500m | 500m |
| 内存 | 2048Mi (2Gi) | 2048Mi (2Gi) |
最低强制措施
指定资源但低于阈值时,可变器将强制实施以下最小值:
| 资源 | 最小值 |
|---|---|
| CPU | 100米 |
| 内存 | 100Mi |
了解资源单位
CPU 单位:
-
m= millicores (1m= CPU 核心的千分之一) -
1000m= 1 个完整 CPU 核心 -
500m= 0.5 CPU 核心(半核) -
100m= 0.1 个 CPU 核心(核心的 10%)
内存单位:
-
Mi= Mebibytes (binary: 1 Mi = 1,024 × 1,024 字节) -
Gi= Gibibytes (binary: 1 Gi = 1,024 Mi) 2048Mi=2Gi-
100Mi≈ 105 MB
CPU 变异规则
可变器对 CPU 资源应用以下逻辑:
| Scenario | Action |
|---|---|
| CPU 请求和限制都缺失 | 将这两者都设置为 500m (默认值) |
CPU 请求存在,但小于 100m |
将请求设置为 100m (最小值) |
CPU 限制存在,但小于 100m |
将限制设置为 100m (最小值) |
| 仅存在 CPU 请求 | 将请求设置为与限制相等 |
| 仅存在 CPU 限制 | 将请求设置为与限制相等 |
内存突变规则
可变器对内存资源应用以下逻辑:
| Scenario | Action |
|---|---|
| 内存请求和限制都缺失 | 将这两者都设置为 2048Mi (默认值) |
内存请求存在,但小于 100Mi |
将请求设置为 100Mi (最小值) |
内存限制存在,但小于 100Mi |
将限制设置为 100Mi (最小值) |
| 仅存在内存请求 | 保持现状(不添加限制) |
| 仅存在内存限制 | 保持原样(未添加请求) |
Kubernetes 服务质量(QoS)类修正
应用 CPU 和内存突变后,如果请求值超出同一资源类型的限制,则可变器会限制请求以匹配限制。 此修补程序维护有效的 Kubernetes 服务质量(QoS)类配置。
已经变异的案例
资源请求变换器在以下情况下应用更改:
-
空资源:没有 CPU 或内存请求或限制的容器接收默认值(
500mCPU、2048Mi内存)。 -
低于最低阈值:将 CPU 请求或以下
100m限制增加到100m。 内存请求或以下100Mi限制将增加到100Mi。 - QoS 方案无效:当请求超出限制时,请求会降低以匹配限制。
- 部分资源规范:仅有请求或仅有限制的容器(但不包括两者)在指定时强制实施最小值。
- 多个容器:Pod 中的所有容器都经过适当处理和变更。
- 已启用的命名空间:只有启用了保护的命名空间中的工作负荷才会被改变。
未改变的案例
资源请求可变器在以下方案中不应用更改:
- 排除的命名空间:排除安全措施的命名空间中的工作负荷保持不变。
- 已符合要求的资源:已具有超过最低阈值的请求和限制的容器保持不变。
- 有效的 QoS 配置:当请求小于或等于限制且两个值都高于最小值时,不会发生任何更改。
反相关性和拓扑分散变异器
将部署保护措施设置为 Enforce 级别时,反关联和拓扑分布可变器会自动添加 Pod 反关联规则和拓扑分布约束,以提高节点之间的工作负荷分布。
当变量器运行时
仅当满足以下所有条件时,才会运行变异器:
- Pod 反相关性和拓扑分布约束在工作负荷上都不存在。
- 命名空间不会从部署安全措施中排除。
- 部署保障机制处于
Enforce模式。 - 工作负荷没有
kubernetes.azure.com/managedby=aks标签。
突变器添加的内容
标签标识:变异器使用以下标签优先级标识 Pod:
-
app标签(第一优先级) -
app.kubernetes.io/name标签(次优先级) - 创建
default-antiaffinity-applabel=<workload-name>标签(回退)
Pod 反亲和性:添加一个权重为 100 的优先 Pod 反亲和性规则,该规则更倾向于在不同节点上调度具有匹配标签的 Pod。 使用拓扑密钥 kubernetes.io/hostname。
拓扑分布约束:添加具有以下设置的约束:
| 设置 | 价值 |
|---|---|
| MaxSkew | 1(允许每个节点的 Pod 数量最多差异 1 个) |
| 当无法满足时 | ScheduleAnyway (尽最大努力,不阻止计划) |
| 拓扑密钥 | kubernetes.io/hostname |
已经变异的案例
反相关性和拓扑分布变异器在以下方案中应用更改:
-
具有
app标签的工作负荷:将app标签值用于反相关性和拓扑分布选择器。 -
带有
app.kubernetes.io/name标签的工作负荷:如果没有app标签,使用该标签作为选择器。 - 没有应用标签的工作负荷:使用工作负荷名称创建默认标签,并添加反相关性和拓扑分散规则。
- 清理工作负荷:没有现有相关性或拓扑分布约束的工作负荷接收这两种配置。
- 部分关联:具有现有节点相关性(但无 Pod 反关联)的工作负荷接收 Pod 反相关性和拓扑分布规则。
- 已启用的命名空间:突变仅发生在启用了保护的命名空间中。
未改变的案例
反相关性和拓扑分布变异器在以下方案中不应用更改:
- 现有的拓扑分布约束:完全跳过已具有任何拓扑分布约束的工作负荷。
- 现有的 Pod 反关联:会完全跳过那些具有现有必需或首选 Pod 反关联规则的工作负载。
- 排除的命名空间:排除安全措施的命名空间中的工作负荷保持不变。
- 没有可识别名称或标签的工作负载:可以正常跳过无法确定应用名称的边缘情况。
部署安全措施错误消息
本节介绍在部署保护措施检测到您可能会遇到的不合规配置时的错误消息,并提供建议的修复措施。
常规安全防护错误消息
下表列出了常规部署保障策略的错误消息:
| Policy | 错误消息 | 修复 |
|---|---|---|
| 强制实施探测 | Container <container_name> in your Pod <pod_name> has no livenessProbe. Required probes: readinessProbe, livenessProbe |
将实时性和就绪情况探测添加到每个容器。 |
| 无“最新”图像 | Please specify an explicit, versioned image tag such as '1.0' for container %v. Using explicit version tags is a best practice to ensure reproducibility, prevent unintended updates, and facilitate easier debugging and rollbacks. Avoid using the 'latest' tag because it can change over time without notice. |
使用非空且不同于 latest 的显式图像标记。 例如, nginx 不允许,但 nginx:v1.0.0 允许。 |
| 强制实施 CSI 驱动程序 |
Storage class <class_name> use intree provisioner kubernetes.io/azure-file is not allowed 或 Storage class <class_name> use intree provisioner kubernetes.io/azure-disk is not allowed |
请改用 disk.csi.azure.com 或 file.csi.azure.com。 有关详细信息,请参阅 AKS 上的 CSI 驱动程序。 |
| 资源请求 | container <container_name> has no resource requests |
将 CPU 和内存请求添加到容器。 |
| AntiAffinity 规则 | Deployment with 2 replicas should have either podAntiAffinity or topologySpreadConstraints set to avoid disruptions due to nodes crashing |
定义 podAntiAffinity 或 topologySpreadConstraints 在工作负载上。 |
| 受限标签 | Label kubernetes.azure.com is reserved for AKS use only |
从工作负荷中删除标签。 |
| 受限节点编辑 | Tainting or labeling individual nodes is not recommended. Please use Azure CLI to taint/label node pools instead |
使用Azure CLI来排斥或标记节点池,而不是单个节点。 |
| 受限污点 | Taint with key CriticalAddonsOnly is reserved for the system pool only |
不要用CriticalAddonsOnly污染用户节点池。 |
Pod 安全标准错误消息
注意事项
AKS 自动中已默认启用基线 Pod 安全标准。 无法停用 AKS 自动化中的基线 Pod 安全标准。
部署安全措施还支持启用基线、受限和特权 Pod 安全标准。 若要确保工作负载成功部署,请确保每个清单符合基线或受限 Pod 安全要求。 默认情况下,Azure Kubernetes Service使用 Privileged Pod 安全标准。
| Policy | 错误消息 | 修复 |
|---|---|---|
| AppArmor |
AppArmor annotation values must be undefined/nil, runtime/default, or localhost/* 或 AppArmor profile type must be one of: undefined/nil, RuntimeDefault, or Localhost |
删除 AppArmor 的任何规范。 Kubernetes 默认应用 AppArmor 设置。 在受支持的主机上,默认情况下应用 RuntimeDefault AppArmor 配置文件。 |
| 主机命名空间 |
Host network namespaces are disallowed: spec.hostNetwork is set to true 或 Host PID namespaces are disallowed: spec.hostPID is set to true 或 Host IPC namespaces are disallowed: spec.hostIPC is set to true |
将这些值设置为 false或删除指定字段。 |
| 特权容器 | Privileged [ephemeral\|init\|N/A] containers are disallowed: spec.containers[*].securityContext.privileged is set to true |
将相应的 securityContext.privileged 字段设置为 false或删除该字段。 |
| 能力 | 消息开头为 Disallowed capabilities detected |
从容器清单中删除显示的功能。 |
| HostPath 卷 | HostPath volumes are forbidden under restricted security policy unless containers mounting them are from allowed images |
移除 HostPath 卷和卷装载。 |
| 主机端口 | HostPorts are forbidden under baseline security policy |
从有问题的容器中删除主机端口规范。 |
| SELinux | SELinux type must be one of: undefined/empty, container_t, container_init_t, container_kvm_t, or container_engine_t |
将容器的 securityContext.seLinuxOptions.type 字段设置为允许的值之一。 |
| /proc 装载类型 | ProcMount must be undefined/nil or 'Default' in spec.containers[*].securityContext.procMount |
spec.containers[*].securityContext.procMount设置为Default或保留其未定义。 |
| Seccomp | Seccomp profile must not be explicitly set to Unconfined. Allowed values are: undefined/nil, RuntimeDefault, or Localhost |
请将securityContext.seccompProfile.type设置为 pod 或容器的允许值之一。 |
| Sysctls | Disallowed sysctl detected. Only baseline Kubernetes pod security standard sysctls are permitted |
删除不允许的 sysctls。 有关特定列表,请参阅 Kubernetes Pod 安全标准规范。 |
| 卷类型(仅限于 PSS 受限模式) | Only the following volume types are allowed under restricted policy: configMap, csi, downwardAPI, emptyDir, ephemeral, persistentVolumeClaim, projected, secret |
删除不属于允许类型之一的任何卷。 |
| 特权升级 (仅限 PSS 受限) | Privilege escalation must be set to false under restricted policy |
将每个容器、initContainer 和临时容器设置为spec.containers[*].securityContext.allowPrivilegeEscalationfalse。 |
| 以非管理员身份运行(仅限 PSS 受限环境) | Containers must not run as root user in spec.containers[*].securityContext.runAsNonRoot |
将每个容器、initContainer 和临时容器设置为spec.containers[*].securityContext.runAsNonRoottrue。 |
| 以非根用户身份运行(仅 PSS 受限) | Containers must not run as root user: spec.securityContext.runAsUser is set to 0 |
设置 securityContext.runAsUser 为非零值,或者在 Pod 级别及每个容器、初始化容器和临时容器中保持未定义。 |
| Seccomp(仅限于 PSS 受限模式) | Seccomp profile must be "RuntimeDefault" or "Localhost" under restricted policy |
请将securityContext.seccompProfile.type设置为 pod 或容器的允许值之一。 这不同于基线,因为受限策略不允许未定义值。 |
| 功能(受限于 PSS) |
All containers must drop ALL capabilities under restricted policy 或 Only NET_BIND_SERVICE may be added to capabilities under restricted policy |
所有容器必须删除 ALL 功能,并且只允许添加 NET_BIND_SERVICE。 |
启用部署安全措施
注意事项
使用部署保障 Enforce 级别意味着你选择加入被阻止和改变的部署。 在启用 Enforce之前,请考虑这些策略如何与 AKS 群集配合使用。
在现有群集上启用部署安全措施
使用带有 az aks safeguard create 标志的 --level 命令在启用了Azure Policy加载项的现有群集上启用部署保障。 如果要接收不合规的警告,请将 --level 设置为 Warn。 如果要拒绝或变更所有不合规的部署,请将其设置为 Enforce。
az aks safeguards create --resource-group <resource-group-name> --name <cluster-name> --level Enforce
还可以使用 --cluster 标志和指定群集资源 ID 来启用部署安全措施。
az aks safeguards create --cluster <ID> --level Enforce
如果要更新现有群集的部署保障级别,请使用新值 --level运行以下命令。
az aks safeguards update --resource-group <resource-group-name> --name <cluster-name> --level Warn
排除命名空间
还可以从部署安全措施中排除某些命名空间。 排除命名空间时,该命名空间中的活动不受 Deployment Safeguards 警告或强制措施影响。
例如,若要排除命名空间 ns1 和 ns2,可以使用带 --excluded-ns 标志的命名空间列表,列表中的命名空间用空格分隔,如以下示例所示:
az aks safeguards update --resource-group <resource-group-name> --name <cluster-name> --level Warn --excluded-ns ns1 ns2
启用 Pod 安全标准
注意事项
默认情况下,Azure Kubernetes Service (AKS) 使用 Privileged Pod 安全标准。 如果要还原到默认配置,请将 --pss-level 标志设置为 Privileged。
若要在部署安全措施中启用 Pod 安全标准,请使用--pss-level标志选择以下级别之一:Baseline或RestrictedPrivileged。
az aks safeguards update --resource-group <resource-group-name> --name <cluster-name> --level Warn --pss-level <Baseline|Restricted|Privileged>
更新部署防护版本
部署安全措施遵循 AKS 加载项版本控制方案。 部署保护的每个新版本都将作为 AKS 中的新次要版本发布。 这些更新将通过 AKS GitHub发行说明传达,并反映在文档中的“部署保障策略”表中。
若要了解有关 AKS 版本控制和加载项的详细信息,请参阅以下文档: aks-component-versions 和 aks-versioning-for-addons。
验证群集之间的合规性
部署 Kubernetes 清单后,如果群集不符合部署保障措施,CLI 或终端中会显示警告或潜在拒绝消息,如以下示例所示:
警告
$ kubectl apply -f deployment.yaml
Warning: [azurepolicy-k8sazurev1antiaffinityrules-ceffa082711831ebffd1] Deployment with 2 replicas should have either podAntiAffinity or topologySpreadConstraints set to avoid disruptions due to nodes crashing
deployment.apps/simple-web created
强制执行
使用部署保护突变时, Enforce 级别会改变 Kubernetes 资源(如果适用)。 但是,Kubernetes 资源仍需要通过所有安全措施才能成功部署。 如果任何安全措施策略失败,资源将被拒绝,不会进行部署。
$ kubectl apply -f deployment.yaml
Error from server (Forbidden): error when creating "deployment.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [azurepolicy-k8sazurev1antiaffinityrules-ceffa082711831ebffd1] Deployment with 2 replicas should have either podAntiAffinity or topologySpreadConstraints set to avoid disruptions due to nodes crashing
如果 Kubernetes 资源符合适用的突变安全措施并满足所有其他保护要求,则会成功部署它们,如以下示例所示:
$ kubectl apply -f deployment.yaml
deployment.apps/simple-web created
使用 Azure Policy 仪表板验证群集之间的合规性
若要验证部署保障是否已应用并检查群集的符合性,请导航到群集的Azure portal页,然后选择 Policies,然后选择 转到 Azure Policy。
从策略和计划列表中,选择与部署安全措施关联的计划。 你会看到一个仪表板,其中显示了 AKS 群集中的合规性状态。
注意事项
若要正确评估 AKS 群集中的合规性,Azure Policy计划的范围必须限定为群集的资源组。
禁用部署安全措施
若要在群集上禁用部署安全措施,请使用 delete 命令。
az aks safeguards delete --resource-group <resource-group-name> --name <cluster-name>
FAQ
我可以创建自己的突变吗?
否。 如果你对安全措施有想法,请在 AKS GitHub 存储库中创建一个 issue并将 [Deployment Safeguards request] 添加到标题开头。
在“Enforcement”中,我可以挑选需要的变更吗?
否。 部署安全措施要么全有,要么全无。 启用警告或强制实施后,所有安全措施都处于活动状态。
为什么即使部署资源未遵循最佳做法,还是得到接纳?
部署安全措施通过Azure Policy控制措施强制执行最佳做法标准,并具有针对 Kubernetes 资源进行验证的策略。 若要评估和强制实施群集组件,Azure Policy 扩展了 Gatekeeper。 守护程序强制目前还在 fail-open 模型中运行。 由于无法保证 Gatekeeper 响应我们发起的网络请求,因此,在这种情况下,我们确保跳过验证,以便拒绝操作不会阻止您的部署。
若要了解详细信息,请参阅 Gatekeeper 中的 workload 验证。
后续步骤
- 详细了解运行 AKS 群集的最佳做法。