本文已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已发生变化。
11 种方法 (不) 被黑
自项目启动以来,Kubernetes 的安全性已取得了长足的进步,但仍有一些陷阱。从控制平面开始,向上构建工作负载和网络安全,最后展望未来的安全性,以下是帮助加固集群并提高其在受到威胁时的恢复能力的便捷技巧列表。
第一部分:控制平面
控制平面是 Kubernetes 的大脑。它对集群上运行的每个容器和 Pod 都有全局视图,可以调度新的 Pod(其中可能包含对父节点拥有 root 访问权限的容器),并且可以读取集群中存储的所有 Secrets。这些宝贵的资产需要保护,以防意外泄露和恶意意图:在被访问时、静止时以及在网络传输时。
1. 全面启用 TLS
应为每个支持 TLS 的组件启用 TLS,以防止流量嗅探,验证服务器身份,并(对于双向 TLS)验证客户端身份。
请注意,某些组件和安装方法可能会通过 HTTP 启用本地端口,管理员应熟悉每个组件的设置以识别潜在的不安全流量。
Lucas Käldström 的这张网络图展示了理想情况下应应用 TLS 的一些位置:Master 上的每个组件之间,以及 Kubelet 和 API Server 之间。Kelsey Hightower 的经典指南 Kubernetes The Hard Way 提供了详细的手动说明,etcd 的安全模型 文档也提供了相关信息。

自动伸缩 Kubernetes 节点过去很困难,因为每个节点都需要 TLS 密钥才能连接到 Master,而将 Secret 烘焙到基础镜像中不是良好的实践。Kubelet TLS 引导 提供了新的 Kubelet 创建证书签名请求 (CSR) 的能力,以便在启动时生成证书。

2. 使用最小权限启用 RBAC,禁用 ABAC,并监控日志
基于角色的访问控制 (RBAC) 为用户访问资源(例如访问命名空间)提供了细粒度的策略管理。

