第一部分:控制平面
Control Plane 是 Kubernetes 的“大脑”。通过 Control Plane,可以整体浏览集群上所有容器和 Pod 的运行情况 。Control Plane 可以调度新 Pod (包含具有对其 Parent Node 有 root 访问权限的容器),也可以读取集群中存储的所有 secret。但当 Control Plane 被访问时,空闲时或有流量通过网络传输进来时,就要格外小心意外损坏和恶意攻击了。
1、TLS 无处不在
应该为支持 TLS 的每个组件启用 TLS 以防止流量嗅探(traffic sniffing)、验证服务器身份,以及(对 mutual TLS)验证客户端的身份。
值得注意的是,有些组件和安装方法可以越过 HTTP 启用本地端口,管理员应该熟悉每个组件的设置,以提高自己识别潜在不安全流量的能力。
Lucas Käldström(Kubernetes 社区 SIG lead & contributor) 的这个网络图展示了应用 TLS 理想情况:清晰地列出了主服务器上的所有组件之间、Kubelet 和 API 服务器之间关系。Kelsey Hightower 大作《Kubernetes The Hard Way 》中,也给出了详细的操作说明,以及安全模型文档。
在以前,自动伸缩 Kubernetes Node 非常困难,因为每个 Node 都需要一个 TLS Key 来连接到 Master,而把 secret 放入基本镜像不是很好实现。Kubelet TLS bootstrapping 为新的 Kubelet 提供了创建 Certificate Signing Request(CSR)文件的能力,以便在启动时间内生成 Certificate。
2、启用最小权限的 RBAC,禁用 ABAC并监控日志
RBAC(Role-Based Access Control ) 可以为用户访问资源提供细粒度策略管理,例如对 Namespace 的访问。
Kubernetes 1.6 发布以后,Kubernetes 的 ABAC(Attribute Based Access Control )已被 RBAC 取代,因此不应在 API 服务器上启用,应使用 RBAC 替代如下:
或者使用这个标记在 GKE 中禁用 ABAC:
对于集群服务和文档来说,RBAC 策略有很多很好的例子。细粒度 RBAC 策略可以通过 audit2rbac 在 Audit Log 中提取。
在 Pod 受损时,错误或过度宽松的 RBAC 策略都是安全威胁。保持最低权限,不断审查和改进 RBAC 规则,这应被视为团队在其开发生命周期中应偿还的“技术债务”(开发团队在设计或架构选型时,从短期效应的角度选择了一个易于实现的方案。但从长远来看,这种方案会带来更消极的影响,即开发团队所欠的债务)的一部分。
Audit Logging(1.10 版本中已处于 beta 阶段)可在有效负载(例如请求和响应)以及元数据级别提供可自定义的 API 日志(log) 记录,方便组织根据安全策略进行调整 ,GKE 也提供了默认设置来帮助用户入门。
对于 Get、List 、Watch 等读取请求来说,只有请求对象是被保存在 Audit Log 中的,而响应对象并不保存在内。对于涉及 Secret 和 ConfigMap 等敏感数据的请求,只有元数据可被导出;所有其他请求的请求和响应对象都保存在 Audit Log 中。
需谨记:一旦遭遇攻击,把这些 Log 保留在集群中的行为将成为安全威胁。和其他安全敏感日志一样,这些 log 应在集群外部传输,以防止在发生破坏时被篡改。
3、对 API 服务器使用第三方验证
在整个组织中,集中身份验证和授权(也称为单点登录)有助于为用户提供 Onboarding,Offboarding 和一致权限。
将 Kubernetes 与第三方 Auth 提供者(如 Google 或 GitHub ) 集成在一起,使用远程平台的标识保证(由 2FA 之类的东西支持),并防止管理员重新配置 Kubernetes API 服务器以添加或删除用户。
Dex(CoreOS 开源项目)是一个带可插拔连接器的 OpenID Connect(OIDC)和 OAuth 2.0 的解决方案。Pusher 通过一些自定义工具在此基础上做了一些改进,另外还有一些其他工具可用,但应用场景略有不同。
4、分离你的 etcd 集群
etcd 是 Kubernetes 中一个存储状态和 secret 信息的关键组件,它的安全保护措施与集群其他部分略有不同。
对 API Server 的 etcd 写访问(Write access)等同于获得整个集群的 root 权限,而读访问(Read access)甚至可以被轻易利用来升级权限。
Kubernetes scheduler 将搜索 etcd,寻找那些没有 nodeSelector 标签的 Pod 。然后将找到的 Pod 调度到可用的 Node 上。提交的 Pod 验证是在写入 etcd 之前由 API 服务器执行的,因此直接写入 etcd 的恶意用户可以绕过许多安全机制,例如 PodSecurityPolicies 的许可控制。
etcd 应配置同级的用户端 TLS 证书,并部署在专属 Node 上。为了减少私钥被盗和或通过 Worker Node 进入,集群也可以成为 API 服务器的防火墙。
5、轮换加密密钥
保证安全性最好的办法就是定期轮换加密密钥和证书。
当现有的凭证到期时,Kubernetes 会通过创建新的 CSRs 来自动轮换某些证书(特别是 kubelet 用户端和服务器证书)。
但是,API server 用于加密 etcd 值的对称加密密钥(Symmetric encryption keys)并不能进行自动轮换,必须手动执行。主访问确实需要这种轮换机制,因此很多托管服务(例如 GKE 或 AKS)把这个问题从运维人员那单独抽取出来。
第二部分:工作负载
我们一般对 Control Plane 的最低要求就是能保障集群安全地运行。但是,就像载满货物的船一样,船上的集装箱必须在发生意外事故或险情时保护好这些货物。
Kubernetes workload(Pod、Deployment、Job、Set 等)也是如此。在部署时,他们可能备受信任,可一旦它们暴露在互联网上,就存在被恶意利用的风险。以最低权限运行 workload 并加强其运行时配置,有助于降低此风险。
6、使用Linux安全功能和PodSecurityPolicies
Linux 具有许多重叠的安全扩展功能(如 Capabilities 机制,SELinux,AppArmor,seccomp-bpf),都可以向应用程序提供最低权限的配置。
像 bane (由 Docker 的核心维护者之一,Jessie Frazelle 创建以简化配置文件的编写难度的工具) 这样的工具可以帮助生成 AppArmor 配置文件,和 seccomp 配置文件的 docker-slim,但值得注意的是,在验证应用这些策略的副作用时,最好对在应用程序中运行所有代码路径进行综合测试。
PodSecurityPolicies 可用于强制使用安全扩展和其他 Kubernetes 安全指令。PodSecurityPolicies 可以保证 Pod 在满足一定条件时,才能提交到 API server,包括安全配置文件,权限标记(Privileged flag)以及主机网络、进程或 IPC namespace 共享。这些指令可以有效防止容器化进程“逃离”其隔离边界,因此非常重要。
7、静态分析 YAML
当 PodSecurityPolicies 拒绝对 API server 进行访问的情况下,静态分析代码在开发流程中,也可以用来模拟一个组织的合规性要求或风险偏好。
敏感信息不应存储在 Pod 类型的 YAML 资源(Deployment、Pods、Sets 等)中,敏感的 configmap 和 secret 应使用诸如 Vault(CoreOS 运营),git-crypt,sealed secret 或云提供商提供 KMS 服务等进行加密。
YAML 配置的静态分析常用来为运行时安全建立基线。kubesec 可为资源生成风险评分:
kubetest 是 Kubernetes 配置的一个单元测试框架:
这些工具适用于“左移测试”(在开发周期的早期进行检查和验证)。开发阶段的安全测试为用户提供了关于代码和配置的快速反馈,虽然这些反馈可能会被以后的手动或自动检查拒绝,但是确实会减少引入更多安全操作时产生的摩擦。
8、以非 root 用户的身份运行容器
以 root 身份运行的容器,通常具有比其 workload 更大的权限,一旦受到损害,它就会帮助攻击者发起进一步的攻击。
目前,容器仍然依赖于传统的 Unix 安全模型(称为自主访问控制或 DAC),以文件形式为主,权限授予 User 和组。
User Namespace 在 Kubernetes 上不可用。这意味着容器的 User ID 表会映射到主机 User 表上,并且容器内的 root user 在运行进程时也会在主机上以 root 身份运行。虽然我们有多层安全机制来防止容器中断,但仍不推荐在容器内以 root 身份运行。
许多容器镜像都使用 root user 运行 PID 1 ,如果该进程受到攻击,攻击者就会在容器中拥有 root 权限,此时任何错误配置都非常容易被利用。
为了将容器镜像移动给 non-root user(OpenShift 上是默认设置的 ),BitNami 做了很多努力,这确实可以简化向 non-root 容器镜像迁移过程。
以下 PodSecurityPolicy 可防止使用 root user 在容器内运行进程,并升级到 root:
Non-root 容器是无法绑定到 1024 以下的特权端口的(这是由 CAP_NET_BIND_SERVICE 内核功能限制的),但 Services 可用来来掩盖这一事实。在这个例子中,虚构的 MyApp 应用程序绑定到其容器中 8443 端口上,但是 Service 通过将请求代理到 targetPort,在 443 上进行暴露:
如果必须使用 non-root user 运行 Workload, 那就直到用户 Namespace 可用也不改变、在容器运行时中运行没有 root 的容器也能保持持续工作。
9、使用网络策略
默认情况下,Kubernetes 网络允许所有 Pod 到 Pod 的流量,也可以使用网络策略进行限制。
传统 Service 受防火墙限制,每个 Service 都必须使用静态 IP 和端口范围(Port ranges)。正因为这些 IP 很少发生变化,所以它们长期被用作一种确认身份的形式。但是容器很少有静态 IP,它们迅速迭代,迅速重建,Service Discovery 也替代了静态 IP 地址。这些特点都意味着防火墙的配置和审查变得更加困难。
由于 Kubernetes 将其所有系统状态都存储在 etcd 中,如果 CNI 网络插件可行的话,它就可以配置动态防火墙。事实上 Calico,Cilium,kube-router,Romana 和 Weave Net 都支持网络策略。
应该注意的是在这里标记的策略是失败关闭的,因为它缺少一个 podSelector 作为默认通配符:
下面是一个 NetworkPolicy 示例,它拒绝除 UDP 53(DNS)之外的所有出口,同时阻止到应用程序入站连接。但 NetworkPolicies 是有状态的网络隔离,因此对出站请求的回复仍然会到达应用程序。
Kubernetes 网络策略不能用于 DNS 域名。这是因为 DNS 可以解决许多 IP loop,或者基于调用 IP 动态地解决问题,所以网络策略只能应用于固定的 IP 或 podSelector (对于动态的 Kubernetes IP)。
最佳做法是首先拒绝 Namespace 的所有流量,然后递增添加路由以允许应用程序通过验收测试。这个过程会比较复杂,因为 Control Plane 会为了高度并行化的 nmap DevSecOps 工作流将 netassert-network 的安全测试一并攻击:
云提供商 Metadata APIs 是不断升级的,为了防止意外错误配置产生, 确认 API 在容器网络上被阻止的特定测试是有必要的。
10、扫描镜像,运行 IDS
Kubernetes 通过一系列的 Admission Controller 允许 Pod 进入集群,这些 Controller 应用于 Pod 和其他资源中,如 Deployment。这些 Controller 可以验证每个 Pod 的入口或更改其内容,现在它们支持后端 Webhook。
容器镜像扫描工具可以利用这些 Webhook,在镜像被部署到集群之前,对镜像进行验证。验证失败的镜像会被拒绝访问。
根据已知漏洞,扫描容器镜像可以缩短攻击者攻击暴露 CVE 的时间。可以在部署 Pipeline 中使用 CoreOS 家的 Clair 和 Aqua 家的 Micro Scanner 等免费工具,以防止在部署时关键镜像有漏洞。
像 Grafeas 这样的工具可以存储镜像元数据,以便针对容器的唯一签名(内容可寻址 hash)进行持续合规性漏洞检查。这意味着使用该 hash 扫描容器镜像与扫描生产中部署的镜像相同,这个过程可以持续完成而无需访问生产环境。
未知的 “Zero Day attack” 始终存在,因此应在 Kubernetes 中部署入侵检测工具,如 Twistlock,Aqua 和 Sysdig Secure。IDS 可以检测容器中的异常行为并暂停或将其扼杀,另外 Sysdig 的 Falco (一个开源规则引擎)也可用。
结束语
云原生应用程序有一组更精细的轻量级安全基元,为工作负载和基础设施确保安全。这些工具的强大功能和灵活性有利也有弊;由于自动化程度不足,更容易暴露允许突破容器或其隔离模型的不安全的工作负载。
现在可供使用的防御工具比以往更多,但须谨慎行事,减小攻击面和错误配置的可能性。
然而,如果安全减慢了企业组织交付功能的步伐,安全永远不会成为“一等公民”。将持续交付原则运用于软件供应链让企业组织得以实现合规、持续审计和强制治理,又不影响公司的账本底线。
如果得到全面测试套件的支持,安全方面快速迭代最容易。这可以通过持续安全(Continuous Security)来实现——这是时间点渗透测试之外的替代方案,持续的流水线验证确保企业组织的攻击面已知,风险不断被理解和管理。
推荐阅读:
一次 HTTP 请求到底经历了什么?
一文详解 LVS、Nginx 及 HAProxy 工作原理
使用 Redis 助力高并发电商秒杀系统
Kubernetes 部署微服务项目踩坑经验分享
2020年DevOps的七大发展趋势
聊聊 CI/CD 场景价值
全球 IPv4 正式耗尽,过渡 IPv6 必知知识点
10个建议,让你的 Web 应用性能至少提升3倍!
小团队如何从零搭建一个自动化运维体系?
值得一看的运维技能图谱
对于Ping的过程,你真的了解吗?
如何画出一张合格的技术架构图?
Kubernetes 企业容器云平台实战
年轻时偷的懒,迟早是要还的。点亮
在看