目录

1. 身份认证

我们在目前的k8s集群环境里面,只能在master节点上执行kubectl的一些命令,在其他节点上执行就会报错

# 看一下是不是
[root@node1 ~]# kubectl get nodes
E0220 12:50:15.695133    6091 memcache.go:238] couldn't get current server API group list: Get "http://localhost:8080/api?timeout=32s": dial tcp [::1]:8080: connect: connection refused
E0220 12:50:15.695771    6091 memcache.go:238] couldn't get current server API group list: Get "http://localhost:8080/api?timeout=32s": dial tcp [::1]:8080: connect: connection refused
E0220 12:50:15.697555    6091 memcache.go:238] couldn't get current server API group list: Get "http://localhost:8080/api?timeout=32s": dial tcp [::1]:8080: connect: connection refused
E0220 12:50:15.699191    6091 memcache.go:238] couldn't get current server API group list: Get "http://localhost:8080/api?timeout=32s": dial tcp [::1]:8080: connect: connection refused
E0220 12:50:15.700655    6091 memcache.go:238] couldn't get current server API group list: Get "http://localhost:8080/api?timeout=32s": dial tcp [::1]:8080: connect: connection refused
The connection to the server localhost:8080 was refused - did you specify the right host or port?

我们可以看到在node1上执行kubectl get nodes都会报错,那就更不谈创建pod之类的操作了,那为什么master可以而其他节点不行呢?
这是因为在master节点上是有一个kubeconfig的

[root@master ~]# env |grep -i kubeconfig
KUBECONFIG=/etc/kubernetes/admin.conf

我们可以看到在master节点上是有一个环境变量加载了这个admin.conf这个文件的,这个文件就是k8s集群默认的管理员文件,换一种说法,只要你有本事偷走这个文件并且保障你的网络跟这个集群的网络是通的,那么恭喜你,得到了一个k8s集群

node节点操作

我们现在来将这个admin.conf传到node1上,再来看看node1能不能去执行命令

# 传文件
[root@master ~]# scp /etc/kubernetes/admin.conf node1:~
admin.conf                                                                    100% 5669     6.2MB/s   00:00  
# 在node1上执行命令看看效果
[root@node1 ~]# kubectl get node --kubeconfig=admin.conf
NAME     STATUS   ROLES                  AGE   VERSION
master   Ready    control-plane,master   43d   v1.26.0
node1    Ready    node1                  43d   v1.26.0
node2    Ready    node2                  43d   v1.26.0

我们通过这个小实验看到,node1节点确实是可以获取到节点信息了,但是他执行的命令跟master上有所不同,在node1上执行的时候他是需要执行配置文件的,如果你不想执行的话可以将这个注册到环境变量里面

[root@node1 ~]# echo "export KUBECONFIG=/root/admin.conf" >> /etc/profile
[root@node1 ~]# tail -1 /etc/profile
export KUBECONFIG=/root/admin.conf

只需要这样就好了

但是这样存在一个问题,他们用的都是管理员的配置文件,那么就相当于他们都是管理员,对集群有全部权限,我们追求是的最小权限原则,就是我给你的权限正好能够让你完成属于你自己的任务,多的权限不应该有,那么我们能不能像Linux一样创建普通用户,给普通用户定制权限呢?当然是可以的

创建普通用户并授权

我们现在来创建一个普通用户zhangsan并授权

1. 生成私钥

# 使用openssl生成一个rsa类型的私钥,私钥文件名是client.key 2048位
[root@master ca]# openssl genrsa -out client.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
........................+++++
...............................................................................................................................................................................................................................................+++++
e is 65537 (0x010001)
[root@master ca]# ls
client.key

2. 生成zhangsan用户证书请求文件

# 使用client.key 生成一个新的文件叫做client.csr
[root@master ca]# openssl req -new -key client.key -subj "/CN=zhangsan" -out client.csr
[root@master ca]# ls
client.csr  client.key

