摘要:源碼解析基礎(chǔ)概念在版本中,正式引入了角色訪問控制機(jī)制,,讓集群管理員可以針對使用者或者或服務(wù)賬號,進(jìn)行更精確的資源訪問控制。在正式對的源碼進(jìn)行解析之前,需要了解幾個(gè)基本的概念。備注本文所有源碼均來自于分支。
Kubernetes RBAC源碼解析 RBAC基礎(chǔ)概念
在kubernetes 1.6版本中,正式引入了角色訪問控制機(jī)制(Role-Based Access Control,RBAC),讓集群管理員可以針對使用者(user或者group)或服務(wù)賬號(service account),進(jìn)行更精確的資源訪問控制。
在正式對kubernetes RBAC的源碼進(jìn)行解析之前,需要了解幾個(gè)基本的概念。
角色:是一系列權(quán)限的集合,例如一個(gè)角色包含services的list、watch權(quán)限。
角色綁定:是把角色映射到用戶,從而讓這些用戶繼承角色的權(quán)限。
若需在kubernetes中開啟RBAC的服務(wù),在apiserver的啟動(dòng)參數(shù)里設(shè)定鑒權(quán)模式,
--authorization-mode=RBAC
角色與角色綁定kubernetes中角色分為Role和ClusterRole,Role是namespace級別的,ClusterRole是集群級別的。
與RBAC相關(guān)的結(jié)構(gòu)體的定義,全部位于pkg/apis/rbac/types.go文件中。
ClusterRole的結(jié)構(gòu)體:
type ClusterRole struct { metav1.TypeMeta metav1.ObjectMeta Rules []PolicyRule AggregationRule *AggregationRule }
Role的結(jié)構(gòu)體:
type Role struct { metav1.TypeMeta metav1.ObjectMeta Rules []PolicyRule }
ClusterRole與Role的結(jié)構(gòu)體定義基本是類似的,角色里面都是關(guān)聯(lián)的Rules規(guī)則,一個(gè)角色有哪些權(quán)限,通過Rules去定義。下面是Rule的結(jié)構(gòu)體定義,主要控制訪問的資源、訪問URL的限制。
type PolicyRule struct { Verbs []string APIGroups []string Resources []string ResourceNames []string NonResourceURLs []string }
那么角色是怎么和使用者或者服務(wù)賬號綁定的呢?這就要看ClusterRoleBinding和RoleBinding。RoleBinding是把角色在namespace中對資源的權(quán)限授權(quán)給使用者或服務(wù)賬號;ClusterRoleBinding允許使用者或服務(wù)賬號在整個(gè)集群中的授權(quán)訪問。ClusterRoleBinding與RoleBinding的功能是一致的,只是有著更寬的使用范圍。下面是ClusterRoleBinding的結(jié)構(gòu)體:
type ClusterRoleBinding struct { metav1.TypeMeta metav1.ObjectMeta Subjects []Subject RoleRef RoleRef }
這是與ClusterRoleBinding具有相同屬性的結(jié)構(gòu)體RoleBinding:
type RoleBinding struct { metav1.TypeMeta metav1.ObjectMeta Subjects []Subject RoleRef RoleRef }
這兩個(gè)結(jié)構(gòu)體主要看兩個(gè)屬性值,第一個(gè)是Subjects,它是綁定的對象,包括User、Group、ServiceAccount;第二個(gè)是RoleRef,它是綁定的角色。
鑒權(quán)流程在了解了kubernetes中角色的定義,并掌握了如何將角色中定義的資源的訪問權(quán)限賦予給User、Group、ServiceAccount之后,我們需要了解的是,在處理一個(gè)API請求時(shí),如何對該請求進(jìn)行鑒權(quán)的處理?
在kubernetes中,所有的請求都會(huì)經(jīng)由apiserver進(jìn)行處理。在初始化apiserver時(shí),若指定了鑒權(quán)模式包括了RBAC后,將會(huì)注冊一個(gè)RBAC的Handler模塊。這樣,在apiserver接收請求并處理時(shí),將會(huì)調(diào)用該Handler,來判斷該請求的調(diào)用者是否有權(quán)限請求該資源。
該Handler位于staging/src/k8s.io/apiserver/pkg/endpoints/filters/authorization.go文件中:
func WithAuthorization(handler http.Handler, requestContextMapper request.RequestContextMapper, a authorizer.Authorizer, s runtime.NegotiatedSerializer) http.Handler { if a == nil { glog.Warningf("Authorization is disabled") return handler } return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ctx, ok := requestContextMapper.Get(req) if !ok { responsewriters.InternalError(w, req, errors.New("no context found for request")) return } attributes, err := GetAuthorizerAttributes(ctx) if err != nil { responsewriters.InternalError(w, req, err) return } authorized, reason, err := a.Authorize(attributes) // an authorizer like RBAC could encounter evaluation errors and still allow the request, so authorizer decision is checked before error here. if authorized == authorizer.DecisionAllow { handler.ServeHTTP(w, req) return } if err != nil { responsewriters.InternalError(w, req, err) return } glog.V(4).Infof("Forbidden: %#v, Reason: %q", req.RequestURI, reason) responsewriters.Forbidden(ctx, attributes, w, req, reason, s) }) }
該Handler做了兩件事,一是根據(jù)http request提取出鑒權(quán)所需的信息,通過函數(shù)GetAuthorizerAttributes()實(shí)現(xiàn),二是根據(jù)提取出的信息,執(zhí)行鑒權(quán)的核心操作,去判斷請求的調(diào)用者是否有權(quán)限操作相關(guān)資源,通過函數(shù)Authorize()處理。
提取信息的函數(shù)GetAuthorizerAttributes()位于staging/src/k8s.io/apiserver/pkg/endpoints/filters/authorization.go文件中。主要包括請求的APIGroup、APIVersion、Resource、SubResource、Verbs、Namespace等這些在PolicyRule結(jié)構(gòu)體中定義的信息。
func GetAuthorizerAttributes(ctx request.Context) (authorizer.Attributes, error) { attribs := authorizer.AttributesRecord{} user, ok := request.UserFrom(ctx) if ok { attribs.User = user } requestInfo, found := request.RequestInfoFrom(ctx) if !found { return nil, errors.New("no RequestInfo found in the context") } // Start with common attributes that apply to resource and non-resource requests attribs.ResourceRequest = requestInfo.IsResourceRequest attribs.Path = requestInfo.Path attribs.Verb = requestInfo.Verb attribs.APIGroup = requestInfo.APIGroup attribs.APIVersion = requestInfo.APIVersion attribs.Resource = requestInfo.Resource attribs.Subresource = requestInfo.Subresource attribs.Namespace = requestInfo.Namespace attribs.Name = requestInfo.Name return &attribs, nil }
在獲取了鑒權(quán)所需的相關(guān)信息后,kubernetes需要根據(jù)這些信息去執(zhí)行鑒權(quán)的核心操作。鑒權(quán)的函數(shù)Authorize()位于文件plugin/pkg/auth/authorizer/rbac/rbac.go文件中。
該函數(shù)會(huì)調(diào)用VisitRulesFor()來進(jìn)行鑒權(quán)的最后判斷工作。
func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (authorizer.Decision, string, error) { ruleCheckingVisitor := &authorizingVisitor{requestAttributes: requestAttributes} r.authorizationRuleResolver.VisitRulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace(), ruleCheckingVisitor.visit) if ruleCheckingVisitor.allowed { return authorizer.DecisionAllow, ruleCheckingVisitor.reason, nil } // Build a detailed log of the denial. // Make the whole block conditional so we don"t do a lot of string-building we won"t use. if glog.V(5) { var operation string if requestAttributes.IsResourceRequest() { b := &bytes.Buffer{} b.WriteString(`"`) b.WriteString(requestAttributes.GetVerb()) b.WriteString(`" resource "`) b.WriteString(requestAttributes.GetResource()) if len(requestAttributes.GetAPIGroup()) > 0 { b.WriteString(`.`) b.WriteString(requestAttributes.GetAPIGroup()) } if len(requestAttributes.GetSubresource()) > 0 { b.WriteString(`/`) b.WriteString(requestAttributes.GetSubresource()) } b.WriteString(`"`) if len(requestAttributes.GetName()) > 0 { b.WriteString(` named "`) b.WriteString(requestAttributes.GetName()) b.WriteString(`"`) } operation = b.String() } else { operation = fmt.Sprintf("%q nonResourceURL %q", requestAttributes.GetVerb(), requestAttributes.GetPath()) } var scope string if ns := requestAttributes.GetNamespace(); len(ns) > 0 { scope = fmt.Sprintf("in namespace %q", ns) } else { scope = "cluster-wide" } glog.Infof("RBAC DENY: user %q groups %q cannot %s %s", requestAttributes.GetUser().GetName(), requestAttributes.GetUser().GetGroups(), operation, scope) } reason := "" if len(ruleCheckingVisitor.errors) > 0 { reason = fmt.Sprintf("%v", utilerrors.NewAggregate(ruleCheckingVisitor.errors)) } return authorizer.DecisionNoOpinion, reason, nil }
VisitRulesFor()位于文件pkg/registry/rbac/validation/rule.go中。
該函數(shù)的鑒權(quán)操作步驟如下:
獲取所有的ClusterRoleBindings,并對其進(jìn)行遍歷操作;
根據(jù)請求調(diào)用者的信息,判斷該調(diào)用者是否被綁定在該ClusterRoleBinding中;
若綁定在該ClusterRoleBinding中,將通過函數(shù)GetRoleReferenceRules()獲取綁定的Role所控制的訪問的資源;
將Role所控制的訪問的資源,與從API請求中提取出的資源進(jìn)行比對,若比對成功,即為API請求的調(diào)用者有權(quán)訪問相關(guān)資源;
若在所有的ClusterRoleBinding中,都沒有獲得鑒權(quán)成功的操作,將會(huì)判斷提取出的信息中是否包括了namespace的信息,若包括了,將會(huì)獲取該namespace下的所有RoleBindings。
獲取了該namesapce下的所有RoleBindings之后,所執(zhí)行的操作將與ClusterRoleBinding類似,對其進(jìn)行遍歷,獲取對應(yīng)Role控制的訪問的資源,與從API請求中提取的資源信息進(jìn)行比對。
若在遍歷了所有CluterRoleBindings,及該namespace下的所有RoleBingdings之后,仍沒有對資源比對成功,則可判斷該API請求的調(diào)用者沒有權(quán)限訪問相關(guān)資源。
func (r *DefaultRuleResolver) VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbac.PolicyRule, err error) bool) { if clusterRoleBindings, err := r.clusterRoleBindingLister.ListClusterRoleBindings(); err != nil { if !visitor(nil, nil, err) { return } } else { sourceDescriber := &clusterRoleBindingDescriber{} for _, clusterRoleBinding := range clusterRoleBindings { subjectIndex, applies := appliesTo(user, clusterRoleBinding.Subjects, "") if !applies { continue } rules, err := r.GetRoleReferenceRules(clusterRoleBinding.RoleRef, "") if err != nil { if !visitor(nil, nil, err) { return } continue } sourceDescriber.binding = clusterRoleBinding sourceDescriber.subject = &clusterRoleBinding.Subjects[subjectIndex] for i := range rules { if !visitor(sourceDescriber, &rules[i], nil) { return } } } } if len(namespace) > 0 { if roleBindings, err := r.roleBindingLister.ListRoleBindings(namespace); err != nil { if !visitor(nil, nil, err) { return } } else { sourceDescriber := &roleBindingDescriber{} for _, roleBinding := range roleBindings { subjectIndex, applies := appliesTo(user, roleBinding.Subjects, namespace) if !applies { continue } rules, err := r.GetRoleReferenceRules(roleBinding.RoleRef, namespace) if err != nil { if !visitor(nil, nil, err) { return } continue } sourceDescriber.binding = roleBinding sourceDescriber.subject = &roleBinding.Subjects[subjectIndex] for i := range rules { if !visitor(sourceDescriber, &rules[i], nil) { return } } } } } } // GetRoleReferenceRules attempts to resolve the RoleBinding or ClusterRoleBinding. func (r *DefaultRuleResolver) GetRoleReferenceRules(roleRef rbac.RoleRef, bindingNamespace string) ([]rbac.PolicyRule, error) { switch kind := rbac.RoleRefGroupKind(roleRef); kind { case rbac.Kind("Role"): role, err := r.roleGetter.GetRole(bindingNamespace, roleRef.Name) if err != nil { return nil, err } return role.Rules, nil case rbac.Kind("ClusterRole"): clusterRole, err := r.clusterRoleGetter.GetClusterRole(roleRef.Name) if err != nil { return nil, err } return clusterRole.Rules, nil default: return nil, fmt.Errorf("unsupported role reference kind: %q", kind) } }備注
本文所有源碼均來自于kubernetes release-1.10分支。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/32704.html
摘要:如果新服務(wù)器無法啟動(dòng),則初始服務(wù)器實(shí)例仍然可用且仍然提供查詢,但處理程序保持關(guān)閉狀態(tài)。在成功重新加載或完全重新啟動(dòng)之前,運(yùn)行狀況不會(huì)回復(fù)請求。后記在新創(chuàng)建后更新有問題需要解決 核心鏈接 https://kubernetes.io/docs/ta... CoreDNS 安裝 apiVersion: v1 kind: ServiceAccount metadata: name: cor...
摘要:在中使用驗(yàn)證使用身份驗(yàn)證策略來認(rèn)證用戶的。審閱狀態(tài)包含名稱和組等用戶信息。中的授權(quán)模塊稍后將以此確定該用戶的訪問級別。認(rèn)證請求認(rèn)證服務(wù)決定該用戶是否通過認(rèn)證,并向發(fā)送響應(yīng)。在對的請求成功進(jìn)行認(rèn)證之后,必須授權(quán)該請求。 Rancher Kubernetes擁有RBAC(基于角色的訪問控制)功能,此功能可以讓管理員配置不同的策略,允許或拒絕用戶和服務(wù)帳戶訪問Kubernetes API資源...
摘要:在中使用驗(yàn)證使用身份驗(yàn)證策略來認(rèn)證用戶的。審閱狀態(tài)包含名稱和組等用戶信息。中的授權(quán)模塊稍后將以此確定該用戶的訪問級別。認(rèn)證請求認(rèn)證服務(wù)決定該用戶是否通過認(rèn)證,并向發(fā)送響應(yīng)。在對的請求成功進(jìn)行認(rèn)證之后,必須授權(quán)該請求。 Rancher Kubernetes擁有RBAC(基于角色的訪問控制)功能,此功能可以讓管理員配置不同的策略,允許或拒絕用戶和服務(wù)帳戶訪問Kubernetes API資源...
摘要:本文介紹了模型中四個(gè)最主要的對象,即,大致了解了的工作原理和使用方法,如果要更加深入地了解和掌握,可以查看官方文檔。只是這個(gè)不能復(fù)用到其他,一般只有在做精細(xì)化權(quán)限管理的時(shí)候,我們才會(huì)創(chuàng)建對象,比如一個(gè)只能查看名稱為的。了解RBAC簡介RBAC是一種基于角色來管理對計(jì)算機(jī)或網(wǎng)絡(luò)資源訪問策略的方法。我們知道,對K8S內(nèi)所有API對象的操作都是通過訪問kube-apiserver來完成的,因此ku...
閱讀 892·2023-04-25 19:17
閱讀 2195·2021-09-10 11:26
閱讀 1908·2019-08-30 15:54
閱讀 3429·2019-08-30 15:53
閱讀 2688·2019-08-30 11:20
閱讀 3404·2019-08-29 15:12
閱讀 1238·2019-08-29 13:16
閱讀 2395·2019-08-26 12:19