Kubernetes 安全最佳实践
目录
概述
所以,你全力投入容器技术。你可能在本地机器上为应用程序启动一个容器,为数据库启动另一个容器,但接下来呢?你需要系统来构建容器。你需要系统来部署容器。你需要系统来运行容器。那么,如何管理如此规模的容器呢?
进入,Kubernetes!
Kubernetes 是新的应用服务器。Kubernetes 为开发团队、运维团队甚至安全团队提供了 API 接口,以便与应用程序和平台进行交互。
Kubernetes 是一个快速发展的开源项目,正在不断进步。因此,本文旨在介绍我观察到的一些常见安全错误,并提供一些关于保护 Kubernetes 集群和工作负载的最佳实践。
传奇:
图标 | 意义 |
---|---|
❌ | 不推荐 |
🗒️ | 基本原理 |
✅ | 推荐 |
⚠️ | 警告 |
安全基线
✅ 确保您的底层主机已加固且安全。我建议以 CIS 基准测试作为起点。
✅ 确保 Docker 本身已按照安全最佳实践进行配置。查看我之前的文章:Docker 安全最佳实践
✅ 确保您从安全基线开始使用 Kubernetes。
- 互联网安全中心 (CIS) 提供免费的文档。
- Aqua Security 的优秀团队还开源了一个基于 CIS 建议的自动检查器。查看:kube-bench
# recommended - on master node
$ kubectl run \
--rm \
-it \
kube-bench-master \
--image=aquasec/kube-bench:latest \
--restart=Never \
--overrides="{ \"apiVersion\": \"v1\", \"spec\": { \"hostPID\": true, \"nodeSelector\": { \"kubernetes.io/role\": \"master\" }, \"tolerations\": [ { \"key\": \"node-role.kubernetes.io/master\", \"operator\": \"Exists\", \"effect\": \"NoSchedule\" } ] } }" \
-- master \
--version 1.8
# recommended - on worker nodes
$ kubectl run \
--rm \
-it \
kube-bench-node \
--image=aquasec/kube-bench:latest \
--restart=Never \
--overrides="{ \"apiVersion\": \"v1\", \"spec\": { \"hostPID\": true } }" \
-- node \
--version 1.8
验证
与 Kubernetes 的大多数交互都是通过与控制平面(特别是控制平面的kube-apiserver组件)通信来完成的。请求在 kube-apiserver 中要经过三个步骤,才能被处理或拒绝:身份验证、授权和准入控制。请求通过这三个步骤后,kube-apiserver 就会通过网络与Kubelet通信。因此,Kubelet 也必须检查身份验证和授权。
kube-apiserver
和的行为kubelet
可以通过使用某些命令行标志启动它们来控制或修改。支持的命令行标志的完整列表记录如下:
让我们检查一些常见的 Kubernetes 身份验证安全错误:
❌ 默认情况下启用匿名身份验证
🗒️ Kubernetes 允许开箱即用的匿名身份验证。有一些kube-apiserver
设置组合可以使匿名身份验证更加安全,例如--authorization-mode=RBAC
,因为您需要显式授予system:anonymous
用户和system:unauthenticated
组 RBAC 权限。
注意:授予*
用户或*
组的 RBAC 权限不包括匿名用户。
✅ 通过传递--anonymous-auth=false
标志来禁用匿名身份验证
# not recommended - on master node
$ kube-apiserver \
<... other flags> \
--anonymous-auth=true
# recommended - on master node
$ kube-apiserver \
<... other flags> \
--anonymous-auth=false
# not recommended - on worker nodes
$ kubelet \
<... other flags> \
--anonymous-auth=true
# recommended - on worker nodes
$ kubelet \
<... other flags> \
--anonymous-auth=false
❌kube-apiserver
跑步--insecure-port=<PORT>
🗒️ 在旧版本的 Kubernetes 中,你可以kube-apiserver
使用没有任何保护措施的 API 端口运行
✅ 通过传递--insecure-port=0
标志来禁用不安全端口。在最近的版本中,此功能已默认禁用,旨在彻底弃用它。
# not recommended
$ kube-apiserver \
<... other flags> \
--insecure-port=6443
# recommended
$ kube-apiserver \
<... other flags> \
--insecure-port=0
✅在对用户进行身份验证时,优先选择基于OpenID Connect或X509 客户端证书的身份验证策略
🗒️ Kubernetes 支持不同的身份验证策略:
- X509 客户端证书:不错的身份验证策略,但您必须定期更新和重新分发客户端证书
- 静态令牌:由于其非短暂性,应避免使用它们
- 引导令牌:与上面的静态令牌相同
- 基本身份验证:避免使用它们,因为凭证以明文形式通过网络传输
- 服务帐户令牌:不应将其用于尝试与 Kubernetes 集群交互的最终用户,但它们是 Kubernetes 上运行的应用程序和工作负载的首选身份验证策略
- OpenID Connect(OIDC)令牌:由于 OIDC 与您的身份提供商(例如 AD、AWS IAM、GCP IAM 等)集成,因此是最终用户的最佳身份验证策略
# recommended - OIDC
$ kube-apiserver \
<... other flags> \
--oidc-issuer-url="https://domain/.well-known/openid-configuration" \
--oidc-client-id="example"
# recommended - X509 cert
$ kube-apiserver \
<... other flags> \
--client-ca-file=/path/to/ca.crt \
--tls-cert-file=/path/to/server.crt \
--tls-private-key-file=/path/to/server.key
授权
❌ 默认情况下,授权模式是始终授权所有请求kube-apiserver
✅ 启用基于角色的访问控制
🗒️ Kubernetes 支持不同的授权策略,但基于角色的访问控制(RBAC)是在 v1.8 中引入的,它允许管理员定义用户和服务帐户在整个 Kubernetes 集群中或在特定的 Kubernetes命名空间内可以做什么或不能做什么
# not recommended
$ kube-apiserver \
<... other flags> \
--authorization-mode=AlwaysAllow
# recommended
$ kube-apiserver \
<... other flags> \
--authorization-mode=RBAC
❌默认情况下,default
服务帐户会自动挂载到 Kubernetes 中所有容器的文件系统中
🗒️default
服务帐户是一个有效的服务帐户令牌,可用于以经过身份验证的工作负载身份查询 Kubernetes API。启用 RBAC 后,这仍然是一个问题,但问题不如未启用 RBAC 时那么严重。如果没有 RBAC,此令牌几乎可以用于在 Kubernetes 集群中执行任何操作。
default
✅ 禁用服务帐户令牌的自动挂载
# recommended
$ kubectl patch serviceaccount default -p "automountServiceAccountToken: false"
准入控制
准入控制器是一段代码,用于在身份验证/授权过程的第三步(也是最后一步)拦截对 Kubernetes API 的请求。准入控制选项的完整列表如下:
✅ 配置准入控制,以通过在特权容器上启动交互式 shell 或附加到特权容器来拒绝特权提升
🗒️ 有一些有效的用例,您需要运行特权容器来与底层主机的内核进行交互,但这意味着用户可以潜在地kubectl attach
或kubectl exec
进入这些特权容器。
# recommended
kube-apiserver \
<...other flags> \
--admission-control=...,DenyEscalatingExec
✅ 配置准入控制以启用 Pod 安全策略
🗒️ Pod 安全策略是 Pod 必须遵守的安全规则,以便在集群上被接受和调度。
⚠️请确保已准备好 PodSecurityPolicy 对象(即 yaml 文件),以便在启用此功能后应用,否则将不会调度任何 Pod。请参阅本文中的Pod 安全策略建议以获取示例。
# recommended
$ kube-apiserver \
<... other flags> \
--addmission-control=...,PodSecurityPolicy
# example PodSecurityPolicy
$ kubectl create -f- <<EOF
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: example
spec:
privileged: false # Don't allow privileged pods!
EOF
# let's try to request a privileged pod to be scheduled on our cluster
$ kubectl create -f- <<EOF
apiVersion: v1
kind: Pod
metadata:
name: pause
spec:
containers:
- name: pause
image: k8s.gcr.io/pause
EOF
# throws error as expected
Error from server (Forbidden): error when creating "STDIN": pods "privileged" is forbidden: unable to validate against any pod security policy: [spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed]
✅ 配置准入控制以始终拉取镜像
🗒️ Kubernetes 会缓存从任何镜像仓库(私有或公共)拉取的容器镜像。任何缓存的容器镜像都可以被集群中的任何 Pod 重复使用。因此,Pod 可能会未经授权访问潜在的敏感信息。强制 Kubernetes 始终拉取镜像将要求每个请求资源提供从私有镜像仓库拉取镜像所需的凭据。
# recommended
$ kube-apiserver \
<... other flags> \
--admission-control=...,AlwaysPullImages
冒充
Kubernetes 具有一项功能,允许任何用户模拟 Kubernetes 集群上的任何其他用户。此功能非常适合调试,但如果控制不当,可能会带来意想不到的安全隐患。
为了说明其含义:
$ kubectl drain test-node
Error from server (Forbidden): User "foo" cannot get nodes at the cluster scope. (get nodes test-node)
$ kubectl drain test-node --as=admin --as-group=system:admins
node "test-node" cordoned
node "test-node" drained
您可以在此处阅读更多相关信息:
✅ 限制谁可以模拟以及他们作为模拟用户可以做什么
# not recommended
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: impersonator
rules:
# allows users to impersonate any "users", "groups", and "serviceaccounts"
- apiGroups: [""]
resources: ["users", "groups", "serviceaccounts"]
verbs: ["impersonate"]
# recommended
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: limited-impersonator
rules:
# Can impersonate the group "developers"
- apiGroups: [""]
resources: ["groups"]
verbs: ["impersonate"]
resourceNames: ["developers"]
Pod 安全策略
Pod 安全策略定义了 Pod 必须遵守的一组条件才能被系统接受。
✅ 禁止特权容器
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
spec:
privileged: false
✅ 不允许共享主机进程 ID 命名空间
⚠️如果hostPID
设置为true
并且容器被授予该SYS_PTRACE
功能,则可以在容器外提升权限
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
spec:
hostPID: false
✅ 不允许共享主机 IPC 命名空间(即内存)
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
spec:
hostIPC: false
✅ 不允许共享主机网络堆栈(即访问环回、本地主机、监听本地节点上的网络流量)
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
spec:
hostNetwork: false
✅ 将允许的卷类型列入白名单
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
spec:
# It's recommended to allow the core volume types.
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
# Assume that persistentVolumes set up by the cluster admin are safe to use.
- 'persistentVolumeClaim'
✅ 要求容器以非 root 用户身份运行
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
spec:
runAsUser:
# Require the container to run without root privileges.
rule: 'MustRunAsNonRoot'
supplementalGroups:
rule: 'MustRunAs'
ranges:
# Forbid adding the root group.
- min: 1
max: 65535
✅ 设置defaultAllowPrivilegeEscalation
为false
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
spec:
defautlAllowPrivilegeEscalation: false
✅ 应用安全增强型 Linux ( seLinux
)、seccomp
或apparmor
配置文件
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
annotations:
# applying default seccomp and apparmor profiles
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
完整 Pod 安全策略示例
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
spec:
privileged: false
# Required to prevent escalations to root.
defautlAllowPrivilegeEscalation: false
# This is redundant with non-root + disallow privilege escalation,
# but we can provide it for defense in depth.
requiredDropCapabilities:
- ALL
# Allow core volume types.
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
# Assume that persistentVolumes set up by the cluster admin are safe to use.
- 'persistentVolumeClaim'
hostNetwork: false
hostIPC: false
hostPID: false
runAsUser:
# Require the container to run without root privileges.
rule: 'MustRunAsNonRoot'
seLinux:
# This policy assumes the nodes are using AppArmor rather than SELinux.
rule: 'RunAsAny'
supplementalGroups:
rule: 'MustRunAs'
ranges:
# Forbid adding the root group.
- min: 1
max: 65535
fsGroup:
rule: 'MustRunAs'
ranges:
# Forbid adding the root group.
- min: 1
max: 65535
readOnlyRootFilesystem: false
网络策略
Kubernetes 允许用户部署他们选择的网络附加组件。
✅ 选择允许您利用网络策略的网络插件,例如Calico或Canal,它们可让您通过 Flannel 进行网络连接并通过 Calico 进行网络策略控制。
# Canal Example
$ kube-apiserver \
<... other flags> \
--cluster-cidr=10.244.0.0/16 \
--allocate-node-cidrs=true
# install RBAC
$ kubectl apply -f \
https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/canal/rbac.yaml
# install Calico
$ kubectl apply -f \
https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/canal/canal.yaml
额外的安全措施
到目前为止的所有建议都只是为了帮助您快速上手。
在本节中,我将介绍一些额外的安全措施!
✅ Kubernetes Secrets在某些有限的用例中很有用。我不会依赖它作为 Secrets 管理解决方案。相反,我会考虑使用 Hashicorp Vault。
✅ 使用Anchore或Clair持续扫描容器中的安全漏洞。
✅ 保持基础设施的安全补丁为最新,或者在保持更新的操作系统上运行 Kubernetes(例如 CoreOS)
✅ 仅部署已分析、扫描和签名的授权容器镜像(即软件供应链安全)。Grafeas 、TUF和Notary可以为您提供帮助。
✅ 限制对 Kubernetes 节点的直接访问。
✅ 避免邻居吵闹的问题。定义资源配额。
✅ 使用 Prometheus 和 Grafana 监控并记录所有内容。Sysdig Falco将检测并警报异常的容器行为,例如容器中的 Shell 执行、容器权限提升、生成意外的子进程、挂载敏感路径、系统二进制文件建立网络连接等等。
其他参考
结论
容器和编排器本质上并不比传统虚拟化技术更安全或更不安全。我个人认为,容器和编排器有潜力彻底改变安全行业,真正以 DevOps 的速度实现安全。
如果您觉得我遗漏了某些内容,或者某些细节有误,或者只是想打个招呼,请随时在下面发表评论,或通过GitHub 🐙、Twitter 🐦或LinkedIn 🔗与我联系。
鏂囩珷鏉ユ簮锛�https://dev.to/pbnj/kubernetes-security-best-practices-hlk