Kubernetes用户认证和RBAC

用户认证和RBAC

Kubernetes 中的用户

K8S中有两类用户:普通意义上的用户(User)和服务账号(ServiceAccount)。ServiceAccount是K8S内部资源,唯一能够通过api方式管理的凭证,常用于pod内与apiserver通信,而User是独立于K8S之外的。

为集群创建一个新用户

Kubernetes 并不包含用来代表普通用户账号的对象。 普通用户的信息无法通过 API 调用添加到集群中。Kubernetes 使用证书中的 'subject' 的通用名称(Common Name)字段 (例如,"/CN=bob")来确定用户名。

bash 复制代码
$ grep /pki /etc/kubernetes/manifests/yxdev-kube-apiserver.yaml
    - --client-ca-file=/etc/kubernetes/pki/ca.crt # 验证客户端的ca证书
    - --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt # apiserver的证书
    - --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key         # apiserver的私钥

为用户生成证书

假设我们要创建一个用户名为tom的用户

  1. 首先需要为此用户创建一个私钥:umask 077;openssl genrsa -out tom.key 2048

  2. 接着用此私钥创建一个csr(证书签名请求)文件,其中我们需要在subject里带上用户信息(CN为用户名,O为用户组): openssl req -new -key tom.key -out tom.csr -subj "/CN=tom/O=UESRADMIN",其中/O参数可以出现多次,即可以有多个用户组。

    CN对应binding里面的User,O对应binding里面的Group

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

  4. 通过集群的CA证书和之前创建的csr文件,来为用户颁发证书,-CA和-CAkey参数需要指定集群CA证书所在位置,-days参数指定此证书的过期时间,这里为365天: openssl x509 -req -in tom.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out tom.crt -days 365

给用户绑定权限

yaml 复制代码
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: test-ops
  name: tom-role
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: tom-binding
  namespace: test-ops
subjects:
- kind: User
  name: tom
  apiGroup: ""
roleRef:
  kind: Role
  name: tom-role
  apiGroup: ""

查看用户是否有权限

shell 复制代码
sudo kubectl auth can-i get pods -n test-ops --as tom

身份认证策略

X509 客户证书

通过给 API 服务器传递 --client-ca-file=SOMEFILE 选项,就可以启动客户端证书身份认证。 所引用的文件必须包含一个或者多个证书机构,用来验证向 API 服务器提供的客户端证书。 如果提供了客户端证书并且证书被验证通过,则 subject 中的公共名称(Common Name) 就被作为请求的用户名。 自 1.4 开始,客户端证书还可以通过证书的 organization 字段标明用户的组成员信息。

shell 复制代码
# 使用用户名 jbeda 生成一个证书签名请求(CSR),且该用户属于 "app1" 和 "app2" 两个用户组。
openssl req -new -key jbeda.pem -out jbeda-csr.pem -subj "/CN=jbeda/O=app1/O=app2"

根CA

路径 默认 CN 描述
ca.crt,key kubernetes-ca Kubernetes 通用 CA
etcd/ca.crt,key etcd-ca 与 etcd 相关的所有功能
front-proxy-ca.crt,key kubernetes-front-proxy-ca 用于前端代理

根CA签发的证书

默认 CN 父级 CA O(位于 Subject 中) kind 主机 (SAN)
kube-etcd etcd-ca server, client <hostname>, <Host_IP>, localhost, 127.0.0.1
kube-etcd-peer etcd-ca server, client <hostname>, <Host_IP>, localhost, 127.0.0.1
kube-etcd-healthcheck-client etcd-ca client
kube-apiserver-etcd-client etcd-ca 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

服务帐户密钥对

私钥路径 公钥路径 命令 参数
sa.key kube-controller-manager --service-account-private-key-file
sa.pub kube-apiserver --service-account-key-file

用户帐户配置证书

文件名 命令 凭据名称 默认 CN O (位于 Subject 中)
admin.conf kubectl default-admin kubernetes-admin system:masters
kubelet.conf kubelet default-auth system:node:<nodeName> (参阅注释) system:nodes
controller-manager.conf kube-controller-manager default-controller-manager system:kube-controller-manager
scheduler.conf kube-scheduler default-scheduler system:kube-scheduler

服务账号令牌

服务账号(Service Account)是一种自动被启用的用户认证机制,使用经过签名的持有者令牌来验证请求。 该插件可接受两个可选参数:

  • --service-account-key-file 文件包含 PEM 编码的 x509 RSA 或 ECDSA 私钥或公钥, 用于验证 ServiceAccount 令牌。这样指定的文件可以包含多个密钥, 并且可以使用不同的文件多次指定此参数。若未指定,则使用 --tls-private-key-file 参数。
  • --service-account-lookup 如果启用,则从 API 删除的令牌会被回收。

serviceaccount是k8s中唯一能够通过API方式管理的apiserver访问凭证,通常用于pod中的业务进程与apiserver的交互,解决Pod在集群里面的身份认证问题,认证使用的授权信息存在secret里面(由SecretAccount Controller自行创建)。