自 1.6 版本以来,Kubernetes 的 ABAC (Attribute Based Access Control) 已被 RBAC 取代,不应在 API Server 上启用。请改为使用 RBAC。
--authorization-mode=RBAC
或者在 GKE 中使用此标志禁用它
--no-enable-legacy-authorization
关于 集群服务的 RBAC 策略 有很多 很好的示例,文档 中也有介绍。而且事情不止于此 - 可以使用 audit2rbac 从审计日志中提取细粒度的 RBAC 策略。
不正确或权限过高的 RBAC 策略在 Pod 被破坏的情况下是安全威胁。维护最小权限,并持续审查和改进 RBAC 规则,应被视为团队在其开发生命周期中建立的“技术债务卫生”的一部分。
审计日志记录(在 1.10 中为 Beta)提供可定制的 API 日志记录,包括负载(例如请求和响应)以及元数据级别。日志级别可以根据组织的安全性策略进行调整 - GKE 提供了合理的默认设置供您入门。
对于 GET、LIST 和 WATCH 等读取请求,审计日志仅保存请求对象;不保存响应对象。对于涉及敏感数据(如 Secret 和 ConfigMap)的请求,仅导出元数据。对于所有其他请求,请求和响应对象都会保存在审计日志中。
别忘了:将这些日志保存在集群内是存在安全威胁的,一旦集群受到破坏,日志可能被篡改。与其他所有安全敏感日志一样,这些日志应传输到集群外部,以防在发生安全漏洞时被篡改。
3. 为 API Server 使用第三方认证
在组织内集中进行认证和授权(即单点登录)有助于用户入职、离职以及一致的权限管理。.
将 Kubernetes 与第三方认证提供商(如 Google 或 GitHub)集成,利用了远程平台的身份保证(由双重认证等提供支持),并避免了管理员必须重新配置 Kubernetes API Server 来添加或删除用户。
Dex 是一个带有可插拔连接器的 OpenID Connect Identity (OIDC) 和 OAuth 2.0 提供商。Pusher 通过 一些自定义工具 更进一步,还有一些 其他 辅助工具 可用,用于 slightly different 用例。
4. 隔离并为 etcd 集群设置防火墙
etcd 存储状态和 Secret 信息,是 Kubernetes 的一个关键组件 - 应与集群的其余部分区别对待。
对 API Server 的 etcd 的写访问权限等同于获得整个集群的 root 权限,即使是读访问权限也可以相当容易地用于提升权限。
Kubernetes 调度器会搜索 etcd 中没有节点的 Pod 定义。然后将其找到的 Pod 发送到可用的 Kubelet 进行调度。提交的 Pod 在写入 etcd 之前由 API Server 执行验证,因此恶意用户直接写入 etcd 可以绕过许多安全机制 - 例如 PodSecurityPolicies。
etcd 应配置 对等和客户端 TLS 证书,并部署在专用节点上。为了减轻私钥被盗并在工作节点上使用,集群也可以只允许来自 API Server 的流量。
5. 轮换加密密钥
安全最佳实践是定期轮换加密密钥和证书,以限制密钥被泄露的“爆炸半径”。
Kubernetes 会 自动轮换一些证书(特别是 kubelet 客户端和服务器证书),通过在其现有凭证过期时创建新的 CSR。
然而,API Server 用于加密 etcd 值的 对称加密密钥 不会自动轮换 - 它们必须 手动轮换。执行此操作需要 Master 访问权限,因此托管服务(如 GKE 或 AKS)将此问题从操作员抽象出来。
第二部分:工作负载
通过对控制平面进行最低限度的安全配置,集群能够安全运行。但是,就像载有潜在危险货物的船一样,船上的容器必须受到保护,以防止意外事故或泄露时货物溢出。Kubernetes 工作负载(Pod、Deployment、Job、Set 等)也是如此 - 它们在部署时可能被信任,但如果它们面向互联网,则始终存在后续被利用的风险。以最小权限运行工作负载并加固其运行时配置有助于减轻此风险。
6. 使用 Linux 安全特性和 PodSecurityPolicies
Linux 内核有许多相互重叠的安全扩展(capabilities、SELinux、AppArmor、seccomp-bpf),可以配置它们以提供应用的最小权限。.
bane 等工具可以帮助生成 AppArmor 配置,docker-slim 可以用于 seccomp 配置,但要注意 - 应用这些策略后,需要一个全面的测试套件来执行应用中的所有代码路径,以验证其副作用。
PodSecurityPolicies 可用于强制使用安全扩展和其他 Kubernetes 安全指令。它们提供 Pod 必须满足才能提交到 API Server 的最低契约,包括安全配置、特权标志以及主机网络、进程或 IPC 命名空间的共享。
这些指令非常重要,因为它们有助于防止容器化进程逃逸其隔离边界,Tim Allclair 的 PodSecurityPolicy 示例 是一个全面的资源,您可以根据自己的用例进行定制。
7. 静态分析 YAML
当 PodSecurityPolicies 拒绝访问 API Server 时,静态分析也可以用于开发工作流程中,以模拟组织合规性要求或风险承受能力。
敏感信息不应存储在 Pod 类型的 YAML 资源(Deployment、Pod、Set 等)中,敏感的 ConfigMap 和 Secret 应使用 vault(使用 CoreOS 的 Operator)、git-crypt、sealed secrets 或 云提供商 KMS 等工具进行加密。
YAML 配置的静态分析可用于建立运行时安全基线。kubesec 生成资源的风险评分
{
"score": -30,
"scoring": {
"critical": [{
"selector": "containers[] .securityContext .privileged == true",
"reason": "Privileged containers can allow almost completely unrestricted host access"
}],
"advise": [{
"selector": "containers[] .securityContext .runAsNonRoot == true",
"reason": "Force the running image to run as a non-root user to ensure least privilege"
}, {
"selector": "containers[] .securityContext .capabilities .drop",
"reason": "Reducing kernel capabilities available to a container limits its attack surface",
"href": "/docs/tasks/configure-pod-container/security-context/"
}]
}
}
而 kubetest 是一个用于 Kubernetes 配置的单元测试框架
#// vim: set ft=python:
def test_for_team_label():
if spec["kind"] == "Deployment":
labels = spec["spec"]["template"]["metadata"]["labels"]
assert_contains(labels, "team", "should indicate which team owns the deployment")
test_for_team_label()
这些工具“左移”(在开发周期中更早地进行检查和验证)。开发阶段的安全测试可以快速反馈用户可能被后续手动或自动化检查拒绝的代码和配置,并可以减少引入更安全实践的阻力。
8. 作为非 root 用户运行容器
以 root 用户身份运行的容器通常具有远远超出其工作负载所需的权限,这在被破坏的情况下可能会帮助攻击者进一步发起攻击。
容器仍然依赖传统的 Unix 安全模型(称为自主访问控制或 DAC)——一切都是文件,权限授予用户和组。
Kubernetes 中未启用用户命名空间。这意味着容器的用户 ID 表映射到主机的用户表,在容器内以 root 用户身份运行进程,等同于在主机上以 root 身份运行。尽管我们有分层安全机制来防止容器逃逸,但仍然不建议在容器内以 root 身份运行。
许多容器镜像使用 root 用户运行 PID 1 - 如果该进程受到破坏,攻击者将在容器中获得 root 权限,并且任何错误配置都会更容易被利用。
Bitnami 做了很多工作 将其容器镜像迁移到 非 root 用户 (特别是 OpenShift 默认要求这样做),这可能会简化迁移到非 root 容器镜像的过程。
这个 PodSecurityPolicy 片段阻止在容器内以 root 身份运行进程,并阻止权限升级到 root。
# Required to prevent escalations to root.
allowPrivilegeEscalation: false
runAsUser:
# Require the container to run without root privileges.
rule: 'MustRunAsNonRoot'
非 root 容器无法绑定到 1024 以下的特权端口(这是由 CAP_NET_BIND_SERVICE 内核功能控制的),但服务可以隐藏这一事实。在此示例中,虚构的 MyApp 应用绑定到其容器中的 8443 端口,但服务通过将请求代理到 targetPort 将其暴露在 443 端口。
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 443
targetPort: 8443
在用户命名空间可用或 无需 root 即可运行容器 的正在进行的工作在容器运行时中落地之前,必须以非 root 用户身份运行工作负载的情况不会改变。
9. 使用网络策略
默认情况下,Kubernetes 网络允许所有 Pod 到 Pod 的流量;这可以使用 网络策略 进行限制。

