文章总结: 本文详细介绍了Kubernetes集群的安全机制,重点讲解了身份认证和权限控制两大核心安全机制。身份认证方面,主要介绍了X.509客户端证书认证和ServiceAccount两种方式;权限控制方面,详细解释了RBAC(基于角色的访问控制)的四种对象及其使用方法。文章通过多个实验案例展示了如何配置和管理K8s集群的访问权限,包括创建用户、角色绑定等实际操作。最后简要介绍了准入控制机制作为集群安全的额外保护层。
综合评分: 91
文章分类: 云安全,应用安全,安全建设,安全培训
K8s集群安全|集群安全机制
原创
摸鱼信安
摸鱼信安
2025年12月3日 20:12
重庆
安全机制说明
API Server 是集群内部各个组件通信的基座,核心安全机制基本都是围绕如何保护 APIServer 的访问和通信而设计的
身份认证
X.509 Client Certificates
最常见、默认即使用的方式,k8s 采用的是双向证书,相对于单向证书,更安全
单向证书认证
一个简单的 https 场景(用词可能不准确,但是大概是这个意思,且单向证书认证不单指 https)
客户端=浏览器
服务端=访问的网站
浏览器发起连接访问
- • 给出浏览器支持的 TLS 版本,加密方法
服务器响应
- • 选一个浏览器支持的加密
- • 将服务器的证书(公钥、CA 签名)发给浏览器
浏览器验证证书
- • 证书如果是受信任的机构颁发的就是安全的,如果是服务端自建的 CA 签发的就是不受信任的,这代表你访问的这个网站可能是假冒的,浏览器会提示不安全,但是如果你点击信任该网站,那加密也会生效,https 不会因为证书不可信而不加密通信,一样会加密通信
浏览器向服务器发送密钥
- • 浏览器使用服务器的证书(里面有公钥)和浏览器生成的会话密钥进行加密
双方协商与后面的加密通信
- • 服务器用自己的私钥进行解密得到浏览器用证书(公钥)加密的会话密钥
- • 浏览器和服务器基于前面的材料进行后续的非对称加密通信
双向证书认证
k8s 为场景
kubectl=客户端
apiserver=服务端
kubectl 发起连接
- • 给出支持的 tls 版本,支持的加密方法等
apiserver 响应
- • 选一个加密方法
- • apiserver 证书(里面有公钥、CA 签名等)
kubectl 验证 apiserver 证书
- • 同单向证书一样,检查是否是受信任的 CA 签发的
- • kubectl 发送证书给 apiserver
apiserver 验证 kubectl 证书
- • 反过来,apiserver 检查证书否是受信任的 CA 签发的
双方协商与后续通信
- • apiserver 生成 ECDHE 参数并用私钥签名,发送给 kubectl
- • kubectl 验证签名后,生成自己的 ECDHE 参数
- • 双方使用对方的 ECDHE 参数和自己的参数,独立计算出相同的 Pre-master Secret
- • 结合两个随机数和 Pre-master Secret,生成最终的对称加密会话密钥
除了 kubectl 之外,还有一些其它组件需要跟 apiserver 交互的都是通过此双向证书认证的方式进行的,比如 etcd、controller 等
证书签发
手动签发
通过 k8s 集群的 CA 进行 HTTPS 证书的签发,主要是对外,比如我们的 kubeconfig
配置加入集群、集群的 apiserver 地址及端口、首次访问的 tokne(有效期 24h)、CA 证书 hash、CRI Socket 指定(这个是因为使用 docker 而产生的,k8s 不支持 docker 后通过此 cri 套接来支持)
kubeconfig
是 kubectl 对 APIserver 访问的一种配置方式,其实我们不使用这个 kubeconfig 文件,而是使用命令加上 CA 证书、APIServer 地址等等信息也是可以访问 APIServer,但是东西太多,太长,所以使用一个 config 文件来进行配置,所以此文件相当重要,如果泄漏,等于攻击者拿到了集群最高管理权限。
自动签发
kubelit 首次访问 APIServer 时,使用 token 进行认证,通过后,Controller Manager 会为 kubelet 生成证书,以后都是通过证书认证了。主要是对内,集群内部的机器自己管理动态的证书。
ServiceAccount(SA)
SA 一般是用于集群的自动化任务
在 k8s1.24 之前,Pod 的 Secret Token 长期有效,通过创建 Secret 进行鉴权
在 k8s1.24 之后,使用 Bound ServiceAccount Token 短期有效(默认 1h)且不在创建Secret
场景:Pod 跟 apiserver 通信的时候,不用用的证书,而是 ServiceAccount Token,因为 Pod 随时可能重构、扩缩容,它是临时的,所以不会像组件一样使用长期的证书进行通信。
serviceaccount
- • token,使用 apiserver 私钥签名的 JWT,用于访问认证
- • ca.crt,根证书,用于客户端验证 apiserver 发送的证书
- • namespace,标识这个 serviceaccount 的作用域
默认目录:
/run/secrets/kubernetes.io/serviceaccount/
创建 sa
命令方式
kubectl create sa test -n default
资源清单方式
[root@k8s-master01 ~]# kubectl create sa test -n default --dry-run -o yaml
W120117:27:30.768989184580helpers.go:704]--dry-runisdeprecatedandcanbereplacedwith--dry-run=client.
apiVersion:v1
kind:ServiceAccount
metadata:
creationTimestamp:null
name:test
namespace: default
k8s 用户和用户组的概念
k8s 没有单独的命令用于创建用户,用户组,apiserver 通过证书的方式识别用户和组
kubeconfig,client-certificate-data
Issuer 是 CA 签发者
Subject: O=kubeadm:cluster-admins, CN=kubernetes-admin
组(单位)O=kubeadm:cluster-admins
用户名:CN=kubernetes-admin
用户可以指的是服务账户 SA,也可以指一个 k8s 管理员使用的 kubeconfig 账户
权限控制
授权插件
- • AlwaysDeny:表面拒绝所有请求
- • AlwaysAllow:允许接收所有请求
- • ABAC:基于属性的访问控制,表示使用用户配置的授权规则对用户请求镜像
- • Webhook:通过调用外部 REST 服务对用户进行授权
- • RBAC:基于角色的访问控制,默认
RBAC
Role-Based Access Control
基于角色访问控制,现行版本默认标准
- • 集群资源(pod、nodes) 和非资源(/metrics、/healthz)完整覆盖
- • 整个 RBAC 通过 API 完成,可以使用 kubectl 进行操作
- • 权限是累加的
RBAC 4 个对象Role(角色),ClusterRole(集群角色),RoleBinding(角色绑定),ClusterRoleBinding(集群角色绑定)
命名空间级
- • Role角色(为某个 namespace 定义权限)
- • RoleBinding角色绑定(可用于全局资源(Node、PV 等),也可在绑定时作为 namespace 级权限使用)
集群级
- • ClusterRole集群角色(将 Role/ClusterRole 绑定到用户、组、ServiceAccount)
- • ClusterRoleBinding集群角色绑定(将 ClusterRole 绑定到用户、组、ServiceAccount,使其获得ClusterRoleBinding全局权限)
k8s 中的角色
参考:https://kubernetes.io/docs/reference/access-authn-authz/rbac/
Role,命名空间级
-
• view
-
• 描述:提供对命名空间内的资源的只读
-
• 权限:
-
• get、list、watch
-
• 适用于 pods,service,deployment 等资源,注意:不包含Secrets(SA 是 Secret 的一个类型,新版 k8s 本已经不存放 token,但是还是会存放 API 密钥、TLS 证书之类的东西 )
-
• edit
-
• 描述:允许用户对命名空间内的资源进行读取、修改、删除和创建等操作,Secret 也可以读取
-
• 权限:
-
• get、list、watch、create、update、patch、delete 等操作
-
• 适用于 pods、service、deployment 等资源
-
• admin
-
• 描述:该角色提供了对命名空间内资源的完全控制,包括管理角色、角色绑定等权限,可以理解为这个命名空间的管理员
-
• 权限:
-
• 命名空间下完整的权限
-
• create,delete,update,get,list,watch 等操作,还拥有在指定命名空间内的完全控制权限,包括管理该命名空间下的角色(Role)和角色绑定(RoleBinding)
ClusterRoles,集群级
ClusterRole 是在 集群级别 进行访问控制的,适用于跨命名空间的资源和集群管理操作,一般在有规范的项目中,这种角色只有运维、安全运维、项目负责人的工作人员持有
-
• cluster-admin
-
• 描述:该角色具有对集群中所有资源的完全访问权限,类似于 Kubernetes 集群的管理员权限
-
• 权限:
-
• 完全的权限,适用于集群内的所有资源,包括命名空间外的资源,如节点、网络策略等
还有两种集群角色,这些是Kubernetes系统内部使用的角色,用于控制核心组件的权限。普通用户通常无需直接操作,但了解其存在有助于理解集群的安全模型,它们也有默认的角色和角色绑定,比如
Core component roles,核心组件角色
- • system:kube-scheduler 绑定 system:kube-scheduler user 作用:主要用于允许调度器访问 Kubernetes 集群资源
- • ……
Other component roles,其他组件角色
- • system:kube-dns 绑定 kube-dns service account in the kube-system namespace 作用:用于管理 DNS 服务
- • ……
这些角色一般用不到,但是它们是 k8s 集群组成的一部分,也遵循 k8s RBAC 的策略,这些东西一般都是 k8s 官方、google 在维护,我们用就行。
查看集群角色
查看集群角色
kubectl get clusterroles
# 查看指定集群的角色
# kubectl get clusterrole 集群名
查看默认集群角色
# 查看 cluster-admin 角色
kubectldescribeclusterrolecluster-admin
# 查看 view 集群角色
kubectldescribeclusterroleview
# 查看 edit 集群角色
kubectldescribeclusterroleedit
# 查看 admin 集群角色(注意:这是一个ClusterRole,但通常用于命名空间绑定)
kubectldescribeclusterrole admin
查看角色绑定关系
# 查看所有
kubectlgetclusterrolebindings
# 查看所有,详细信息
kubectlgetclusterrolebindings-owide
# 查看集群角色被哪些绑定引用
kubectlgetclusterrolebindings-ocustom-columns=NAME:.metadata.name,ROLE:.roleRef.name|grep cluster-admin
查看命名空间角色
查看命名空间内的角色
# 查看kube-system 命名空间的角色
kubectl get roles -n kube-system
# 查看所有命名空间的角色
kubectl get roles --all-namespaces
查看命名空间角色绑定
# 查看命名空间 dev 的角色绑定
kubectl get rolebindings -n dev
# 查看所有命名空间的角色绑定
kubectl get rolebindings --all-namespaces
角色+角色绑定
Role+RoleBinding
单命名空间范围
- • Role 是命名空间级的权限定义
- • RoleBinding 也是命名空间级权限定义
- • 只能赋予在当前命名空间级的管理员权限
- • 比如:给某个 namespace 内的用户/SA 授权读写 Pod、ConfigMap、Secret 等
Role 表示一组规则的权限,权限只会增加(累加),角色可以绑定一个命名空间,如果需要跨命名空间,需要集群角色,角色是命名空间级别,必须要有命名空间
角色可以添加多个权限
比如这个资源清单,赋予了 pod 的 get、list 等命令权限,在赋予了 services 等 get、list 权限,这是角色权限的定义
有两种写法
这种是数组写法
apiVersion: rbac.authorization.k8s.io/v1
kind:Role
metadata:
name:pod-manager
namespace:my-namespace
rules:
-apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "create", "delete"]
-apiGroups: [""]
resources: ["services"]
verbs: ["get", "list"]
这种是列表
apiVersion: rbac.authorization.k8s.io/v1
kind:Role
metadata:
name:pod-manager
namespace:my-namespace
rules:
-apiGroups:
-''
resources:
-pods
-services
verbs:
-get
-list
-create
- delete
Role 角色与 角色绑定实验
创建命名空间
kubectl create namespace rbac-role-test
创建 RBAC 资源
apiVersion: rbac.authorization.k8s.io/v1
kind:Role
metadata:
name:pod-viewer-role
namespace:rbac-role-test
rules:
# 规则1:对pods只有只读权限
-apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
# 规则2:对configmaps有完整权限
-apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
创建 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-service-account
namespace: rbac-role-test
创建角色绑定
apiVersion: rbac.authorization.k8s.io/v1
kind:RoleBinding
metadata:
name:test-role-binding
namespace:rbac-role-test
subjects:
-kind:ServiceAccount
name:test-service-account
namespace:rbac-role-test
roleRef:
kind:Role
name:pod-viewer-role
apiGroup: rbac.authorization.k8s.io
角色、角色的 SA 绑定上了,在这个命名空间下,创建对应的资源,如 pod、deployment 等将受到权限控制
pod
apiVersion: v1
kind:Pod
metadata:
name:test-pod
namespace:rbac-role-test
spec:
containers:
-name:nginx
image:docker.xuanyuan.run/nginx:alpine
imagePullPolicy:IfNotPresent
ports:
-containerPort: 80
然后找 AI 写个测试的 sh,试一试
所有的测试都没问题,所有权限被限制在了命名空间下,且都只有赋予的权限命令
集群角色+集群角色绑定
ClusterRole+ClusterRoleBinding
整个集群范围
- • ClusterRole 可以包含命名空间资源或集群资源(Nodes、PV、Namespace 等)
- • ClusterRoleBinding 将其绑定给用户/组/SA,使其获得全局权限
- • 比如:集群管理员(cluster-admin)、监控系统(Prometheus)等
集群角色,集群角色拥有与角色相同的控制能力,集群角色的域是整个集群,角色是它绑定的命名空间
- • 集群级别资源控制(node 的访问权限)
- • 非资源类型 endpoints
- • 所有命名空间资源控制
apiVersion: rbac.authorization.k8s.io/v1
kind:ClusterRole
metadata:
name:cluster-pod-manager
rules:
# 对所有 namespace 下的 Pod 操作权限
-apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "create", "delete"]
# 对所有 namespace 下的 Node 查看权限
-apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
# 对所有 namespace 下的 ConfigMap 查看与更新权限
-apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch", "update"]
集群角色(ClusterRole)与集群角色绑定(ClusterRoleBinding)实验
创建一个资源清单,集群角色,赋予了集群级下的查看权限
apiVersion: rbac.authorization.k8s.io/v1
kind:ClusterRole
metadata:
name:cluster-viewer
rules:
# 可以查看所有命名空间的pods
-apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
# 可以查看所有命名空间的configmaps
-apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
# 可以查看节点信息(集群级资源)
-apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list"]
# 可以查看命名空间本身
-apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list"]
创建一个 sa
apiVersion: v1
kind: ServiceAccount
metadata:
name: cluster-sa
namespace: default # SA在default命名空间,但权限是集群范围的
集群角色绑定
将集群角色的权限绑定在 sa 服务上
apiVersion: rbac.authorization.k8s.io/v1
kind:ClusterRoleBinding
metadata:
name:cluster-sa-binding
subjects:
-kind:ServiceAccount
name:cluster-sa
namespace:default
roleRef:
kind:ClusterRole
name:cluster-viewer
apiGroup: rbac.authorization.k8s.io
资源
创建多个资源来进行测试
apiVersion: v1
kind:Namespace
metadata:
name:test-ns-1
---
apiVersion:v1
kind:Namespace
metadata:
name:test-ns-2
---
apiVersion:v1
kind:ConfigMap
metadata:
name:test-config-1
namespace:test-ns-1
data:
key1:value1
---
apiVersion:v1
kind:ConfigMap
metadata:
name:test-config-2
namespace:test-ns-2
data:
key2:value2
---
apiVersion:v1
kind:Pod
metadata:
name:test-pod-1
namespace:test-ns-1
spec:
containers:
-name:nginx1
image:docker.xuanyuan.run/nginx:alpine
command: ["sleep", "3600"]
---
apiVersion:v1
kind:Pod
metadata:
name:test-pod-2
namespace:test-ns-2
spec:
containers:
-name:nginx2
image:docker.xuanyuan.run/nginx:alpine
command: ["sleep", "3600"]
用 AI 写个测试脚本
#!/bin/bash
echo"=============================================="
echo"Kubernetes ClusterRole 权限测试脚本"
echo"=============================================="
# 应用所有资源
echo-e"\n1. 应用RBAC和测试资源..."
kubectlapply-fcluster-role.yaml
kubectlapply-fcluster-sa.yaml
kubectlapply-fcluster-binding.yaml
kubectlapply-ftest-resources.yaml
# 等待Pod运行
echo-e"\n等待测试Pod就绪..."
kubectlwait--for=condition=Readypod/test-pod-1-ntest-ns-1--timeout=30s
kubectlwait--for=condition=Readypod/test-pod-2-ntest-ns-2--timeout=30s
echo-e"\n2. 验证创建的RBAC资源..."
echo"=== ClusterRole ==="
kubectlgetclusterrolecluster-viewer-oyaml|grep-A20"rules:"
echo-e"\n=== ClusterRoleBinding ==="
kubectlgetclusterrolebindingcluster-sa-binding-oyaml|grep-A10"subjects:"
echo-e"\n3. 开始权限测试..."
echo"测试ServiceAccount: system:serviceaccount:default:cluster-sa"
# 测试函数
test_permission() {
localverb=$1
localresource=$2
localnamespace=$3
result=$(kubectlauthcan-i$verb$resource\
--as=system:serviceaccount:default:cluster-sa\
${namespace:+-n$namespace} 2>/dev/null)
if [ "$result"="yes" ];then
echo" ✅ 可以 $verb $resource ${namespace:+在 $namespace 命名空间}"
else
echo" ❌ 不可以 $verb $resource ${namespace:+在 $namespace 命名空间}"
fi
}
echo-e"\n=== 测试跨命名空间权限 ==="
echo"在 test-ns-1 命名空间:"
test_permission"get""pods""test-ns-1"
test_permission"list""pods""test-ns-1"
test_permission"create""pods""test-ns-1"
echo-e"\n在 test-ns-2 命名空间:"
test_permission"get""pods""test-ns-2"
test_permission"list""pods""test-ns-2"
test_permission"watch""pods""test-ns-2"
echo-e"\n在 default 命名空间:"
test_permission"get""pods""default"
test_permission"list""configmaps""default"
echo-e"\n=== 测试集群级资源权限 ==="
test_permission"get""nodes""" # 不指定命名空间
test_permission"list""nodes"""
test_permission"watch""nodes"""
echo-e"\n=== 测试命名空间资源 ==="
test_permission"get""namespaces"""
test_permission"list""namespaces"""
test_permission"create""namespaces"""
echo-e"\n=== 测试没有权限的操作 ==="
test_permission"create""pods""test-ns-1" # 应该不行
test_permission"delete""configmaps""test-ns-2"# 应该不行
test_permission"get""secrets""default" # 应该不行
echo-e"\n4. 查看完整权限列表..."
echo"在所有命名空间的权限:"
kubectlauthcan-i--list--as=system:serviceaccount:default:cluster-sa
echo-e"\n5. 创建测试Pod进行实际验证..."
cat<<EOF|kubectlapply-f-
apiVersion:v1
kind:Pod
metadata:
name:rbac-tester
namespace:default
spec:
serviceAccountName:cluster-sa
containers:
-name:kubectl
image:bitnami/kubectl:latest
command: ["sleep", "infinity"]
EOF
echo"等待测试Pod就绪..."
kubectlwait--for=condition=Readypod/rbac-tester-ndefault--timeout=30s
echo-e"\n6. 实际执行测试..."
echo"=== 测试1: 查看所有命名空间的pods ==="
kubectlexec-itrbac-tester-ndefault--kubectlgetpods--all-namespaces|head-10
echo-e"\n=== 测试2: 查看所有命名空间的configmaps ==="
kubectlexec-itrbac-tester-ndefault--kubectlgetconfigmaps--all-namespaces|head-10
echo-e"\n=== 测试3: 查看节点信息 ==="
kubectlexec-itrbac-tester-ndefault--kubectlgetnodes
echo-e"\n=== 测试4: 查看所有命名空间 ==="
kubectlexec-itrbac-tester-ndefault--kubectlgetnamespaces
echo-e"\n=== 测试5: 尝试创建pod(应该失败)==="
kubectlexec-itrbac-tester-ndefault--kubectlruntest-pod--image=busybox--sleep3600 2>&1|head-3||echo"创建失败(符合预期)"
echo-e"\n=== 测试6: 尝试删除configmap(应该失败)==="
kubectlexec-itrbac-tester-ndefault--kubectldeleteconfigmaptest-config-1-ntest-ns-12>&1|head-3||echo"删除失败(符合预期)"
echo-e"\n7. 清理测试Pod..."
kubectldeletepodrbac-tester-ndefault
echo-e"\n=============================================="
echo"测试完成!"
echo"=============================================="
echo"创建的资源:"
echo" - ClusterRole: cluster-viewer"
echo" - ServiceAccount: default:cluster-sa"
echo" - ClusterRoleBinding: cluster-sa-binding"
echo" - 测试命名空间: test-ns-1, test-ns-2"
echo""
echo"验证的权限:"
echo" ✅ 可以查看所有命名空间的 pods"
echo" ✅ 可以查看所有命名空间的 configmaps"
echo" ✅ 可以查看节点信息"
echo" ✅ 可以查看命名空间"
echo" ❌ 不能创建/删除 pods"
echo" ❌ 不能创建/删除 configmaps"
echo" ❌ 不能查看 secrets"
echo"=============================================="
echo-e"\n清理命令:"
echo" kubectl delete -f cluster-role.yaml"
echo" kubectl delete -f cluster-sa.yaml"
echo" kubectl delete -f cluster-binding.yaml"
echo " kubectl delete -f test-resources.yaml"
集群角色+角色绑定
ClusterRole+RoleBinding
集群角色进行了赋权,但是角色绑定时赋予了命名空间,那这个集群角色就降级为这个命名空间的权限了,为什么已经有角色+角色的绑定、也有了集群角色+集群角色的绑定了,还要弄一个集群角色+角色的绑定
因为一个集群角色可以绑定多个命名空间级的服务、账号,这样就不用对应每个账户、服务都去创建一个角色了
- • ClusterRole 集群角色降级到单命名空间范围
- • RoleBinding 是命名空间级,但是可以搭配集群角色使用搭配后集群角色就仅限于当前命名空间内了
- • 比如:多 team 多 namespace 分权管理:共用 ClusterRole,但绑定到不同 namespace
把集群角色绑定到具体的 用户(User)/组(Group)/服务账户(ServiceAccount)
而这些用户、组、sa 的权限是 role 定义的
apiVersion: rbac.authorization.k8s.io/v1
kind:RoleBinding
metadata:
name:pod-manager-binding
namespace:my-namespace
subjects:
-kind:User
name:alice
apiGroup:rbac.authorization.k8s.io
roleRef:
kind:Role
name:pod-manager # 对应创建的 Role进行绑定
apiGroup:rbac.authorization.k8s.io
集群角色(ClusterRole)与角色绑定实验
# all.yaml
---
apiVersion:v1
kind:Namespace
metadata:
name:test-ns
---
apiVersion:v1
kind:Namespace
metadata:
name:other-ns
---
apiVersion:v1
kind:ServiceAccount
metadata:
name:test-sa
namespace:test-ns
---
apiVersion:v1
kind:ServiceAccount
metadata:
name:other-sa
namespace:other-ns
---
apiVersion:rbac.authorization.k8s.io/v1
kind:ClusterRole
metadata:
name:pod-viewer-cr
rules:
-apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
-apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list"]
---
apiVersion:rbac.authorization.k8s.io/v1
kind:RoleBinding
metadata:
name:pod-viewer-binding
namespace:test-ns
roleRef:
apiGroup:rbac.authorization.k8s.io
kind:ClusterRole
name:pod-viewer-cr
subjects:
-kind:ServiceAccount
name:test-sa
namespace:test-ns
---
apiVersion:v1
kind:Pod
metadata:
name:test-pod-1
namespace:test-ns
spec:
containers:
-name:nginx
image:docker.xuanyuan.run/nginx:alpine
ports:
-containerPort:80
---
apiVersion:v1
kind:Pod
metadata:
name:test-pod-2
namespace:other-ns
spec:
containers:
-name:nginx
image:docker.xuanyuan.run/nginx:alpine
ports:
-containerPort:80
---
apiVersion:apps/v1
kind:Deployment
metadata:
name:test-deploy
namespace:test-ns
spec:
replicas:1
selector:
matchLabels:
app:test-app
template:
metadata:
labels:
app:test-app
spec:
containers:
-name:nginx
image:docker.xuanyuan.run/nginx:alpine
ports:
-containerPort: 80
在这里插入图片描述
subjects
被授权对象
角色绑定和集群角色绑定可以将 Role 绑定到 subjects,subjects 可以是组、用户、SA,一般在服务中是创建 SA,而我们的开发,运维也需要账户对 k8s 进行管理使用,使用的就是账户
subjects 中的 user 使用字符串,可以是普通字符串、邮箱地址、数字、但是 user 的前缀不能是 system,可以理解为 C 语言里的保留字符
创建账户实现资源分割实验
创建对应的 k8s 账户——》给到对应的开发人员——〉给这个账户进行签名——》给这个账户进行角色绑定(绑定开发应有的权限)——〉赋权——》使用
在项目中,一般通过创建用户,管理一个命名空间的资源,在不借助外部系统(如堡垒机)、资源的情况下实现
创建证书
证书最好有指定的位置进行保存,可以放在默认目录下
/etc/kubernetes/pki/
devuser.json
这个文件声明了证书的组、用户名等其它信息,但是这些信息没有被认证,需要签名后这个叫 devuser 的用户才会生效
{
"CN":"devuser",
"hosts": [],
"key": {
"algo":"rsa",
"size":2048
},
"names": [
{
"C":"CN",
"ST":"BeiJing",
"L":"BeiJing",
"O":"k8s",
"OU":"System"
}
]
}
下载安装 cfssl 工具链,用于给我们的 devuser 生成 CSR 并签名
https://github.com/cloudflare/cfssl/
下载
cfssl、cfssljson、cfssl-certinfo,并赋权
curl -xhttp://192.168.10.107:7897-Lhttps://github.com/cloudflare/cfssl/releases/download/v1.6.5/cfssl_1.6.5_linux_amd64-o/usr/local/bin/cfssl
curl-xhttp://192.168.10.107:7897-Lhttps://github.com/cloudflare/cfssl/releases/download/v1.6.5/cfssljson_1.6.5_linux_amd64-o/usr/local/bin/cfssljson
curl-xhttp://192.168.10.107:7897-Lhttps://github.com/cloudflare/cfssl/releases/download/v1.6.5/cfssl-certinfo_1.6.5_linux_amd64-o/usr/local/bin/cfssl-certinfo
chmod+x/usr/local/bin/cfssl/usr/local/bin/cfssljson/usr/local/bin/cfssl-certinfo
cfsslversion
cfssljson-h
cfssl-certinfo -h
使用 k8s 集群的 CA 机构的私钥和公钥,给要创建的用户签名,代表认可这个账户信息
cfssl gencert -ca=/etc/kubernetes/pki/ca.crt -ca-key=/etc/kubernetes/pki/ca.key -profile=kubernetes /etc/kubernetes/pki/user/devuser.json | cfssljson -bare devuser
设置客户端认证参数
也就是客户端的认证信息
设置一个凭据,叫 devuser
设置这个 devuser 的证书
设置这个 devuser 的私钥
认证为 true,代表需要证书认证
kubeconfig 输出为 devuser.kubeconfig
kubectl config set-credentials devuser \
--client-certificate=devuser.pem \
--client-key=devuser-key.pem \
--embed-certs=true \
--kubeconfig=devuser.kubeconfig
这时,就有了客户端的公钥、私钥、以及公私钥的所有者,但是我们的身份认证是双向的,所以需要本地客户端有了,服务端也需要有对应的证书才行。
设置集群参数
设置环境变量 apiserver 的地址
指定集群的名字,一个大的集群下可能有多个集群,但是一般的项目一个集群就够了,默认就是kubernetes
指定 ca 根证书,这个证书是 k8s 集群在部署的时候自动生成的
认证为 true,代表需要证书认证
kubeconfig 输出为 devuser.kubeconfig
export KUBE_APISERVER="https://192.168.66.11:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=ca.crt \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=devuser.kubeconfig
创建好后的 kubeconfig 文件就有服务端的信息了,它包含 apiserver 的地址,ca 证书,指定的那个集群
设置上下文
上下文将客户端的公私钥和服务端的公钥、地址、集群名字绑定在一起
设置了这个客户端、服务端使用的集群,集群名字
设置了客户端的 user
设置了客户端的命名空间为 dev,那这个账户的所有权就只在 dev 这个命名空间内了
输出到devuser.kubeconfig
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=devuser \
--namespace=dev \
--kubeconfig=devuser.kubeconfig
设置上下文连接,此时的上下文已经创建好了,但是上下文没有关联,因为一个 config 里可以放多个集群、用户、上下文,所以需要关联上下文
kubectl config use-context kubernetes --kubeconfig=devuser.kubeconfig
这时,这个 kubeconfig 已经可以连接上 apiserver 了,但是还没有权限,把这个配置文件 copy 到对应的开发电脑上,他就可以跟 APIserver 通信了
linux/mac
/root/.kube/config
windows
%USERPROFILE%\.kube\config
角色绑定
创建命名空间
apiVersion: v1
kind: Namespace
metadata:
name: dev
也可以使用命令
# kubectl create ns dev --dry-run -o yaml
kubectl create ns dev
角色绑定与赋权
创建一个角色绑定,名为devuser-admin-binding
将这个 user 为 devuser 的、命名空间为 dev 的用户绑定到clusterrole= admin
虽然组是集群管理员,但是因为命名空间被限制,所以他的权限也仅限于 dev 这个环境变量下
注意,这里没有自定义角色,而是使用的 k8s 默认预设的一个集群角色,叫admin,这个在上面的 RBAC 里有讲过
kubectl create rolebinding devuser-admin-binding --clusterrole=admin --user=devuser --namespace=dev
这条命令对应的资源清单就是这样的
apiVersion: rbac.authorization.k8s.io/v1
kind:RoleBinding
metadata:
creationTimestamp:null
name:devuser-admin-binding
namespace:dev
roleRef:
apiGroup:rbac.authorization.k8s.io
kind:ClusterRole
name:admin
subjects:
-apiGroup:rbac.authorization.k8s.io
kind:User
name: devuser
一个开发可能拥有多个 kubeconfig,可以通过–kubeconfig 来进行切换,对应的也可以是我们的 dev、uat、test 等等这种概念
kubectl config use-context kubernetes --kubeconfig=devuser.kubeconfig
测试生成的新账户
将 config 给到开发的电脑上
kubectl config view
配置好后确认一下权限,dev 以外的环境变量是没有权限的
一般项目中有多个开发、测试,那就需要创建多个证书信息文件 *.json,然后都进行签名、客户端证书的生成、服务端证书的生成,后面的角色绑定其实就是对开发和测试的权限做限制。
准入控制
https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
有权限,但需要合理,官方给了一些准入控制的插件,可以理解为准入规则包
默认启用的准入插件
kubectl logs -n kube-system kube-apiserver-k8s-master01 | grep 'Admission'
查看当前版本默认开启了哪些额外插件,额外的插件是指没有默认启用的
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep enable-admission-plugins
两种类型
Mutating
mutating admission controller(s)
修改类型插件,自动化一些操作
Validating
validating admission controller(s)
验证类型插件,只验,不修改
插件列表
Mutating
NamespaceLifecycle
- • NS 生命周期保护
- • 建议开启
LimitRanger
- • 自动补全资源限制
- • 建议开启
ServiceAccount
- • 实现自动化添加 ServiceAccount
ResourceQuota
- • 确保资源不会超过限制
后面会单独研究安全这一块内容
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:摸鱼信安 摸鱼信安《K8s集群安全|集群安全机制》