mac 上学习k8s系列(17)rbac 源码学习(part I)

2022-08-02 19:30:48 浏览数 (1)

整理了下k8s 源码的核心数据结构,类图如上,可以看到核心就是Role和RoleBinding,对应到资源文件如下

role.yaml

代码语言:javascript复制
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" 标明 core API 组
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

rolebinding.yaml

代码语言:javascript复制
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定允许 "jane" 读取 "default" 名字空间中的 Pods
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
# 你可以指定不止一个“subject(主体)”
- kind: User
  name: jane # "name" 是区分大小写的
  apiGroup: rbac.authorization.k8s.io
roleRef:
  # "roleRef" 指定与某 Role 或 ClusterRole 的绑定关系
  kind: Role # 此字段必须是 Role 或 ClusterRole
  name: pod-reader     # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配
  apiGroup: rbac.authorization.k8s.io

下面我们先配置一个完整的rbac认证过程,然后再从源码的角度详细分析下rbac的设计实现精髓。

1,创建角色

代码语言:javascript复制
% kubectl apply -f rbac/role.yaml 
role.rbac.authorization.k8s.io/pod-reader created

2,创建角色绑定

代码语言:javascript复制
 % kubectl apply -f rbac/role-binding.yaml 
rolebinding.rbac.authorization.k8s.io/read-pods created

K8S中有两种用户(User)——服务账号(ServiceAccount)和普通意义上的用户(User):ServiceAccount是由K8S管理的,而User通常是在外部管理,K8S不存储用户列表——也就是说,添加/编辑/删除用户都是在外部进行,无需与K8S API交互,虽然K8S并不管理用户,但是在K8S接收API请求时,是可以认知到发出请求的用户的,实际上,所有对K8S的API请求都需要绑定身份信息(User或者ServiceAccount)。最主要的区别,即ServiceAccount是K8S内部资源,而User是独立于K8S之外的:User通常是人来使用,而ServiceAccount是某个服务/资源/程序使用的;User独立在K8S之外,也就是说User是可以作用于全局的,在任何命名空间都可被认知,并且需要在全局唯一;而ServiceAccount作为K8S内部的某种资源,是存在于某个命名空间之中的,在不同命名空间中的同名ServiceAccount被认为是不同的资源

K8S不会管理User,所以User的创建/编辑/注销等,需要依赖外部的管理机制,K8S所能认知的只有一个用户名 ServiceAccount是由K8S管理的,创建等操作,都通过K8S完

角色绑定包含了一组相关主体(即 subject, 包括用户 ——User、用户组 ——Group、或者服务账户 ——Service Account)以及对被授予角色的引用。

尽管K8S认知用户靠的只是用户的名字,但是只需要一个名字就能请求K8S的API显然是不合理的,所以依然需要验证此用户的身份,在K8S中,有以下几种验证方式:

X509客户端证书

客户端证书验证通过为API Server指定--client-ca-file=xxx选项启用,API Server通过此ca文件来验证API请求携带的客户端证书的有效性,一旦验证成功,API Server就会将客户端证书Subject里的CN属性作为此次请求的用户名

静态token文件

通过指定--token-auth-file=SOMEFILE选项来启用bearer token验证方式,引用的文件是一个包含了 token,用户名,用户ID 的csv文件 请求时,带上Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269头信息即可通过bearer token验证

静态密码文件

通过指定--basic-auth-file=SOMEFILE选项启用密码验证,类似的,引用的文件时一个包含 密码,用户名,用户ID 的csv文件 请求时需要将Authorization头设置为Basic BASE64ENCODED(USER:PASSWORD)

下面介绍下X509客户端证书认证的过程:

1,为用户生成证书:假设我们操作的用户名为jane;首先需要为此用户创建一个私钥

代码语言:javascript复制
openssl genrsa -out jane.key 2048

2,接着用此私钥创建一个csr(证书签名请求)文件,其中我们需要在subject里带上用户信息(CN为用户名,O为用户组)

代码语言:javascript复制
openssl req -new -key tom.key -out tom.csr -subj "/CN=tom/O=MGM"

其中/O参数可以出现多次,即可以有多个用户组

3,找到K8S集群(API Server)的CA证书文件,其位置取决于安装集群的方式,通常会在/etc/kubernetes/pki/路径下,会有两个文件,一个是CA证书(ca.crt),一个是CA私钥(ca.key)

