Merge pull request #36604 from deads2k/api-42-add-generic-loopback

Automatic merge from submit-queue

move parts of the mega generic run struct out

This splits the main `ServerRunOptions` into composeable pieces that are bindable separately and adds easy paths for composing servers to run delegating authentication and authorization.

@sttts @ncdc alright, I think this is as far as I need to go to make the composing servers reasonable to write.  I'll try leaving it here
This commit is contained in:
Kubernetes Submit Queue
2016-11-30 21:11:06 -08:00
committed by GitHub
35 changed files with 1810 additions and 730 deletions

View File

@@ -26,9 +26,8 @@ go_library(
"//pkg/apis/extensions:go_default_library",
"//pkg/apiserver:go_default_library",
"//pkg/apiserver/authenticator:go_default_library",
"//pkg/auth/authorizer/union:go_default_library",
"//pkg/auth/user:go_default_library",
"//pkg/capabilities:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/cloudprovider:go_default_library",
"//pkg/cloudprovider/providers:go_default_library",
"//pkg/controller/informers:go_default_library",
@@ -36,11 +35,11 @@ go_library(
"//pkg/generated/openapi:go_default_library",
"//pkg/genericapiserver:go_default_library",
"//pkg/genericapiserver/authorizer:go_default_library",
"//pkg/genericapiserver/validation:go_default_library",
"//pkg/genericapiserver/options:go_default_library",
"//pkg/master:go_default_library",
"//pkg/registry/cachesize:go_default_library",
"//pkg/runtime/schema:go_default_library",
"//pkg/serviceaccount:go_default_library",
"//pkg/util/errors:go_default_library",
"//pkg/util/net:go_default_library",
"//pkg/util/wait:go_default_library",
"//pkg/version:go_default_library",
@@ -63,7 +62,6 @@ go_library(
"//plugin/pkg/admission/securitycontext/scdeny:go_default_library",
"//plugin/pkg/admission/serviceaccount:go_default_library",
"//plugin/pkg/admission/storageclass/default:go_default_library",
"//plugin/pkg/auth/authenticator/request/union:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:github.com/pborman/uuid",
"//vendor:github.com/spf13/cobra",

View File

@@ -31,24 +31,32 @@ import (
// ServerRunOptions runs a kubernetes api server.
type ServerRunOptions struct {
GenericServerRunOptions *genericoptions.ServerRunOptions
AllowPrivileged bool
EventTTL time.Duration
KubeletConfig kubeletclient.KubeletClientConfig
MaxConnectionBytesPerSec int64
SSHKeyfile string
SSHUser string
ServiceAccountKeyFiles []string
ServiceAccountLookup bool
WebhookTokenAuthnConfigFile string
WebhookTokenAuthnCacheTTL time.Duration
GenericServerRunOptions *genericoptions.ServerRunOptions
Etcd *genericoptions.EtcdOptions
SecureServing *genericoptions.SecureServingOptions
InsecureServing *genericoptions.ServingOptions
Authentication *genericoptions.BuiltInAuthenticationOptions
Authorization *genericoptions.BuiltInAuthorizationOptions
AllowPrivileged bool
EventTTL time.Duration
KubeletConfig kubeletclient.KubeletClientConfig
MaxConnectionBytesPerSec int64
SSHKeyfile string
SSHUser string
}
// NewServerRunOptions creates a new ServerRunOptions object with default parameters
func NewServerRunOptions() *ServerRunOptions {
s := ServerRunOptions{
GenericServerRunOptions: genericoptions.NewServerRunOptions().WithEtcdOptions(),
EventTTL: 1 * time.Hour,
GenericServerRunOptions: genericoptions.NewServerRunOptions(),
Etcd: genericoptions.NewEtcdOptions(),
SecureServing: genericoptions.NewSecureServingOptions(),
InsecureServing: genericoptions.NewInsecureServingOptions(),
Authentication: genericoptions.NewBuiltInAuthenticationOptions().WithAll(),
Authorization: genericoptions.NewBuiltInAuthorizationOptions(),
EventTTL: 1 * time.Hour,
KubeletConfig: kubeletclient.KubeletClientConfig{
Port: ports.KubeletPort,
PreferredAddressTypes: []string{
@@ -60,7 +68,6 @@ func NewServerRunOptions() *ServerRunOptions {
EnableHttps: true,
HTTPTimeout: time.Duration(5) * time.Second,
},
WebhookTokenAuthnCacheTTL: 2 * time.Minute,
}
return &s
}
@@ -69,29 +76,21 @@ func NewServerRunOptions() *ServerRunOptions {
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
// Add the generic flags.
s.GenericServerRunOptions.AddUniversalFlags(fs)
//Add etcd specific flags.
s.GenericServerRunOptions.AddEtcdStorageFlags(fs)
s.Etcd.AddFlags(fs)
s.SecureServing.AddFlags(fs)
s.SecureServing.AddDeprecatedFlags(fs)
s.InsecureServing.AddFlags(fs)
s.InsecureServing.AddDeprecatedFlags(fs)
s.Authentication.AddFlags(fs)
s.Authorization.AddFlags(fs)
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
// arrange these text blocks sensibly. Grrr.
fs.DurationVar(&s.EventTTL, "event-ttl", s.EventTTL,
"Amount of time to retain events. Default is 1h.")
fs.StringArrayVar(&s.ServiceAccountKeyFiles, "service-account-key-file", s.ServiceAccountKeyFiles, ""+
"File containing PEM-encoded x509 RSA or ECDSA private or public keys, used to verify "+
"ServiceAccount tokens. If unspecified, --tls-private-key-file is used. "+
"The specified file can contain multiple keys, and the flag can be specified multiple times with different files.")
fs.BoolVar(&s.ServiceAccountLookup, "service-account-lookup", s.ServiceAccountLookup,
"If true, validate ServiceAccount tokens exist in etcd as part of authentication.")
fs.StringVar(&s.WebhookTokenAuthnConfigFile, "authentication-token-webhook-config-file", s.WebhookTokenAuthnConfigFile, ""+
"File with webhook configuration for token authentication in kubeconfig format. "+
"The API server will query the remote service to determine authentication for bearer tokens.")
fs.DurationVar(&s.WebhookTokenAuthnCacheTTL, "authentication-token-webhook-cache-ttl", s.WebhookTokenAuthnCacheTTL,
"The duration to cache responses from the webhook token authenticator. Default is 2m.")
fs.BoolVar(&s.AllowPrivileged, "allow-privileged", s.AllowPrivileged,
"If true, allow privileged containers.")

View File

@@ -41,24 +41,22 @@ import (
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apiserver"
"k8s.io/kubernetes/pkg/apiserver/authenticator"
authorizerunion "k8s.io/kubernetes/pkg/auth/authorizer/union"
"k8s.io/kubernetes/pkg/auth/user"
"k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/cloudprovider"
"k8s.io/kubernetes/pkg/controller/informers"
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi"
"k8s.io/kubernetes/pkg/genericapiserver"
"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation"
genericoptions "k8s.io/kubernetes/pkg/genericapiserver/options"
"k8s.io/kubernetes/pkg/master"
"k8s.io/kubernetes/pkg/registry/cachesize"
"k8s.io/kubernetes/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/serviceaccount"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
utilnet "k8s.io/kubernetes/pkg/util/net"
"k8s.io/kubernetes/pkg/util/wait"
"k8s.io/kubernetes/pkg/version"
authenticatorunion "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union"
)
// NewAPIServerCommand creates a *cobra.Command object with default parameters
@@ -80,11 +78,20 @@ cluster's shared state through which all other components interact.`,
// Run runs the specified APIServer. This should never exit.
func Run(s *options.ServerRunOptions) error {
genericvalidation.VerifyEtcdServersList(s.GenericServerRunOptions)
if errs := s.Etcd.Validate(); len(errs) > 0 {
return utilerrors.NewAggregate(errs)
}
if err := s.GenericServerRunOptions.DefaultExternalAddress(s.SecureServing, s.InsecureServing); err != nil {
return err
}
genericapiserver.DefaultAndValidateRunOptions(s.GenericServerRunOptions)
genericConfig := genericapiserver.NewConfig(). // create the new config
ApplyOptions(s.GenericServerRunOptions). // apply the options selected
Complete() // set default values based on the known values
ApplySecureServingOptions(s.SecureServing).
ApplyInsecureServingOptions(s.InsecureServing).
ApplyAuthenticationOptions(s.Authentication).
ApplyRBACSuperUser(s.Authorization.RBACSuperUser)
serviceIPRange, apiServerServiceIP, err := genericapiserver.DefaultServiceIPRange(s.GenericServerRunOptions.ServiceClusterIPRange)
if err != nil {
@@ -142,7 +149,7 @@ func Run(s *options.ServerRunOptions) error {
// Proxying to pods and services is IP-based... don't expect to be able to verify the hostname
proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true}
if s.GenericServerRunOptions.StorageConfig.DeserializationCacheSize == 0 {
if s.Etcd.StorageConfig.DeserializationCacheSize == 0 {
// When size of cache is not explicitly set, estimate its size based on
// target memory usage.
glog.V(2).Infof("Initalizing deserialization cache size based on %dMB limit", s.GenericServerRunOptions.TargetRAMMB)
@@ -158,9 +165,9 @@ func Run(s *options.ServerRunOptions) error {
// size to compute its size. We may even go further and measure
// collective sizes of the objects in the cache.
clusterSize := s.GenericServerRunOptions.TargetRAMMB / 60
s.GenericServerRunOptions.StorageConfig.DeserializationCacheSize = 25 * clusterSize
if s.GenericServerRunOptions.StorageConfig.DeserializationCacheSize < 1000 {
s.GenericServerRunOptions.StorageConfig.DeserializationCacheSize = 1000
s.Etcd.StorageConfig.DeserializationCacheSize = 25 * clusterSize
if s.Etcd.StorageConfig.DeserializationCacheSize < 1000 {
s.Etcd.StorageConfig.DeserializationCacheSize = 1000
}
}
@@ -169,7 +176,7 @@ func Run(s *options.ServerRunOptions) error {
glog.Fatalf("error generating storage version map: %s", err)
}
storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
s.GenericServerRunOptions.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs,
s.Etcd.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs,
genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion,
// FIXME: this GroupVersionResource override should be configurable
[]schema.GroupVersionResource{batch.Resource("cronjobs").WithVersion("v2alpha1")},
@@ -179,7 +186,7 @@ func Run(s *options.ServerRunOptions) error {
}
storageFactory.AddCohabitatingResources(batch.Resource("jobs"), extensions.Resource("jobs"))
storageFactory.AddCohabitatingResources(autoscaling.Resource("horizontalpodautoscalers"), extensions.Resource("horizontalpodautoscalers"))
for _, override := range s.GenericServerRunOptions.EtcdServersOverrides {
for _, override := range s.Etcd.EtcdServersOverrides {
tokens := strings.Split(override, "#")
if len(tokens) != 2 {
glog.Errorf("invalid value of etcd server overrides: %s", override)
@@ -200,96 +207,49 @@ func Run(s *options.ServerRunOptions) error {
}
// Default to the private server key for service account token signing
if len(s.ServiceAccountKeyFiles) == 0 && s.GenericServerRunOptions.TLSPrivateKeyFile != "" {
if authenticator.IsValidServiceAccountKeyFile(s.GenericServerRunOptions.TLSPrivateKeyFile) {
s.ServiceAccountKeyFiles = []string{s.GenericServerRunOptions.TLSPrivateKeyFile}
if len(s.Authentication.ServiceAccounts.KeyFiles) == 0 && s.SecureServing.ServerCert.CertKey.KeyFile != "" {
if authenticator.IsValidServiceAccountKeyFile(s.SecureServing.ServerCert.CertKey.KeyFile) {
s.Authentication.ServiceAccounts.KeyFiles = []string{s.SecureServing.ServerCert.CertKey.KeyFile}
} else {
glog.Warning("No TLS key provided, service account token authentication disabled")
}
}
var serviceAccountGetter serviceaccount.ServiceAccountTokenGetter
if s.ServiceAccountLookup {
authenticatorConfig := s.Authentication.ToAuthenticationConfig(s.SecureServing.ClientCA)
if s.Authentication.ServiceAccounts.Lookup {
// If we need to look up service accounts and tokens,
// go directly to etcd to avoid recursive auth insanity
storageConfig, err := storageFactory.NewConfig(api.Resource("serviceaccounts"))
if err != nil {
glog.Fatalf("Unable to get serviceaccounts storage: %v", err)
}
serviceAccountGetter = serviceaccountcontroller.NewGetterFromStorageInterface(storageConfig, storageFactory.ResourcePrefix(api.Resource("serviceaccounts")), storageFactory.ResourcePrefix(api.Resource("secrets")))
authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromStorageInterface(storageConfig, storageFactory.ResourcePrefix(api.Resource("serviceaccounts")), storageFactory.ResourcePrefix(api.Resource("secrets")))
}
apiAuthenticator, securityDefinitions, err := authenticator.New(authenticator.AuthenticatorConfig{
Anonymous: s.GenericServerRunOptions.AnonymousAuth,
AnyToken: s.GenericServerRunOptions.EnableAnyToken,
BasicAuthFile: s.GenericServerRunOptions.BasicAuthFile,
ClientCAFile: s.GenericServerRunOptions.ClientCAFile,
TokenAuthFile: s.GenericServerRunOptions.TokenAuthFile,
OIDCIssuerURL: s.GenericServerRunOptions.OIDCIssuerURL,
OIDCClientID: s.GenericServerRunOptions.OIDCClientID,
OIDCCAFile: s.GenericServerRunOptions.OIDCCAFile,
OIDCUsernameClaim: s.GenericServerRunOptions.OIDCUsernameClaim,
OIDCGroupsClaim: s.GenericServerRunOptions.OIDCGroupsClaim,
ServiceAccountKeyFiles: s.ServiceAccountKeyFiles,
ServiceAccountLookup: s.ServiceAccountLookup,
ServiceAccountTokenGetter: serviceAccountGetter,
KeystoneURL: s.GenericServerRunOptions.KeystoneURL,
KeystoneCAFile: s.GenericServerRunOptions.KeystoneCAFile,
WebhookTokenAuthnConfigFile: s.WebhookTokenAuthnConfigFile,
WebhookTokenAuthnCacheTTL: s.WebhookTokenAuthnCacheTTL,
RequestHeaderConfig: s.GenericServerRunOptions.AuthenticationRequestHeaderConfig(),
})
apiAuthenticator, securityDefinitions, err := authenticator.New(authenticatorConfig)
if err != nil {
glog.Fatalf("Invalid Authentication Config: %v", err)
}
privilegedLoopbackToken := uuid.NewRandom().String()
selfClientConfig, err := s.GenericServerRunOptions.NewSelfClientConfig(privilegedLoopbackToken)
selfClientConfig, err := genericoptions.NewSelfClientConfig(s.SecureServing, s.InsecureServing, privilegedLoopbackToken)
if err != nil {
glog.Fatalf("Failed to create clientset: %v", err)
}
client, err := s.GenericServerRunOptions.NewSelfClient(privilegedLoopbackToken)
client, err := internalclientset.NewForConfig(selfClientConfig)
if err != nil {
glog.Errorf("Failed to create clientset: %v", err)
}
sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute)
authorizationConfig := authorizer.AuthorizationConfig{
PolicyFile: s.GenericServerRunOptions.AuthorizationPolicyFile,
WebhookConfigFile: s.GenericServerRunOptions.AuthorizationWebhookConfigFile,
WebhookCacheAuthorizedTTL: s.GenericServerRunOptions.AuthorizationWebhookCacheAuthorizedTTL,
WebhookCacheUnauthorizedTTL: s.GenericServerRunOptions.AuthorizationWebhookCacheUnauthorizedTTL,
RBACSuperUser: s.GenericServerRunOptions.AuthorizationRBACSuperUser,
InformerFactory: sharedInformers,
}
authorizationModeNames := strings.Split(s.GenericServerRunOptions.AuthorizationMode, ",")
apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, authorizationConfig)
authorizationConfig := s.Authorization.ToAuthorizationConfig(sharedInformers)
apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationConfig)
if err != nil {
glog.Fatalf("Invalid Authorization Config: %v", err)
}
admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",")
// TODO(dims): We probably need to add an option "EnableLoopbackToken"
if apiAuthenticator != nil {
var uid = uuid.NewRandom().String()
tokens := make(map[string]*user.DefaultInfo)
tokens[privilegedLoopbackToken] = &user.DefaultInfo{
Name: user.APIServerUser,
UID: uid,
Groups: []string{user.SystemPrivilegedGroup},
}
tokenAuthenticator := authenticator.NewAuthenticatorFromTokens(tokens)
apiAuthenticator = authenticatorunion.New(tokenAuthenticator, apiAuthenticator)
tokenAuthorizer := authorizer.NewPrivilegedGroups(user.SystemPrivilegedGroup)
apiAuthorizer = authorizerunion.New(tokenAuthorizer, apiAuthorizer)
}
pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer)
admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer)
if err != nil {
glog.Fatalf("Failed to initialize plugins: %v", err)
@@ -314,7 +274,7 @@ func Run(s *options.ServerRunOptions) error {
genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions
config := &master.Config{
GenericConfig: genericConfig.Config,
GenericConfig: genericConfig,
StorageFactory: storageFactory,
EnableWatchCache: s.GenericServerRunOptions.EnableWatchCache,

View File

@@ -26,10 +26,9 @@ go_library(
"//pkg/api/v1:go_default_library",
"//pkg/apis/componentconfig:go_default_library",
"//pkg/apis/componentconfig/v1alpha1:go_default_library",
"//pkg/apiserver/authenticator:go_default_library",
"//pkg/auth/authenticator:go_default_library",
"//pkg/auth/authenticator/bearertoken:go_default_library",
"//pkg/auth/authorizer:go_default_library",
"//pkg/auth/group:go_default_library",
"//pkg/capabilities:go_default_library",
"//pkg/client/chaosclient:go_default_library",
"//pkg/client/clientset_generated/release_1_5:go_default_library",
@@ -99,11 +98,6 @@ go_library(
"//pkg/volume/rbd:go_default_library",
"//pkg/volume/secret:go_default_library",
"//pkg/volume/vsphere_volume:go_default_library",
"//plugin/pkg/auth/authenticator/request/anonymous:go_default_library",
"//plugin/pkg/auth/authenticator/request/union:go_default_library",
"//plugin/pkg/auth/authenticator/request/x509:go_default_library",
"//plugin/pkg/auth/authenticator/token/webhook:go_default_library",
"//plugin/pkg/auth/authorizer/webhook:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:github.com/spf13/cobra",
"//vendor:github.com/spf13/pflag",

View File

@@ -22,22 +22,16 @@ import (
"reflect"
"k8s.io/kubernetes/pkg/apis/componentconfig"
apiserverauthenticator "k8s.io/kubernetes/pkg/apiserver/authenticator"
"k8s.io/kubernetes/pkg/auth/authenticator"
"k8s.io/kubernetes/pkg/auth/authenticator/bearertoken"
"k8s.io/kubernetes/pkg/auth/authorizer"
"k8s.io/kubernetes/pkg/auth/group"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
authenticationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1"
authorizationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authorization/v1beta1"
alwaysallowauthorizer "k8s.io/kubernetes/pkg/genericapiserver/authorizer"
apiserverauthorizer "k8s.io/kubernetes/pkg/genericapiserver/authorizer"
"k8s.io/kubernetes/pkg/kubelet/server"
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/cert"
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/anonymous"
unionauth "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union"
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/x509"
webhooktoken "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/webhook"
webhooksar "k8s.io/kubernetes/plugin/pkg/auth/authorizer/webhook"
)
func buildAuth(nodeName types.NodeName, client clientset.Interface, config componentconfig.KubeletConfiguration) (server.AuthInterface, error) {
@@ -67,43 +61,21 @@ func buildAuth(nodeName types.NodeName, client clientset.Interface, config compo
}
func buildAuthn(client authenticationclient.TokenReviewInterface, authn componentconfig.KubeletAuthentication) (authenticator.Request, error) {
authenticators := []authenticator.Request{}
// x509 client cert auth
if len(authn.X509.ClientCAFile) > 0 {
clientCAs, err := cert.NewPool(authn.X509.ClientCAFile)
if err != nil {
return nil, fmt.Errorf("unable to load client CA file %s: %v", authn.X509.ClientCAFile, err)
}
verifyOpts := x509.DefaultVerifyOptions()
verifyOpts.Roots = clientCAs
authenticators = append(authenticators, x509.New(verifyOpts, x509.CommonNameUserConversion))
authenticatorConfig := apiserverauthenticator.DelegatingAuthenticatorConfig{
Anonymous: authn.Anonymous.Enabled,
CacheTTL: authn.Webhook.CacheTTL.Duration,
ClientCAFile: authn.X509.ClientCAFile,
}
// bearer token auth that uses authentication.k8s.io TokenReview to determine userinfo
if authn.Webhook.Enabled {
if client == nil {
return nil, errors.New("no client provided, cannot use webhook authentication")
}
tokenAuth, err := webhooktoken.NewFromInterface(client, authn.Webhook.CacheTTL.Duration)
if err != nil {
return nil, err
}
authenticators = append(authenticators, bearertoken.New(tokenAuth))
authenticatorConfig.TokenAccessReviewClient = client
}
if len(authenticators) == 0 {
if authn.Anonymous.Enabled {
return anonymous.NewAuthenticator(), nil
}
return nil, errors.New("No authentication method configured")
}
authenticator := group.NewGroupAdder(unionauth.New(authenticators...), []string{"system:authenticated"})
if authn.Anonymous.Enabled {
authenticator = unionauth.NewFailOnError(authenticator, anonymous.NewAuthenticator())
}
return authenticator, nil
authenticator, _, err := authenticatorConfig.New()
return authenticator, err
}
func buildAuthz(client authorizationclient.SubjectAccessReviewInterface, authz componentconfig.KubeletAuthorization) (authorizer.Authorizer, error) {
@@ -115,11 +87,12 @@ func buildAuthz(client authorizationclient.SubjectAccessReviewInterface, authz c
if client == nil {
return nil, errors.New("no client provided, cannot use webhook authorization")
}
return webhooksar.NewFromInterface(
client,
authz.Webhook.CacheAuthorizedTTL.Duration,
authz.Webhook.CacheUnauthorizedTTL.Duration,
)
authorizerConfig := apiserverauthorizer.DelegatingAuthorizerConfig{
SubjectAccessReviewClient: client,
AllowCacheTTL: authz.Webhook.CacheAuthorizedTTL.Duration,
DenyCacheTTL: authz.Webhook.CacheUnauthorizedTTL.Duration,
}
return authorizerConfig.New()
case "":
return nil, fmt.Errorf("No authorization mode specified")