3. 为zhangsan用户颁发证书

zhangsan用户如何将请求发送给k8s的ca进行证书颁发呢?这个时候我们可以使用k8s自带的ca来颁发证书

# k8s的ca在/etc/kubernetes/pki下
[root@master ca]# openssl x509 -req -in client.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out client.crt -days 3650
Signature ok
subject=CN = zhangsan
Getting CA Private Key
# 拷贝ca到当前目录
[root@master ca]# cp /etc/kubernetes/pki/ca.crt .
[root@master ca]# ls
ca.crt  client.crt  client.csr  client.key

4. 创建命名空间及pod

[root@master ca]# kubectl create ns zhangsan
namespace/zhangsan created
# 切到这个命名空间
[root@master ca]# kubectl config set-context --current --namespace zhangsan
Context "kubernetes-admin@kubernetes" modified.
# 创建一个pod
[root@master ca]# kubectl run test01 --image nginx --image-pull-policy IfNotPresent
pod/test01 created
[root@master ca]# kubectl get pods
NAME     READY   STATUS    RESTARTS   AGE
test01   1/1     Running   0          13s

5. 创建角色

角色是什么呢?我们可以这样想,假如我们现在有增删改查4个权限,用户用张三,李四,王五,那我们现在给他们授权的话只能是一个权限一个权限的去给,万一后面又新增了用户我们依旧是一个个去指定,过于麻烦,而角色就是介于权限与用户之间的一个模板,就像这样
我们指定了一个角色是管理员,拥有增删改查4个权限
一个是开发的角色,拥有增改查的权限
一个是普通用户角色,只有查的权限
我们指定好这3个模板之后,后面新来的用户只需要知道他的作用是什么,比如他就是一个普通用户,那我们直接把这个模板给他套上,那他就只有查的权限,来了一个开发者,那我们就给他开发的这个角色模板,他就自然而然的拥有增改查的权限

# 这里的pod-reader是role的名字 后面的--verb就是这个角色所包含哪些权限,并且这个角色所能操作的资源对象仅仅只有pod
[root@master ca]# kubectl create role pod-reader --verb=get --verb=list --verb=watch --resource=pods
role.rbac.authorization.k8s.io/pod-reader created

6. 绑定角色给用户

# 创建一个rolebinding名字叫zhangsan,这个zhangsan并不是用户张三,而是这个rolebinding的名字,后面--user这个才是用户张三
[root@master ca]# kubectl create rolebinding zhangsan --role pod-reader --user zhangsan
rolebinding.rbac.authorization.k8s.io/zhangsan created
[root@master ca]# kubectl get rolebindings.rbac.authorization.k8s.io 
NAME       ROLE              AGE
zhangsan   Role/pod-reader   4s

7. 编辑kubeconfig文件

关于这个文件的框架,我们可以到官网去找到

地址 https://kubernetes.io/zh-cn/docs/concepts/configuration/organize-cluster-access-kubeconfig/
在官网找到之后我们只需要做一些修改就行,改成这样就可以,直接复制这个去改也行

apiVersion: v1
kind: Config

clusters:
- cluster:
  name: cluster-zs

users:
- name: zhangsan

contexts:
- context:
  name: context-zs
  namespace: zhangsan
current-context: "context-zs"

这个文件就写好了,但是目前来看他与管理员的那个admin.conf好像不一样,那个文件里面内容很多,这个很少
这是因为我们还没有将刚刚创建出来的那些密钥文件嵌入进去

8. 嵌入密钥文件

# 1. 嵌入ca文件
# set-cluster与刚刚文件里的一样就好了 server地址就是master的ip加上6443端口 
[root@master ca]# kubectl config --kubeconfig=kube-zhangsan set-cluster cluster-zs --server=https://192.168.200.200:6443 --certificate-authority=ca.crt --embed-certs=true
Cluster "cluster-zs" set.
# 2. 嵌入client
[root@master ca]# kubectl config --kubeconfig=kube-zhangsan set-credentials zhangsan --client-certificate=client.crt --client-key=client.key --embed-certs=true
User "zhangsan" set.
# 3. 设置上下文信息
[root@master ca]# kubectl config --kubeconfig=kube-zhangsan set-context context-zs --cluster=cluster-zs --namespace=zhangsan --user=zhangsan
Context "context-zs" modified.

