国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Kubernetes RBAC源碼解析

2json / 2781人閱讀

摘要:源碼解析基礎概念在版本中,正式引入了角色訪問控制機制,,讓集群管理員可以針對使用者或者或服務賬號,進行更精確的資源訪問控制。在正式對的源碼進行解析之前,需要了解幾個基本的概念。備注本文所有源碼均來自于分支。

Kubernetes RBAC源碼解析 RBAC基礎概念

在kubernetes 1.6版本中,正式引入了角色訪問控制機制(Role-Based Access Control,RBAC),讓集群管理員可以針對使用者(user或者group)或服務賬號(service account),進行更精確的資源訪問控制。

在正式對kubernetes RBAC的源碼進行解析之前,需要了解幾個基本的概念。

角色:是一系列權限的集合,例如一個角色包含services的list、watch權限。

角色綁定:是把角色映射到用戶,從而讓這些用戶繼承角色的權限。

若需在kubernetes中開啟RBAC的服務,在apiserver的啟動參數里設定鑒權模式,

--authorization-mode=RBAC

角色與角色綁定

kubernetes中角色分為Role和ClusterRole,Role是namespace級別的,ClusterRole是集群級別的。

與RBAC相關的結構體的定義,全部位于pkg/apis/rbac/types.go文件中。

ClusterRole的結構體:

type ClusterRole struct {
    metav1.TypeMeta
    
    metav1.ObjectMeta

    Rules []PolicyRule

    AggregationRule *AggregationRule
}

Role的結構體:

type Role struct {
    metav1.TypeMeta
    
    metav1.ObjectMeta

    Rules []PolicyRule
}

ClusterRole與Role的結構體定義基本是類似的,角色里面都是關聯的Rules規則,一個角色有哪些權限,通過Rules去定義。下面是Rule的結構體定義,主要控制訪問的資源、訪問URL的限制。

type PolicyRule struct {
    Verbs []string

    APIGroups []string

    Resources []string

    ResourceNames []string

    NonResourceURLs []string
}

那么角色是怎么和使用者或者服務賬號綁定的呢?這就要看ClusterRoleBinding和RoleBinding。RoleBinding是把角色在namespace中對資源的權限授權給使用者或服務賬號;ClusterRoleBinding允許使用者或服務賬號在整個集群中的授權訪問。ClusterRoleBinding與RoleBinding的功能是一致的,只是有著更寬的使用范圍。下面是ClusterRoleBinding的結構體:

type ClusterRoleBinding struct {
    metav1.TypeMeta    
    metav1.ObjectMeta

    Subjects []Subject

    RoleRef RoleRef
}

這是與ClusterRoleBinding具有相同屬性的結構體RoleBinding:

type RoleBinding struct {
    metav1.TypeMeta
    metav1.ObjectMeta

    Subjects []Subject

    RoleRef RoleRef
}

這兩個結構體主要看兩個屬性值,第一個是Subjects,它是綁定的對象,包括User、Group、ServiceAccount;第二個是RoleRef,它是綁定的角色。

鑒權流程

在了解了kubernetes中角色的定義,并掌握了如何將角色中定義的資源的訪問權限賦予給User、Group、ServiceAccount之后,我們需要了解的是,在處理一個API請求時,如何對該請求進行鑒權的處理?

在kubernetes中,所有的請求都會經由apiserver進行處理。在初始化apiserver時,若指定了鑒權模式包括了RBAC后,將會注冊一個RBAC的Handler模塊。這樣,在apiserver接收請求并處理時,將會調用該Handler,來判斷該請求的調用者是否有權限請求該資源。

該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做了兩件事,一是根據http request提取出鑒權所需的信息,通過函數GetAuthorizerAttributes()實現,二是根據提取出的信息,執行鑒權的核心操作,去判斷請求的調用者是否有權限操作相關資源,通過函數Authorize()處理。

提取信息的函數GetAuthorizerAttributes()位于staging/src/k8s.io/apiserver/pkg/endpoints/filters/authorization.go文件中。主要包括請求的APIGroup、APIVersion、Resource、SubResource、Verbs、Namespace等這些在PolicyRule結構體中定義的信息。

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
}