传统服务通过防火墙限制,防火墙为每个服务使用静态 IP 和端口范围。由于这些 IP 地址很少改变,历史上它们一直被用作一种身份形式。容器很少有静态 IP - 它们被设计为快速失败、快速重新调度,并使用服务发现而不是静态 IP 地址。这些特性意味着防火墙配置和审查变得更加困难。
由于 Kubernetes 将所有系统状态存储在 etcd 中,因此如果 CNI 网络插件支持,它可以配置动态防火墙。Calico、Cilium、kube-router、Romana 和 Weave Net 都支持网络策略。
需要注意的是,这些策略是默认拒绝的,因此如果此处没有 podSelector,则默认为通配符。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector:
这是一个阻止除 UDP 53 (DNS) 之外所有出站连接的网络策略示例,它也阻止入站连接到您的应用程序。网络策略是有状态的,因此对出站请求的回复仍然可以到达应用程序。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: myapp-deny-external-egress
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Egress
egress:
- ports:
- port: 53
protocol: UDP
- to:
- namespaceSelector: {}
Kubernetes 网络策略不能应用于 DNS 名称。这是因为 DNS 可以通过轮询解析到许多 IP,或者根据调用 IP 动态解析,因此网络策略只能应用于固定 IP 或 podSelector(用于动态 Kubernetes IP)。
最佳实践是首先拒绝命名空间的所有流量,然后逐步添加路由以允许应用程序通过其验收测试套件。这可能变得复杂,因此 ControlPlane 开发了 netassert - 一个通过高度并行化的 nmap 进行 DevSecOps 工作流程的网络安全测试工具。
k8s: # used for Kubernetes pods
deployment: # only deployments currently supported
test-frontend: # pod name, defaults to `default` namespace
test-microservice: 80 # `test-microservice` is the DNS name of the target service
test-database: -80 # `test-frontend` should not be able to access test-database’s port 80
169.254.169.254: -80, -443 # AWS metadata API
metadata.google.internal: -80, -443 # GCP metadata API
new-namespace:test-microservice: # `new-namespace` is the namespace name
test-database.new-namespace: 80 # longer DNS names can be used for other namespaces
test-frontend.default: 80
169.254.169.254: -80, -443 # AWS metadata API
metadata.google.internal: -80, -443 # GCP metadata API
云提供商元数据 API 是持续的提权来源(如最近的 Shopify 漏洞赏金 所证明的那样),因此专门的测试来确认 API 在容器网络上被阻止有助于防范意外的错误配置。
10. 扫描镜像并运行 IDS
Web 服务器向其连接的网络呈现攻击面:扫描镜像的已安装文件可确保不存在攻击者可以利用的已知漏洞,以获取对容器的远程访问权限。IDS(入侵检测系统)会在发生此类情况时检测到它们。
Kubernetes 通过一系列准入控制器网关允许 Pod 进入集群,这些网关应用于 Pod 和其他资源(如 Deployment)。这些网关可以验证每个 Pod 的准入或更改其内容,并且现在支持后端 webhook。

