wire up a means to dynamically reload ca bundles for kube-apiserver

This commit is contained in:
David Eads
2019-10-07 14:06:42 -04:00
parent b0c272e1fb
commit 6beb96261e
24 changed files with 438 additions and 105 deletions

View File

@@ -24,6 +24,7 @@ go_library(
"//staging/src/k8s.io/apiserver/pkg/authentication/token/cache:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/token/tokenfile:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/token/union:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/server/dynamiccertificates:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/apiserver/plugin/pkg/authenticator/password/passwordfile:go_default_library",
"//staging/src/k8s.io/apiserver/plugin/pkg/authenticator/request/basicauth:go_default_library",

View File

@@ -33,6 +33,7 @@ import (
tokencache "k8s.io/apiserver/pkg/authentication/token/cache"
"k8s.io/apiserver/pkg/authentication/token/tokenfile"
tokenunion "k8s.io/apiserver/pkg/authentication/token/union"
"k8s.io/apiserver/pkg/server/dynamiccertificates"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/plugin/pkg/authenticator/password/passwordfile"
"k8s.io/apiserver/plugin/pkg/authenticator/request/basicauth"
@@ -77,10 +78,10 @@ type Config struct {
// TODO, this is the only non-serializable part of the entire config. Factor it out into a clientconfig
ServiceAccountTokenGetter serviceaccount.ServiceAccountTokenGetter
BootstrapTokenAuthenticator authenticator.Token
// ClientVerifyOptionFn are the options for verifying incoming connections using mTLS and directly assigning to users.
// ClientCAContentProvider are the options for verifying incoming connections using mTLS and directly assigning to users.
// Generally this is the CA bundle file used to authenticate client certificates
// If this value is nil, then mutual TLS is disabled.
ClientVerifyOptionFn x509.VerifyOptionFunc
ClientCAContentProvider dynamiccertificates.CAContentProvider
}
// New returns an authenticator.Request or an error that supports the standard
@@ -94,7 +95,7 @@ func (config Config) New() (authenticator.Request, *spec.SecurityDefinitions, er
// Add the front proxy authenticator if requested
if config.RequestHeaderConfig != nil {
requestHeaderAuthenticator := headerrequest.NewDynamicVerifyOptionsSecure(
config.RequestHeaderConfig.VerifyOptionFn,
config.RequestHeaderConfig.CAContentProvider.VerifyOptions,
config.RequestHeaderConfig.AllowedClientNames,
config.RequestHeaderConfig.UsernameHeaders,
config.RequestHeaderConfig.GroupHeaders,
@@ -120,8 +121,8 @@ func (config Config) New() (authenticator.Request, *spec.SecurityDefinitions, er
}
// X509 methods
if config.ClientVerifyOptionFn != nil {
certAuth := x509.NewDynamic(config.ClientVerifyOptionFn, x509.CommonNameUserConversion)
if config.ClientCAContentProvider != nil {
certAuth := x509.NewDynamic(config.ClientCAContentProvider.VerifyOptions, x509.CommonNameUserConversion)
authenticators = append(authenticators, certAuth)
}

View File

@@ -324,7 +324,7 @@ func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig() (kubeauthenticat
if s.ClientCert != nil {
var err error
ret.ClientVerifyOptionFn, err = s.ClientCert.GetClientVerifyOptionFn()
ret.ClientCAContentProvider, err = s.ClientCert.GetClientCAContentProvider()
if err != nil {
return kubeauthenticator.Config{}, err
}
@@ -390,15 +390,24 @@ func (o *BuiltInAuthenticationOptions) ApplyTo(c *genericapiserver.Config) error
return nil
}
var err error
if o.ClientCert != nil {
if err = c.Authentication.ApplyClientCert(o.ClientCert.ClientCA, c.SecureServing); err != nil {
clientCertificateCAContentProvider, err := o.ClientCert.GetClientCAContentProvider()
if err != nil {
return fmt.Errorf("unable to load client CA file: %v", err)
}
if err = c.Authentication.ApplyClientCert(clientCertificateCAContentProvider, c.SecureServing); err != nil {
return fmt.Errorf("unable to load client CA file: %v", err)
}
}
if o.RequestHeader != nil {
if err = c.Authentication.ApplyClientCert(o.RequestHeader.ClientCAFile, c.SecureServing); err != nil {
return fmt.Errorf("unable to load client CA file: %v", err)
requestHeaderConfig, err := o.RequestHeader.ToAuthenticationRequestHeaderConfig()
if err != nil {
return fmt.Errorf("unable to create request header authentication config: %v", err)
}
if requestHeaderConfig != nil {
if err = c.Authentication.ApplyClientCert(requestHeaderConfig.CAContentProvider, c.SecureServing); err != nil {
return fmt.Errorf("unable to load client CA file: %v", err)
}
}
}

View File

@@ -146,7 +146,7 @@ func TestToAuthenticationConfig(t *testing.T) {
Anonymous: false,
BasicAuthFile: "/testBasicAuthFile",
BootstrapToken: false,
ClientVerifyOptionFn: nil, // this is nil because you can't compare functions
ClientCAContentProvider: nil, // this is nil because you can't compare functions
TokenAuthFile: "/testTokenFile",
OIDCIssuerURL: "testIssuerURL",
OIDCClientID: "testClientID",
@@ -165,7 +165,7 @@ func TestToAuthenticationConfig(t *testing.T) {
UsernameHeaders: headerrequest.StaticStringSlice{"x-remote-user"},
GroupHeaders: headerrequest.StaticStringSlice{"x-remote-group"},
ExtraHeaderPrefixes: headerrequest.StaticStringSlice{"x-remote-extra-"},
VerifyOptionFn: nil, // this is nil because you can't compare functions
CAContentProvider: nil, // this is nil because you can't compare functions
AllowedClientNames: headerrequest.StaticStringSlice{"kube-aggregator"},
},
}
@@ -176,14 +176,14 @@ func TestToAuthenticationConfig(t *testing.T) {
}
// nil these out because you cannot compare pointers. Ensure they are non-nil first
if resultConfig.ClientVerifyOptionFn == nil {
if resultConfig.ClientCAContentProvider == nil {
t.Error("missing client verify")
}
if resultConfig.RequestHeaderConfig.VerifyOptionFn == nil {
if resultConfig.RequestHeaderConfig.CAContentProvider == nil {
t.Error("missing requestheader verify")
}
resultConfig.ClientVerifyOptionFn = nil
resultConfig.RequestHeaderConfig.VerifyOptionFn = nil
resultConfig.ClientCAContentProvider = nil
resultConfig.RequestHeaderConfig.CAContentProvider = nil
if !reflect.DeepEqual(resultConfig, expectConfig) {
t.Error(cmp.Diff(resultConfig, expectConfig))