授权

认证通过后通信的双方都确认了对方是可信的,可以相互通信。 Authrization 简单来说就是检查这个用户权限是否拥有操作K8S资源的权限,对哪些资源有操作权限,只要存在一个资源的操作权限正确,就允许通过而鉴权是确定请求方有哪些资源的权限。在Kubernetes中,默认使用的,也是使用较多的是RBAC(Role-Based Access Control)。

授权阶段判断请求是否有相应的权限,授权方式有多种:AlwaysDeny,AlwaysAllow,ABAC,RBAC,Node 等。API Server 启动时如果多种授权模式同时被启用,Kubernetes 将检查所有模块,如果其中一种通过授权,则请求授权通过。 如果所有的模块全部拒绝,则请求被拒绝(HTTP状态码403)。高版本 Kubernetes 默认开启的授权方式是 RBAC 和 Node。

kube-apiserver启动时需要配置:

--authorization-mode=Node,RBAC

目前k8s支持的授权模式主要有以下几种:

  • Node Authorization

  • ABAC Authorization

  • RBAC Authorization

  • Webhook Authorization

本文只描述Node Authorization 和 RBAC Authorization,

01.RBAC Authrization

基于角色的访问控制(Role-Based Access Control, 即 RBAC),是 k8s 提供的一种授权策略, 针对 RBAC 机制,k8s 提供了四种 API 资源:

  • Role

  • ClusterRole

  • RoleBinding

  • ClusterRoleBinding

这四种API资源的逻辑关系如下:

0101.角色(Role)

一个角色就是一组权限的集合,这里的权限都是许可模式,不存在拒绝的规则。在一个命名空间中,可以用角色来定义一个角色,如果是集群级别的,就需要使用 ClusterRole 了。

角色只能对命名空间内的资源进行授权,下面的例子中定义的角色具有读取 Pod 的权限:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" 空字符串,表示核心 API 群
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

rules中参数说明如下:

apiGroups:支持的 API 组列表,例如 “apiVersion: batch/v1” “apiVersion: extensions/v1beta1” "apiVersion: apps/v1beta1" 等。 resource:支持的资源对象列表,例如 pods、deployments、jobs 等。 verbs:对资源对象的操作方法列表,例如 get、watch、list、delete、replace、patch 等。

应该使用哪个 Group 和 Version?

0102.集群角色(Cluster Role)

集群角色除了具有和角色一致的命名空间内资源的管理能力,因其集群级别的范围,还可以用于以下特殊元素的授权。

  • 集群范围的资源,例如 Node(节点)。

  • 非资源型的路径,例如 “/healthz”。

  • 包含全部命名空间的资源,例如 pods(用于 kubectl get pods --all-namespaces 这样的操作授权)。

下面的集群角色可以让用户有权访问任意一个或所有命名空间的 secret:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  # ClusterRole 不授权与命名空间,所以忽略了 namespace 的定义。
rules:
- apiGroups: [""] # "" 空字符串,表示核心 API 群
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

0103.角色绑定(RoleBinding)和集群角色绑定(ClusterRoleBinding)

角色绑定或集群角色绑定用来把一个角色绑定到一个目标上,保定目标可以是 User(用户)、Group(组)或者 Service Account。使用 RoleBinding 为某个命名空间授权,使用 ClusterRoleBinding 为集群范围内授权

RoleBinding

RoleBinding 可以引用 Role 进行授权。下例中的 RoleBinding 将在 default 命名空间中把 pod-reader 角色授权用户 jane,这一操作让 jane 可以读取 default 命名空间中的 Pod:

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: default
  namespace: default
subjects:
- kind: User
  name: jane
  apiGroups: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroups: rbac.authorization.k8s.io

RoleBinding 也可以引用 ClusterRole,对属于同一命名空间内 ClusterRole 定义的资源主体进行授权。一种常见的做法是集群管理员为集群范围预先定义好了一组角色(ClusterRole),然后在多个命名空间中重复使用这些 ClusterRole。

例如下面的例子,虽然 secret-reader 是一个集群角色,但是因为使用了 RoleBinding,所以 dave 只能读取 development 命名空间的 secret:

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: read-secrets
  namespace: development # 集群角色中,只有在 development namespace 中的权限才能赋予 dave
