diff --git a/cmd/controller-manager/app/serve.go b/cmd/controller-manager/app/serve.go index 5405121ac31..9c958128b41 100644 --- a/cmd/controller-manager/app/serve.go +++ b/cmd/controller-manager/app/serve.go @@ -44,7 +44,7 @@ func BuildHandlerChain(apiHandler http.Handler, authorizationInfo *apiserver.Aut handler = genericapifilters.WithAuthorization(apiHandler, authorizationInfo.Authorizer, legacyscheme.Codecs) } if authenticationInfo != nil { - handler = genericapifilters.WithAuthentication(handler, authenticationInfo.Authenticator, failedHandler) + handler = genericapifilters.WithAuthentication(handler, authenticationInfo.Authenticator, failedHandler, nil) } handler = genericapifilters.WithRequestInfo(handler, requestInfoResolver) handler = genericfilters.WithPanicRecovery(handler) diff --git a/cmd/kube-scheduler/app/server.go b/cmd/kube-scheduler/app/server.go index 32eaa86c0e0..f15ac031fde 100644 --- a/cmd/kube-scheduler/app/server.go +++ b/cmd/kube-scheduler/app/server.go @@ -232,7 +232,7 @@ func buildHandlerChain(handler http.Handler, authn authenticator.Request, authz handler = genericapifilters.WithRequestInfo(handler, requestInfoResolver) handler = genericapifilters.WithAuthorization(handler, authz, legacyscheme.Codecs) - handler = genericapifilters.WithAuthentication(handler, authn, failedHandler) + handler = genericapifilters.WithAuthentication(handler, authn, failedHandler, nil) handler = genericapifilters.WithRequestInfo(handler, requestInfoResolver) handler = genericfilters.WithPanicRecovery(handler) diff --git a/pkg/kubeapiserver/options/authentication.go b/pkg/kubeapiserver/options/authentication.go index 465c9c661ae..846883940d7 100644 --- a/pkg/kubeapiserver/options/authentication.go +++ b/pkg/kubeapiserver/options/authentication.go @@ -29,7 +29,7 @@ import ( genericapiserver "k8s.io/apiserver/pkg/server" genericoptions "k8s.io/apiserver/pkg/server/options" "k8s.io/apiserver/pkg/util/flag" - "k8s.io/kubernetes/pkg/kubeapiserver/authenticator" + kubeauthenticator "k8s.io/kubernetes/pkg/kubeapiserver/authenticator" authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" ) @@ -283,8 +283,8 @@ func (s *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { } } -func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig() authenticator.AuthenticatorConfig { - ret := authenticator.AuthenticatorConfig{ +func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig() kubeauthenticator.AuthenticatorConfig { + ret := kubeauthenticator.AuthenticatorConfig{ TokenSuccessCacheTTL: s.TokenSuccessCacheTTL, TokenFailureCacheTTL: s.TokenFailureCacheTTL, } @@ -367,6 +367,7 @@ func (o *BuiltInAuthenticationOptions) ApplyTo(c *genericapiserver.Config) error } c.Authentication.SupportsBasicAuth = o.PasswordFile != nil && len(o.PasswordFile.BasicAuthFile) > 0 + c.Authentication.APIAudiences = o.ServiceAccounts.APIAudiences return nil } diff --git a/pkg/kubeapiserver/server/insecure_handler.go b/pkg/kubeapiserver/server/insecure_handler.go index bde19e53929..05937e32d7e 100644 --- a/pkg/kubeapiserver/server/insecure_handler.go +++ b/pkg/kubeapiserver/server/insecure_handler.go @@ -32,7 +32,7 @@ import ( func BuildInsecureHandlerChain(apiHandler http.Handler, c *server.Config) http.Handler { handler := apiHandler handler = genericapifilters.WithAudit(handler, c.AuditBackend, c.AuditPolicyChecker, c.LongRunningFunc) - handler = genericapifilters.WithAuthentication(handler, server.InsecureSuperuser{}, nil) + handler = genericapifilters.WithAuthentication(handler, server.InsecureSuperuser{}, nil, nil) handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true") handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.LongRunningFunc, c.RequestTimeout) handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.MaxMutatingRequestsInFlight, c.LongRunningFunc) diff --git a/staging/src/k8s.io/apiserver/pkg/authentication/authenticator/BUILD b/staging/src/k8s.io/apiserver/pkg/authentication/authenticator/BUILD index 4a2741d9db0..31a1d8ac3f1 100644 --- a/staging/src/k8s.io/apiserver/pkg/authentication/authenticator/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/authentication/authenticator/BUILD @@ -7,7 +7,10 @@ load( go_library( name = "go_default_library", - srcs = ["interfaces.go"], + srcs = [ + "helpers.go", + "interfaces.go", + ], importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/authentication/authenticator", importpath = "k8s.io/apiserver/pkg/authentication/authenticator", deps = ["//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library"], diff --git a/staging/src/k8s.io/apiserver/pkg/authentication/authenticator/helpers.go b/staging/src/k8s.io/apiserver/pkg/authentication/authenticator/helpers.go new file mode 100644 index 00000000000..8227a736c33 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/authentication/authenticator/helpers.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package authenticator + +// Audiences is a container for the Audiences of a token. +type Audiences []string diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication.go b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication.go index ba53fc609e0..ec3bbc274e1 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication.go @@ -50,12 +50,15 @@ func init() { // stores any such user found onto the provided context for the request. If authentication fails or returns an error // the failed handler is used. On success, "Authorization" header is removed from the request and handler // is invoked to serve the request. -func WithAuthentication(handler http.Handler, auth authenticator.Request, failed http.Handler) http.Handler { +func WithAuthentication(handler http.Handler, auth authenticator.Request, failed http.Handler, apiAuds authenticator.Audiences) http.Handler { if auth == nil { glog.Warningf("Authentication is disabled") return handler } return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + if len(apiAuds) > 0 { + req = req.WithContext(genericapirequest.WithAudiences(req.Context(), apiAuds)) + } user, ok, err := auth.AuthenticateRequest(req) if err != nil || !ok { if err != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication_test.go b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication_test.go index 342ed6b95aa..a43119a9950 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication_test.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication_test.go @@ -50,6 +50,7 @@ func TestAuthenticateRequest(t *testing.T) { http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { t.Errorf("unexpected call to failed") }), + nil, ) auth.ServeHTTP(httptest.NewRecorder(), &http.Request{Header: map[string][]string{"Authorization": {"Something"}}}) @@ -69,6 +70,7 @@ func TestAuthenticateRequestFailed(t *testing.T) { http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { close(failed) }), + nil, ) auth.ServeHTTP(httptest.NewRecorder(), &http.Request{}) @@ -88,6 +90,7 @@ func TestAuthenticateRequestError(t *testing.T) { http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { close(failed) }), + nil, ) auth.ServeHTTP(httptest.NewRecorder(), &http.Request{}) diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/request/BUILD b/staging/src/k8s.io/apiserver/pkg/endpoints/request/BUILD index 5e84006a1cf..e56dc33f8bd 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/request/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/request/BUILD @@ -35,6 +35,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apiserver/pkg/apis/audit:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library", "//vendor/github.com/golang/glog:go_default_library", ], diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/request/context.go b/staging/src/k8s.io/apiserver/pkg/endpoints/request/context.go index 95166f5c474..eb1e8546093 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/request/context.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/request/context.go @@ -21,6 +21,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apiserver/pkg/apis/audit" + "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/user" ) @@ -36,6 +37,9 @@ const ( // auditKey is the context key for the audit event. auditKey + + // audiencesKey is the context key for request audiences. + audiencesKey ) // NewContext instantiates a base context object for request flows. @@ -91,3 +95,14 @@ func AuditEventFrom(ctx context.Context) *audit.Event { ev, _ := ctx.Value(auditKey).(*audit.Event) return ev } + +// WithAudiences returns a context that stores a request's expected audiences. +func WithAudiences(ctx context.Context, auds authenticator.Audiences) context.Context { + return context.WithValue(ctx, audiencesKey, auds) +} + +// AudiencesFrom returns a request's expected audiences stored in the request context. +func AudiencesFrom(ctx context.Context) (authenticator.Audiences, bool) { + auds, ok := ctx.Value(audiencesKey).(authenticator.Audiences) + return auds, ok +} diff --git a/staging/src/k8s.io/apiserver/pkg/server/config.go b/staging/src/k8s.io/apiserver/pkg/server/config.go index e7b0a8ecca0..10621f84f60 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/config.go @@ -227,6 +227,9 @@ type SecureServingInfo struct { } type AuthenticationInfo struct { + // APIAudiences is a list of identifier that the API identifies as. This is + // used by some authenticators to validate audience bound credentials. + APIAudiences authenticator.Audiences // Authenticator determines which subject is making the request Authenticator authenticator.Request // SupportsBasicAuth indicates that's at least one Authenticator supports basic auth @@ -534,7 +537,7 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler { handler = genericapifilters.WithAudit(handler, c.AuditBackend, c.AuditPolicyChecker, c.LongRunningFunc) failedHandler := genericapifilters.Unauthorized(c.Serializer, c.Authentication.SupportsBasicAuth) failedHandler = genericapifilters.WithFailedAuthenticationAudit(failedHandler, c.AuditBackend, c.AuditPolicyChecker) - handler = genericapifilters.WithAuthentication(handler, c.Authentication.Authenticator, failedHandler) + handler = genericapifilters.WithAuthentication(handler, c.Authentication.Authenticator, failedHandler, c.Authentication.APIAudiences) handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true") handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.LongRunningFunc, c.RequestTimeout) handler = genericfilters.WithWaitGroup(handler, c.LongRunningFunc, c.HandlerChainWaitGroup)