但是docker for mac 是基于虚拟机linuixkit的,所以路径不一样

代码语言:javascript复制
ls  /run/config/pki
ls: /run/config/pki: No such file or directory

我们可以看下其他目录都是不存在的:

代码语言:javascript复制
kubectl describe pod kube-apiserver-docker-desktop  -n kube-system 
    Mounts:
      /etc/ca-certificates from etc-ca-certificates (ro)
      /etc/ssl/certs from ca-certs (ro)
      /run/config/pki from k8s-certs (ro)
      /usr/local/share/ca-certificates from usr-local-share-ca-certificates (ro)
      /usr/share/ca-certificates from usr-share-ca-certificates (ro)

docker for mac 的API Server的证书位于

代码语言:javascript复制
~/Library/Group Containers/group.com.docker/pki/

目录。通过集群的CA证书和之前创建的csr文件,来为用户颁发证书

代码语言:javascript复制
openssl x509 -req -in jane.csr -CA ~/Library/Group Containers/group.com.docker/pki/ca.crt  -CAkey ~/Library/Group Containers/group.com.docker/pki/ca.key -CAcreateserial -out jane.crt  -days 365 
Signature ok
subject=CN = jane, O = MGM
Getting CA Private Key

-CA和-CAkey参数需要指定集群CA证书所在位置,-days参数指定此证书的过期时间,这里为365天。最后将证书(jane.crt)和私钥(jane.key)保存起来,这两个文件将被用来验证API请求。

4,为kubectl配置用户

现在我们想要通过kubectl以jane的身份来操作集群,需要将jane的认证信息添加进kubectl的配置,即~/.kube/config中

代码语言:javascript复制
kubectl config set-credentials jane --client-certificate=jane.crt --client-key=jane.key    
User "jane" set.

vi ~/.kube/config

可以看到

代码语言:javascript复制
- name: jane
user:
client-certificate: /Users/xiazemin/source/k8s_learn/rbac/user/jane/jane.crt
client-key: /Users/xiazemin/source/k8s_learn/rbac/user/jane/jane.key

创建context

代码语言:javascript复制
kubectl config set-context docker-desktop@jane --cluster=docker-desktop --user=jane
Context "docker-desktop@jane" created.

切换context

代码语言:javascript复制
kubectl config use-context docker-desktop@jane
Switched to context "docker-desktop@jane".

实验下结果

代码语言:javascript复制
% kubectl get secret   
Error from server (Forbidden): secrets is forbidden: User "jane" cannot list resource "secrets" in API group "" in the namespace "default"

查看pod

代码语言:javascript复制
% kubectl get pods   
NAME                                        READY   STATUS      RESTARTS   AGE
apple-app                                   1/1     Running     12         65d
ingress-nginx-admission-create-vjn92        0/1     Completed   0          62d
ingress-nginx-admission-patch-wlq6p         0/1     Completed   0          62d
ingress-nginx-controller-57648496fc-84wl8   1/1     Running     19         62d
minio-deployment-55bf5bff5d-cvq7v           1/1     Running     14         60d
redis-f9f74787-tq6tw                        1/1     Running     14         60d

我们可以看到,由于role里我们只允许了pods的操作权限,所以对secret和svc是没有权限操作的。

代码语言:javascript复制
% kubectl get svc 
Error from server (Forbidden): services is forbidden: User "jane" cannot list resource "services" in API group "" in the namespace "default"

至此整个流程配置完毕了。

也许大家有疑问,安装完docker for mac 我们什么也没有操作,为啥我们就有所有的访问权限?其实安装后默认给我们配置了一个角色cluster-admin

代码语言:javascript复制
% kubectl get clusterrolebinding docker-for-desktop-binding  
NAME                         ROLE                        AGE
docker-for-desktop-binding   ClusterRole/cluster-admin   66d
代码语言:javascript复制
% kubectl get clusterrole cluster-admin
NAME            CREATED AT
cluster-admin   2021-08-23T03:18:58Z

这个角色能做哪些事情呢

代码语言:javascript复制
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2021-08-23T03:18:58Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: cluster-admin
  resourceVersion: "89"
  uid: 9055834a-3bc3-41d2-8bd1-32d2f7359046
rules:
- apiGroups:
  - '*'
  resources:
  - '*'
  verbs:
  - '*'
- nonResourceURLs:
  - '*'
  verbs:
  - '*'

可以看到,赋予了对所有资源的所有访问权限。

0 人点赞