Skip to content

Commit

Permalink
authn/z: optionally opt-out of mandatory authn/authz kubeconfig
Browse files Browse the repository at this point in the history
Kubernetes-commit: a671d65673590f0dfcf5c2b673e1518d11510bdb
  • Loading branch information
sttts authored and k8s-publishing-bot committed Aug 22, 2018
1 parent 107ff76 commit ec43187
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 17 deletions.
1 change: 1 addition & 0 deletions pkg/authentication/authenticatorfactory/delegating.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
type DelegatingAuthenticatorConfig struct {
Anonymous bool

// TokenAccessReviewClient is a client to do token review. It can be nil. Then every token is ignored.
TokenAccessReviewClient authenticationclient.TokenReviewInterface

// CacheTTL is the length of time that a token authentication answer will be cached.
Expand Down
37 changes: 30 additions & 7 deletions pkg/server/options/authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ type DelegatingAuthenticationOptions struct {
// RemoteKubeConfigFile is the file to use to connect to a "normal" kube API server which hosts the
// TokenAccessReview.authentication.k8s.io endpoint for checking tokens.
RemoteKubeConfigFile string
// RemoteKubeConfigFileOptional is specifying whether not specifying the kubeconfig or
// a missing in-cluster config will be fatal.
RemoteKubeConfigFileOptional bool

// CacheTTL is the length of time that a token authentication answer will be cached.
CacheTTL time.Duration
Expand Down Expand Up @@ -139,9 +142,13 @@ func (s *DelegatingAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
return
}

var optionalKubeConfigSentence string
if s.RemoteKubeConfigFileOptional {
optionalKubeConfigSentence = " This is optional. If empty, all token requests are considered to be anonymous and no client CA is looked up in the cluster."
}
fs.StringVar(&s.RemoteKubeConfigFile, "authentication-kubeconfig", s.RemoteKubeConfigFile, ""+
"kubeconfig file pointing at the 'core' kubernetes server with enough rights to create "+
"tokenaccessreviews.authentication.k8s.io.")
"tokenaccessreviews.authentication.k8s.io."+optionalKubeConfigSentence)

fs.DurationVar(&s.CacheTTL, "authentication-token-webhook-cache-ttl", s.CacheTTL,
"The duration to cache responses from the webhook token authenticator.")
Expand All @@ -152,7 +159,6 @@ func (s *DelegatingAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
fs.BoolVar(&s.SkipInClusterLookup, "authentication-skip-lookup", s.SkipInClusterLookup, ""+
"If false, the authentication-kubeconfig will be used to lookup missing authentication "+
"configuration from the cluster.")

}

func (s *DelegatingAuthenticationOptions) ApplyTo(c *server.AuthenticationInfo, servingInfo *server.SecureServingInfo, openAPIConfig *openapicommon.Config) error {
Expand All @@ -161,15 +167,19 @@ func (s *DelegatingAuthenticationOptions) ApplyTo(c *server.AuthenticationInfo,
return nil
}

cfg := authenticatorfactory.DelegatingAuthenticatorConfig{
Anonymous: true,
CacheTTL: s.CacheTTL,
}

client, err := s.getClient()
if err != nil {
return fmt.Errorf("failed to get delegated authentication kubeconfig: %v", err)
}

cfg := authenticatorfactory.DelegatingAuthenticatorConfig{
Anonymous: true,
CacheTTL: s.CacheTTL,
TokenAccessReviewClient: client.AuthenticationV1beta1().TokenReviews(),
// configure token review
if client != nil {
cfg.TokenAccessReviewClient = client.AuthenticationV1beta1().TokenReviews()
}

// look into configmaps/external-apiserver-authentication for missing authn info
Expand Down Expand Up @@ -217,6 +227,15 @@ func (s *DelegatingAuthenticationOptions) lookupMissingConfigInCluster(client ku
if len(s.ClientCert.ClientCA) > 0 && len(s.RequestHeader.ClientCAFile) > 0 {
return nil
}
if client == nil {
if len(s.ClientCert.ClientCA) == 0 {
glog.Warningf("No authentication-kubeconfig provided in order to lookup client-ca-file in configmap/%s in %s, so client certificate authentication to extension api-server won't work.", authenticationConfigMapName, authenticationConfigMapNamespace)
}
if len(s.RequestHeader.ClientCAFile) == 0 {
glog.Warningf("No authentication-kubeconfig provided in order to lookup requestheader-client-ca-file in configmap/%s in %s, so request-header client certificate authentication to extension api-server won't work.", authenticationConfigMapName, authenticationConfigMapNamespace)
}
return nil
}

authConfigMap, err := client.CoreV1().ConfigMaps(authenticationConfigMapNamespace).Get(authenticationConfigMapName, metav1.GetOptions{})
if err != nil {
Expand Down Expand Up @@ -321,6 +340,8 @@ func deserializeStrings(in string) ([]string, error) {
return ret, nil
}

// getClient returns a Kubernetes clientset. If s.RemoteKubeConfigFileOptional is true, nil will be returned
// if no kubeconfig is specified by the user and the in-cluster config is not found.
func (s *DelegatingAuthenticationOptions) getClient() (kubernetes.Interface, error) {
var clientConfig *rest.Config
var err error
Expand All @@ -329,11 +350,13 @@ func (s *DelegatingAuthenticationOptions) getClient() (kubernetes.Interface, err
loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})

clientConfig, err = loader.ClientConfig()

} else {
// without the remote kubeconfig file, try to use the in-cluster config. Most addon API servers will
// use this path
clientConfig, err = rest.InClusterConfig()
if err == rest.ErrNotInCluster && s.RemoteKubeConfigFileOptional {
return nil, nil
}
}
if err != nil {
return nil, fmt.Errorf("failed to get delegated authentication kubeconfig: %v", err)
Expand Down
35 changes: 25 additions & 10 deletions pkg/server/options/authorization.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"time"

"github.com/golang/glog"
"github.com/spf13/pflag"

"k8s.io/apiserver/pkg/authorization/authorizer"
Expand All @@ -41,6 +42,9 @@ type DelegatingAuthorizationOptions struct {
// RemoteKubeConfigFile is the file to use to connect to a "normal" kube API server which hosts the
// SubjectAccessReview.authorization.k8s.io endpoint for checking tokens.
RemoteKubeConfigFile string
// RemoteKubeConfigFileOptional is specifying whether not specifying the kubeconfig or
// a missing in-cluster config will be fatal.
RemoteKubeConfigFileOptional bool

// AllowCacheTTL is the length of time that a successful authorization response will be cached
AllowCacheTTL time.Duration
Expand Down Expand Up @@ -72,9 +76,13 @@ func (s *DelegatingAuthorizationOptions) AddFlags(fs *pflag.FlagSet) {
return
}

var optionalKubeConfigSentence string
if s.RemoteKubeConfigFileOptional {
optionalKubeConfigSentence = " This is optional. If empty, all requests not skipped by authorization are forbidden."
}
fs.StringVar(&s.RemoteKubeConfigFile, "authorization-kubeconfig", s.RemoteKubeConfigFile,
"kubeconfig file pointing at the 'core' kubernetes server with enough rights to create "+
" subjectaccessreviews.authorization.k8s.io.")
"subjectaccessreviews.authorization.k8s.io."+optionalKubeConfigSentence)

fs.DurationVar(&s.AllowCacheTTL, "authorization-webhook-cache-authorized-ttl",
s.AllowCacheTTL,
Expand Down Expand Up @@ -115,16 +123,20 @@ func (s *DelegatingAuthorizationOptions) toAuthorizer(client kubernetes.Interfac
authorizers = append(authorizers, a)
}

cfg := authorizerfactory.DelegatingAuthorizerConfig{
SubjectAccessReviewClient: client.AuthorizationV1beta1().SubjectAccessReviews(),
AllowCacheTTL: s.AllowCacheTTL,
DenyCacheTTL: s.DenyCacheTTL,
}
a, err := cfg.New()
if err != nil {
return nil, err
if client == nil {
glog.Warningf("No authorization-kubeconfig provided, so SubjectAccessReview of authorization tokens won't work.")
} else {
cfg := authorizerfactory.DelegatingAuthorizerConfig{
SubjectAccessReviewClient: client.AuthorizationV1beta1().SubjectAccessReviews(),
AllowCacheTTL: s.AllowCacheTTL,
DenyCacheTTL: s.DenyCacheTTL,
}
delegatedAuthorizer, err := cfg.New()
if err != nil {
return nil, err
}
authorizers = append(authorizers, delegatedAuthorizer)
}
authorizers = append(authorizers, a)

return union.New(authorizers...), nil
}
Expand All @@ -141,6 +153,9 @@ func (s *DelegatingAuthorizationOptions) getClient() (kubernetes.Interface, erro
// without the remote kubeconfig file, try to use the in-cluster config. Most addon API servers will
// use this path
clientConfig, err = rest.InClusterConfig()
if err == rest.ErrNotInCluster && s.RemoteKubeConfigFileOptional {
return nil, nil
}
}
if err != nil {
return nil, fmt.Errorf("failed to get delegated authorization kubeconfig: %v", err)
Expand Down

0 comments on commit ec43187

Please sign in to comment.