在獲取了鑒權所需的相關信息后,kubernetes需要根據這些信息去執行鑒權的核心操作。鑒權的函數Authorize()位于文件plugin/pkg/auth/authorizer/rbac/rbac.go文件中。

該函數會調用VisitRulesFor()來進行鑒權的最后判斷工作。

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中。

該函數的鑒權操作步驟如下:

獲取所有的ClusterRoleBindings,并對其進行遍歷操作;

根據請求調用者的信息,判斷該調用者是否被綁定在該ClusterRoleBinding中;

若綁定在該ClusterRoleBinding中,將通過函數GetRoleReferenceRules()獲取綁定的Role所控制的訪問的資源;

將Role所控制的訪問的資源,與從API請求中提取出的資源進行比對,若比對成功,即為API請求的調用者有權訪問相關資源;

若在所有的ClusterRoleBinding中,都沒有獲得鑒權成功的操作,將會判斷提取出的信息中是否包括了namespace的信息,若包括了,將會獲取該namespace下的所有RoleBindings。

獲取了該namesapce下的所有RoleBindings之后,所執行的操作將與ClusterRoleBinding類似,對其進行遍歷,獲取對應Role控制的訪問的資源,與從API請求中提取的資源信息進行比對。

若在遍歷了所有CluterRoleBindings,及該namespace下的所有RoleBingdings之后,仍沒有對資源比對成功,則可判斷該API請求的調用者沒有權限訪問相關資源。

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分支。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/32704.html

相關文章

  • coredns 排錯記

    摘要:如果新服務器無法啟動,則初始服務器實例仍然可用且仍然提供查詢,但處理程序保持關閉狀態。在成功重新加載或完全重新啟動之前,運行狀況不會回復請求。后記在新創建后更新有問題需要解決 核心鏈接 https://kubernetes.io/docs/ta... CoreDNS 安裝 apiVersion: v1 kind: ServiceAccount metadata: name: cor...

    Salamander 評論0 收藏0
  • Rancher中的K8S認證和RBAC

    摘要:在中使用驗證使用身份驗證策略來認證用戶的。審閱狀態包含名稱和組等用戶信息。中的授權模塊稍后將以此確定該用戶的訪問級別。認證請求認證服務決定該用戶是否通過認證,并向發送響應。在對的請求成功進行認證之后,必須授權該請求。 Rancher Kubernetes擁有RBAC(基于角色的訪問控制)功能,此功能可以讓管理員配置不同的策略,允許或拒絕用戶和服務帳戶訪問Kubernetes API資源...

    raise_yang 評論0 收藏0
  • Rancher中的K8S認證和RBAC

    摘要:在中使用驗證使用身份驗證策略來認證用戶的。審閱狀態包含名稱和組等用戶信息。中的授權模塊稍后將以此確定該用戶的訪問級別。認證請求認證服務決定該用戶是否通過認證,并向發送響應。在對的請求成功進行認證之后,必須授權該請求。 Rancher Kubernetes擁有RBAC(基于角色的訪問控制)功能,此功能可以讓管理員配置不同的策略,允許或拒絕用戶和服務帳戶訪問Kubernetes API資源...

    Forest10 評論0 收藏0
  • 【容器云 UK8S】最佳實踐:權限管理之了解RBAC和權限管理實踐

    摘要:本文介紹了模型中四個最主要的對象,即,大致了解了的工作原理和使用方法,如果要更加深入地了解和掌握,可以查看官方文檔。只是這個不能復用到其他,一般只有在做精細化權限管理的時候,我們才會創建對象,比如一個只能查看名稱為的。了解RBAC簡介RBAC是一種基于角色來管理對計算機或網絡資源訪問策略的方法。我們知道,對K8S內所有API對象的操作都是通過訪問kube-apiserver來完成的,因此ku...

    Tecode 評論0 收藏0

發表評論

0條評論

2json

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<