subjects:
- kind: User
  name: dave
  apiGroups: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroups: rbac.authorization.k8s.io

ClusterRoleBinding

集群角色绑定中的角色只能是集群角色,用于进行集群级别或者对所有命名空间都生效的授权

下面的例子允许 manager 组的用户读取任意 namespace 中的 secret:

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: read-secrets-global
subjects:
- kind: Group
  name: manager
  apiGroups: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroups: rbac.authorization.k8s.io

0104.集群内置role和rolebinding

集群创建后 API Server 默认会创建一些 ClusterRole 和 ClusterRoleBinding 对象;这些对象以 system: 为前缀,这表明这些资源对象由集群基础设施拥有;修改这些集群基础设施拥有的对象可能导致集群不可用。 一个简单的例子是 system:node ClusterRole,这个 ClusterRole 定义了 kubelet 的相关权限,如果该 ClusterRole 被修改可能导致 ClusterRole 不可用。

所有的默认 ClusterRole 和 RoleBinding 都具有 kubernetes.io/bootstrapping=rbac-defaultslable

默认Role

一些默认的 Role 并未以 system: 前缀开头,这表明这些默认的 Role 是面向用户级别的。这其中包括超级用户的一些 Role( cluster-admin ),和为面向集群范围授权的 RoleBinding( cluster-status ),以及在特定命名空间中授权的 RoleBinding( admineditview )

Default ClusterRole

Default ClusterRoleBinding

Description

cluster-admin

system:masters group

允许超级用户对集群内任意资源执行任何动作。当该 Role 绑定到 ClusterRoleBinding 时,将授予目标 subject 在任意 namespace 内对任何 resource 执行任何动作的权限;当绑定到 RoleBinding 时,将授予目标 subject 在当前 namespace 内对任意 resource 执行任何动作的权限,当然也包括 namespace 自己

admin

None

管理员权限,用于在单个 namespace 内授权;在与某个 RoleBinding 绑定后提供在单个 namesapce 中对资源的读写权限,包括在单个 namesapce 内创建 Role 和进行 RoleBinding 的权限。该 ClusterRole 不允许对资源配额和 namespace 本身进行修改

edit

None

允许读写指定 namespace 中的大多数资源对象;该 ClusterRole 不允许查看或修改 Role 和 RoleBinding

view

None

允许以只读方式访问特定 namespace 中的大多数资源对象;该 ClusterRole 不允许查看 Role 或 RoleBinding,同时不允许查看 secrets,因为他们会不断更新

组件默认role

Default ClusterRole

Default ClusterRoleBinding

Description

system:kube-scheduler

system:kube-scheduler user

允许访问 kube-scheduler 所需资源

system:kube-controller-manager

system:kube-controller-manager user

允许访问 kube-controller-manager 所需资源;该 ClusterRole 包含每个控制循环所需要的权限

system:node

system:nodes group (deprecated in 1.7)

允许访问 kubelet 所需资源;包括对所有的 secrets 读访问权限和对所有 pod 的写权限;在 1.7 中更推荐使用 Node authorizerNodeRestriction admission plugin 而非本 ClusterRole;Node authorizer 和 NodeRestriction admission plugin 可以授权当前 node 上运行的具体 pod 对 kubelet API 的访问权限,在 1.7 版本中,如果开启了 Node authorization mode,那么 system:nodes group将不会被创建和自动绑定

system:node-proxier

system:kube-proxy user

允许访问 kube-proxy 所需资源

system:auth-delegator

None

允许委托认证和授权检查;此情况下通常由附加的 API Server 来进行统一认证和授权

system:heapster

None

Heapster 组件相关权限

system:kube-aggregator

None

kube-aggregator 相关权限

system:kube-dns

kube-dns service account in the kube-system namespace

kube-dns 相关权限

system:node-bootstrapper

None

允许访问 Kubelet TLS bootstrapping 相关资源权限

system:node-problem-detector

None

system:persistent-volume-provisioner

Node

允许访问 dynamic volume provisioners 相关资源权限

0105.最佳实践

010501.实践一

