kubernetes中的RBAC权限管理

  |   0 评论   |   0 浏览

背景

RBAC是Role-based access control (RBAC)的缩写,即基于角色进行权限控制。

基础命令

先复习下基本的权限管理命令。

查看 service account

查看当前系统的ServiceAccount

# kubectl get serviceaccounts
NAME      SECRETS   AGE
default   1         5d12h

查看所有namespace的ServiceAccount

# kubectl get serviceaccounts --all-namespaces
NAMESPACE         NAME                                 SECRETS   AGE
default           default                              1         5d14h
……………………
kube-system       token-cleaner                        1         5d14h
kube-system       ttl-controller                       1         5d14h

创建 service account

创建一个自己的service account:myaccount

# kubectl create serviceaccount myaccount
serviceaccount/myaccount created

确认创建成功

# kubectl get serviceaccounts
NAME        SECRETS   AGE
default     1         5d14h
myaccount   1         4m

创建service account的同时,会自动创建secrets,如:

# kubectl get secrets
NAME                    TYPE                                  DATA   AGE
default-token-qhcq8     kubernetes.io/service-account-token   3      5d14h
myaccount-token-s292c   kubernetes.io/service-account-token   3      4m32s

查看 token

service account中会保存一个JWT格式的token

查看token名称:

# kubectl describe serviceaccount default
Name:                default
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   default-token-qhcq8
Tokens:              default-token-qhcq8
Events:              <none>

拿着token名称,来查看token内容:

# kubectl describe secrets default-token-qhcq8
Name:         default-token-qhcq8
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: default
              kubernetes.io/service-account.uid: 38bba8ca-258d-46e6-9055-2bc3cdfd3304

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1025 bytes
namespace:  7 bytes
token:      eyJhb******dyoLzg

可以拿着token到JWT官网来解码,解码结果示例:

{
  "alg": "RS256",
  "kid": ""
}
{
  "iss": "kubernetes/serviceaccount",
  "kubernetes.io/serviceaccount/namespace": "default",
  "kubernetes.io/serviceaccount/secret.name": "default-token-qhcq8",
  "kubernetes.io/serviceaccount/service-account.name": "default",
  "kubernetes.io/serviceaccount/service-account.uid": "38bba8ca-258d-46e6-9055-2bc3cdfd3304",
  "sub": "system:serviceaccount:default:default"
}

Pod 和 account

每一个pod都对应着一个service account,默认是 default,可以在 yaml 文件中指定。

比如我们有一个 pod: kubernetes-bootcamp-7dc9765bf6-fk92j,来查看其service account

# kubectl edit pod kubernetes-bootcamp-7dc9765bf6-fk92j

部分结果

…………
  serviceAccount: default
  serviceAccountName: default
…………

可见其 service account 确实为 default

此外,pod 在创建时,认证的相关文件会以 volume 的形式挂载在 pod 中,在 pod 访问 api server 时会使用。

# kubectl edit pod kubernetes-bootcamp-7dc9765bf6-fk92j

部分结果

…………
spec:
  containers:
  - image: docker.io/jocatalin/kubernetes-bootcamp:v1
    imagePullPolicy: IfNotPresent
    name: kubernetes-bootcamp
    ports:
    - containerPort: 8080
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-qhcq8
      readOnly: true
…………

测试 token 的有效性

先进入容器,

# kubectl exec -it kubernetes-bootcamp-7dc9765bf6-fk92j bash

直接访问 api server,不使用 token,会提示为匿名访问,报错

# curl "https://10.96.0.1" -k
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

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

  },
  "code": 403
}

使用 默认 token 来提交,会看到识别出来使用的 user 为 system:serviceaccount:default:default,但是没有权限,报错,

root@kubernetes-bootcamp-7dc9765bf6-fk92j:~# KUBE_TOKEN=$(</var/run/secrets/kubernetes.io/serviceaccount/token)
root@kubernetes-bootcamp-7dc9765bf6-fk92j:~# curl -sSk -H "Authorization: Bearer $KUBE_TOKEN" "https://10.96.0.1"
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

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

  },
  "code": 403
}

其中 -H "Authorization: Bearer $KUBE_TOKEN" 部分为 JWT 认证的写法。

RBAC授权

在认证完成后,接下来就是授权的过程。现在默认使用的是RBAC(Role Based Access Control)授权,其中的关键点如下:

  • Role: 即角色,可以给 role上指定权限, 比如 get, list, update, delete, add, watch权限。
  • RoleBinding: 把 role 和 service account 关联起来。
  • CluterRole: cluster role 的作用域是整个集群,相对 role 的作用域是name space。
  • CluterRoleBinding: 把 cluster role 和 service account 关联起来。

注: RoleBinding 过程中,除了可以将 role 和 service account 关联,也可以将 role 和 user / group 关联。

复现没有权限

先复现一下,system:serviceaccount:default:default这个账号,没有 list pods权限

# kubectl auth can-i list pods -n default --as=system:serviceaccount:default:default
no

放开权限

创建 role

# kubectl create role default-read-pod --verb=get,list,watch --resource=pods
role.rbac.authorization.k8s.io/default-read-pod created

创建 role binding

kubectl create rolebinding default --role=default-read-pod --serviceaccount=default:default
rolebinding.rbac.authorization.k8s.io/default created

测试效果

使用 kubectl 来测试权限

# kubectl auth can-i list pods -n default --as=system:serviceaccount:default:default
yes

在容器中执行命令来测试权限

# curl -sSk -H "Authorization: Bearer $KUBE_TOKEN" "https://10.96.0.1/api/v1/namespaces/default/pods/$HOSTNAME"
{
  "kind": "Pod",
  "apiVersion": "v1",
  "metadata": {
    "name": "kubernetes-bootcamp-7dc9765bf6-fk92j",
    "generateName": "kubernetes-bootcamp-7dc9765bf6-",
    "namespace": "default",
……………………
    ],
    "qosClass": "BestEffort"
  }
}

可见是生效了的。

其它

查看有没有权限执行

有权限的例子

# kubectl auth can-i create deployments --namespace dev
yes

看看别的账号(dave)有没有权限

# kubectl auth can-i list secrets --namespace dev --as dave
no - no RBAC policy matched

查看当前账号

# kubectl get clusterrole

参考