这3个操作搞定之后,你再去看看这个文件,你会发现他跟admin.conf是一样一样的了

9. 验证权限

这个文件我们就算搞定了,我们来看看使用这个文件所拥有的权限是否是与我们预期的一样

[root@node1 ~]# kubectl get pods --kubeconfig=kube-zhangsan
NAME     READY   STATUS    RESTARTS   AGE
test01   1/1     Running   0          9m
# 可以看到pod,我们尝试一下能否创建pod
[root@node1 ~]# kubectl run test02 --image nginx --kubeconfig=kube-zhangsan
Error from server (Forbidden): pods is forbidden: User "zhangsan" cannot create resource "pods" in API group "" in the namespace "zhangsan"
# 我们看报错信息,用户zhangsan是不能创建的,我们来看看除了pod之外的其他资源是否可见
[root@node1 ~]# kubectl get ns --kubeconfig=kube-zhangsan
Error from server (Forbidden): namespaces is forbidden: User "zhangsan" cannot list resource "namespaces" in API group "" at the cluster scope

现在这个文件符合我们预期的权限,那么这就是创建一个用户并授权的过程

静态token登录

这个方法用人话来讲就是,账号密码登录
静态的方式就是创建一个csv文件,csv文件的格式是
token,user,id
token这一栏我们可以使用openssl生成

1. 生成token

# 注意文件位置,最好放在/etc/kubernetes/pki下,因为k8s默认只对/etc/kubernetes这个目录有权限操作,放在其他位置可能会产生权限错误
[root@master pki]# openssl rand -hex 10 > jerry.csv
[root@master pki]# cat jerry.csv
# 这里的用户名和id可以自己改动
3127c2e2b863d4c23878a,jerry,2000

在apiserver加入参数

# 默认情况下你刚刚写的文件与集群是没有任何关联的,如果想要产生作用需要在kube-apiserver文件加入参数
[root@master manifests]# vim /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
  containers:
  - command:
    - kube-apiserver
# 在这里加上 --token-auth-file后面就是你刚刚的那个文件
    - --token-auth-file=/etc/kubernetes/pki/jerry.csv
    - --advertise-address=192.168.200.200
    - --allow-privileged=true
# 然后重启kubelet
[root@master pki]# systemctl restart kubelet

2. 尝试登录集群

[root@node1 pki]# kubectl --server="https://192.168.200.200:6443" --token="3127c2e2b863d4c23878a" get pod -n default
Unable to connect to the server: x509: certificate signed by unknown authority

他会有一个报错,但是我们现在没有使用x509的证书啊,所以我们需要让他跳过安全认证

3. 带上参数再次尝试

[root@node1 pki]# kubectl --server="https://192.168.200.200:6443" --token="3127c2e2b863d4c23878a" get pod  --insecure-skip-tls-verify=true -n zhangsan
Error from server (Forbidden): pods is forbidden: User "jerry" cannot list resource "pods" in API group "" in the namespace "zhangsan"

现在我们再来看,他报的错是不是跟刚刚不一样了,这个报错说的是jerry这个用户没有权限
能看到这个其实就说明我们已经可以登录了,只是没有权限看到一些信息罢了

2. 角色授权

上面我们提到了用户的登录,提到了一点点授权,现在开始聊授权的那些事
默认情况下k8s采用的是Node和RBAC的鉴权模式
RBAC就是基于角色的访问控制 R就是role嘛
我们可以在kube-apiserver文件里面看到

spec:
  containers:
  - command:
    - kube-apiserver
    - --token-auth-file=/etc/kubernetes/pki/jerry.csv
    - --advertise-address=192.168.200.200
    - --allow-privileged=true
