问题描述

该笔记将记录:在 Kubernetes Cluster 中,如何使用 RBAC 及 ServiceAccount 进行权限管理,以及常见问题处理。

解决方案

场景一、限制 kubectl 命令

当集群部署完成之后,使用 kubectl 命令能够控制整个集群,这是因为 ~/.kube/config 的凭证权限足够高。我们不能直接分发该凭证,应该创建新的碰正限制访问权限。

第一步、检查 RBAC 是否启用



# kubectl api-versions | grep -E '^rbac\.'
rbac.authorization.k8s.io/v1
rbac.authorization.k8s.io/v1beta1



启用 RBAC 认证:在启动 kube-apiserver 服务时,指定 --authorization-mode=Example,RBAC 选项

第二步、创建 ServiceAccount 对象


cat > udef-ServiceAccount-PodReader.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: pod-reader
EOF

kubectl apply -f udef-ServiceAccount-PodReader.yaml
 
 
ServiceAccount 相当于传统认证体系的账户。
第三步、创建 Role 对象
该 Role 仅具有读取 Pod 的权限:
 
 
cat > udef-Role-PodReader.yaml <<EOF
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: pod-reader
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "watch"]
EOF

kubectl apply -f udef-Role-PodReader.yaml
 
 
Role 相当于传统认证体系中的角色
第四步、创建 RoleBinding 对象
 
 
cat > udef-RoleBinding-PodReader.yaml <<EOF
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
   name: pod-reader
subjects:
 - kind: ServiceAccount
   name: pod-reader
roleRef:
   kind: Role
   name: pod-reader
   apiGroup: rbac.authorization.k8s.io
EOF

kubectl apply -f udef-RoleBinding-PodReader.yaml
 
 
RoleBinding 相当于传统认证体系中的授权动作,将用户与角色绑定。
第五步、访问集群
 
 
SECRET_NAME=$(kubectl get -n default serviceaccount pod-reader -o jsonpath="{.secrets[0].name}")
TOKEN=$(kubectl get secrets $SECRET_NAME -o jsonpath="{.data.token}" | base64 -d)

# 创建 pod-reader 用户
kubectl config set-credentials "pod-reader" --token=$TOKEN 

# 创建 Context 来绑定“用户”与“集群”
# 用户:我们刚才创建的
# 集群:需要查看 ~/.kube/config 文件的 clusters 属性中的 name 字段
kubectl config set-context "pod-reader" --cluster="kubernetes" --user="pod-reader"

# 切换到 Context 
kubectl config use-context "pod-reader"
 
 
查看命令空间 Pod 信息:
 
 
# kubectl get pods -n default
No resources found in default namespace.
 
 
如果查看其他命令空间的 Pod 将返回错误信息:
 
 
# kubectl get pods -n kube-system
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:pod-reader" cannot list resource "pods" in API group "" in the namespace "kube-system"
 
 
补充说明
1)其实,这里 TOKEN 也是访问 Kubernetes Dashboard 要输入的 TOKEN 参数
2)kubectl get 与 kubectl describe 输出的 token 并不相同,前者需要 base64 解码,否则提示:error: You must be logged in to the server (Unauthorized)
3)我们这里紧演示如何通过 RBAC 限制 kubectl 对集群的操作。实际上,Pod 启动时,会将 namespace 的 default ServiceAccount 挂载到 Pod 中,能够用来访问集群,参考 Use the Default Service Account to access the API server. 与 Accessing the API from a Pod 文档。
4)限制仅能访问特定 Namespace 资源:我们的示例便是如此,只是赋予的 apiGroups 及 resources 是有限的。如果希望访问 Namesapce 的所有资源,使用:
 
 
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: mynamespace-user-full-access
  namespace: mynamespace
rules:
- apiGroups: ["", "extensions", "apps"]
  resources: ["*"]
  verbs: ["*"]
- apiGroups: ["batch"]
  resources:
  - jobs
  - cronjobs
  verbs: ["*"]
 
 
Role and ClusterRole
Role - namespaced resource
 
 
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
 
 
官方文档给出一些 Role 示例:https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-examples
ClusterRole - non-namespaced resource
 
 
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # "namespace" omitted since ClusterRoles are not namespaced
  name: secret-reader
