背景
我们对K8S集群中的一些 Pod 已采取限制,以防止它们访问 API server。 然而,一位安全分析师刚刚报告说 Pod 仍然可以绕过现有的控制并查询 API。 本文将通过重现攻击来验证问题是否存在,并修复错误的配置。
假设,集群已部署的资源如下:
apiVersion: V1
kind: Secret
metadata:
name: credentials
type: Opaque
data:
credentials: UmllQ2v1zmkxSnV4NnZlaTlvaiZib3h1bTdhVGFpSDNtZNVtYwhraTBv
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: anon-rolebinding
subjects:
- kind: User
name: system:anonymous
apiGroup: rbac.authorization.k8s.10
roleRef:
apiGroup:
kind: Clusterole
name: admin
---
apiversion: apps/v1
kind: Deployment
metadata:
name: secured
spec:
selector:
matchlabels:
name: secured
replicas: 1
template:
metadata:
labels:
name: secured
spec:
automountServiceAccountToken: false
containers:
- name: secured
image: sf-alpine
imagePullPolicy: Never
command: ["sh"]
args: [ "-C", "exec sleep infinity" ]
从上文的yaml可以看到,我们分别定义了Secret
,ClusterRoleBinding
以及一个Deployment
三种资源, 其中Deployment
并未关联Secret
, 然而我们将尝试在pod中获取到 secret的值, 即说明集群中确实存在安全隐患。
这里值得一提的是,在Depolyment中, 我们定义了 automountServiceAccountToken: false
的配置, 以禁用POD自动挂载 API credentials
以及l查询API服务器。具体含义可参考官方文档: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#opt-out-of-api-credential-automounting
尝试攻击
Instructions
- 首先, 进入到 secured Pod 并观察看看
API credential
文件是否被挂载 。通常, POD 加载相关的ServiceAccount 的话,可以在pod/var/run/secrets/kubernetes.io/serviceaccount/token
查找到相应的service account
token
可以看到,该 secured Pod 由于 已配置 automountServiceAccountToken
option 为 false
, 并未能查找到token文件
- 接下来,我们尝试即使在没有credentials的情况下, 该pod也能访问到Kubernetes API 并获取集群中所有secrets的信息, 我们可以通过POD 中env环境变量中找到 Kubernetes API 的 IP 地址
- 我们直接使用 curl命令 访问Kubernetes API URL, 并在
/api/v1/namespaces/default/secrets
路径下获取secret 信息
可以看到,我们的Curl命令成功地从Kubernetes API返回了json 信息且看到我们在上文定义的secret。设想下若是攻击者已获取该pod的掌握权,通过简单的curl方式就能获取到集群中所有的credentials,会带来极大的安全隐患。
问题解决
既然我们在POD中已经定义了 automountServiceAccountToken: false
的配置, 以禁用POD自动挂载 API Credentials
, 为何POD还是能访问API Server呢?
原因:
我们再来看看yaml配置, 原来在ClusterRoleBinding
配置中 将admin
Role 赋给了 system:anonymous
这个user。要知道, 如果我们访问 API server的 secure-port端口时不带任何凭证的话,默认会被服务器标记为匿名请求,即使用system:anonymous
用户的权限访问。
因此,我们试着删除这个错误的ClusterRoleBinding
配置,再来访问 KUBE API server 看看。
可以看到,这次我们的请求就会被拒绝了 ,返回了403的错误
总结:
即使在禁用POD自动挂载 API credential的情况下, 该Pod 仍可能使用宽松的 RBAC 规则来查询服务器的 API 并窃取机密。 因此,我们在定义RBAC 规则时候,需要格外注意权限是否过度暴露的情况。
原文关注公众号:“云原生SRE”