hello云胜

技术与生活

0%

k8s中的RBAC

k8s中的RBAC

我们在业务开发中经常会遇到权限认证和授权业务。

前面说到的serviceAccount就是k8s的认证过程。而k8s的授权机制是通过RBAC来完成的。

RBAC顾名思义即基于角色的权限控制。

RBAC的授权是通过四种资源来配置的,它们又可以分成两组

  • Role(角色)ClusterRole(集群角色),它们指定了在资源上可以执行哪些动词
  • RoleBinding(角色绑定)ClusterRoleBinding(集群角色绑定),它们将上述角色绑定到特定的用户、组或ServiceAccounts上。

角色定义了可以做什么操作,而绑定定义了谁可以做这些操作

在k8s中所有的资源信息都在etcd里,要访问etcd必须通过apiserver。而apiserver就是通过role来控制哪些账号能访问哪些资源。

Role和ClusterRole

k8s了有两个和角色相关的资源:Role和ClusterRole

Role 是定义在一个 namespace 中,而 ClusterRole 是集群级别的。

定义一个Role

1
2
3
4
5
6
7
8
9
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: test-role
namespace: test
rules:
- apiGroups: [""] # 为空表示为默认的Core API组
resources: ["pods"] # 数据源类型
verbs: ["get","watch","list"] #赋予的动作权限

这个Role的规则含义是:在名字为 test的namespace 中,对Pods有get,watch,list的权限

注意一点:在指定资源时必须使用复数的形式。

定义一个ClusterRole

1
2
3
4
5
6
7
8
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: test-clusterrole
rules:
- apiGroups: [""]
resources: ["services"]
verbs: ["get","create","list"]

与Role的区别就是matadata中没有namespace的限定。

这个ClusterRole的含义是,对整个集群的service有get,create,list的权限

分别创建

1
2
kc apply -f test_role.yaml
kc apply -f test_clusterrole.yaml

rules的参数说明:

  1. apiGroups可配置参数
    “”(空表示core api组),“apps”, “autoscaling”, “batch”, “extensions”等等

这个apiGroups指的就是kubectl api-resources的APIGROUP

image-20230630143323612

  1. resources可配置参数

不同的apiGroups对应的resource是不一样的。

比如 “”组有pods,nodes等等resources

apps组才有deployments

就是和代码开发对应的

  1. verbs可配置参数
    “get”,“list”,“watch”, “create”,“update”, “patch”, “delete”,“exec”

  2. resourcesNames

    上面三个是必填的,这个resourcesNames是可选的

    他的含义是可以对具体某个资源进行限制。比如对名字是aaa的pod进行授权

RoleBinding 和 ClusterRoleBinding

我们定义了role,但现在role只是被定义出来,并没有实际的作用。因为现在role还是孤零零的存在,需要将role和用户进行绑定,才能真正发挥作用。

img

role可以和三种对象subjects绑定,一种是User,一个是Group,最重要的一个就是serviceaccount。

和useraccount绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rolebinding
namespace: test
subjects:
- kind: User # 权限资源类型
name: yys # 名称
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role #要绑定的Role的类型(可以是Role或ClusterRole)
name: test-role # Role的名称
apiGroup: rbac.authorization.k8s.io

这个绑定的含义是,给用户yys绑定了test-role角色,也就是yys拥有了对名字为 test的namespace 中,对Pods有get,watch,list的权限

实验