主要授权zhangsan可以访问develop namespace下的所有的权限

1.创建x509证书

由于使用X509方式时k8s将证书中的CN作为用户名, O作为组名,所以下面为的CSR文件为

cat > developer-csr.json <<EOF
{
  "CN": "zhangsan",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "China",
      "L": "Beijing",
      "O": "Kubernetes",
      "OU": "Kubernetes",
      "ST": "Beijing"
    }
  ]
}
EOF

创建 developer 凭证与私钥:

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=kubernetes \
  developer-csr.json | cfssljson -bare developer

结果将产生以下两个文件:

developer-key.pem
developer.pem

2.创建kubeconfig文件

先确定apiserver对外提供服务的地址

export KUBE_APISERVER="https://apiserver-p001.svc.gxd88.cn:6443"
  • 设置集群参数

      kubectl config set-cluster kubernetes \
      --certificate-authority=ca.pem \
      --embed-certs=true \
      --server=${KUBE_APISERVER} \
      --kubeconfig=develope.kubeconfig
  • 设置客户端认证参数

      kubectl config set-credentials developer-user \
      --client-certificate=developer.pem \
      --client-key=developer-key.pem \
      --embed-certs=true \
      --kubeconfig=develope.kubeconfig
  • 设置上下文参数

      kubectl config set-context default \
      --cluster=kubernetes \
      --user=developer-user \
      --kubeconfig=develope.kubeconfig
  • 设置默认上下文

      kubectl config use-context default --kubeconfig=develope.kubeconfig

3.授权

由于k8s集群中默认已经创建了名称为 admin 的clusterrole, 所以我们只需要创建rolebinding, 指令如下:

创建namespace:

kubectl  create ns develop

创建rolebinding:

kubectl create rolebinding developer-role-binding \
    --clusterrole=admin  \
    --user=zhangsan \
    --namespace=develop

4.验证

获取default namespace下的资源

$ kubectl --kubeconfig=developer.kubeconfig  get pods
Error from server (Forbidden): pods is forbidden: User "zhangsan" cannot list resource "pods" in API group "" in the namespace "default"

获取develop下的资源

$ kubectl --kubeconfig=developer.kubeconfig  get pods -n develop
No resources found in develop namespace.

010502.实践二

用户张三可以操作develop namespace下的deployment、svc、ingresses资源, 对于其它资源没有操作权限。

请根据010501.实践一 完成x509证书和kubeconfig的相关部分

1.role yaml模版文件

执行如下指令获取role文件的字段名称已经文件结构:

$ kubectl explain  role  --recursive
KIND:     Role
VERSION:  rbac.authorization.k8s.io/v1

DESCRIPTION:
     Role is a namespaced, logical grouping of PolicyRules that can be
     referenced as a unit by a RoleBinding.

FIELDS:
   apiVersion    <string>
   kind    <string>
   metadata    <Object>
      annotations    <map[string]string>
      clusterName    <string>
      creationTimestamp    <string>
      deletionGracePeriodSeconds <integer>
      deletionTimestamp    <string>
      finalizers    <[]string>
      generateName    <string>
      generation    <integer>
      labels    <map[string]string>
      managedFields    <[]Object>
         apiVersion    <string>
         fieldsType    <string>
         fieldsV1    <map[string]>
         manager    <string>
         operation    <string>
         time    <string>
      name    <string>
      namespace    <string>
      ownerReferences    <[]Object>
         apiVersion    <string>
         blockOwnerDeletion    <boolean>
         controller    <boolean>
         kind    <string>
         name    <string>
         uid    <string>
      resourceVersion    <string>
      selfLink    <string>
      uid    <string>
   rules    <[]Object>
      apiGroups    <[]string>
      nonResourceURLs    <[]string>
      resourceNames    <[]string>
      resources    <[]string>
      verbs    <[]string>

根据上面文件的KING部分和Version部分获取了api版本, FIELDS部分可以获取到字段名称以及结构, yaml文件的结构如下:

kind:     Role
apiVersion:  rbac.authorization.k8s.io/v1
metadata: 
  name: develop-role
  namespace: develop 
