k8s 权限控制初探
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。