# 就是这一行
    - --authorization-mode=Node,RBAC

刚刚我们不是使用jerry用户登录但是没有任何权限吗?我们现在将这一行参数改掉

# 将之前的注释掉,然后写一行新的
   # - --authorization-mode=Node,RBAC
# 这个是总是允许,不会鉴权,你能登录就有权限,这个模式仅用于测试
    - --authorization-mode=AlwaysAllow
# 重启kubelet
[root@master manifests]# systemctl restart kubelet

然后我们来到node节点再尝试一下jerry用户

[root@node1 manifests]# kubectl --server="https://192.168.200.200:6443" --token="3127c2e2b863d4c23878a" get pod  --insecure-skip-tls-verify=true -n zhangsan
NAME     READY   STATUS    RESTARTS   AGE
test01   1/1     Running   0          56m

我们发现他确实有权限查看了,好了但是我们的重点并不是这个,我们将他改回来

role与rolebinding

是通过命名空间来授权的,你在哪个命名空间创建的角色,那么这个角色只有这个命名空间下的权限
rolebinding就是将角色与用户进行绑定

1. 创建角色

刚刚我们不是有一个Jerry用户可以登录集群,但是没有任何权限吗?
那我们现在来授权

# 不知道参数是怎么来的可以使用kubectl create role --help 里面有示例
[root@master role]# kubectl create role jerry --verb=get --verb=list --verb=watch --resource=pods --dry-run=client -o yaml > jerry.yaml
[root@master role]# kubectl apply -f jerry.yaml 
role.rbac.authorization.k8s.io/jerry created
[root@master role]# kubectl get role
NAME         CREATED AT
jerry        2024-02-20T09:31:35Z
pod-reader   2024-02-20T05:23:30Z

我们现在有2个role一个是之前的,一个jerry就是刚刚我们创建出来的
现在我们角色有了,但是jerry用户依旧是查不到任何信息的,因为我们没有对他进行绑定

2. rolebinding

# 注意一个坑,当这个用户是token登录的时候必须指定他的token,老版本不会有这个问题,新版本不指定的话依然是没有权限的,注意一下
[root@master role]#  kubectl create rolebinding jerry --role=jerry --user=jerry --token="3127c2e2b863d4c23878a" --dry-run=client -o yaml > rolebinding.yaml
[root@master role]# kubectl apply -f rolebinding.yaml 
rolebinding.rbac.authorization.k8s.io/jerry created
[root@master role]# kubectl get rolebindings.rbac.authorization.k8s.io 
NAME       ROLE              AGE
jerry      Role/jerry        5s
zhangsan   Role/pod-reader   4h3m

这里的每一步操作都应该能看懂吧,然后我们回到node节点上使用jerry来查一下zhangsan命名空间下的pod

3. 验证权限

[root@node1 manifests]# kubectl --server="https://192.168.200.200:6443" --token="3127c2e2b863d4c23878a" get pod  --insecure-skip-tls-verify=true -n zhangsan
NAME     READY   STATUS    RESTARTS   AGE
test01   1/1     Running   0          4h24m

我们可以看到,他现在就可以看到pod的信息了,但是我们在指定权限的时候是没有给他创建的权限的,那么他肯定不能创建pod,但是我们现在想要他可以创建pod怎么办呢?
也是很简单,只需要给角色加上一个权限就可以了

4. 修改权限

修改权限我们只需要修改jerry.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  creationTimestamp: null
  name: jerry
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
  - watch
# 加上这个他就可以创建pod了,如果加上delete那么他就可以删除
  - create

然后我们再apply这个文件

[root@master role]# kubectl apply -f jerry.yaml 
role.rbac.authorization.k8s.io/jerry configured

5. 验证是否成功增加权限