容器镜像扫描工具可以使用这些 webhook 在镜像部署到集群之前验证它们。未能通过检查的镜像可以被拒绝准入。
扫描容器镜像是否存在已知漏洞可以缩短攻击者利用已披露 CVE 的时间窗口。部署流水线中应使用 CoreOS 的 Clair 和 Aqua 的 Micro Scanner 等免费工具,以防止部署具有严重可利用漏洞的镜像。
Grafeas 等工具可以存储镜像元数据,以便根据容器的唯一签名(内容寻址 哈希)进行持续合规性和漏洞检查。这意味着扫描具有该哈希值的容器镜像与扫描生产环境中部署的镜像相同,并且可以持续进行而无需访问生产环境。
未知的零日漏洞将始终存在,因此应在 Kubernetes 中部署 Twistlock、Aqua 和 Sysdig Secure 等入侵检测工具。IDS 检测容器中的异常行为并暂停或终止它 - Sysdig 的 Falco 是一个开源规则引擎,也是进入此生态系统的入口点。
第三部分:未来
安全的“云原生演进”的下一阶段似乎是服务网格,尽管普及可能需要时间——迁移涉及将复杂度从应用转移到网格基础设施,组织会急于了解最佳实践。

11. 运行服务网格
服务网格是由 Envoy 和 Linkerd 等高性能“Sidecar”代理服务器组成的加密持久连接网络。它添加了流量管理、监控和策略功能——所有这些都不需要修改微服务。
将微服务安全和网络代码卸载到一套共享的、经过实战检验的库中,使用 Linkerd 已经成为可能,而 Google、IBM 和 Lyft 引入 Istio 则在此领域提供了另一种选择。随着 SPIFFE 提供按 Pod 的加密身份和大量 其他功能,Istio 可以简化下一代网络安全的部署。
在“零信任”网络中,可能不需要传统的防火墙或 Kubernetes 网络策略,因为所有交互都通过 mTLS(双向 TLS)发生,确保双方不仅安全通信,而且已知双方服务的身份。
这种从传统网络到云原生安全原则的转变,我们预计对于那些具有传统安全思维的人来说并非易事,而 SPIFFE 的 Evan Gilman 所著的 《零信任网络》 一书是介绍这个勇敢新世界的强烈推荐读物。
Istio 0.8 LTS 已发布,项目正在迅速接近 1.0 版本。其稳定性版本控制与 Kubernetes 模型相同:一个稳定的核心,每个 API 在自己的 alpha/beta 稳定性命名空间下标识自己。预计未来几个月 Istio 的采用率将有所上升。
结论
云原生应用拥有一套更细粒度、轻量级的安全原语,用于锁定工作负载和基础设施。这些工具的力量和灵活性既是 Blessing 也是 Curse——自动化不足使得暴露不安全的工作负载变得更容易,从而允许容器或其隔离模型发生逃逸。
防御工具比以往任何时候都多,但必须谨慎减少攻击面和配置错误的潜在风险。
然而,如果安全性减缓了组织的特性交付速度,它永远不会成为首要公民。将持续交付原则应用于软件供应链,可以帮助组织在不影响业务底线的情况下实现合规性、持续审计和强制治理。
在全面的测试套件支持下,快速迭代安全措施最容易。这可以通过持续安全实现——它是点对点渗透测试的替代方案,通过持续的管道验证,确保组织了解其攻击面,并持续理解和管理风险。
这是 ControlPlane 的工作方式:如果我们能帮助您启动持续安全实践、提供 Kubernetes 安全与运维培训,或与您共同实施安全的云原生演进,请联系我们。
Andrew Martin 是 @controlplaneio 的联合创始人,并在 @sublimino 上发布关于云原生安全的推文