rules: 
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  -  
- apiGroups:
  - ""
  resources:
  - ingress
  verbs:
  -  
- apiGroups:
  - ""
  resources:
  - deployments
  verbs:
  -

2.获取deployments、services、ingress所属的apigroups

获取资源所属apigroups以及可以进行的操作

$ kubectl api-resources -o wide

得出资源所对应的apigroup, 汇总如下表:

resource

apigroup

deployments

apps

services

k8s core

ingresses

extensions、 networking.k8s.io

最后role文件汇总

cat > developer-role.yaml << EOF

Kind:     Role
apiVersion:  rbac.authorization.k8s.io/v1
metadata: 
  name: develop-role
  namespace: develop 
rules: 
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - create 
  - delete 
  - get 
  - list 
  - patch 
  - update 
  - watch
- apiGroups:
  - "extensions"
  - "networking.k8s.io"
  resources:
  - ingresses
  verbs:
  - create 
  - delete 
  - deletecollection 
  - get 
  - list 
  - patch 
  - update 
  - watch
- apiGroups:
  - "apps"
  resources:
  - deployments
  verbs:
  - create 
  - delete 
  - get 
  - list 
  - patch 
  - update 
  - watch
EOF

创建role:

$ kubectl  apply -f developer-role.yaml

3.授权

创建rolebinding:

kubectl create rolebinding developer-role-binding \
    --role=develop-role  \
    --user=zhangsan \
    --namespace=develop

4.验证

执行如下指令:

$ kubectl  --kubeconfig=developer.kubeconfig  get deployments -n develop
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
nginx-app   1/1     1            1           18h

$ kubectl  --kubeconfig=developer.kubeconfig  get svc  -n develop
No resources found in develop namespace.

$ kubectl  --kubeconfig=developer.kubeconfig  get ingress  -n develop
No resources found in develop namespace.

$ kubectl  --kubeconfig=developer.kubeconfig  get pods  -n develop
Error from server (Forbidden): pods is forbidden: User "zhangsan" cannot list resource "pods" in API group "" in the namespace "develop"

因为只授权了deployment, svc, ingress 相关的资源所以查看pods会提示没有权限

02.Node Authrization

下面文字摘自官方文档, 具体内部的工作逻辑找了很多文档也没有看出所以然, 只能说node authrization是 kubernetes 的内部机制

Node Authrization 是一种特殊目的的授权模式,主要用来让 kubernetes 遵从 node 的编排规则,实际上是 RBAC 的一部分,相当于只定义了 node 这个角色以及它的权限, 专门对 kubelet 发出的 API 请求进行鉴权。

要启用节点授权器,启用 Node 鉴权模式 (--authorization-mode=Node,RBAC) 和 NodeRestriction 准入插件

节点鉴权器允许 kubelet 执行 API 操作。包括:

读取操作:

  • services

  • endpoints

  • nodes

  • pods

  • secrets、configmaps、以及绑定到 kubelet 的节点的 pod 的持久卷申领和持久卷

写入操作:

  • 节点和节点状态(启用 NodeRestriction 准入插件以限制 kubelet 只能修改自己的节点)

  • Pod 和 Pod 状态 (启用 NodeRestriction 准入插件以限制 kubelet 只能修改绑定到自身的 Pod)

    事件

鉴权相关操作:

  • 对于基于 TLS 的启动引导过程时使用的 certificationsigningrequests API 的读/写权限

  • 为委派的身份验证/授权检查创建 tokenreviews 和 subjectaccessreviews 的能力

在将来的版本中,节点鉴权器可能会添加或删除权限,以确保 kubelet 具有正确操作所需的最小权限集。 为了获得节点鉴权器的授权,kubelet 必须使用一个凭证以表示它在 system:nodes 组中,用户名为 system:node:<nodeName>。 上述的组名和用户名格式要与 kubelet TLS 启动引导过程中为每个 kubelet 创建的标识相匹配。

要启用节点授权器,请使用 --authorization-mode = Node 启动 apiserver。

要限制 kubelet 具有写入权限的 API 对象,请使用--enable-admission-plugins=...,NodeRestriction,...启动 apiserver,从而启用 NodeRestriction 准入插件。

最后更新于