Kubernetes 的安全是一个相当广泛的主题,涉及很多高度相关的内容。和探讨大部分安全性相关的问题一样,首先需要考虑威胁模型——谁可能攻击你的系统,以及他们如何做到这一点。这可以帮你确定安全工作的优先级。对于大多数 Kubernetes 应用有三类主要的攻击者:
围绕云原生基础概念构建的模型可以帮你建立对 Kubernetes 安全的总体认识。下图将安全划分为四个层级,被称为云原生安全的4C模型。管理员将在不同的层次上应对三类攻击者。
4C 指的是云(Cloud)、集群(Cluster),容器(Containers)和代码(Code)
正如你在图中所看见的,4C 模型中每部分的安全性都是相互包含的。只依靠增强代码层次安全来预防云、集群和容器中安全漏洞是几乎不可能的。适当提高其他层的安全能力,就已经为你的代码提供强大的基础安全保障。下面将详细介绍这四部分内容。
大多数情况下,云为 Kubernetes 集群提供可信的计算资源。如果云的基础设置是不可靠的(或以易受到攻击的方式配置),那就没有办法保证在这个基础上构建的 Kubernetes 集群的安全性。每一个云服务提供商都向他们的客户提供大量如何在其环境安全运行负载的建议。下面提供常用云服务厂商的安全文档链接,并且提供了构建安全 Kubernetes 集群的建议。
云服务厂商 | 链接 |
---|---|
阿里云 | https://www.alibabacloud.com/... |
AWS | https://aws.amazon.com/security/ |
Google Cloud Platform | https://cloud.google.com/secu... |
Microsoft Azure | https://docs.microsoft.com/en... |
如果你运行在自己的硬件上或者其他云服务提供商,请查阅文档获取最佳安全实践。
Kubernetes 是一个复杂的系统,下图展示了一个集群不同的组成部分,为了保证集群整体的安全,需要仔细保护每一个组件。
将需要注意保护的集群组件划分成两个部分:
使用 TLS 进行安全通讯。Kubernetes 期望默认情况下使用 TLS 对集群中所有 API 通信进行加密,大多数安装方式都会创建必要的证书并分发给集群组件。
API 认证。在安装集群时,为API服务器选择与通用访问模式匹配的身份验证机制。例如,小型单用户集群可能希望使用简单的证书或静态Bearer令牌方法。较大的群集可能希望集成现有的OIDC或LDAP服务器,以将用户细分为多个组。更多有信息请参考认证。
API 授权。一旦通过身份验证,每个API调用也都有望通过授权检查。Kubernetes 附带了一个集成的基于角色的访问控制(RBAC)组件,该组件将传入的用户或组与捆绑到角色中的一组权限进行匹配。这些权限将动词(get,create,delete)与资源(pods,service,nodes)结合在一起,并且可以是命名空间或集群作用域。提供了一组现成的角色,这些角色根据客户端可能要执行的操作提供合理的默认责任分离。更多有关信息请参考授权
Kubelet 在端口10250和10255上提供小型 REST API。端口10250是读/写端口,而10255是具有API端点子集的只读端口。这些端点授予对节点和容器的强大控制权。默认情况下,Kubelets允许未经身份验证对此API进行访问。生产集群应启用 Kubelet 身份验证和授权,可以通过设置 --read-only-port=0
来禁用只读端口,但是10250 端口用于系统指标收集和其他重要功能,所以开发者必须仔细控制对此端口的访问。更多有关信息请参考Kubelet身份验证/授权
保护集群组件不受损坏
根据应用程序受到的攻击,关注安全的特定方面。例如,运行中的服务 A 对于其他应用非常重要,而服务 B 容易受到资源耗尽攻击,如果不设置服务 B 的资源限制,就会因为服务 B 耗尽资源导致服务 A 不可用。所以需要注意下面几个常见安全措施:
定义资源限制
默认情况下,Kubernetes 集群中对所有资源没有对 CPU 、内存和磁盘的使用限制。可以通过创建资源配额策略,并附加到 namespace 中来限制资源的使用。
下面的例子将限制命名空间中Pod 的数量为4个,CPU使用在1和2之间,内存使用在1GB 和 2GB 之间。
# compute-resources.yaml apiVersion: v1 kind: ResourceQuota metadata: name: compute-resources spec: hard: pods: "4" requests.cpu: "1" requests.memory: 1Gi limits.cpu: "2" limits.memory: 2Gi requests.nvidia.com/gpu: 4
分配资源配额到命名空间:
kubectl create -f ./compute-resources.yaml --namespace=myspace
查看 namespace 资源使用情况:
[root@localhost ~]# kubectl describe quota compute-resources --namespace=myspace Name: compute-resources Namespace: myspace Resource Used Hard -------- ---- ---- limits.cpu 0 2 limits.memory 0 2Gi pods 0 4 requests.cpu 0 1 requests.memory 0 1Gi requests.nvidia.com/gpu 0 4
也可以为 Pod 添加资源限制,设置内存请求为 256MiB,内存限制为512MiB
apiVersion: v1 kind: Pod metadata: name: default-mem-demo spec: containers: - name: default-mem-demo-ctr image: nginx resources: limits: memory: 512Mi requests:
- Pod 安全策略 作为 Pod 的组成部分,容器通常配置有非常实用的安全默认值,这些默认值适用于大多数情况。但是,有时 Pod 可能需要其他权限才能执行其预期任务,在这种情况下,我们需要增强 Pod 的默认权限。安全上下文定义了 Pod 或容器的特权和访问控制,安全上下文设置有: 1. 委托访问:基于用户ID 和用户组ID 权限去访问资源对象(如文件)。 2. SELinux:为对象分配安全标签 3. 以特权或非特权用户运行 4. Linux 功能:为进程提供一些特权,而不去赋予它root用户的所有特权 5. AppArmor:使用程序配置文件来限制单个程序的功能。 6. Seccomp:过滤进程的系统调用 7. 允许提升权限(AllowPrivilegeEscalation):子进程能否获得父进程更多的权限。这个布尔值直接控制是否在容器进程上设置了 no_new_privs 标志。在以下情况下 AllowPrivilegeEscalation 始终为 true——一是,以特权OR运行;二是,具有 `CAP_SYS_ADMIN`。 在 `securityContext` 字段下配置安全策略,在 Pod 中指定的安全策略将被应用于所有容器,容器中指定的安全策略应用于单个容器,当它们重复时,容器级会覆盖 Pod 级的的安全策略。
apiVersion: v1 kind: Pod metadata: name: security-context-demo spec: securityContext: runAsUser: 1000 runAsGroup: 3000 fsGroup: 2000 volumes: - name: sec-ctx-vol emptyDir: {} containers: - name: sec-ctx-demo image: busybox command: [ "sh", "-c", "sleep 1h" ] volumeMounts: - name: sec-ctx-vol mountPath: /data/demo securityContext: runAsUser: 2000 allowPrivilegeEscalation: false ``` 更多有关信息请参考[Pod 安全策略](https://kubernetes.io/docs/concepts/policy/pod-security-policy/)
Kubernetes允许来自集群中任何容器的所有网络流量发送到集群中的任何其他容器并由其接收。当尝试隔离工作负载时,这种开放式方法没有帮助,因此需要应用网络策略来帮助开发者实现所需的隔离。Kubernetes NetworkPolicy API使开发者能够将入口和出口规则应用于选定的Pod,用于第3层和第4层流量,并依赖于实现容器网络接口(CNI)的兼容网络插件的部署。
网络策略是 namespace 作用域,并根据匹配标签(例如,tier:backend)的选择应用于Pod。当NetworkPolicy对象的Pod选择器与Pod匹配时,根据策略中定义的入口和出口规则来管理进出Pod的流量。 所有来自或发往该Pod的流量都会被拒绝,除非有允许它的规则。
要在Kubernetes集群中正确隔离网络和传输层的应用程序,网络策略应以“拒绝所有”的默认前提开始。然后,应将每个应用程序组件及其所需源和目标的规则逐个列入白名单,并进行测试以确保流量模式按预期工作。
Kubernetes 使用 Secrets 保护应用程序需要访问敏感信息——密码、X.509证书、SSH密钥或OAuth令牌等。它通过卷装入,对它的访问严格限于那些需要使用它的实体(用户和Pod),且当存储在磁盘上时(静止状态)它是不可访问或只读的。
需要考虑的全部安全问题如下:
需要关注的安全领域 | 建议 |
---|---|
RBAC 授权 | https://kubernetes.io/docs/re... |
认证方式 | https://kubernetes.io/docs/re... |
密钥管理 | https://kubernetes.io/docs/co... |
Pod 安全规则 | https://kubernetes.io/docs/co... |
服务质量 | https://kubernetes.io/docs/ta... |
网络规则 | https://kubernetes.io/docs/co... |
ingress 的 TLS | https://kubernetes.io/docs/co... |
为了在 Kunernetes 中运行软件,必须将它打包成容器。需要考虑下面的注意事项,来保证容器符合 Kubernetes 安全配置。
理想情况下,使用应用程序二进制文件和二进制文件所依赖的的任何相关项来创建镜像。事实上,没有什么阻止开发者将 scratch
作为基础镜像,并将静态链接的二进制文件复制到镜像中。它没有其他依赖,镜像中包含单个文件,以及一些描述容器如何运行的元数据。最小化镜像加快镜像的分发速度,并且显著减少容器内部的受攻击面。
但是这并不总是可行的,因此需要慎重选择基础镜像。最佳的方法是使用操作系统供应商支持的镜像,或者是 docker hub 上官方支持的镜像。不要盲目使用之前未经过审查的不受信任来源的镜像,尤其是在生产环境中。
镜像扫描对于保障容器应用的安全至关重要,确保您的镜像定期通过信誉良好的工具进行扫描,可以使用 CoreOS 的 Clair 之类的工具扫描容器中的已知漏洞,它是容器镜像的静态漏洞分析器。
使用 CNCF 项目的的 TUF 和 Notary 对容器进行签名,在执行前验证签名,确保镜像的正确没有被篡改。
在构建镜像时,创建最低操作系统权限的用户完成容器的运行。
最后是代码级别,这是程序员能掌控的被攻击面,但不在 Kubernetes 的安全保护范围,提供如下建议:
如果您的代码需要通过TCP进行通信,则理想情况下,它将提前与客户端执行TLS握手。除少数情况外,默认行为应是对传输中的所有内容进行加密。
无论什么情况下,程序只应该公开必要的端口。
确保第三方依赖是安全的。
大多数语言都提供了静态代码分析,可以分析代码中是否存在潜在的不安全编码实践。
自动化工具可以针对您的服务尝试会破坏服务的攻击。这些包括SQL注入,CSRF和XSS。最受欢迎的动态分析工具之一是OWASP Zed Attack代理。
本篇文章出自Choerodon猪齿鱼社区易大强。