问题描述
该笔记将记录:在 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 进行修改。