CKA自学笔记18:RBAC鉴权 ¶
摘要 ¶
演示场景:
- 为一个集群创建不同的配置文件。
- 使用
cfssl
为每个配置文件生成证书。 - 创建新的
kubeconfig
文件,包含所有配置文件和相应的用户。 - 将旧的和新的
kubeconfig
文件合并到新的kubeconfig
文件中。我们可以切换不同的上下文来进行进一步的演示。
基本概念
- 基于角色的访问控制(Role-based access control,RBAC)是一种基于组织中个人用户角色的访问计算机或网络资源的方法。
- 当使用客户端证书认证时,我们可以通过 easyrsa、openssl 或 cfssl 手动生成证书。
建议:
- kubeconfig 的目的是为不同用户授予不同集群的权限。
- 不同的上下文将链接到不同的集群。
- 不建议将多个用户的上下文放在一个 kubeconfig 中使用同一个集群。
- 建议为一个用户使用一个 kubeconfig 文件。
安装cfssl ¶
安装 cfssl
。
apt install golang-cfssl
设置多个上下文 ¶
当前上下文 ¶
执行命令 kubectl config
查询当前使用的上下文(contenxt)。
kubectl config get-contexts
我们可以得到类似如下集群的关键信息。
- 集群名称:kubernetes
- 系统账号:kubenetes-admin
- 当前上下文名称:kubernetes-admin@kubernetes(格式为
<system_account>@<cluster_name>
)
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kubernetes-admin@kubernetes kubernetes kubernetes-admin dev
创建CA配置文件 ¶
CA(Certificate Authority)配置文件(config file)是一个用于存储证书颁发机构(CA)信息的文件。 在使用TLS/SSL加密通信时,需要使用证书来验证通信双方的身份。 而CA则是负责签发和验证证书的机构,因此在建立TLS/SSL连接时需要先验证CA的信任关系,以保证证书的有效性。 CA文件中存储了CA的公钥信息和其他相关的配置信息。 在Kubernetes中,使用CA文件来验证证书的有效性和授权访问。
查看目录/etc/kubernetes/pki
及其子目录的结构情况。
tree /etc/kubernetes/pki
运行结果,下面是Kubernetes初始安装后的文件结构的示例内容。
/etc/kubernetes/pki
├── apiserver.crt
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
├── apiserver.key
├── apiserver-kubelet-client.crt
├── apiserver-kubelet-client.key
├── ca.crt
├── ca.key
├── etcd
│ ├── ca.crt
│ ├── ca.key
│ ├── healthcheck-client.crt
│ ├── healthcheck-client.key
│ ├── peer.crt
│ ├── peer.key
│ ├── server.crt
│ └── server.key
├── front-proxy-ca.crt
├── front-proxy-ca.key
├── front-proxy-client.crt
├── front-proxy-client.key
├── sa.key
└── sa.pub
进入目录/etc/kubernetes/pki
,即当前工作目录。
cd /etc/kubernetes/pki
检查文件ca-config.json
是否已经存在与当前工作目录。
ll ca-config.json
如果不存在,则创建这个文件。
- 我们可以添加多个配置文件来指定不同的过期日期、场景、参数等。
- 配置文件将用于签署证书。
87600
小时大约是10年。
这里我们将在ca-config.json
文件中添加一个名为dev
的配置文件。
cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"dev": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "87600h"
}
}
}
}
EOF
创建证书签名请求 (CSR) 文件 ¶
证书签名请求(CSR)资源用于请求由指定签名者签署的证书,此后可以在最终签署之前批准或拒绝请求。
设置CSR的CN
和O
属性很重要。
CN
是请求CSR的用户的名称。O
是此用户将属于的组。我们可以参考RBAC以了解标准组。
保持当前工作目录为/etc/kubernetes/pki
。
创建CSR文件cka-dev-csr.json
。 CN
代表 cka-dev
。 O
代表 k8s
。
cat > cka-dev-csr.json <<EOF
{
"CN": "cka-dev",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Shanghai",
"L": "Shanghai",
"O": "k8s",
"OU": "System"
}
]
}
EOF
为我们之前定义的配置文件生成证书和密钥。 使用cfssljson -bare cka-dev
命令会生成两个文件,cka-dev.pem
作为公钥,cka-dev-key.pem
作为私钥。
cfssl gencert -ca=ca.crt -ca-key=ca.key -config=ca-config.json -profile=dev cka-dev-csr.json | cfssljson -bare cka-dev
验证这2个文件已经成功创建出来了。
ll -tr | grep cka-dev
运行结果:
-rw-r--r-- 1 root root 222 Jul 24 08:49 cka-dev-csr.json
-rw-r--r-- 1 root root 1281 Jul 24 09:14 cka-dev.pem
-rw------- 1 root root 1675 Jul 24 09:14 cka-dev-key.pem
-rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr
创建kubeconfig文件 ¶
获取控制平面的IP地址(如:<cka001_ip>
)来拼接出环境变量APISERVER
的值,如:https://<control_plane_ip>:<port>
。
kubectl get node -owide
运行结果:
NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
cka001 Ready control-plane,master 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9
cka002 Ready <none> 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9
cka003 Ready <none> 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9
设定并输出环境变量APISERVER
。
echo "export APISERVER=\"https://<cka001_ip>:6443\"" >> ~/.bashrc
source ~/.bashrc
验证环境变量APISERVER
的值。
echo $APISERVER
运行结果:
https://<cka001_ip>:6443
设置集群 ¶
保持当前工作目录为 /etc/kubernetes/pki
。
生成kubeconfig
文件。
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=${APISERVER} \
--kubeconfig=cka-dev.kubeconfig
现在我们生成了新的配置文件 cka-dev.kubeconfig
。
ll -tr | grep cka-dev
输出结果:
-rw-r--r-- 1 root root 222 Jul 24 08:49 cka-dev-csr.json
-rw-r--r-- 1 root root 1281 Jul 24 09:14 cka-dev.pem
-rw------- 1 root root 1675 Jul 24 09:14 cka-dev-key.pem
-rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr
-rw------- 1 root root 1671 Jul 24 09:16 cka-dev.kubeconfig
读取配置文件cka-dev.kubeconfig
的内容。
cat cka-dev.kubeconfig
输出的内容:
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: <your_key>
server: https://<cka001_ip>:6443
name: kubernetes
contexts: null
current-context: ""
kind: Config
preferences: {}
users: null
配置用户 ¶
在文件cka-dev.kubeconfig
中,用户信息这部分是空的。
下面我们配置一个用户cka-dev
。
kubectl config set-credentials cka-dev \
--client-certificate=/etc/kubernetes/pki/cka-dev.pem \
--client-key=/etc/kubernetes/pki/cka-dev-key.pem \
--embed-certs=true \
--kubeconfig=cka-dev.kubeconfig
现在,用户信息已经被添加到配置文件cka-dev.kubeconfig
中了。
cat cka-dev.kubeconfig
输出结果:
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: <your_key>
server: https://<cka001_ip>:6443
name: kubernetes
contexts: null
current-context: ""
kind: Config
preferences: {}
users:
- name: cka-dev
user:
client-certificate-data: <your_key>
client-key-data: <your_key>
至此我们得到了一个完整的配置文件cka-dev.kubeconfig
。 由于我们没有在 kubeconfig 文件中设置当前上下文,当我们使用它来获取节点信息时,会收到以下错误。
kubectl --kubeconfig=cka-dev.kubeconfig get nodes
运行结果:
The connection to the server localhost:8080 was refused - did you specify the right host or port?
当前上下文内容是空白。
kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts
输出结果:
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
配置上下文 ¶
配置上下文。
kubectl config set-context dev --cluster=kubernetes --user=cka-dev --kubeconfig=cka-dev.kubeconfig
现在我们配置了上下文,但其中CURRENT
仍然是空白。
kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts
运行结果:
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
dev kubernetes cka-dev
设置默认上下文。上下文将为多集群环境中的集群和用户链接,并且我们可以切换到不同的集群。
kubectl --kubeconfig=cka-dev.kubeconfig config use-context dev
验证 ¶
现在CURRENT
已经被标记为*
了,这就说明当前上下文已经配置好了。
kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts
运行结果:
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* dev kubernetes cka-dev
因为用户 cka-dev
在该集群中没有授权,所以当我们尝试获取 Pod 或 Node 的信息时,会收到“禁止访问(forbidden)”错误。
kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get pod
kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get node
合并kubeconfig文件 ¶
拷贝当前配置文件,作为备份。
cp ~/.kube/config ~/.kube/config.old
把两个配置文件合并成一个新的配置文件,并存放在/tmp/config
。
KUBECONFIG=~/.kube/config:/etc/kubernetes/pki/cka-dev.kubeconfig kubectl config view --flatten > /tmp/config
用合并后的新配置文件替换老的配置文件。
mv /tmp/config ~/.kube/config
新的配置文件~/.kube/config
类似如下。
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: <your_key>
server: https://<cka001_ip>:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: cka-dev
name: dev
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: cka-dev
user:
client-certificate-data: <your_key>
client-key-data: <your_key>
- name: kubernetes-admin
user:
client-certificate-data: <your_key>
client-key-data: <your_key>
检查基于新的配置文件下的当前上下文。
kubectl config get-contexts
当前上下文是系统默认配置kubernetes-admin@kubernetes
。
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
dev kubernetes cka-dev
* kubernetes-admin@kubernetes kubernetes kubernetes-admin dev
命名空间和上下文 ¶
查询当前命名空间namespace列表和对应标签label的信息。
kubectl get ns --show-labels
创建namespace cka
。
kubectl create namespace cka
使用以下命令更新上下文信息,例如,更新默认命名空间等。
kubectl config set-context <context name> --cluster=<cluster name> --namespace=<namespace name> --user=<user name>
下面针对每个上下文context设定默认的namespace。
kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin
kubectl config set-context dev --cluster=kubernetes --namespace=cka --user=cka-dev
检查当前上下文context的信息。
kubectl config get-contexts
输出结果:
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
dev kubernetes cka-dev cka
* kubernetes-admin@kubernetes kubernetes kubernetes-admin dev
通过下面的命令,可以切换到新的context。
kubectl config use-contexts <context name>
例如:
kubectl config use-context dev
检查上面的变更是否生效。
kubectl config get-contexts
运行结果;
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* dev kubernetes cka-dev cka
kubernetes-admin@kubernetes kubernetes kubernetes-admin dev
Be noted, four users beginning with cka-dev
created don't have any authorizations, e.g., access namespaces, get pods, etc.. Referring RBAC to grant their authorizations.
注意:前面创建的以cka-dev
开头的用户实际没有任何权限,例如访问命名空间、获取 pod 等,下面将通过 RBAC 授予他们授权。
角色Role和角色绑定RoleBinding ¶
将当前工作上下文切换到 kubernetes-admin@kubernetes
。
kubectl config use-context kubernetes-admin@kubernetes
使用带有选项--dry-run=client
和-o yaml
的kubectl create role
命令,生成创建角色role的 yaml 模板。
kubectl create role admin-dev --resource=pods --verb=get --verb=list --verb=watch --dry-run=client -o yaml
在namespace cka
上创建角色role admin-dev
。
kubectl apply -f - << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: cka
name: admin-dev
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- watch
- list
EOF
使用带有选项--dry-run=client
和-o yaml
的kubectl create rolebinding
命令,生成创建角色绑定rolebinding的 yaml 模板。
kubectl create rolebinding admin --role=admin-dev --user=cka-dev --dry-run=client -o yaml
在namespace cka
上创建一个角色绑定rolebinding admin
。
kubectl apply -f - << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: admin
namespace: cka
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: admin-dev
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: cka-dev
EOF
验证namespace cka
上的用户cka-dev
的权限。
切换到上下文dev
。
kubectl config use-context dev
查询namespace cka
上pod的状态,成功!
kubectl get pod -n cka
查询namespace kube-system
上pod的状态,失败!因为前面添加的权限仅限于namespace cka
。
kubectl get pod -n kube-system
查询节点node的状态,失败!因为在角色role里面我们只定义了pod这一种资源。
kubectl get node
在namespace dev
上创建一个pod,失败!因为我们在只有对pod的get
,watch
,list
三种操作权限,没有create
权限。
kubectl run nginx --image=nginx -n cka
集群角色ClusterRole和集群角色绑定ClusterRoleBinding ¶
切换到上下文kubernetes-admin@kubernetes
。
kubectl config use-context kubernetes-admin@kubernetes
创建一个名为 nodes-admin
的 ClusterRole,它授予 get
、watch
、list
对 nodes
资源的授权。
kubectl apply -f - <<EOF
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nodes-admin
rules:
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- watch
- list
EOF
将 ClusterRole nodes-admin
绑定到用户 cka-dev
。
kubectl apply -f - << EOF
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: admin
subjects:
- kind: User
name: cka-dev
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: nodes-admin
apiGroup: rbac.authorization.k8s.io
EOF
切换到上下文到 dev
。验证权限。
kubectl config use-context dev
查询节点node信息,成功!
kubectl get node
切换到系统的上下文kubernetes-admin@kubernetes
。
kubectl config use-context kubernetes-admin@kubernetes
集群角色ClusterRole和ServiceAccount ¶
演示场景:
- 创建一个 ClusterRole,该 ClusterRole 有权创建 Deployment、StatefulSet 和 DaemonSet。
- 将该 ClusterRole 绑定到一个 ServiceAccount 上。
Demo:
kubectl create namespace my-namespace
kubectl -n my-namespace create serviceaccount my-sa
kubectl create clusterrole my-clusterrole --verb=create --resource=deployments,statefulsets,daemonsets
kubectl -n my-namespace create rolebinding my-clusterrolebinding --clusterrole=my-clusterrole --serviceaccount=my-namespace:my-sa
删除演示中创建的临时资源。
kubectl delete namespace my-namespace
kubectl delete clusterrole my-clusterrole
建议:
- 一个RoleBinding可以引用同一命名空间中的任何Role。
- 一个RoleBinding可以引用ClusterRole并将其绑定到RoleBinding所在的命名空间。
- 如果要将ClusterRole绑定到集群中的所有命名空间,则使用ClusterRoleBinding。
- 使用RoleBinding绑定ClusterRole是为了重用ClusterRole以授权命名空间资源,避免为相同授权创建重复的命名空间角色。