37、K8S-安全机制-CA、User、Cluster
1、证书信息
1.1、简介
我们知道,通过kubeadm在创建集群的时候,其中有一步就是:生成kubernetes控制组件的kubeconfig文
件及相关的启动配置文件,通过各种conf文件,让不同的组件具备操作相关资源的权限。
1.2、位置
master1 ~]# ll /etc/kubernetes/pki/ -rw-r--r-- 1 root root 1310 Mar 16 20:42 apiserver.crt -rw-r--r-- 1 root root 1155 Mar 16 20:42 apiserver-etcd-client.crt -rw------- 1 root root 1679 Mar 16 20:42 apiserver-etcd-client.key -rw------- 1 root root 1675 Mar 16 20:42 apiserver.key -rw-r--r-- 1 root root 1164 Mar 16 20:42 apiserver-kubelet-client.crt -rw------- 1 root root 1675 Mar 16 20:42 apiserver-kubelet-client.key -rw-r--r-- 1 root root 1099 Mar 16 20:06 ca.crt -rw------- 1 root root 1675 Mar 16 20:06 ca.key drwxr-xr-x 2 root root 162 Mar 16 20:06 etcd -rw-r--r-- 1 root root 1115 Mar 16 20:06 front-proxy-ca.crt -rw------- 1 root root 1679 Mar 16 20:06 front-proxy-ca.key -rw-r--r-- 1 root root 1119 Mar 16 20:42 front-proxy-client.crt -rw------- 1 root root 1679 Mar 16 20:42 front-proxy-client.key -rw------- 1 root root 1675 Mar 16 20:06 sa.key -rw------- 1 root root 451 Mar 16 20:06 sa.pub master1 ~]# ll /etc/kubernetes/manifests/ -rw------- 1 root root 2402 Mar 16 20:06 etcd.yaml -rw------- 1 root root 3372 Mar 16 20:42 kube-apiserver.yaml -rw------- 1 root root 2878 Mar 16 20:42 kube-controller-manager.yaml -rw------- 1 root root 1464 Mar 16 20:42 kube-scheduler.yaml
1.3、配置信息
1.3.1、kubectl config命令解析
master1 ~]# kubectl config -h Modify kubeconfig files using subcommands like "kubectl config set current-context my-context" # 配置的加载顺序 1. --kubeconfig flag 2. $KUBECONFIG environment variable 3. ${HOME}/.kube/config Available Commands: current-context # 显示 current_context delete-cluster # 删除 kubeconfig 文件中指定的集群 delete-context # 删除 kubeconfig 文件中指定的 context get-clusters # 显示 kubeconfig 文件中定义的集群 get-contexts # 描述一个或多个 contexts rename-context # 重命名上下文 set # 设置 kubeconfig 文件中的一个单个值 set-cluster # 设置 kubeconfig 文件中的一个集群条目 set-context # 设置 kubeconfig 文件中的一个 context 条目 set-credentials # 设置 kubeconfig 文件中的一个用户条目 unset # 取消设置 kubeconfig 文件中的一个单个值 use-context # 设置 kubeconfig 文件中的当前上下文 view # 显示合并的 kubeconfig 配置或一个指定的 kubeconfig 文件 Usage: kubectl config SUBCOMMAND [options] 结果显示: 对于一个用户账号来说,至少包含了三部分: 1、用户条目-credentials 设定具体的user account名称 2、集群-cluster 设定该user account所工作的区域 3、上下文环境-context 设定用户和集群的关系
1.3.2、kubectl config view-查看当前的配置内容
master1 ~]# kubectl config view apiVersion: v1 clusters: - cluster: # 集群列表 certificate-authority-data: DATA+OMITTED # 证书的认证方式 server: https://vip.k8test.com:6443 # api_server 的地址 name: kubernetes # 当前集群的名称 contexts: # 上下文列表,一般指的是多集群间用户的切换所需的环境属性 - context: cluster: kubernetes # 集群名称kubernetes user: kubernetes-admin # 使用kubernetes-admin用户来访问集群kubernetes name: kubernetes-admin@kubernetes # 该context的名称标准写法 current-context: kubernetes-admin@kubernetes # 当前上下文的名称 kind: Config preferences: {} users: # 用户列表 - name: kubernetes-admin # 用户名称 user: client-certificate-data: REDACTED # 客户端证书 client-key-data: REDACTED # 客户端密钥 总结: 一个config主要包含了三部分内容:users、clusters、contexts,每个部分都有两部分组成: name和user|cluster|context 对于cluster,对外的地址-server 和 基本的认证方式-certificate-authority-data 对于context,连接到的集群-cluster 和 连接集群的用户-user 对于user,连接集群的认证方式-client-certificate-data 和 私钥信息-client-key-data current-context表明我们是处于哪一个环境中。
1.4、kubectl加载配置的3种方法
1.4.1、--kubeconfig
node1 ~]# kubectl --kubeconfig /opt/admin.conf get nodes NAME STATUS ROLES AGE VERSION master1 Ready control-plane 13d v1.25.7 master2 Ready control-plane 13d v1.25.7 master3 Ready control-plane 13d v1.25.7 node1 Ready <none> 13d v1.25.7 node2 Ready <none> 13d v1.25.7
1.4.2、KUBECONFIG
export KUBECONFIG=/opt/admin.conf node1 ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION master1 Ready control-plane 13d v1.25.7 master2 Ready control-plane 13d v1.25.7 master3 Ready control-plane 13d v1.25.7 node1 Ready <none> 13d v1.25.7 node2 Ready <none> 13d v1.25.7
1.4.3、.kube
mkdir ~/.kube -p cp /opt/admin.conf ~/.kube/config node1 ~]# kubectl get node NAME STATUS ROLES AGE VERSION master1 Ready control-plane 13d v1.25.7 master2 Ready control-plane 13d v1.25.7 master3 Ready control-plane 13d v1.25.7 node1 Ready <none> 13d v1.25.7 node2 Ready <none> 13d v1.25.7
1.5、kubectl流程图
1.6、K8S-证书体系
1.6.1、证书体系图
1.6.2、证书对应表
参考官网:https://kubernetes.io/zh-cn/docs/setup/best-practices/certificates/
默认 CN | 父级 CA | O(位于 Subject 中) | kind | 主机 (SAN) |
---|---|---|---|---|
kube-etcd | etcd-ca | server, client | <hostname> , <Host_IP> , localhost , 127.0.0.1 |
|
kube-etcd-peer | etcd-ca | server, client | <hostname> , <Host_IP> , localhost , 127.0.0.1 |
|
kube-etcd-healthcheck-client | etcd-ca | client | ||
kube-apiserver-etcd-client | etcd-ca | system:masters | client | |
kube-apiserver | kubernetes-ca | server | <hostname> , <Host_IP> , <advertise_IP> , [1] |
|
kube-apiserver-kubelet-client | kubernetes-ca | system:masters | client | |
front-proxy-client | kubernetes-front-proxy-ca | client |
1.7、权限关系
1.7.1、用户组
我们知道所有的资源操作,其实都是node结点上的kubelet和master结点上的apiserver中间的通信,而 在kubernetes的认证目录中尤其专用的通信认证证书 apiserver-kubelet-client.crt,我们可以通 过该文件来检查一下这两者之间是一个怎样的关系。 ]# cd /etc/kubernetes/pki/ ]# openssl x509 -in ./apiserver-kubelet-client.crt -text -noout Certificate: Validity Not Before: Mar 16 12:06:54 2023 GMT Not After : Mar 15 12:42:10 2024 GMT Subject: O=system:masters, CN=kube-apiserver-kubelet-client Subject Public Key Info: Public Key Algorithm: rsaEncryption ... 结果显示: 对于kubelet来说,他的用户名是kube-apiserver-kubelet-client,而且属于system:master 的组,这两者的关系是我们在基于openssl或者csffl工具创建用户时候基于CN和O来设定的信息。
1.7.2、绑定关系
在我们的集群环境中有一个资源叫clusterrolebindings,该资源会基于用户的名称或者组信息将其绑定到 一个权限列表中(即clusterrole),在这个绑定关系中有一个cluster-admin,在这里面定义了group和clusterrole之间的关系。 master1 ~]# kubectl describe clusterrolebindings cluster-admin Name: cluster-admin Labels: kubernetes.io/bootstrapping=rbac-defaults Annotations: rbac.authorization.kubernetes.io/autoupdate: true Role: Kind: ClusterRole Name: cluster-admin Subjects: Kind Name Namespace ---- ---- --------- Group system:masters master1 ~]# kubectl get clusterrolebindings cluster-admin -o yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: annotations: rbac.authorization.kubernetes.io/autoupdate: "true" creationTimestamp: "2023-03-16T12:07:00Z" labels: kubernetes.io/bootstrapping: rbac-defaults name: cluster-admin resourceVersion: "131" uid: 7e9e1f2f-0958-42c3-93c2-1057b3efa54f roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: system:masters 总结: 只要是"system:masters"组中的成员,都具有cluster-admin的所有权限
1.7.3、角色权限
master1 ~]# kubectl describe clusterrole cluster-admin Name: cluster-admin Labels: kubernetes.io/bootstrapping=rbac-defaults Annotations: rbac.authorization.kubernetes.io/autoupdate: true PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- *.* [] [] [*] [*] [] [*] # 对于cluster-admin来说,它拥有所有资源在所有空间的所有权限。
2、创建用户关联集群认证-实践【重点】
2.1、基本流程
1、创建私钥文件 2、基于私钥文件创建证书签名请求 3、基于私钥和签名请求生成证书文件 4、基于tls文件在k8s上创建用户 5、创建工作区域-cluster 6、将cluster和user关联起来-context 7、验证效果
2.2、技术关键点
这七步各有操作关键点,我们在操作之前必须提前认识清楚,否则的话,在执行过程中,会遇到各种意外。 1、创建私钥文件 对于用户名和用户组需要提前规划好,如果用户多权限集中的情况下,一定要规划好用户组信息 2、基于私钥文件创建证书签名请求 要基于我们自建的私钥来创建签证请求文件 3、基于私钥和签名请求生成证书文件 因为我们的生成的证书要应用在kubernetes环境中,所以必须由kubernetes的全局证书来认证 4、基于tls文件在k8s上创建用户 我们说过kubernetes平台上的普通用户需要基于秘钥认证通信 5、创建工作区域-cluster 所谓的工作区域是用户的工作场景,必须定制好,一个cluster可以被多个用户使用 6、将cluster和user关联起来-context 关联的作用就是,将用户和区域整合在一起,我们使用资源的时候便于调用 7、验证效果 因为我们主要做的是认证,而用户的操作涉及到资源权限,这部分是需要结合授权机制来进行的 默认情况下,基于创建好的文件来获取资源是被forbidden的
2.3、开始实操
2.3.1、创建私钥文件
给用户 cyc 创建一个私钥,命名成:cyc.key(无加密) cd /etc/kubernetes/pki/ (umask 077; openssl genrsa -out cyc.key 2048) 命令解析: genrsa 该子命令用于生成RSA私钥,不会生成公钥,因为公钥提取自私钥 -out filename 生成的私钥保存至filename文件,若未指定输出文件,则为标准输出 -numbits 指定私钥的长度,默认1024,该项必须为命令行的最后一项参数 注意: 为了避免对当前环境产生不必要的影响,我们这里使用子shell的方式创建私钥 由于我们后面需要k8s的私钥对用户进行认证,所以我们在k8s的认证文件目录中创建 # 检查创建好的文件 master1 pki]# ll cyc.key -rw------- 1 root root 1675 Mar 30 15:00 cyc.key
2.3.2、签名请求
用刚创建的私钥创建一个证书签名请求文件:cyc.csr openssl req -new -key cyc.key -out cyc.csr -subj '/CN=cyc/O=cyc' 参数说明: -new 生成证书请求文件 -key 指定已有的秘钥文件生成签名请求,必须与-new配合使用 -out 输出证书文件名称 -subj 输入证书拥有者信息,这里指定 CN 以及 O 的值,/表示内容分隔 CN以及O的值对于kubernetes很重要,因为kubernetes会从证书这两个值对应获取相关信息: "CN":Common Name,用于从证书中提取该字段作为请求的用户名 (User Name); 浏览器使用该字段验证网站是否合法; "O":Organization,用于分组认证 注意: 证书名称必须设计好,在我们这里,用户是cyc、组是cyc。 master1 pki]# ll cyc* -rw-r--r-- 1 root root 903 Mar 30 15:03 cyc.csr # 签名请求文件 -rw------- 1 root root 1675 Mar 30 15:00 cyc.key # 私钥
2.3.3、生成证书
刚才的私钥和认证并没有被我们的Kubernetes集群纳入到管理体系,我们需要基于kubeadm集群的CA相关证 书来进行认证,CA相关文件位于/etc/kubernetes/pki/目录下面,我们会利用该目录下面的ca.crt和ca.key两个文件来批准上面的证书请求 master1 pki]# openssl x509 -req -in cyc.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out cyc.crt -days 1000 Signature ok subject=/CN=cyc/O=cyc Getting CA Private Key 参数说明: -req 产生证书签发申请命令 -in 指定需要签名的请求文件 -CA 指定CA证书文件 -CAkey 指定CA证书的秘钥文件 -CAcreateserial 生成唯一的证书序列号 -x509 表示输出一个X509格式的证书 -days 指定证书过期时间为365天 -out 输出证书文件 master1 pki]# ls -l cyc.* -rw-r--r-- 1 root root 989 Mar 30 16:01 cyc.crt # *.crt就是我们最终生成的签证证书 -rw-r--r-- 1 root root 903 Mar 30 15:03 cyc.csr -rw------- 1 root root 1675 Mar 30 15:00 cyc.key master1 pki]# openssl x509 -in cyc.crt -text -noout Certificate: Data: Version: 1 (0x0) Serial Number: aa:fb:cb:30:af:d9:c7:e2 Signature Algorithm: sha256WithRSAEncryption Issuer: CN=kubernetes # 表示是哪个CA机构帮我们认证的 Validity Not Before: Mar 30 08:01:55 2023 GMT Not After : Dec 24 08:01:55 2025 GMT Subject: CN=cyc, O=cyc # 重点在于Subject内容中的请求用户所属的组信息 Subject Public Key Info:
2.3.4、创建k8s用户
# 创建用户 cyc 信息 master1 pki]# kubectl config set-credentials cyc --client-certificate=./cyc.crt --client-key=./cyc.key --embed-certs=true --kubeconfig=/tmp/cyc.conf User "cyc" set. 参数详解: set-credentials 子命令的作用就是给kubeconfig认证文件创建一个用户条目 --client-certificate=path/to/certfile 指定用户的签证证书文件 --client-key=path/to/keyfile 指定用户的私钥文件 --embed-certs=true,在kubeconfig中为用户条目嵌入客户端证书/密钥,默认值是false, --kubeconfig=/path/to/other_config.file 表示将属性信息单独输出到一个文件,不指定的话,表示存到默认的 ~/.kube/config文件中 # 在指定配置文件的users部分增加了一个cyc的普通用户 master1 pki]# kubectl config view --kubeconfig=/tmp/cyc.conf apiVersion: v1 clusters: null contexts: null current-context: "" kind: Config preferences: {} users: - name: cyc user: client-certificate-data: REDACTED # cyc.crt client-key-data: REDACTED # cyc.key
2.3.5、创建集群
# 创建一个新的集群-mycluster master1 pki]# kubectl config set-cluster mycluster --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --kubeconfig=/tmp/cyc.conf --server="https://vip.k8test.com:6443" Cluster "mycluster" set. 参数详解: --server=cluster_api_server --certificate-authority=path/to/certificate/authority 注意: 这里使用到的证书,必须是kubernetes的ca证书。 # 查看clusters集群:用户cyc是否多了一个mycluster集群 master1 ~]# kubectl config view --kubeconfig=/tmp/cyc.conf apiVersion: v1 clusters: - cluster: certificate-authority-data: DATA+OMITTED server: https://vip.k8test.com:6443 name: mycluster contexts: null current-context: "" kind: Config preferences: {} users: - name: cyc user: client-certificate-data: REDACTED client-key-data: REDACTED 属性解析 如果不用--embed-certs=true
需要手动指定ca.crt的位置:certificate-authority: /etc/kubernetes/pki/ca.crt
2.3.6、关联用户和集群
master1 ~]# kubectl config set-context cyc@mycluster --cluster=mycluster --user=cyc --kubeconfig=/tmp/cyc.conf Context "cyc@mycluster" created. 属性详解 --cluster=cluster_nickname 关联的集群名称 --user=user_nickname 关联的用户名称 --namespace=namespace 可以设置该生效的命名空间 # 查看contexts是否关联集群与用户 master1 ~]# kubectl config view --kubeconfig=/tmp/cyc.conf apiVersion: v1 clusters: - cluster: certificate-authority-data: DATA+OMITTED server: https://vip.k8test.com:6443 name: mycluster contexts: - context: cluster: mycluster user: cyc name: cyc@mycluster current-context: "" kind: Config preferences: {} users: - name: cyc user: client-certificate-data: REDACTED client-key-data: REDACTED
2.3.7、验证效果
根据刚才的信息显示,current-context的信息是空,那么我们切换一下用户更改用户 master1 ~]# kubectl config use-context cyc@mycluster --kubeconfig=/tmp/cyc.conf Switched to context "cyc@mycluster". master1 ~]# kubectl config view --kubeconfig=/tmp/cyc.conf apiVersion: v1 clusters: - cluster: certificate-authority-data: DATA+OMITTED server: https://vip.k8test.com:6443 name: mycluster contexts: - context: cluster: mycluster user: cyc name: cyc@mycluster current-context: cyc@mycluster kind: Config preferences: {} users: - name: cyc user: client-certificate-data: REDACTED client-key-data: REDACTED master1 ~]# kubectl get pod --kubeconfig=/tmp/cyc.conf Error from server (Forbidden): pods is forbidden: User "cyc" cannot list resource "pods" in API group "" in the namespace "default" # 简便方法 master1 ~]# kubectl get pod --context=cyc@mycluster --kubeconfig=/tmp/cyc.conf Error from server (Forbidden): pods is forbidden: User "cyc" cannot list resource "pods" in API group "" in the namespace "default" # 虽然认证信息我们配置好了,但是由于权限相关的内容没有设置,所以我们看不了任何资源信息。
3、kubectl加载配置&上下文切换-进阶-实践
3.1、默认的kubectl config-加载配置文件
master1 ~]# kubectl get sa NAME SECRETS AGE admin 0 3h58m default 0 13d 这里使用的配置文件是 ~/.kube/config 文件 master1 ~]# ll ~/.kube/config -rw------- 1 root root 5638 Mar 16 20:10 /root/.kube/config
3.2、--kubeconfig 参数-加载配置文件
master1 ~]# kubectl get sa --kubeconfig=/etc/kubernetes/admin.conf NAME SECRETS AGE admin 0 4h default 0 13d --kubeconfig 参数的优先级要高于 默认的 .kube/config 配置文件
3.3、环境变量-加载配置文件
master1 ~]# export KUBECONFIG='/etc/kubernetes/admin.conf' [root@master1 ~]# kubectl get sa NAME SECRETS AGE admin 0 4h1m default 0 13d # 还没有分配资源,所以查询不了 master1 ~]# export KUBECONFIG="/tmp/cyc.conf" master1 ~]# kubectl get sa Error from server (Forbidden): serviceaccounts is forbidden: User "cyc" cannot list resource "serviceaccounts" in API group "" in the namespace "default" # --kubeconfig 的优先级要高于 环境变量KUBECONFIG master1 ~]# kubectl get sa --kubeconfig=/etc/kubernetes/admin.conf NAME SECRETS AGE admin 0 4h2m default 0 13d
3.4、环境变量-加载配置文件-多配置文件合并查询
3.4.1、环境变量方式-多配置文件合并查询
# 多个文件可以通过冒号隔开 master1 ~]# export KUBECONFIG='/etc/kubernetes/admin.conf:/tmp/cyc.conf' master1 ~]# kubectl get sa NAME SECRETS AGE admin 0 4h4m default 0 13d # 查看多个配置文件的合并统一查询效果 master1 ~]# kubectl get sa NAME SECRETS AGE admin 0 4h4m default 0 13d [root@master1 ~]# kubectl config view apiVersion: v1 clusters: - cluster: certificate-authority-data: DATA+OMITTED server: https://vip.k8test.com:6443 name: kubernetes - cluster: certificate-authority-data: DATA+OMITTED server: https://vip.k8test.com:6443 name: mycluster contexts: - context: cluster: mycluster user: cyc name: cyc@mycluster - context: cluster: kubernetes user: kubernetes-admin name: kubernetes-admin@kubernetes current-context: kubernetes-admin@kubernetes kind: Config preferences: {} users: - name: cyc user: client-certificate-data: REDACTED client-key-data: REDACTED - name: kubernetes-admin user: client-certificate-data: REDACTED client-key-data: REDACTED
3.4.2、采用 merge 参数合并当前的配置文件
master1 ~]# kubectl config view --merge --flatten > /tmp/cyc_kube-admin.conf 属性解析: --flatten 用于显示加密后的内容 # 可以在一个config文件中,配置多个用户和集群及配套的上下文环境。 master1 ~]# kubectl get sa --kubeconfig=/tmp/cyc_kube-admin.conf NAME SECRETS AGE admin 0 4h10m default 0 13d
3.4.3、查看kubectl当前的上下文
master1 ~]# kubectl config view --kubeconfig=/tmp/cyc_kube-admin.conf | grep current current-context: kubernetes-admin@kubernetes
3.4.4、切换上下文
master1 ~]# kubectl config use-context cyc@mycluster --kubeconfig=/tmp/cyc_kube-admin.conf Switched to context "cyc@mycluster". master1 ~]# kubectl config view --kubeconfig=/tmp/cyc_kube-admin.conf | grep current current-context: cyc@mycluster master1 ~]# kubectl get sa --kubeconfig=/tmp/cyc_kube-admin.conf Error from server (Forbidden): serviceaccounts is forbidden: User "cyc" cannot list resource "serviceaccounts" in API group "" in the namespace "default"