[root@node1 manifests]# kubectl --server="https://192.168.200.200:6443" --token="3127c2e2b863d4c23878a"   --insecure-skip-tls-verify=true -n zhangsan run test02 --image nginx
pod/test02 created

我们可以看到pod被创建出来了,说明刚刚的权限已经增加上了
这里我们仅仅只是针对pod的操作,如果我要创建一个deployment控制器呢?
上操作

6. deploymentde的操作

我们仔细观察一下jerry.yaml这个文件,发现里面有一行写的是pods,那我们是不是直接在这里加上deployments就好了呢?
我们来试试

# 修改yaml文件
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  creationTimestamp: null
  name: jerry
rules:
- apiGroups:
  - ""
  resources:
  - pods
  - deployments
  verbs:
  - get
  - list
  - watch
  - create

然后我们apply这个文件

[root@master role]# kubectl apply -f jerry.yaml 
role.rbac.authorization.k8s.io/jerry configured

我们来看看是不是能够创建deployment了

[root@node1 manifests]# kubectl --server="https://192.168.200.200:6443" --token="3127c2e2b863d4c23878a"   --insecure-skip-tls-verify=true -n zhangsan create deployment test03 --image nginx
error: failed to create deployment: deployments.apps is forbidden: User "jerry" cannot create resource "deployments" in API group "apps" in the namespace "zhangsan"

喔嚯,报错了,我们不是加上了deployment吗?
这其实是因为我们还需要给他指定apiGroup,光指定资源是不行的,能创建pod是因为pod他的apiVersion就是v1,而deployment的apiVersion是apps/v1所以他会报错,那我们再来修改一下文件

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  creationTimestamp: null
  name: jerry
rules:
- apiGroups:
  - ""
# 加上这个,如果你想要创建其他的资源,那么你也要在这里写上
# 查询apiVersion很简单,你可以使用kubectl create xxx --dry-run 的方式,也可以直接 kubectl api-version去查,查到之后填到这里
  - "apps"
  resources:
  - pods
  - deployments
  verbs:
  - get
  - list
  - watch
  - create

然后我们apply之后再来创建

[root@node1 manifests]# kubectl --server="https://192.168.200.200:6443" --token="3127c2e2b863d4c23878a"   --insecure-skip-tls-verify=true -n zhangsan create deployment test03 --image nginx
deployment.apps/test03 created

我们现在是可以创建deployment了,那我们想更新他的副本数量也是可以的嘛?来看看

[root@node1 manifests]# kubectl --server="https://192.168.200.200:6443" --token="3127c2e2b863d4c23878a"   --insecure-skip-tls-verify=true -n zhangsan scale deployment test03 --replicas 3
Error from server (Forbidden): deployments.apps "test03" is forbidden: User "jerry" cannot patch resource "deployments/scale" in API group "apps" in the namespace "zhangsan"

他又报错了,他说不能patch,那我们在verb里面加上个试试看呢,等一下,注意看完报错,他说resource里面是deployments/scale我们好像也没有给他这个资源,一并加上
最终的yaml文件是这样的

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  creationTimestamp: null
  name: jerry
rules:
- apiGroups:
  - ""
  - "apps"
  resources:
  - pods
  - deployments/scale
  - deployments
  verbs:
  - get
  - patch
  - list
  - watch
  - create

我们apply之后再来试试看呢

[root@master role]# kubectl apply -f jerry.yaml 
role.rbac.authorization.k8s.io/jerry configured
# 修改副本数
[root@node1 manifests]# kubectl --server="https://192.168.200.200:6443" --token="3127c2e2b863d4c23878a"   --insecure-skip-tls-verify=true -n zhangsan scale deployment test03 --replicas 3
deployment.apps/test03 scaled

我们可以看到现在他可以了
这个yaml文件还可以有另外一种格式

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  creationTimestamp: null
  name: jerry
rules:
- apiGroups: ["","apps"]
  resources: ["pods","deployments"]
  verbs: ["get","delete","watch"]

