37、K8S-安全机制-CA、User、Cluster

发布时间 2023-03-30 17:55:23作者: 小粉优化大师

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父级 CAO(位于 Subject 中)kind主机 (SAN)
kube-etcd etcd-ca   server, client <hostname><Host_IP>localhost127.0.0.1
kube-etcd-peer etcd-ca   server, client <hostname><Host_IP>localhost127.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"