k8s 权限控制
Secret、ServiceAccount 的权限受限于 Role/ClusterRole。
一提到权限就整 RABC,其实就是 Role-Based Access Control。说白了异常简单
user1 ------rolebinding1------> role1 user1 ------rolebinding2------> role2
- 权限在 role 上,通过 rolebinding 将 user 和 role 串起来
- k8s 只能给用户赋予什么权利;给用户赋予所有权限除了 XX 权限是不行的
据我现在的经验所知:
- user 可以是
serviceaccout
(基于某个 namespace)、users
(没有试验过) - role 可以是
role
(基于某个 namespace)、clusterRole
(全局) - rolebinding 可以是
rolebinding
(基于某个 namespace)、clusterrolebinding
(全局)
User
以 serviceaccout 为例:
# 定义 [root@master lihao04-test]# cat lihao-rbac.yaml apiVersion: v1 kind: ServiceAccount metadata: # 名字 name: lihao-sa # 所属的 namespace namespace: monitoring # 创建 [root@master lihao04-test]# kubectl apply -f lihao-rbac.yaml serviceaccount/lihao-sa created # 查询创建结果 [root@master lihao04-test]# kubectl describe serviceaccount lihao-sa -n monitoring Name: lihao-sa Namespace: monitoring Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"name":"lihao-sa","namespace":"monitoring"}} Image pull secrets: <none> Mountable secrets: lihao-sa-token-qhzbk Tokens: lihao-sa-token-qhzbk Events: <none>
可以看出 serviceaccout 非常简单,创建后,会默认给你创建一个 token
也就是 secret
。目前为止 RABC 的主体 user,我们就大致搞清楚了。
Role
Role 代表权限,本质上说就是对某种资源的什么操作是允许的
- APIGroups + Resources + ResourceNames 是表征资源
- Verbs 是表征操作
具体含义我们在源码中仔细分析:
Role 的定义 kubernetes/vendor/k8s.io/api/rbac/v1beta1/types.go
type Role struct { metav1.TypeMeta `json:",inline"` // Standard object's metadata. // +optional metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` // Rules holds all the PolicyRules for this Role // +optional # 规则 Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"` }
ClusterRole 的定义 kubernetes/vendor/k8s.io/api/rbac/v1beta1/types.go
type ClusterRole struct { metav1.TypeMeta `json:",inline"` // Standard object's metadata. // +optional metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` // Rules holds all the PolicyRules for this ClusterRole // +optional Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"` // AggregationRule is an optional field that describes how to build the Rules for this ClusterRole. // If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be // stomped by the controller. // +optional # 比 Role 多了的信息,但是我看不懂 AggregationRule *AggregationRule `json:"aggregationRule,omitempty" protobuf:"bytes,3,opt,name=aggregationRule"` }
关键看权限 PolicyRule:
type PolicyRule struct { // Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule. VerbAll represents all kinds. # 操作包括如下,详细参考:https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb # create # get # list # watch # update # patch # delete # deletecollection # 根据自己的需要来确定如何填写,全部操作都支持用 ["*"] Verbs []string `json:"verbs" protobuf:"bytes,1,rep,name=verbs"` // APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of // the enumerated resources in any API group will be allowed. // +optional # k8s 的 api 太多了,因此分 group,可选的如下,参见 # https://github.com/kubernetes/community/tree/master/sig-api-machinery # https://kubernetes.io/docs/reference/access-authn-authz/rbac/ # 这个太复杂,一般都用 [""] 表示 core api APIGroups []string `json:"apiGroups,omitempty" protobuf:"bytes,2,rep,name=apiGroups"` // Resources is a list of resources this rule applies to. '*' represents all resources in the specified apiGroups. // '*/foo' represents the subresource 'foo' for all resources in the specified apiGroups. // +optional # 不是很懂,感觉是 APIGroup 本身就含有很多的 resource,这里进一步约束了使用那些 resource # ["*"] 所有的 APIGroup 中的 resource # 注意,node 是 resource,但是只填 node,没有权限访问 /nodes/metrics,必须填 node/metrics,metrics 作为 subresources # 如果要访问 /nodes/metrics/cadvisor 难道需要填写:nodes/metrics/cadvisor?不需要,只要填写了 subresources 再下一层的自动有权限 Resources []string `json:"resources,omitempty" protobuf:"bytes,3,rep,name=resources"` // ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. // +optional # 指定资源的名字,一般不用,除非访问特定的某一个已经被创建出来的资源,不灵活 ResourceNames []string `json:"resourceNames,omitempty" protobuf:"bytes,4,rep,name=resourceNames"` // NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path // Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. // Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both. // +optional # 我不太清楚,但是我理解可能是用户 pod 的 metrics 采集权限? # https://github.com/brancz/kube-rbac-proxy/tree/master/examples/non-resource-url NonResourceURLs []string `json:"nonResourceURLs,omitempty" protobuf:"bytes,5,rep,name=nonResourceURLs"` }
ClusterRole 中增加了额外的内容
// AggregationRule describes how to locate ClusterRoles to aggregate into the ClusterRole type AggregationRule struct { // ClusterRoleSelectors holds a list of selectors which will be used to find ClusterRoles and create the rules. // If any of the selectors match, then the ClusterRole's permissions will be added // +optional # 不懂 ClusterRoleSelectors []metav1.LabelSelector `json:"clusterRoleSelectors,omitempty" protobuf:"bytes,1,rep,name=clusterRoleSelectors"` }
RoleBinding
RoleBinding 是 role 与 user 的桥梁
kubernetes/vendor/k8s.io/api/rbac/v1beta1/types.go
type RoleBinding struct { metav1.TypeMeta `json:",inline"` // Standard object's metadata. // +optional metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` // Subjects holds references to the objects the role applies to. // +optional # 是个数组,因此,user 可以填多个 Subjects []Subject `json:"subjects,omitempty" protobuf:"bytes,2,rep,name=subjects"` // RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace. // If the RoleRef cannot be resolved, the Authorizer must return an error. # 只能填一个值,因此,大家懂得 RoleRef RoleRef `json:"roleRef" protobuf:"bytes,3,opt,name=roleRef"` }
Subject 中,一版就用 name 来标识
// Subject contains a reference to the object or user identities a role binding applies to. This can either hold a direct API object reference, // or a value for non-objects such as user and group names. type Subject struct { // Kind of object being referenced. Values defined by this API group are "User", "Group", and "ServiceAccount". // If the Authorizer does not recognized the kind value, the Authorizer should report an error. Kind string `json:"kind" protobuf:"bytes,1,opt,name=kind"` // APIGroup holds the API group of the referenced subject. // Defaults to "" for ServiceAccount subjects. // Defaults to "rbac.authorization.k8s.io" for User and Group subjects. // +optional APIGroup string `json:"apiGroup,omitempty" protobuf:"bytes,2,opt.name=apiGroup"` // Name of the object being referenced. Name string `json:"name" protobuf:"bytes,3,opt,name=name"` // Namespace of the referenced object. If the object kind is non-namespace, such as "User" or "Group", and this value is not empty // the Authorizer should report an error. // +optional Namespace string `json:"namespace,omitempty" protobuf:"bytes,4,opt,name=namespace"` }
RoleRef 一般也用名字而已,如果 user 要对应多个 role,记得填多个 rolebinding
// RoleRef contains information that points to the role being used type RoleRef struct { // APIGroup is the group for the resource being referenced APIGroup string `json:"apiGroup" protobuf:"bytes,1,opt,name=apiGroup"` // Kind is the type of resource being referenced Kind string `json:"kind" protobuf:"bytes,2,opt,name=kind"` // Name is the name of resource being referenced Name string `json:"name" protobuf:"bytes,3,opt,name=name"` }
给个例子
apiVersion: v1 kind: ServiceAccount metadata: name: prometheus-k8s namespace: monitoring --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: prometheus-k8s rules: - apiGroups: [""] resources: ["nodes", "nodes/metrics", "services", "endpoints", "pods"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["configmaps"] verbs: ["get"] --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: prometheus-k8s roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: prometheus-k8s subjects: - kind: ServiceAccount name: prometheus-k8s namespace: monitoring
附录
为什么在 deployment/statefulset 等中填写
serviceAccount: lihao-sa
就可以在 /var/run/secrets/kubernetes.io/serviceaccount/token 获得 token 的值?简言之,这是 k8s 的机制,token/ca/namespace 都会自动挂载到 /var/run/secrets/kubernetes.io/serviceaccount/ 下。
因为 serviceaccount 是访问 apiserver 等 k8s 服务,或者与其他 pod 服务交互的基础,如果不填 serviceaccount,系统将会给予一个 default 的 serviceaccount。