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。