本节重点总结 :
rbac模型四种对象的关系
role,clusterrole rolebinding,clusterrolebinding role、clusterrole中的rules规则
rbac鉴权的代码逻辑
通过informer获取clusterRoleBindings列表,根据user匹配subject,通过informer获取clusterRoleBindings的rules,遍历调用visit进行rule匹配 通过informer获取RoleBindings列表,根据user和namespace匹配subject,,通过informer获取RoleBindings的rules,遍历调用visit进行rule匹配
rbac鉴权模型
文档地址 https://kubernetes.io/zh/docs/reference/access-authn-authz/rbac/
简介
基于角色(Role)的访问控制(RBAC)是一种基于组织中用户的角色来调节控制对 计算机或网络资源的访问的方法。 RBAC 鉴权机制使用 rbac.authorization.k8s.io API 组 来驱动鉴权决定,允许你通过 Kubernetes API 动态配置策略。
看文档介绍
源码解读
入口 D:\go_path\src\github.com\kubernetes\kubernetes\pkg\kubeapiserver\authorizer\config.go
case modes. ModeRBAC:
rbacAuthorizer := rbac. New (
& rbac. RoleGetter{ Lister: config. VersionedInformerFactory. Rbac ( ) . V1 ( ) . Roles ( ) . Lister ( ) } ,
& rbac. RoleBindingLister{ Lister: config. VersionedInformerFactory. Rbac ( ) . V1 ( ) . RoleBindings ( ) . Lister ( ) } ,
& rbac. ClusterRoleGetter{ Lister: config. VersionedInformerFactory. Rbac ( ) . V1 ( ) . ClusterRoles ( ) . Lister ( ) } ,
& rbac. ClusterRoleBindingLister{ Lister: config. VersionedInformerFactory. Rbac ( ) . V1 ( ) . ClusterRoleBindings ( ) . Lister ( ) } ,
)
authorizers = append ( authorizers, rbacAuthorizer)
ruleResolvers = append ( ruleResolvers, rbacAuthorizer)
rbac.New 传入Role、ClusterRole、RoleBinding 和 ClusterRoleBinding 4种对象的Getter
func New ( roles rbacregistryvalidation. RoleGetter, roleBindings rbacregistryvalidation. RoleBindingLister, clusterRoles rbacregistryvalidation. ClusterRoleGetter, clusterRoleBindings rbacregistryvalidation. ClusterRoleBindingLister) * RBACAuthorizer {
authorizer := & RBACAuthorizer{
authorizationRuleResolver: rbacregistryvalidation. NewDefaultRuleResolver (
roles, roleBindings, clusterRoles, clusterRoleBindings,
) ,
}
return authorizer
}
构建DefaultRuleResolver,并用DefaultRuleResolver构建RBACAuthorizer
RBACAuthorizer的Authorize解析
核心判断点在ruleCheckingVisitor的allowed标志位,如果为true,则通过,否则就不通过
func ( r * RBACAuthorizer) Authorize ( ctx context. Context, 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
}
return authorizer. DecisionNoOpinion, reason, nil
}
这个allowed标志位只有在visit方法中才会被设置,条件是RuleAllows=true
func ( v * authorizingVisitor) visit ( source fmt. Stringer, rule * rbacv1. PolicyRule, err error ) bool {
if rule != nil && RuleAllows ( v. requestAttributes, rule) {
v. allowed = true
v. reason = fmt. Sprintf ( "RBAC: allowed by %s" , source. String ( ) )
return false
}
if err != nil {
v. errors = append ( v. errors, err)
}
return true
}
VisitRulesFor调用visit方法校验每一条rule
r. authorizationRuleResolver. VisitRulesFor ( requestAttributes. GetUser ( ) , requestAttributes. GetNamespace ( ) , ruleCheckingVisitor. visit)
先校验clusterRoleBinding
具体流程先用informer获取 clusterRoleBindings,出错了就校验失败,因为传给visitor的rule为nil就意味着allowed不会被设置为true
if clusterRoleBindings, err := r. clusterRoleBindingLister. ListClusterRoleBindings ( ) ; err != nil {
if ! visitor ( nil , nil , err) {
return
}
}
先根据传入的user对象对比subject主体
for _ , clusterRoleBinding := range clusterRoleBindings {
subjectIndex, applies := appliesTo ( user, clusterRoleBinding. Subjects, "" )
if ! applies {
continue
}
appliesToUser对比函数
根据user类型判断
如果是普通用户就判断名字 如果是group就判断 里面的user名字 如果是ServiceAccount就要用serviceaccount.MatchesUsername对比
func appliesToUser ( user user. Info, subject rbacv1. Subject, namespace string ) bool {
switch subject. Kind {
case rbacv1. UserKind:
return user. GetName ( ) == subject. Name
case rbacv1. GroupKind:
return has ( user. GetGroups ( ) , subject. Name)
case rbacv1. ServiceAccountKind:
saNamespace := namespace
if len ( subject. Namespace) > 0 {
saNamespace = subject. Namespace
}
if len ( saNamespace) == 0 {
return false
}
return serviceaccount. MatchesUsername ( saNamespace, subject. Name, user. GetName ( ) )
default :
return false
}
}
serviceaccount.MatchesUsername对比 serviceaccount的全名 system:serviceaccount:namespace:name 逐次进行对比
func MatchesUsername ( namespace, name string , username string ) bool {
if ! strings. HasPrefix ( username, ServiceAccountUsernamePrefix) {
return false
}
username = username[ len ( ServiceAccountUsernamePrefix) : ]
if ! strings. HasPrefix ( username, namespace) {
return false
}
username = username[ len ( namespace) : ]
if ! strings. HasPrefix ( username, ServiceAccountUsernameSeparator) {
return false
}
username = username[ len ( ServiceAccountUsernameSeparator) : ]
return username == name
}
再根据clusterRoleBinding.RoleRef从informer获取rules
rules, err := r. GetRoleReferenceRules ( clusterRoleBinding. RoleRef, "" )
遍历rule,传入找到的clusterRoleBinding,调用visit进行比对
sourceDescriber. binding = clusterRoleBinding
sourceDescriber. subject = & clusterRoleBinding. Subjects[ subjectIndex]
for i := range rules {
if ! visitor ( sourceDescriber, & rules[ i] , nil ) {
return
}
}
资源型
func VerbMatches ( rule * rbacv1. PolicyRule, requestedVerb string ) bool {
for _ , ruleVerb := range rule. Verbs {
if ruleVerb == rbacv1. VerbAll {
return true
}
if ruleVerb == requestedVerb {
return true
}
}
return false
}
非资源型的
func NonResourceURLMatches ( rule * rbacv1. PolicyRule, requestedURL string ) bool {
for _ , ruleURL := range rule. NonResourceURLs {
if ruleURL == rbacv1. NonResourceAll {
return true
}
if ruleURL == requestedURL {
return true
}
if strings. HasSuffix ( ruleURL, "*" ) && strings. HasPrefix ( requestedURL, strings. TrimRight ( ruleURL, "*" ) ) {
return true
}
}
return false
}
再校验RoleBinding
通过informer获取roleBinding列表
if roleBindings, err := r. roleBindingLister. ListRoleBindings ( namespace) ; err != nil {
if ! visitor ( nil , nil , err) {
return
}
遍历对比subject
for _ , roleBinding := range roleBindings {
subjectIndex, applies := appliesTo ( user, roleBinding. Subjects, namespace)
if ! applies {
根据informer获取匹配到的roleBinding的rules对象
rules, err := r. GetRoleReferenceRules ( roleBinding. RoleRef, namespace)
if err != nil {
if ! visitor ( nil , nil , err) {
return
}
continue
}
调用visit方法遍历rule进行匹配
sourceDescriber. binding = roleBinding
sourceDescriber. subject = & roleBinding. Subjects[ subjectIndex]
for i := range rules {
if ! visitor ( sourceDescriber, & rules[ i] , nil ) {
return
}
}
本节重点总结 :
rbac模型四种对象的关系
role,clusterrole rolebinding,clusterrolebinding role、clusterrole中的rules规则
rbac鉴权的代码逻辑
通过informer获取clusterRoleBindings列表,根据user匹配subject,通过informer获取clusterRoleBindings的rules,遍历调用visit进行rule匹配 通过informer获取RoleBindings列表,根据user和namespace匹配subject,,通过informer获取RoleBindings的rules,遍历调用visit进行rule匹配