用root用户操作

  1. 新建用户yys

    1
    2
    3
    4
    [root@paas-m-k8s-master-1 test]# useradd yys
    [root@paas-m-k8s-master-1 test]# su - yys
    [yys@paas-m-k8s-master-1 ~]$ kubectl -n test get pod
    The connection to the server localhost:8080 was refused - did you specify the right host or port?

    默认肯定是访问不到的,如果想要访问,必须要创建用户的访问证书

  2. 创建访问证书

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ## 下载证书生成工具 cfssl
    # wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
    # wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
    # wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64

    ## 给执行权限
    # chmod +x *
    # mkdir cert
    # cd cert

    创建CA证书签名请求JSON文件 yys-csr.json

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    {
    "CN": "yys", # 用户名称,必须填你的用户名,因为api-server鉴权时就用证书的CN字段作为用户名
    "hosts": [], # 主机地址,不填表示所有主机都可使用
    "key": {
    "algo": "rsa", # 加密算法
    "size": 2048
    },
    "names": [
    {
    "C": "CN",
    "L": "BeiJing",
    "O": "OKK",
    "ST": "BeiJing",
    "OU": "System"
    }
    ]
    }

    开始创建访问证书

    1
    2
    # cd /etc/kubernetes/pki/
    # /home/yys/cfssl_linux-amd64 gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /home/yys/cert/yys-csr.json | /home/yys/cfssljson_linux-amd64 -bare yys

    image-20230630150228491

    执行成功后多出这三个文件

  3. 为yys用户生成集群kubeconfig文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    ## 给用户创建kubeconfig文件
    [root@paas-m-k8s-master-1 cert]# pwd
    /home/yys/cert
    [root@paas-m-k8s-master-1 cert]# kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --server=https://你的master的ip:6443 --kubeconfig=yys.kubeconfig
    Cluster "kubernetes" set.
    [root@paas-m-k8s-master-1 cert]# ll
    总用量 8
    -rw-rw-r-- 1 yys yys 231 6月 30 15:00 yys-csr.json
    -rw------- 1 root root 1570 6月 30 15:07 yys.kubeconfig


    ## 设置客户端参数,绑定用户信息至kubeconfig中
    [root@paas-m-k8s-master-1 cert]# kubectl config set-credentials yys \
    --client-certificate=/etc/kubernetes/pki/yys.pem \
    --client-key=/etc/kubernetes/pki/yys-key.pem \
    --embed-certs=true \
    --kubeconfig=yys.kubeconfig
    User "yys" set.

    ## 设置上下文参数
    [root@paas-m-k8s-master-1 cert]# kubectl config set-context kubernetes \
    --cluster=kubernetes \
    --user=yys \
    --namespace=test \
    --kubeconfig=yys.kubeconfig
    Context "kubernetes created.
  4. 把kubeconfig文件复制到 用户的home目录的.kube下

    1
    2
    3
    mkdir -p /home/yys/.kube
    cp /home/yys/cert/yys.kubeconfig /home/yys/.kube/config
    chown -R yys:yys /home/yys/.kube
  5. 切换用户为yys,绑定kubectl读取config

    1
    2
    3
    4
    [root@paas-m-k8s-master-1 .kube]# su - yys
    [yys@paas-m-k8s-master-1 ~]$ kubectl config use-context kubernetes --kubeconfig=/home/yys/.kube/config
    Switched to context "kubernetes".

  6. 测试

    1
    2
    [yys@paas-m-k8s-master-1 ~]$ kubectl get pod
    Error from server (Forbidden): pods is forbidden: User "yys" cannot list resource "pods" in API group "" in the namespace "test"

    apply 绑定

    1
    2
    切回root用户
    # kc apply -f test-rolebing.yaml

    应用rolebinding

    再切回yys用户

    1
    2
    3
    4
    5
    6
    [yys@paas-m-k8s-master-1 .kube]$ kubectl get pod
    NAME READY STATUS RESTARTS AGE
    jdktest-9302-e2y-1li-f283862d4944-job-9d9l8 0/1 Error 0 638d
    nginx-volume-host 1/1 Running 0 217d
    ...
    pcloud-testjjj-latest-7t9-esm-e2487db22694-job-29492 0/1 Completed 0 710d

    打印的就是test namespace下的pod。因为我们创建这个Context时已经制定了namespace就是test

    如果干点别的

    1
    2
    [yys@paas-m-k8s-master-1 ~]$ kubectl get ns
    Error from server (Forbidden): namespaces is forbidden: User "yys" cannot list resource "namespaces" in API group "" at the cluster scope

    会报没权限

和serviceaccount绑定

我们已经知道,ServiceAccount的主要作用是pod和apiserver交互。我们编写的程序默认是不能直接调用api-server的,需要对pod进行合适的授权,这个授权就是通过和ServiceAccount绑定来做的。

关于ServiceAccount的介绍,请看这里

说说K8S中的ServiceAccount (qq.com)

在这篇文章里,我们创建了一个命名为mytest的serviceaccount。创建了一个名为test-sa的pod使用这个sa。

我们继续沿用。

实验

进入这个pod

1
2
3
4
5
6
[root@paas-m-k8s-master-1 test]# kc exec -it test-sa -- /bin/sh
#
# cd /var/run/secrets/kubernetes.io/serviceaccount
# ls
ca.crt namespace token
#

现在访问一下api-server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
# TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
#
# curl -H "Authorization: Bearer $TOKEN" https://kubernetes/api/v1/namespaces/default/pods
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {

},
"status": "Failure",
"message": "forbidden: User \"system:serviceaccount:default:mytest\" cannot get path \"/\"",
"reason": "Forbidden",
"details": {

},
"code": 403
}#

可以看到现在调用api-server是Forbidden的。

绑定role

新建一个role,并进行roleBinding。

写在一起了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: role-demo
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
nonResourceURLs: []
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: rolebinding-demo
namespace: default
subjects:
- kind: ServiceAccount
name: mytest
namespace: default
roleRef:
kind: Role
name: role-demo
apiGroup: rbac.authorization.k8s.io

现在再进到之前的pod里

1
2
curl -H "Authorization: Bearer $TOKEN" https://kubernetes/api/v1/namespaces/default/pods

image-20230704160100890

可以看到已经可以调用了,说明通过roleBinding赋予了pod调用api-server的权限