服务账号被身份认证后,所确定的用户名为 system:serviceaccount:<名字空间>:<服务账号>, 并被分配到用户组 system:serviceaccountssystem:serviceaccounts:<名字空间>

RBAC

kubernetes.io/zh-cn/docs/...

RBAC API 声明了四种 Kubernetes 对象:RoleClusterRoleRoleBindingClusterRoleBinding

API Server目前支持以下几种授权策略:

  • AlwaysDeny:表示拒绝所有请求,一般用于测试
  • AlwaysAllow:允许接收所有请求,相当于集群不需要授权流程(Kubernetes默认的策略)
  • ABAC:基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制
  • Webhook:通过调用外部REST服务对用户进行授权
  • Node:是一种专用模式,用于对kubelet发出的请求进行访问控制
  • RBAC:基于角色的访问控制(kubeadm安装方式下的默认选项)

从1.6版本起,Kubernetes 默认启用RBAC访问控制策略。从1.8开始,RBAC已作为稳定的功能。通过设置kube-apiserver --authorization-mode=RBAC,启用RABC。

RBAC(Role-Based Access Control) 基于角色的访问控制,主要是在描述一件事情:给哪些对象授予了哪些权限

其中涉及到了下面几个概念:

  • 对象:User、Groups、ServiceAccount
  • 角色:代表着一组定义在资源上的可操作动作(权限)的集合
  • 绑定:将定义好的角色跟用户绑定在一起

RBAC引入了4个顶级资源对象:

  • Role、ClusterRole:角色,用于指定一组权限
  • RoleBinding、ClusterRoleBinding:角色绑定,用于将角色(权限)赋予给对象

Role、ClusterRole

使用通配符 * 可以批量引用所有的 resourcesverbs 对象

一个角色就是一组权限的集合,这里的权限都是许可形式的(白名单)。

yaml 复制代码
# Role只能对命名空间内的资源进行授权,需要指定nameapce
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: dev
  name: authorization-role
rules:
- apiGroups: [""]  # 支持的API组列表,"" 空字符串,表示核心API群,支持的apiGroups和resources列表可通过`kubectl api-resources`查看
  resources: ["pods"] # 支持的资源对象列表
  verbs: ["get", "watch", "list"] # 允许的对资源对象的操作方法列表
yaml 复制代码
# ClusterRole可以对集群范围内资源、跨namespaces的范围资源、非资源类型进行授权
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
 name: authorization-clusterrole
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"] # log 是 pods 的子资源
  verbs: ["get", "watch", "list"]

需要详细说明的是,rules中的参数:

  • apiGroups: 支持的API组列表

    erlang 复制代码
    "","apps", "autoscaling", "batch" ...
  • resources:支持的资源对象列表

    arduino 复制代码
    "services", "endpoints", "pods","secrets","configmaps","crontabs","deployments","jobs",
    "nodes","rolebindings","clusterroles","daemonsets","replicasets","statefulsets",
    "horizontalpodautoscalers","replicationcontrollers","cronjobs"
  • verbs:对资源对象的操作方法列表

    arduino 复制代码
    "get", "list", "watch", "create", "update", "patch", "delete", "exec"

RoleBinding、ClusterRoleBinding

角色绑定用来把一个角色绑定到一个目标对象上,绑定目标可以是UserGroup或者ServiceAccount。创建了绑定之后,你不能再修改绑定对象所引用的 Role 或 ClusterRole。如果你想要改变现有绑定对象中 roleRef 字段的内容,必须删除重新创建绑定对象。kubectl auth reconcile 可以创建或者更新包含 RBAC 对象的清单文件, 并且在必要的情况下删除和重新创建绑定对象,以改变所引用的角色。

RoleBinding 也可以引用 ClusterRole,但是只能访问对应namespace下的资源。

yaml 复制代码
# RoleBinding可以将同一namespace中的subject绑定到某个Role下,则此subject即具有该Role定义的权限
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: authorization-role-binding
  namespace: dev
subjects:
- kind: User
  name: heima # 角色
  apiGroup: rbac.authorization.k8s.io
roleRef: # Role 或 ClusterRole 的绑定关系
  kind: Role
  name: authorization-role # 对应的role
  apiGroup: rbac.authorization.k8s.io
yaml 复制代码
# ClusterRoleBinding在整个集群级别和所有namespaces将特定的subject与ClusterRole绑定,授予权限
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
 name: authorization-clusterrole-binding
subjects:
- kind: User
  name: heima
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: authorization-clusterrole
  apiGroup: rbac.authorization.k8s.io

RoleBinding 或者 ClusterRoleBinding 可绑定角色到某 主体(Subject) 上。 主体可以是组,用户或者服务账户服务账户(ServiceAccount) 的用户名前缀为 system:serviceaccount:,属于前缀为 system:serviceaccounts: 的用户组(前缀 system: 是 Kubernetes 系统保留的)。

  • system:serviceaccount: (单数)是用于服务账户用户名的前缀;
  • system:serviceaccounts: (复数)是用于服务账户组名的前缀。

