深入理解K8S【安全认证机制】
1 核心概念
1.1 安全体系
对于大型系统来说,对业务的权限、网络的安全认证是必不可少的。
K8S权限及认证(3A):
K8s安全校验流程解析:
①上图左侧的用户:
- kubernetes主要有两种用户:
- User Account:普通人类用户(交互模式)
- Service Account:集群内部的pod用户(服务进程)
②中间:每个部分都是以插件的方式来整合到 kubernetes 集群环境中:
认证和授权是按照插件的顺序依次进行检测,并且遵循 “短路模型” 的认证方式所谓的"短路"即,失败的时候,到此结束,后续的规则不会进行。
准入控制 由于仅用户写操作场景,所以它不遵循 “短路模型”,而是会全部检测通过才允许执行原因在于,它要记录为什么不执行,原因是什么,方便后续审计等动作。
③右侧部分:k8s资源
1.2 认证机制
1.2.1 k8s中的用户
1.2.2 用户组(类比windows用户组)
①查看集群中的用户和组(CN和OU):openssl x509 -in xx-apiserver.crt -text -noout
例如:查看用户组system:master权限
# 以rancher搭建的k8s为例
# 查看集群中的用户关系
openssl x509 -in /var/lib/rancher/rke2/server/tls/client-kube-apiserver.crt -text -noout
结果:
Certificate:
...
Issuer: CN = kubernetes
Validity
Not Before: Oct 3 03:06:43 2021 GMT
Not After : Oct 3 03:06:43 2022 GMT
Subject: O=system:masters, CN=kube-apiserver-kubelet-client
...
结果显示:对于kubelet,用户名是kube-apiserver-kubelet-client,而且属于system:master的组,这两者的关系是在基于openssl或者csffl工具创建用户时候基于CN和O来设定的信息。
②查看集群角色权限:kubectl get clusterrole cluster-admin -o yaml
# 查看k8s cluster-admin的用户权限
kubectl get clusterrole cluster-admin -o yaml
③查看集群和用户角色绑定关系:kubectl get clusterrolebinding cluster-admin -o yaml
# 查看cluster-admin这个绑定配置,做了什么配置
kubectl get clusterrolebinding cluster-admin -o yaml
...
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole # 被绑定人拥有cluster-admin用户的权限
name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
# 将system:masters里的所有人都应用该绑定关系
name: system:masters
1.2.3 认证插件
API Server启用的身份认证机制:
- 基于认证插件支持多种认证方式,而相应认证插件的启用需要经由kube-apiserver上的专用选项完成
- kubeadm 部署的集群默认启用的认证机制包括如下几种:
- X509客户端证书认证
- Bootstrap令牌认证
- 前端代理身份认证 front-proxy
- Service Account 令牌
注意:API Server并不保证各认证插件的生效次序与定义的次序相同(认证插件遵循或
关系,有一个认证通过就放行,不再进行其他认证插件的校验。直接进入下一步授权)
# 在master节点查看认证机制
cat /etc/kubernetes/manifests/kube-apiserver.yaml
①X509客户端证书认证(TSL双向认证):k8s ca.crt签发证书
②Token令牌认证:节点数量很多,直接通过token进行通信
③代理认证
④匿名方式
2 实战
2.1 User Account管理
2.1.1 X509客户端认证(k8s集群维护了三套CA证书系统)
Kubernetes集群中的X509客户端认证依赖于PKI证书体系,有如下三套CA证书系统
kubeadm部署Kubernetes集群时会自动生成所需要的证书,它们位于/etc/kubernetes/pki自录下
文件 | Default CN | 说明 |
---|---|---|
ca.crt,ca.key | kubernetes-ca | Kubernetes general CA |
etcd/ca.crt,etcd/ca.key | etcd-ca | For all etcd-related functions |
front-proxy-ca.crt,front-proxyca.crt.key | kubernetes-frontproxy-ca | For the front-end proxy |
2.1.2 X509创建用户证书(普通用户、管理员)
①创建普通用户
# 执行下面命令后展示的内容,表示默认kubernetes的CA签发的证书,都是k8s客户端的用户
grep '\-\-client-ca-file' /etc/kubernetes/manifests/kubeapiserver.yaml
- --client-ca-file=/etc/kubernetes/pki/ca.crt
# 创建存放证书的目录
mkdir pki
(umask 077; openssl genrsa -out pki/test.key 4096)
# 生成证书申请,加入ops组只具有普通权限
openssl req -new -key pki/test.key -out pki/test.csr -subj
"/CN=test/O=ops"
# 使用kubernetes-ca颁发证书
openssl x509 -req -days 3650 -CA /etc/kubernetes/pki/ca.crt -
CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -in pki/test.csr -out
pki/test.crt
#复制证书文件到到worker节点
#执行kubectl命令并指定apiserver地址和test用户的证书等信息
kubectl get pod --server=https://192.xx.xxx.xx:6443 --clientcertificate=pki/test.crt --client-key=pki/test.key --certificateauthority=/etc/kubernetes/pki/ca.crt
# Error from server (Forbidden): pods is forbidden: User "test" cannot list resource "pods" in API group "" in the namespace "default"
解决:
方法一:提升test用户的权限,加入管理员组或绑定其他权限
方法二:忽略证书校验
kubectl get pod -s https://192.xx.xxx.xx:6443 --clientcertificate=pki/test.crt --client-key=pki/test.key --insecure-skip-tlsverify=true
# 如果没有kubectl命令,也可以通过curl命令验证
curl --cert pki/test.crt --key pki/test.key --key-type PEM --
cacert /etc/kubernetes/pki/ca.crt https://192.xx.xxx.xx:6443
②创建管理员
# 创建管理员用户testuser证书
(umask 077; openssl genrsa -out pki/testuser.key 4096)
#生成证书申请文件,注意:加入system:masters组或System组才具有管理权限
openssl req -new -key pki/testuser.key -out pki/testuser.csr -subj
"/CN=testuser/O=system:masters"
# 通过k8s ca签发证书
openssl x509 -req -days 3650 -CA /etc/kubernetes/pki/ca.crt -
CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -in pki/testuser.csr -out pki/testuser.crt
# 查看目录下的文件(应该有testuser.csr testuser.key testuser.crt文件)
ls pki
# 使用证书访问节点,观察是否有权限获取pod
kubectl get pods -s https://192.xx.xxx.xx:6443 --certificateauthority=/etc/kubernetes/pki/ca.crt --client-certificate=pki/testuser.crt --clientkey=pki/testuser.key
2.2 ServiceAccount管理
2.2.1 ServiceAccount概念
# 查看pod配置 -o yaml以yaml格式输出,-o json以json格式输出
kubectl get po nginx-statefulset-0 -o yaml | grep -C 9 -i ServiceAccount
2.2.2 创建&使用ServiceAccount
①查看和创建新SA
查看SA:
#每个命名空间都会有一个默认的default的SA账号名称
kubectl get sa -A
创建SA:
# 创建namespace
kubectl create ns mynamespace
mysa.yml:
apiVersion: v1
kind: ServiceAccount
metadata:
name: mysa
namespace: mynamespace # 指定命名空间,可忽略
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: myrole
namespace: mynamespace # 确保与ServiceAccount在同一命名空间
rules:
- apiGroups: [""]
resources: ["pods", "services", "secrets"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: bind-mysa-to-myrole
namespace: mynamespace # 同样,确保与ServiceAccount和Role在同一命名空间
subjects:
- kind: ServiceAccount
name: mysa
namespace: mynamespace
roleRef:
kind: Role
name: myrole
apiGroup: rbac.authorization.k8s.io
#创建账号
kubectl apply -f mysa.yml
# 查看sa账号(我们在mynamespace创建的,这里需要指定名称空间)
kubectl get sa -n mynamespace -o wide | grep mysa
# 查看sa详情信息
kubectl describe sa -n mynamespace
# 查看ServiceAccount的Secret信息
kubectl get secrets -n mynamespace
# 查看ServiceAccount详情
kubectl get sa mysa -n mynamespace -o yaml
②应用SA
在pod资源中一个属性专门来设置该资源属于哪个SA管理
# 查看pod.spec.serviceAccountName作用
kubectl explain pod.spec.serviceAccountName
# 创建rolebonding(给mynamespace的mysa赋予admin权限)
kubectl create clusterrolebinding mysa-clusterrolebinding --clusterrole=admin --serviceaccount=mynamespace:mysa
2.3 kubectlconfig管理
总结:
- kubectlconfig文件(yaml格式文件)清晰明了,方便下载
- kubectlconfig支持配置多个环境。(类比Java SpringBoot多环境yml配置:dev、pre、pro)
2.3.1 kubectlconfig概念
kubectl管理多个context,每个context包含了访问k8s集群必要的两个配置:用户、地址。
- clusters:每个Kubernetes集群的信息,包括集群对应访问端点(API Server)的地址
- users:认证到API Server的用户的身份凭据列表
- contexts:将每一个user同可认证到的cluster建立关联关系的上下文列表
- current-context:当前默认使用的context
# 查看帮助手册
kubectl config --help
Available Commands:
current-context 显示 current_context
delete-cluster 删除 kubeconfig 文件中指定的集群
delete-context 删除 kubeconfig 文件中指定的 context
delete-user Delete the specified user from the kubeconfig
get-clusters 显示 kubeconfig 文件中定义的集群
get-contexts 描述一个或多个 contexts
get-users Display users defined in the kubeconfig
rename-context Renames a context from the kubeconfig file.
set 设置 kubeconfig 文件中的一个单个值
set-cluster 设置 kubeconfig 文件中的一个集群条目
set-context 设置 kubeconfig 文件中的一个 context 条目
set-credentials 设置 kubeconfig 文件中的一个用户条目
unset 取消设置 kubeconfig 文件中的一个单个值
use-context 设置 kubeconfig 文件中的当前上下文
view 显示合并的 kubeconfig 配置或一个指定的 kubeconfig 文件
# 例如:查看当前使用的context
kubectl config current-context
# 使用testuser-context,后续执行kubectl命令
#会自动读取testuser-context存储的集群及用户凭证信息
kubectl config use-context testuser-context
3 安全认证综合案例
3.1 UserAccount创建&使用kubetlconfig
3.1.1 UserAccount创建
最终生成的文件:.key 是私钥,.csr是签名请求文件,.crt是证书
# 1 创建私钥文件
(umask 077; openssl genrsa -out user1.key 2048)
# 2 签名请求
openssl req -new -key user1.key -out user1.csr -subj "/CN=user1/O=group"
# 3 利用k8s ca机构签发证书
openssl x509 -req -in user1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out user1.crt -days 365
#结果显示:*.key 是私钥,*.csr是签名请求文件
# 查看证书信息
openssl x509 -in user1.crt -text -noout
3.1.2 使用kubectlconfig
①创建kubectlconfig用户
# 1 指定用户证书、私钥,以及生成的conf文件位置
kubectl config set-credentials user1 --embed-certs=true --client-certificate=user1.crt --client-key=user1.key --kubeconfig=/tmp/user1.conf
②创建kubectlconfig集群
# --certificateauthority配置k8s ca证书路径
kubectl config set-cluster mycluster --server="https://localhost:6443" --embed-certs=true --kubeconfig=/tmp/user1.conf --certificate-authority=ca.crt
③创建context(关联集群)
kubectl config set-context user1@mycluster --cluster=mycluster --user=user1 --kubeconfig=/tmp/user1.conf
查看配置文件最后效果:
kubectl config view --kubeconfig=/tmp/user1.conf
# 解析client-certificate-data、client-key-data(base64方式解析证书信息)
# kubectl config view --kubeconfig=/tmp/user1.conf --raw
总结
openssl genrsa -out user1.key 2048
# 生成证书签名请求
openssl req -new -key user1.key -out user1.csr -subj "/CN=user1/O=group"
# 使用集群的CA证书和私钥对证书签名请求进行签名
openssl x509 -req -in user1.csr -CA /var/lib/rancher/rke2/server/tls/client-ca.crt -CAkey /var/lib/rancher/rke2/server/tls/client-ca.key -CAcreateserial -out user1.crt -days 365
# 创建一个kubectl配置文件(--embed-certs=true将认证内嵌其中)
kubectl config set-credentials user1 --embed-certs=true --client-certificate=user1.crt --client-key=user1.key
# 查看配置信息(并且显示认证信息(经过base64编码))
kubectl config view --raw
# 设置上下文
kubectl config set-context user1-context --cluster=default --namespace=default --user=user1
# 切换到user1用户
kubectl config use-context user1-context
# 设置context证书文件
# kubectl config --kubeconfig=/root/user1/user1.yml set-credentials user1-context --client-certificate=/root/user1/user1.crt --client-key=/root/user1/user1.key
user1-clusterrole.yml:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: user1-clusterrole
rules:
- apiGroups: [ "*" ]
resources: [ "*" ]
verbs: [ "*" ]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: user1-clusterrole-binding
subjects:
- kind: User
name: user1 # 将user1应用ClusterRoleBinding
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: user1-clusterrole # ClusterRoleBinding绑定user1-clusterrole这个ClusterRole
apiGroup: rbac.authorization.k8s.io
3.2 SA账号创建&使用kubectlconfig
- 创建sa账号
security-sa-admin.yaml:
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin
namespace: default
---
#v1.24版之后添加下面内容手动创建secret
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: admin-secret
annotations:
kubernetes.io/service-account.name: "admin"
# 应用配置文件
kubectl apply -f security-sa-admin.yaml
2. 查看和配置kubectlconfig
# 查看SA账号的Token
kubectl get secret admin-secret -n default -o jsonpath='{.data.token}' |base64 -d
# 将获取到的token设置到KUBEADMIN_TOKEN字段
KUBEADMIN_TOKEN=$(kubectl get secret admin-secret -n default -o jsonpath='{.data.token}' |base64 -d)
# 设置用户信息
kubectl config set-credentials kubeadmin --token=$KUBEADMIN_TOKEN --kubeconfig=/root/kubeadmin.conf
# 设置集群信息--certificate-authority
kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server="https://localhost:6443" --embed-certs=true --kubeconfig=/root/kubeadmin.conf
# 设置上下文信息context(集群及用户信息)
kubectl config set-context kubeadmin@kubernetes --cluster=kubernetes --user=kubeadmin --kubeconfig=/root/kubeadmin.conf
# 指定默认context
kubectl config use-context kubeadmin@kubernetes --kubeconfig=/root/kubeadmin.conf
# 给admin角色设置admin权限
kubectl create clusterrolebinding admin-binding --serviceaccount default:admin --clusterrole cluster-admin