


--authorization-mode=RBAC
而在GKE中通过另一个参数来禁用ABAC:
--no-enable-legacy-authorization
网上有很多不错的例子和文档描述了如何在集群中使用RBAC策略[4]。 除此之外, 管理员还可以通过audit2rbac[5]生成的审计日志来分析调优RBAC规则。
如果将RBAC规则设置得过大或者不正确, 一旦集群中出现有问题的Pod会对整个集群产生安全威胁。 RBAC规则应该基于最小特权原则进行维护, 并持续地加之以审阅和改善。 这应被团队视为技术负债的清除手段被整合进开发流程之中。
审计日志功能(1.10中为beta阶段)提供了可定制化地对集群各组件的访问流量内容(例如请求和响应)及元数据(例如发起用户和时间戳)记录日志的功能。 日志等级可以根据组织内的安全策略进行调整。 在GKE上也有相应的设置来配置这个功能。
对于读取类请求(比如get, list和watch) ,只有请求内容会被记录在审计日志中, 响应内容不会保存。 对于涉及到敏感数据(比如Configmap和Secret)的请求, 只有元数据会被记录。 对于其他类型的请求, 请求和相应对象都会被记录。
切记:如果将审计日志保留在集群内部, 在集群已被入侵时会有安全威胁。 像这样的所有安全相关的日志都应转移到集群之外, 以避免出现安全漏洞时被篡改。
3. 为API Server启用第三方认证
在一个组织内部通过集中化的手段管理认证和授权(又被称为单点登录)有助于管理用户的添加, 删除以及一致的权限控制。
通过将Kubernetes与第三方的身份验证服务(比如Google和GitHub)整合,这样可以使用第三方平台的身份保证机制(包括双因子验证等机制), 以避免管理员不得不重新配置API Server来添加或删除用户。
Dex[6]是个OpenID Connect(OIDC)和OAuth2.0的身份服务组件。 它带有可插拔的连接器。 Pusher公司通过这个机制将Dex作为认证链的中间件将Kubernetes与其他第三方认证服务关联。 除此之外还有其他工具可以达成类似目的。
4. 将etcd集群隔离出来并加上防火墙控制
etcd中存储了集群的状态和secret, 对Kubernetes而言是至关重要的组件。 它的防护措施应该与集群的其他部分区别处理。
对API Server的etcd拥有写权限相当于获取了整个集群的root权限。 甚至仅通过对etcd的读取操作都可以相当简单地自行提权。
Kubernetes的调度器会搜索etcd找出那些已定义但还没被调度到节点上的Pod, 然后把这样的Pod发送到空闲的Kubelet节点进行部署。 在Pod信息被写进etcd之前, API Server会检查提交的Pod定义。 因此一些有恶意使用者会直接把Pod定义写入etcd, 以跳过许多诸如PodSecurityPolicy这样的安全机制。
无论是etcd集群的节点与节点, 还是节点与API Server, 他们的通信都应该配置TLS证书, 并且etcd集群应部署在专属的节点之上。 etcd集群与Kubernetes集群间也应该设置防火墙, 以避免由于私钥被盗而被从工作节点上发起攻击。
5. 定期替换密钥
定期替换密钥和证书是一条安全方面的最佳实践。 这样能减小当密钥被盗时所遭受的损害范围。
Kubernetes会在某些现有证书过期时创建新的证书签名申请来自动替换Kubelet的客户端和服务器端证书。
但是API Server用来加密etcd数据的对称密钥是无法自动替换的。 它只能手工替换。 这样的操作需要有对主节点操作的权限, 因此托管Kubernetes服务(比如谷歌的GKE和微软的AKS)会自行解决这个问题而无需管理员操心。
第二部分:工作负载
{ "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": "https://kubernetes.io/docs/tasks/configure-pod-container/security-context/" }] }}
而kubetest工具是个针对Kubernetes的YAML文件的单元测试框架。 代码例子如下:
#// 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()
以上这些工具都通过将检查和验证工作在软件开发周期中提前(shift left])到更早的开发阶段的方式, 使开发人员能更早地获得对于代码和配置的反馈, 以避免提交在之后的人工或自动检查中被退回。这样也可以减少引入更多安全实践的障碍。
8. 使用非root的用户运行容器
运行在root用户下的容器大多拥有了大大超过其所承载的服务需要的权限。 当集群被侵入时,这样的容器会让攻击者有能力执行更进一步的破坏。
容器技术依然基于传统的Unix安全模型, 叫做自主访问控制(简称DAC)。在这个模型之下,所有东西都是文件, 而权限是可以被赋予用户或用户组。
用户命名空间在Kubernetes下并没有启用, 这意味着容器中的用户表会被映射到宿主机的用户表中, 而在容器里由root身份运行的进程相当于在宿主机上也是以root身份运行。 尽管说我们有层级安全机制来防范容器发生问题, 但在容器中用root身份运行进程依然是不推荐的做法。
许多容器镜像使用root用户运行一号进程。 如果这个进程被攻破, 那么攻击者在容器中就有了root的权限, 从而会轻易放大由于集群误配置造成的安全漏洞。
Bitnami公司在将容器镜像迁移到非root用户这方面做了很多工作[9](主要由于OpenShift平台默认要求非root身份运行容器)。参考他们提供的文档可以降低管理员实施类似迁移的难度。
下列Pod安全规则的代码片段给出了防止容器中的进程以root身份运行, 以及防止进程提权到root身份的方法:
# Required to prevent escalations to root.allowPrivilegeEscalation: falserunAsUser: # Require the container to run without root privileges. rule: 'MustRunAsNonRoot'
非root的容器无法绑定小于1024的端口(可以通过配置内核参数CAP_NET_BIND_SERVICE来启用), 但使用service的特性可以使对外端口配置为1024以下。 在以下例子中,MyApp这个应用在容器中绑定了8443端口,而service将相关流量代理到443这个端口中对外暴露应用:
kind: ServiceapiVersion: v1metadata: name: my-servicespec: selector: app: MyApp ports: - protocol: TCP port: 443 targetPort: 8443
在用户命名空间在Kubernetes中可用之前,或者非root功能在容器运行时组件中获得直接支持之前, 使用非root用户运行容器依然是推荐的做法。
9. 使用网络规则
默认状态下, Kubernetes中Pod与Pod之间的网络是互通的。 可以通过使用网络规则来对此加以限制。

apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: default-denyspec: podSelector:
下列的网络规则的例子描述了如何关闭除了UDP 53(DNS端口)之外的所有对外流量。 这样也防止了进入应用的连接——这是因为网络规则是有状态面向连接的, 同一个网络连接中应用对外请求的响应也依旧会返回到应用中。
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: myapp-deny-external-egressspec: podSelector: matchLabels: app: myapp policyTypes: - Egress egress: - ports: - port: 53 protocol: UDP - to: - namespaceSelector: {}
Kubernetes的网络规则并不能被应用到DNS名字上。 这是因为一个DNS名字会可能被轮询调度解析到许多个IP地址,或者依据调用IP动态被解析到不同的目标IP地址, 而网络规则只能被应用到静态的IP或podSelector(也就是Kubernetes的动态IP机制)上。
安全上有一条最佳实践建议一开始对Kubernetes的namespace先拒绝所有流量, 然后再逐渐添加路由允许应用能通过测试场景。 这样做是非常复杂的, 可以通过下列ControlPlane公司出品的netassert这个开源工具来帮助达成最佳实践。 netassert[10]是一个安全运维工作流方面的网络安全工具, 通过高度并发运用nmap来扫描和嗅探网络:
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受攻击的案例[11]), 因此也需要有专门的测试来确定这一类API在容器网络中被关闭, 以避免误配置的可能。
10. 扫描容器镜像和运行IDS(入侵检测系统)
Web服务器作为它所部署的网络上的一个可被攻击的切入口,它镜像上的文件系统需要被完全扫描,以避免存在已知的漏洞被攻击者利用来取得远程控制容器的权限。使用IDS可以检测已知漏洞。
Kubernetes通过一系列的Admission Controller来控制Pod类型的资源(如Deployment等)是否能被部署进集群。 Admission controller会检验每个被提交进来的Pod的定义,或者有时会修改Pod定义的内容。 现在已经支持后台webhook挂载外部应用。


-
https://docs.google.com/presentation/d/1Gp-2blk5WExI_QR59EUZdwfO2BWLJqa626mK2ej-huo/edit#slide=id.g1e639c415b_0_56
-
https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/1.9.0/docs/04-certificate-authority.md
-
https://coreos.com/etcd/docs/latest/op-guide/security.html
-
https://github.com/uruddarraju/kubernetes-rbac-policies
-
https://github.com/liggitt/audit2rbac
-
https://github.com/coreos/dex
-
https://github.com/genuinetools/bane
-
https://gist.github.com/tallclair/11981031b6bfa829bb1fb9dcb7e026b0
-
https://engineering.bitnami.com/articles/running-non-root-containers-on-openshift.html
-
https://github.com/controlplaneio/netassert
-
https://hackerone.com/reports/341876
-
https://github.com/draios/falco
-
https://amzn.to/2Gg6Pav