authc认证
# 1.初始化
# 1.1.authentication
authentication会解析命令行参数,初始化authenticator支持的认证器,相关的配置经过genericConfig阶段执行applyTo写到通用配置。// NewServerRunOptions creates a new ServerRunOptions object with default parameters func NewServerRunOptions() *ServerRunOptions { s := ServerRunOptions{ ... Authentication: kubeoptions.NewBuiltInAuthenticationOptions().WithAll(), ... } ... return &s } // NewBuiltInAuthenticationOptions create a new BuiltInAuthenticationOptions, just set default token cache TTL func NewBuiltInAuthenticationOptions() *BuiltInAuthenticationOptions { return &BuiltInAuthenticationOptions{ TokenSuccessCacheTTL: 10 * time.Second, TokenFailureCacheTTL: 0 * time.Second, } } // WithAll set default value for every build-in authentication option func (o *BuiltInAuthenticationOptions) WithAll() *BuiltInAuthenticationOptions { return o. WithAnonymous(). WithBootstrapToken(). WithClientCert(). WithOIDC(). WithRequestHeader(). WithServiceAccounts(). WithTokenFile(). WithWebHook() } // genericConfig构造阶段加载Authentication func buildGenericConfig(s *options.ServerRunOptions, proxyTransport *http.Transport) (...) { ... // 应用认证配置 s.Authentication.ApplyTo(...) ... return } // ApplyTo requires already applied OpenAPIConfig and EgressSelector if present. func (o *BuiltInAuthenticationOptions) ApplyTo(...) error { ... // 认证相关配置 authenticatorConfig, err := o.ToAuthenticationConfig() ... // 加载客户端根CA if authenticatorConfig.ClientCAContentProvider != nil { authInfo.ApplyClientCert(authenticatorConfig.ClientCAContentProvider, secureServing) ... } // 加载请求头CA(验证上级apiserver转过来的请求) if authenticatorConfig.RequestHeaderConfig.CAContentProvider != nil { authInfo.ApplyClientCert(authenticatorConfig.RequestHeaderConfig.CAContentProvider, secureServing) ... } ... // 设置SA Token获取器 authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromClient( extclient, versionedInformer.Core().V1().Secrets().Lister(), versionedInformer.Core().V1().ServiceAccounts().Lister(), versionedInformer.Core().V1().Pods().Lister(), ) // 设置secret写出器 authenticatorConfig.SecretsWriter = extclient.CoreV1() // 设置bootstrap Token认证器 authenticatorConfig.BootstrapTokenAuthenticator = bootstrap.NewTokenAuthenticator( versionedInformer.Core().V1().Secrets().Lister().Secrets(metav1.NamespaceSystem), ) // 应用自定义网络出口拨号器 if egressSelector != nil { egressDialer, err := egressSelector.Lookup(egressselector.ControlPlane.AsNetworkContext()) ... authenticatorConfig.CustomDial = egressDialer } // 创建Authenticator authInfo.Authenticator, openAPIConfig.SecurityDefinitions, err = authenticatorConfig.New() ... return nil }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93注意
authenticator支持8种类型的认证方式,其实通常情况下只会用到WithClientCert()和WithServiceAccounts()
# 1.2.authenticator
authenticatorConfig.New()基于认证配置初始化authenticator,authenticator实现AuthenticateRequest,用于在请求链中认证。// New returns an authenticator.Request or that supports the standard Kubernetes authentication mechanisms. func (config Config) New() (authenticator.Request, *spec.SecurityDefinitions, error) { ... // apiserver代理身份认证 if config.RequestHeaderConfig != nil { requestHeaderAuthenticator := headerrequest.NewDynamicVerifyOptionsSecure( config.RequestHeaderConfig.CAContentProvider.VerifyOptions, config.RequestHeaderConfig.AllowedClientNames, config.RequestHeaderConfig.UsernameHeaders, config.RequestHeaderConfig.GroupHeaders, config.RequestHeaderConfig.ExtraHeaderPrefixes, ) authenticators = append(authenticators, authenticator.WrapAudienceAgnosticRequest(config.APIAudiences, requestHeaderAuthenticator)) } // X509客户端证书认证 if config.ClientCAContentProvider != nil { certAuth := x509.NewDynamic(config.ClientCAContentProvider.VerifyOptions, x509.CommonNameUserConversion) authenticators = append(authenticators, certAuth) } // 基于静态Token文件认证 if len(config.TokenAuthFile) > 0 { tokenAuth, err := newAuthenticatorFromTokenFile(config.TokenAuthFile) ... tokenAuthenticators = append(tokenAuthenticators, authenticator.WrapAudienceAgnosticToken(config.APIAudiences, tokenAuth)) } // 基于SA公钥文件认证 if len(config.ServiceAccountKeyFiles) > 0 { serviceAccountAuth, err := newLegacyServiceAccountAuthenticator(config.ServiceAccountKeyFiles, config.ServiceAccountLookup, config.APIAudiences, config.ServiceAccountTokenGetter, config.SecretsWriter) ... tokenAuthenticators = append(tokenAuthenticators, serviceAccountAuth) } // 基于SA JWT认证 if len(config.ServiceAccountIssuers) > 0 { serviceAccountAuth, err := newServiceAccountAuthenticator(config.ServiceAccountIssuers, config.ServiceAccountKeyFiles, config.APIAudiences, config.ServiceAccountTokenGetter) ... tokenAuthenticators = append(tokenAuthenticators, serviceAccountAuth) } // bootstrap Token认证 if config.BootstrapToken { if config.BootstrapTokenAuthenticator != nil { tokenAuthenticators = append(tokenAuthenticators, authenticator.WrapAudienceAgnosticToken(config.APIAudiences, config.BootstrapTokenAuthenticator)) } } // 基于OIDC认证 if len(config.OIDCIssuerURL) > 0 && len(config.OIDCClientID) > 0 { ... // 读取自签CA if len(config.OIDCCAFile) != 0 { ... oidcCAContent, oidcCAErr = staticCAContentProviderFromFile("oidc-authenticator", config.OIDCCAFile) ... } // 构建OIDC认证器,拉取Provider公钥及进行认证 oidcAuth, err := newAuthenticatorFromOIDCIssuerURL(oidc.Options{ IssuerURL: config.OIDCIssuerURL, ClientID: config.OIDCClientID, CAContentProvider: oidcCAContent, UsernameClaim: config.OIDCUsernameClaim, UsernamePrefix: config.OIDCUsernamePrefix, GroupsClaim: config.OIDCGroupsClaim, GroupsPrefix: config.OIDCGroupsPrefix, SupportedSigningAlgs: config.OIDCSigningAlgs, RequiredClaims: config.OIDCRequiredClaims, }) ... tokenAuthenticators = append(tokenAuthenticators, authenticator.WrapAudienceAgnosticToken(config.APIAudiences, oidcAuth)) } // webhook认证 if len(config.WebhookTokenAuthnConfigFile) > 0 { webhookTokenAuth, err := newWebhookTokenAuthenticator(config) ... tokenAuthenticators = append(tokenAuthenticators, webhookTokenAuth) } // 构造union认证器 if len(tokenAuthenticators) > 0 { // Union the token authenticators tokenAuth := tokenunion.New(tokenAuthenticators...) // 级联认证器加入缓存 if config.TokenSuccessCacheTTL > 0 || config.TokenFailureCacheTTL > 0 { tokenAuth = tokencache.New(tokenAuth, true, config.TokenSuccessCacheTTL,config.TokenFailureCacheTTL) } // 注册为http及websocket请求的认证器 authenticators = append(authenticators, bearertoken.New(tokenAuth), websocket.NewProtocolAuthenticator(tokenAuth)) ... } // 无可用认证器,追加配置的匿名认证 if len(authenticators) == 0 { if config.Anonymous { return anonymous.NewAuthenticator(), &securityDefinitions, nil } return nil, &securityDefinitions, nil } // 组合为联合认证器 authenticator := union.New(authenticators...) // 外部包装认证模块,认证通过用户添加系统组,区分匿名用户 authenticator = group.NewAuthenticatedGroupAdder(authenticator) // 开启匿名访问 if config.Anonymous { // 构造失败匿名兜底认证链 authenticator = union.NewFailOnError(authenticator, anonymous.NewAuthenticator()) } return authenticator, &securityDefinitions, nil }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121注意
authenticator会聚合所有认证模块,根据先后顺序依次调用auth.AuthenticateRequest()方法,认证
# 1.3.privileged
kube-xxxserver初始化会执行Complete()进行配置补充,相应会在union Authenticator头部注册privileged auth认证特权用户。// Complete fills in any fields not set that are required to have valid data. func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedConfig { ... // 补充超级管理员token认证 AuthorizeClientBearerToken(c.LoopbackClientConfig, &c.Authentication, &c.Authorization) // 初始化requestInfo解析器(URL解析) if c.RequestInfoResolver == nil { c.RequestInfoResolver = NewRequestInfoResolver(c) } ... return CompletedConfig{&completedConfig{c, informers}} } // AuthorizeClientBearerToken wraps the authenticator and authorizer in loopback authentication logic. func AuthorizeClientBearerToken(loopback *restclient.Config,authn *AuthenticationInfo,authz *AuthorizationInfo){ ... // 特权token privilegedLoopbackToken := loopback.BearerToken ... // 特权token关联的用户 tokens[privilegedLoopbackToken] = &user.DefaultInfo{ Name: "system:apiserver", UID: uid, Groups: []string{"system:masters"}, } // 生成一个特权Token认证器 tokenAuthenticator := authenticatorfactory.NewFromTokens(tokens, authn.APIAudiences) // 加入到联合认证器第一个 authn.Authenticator = authenticatorunion.New(tokenAuthenticator, authn.Authenticator) } // tokenAuthenticator认证 func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) { auth := strings.TrimSpace(req.Header.Get("Authorization")) ... parts := strings.SplitN(auth, " ", 3) ... token := parts[1] ... resp, ok, err := a.auth.AuthenticateToken(req.Context(), token) // pass if ok { req.Header.Del("Authorization") } ... return resp, ok, err } // a.auth.AuthenticateToken func (a *audAgnosticTokenAuthenticator) AuthenticateToken(ctx context.Context, tok string) (...) { return authenticate(ctx, a.implicit, func() (*Response, bool, error) { return a.delegate.AuthenticateToken(ctx, tok) }) } func authenticate(ctx context.Context, implicitAuds Audiences, authenticate func() (...) { targetAuds, ok := AudiencesFrom(ctx) ... auds := implicitAuds.Intersect(targetAuds) if len(auds) == 0 { return nil, false, nil } // 执行回调认证 resp, ok, err := authenticate() ... resp.Audiences = auds return resp, true, nil } // a.delegate.AuthenticateToken func (a *TokenAuthenticator) AuthenticateToken(ctx context.Context, value string) (...) { user, ok := a.tokens[value] if !ok { return nil, false, nil } return &authenticator.Response{User: user}, true, nil }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86补充
privileged Authenticator会认证静态特权token,认证通过则以system:apiserver作为用户
# 2.绑定
# 2.1.authHandler
WithAuthentication()会初始化一个绑定认证的handler,依次执行不同认证,没有携带任何认证信息会进行Anonymous匿名认证。func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler { ... // 补充未鉴权标识 failedHandler := genericapifilters.Unauthorized(c.Serializer) ... handler = genericapifilters.WithAuthentication(handler, c.Authentication.Authenticator, failedHandler, c.Authentication.APIAudiences, c.Authentication.RequestHeaderConfig) ... } // WithAuthentication creates an http handler that tries to authenticate the given request as a user. func WithAuthentication(...) http.Handler { return withAuthentication(handler, auth, failed, apiAuds, requestHeaderConfig, recordAuthMetrics) } func withAuthentication(...) http.Handler { ... return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ... // 执行认证 resp, ok, err := auth.AuthenticateRequest(req) ... // 认证失败 if err != nil || !ok { ... // 写出未授权响应 failed.ServeHTTP(w, req) return } ... // 清理Authorization头 req.Header.Del("Authorization") // 清理标准认证相关头(X-Remote-User) headerrequest.ClearAuthenticationHeaders(...) // 清理自定义认证相关头 if requestHeaderConfig != nil { headerrequest.ClearAuthenticationHeaders(...) } ... // 记录认证通过的USER信息 req = req.WithContext(genericapirequest.WithUser(req.Context(), resp.User)) handler.ServeHTTP(w, req) }) }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51注意
WithAuthentication()绑定的其实是一个回调handler,用于执行authenticator.AuthenticateRequest()执行认证
# 2.2.authRequest
union authenticator本质上是认证组合器,实现的authenticateRequest会轮流调用每个auth模块执行请求认证,有一个通过就结束。// token联合认证链 func New(authTokenHandlers ...authenticator.Token) authenticator.Token { if len(authTokenHandlers) == 1 { return authTokenHandlers[0] } return &unionAuthTokenHandler{Handlers: authTokenHandlers, FailOnError: false} } // 请求联合认证链(requestHeader+X509认证+token认证链+匿名认证器) func New(authRequestHandlers ...authenticator.Request) authenticator.Request { if len(authRequestHandlers) == 1 { return authRequestHandlers[0] } return &unionAuthRequestHandler{Handlers: authRequestHandlers, FailOnError: false} } // 包装为添加用户组的认证器 func NewAuthenticatedGroupAdder(auth authenticator.Request) authenticator.Request { return &AuthenticatedGroupAdder{auth} } // AuthenticateRequest authenticates the request using a chain of authenticator.Request objects. func (authHandler *unionAuthRequestHandler) AuthenticateRequest(req *http.Request) (...) { ... // 依次执行认证(requestHeader-->X509-->Token认证链) for _, currAuthRequestHandler := range authHandler.Handlers { resp, ok, err := currAuthRequestHandler.AuthenticateRequest(req) ... if ok { return resp, ok, err } } // 无法认证 return nil, false, utilerrors.NewAggregate(errlist) } // AuthenticateToken authenticates the token using a chain of authenticator.Token objects with http/websocket. func (authHandler *unionAuthTokenHandler) AuthenticateToken(ctx context.Context, token string) (...) { ... for _, currAuthRequestHandler := range authHandler.Handlers { // Token认证(静态Token-->SA Secret Token-->SA JWT Token-->Bootstrap Token-->OIDC Token-->WebHook Token) info, ok, err := currAuthRequestHandler.AuthenticateToken(ctx, token) ... if ok { return info, ok, err } } // 无法认证 return nil, false, utilerrors.NewAggregate(errlist) }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56注意
handlerChain绑定的其实就是union Authenticator,执行认证的流程就是调用auth.AuthenticateToken()依次执行认证
# 3.认证
# 3.1.header
requestHeader是一种代理认证方式,代理服务设置请求头部及透传请求给apiserver,由apiserver基于证书认证及信任请求头的用户信息。// AuthenticateRequest verifies the presented client certificate, then delegates to the wrapped auth func (a *Verifier) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) { ... // 加载证书套件 optsCopy, ok := a.verifyOptionsFn() ... // 补充中间证书池 if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 { optsCopy.Intermediates = x509.NewCertPool() for _, intermediate := range req.TLS.PeerCertificates[1:] { optsCopy.Intermediates.AddCert(intermediate) } } // 校验证书合法性 req.TLS.PeerCertificates[0].Verify(optsCopy) ... // 校验subject合法性 a.verifySubject(req.TLS.PeerCertificates[0].Subject) ... return a.auth.AuthenticateRequest(req) } func (a *requestHeaderAuthRequestHandler) AuthenticateRequest(req *http.Request) (...) { // 获取用户信息 name := headerValue(req.Header, a.nameHeaders.Value()) ... groups := allHeaderValues(req.Header, a.groupHeaders.Value()) extra := newExtra(req.Header, a.extraHeaderPrefixes.Value()) // 清理请求头认证信息 ClearAuthenticationHeaders(req.Header, a.nameHeaders, a.groupHeaders, a.extraHeaderPrefixes) return &authenticator.Response{ User: &user.DefaultInfo{ Name: name, Groups: groups, Extra: extra, }, }, true, nil }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45注意
requestHeader认证主要验证CA证书,证书合法即认为header身份信息受信
# 3.2.x509
x509 CA认证又称为TLS双向认证,kube-apiserver启动时基于--client-ca-file指定客户端的CA文件,用于客户端请求的认证。// AuthenticateRequest authenticates the request using presented client certificates func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) { ... // 加载证书套件 optsCopy, ok := a.verifyOptionsFn() ... // 补充中间证书池 if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 { optsCopy.Intermediates = x509.NewCertPool() for _, intermediate := range req.TLS.PeerCertificates[1:] { optsCopy.Intermediates.AddCert(intermediate) } } ... // 校验证书合法性 chains, err := req.TLS.PeerCertificates[0].Verify(optsCopy) ... // 解析证书链中用户 for _, chain := range chains { user, ok, err := a.user.User(chain) ... if ok { return user, ok, err } } return nil, false, utilerrors.NewAggregate(errlist) } // CommonNameUserConversion builds user info from a certificate chain using the subject's CommonName var CommonNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) { ... return &authenticator.Response{ User: &user.DefaultInfo{ Name: chain[0].Subject.CommonName, Groups: chain[0].Subject.Organization, }, }, true, nil })1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44注意
X509认证主要校验客户端证书合法性,验证通过的证书关联用户作为合法用户
# 3.3.anonymous
Anonymous用于处理其他身份认证无法识别的匿名请求,这类请求的用户名为system:anonymous,用户组为system:unauthenticated。func NewAuthenticator() authenticator.Request { return authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) { // 获取上下文audience auds, _ := authenticator.AudiencesFrom(req.Context()) // 构造匿名用户 return &authenticator.Response{ User: &user.DefaultInfo{ Name: anonymousUser, Groups: []string{unauthenticatedGroup}, }, Audiences: auds, }, true, nil }) }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16注意
ABAC和RBAC鉴权要求Anonymous用户执行显示的权限判断,因此*这种通配的权限策略规则上不再包含匿名用户
# 3.4.bearertoken
bearertoken本质是union token authenticator联合认证,组合认证链外部包装cache和http/websocket实现,利用层层嵌套实现认证。// http authenticator func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) { // 获取认证信息 auth := strings.TrimSpace(req.Header.Get("Authorization")) ... // 切割出类型和token parts := strings.SplitN(auth, " ", 3) ... token := parts[1] ... // 委托到cache token authenticator resp, ok, err := a.auth.AuthenticateToken(req.Context(), token) // 认证通过,清理认证信息 if ok { req.Header.Del("Authorization") } ... return resp, ok, err } // cache token authenticator func (a *cachedTokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (...) { // 执行token认证 record := a.doAuthenticateToken(ctx, token) ... return record.resp, true, nil } // doAuthenticateToken auth token with cache. func (a *cachedTokenAuthenticator) doAuthenticateToken(ctx context.Context, token string) *cacheRecord { ... // 取出签发目标 auds, audsOk := authenticator.AudiencesFrom(ctx) // 构造key key := keyFunc(a.hashPool, auds, token) // 获取缓存token if record, ok := a.cache.get(key); ok { ... return record } ... c := a.group.DoChan(key, func() (val interface{}, _ error) { ... // 缓存获取(双重检入,避免缓存延迟导致的再次校验问题) if record, ok := a.cache.get(key); ok { return record, nil } ... // 执行union authenticator认证 record.resp, record.ok, record.err = a.authenticator.AuthenticateToken(ctx, token) ... // 更新缓存 switch { case record.ok && a.successTTL > 0: a.cache.set(key, record, a.successTTL) case !record.ok && a.failureTTL > 0: a.cache.set(key, record, a.failureTTL) } return record, nil }) select { case result := <-c: // we always set Val and never set Err return result.Val.(*cacheRecord) case <-ctx.Done(): // fake a record on context cancel return &cacheRecord{err: ctx.Err()} } } // union authenticator auth token using a chain of authenticator.Token objects. func (authHandler *unionAuthTokenHandler) AuthenticateToken(ctx context.Context, token string) (...) { ... // 遍历认证链 for _, currAuthRequestHandler := range authHandler.Handlers { // 依次执行认证 info, ok, err := currAuthRequestHandler.AuthenticateToken(ctx, token) ... if ok { return info, ok, err } } return nil, false, utilerrors.NewAggregate(errlist) }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100注意
bearertoken认证基于bearertoken-->cache--->authenticator认证链完成,依次向下委托
# 3.5.satoken
SA认证基于JWT形式,请求中的token以base64编码放在header,使用的token是挂载到容器内的SA关联的secret token内容。// newLegacyServiceAccountAuthenticator returns an authenticator.Token or an error func newLegacyServiceAccountAuthenticator(...) (authenticator.Token, error) { ... // 加载公钥 for _, keyfile := range keyfiles { publicKeys, err := keyutil.PublicKeysFromFile(keyfile) ... allPublicKeys = append(allPublicKeys, publicKeys...) } // 校验器 validator, err := serviceaccount.NewLegacyValidator(lookup, serviceAccountGetter, secretsWriter) ... // JWT认证对象 tokenAuthenticator := serviceaccount.JWTTokenAuthenticator([]string{serviceaccount.LegacyIssuer}, allPublicKeys, apiAudiences, validator) return tokenAuthenticator, nil } // newServiceAccountAuthenticator returns an authenticator.Token or an error func newServiceAccountAuthenticator(...) (authenticator.Token, error) { ... // 加载公钥 for _, keyfile := range keyfiles { publicKeys, err := keyutil.PublicKeysFromFile(keyfile) ... allPublicKeys = append(allPublicKeys, publicKeys...) } // JWT认证对象 tokenAuthenticator := serviceaccount.JWTTokenAuthenticator(issuers, allPublicKeys, apiAudiences, serviceaccount.NewValidator(serviceAccountGetter)) return tokenAuthenticator, nil } // 认证 func (j *jwtTokenAuthenticator) AuthenticateToken(ctx context.Context, tokenData string) (...) { // 签发者校验 if !j.hasCorrectIssuer(tokenData) { return nil, false, nil } // 解析JWT签名 tok, err := jwt.ParseSigned(tokenData) ... // 基于公钥加载签名内容 for _, key := range j.keys { // 解析到标准JWT和自定义字段 tok.Claims(key, public, private) ... } ... // 获取token声明的audience tokenAudiences := authenticator.Audiences(public.Audience) if len(tokenAudiences) == 0 { ... // 老式Token,设置为kube-apiserver tokenAudiences = j.implicitAuds } // 获取上下文的audience(apiserver配置/issuer) requestedAudiences, ok := authenticator.AudiencesFrom(ctx) // 未指定 if !ok { // 设置为kube-apiserver requestedAudiences = j.implicitAuds } // 取交集 auds := authenticator.Audiences(tokenAudiences).Intersect(requestedAudiences) ... // 校验claims(有效期/secret/SA...) sa, err := j.validator.Validate(ctx, tokenData, public, private) ... return &authenticator.Response{ User: sa.UserInfo(), Audiences: auds, }, true, nil }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85注意
SA关联Token secret会挂到pod,供pod访问集群使用,这里的validator.Validate()其实就是验证SA/Secret/Pod存在合法性
# 3.6.webhook
webhook是一种验证持有者令牌的回调机制,kube-apiserver基于POST请求发送JSON序列化对象到远程服务,委托给webhook完成身份认证。func newWebhookTokenAuthenticator(config Config) (authenticator.Token, error) { ... // 初始化webhook连接配置 clientConfig, err := webhookutil.LoadKubeconfig(config.WebhookTokenAuthnConfigFile, config.CustomDial) ... // 构造webhook Token认证器 webhookTokenAuthenticator, err := webhook.New(clientConfig, config.WebhookTokenAuthnVersion, config.APIAudiences, *config.WebhookRetryBackoff) ... // cache authenticator包装 return tokencache.New(webhookTokenAuthenticator, false, config.WebhookTokenAuthnCacheTTL, config.WebhookTokenAuthnCacheTTL), nil } // New creates a new WebhookTokenAuthenticator from the provided rest config. func New(...) (*WebhookTokenAuthenticator, error) { // 请求客户端 tokenReview, err := tokenReviewInterfaceFromConfig(config, version, retryBackoff) ... // 构造带重试的webhookAuthenticator return newWithBackoff(tokenReview, retryBackoff, implicitAuds, time.Duration(0), AuthenticatorMetrics{...}) } // AuthenticateToken implements the authenticator.Token interface. func (w *WebhookTokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (...) { // 获取上下文audience wantAuds, checkAuds := authenticator.AudiencesFrom(ctx) // 构造请求的 r := &authenticationv1.TokenReview{ Spec: authenticationv1.TokenReviewSpec{ Token: token, Audiences: wantAuds, }, } ... // WithExponentialBackoff will return tokenreview create error (tokenReviewErr) if any. if err := webhook.WithExponentialBackoff(ctx, w.retryBackoff, func() error { ... // 发tokenReview请求 result, statusCode, tokenReviewErr = w.tokenReview.Create(ctx, r, metav1.CreateOptions{}) ... return tokenReviewErr }, webhook.DefaultShouldRetry) ... // 检查audience if checkAuds { gotAuds := w.implicitAuds if len(result.Status.Audiences) > 0 { gotAuds = result.Status.Audiences } // 取webhook结果与上下文交集 auds = wantAuds.Intersect(gotAuds) ... } ... // 保存用户额外信息 if r.Status.User.Extra != nil { extra = map[string][]string{} for k, v := range r.Status.User.Extra { extra[k] = v } } // 认证成功 return &authenticator.Response{ User: &user.DefaultInfo{ Name: r.Status.User.Username, UID: r.Status.User.UID, Groups: r.Status.User.Groups, Extra: extra, }, Audiences: auds, }, true, nil }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83注意
webhook认证本质上是构造tokenReview对象,基于http调用将token及audiences转给webhook处理,根据处理结果决定是否认证完成