RoleBinding引用ClusterRole进行授权

RoleBinding可以引用ClusterRole,对属于同一命名空间内ClusterRole定义的资源主体进行授权。

一种很常用的做法就是,集群管理员为集群范围预定义好一组角色(ClusterRole),然后在多个命名空间中重复使用这些ClusterRole。这样可以大幅提高授权管理工作效率,也使得各个命名空间下的基础性授权规则与使用体验保持一致。

yaml 复制代码
# 虽然authorization-clusterrole是一个集群角色,但是因为使用了RoleBinding
# 所以heima只能读取dev命名空间中的资源
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: authorization-role-binding-ns
  namespace: dev
subjects:
- kind: User
  name: heima
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: authorization-clusterrole
  apiGroup: rbac.authorization.k8s.io

实战:创建一个只能管理dev空间下Pods资源的账号

  1. 创建账号
shell 复制代码
# 1) 创建证书
[root@k8s-master01 pki]# cd /etc/kubernetes/pki/
[root@k8s-master01 pki]# (umask 077;openssl genrsa -out devman.key 2048)

# 2) 用apiserver的证书去签署
# 2-1) 签名申请,申请的用户是devman,组是devgroup
[root@k8s-master01 pki]# openssl req -new -key devman.key -out devman.csr -subj "/CN=devman/O=devgroup"
# 2-2) 签署证书
[root@k8s-master01 pki]# openssl x509 -req -in devman.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out devman.crt -days 3650

# 3) 设置集群、用户、上下文信息
[root@k8s-master01 pki]# kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.109.100:6443
[root@k8s-master01 pki]# kubectl config set-credentials devman --embed-certs=true --client-certificate=/etc/kubernetes/pki/devman.crt --client-key=/etc/kubernetes/pki/devman.key
[root@k8s-master01 pki]# kubectl config set-context devman@kubernetes --cluster=kubernetes --user=devman

# 切换账户到devman
[root@k8s-master01 pki]# kubectl config use-context devman@kubernetes
Switched to context "devman@kubernetes".

# 查看dev下pod,发现没有权限
[root@k8s-master01 pki]# kubectl get pods -n dev
Error from server (Forbidden): pods is forbidden: User "devman" cannot list resource "pods" in API group "" in the namespace "dev"

# 切换到admin账户
[root@k8s-master01 pki]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".

2) 创建Role和RoleBinding,为devman用户授权

yaml 复制代码
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: dev
  name: dev-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: authorization-role-binding
  namespace: dev
subjects:
- kind: User
  name: devman
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: dev-role
  apiGroup: rbac.authorization.k8s.io
shell 复制代码
[root@k8s-master01 pki]# kubectl create -f dev-role.yaml
role.rbac.authorization.k8s.io/dev-role created
rolebinding.rbac.authorization.k8s.io/authorization-role-binding created
  1. 切换账户,再次验证
shell 复制代码
# 切换账户到devman
[root@k8s-master01 pki]# kubectl config use-context devman@kubernetes
Switched to context "devman@kubernetes".

# 再次查看
[root@k8s-master01 pki]# kubectl get pods -n dev
NAME                                 READY   STATUS             RESTARTS   AGE
nginx-deployment-66cb59b984-8wp2k    1/1     Running            0          4d1h
nginx-deployment-66cb59b984-dc46j    1/1     Running            0          4d1h
nginx-deployment-66cb59b984-thfck    1/1     Running            0          4d1h
相关推荐
Johny_Zhao3 小时前
Docker + CentOS 部署 Zookeeper 集群 + Kubernetes Operator 自动化运维方案
linux·网络安全·docker·信息安全·zookeeper·kubernetes·云计算·系统运维
木鱼时刻1 天前
容器与 Kubernetes 基本概念与架构
容器·架构·kubernetes
chuanauc2 天前
Kubernets K8s 学习
java·学习·kubernetes
庸子2 天前
基于Jenkins和Kubernetes构建DevOps自动化运维管理平台
运维·kubernetes·jenkins
李白你好2 天前
高级运维!Kubernetes(K8S)常用命令的整理集合
运维·容器·kubernetes
Connie14512 天前
k8s多集群管理中的联邦和舰队如何理解?
云原生·容器·kubernetes
伤不起bb3 天前
Kubernetes 服务发布基础
云原生·容器·kubernetes
别骂我h3 天前
Kubernetes服务发布基础
云原生·容器·kubernetes
weixin_399380693 天前
k8s一键部署tongweb企业版7049m6(by why+lqw)
java·linux·运维·服务器·云原生·容器·kubernetes
斯普信专业组4 天前
K8s环境下基于Nginx WebDAV与TLS/SSL的文件上传下载部署指南
nginx·kubernetes·ssl