rules:
- apiGroups: [""]
  #
  # at the HTTP level, the name of the resource for accessing Secret
  # objects is "secrets"
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]
 
 
Aggregated ClusterRoles
将多个 ClusterRole 聚合到同个中,通过 selector 与 label 进行匹配。
带有 aggregationRule 的资源:
 
 
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: monitoring
aggregationRule:
  clusterRoleSelectors:
  - matchLabels:
      rbac.example.com/aggregate-to-monitoring: "true"
rules: [] # The control plane automatically fills in the rules
 
 
当定义如下 ClusterRole 资源时,由于设置“对应的标签”,该 ClusterRole 会被自动合并到上面的 ClusterRole 资源中:
 
 
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: monitoring-endpoints
  labels:
    rbac.example.com/aggregate-to-monitoring: "true"
# When you create the "monitoring-endpoints" ClusterRole,
# the rules below will be added to the "monitoring" ClusterRole.
rules:
- apiGroups: [""]
  resources: ["services", "endpoints", "pods"]
  verbs: ["get", "list", "watch"]
 
 
官方文档还给了另外两个示例,将 CRD 资源的权限赋予 default user-facing roles,这也是通过 Aggregated ClusterRoles 实现的:
 
 
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: aggregate-cron-tabs-edit
  labels:
    # Add these permissions to the "admin" and "edit" default roles.
    rbac.authorization.k8s.io/aggregate-to-admin: "true"
    rbac.authorization.k8s.io/aggregate-to-edit: "true"
rules:
- apiGroups: ["stable.example.com"]
  resources: ["crontabs"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: aggregate-cron-tabs-view
  labels:
    # Add these permissions to the "view" default role.
    rbac.authorization.k8s.io/aggregate-to-view: "true"
rules:
- apiGroups: ["stable.example.com"]
  resources: ["crontabs"]
  verbs: ["get", "list", "watch"]
 
 
附加说明
限制访问子资源:
 
 
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list"]
 
 
通过资源名进行限制:
 
 
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: configmap-updater
rules:
- apiGroups: [""]
  #
  # at the HTTP level, the name of the resource for accessing ConfigMap
  # objects is "configmaps"
  resources: ["configmaps"]
  resourceNames: ["my-configmap"]
  verbs: ["update", "get"]
 
 
RoleBinding and ClusterRoleBinding
RoleBinding
= a Role + Subjects (Users, Groups, Service Accounts)
 
 
apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows "jane" to read pods in the "default" namespace.
# You need to already have a Role named "pod-reader" in that namespace.
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default

subjects:
# You can specify more than one "subject"
- kind: User
  name: jane # "name" is case sensitive
  apiGroup: rbac.authorization.k8s.io

roleRef:
  # "roleRef" specifies the binding to a Role / ClusterRole
  kind: Role #this must be Role or ClusterRole
  name: pod-reader # this must match the name of the Role or ClusterRole you wish to bind to
  apiGroup: rbac.authorization.k8s.io
 
 
= a ClusterRole + Subjects (Users, Groups, Service Accounts)
 
 
apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows "dave" to read secrets in the "development" namespace.
# You need to already have a ClusterRole named "secret-reader".
kind: RoleBinding
metadata:
  name: read-secrets
  #
  # The namespace of the RoleBinding determines where the permissions are granted.
  # This only grants permissions within the "development" namespace.
  namespace: development
subjects:
- kind: User
  name: dave # Name is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io
 
 
"dave" will only be able to read Secrets in the "development" namespace, because the RoleBinding's namespace is "development".
ClusterRoleBinding
 
 
apiVersion: rbac.authorization.k8s.io/v1
# This cluster role binding allows anyone in the "manager" group to read secrets in any namespace.
kind: ClusterRoleBinding
metadata:
  name: read-secrets-global
subjects:
- kind: Group
  name: manager # Name is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io


附加说明

创建 Binding 后,不可以修改它所引用的 Role/ClusterRole,如果尝试修改 Binding 的 roleRel 将产生错误。原因有二:
1)“可以为别人授权的用户”,可以在不修改 subjects,但是不影响 roleRef 参数;
2)防止错误调整为其他人意外赋予权限;

可以使用 kubectl auth reconcile 进行修改。