kube-apiserver鉴权源码简析

1 概述

1.1 环境

版本信息如下:
a、操作系统:centos 7.6
b、kubernetes版本:v1.15.0


1.2 鉴权Authorization

4A包括账号Account、认证Authentication、鉴权Authorization、审计Audit,是一个IT系统的一个基础的非业务性的通用功能。后台鉴权一般分为接口权限和数据权限,接口权限在在controller层的拦截器中实现,数据权限在dao层中实现。
kube-apiserver是一个http web服务,显然接口鉴权的工作也是在controller层的拦截器中实现。

1.3 kube-apiserver中的RBAC鉴权思路

kube-apiserver支持ABAC和RBAC,但RBAC往往使用得最广泛,因此本文只讨论RBAC。
对于RBAC而言,kubernetes的Role对象和ClusterRole对象,保存着一组权限,而权限就是谓语(action,或者叫verb)和宾语(object)(例如:get是谓语,pod是宾语)。kube-apiserver从http request对象的tls信息中获得主语(subject),从http mechod和http path推断出谓语和宾语,具备了主语、谓语和宾语后,遍历所有ClusterRole对象和Role对象中的权限信息,逐一对比,匹配正确则放行请求,不匹配则返回403响应。

2 源码

2.1 在拦截器链中注册鉴权相关的两个拦截器

鉴权拦截器是genericapifilters.WithAuthorization( ),而推断了主语、谓语和宾语的拦截器是genericapifilters.WithRequestInfo( )。在拦截器链中,因为genericapifilters.WithRequestInfo( )是较后配置的,因此是较先执行的。

# kubernetes/staging/src/k8s.io/apiserver/pkg/server/config.go
func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {

    handler := genericapifilters.WithAuthorization(apiHandler, c.Authorization.Authorizer, c.Serializer)
    
    /*
    	其他拦截器
    */
    
    handler = genericapifilters.WithRequestInfo(handler, c.RequestInfoResolver)
    
    /*
    	其他拦截器
    */
    
    return handler
}

2.2 拦截器genericapifilters.WithRequestInfo( )

将http request的信息解析之后,得到k8s对象的gvr信息、namespace、verb等信息,并保存到名称为info且类型为RequestInfo结构体的对象中,这些信息会在authorize阶段中被使用到。

func WithRequestInfo(handler http.Handler, resolver request.RequestInfoResolver) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
        ctx := req.Context()
        // 解析http请求的path和query参数,形成info对象,info对象会在authorize阶段中被使用到
        info, err := resolver.NewRequestInfo(req)
        if err != nil {
            responsewriters.InternalError(w, req, fmt.Errorf("failed to create RequestInfo: %v", err))
            return
        }

        // 将info对象放入http request中的ctx对象中
        req = req.WithContext(request.WithRequestInfo(ctx, info))

        handler.ServeHTTP(w, req)
    })
}
// RequestInfo holds information parsed from the http.Request
type RequestInfo struct {
	IsResourceRequest bool
	Path string

	Verb string

	APIPrefix  string
	APIGroup   string
	APIVersion string
	Namespace  string
	Resource string
	Subresource string
	Name string
	Parts []string
}

2.3 拦截器genericapifilters.WithAuthorization( )

func WithAuthorization(handler http.Handler, a authorizer.Authorizer, s runtime.NegotiatedSerializer) http.Handler {
	
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		ctx := req.Context()
		
		// 从request的ctx对象中提取数据
		attributes, err := GetAuthorizerAttributes(ctx)

		// 使用鉴权器进行鉴权,这行代码是重点
		authorized, reason, err := a.Authorize(attributes)
		
		// 鉴权结果是通过,则放行请求
		if authorized == authorizer.DecisionAllow {
			handler.ServeHTTP(w, req)
			return
		}
		
		// 服务器内部发生错误,返回5xx响应
		if err != nil {
			responsewriters.InternalError(w, req, err)
			return
		}

		// 鉴权结果是不通过,返回403响应
		responsewriters.Forbidden(ctx, attributes, w, req, reason, s)
	})
}

RBAC鉴权器的主要逻辑如下:

func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (authorizer.Decision, string, error) {
    ruleCheckingVisitor := &authorizingVisitor{requestAttributes: requestAttributes}

    // VisitRulesFor(  )从http request的ctx对象中拿出info对象,然后遍历ClusterRoleBinding和RoleBinding找出所有role
    // 最终逐一进行比对role中表示的权限
    r.authorizationRuleResolver.VisitRulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace(), ruleCheckingVisitor.visit)
   
    // 鉴权结果是一个布尔值,放在ruleCheckingVisitor的属性allowed中
    if ruleCheckingVisitor.allowed {
        return authorizer.DecisionAllow, ruleCheckingVisitor.reason, nil
    }

    /*
        其他代码
    */
    return authorizer.DecisionNoOpinion, reason, nil
}

3 小结

kube-apiserver是一个普通web http服务,鉴权逻辑清晰易懂,先是从http request中提取主语、谓语和宾语,在鉴权阶段就拿着刚获得的主谓宾信息去逐一匹配所有ClusterRole和Role对象中包含的权限信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值