这种方式也可以,喜欢用哪种就用哪种,无所谓的嘛
这个就是role和rolebinding

clusterrole和clusterrolebinding

clusterrole对于role来说,role是属于某个命名空间的,而clusterrole是属于整个集群的,clusterrole可以进行clusterrolebinding,也可以进行rolebinding,rolebinding的时候指定一下命名空间就可以了
使用rolebinding的时候它就相当于是将clusterrole的权限模板给了某个命名空间下的某个用户,也就是说在你进行rolebinding的时候你就当这个clusterrole就是一个普通的没有指定特定命名空间的role
我们可以这样想一下,我们有很多个命名空间,然后每个命名空间里的用户权限其实都是差不多的,那么如果我要是使用role的话,我就需要每个命名空间下都要去创建role,费时费力
但是我们使用clusterrole的话,所有命名空间都可以看到这个clusterrole,那么就无需每个命名空间都去创建role了,直接rolebingding就好了

1. 创建一个新的用户,使用token

[root@master pki]# openssl rand -hex 10 >> /etc/kubernetes/pki/jerry.csv
[root@master pki]# cat jerry.csv
# 这里的token不一样长可能是因为我按a插入的时候多按了一下,没什么太大的问题,token是可以自己写的
3127c2e2b863d4c23878a,jerry,2000
958a15cfa9431e088e0b,tom,2001

2. 创建clusterrole

这个创建方法与role是一样的

[root@master role]# kubectl create clusterrole cluster-pod --verb=get,list,watch --resource=pods --dry-run=client -o yaml > clusterrole.yaml
[root@master role]# cat clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: null
  name: cluster-pod
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
  - watch

3. clusterrolebinding

[root@master role]# kubectl create clusterrolebinding cluster-tom --clusterrole=cluster-pod --user=tom --token="958a15cfa9431e088e0b"

4. 验证权限

在验证权限之前我建议退出shell重新登录一下,或者重启一下节点,因为你直接登录的话他可能会报错
error: You must be logged in to the server (Unauthorized)
我就遇到这个问题了,我的解决方式是将kube-system里面的apiserver这个pod重启了

# 查看pod
[root@node1 manifests]# kubectl --server="https://192.168.200.200:6443" --token="958a15cfa9431e088e0bb"   --insecure-skip-tls-verify=true -n zhangsan get pods
NAME                      READY   STATUS    RESTARTS   AGE
test01                    1/1     Running   0          6h29m
test03-6484c64bb6-88xlr   1/1     Running   0          81m
test03-6484c64bb6-9hf4l   1/1     Running   0          75m
test03-6484c64bb6-w4zwk   1/1     Running   0          75m
# 查看其他命名空间的pod
[root@node1 manifests]# kubectl --server="https://192.168.200.200:6443" --token="958a15cfa9431e088e0bb"   --insecure-skip-tls-verify=true -n kube-system get pods
NAME                             READY   STATUS    RESTARTS        AGE
coredns-5bbd96d687-9tsbb         1/1     Running   38 (7h6m ago)   42d
coredns-5bbd96d687-q6dl8         1/1     Running   38 (7h6m ago)   42d
etcd-master                      1/1     Running   42 (7h6m ago)   44d
kube-apiserver-master            1/1     Running   0               13m
kube-controller-manager-master   1/1     Running   63 (3h1m ago)   44d
kube-proxy-mp98s                 1/1     Running   40 (7h6m ago)   44d
kube-proxy-snk8k                 1/1     Running   46 (7h6m ago)   44d
kube-proxy-xmxpj                 1/1     Running   38 (7h6m ago)   44d
kube-scheduler-master            1/1     Running   61 (3h1m ago)   44d
metrics-server-54b5b8fb6-v4cqx   1/1     Running   29 (7h4m ago)   7d1h

我们可以看到,他可以看到其他命名空间下的pod,这就是role和clusterrole的区别了
至于他能不能创建pod,能不能创建deployment,这些东西就是跟role是一样的了