mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
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:
commit
b0fd700f61
@ -26,9 +26,8 @@ go_library(
|
|||||||
"//pkg/apis/extensions:go_default_library",
|
"//pkg/apis/extensions:go_default_library",
|
||||||
"//pkg/apiserver:go_default_library",
|
"//pkg/apiserver:go_default_library",
|
||||||
"//pkg/apiserver/authenticator: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/capabilities:go_default_library",
|
||||||
|
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||||
"//pkg/cloudprovider:go_default_library",
|
"//pkg/cloudprovider:go_default_library",
|
||||||
"//pkg/cloudprovider/providers:go_default_library",
|
"//pkg/cloudprovider/providers:go_default_library",
|
||||||
"//pkg/controller/informers:go_default_library",
|
"//pkg/controller/informers:go_default_library",
|
||||||
@ -36,11 +35,11 @@ go_library(
|
|||||||
"//pkg/generated/openapi:go_default_library",
|
"//pkg/generated/openapi:go_default_library",
|
||||||
"//pkg/genericapiserver:go_default_library",
|
"//pkg/genericapiserver:go_default_library",
|
||||||
"//pkg/genericapiserver/authorizer: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/master:go_default_library",
|
||||||
"//pkg/registry/cachesize:go_default_library",
|
"//pkg/registry/cachesize:go_default_library",
|
||||||
"//pkg/runtime/schema: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/net:go_default_library",
|
||||||
"//pkg/util/wait:go_default_library",
|
"//pkg/util/wait:go_default_library",
|
||||||
"//pkg/version: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/securitycontext/scdeny:go_default_library",
|
||||||
"//plugin/pkg/admission/serviceaccount:go_default_library",
|
"//plugin/pkg/admission/serviceaccount:go_default_library",
|
||||||
"//plugin/pkg/admission/storageclass/default: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/golang/glog",
|
||||||
"//vendor:github.com/pborman/uuid",
|
"//vendor:github.com/pborman/uuid",
|
||||||
"//vendor:github.com/spf13/cobra",
|
"//vendor:github.com/spf13/cobra",
|
||||||
|
@ -31,24 +31,32 @@ import (
|
|||||||
|
|
||||||
// ServerRunOptions runs a kubernetes api server.
|
// ServerRunOptions runs a kubernetes api server.
|
||||||
type ServerRunOptions struct {
|
type ServerRunOptions struct {
|
||||||
GenericServerRunOptions *genericoptions.ServerRunOptions
|
GenericServerRunOptions *genericoptions.ServerRunOptions
|
||||||
AllowPrivileged bool
|
Etcd *genericoptions.EtcdOptions
|
||||||
EventTTL time.Duration
|
SecureServing *genericoptions.SecureServingOptions
|
||||||
KubeletConfig kubeletclient.KubeletClientConfig
|
InsecureServing *genericoptions.ServingOptions
|
||||||
MaxConnectionBytesPerSec int64
|
Authentication *genericoptions.BuiltInAuthenticationOptions
|
||||||
SSHKeyfile string
|
Authorization *genericoptions.BuiltInAuthorizationOptions
|
||||||
SSHUser string
|
|
||||||
ServiceAccountKeyFiles []string
|
AllowPrivileged bool
|
||||||
ServiceAccountLookup bool
|
EventTTL time.Duration
|
||||||
WebhookTokenAuthnConfigFile string
|
KubeletConfig kubeletclient.KubeletClientConfig
|
||||||
WebhookTokenAuthnCacheTTL time.Duration
|
MaxConnectionBytesPerSec int64
|
||||||
|
SSHKeyfile string
|
||||||
|
SSHUser string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServerRunOptions creates a new ServerRunOptions object with default parameters
|
// NewServerRunOptions creates a new ServerRunOptions object with default parameters
|
||||||
func NewServerRunOptions() *ServerRunOptions {
|
func NewServerRunOptions() *ServerRunOptions {
|
||||||
s := ServerRunOptions{
|
s := ServerRunOptions{
|
||||||
GenericServerRunOptions: genericoptions.NewServerRunOptions().WithEtcdOptions(),
|
GenericServerRunOptions: genericoptions.NewServerRunOptions(),
|
||||||
EventTTL: 1 * time.Hour,
|
Etcd: genericoptions.NewEtcdOptions(),
|
||||||
|
SecureServing: genericoptions.NewSecureServingOptions(),
|
||||||
|
InsecureServing: genericoptions.NewInsecureServingOptions(),
|
||||||
|
Authentication: genericoptions.NewBuiltInAuthenticationOptions().WithAll(),
|
||||||
|
Authorization: genericoptions.NewBuiltInAuthorizationOptions(),
|
||||||
|
|
||||||
|
EventTTL: 1 * time.Hour,
|
||||||
KubeletConfig: kubeletclient.KubeletClientConfig{
|
KubeletConfig: kubeletclient.KubeletClientConfig{
|
||||||
Port: ports.KubeletPort,
|
Port: ports.KubeletPort,
|
||||||
PreferredAddressTypes: []string{
|
PreferredAddressTypes: []string{
|
||||||
@ -60,7 +68,6 @@ func NewServerRunOptions() *ServerRunOptions {
|
|||||||
EnableHttps: true,
|
EnableHttps: true,
|
||||||
HTTPTimeout: time.Duration(5) * time.Second,
|
HTTPTimeout: time.Duration(5) * time.Second,
|
||||||
},
|
},
|
||||||
WebhookTokenAuthnCacheTTL: 2 * time.Minute,
|
|
||||||
}
|
}
|
||||||
return &s
|
return &s
|
||||||
}
|
}
|
||||||
@ -69,29 +76,21 @@ func NewServerRunOptions() *ServerRunOptions {
|
|||||||
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
|
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
|
||||||
// Add the generic flags.
|
// Add the generic flags.
|
||||||
s.GenericServerRunOptions.AddUniversalFlags(fs)
|
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
|
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
|
||||||
// arrange these text blocks sensibly. Grrr.
|
// arrange these text blocks sensibly. Grrr.
|
||||||
|
|
||||||
fs.DurationVar(&s.EventTTL, "event-ttl", s.EventTTL,
|
fs.DurationVar(&s.EventTTL, "event-ttl", s.EventTTL,
|
||||||
"Amount of time to retain events. Default is 1h.")
|
"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,
|
fs.BoolVar(&s.AllowPrivileged, "allow-privileged", s.AllowPrivileged,
|
||||||
"If true, allow privileged containers.")
|
"If true, allow privileged containers.")
|
||||||
|
|
||||||
|
@ -41,24 +41,22 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
"k8s.io/kubernetes/pkg/apiserver/authenticator"
|
"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/capabilities"
|
||||||
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
"k8s.io/kubernetes/pkg/controller/informers"
|
"k8s.io/kubernetes/pkg/controller/informers"
|
||||||
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
|
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
|
||||||
generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi"
|
generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
|
"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/master"
|
||||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
"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"
|
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||||
"k8s.io/kubernetes/pkg/util/wait"
|
"k8s.io/kubernetes/pkg/util/wait"
|
||||||
"k8s.io/kubernetes/pkg/version"
|
"k8s.io/kubernetes/pkg/version"
|
||||||
authenticatorunion "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewAPIServerCommand creates a *cobra.Command object with default parameters
|
// 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.
|
// Run runs the specified APIServer. This should never exit.
|
||||||
func Run(s *options.ServerRunOptions) error {
|
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)
|
genericapiserver.DefaultAndValidateRunOptions(s.GenericServerRunOptions)
|
||||||
genericConfig := genericapiserver.NewConfig(). // create the new config
|
genericConfig := genericapiserver.NewConfig(). // create the new config
|
||||||
ApplyOptions(s.GenericServerRunOptions). // apply the options selected
|
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)
|
serviceIPRange, apiServerServiceIP, err := genericapiserver.DefaultServiceIPRange(s.GenericServerRunOptions.ServiceClusterIPRange)
|
||||||
if err != nil {
|
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
|
// Proxying to pods and services is IP-based... don't expect to be able to verify the hostname
|
||||||
proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true}
|
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
|
// When size of cache is not explicitly set, estimate its size based on
|
||||||
// target memory usage.
|
// target memory usage.
|
||||||
glog.V(2).Infof("Initalizing deserialization cache size based on %dMB limit", s.GenericServerRunOptions.TargetRAMMB)
|
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
|
// size to compute its size. We may even go further and measure
|
||||||
// collective sizes of the objects in the cache.
|
// collective sizes of the objects in the cache.
|
||||||
clusterSize := s.GenericServerRunOptions.TargetRAMMB / 60
|
clusterSize := s.GenericServerRunOptions.TargetRAMMB / 60
|
||||||
s.GenericServerRunOptions.StorageConfig.DeserializationCacheSize = 25 * clusterSize
|
s.Etcd.StorageConfig.DeserializationCacheSize = 25 * clusterSize
|
||||||
if s.GenericServerRunOptions.StorageConfig.DeserializationCacheSize < 1000 {
|
if s.Etcd.StorageConfig.DeserializationCacheSize < 1000 {
|
||||||
s.GenericServerRunOptions.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)
|
glog.Fatalf("error generating storage version map: %s", err)
|
||||||
}
|
}
|
||||||
storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
|
storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
|
||||||
s.GenericServerRunOptions.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs,
|
s.Etcd.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs,
|
||||||
genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion,
|
genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion,
|
||||||
// FIXME: this GroupVersionResource override should be configurable
|
// FIXME: this GroupVersionResource override should be configurable
|
||||||
[]schema.GroupVersionResource{batch.Resource("cronjobs").WithVersion("v2alpha1")},
|
[]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(batch.Resource("jobs"), extensions.Resource("jobs"))
|
||||||
storageFactory.AddCohabitatingResources(autoscaling.Resource("horizontalpodautoscalers"), extensions.Resource("horizontalpodautoscalers"))
|
storageFactory.AddCohabitatingResources(autoscaling.Resource("horizontalpodautoscalers"), extensions.Resource("horizontalpodautoscalers"))
|
||||||
for _, override := range s.GenericServerRunOptions.EtcdServersOverrides {
|
for _, override := range s.Etcd.EtcdServersOverrides {
|
||||||
tokens := strings.Split(override, "#")
|
tokens := strings.Split(override, "#")
|
||||||
if len(tokens) != 2 {
|
if len(tokens) != 2 {
|
||||||
glog.Errorf("invalid value of etcd server overrides: %s", override)
|
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
|
// Default to the private server key for service account token signing
|
||||||
if len(s.ServiceAccountKeyFiles) == 0 && s.GenericServerRunOptions.TLSPrivateKeyFile != "" {
|
if len(s.Authentication.ServiceAccounts.KeyFiles) == 0 && s.SecureServing.ServerCert.CertKey.KeyFile != "" {
|
||||||
if authenticator.IsValidServiceAccountKeyFile(s.GenericServerRunOptions.TLSPrivateKeyFile) {
|
if authenticator.IsValidServiceAccountKeyFile(s.SecureServing.ServerCert.CertKey.KeyFile) {
|
||||||
s.ServiceAccountKeyFiles = []string{s.GenericServerRunOptions.TLSPrivateKeyFile}
|
s.Authentication.ServiceAccounts.KeyFiles = []string{s.SecureServing.ServerCert.CertKey.KeyFile}
|
||||||
} else {
|
} else {
|
||||||
glog.Warning("No TLS key provided, service account token authentication disabled")
|
glog.Warning("No TLS key provided, service account token authentication disabled")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var serviceAccountGetter serviceaccount.ServiceAccountTokenGetter
|
authenticatorConfig := s.Authentication.ToAuthenticationConfig(s.SecureServing.ClientCA)
|
||||||
if s.ServiceAccountLookup {
|
if s.Authentication.ServiceAccounts.Lookup {
|
||||||
// If we need to look up service accounts and tokens,
|
// If we need to look up service accounts and tokens,
|
||||||
// go directly to etcd to avoid recursive auth insanity
|
// go directly to etcd to avoid recursive auth insanity
|
||||||
storageConfig, err := storageFactory.NewConfig(api.Resource("serviceaccounts"))
|
storageConfig, err := storageFactory.NewConfig(api.Resource("serviceaccounts"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Unable to get serviceaccounts storage: %v", err)
|
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{
|
apiAuthenticator, securityDefinitions, err := authenticator.New(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(),
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Invalid Authentication Config: %v", err)
|
glog.Fatalf("Invalid Authentication Config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
privilegedLoopbackToken := uuid.NewRandom().String()
|
privilegedLoopbackToken := uuid.NewRandom().String()
|
||||||
selfClientConfig, err := s.GenericServerRunOptions.NewSelfClientConfig(privilegedLoopbackToken)
|
selfClientConfig, err := genericoptions.NewSelfClientConfig(s.SecureServing, s.InsecureServing, privilegedLoopbackToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to create clientset: %v", err)
|
glog.Fatalf("Failed to create clientset: %v", err)
|
||||||
}
|
}
|
||||||
client, err := s.GenericServerRunOptions.NewSelfClient(privilegedLoopbackToken)
|
client, err := internalclientset.NewForConfig(selfClientConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to create clientset: %v", err)
|
glog.Errorf("Failed to create clientset: %v", err)
|
||||||
}
|
}
|
||||||
sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute)
|
sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute)
|
||||||
|
|
||||||
authorizationConfig := authorizer.AuthorizationConfig{
|
authorizationConfig := s.Authorization.ToAuthorizationConfig(sharedInformers)
|
||||||
PolicyFile: s.GenericServerRunOptions.AuthorizationPolicyFile,
|
apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationConfig)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Invalid Authorization Config: %v", err)
|
glog.Fatalf("Invalid Authorization Config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",")
|
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)
|
pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer)
|
||||||
|
|
||||||
admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer)
|
admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to initialize plugins: %v", err)
|
glog.Fatalf("Failed to initialize plugins: %v", err)
|
||||||
@ -314,7 +274,7 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions
|
genericConfig.OpenAPIConfig.SecurityDefinitions = securityDefinitions
|
||||||
|
|
||||||
config := &master.Config{
|
config := &master.Config{
|
||||||
GenericConfig: genericConfig.Config,
|
GenericConfig: genericConfig,
|
||||||
|
|
||||||
StorageFactory: storageFactory,
|
StorageFactory: storageFactory,
|
||||||
EnableWatchCache: s.GenericServerRunOptions.EnableWatchCache,
|
EnableWatchCache: s.GenericServerRunOptions.EnableWatchCache,
|
||||||
|
@ -26,10 +26,9 @@ go_library(
|
|||||||
"//pkg/api/v1:go_default_library",
|
"//pkg/api/v1:go_default_library",
|
||||||
"//pkg/apis/componentconfig:go_default_library",
|
"//pkg/apis/componentconfig:go_default_library",
|
||||||
"//pkg/apis/componentconfig/v1alpha1: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:go_default_library",
|
||||||
"//pkg/auth/authenticator/bearertoken:go_default_library",
|
|
||||||
"//pkg/auth/authorizer:go_default_library",
|
"//pkg/auth/authorizer:go_default_library",
|
||||||
"//pkg/auth/group:go_default_library",
|
|
||||||
"//pkg/capabilities:go_default_library",
|
"//pkg/capabilities:go_default_library",
|
||||||
"//pkg/client/chaosclient:go_default_library",
|
"//pkg/client/chaosclient:go_default_library",
|
||||||
"//pkg/client/clientset_generated/release_1_5: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/rbd:go_default_library",
|
||||||
"//pkg/volume/secret:go_default_library",
|
"//pkg/volume/secret:go_default_library",
|
||||||
"//pkg/volume/vsphere_volume: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/golang/glog",
|
||||||
"//vendor:github.com/spf13/cobra",
|
"//vendor:github.com/spf13/cobra",
|
||||||
"//vendor:github.com/spf13/pflag",
|
"//vendor:github.com/spf13/pflag",
|
||||||
|
@ -22,22 +22,16 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
"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"
|
||||||
"k8s.io/kubernetes/pkg/auth/authenticator/bearertoken"
|
|
||||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||||
"k8s.io/kubernetes/pkg/auth/group"
|
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
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"
|
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"
|
authorizationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authorization/v1beta1"
|
||||||
alwaysallowauthorizer "k8s.io/kubernetes/pkg/genericapiserver/authorizer"
|
alwaysallowauthorizer "k8s.io/kubernetes/pkg/genericapiserver/authorizer"
|
||||||
|
apiserverauthorizer "k8s.io/kubernetes/pkg/genericapiserver/authorizer"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/server"
|
"k8s.io/kubernetes/pkg/kubelet/server"
|
||||||
"k8s.io/kubernetes/pkg/types"
|
"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) {
|
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) {
|
func buildAuthn(client authenticationclient.TokenReviewInterface, authn componentconfig.KubeletAuthentication) (authenticator.Request, error) {
|
||||||
authenticators := []authenticator.Request{}
|
authenticatorConfig := apiserverauthenticator.DelegatingAuthenticatorConfig{
|
||||||
|
Anonymous: authn.Anonymous.Enabled,
|
||||||
// x509 client cert auth
|
CacheTTL: authn.Webhook.CacheTTL.Duration,
|
||||||
if len(authn.X509.ClientCAFile) > 0 {
|
ClientCAFile: authn.X509.ClientCAFile,
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// bearer token auth that uses authentication.k8s.io TokenReview to determine userinfo
|
|
||||||
if authn.Webhook.Enabled {
|
if authn.Webhook.Enabled {
|
||||||
if client == nil {
|
if client == nil {
|
||||||
return nil, errors.New("no client provided, cannot use webhook authentication")
|
return nil, errors.New("no client provided, cannot use webhook authentication")
|
||||||
}
|
}
|
||||||
tokenAuth, err := webhooktoken.NewFromInterface(client, authn.Webhook.CacheTTL.Duration)
|
authenticatorConfig.TokenAccessReviewClient = client
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
authenticators = append(authenticators, bearertoken.New(tokenAuth))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(authenticators) == 0 {
|
authenticator, _, err := authenticatorConfig.New()
|
||||||
if authn.Anonymous.Enabled {
|
return authenticator, err
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildAuthz(client authorizationclient.SubjectAccessReviewInterface, authz componentconfig.KubeletAuthorization) (authorizer.Authorizer, error) {
|
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 {
|
if client == nil {
|
||||||
return nil, errors.New("no client provided, cannot use webhook authorization")
|
return nil, errors.New("no client provided, cannot use webhook authorization")
|
||||||
}
|
}
|
||||||
return webhooksar.NewFromInterface(
|
authorizerConfig := apiserverauthorizer.DelegatingAuthorizerConfig{
|
||||||
client,
|
SubjectAccessReviewClient: client,
|
||||||
authz.Webhook.CacheAuthorizedTTL.Duration,
|
AllowCacheTTL: authz.Webhook.CacheAuthorizedTTL.Duration,
|
||||||
authz.Webhook.CacheUnauthorizedTTL.Duration,
|
DenyCacheTTL: authz.Webhook.CacheUnauthorizedTTL.Duration,
|
||||||
)
|
}
|
||||||
|
return authorizerConfig.New()
|
||||||
|
|
||||||
case "":
|
case "":
|
||||||
return nil, fmt.Errorf("No authorization mode specified")
|
return nil, fmt.Errorf("No authorization mode specified")
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/registry/generic"
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||||
"k8s.io/kubernetes/pkg/storage/storagebackend"
|
"k8s.io/kubernetes/pkg/storage/storagebackend"
|
||||||
|
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||||
|
|
||||||
// Install the testgroup API
|
// Install the testgroup API
|
||||||
_ "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup/install"
|
_ "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup/install"
|
||||||
@ -54,20 +55,51 @@ func newStorageFactory() genericapiserver.StorageFactory {
|
|||||||
return storageFactory
|
return storageFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServerRunOptions() *genericoptions.ServerRunOptions {
|
type ServerRunOptions struct {
|
||||||
serverOptions := genericoptions.NewServerRunOptions().WithEtcdOptions()
|
GenericServerRunOptions *genericoptions.ServerRunOptions
|
||||||
serverOptions.InsecurePort = InsecurePort
|
Etcd *genericoptions.EtcdOptions
|
||||||
return serverOptions
|
SecureServing *genericoptions.SecureServingOptions
|
||||||
|
InsecureServing *genericoptions.ServingOptions
|
||||||
|
Authentication *genericoptions.BuiltInAuthenticationOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func Run(serverOptions *genericoptions.ServerRunOptions, stopCh <-chan struct{}) error {
|
func NewServerRunOptions() *ServerRunOptions {
|
||||||
|
s := ServerRunOptions{
|
||||||
|
GenericServerRunOptions: genericoptions.NewServerRunOptions(),
|
||||||
|
Etcd: genericoptions.NewEtcdOptions(),
|
||||||
|
SecureServing: genericoptions.NewSecureServingOptions(),
|
||||||
|
InsecureServing: genericoptions.NewInsecureServingOptions(),
|
||||||
|
Authentication: genericoptions.NewBuiltInAuthenticationOptions().WithAll(),
|
||||||
|
}
|
||||||
|
s.InsecureServing.BindPort = InsecurePort
|
||||||
|
s.SecureServing.ServingOptions.BindPort = SecurePort
|
||||||
|
|
||||||
|
return &s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (serverOptions *ServerRunOptions) Run(stopCh <-chan struct{}) error {
|
||||||
// Set ServiceClusterIPRange
|
// Set ServiceClusterIPRange
|
||||||
_, serviceClusterIPRange, _ := net.ParseCIDR("10.0.0.0/24")
|
_, serviceClusterIPRange, _ := net.ParseCIDR("10.0.0.0/24")
|
||||||
serverOptions.ServiceClusterIPRange = *serviceClusterIPRange
|
serverOptions.GenericServerRunOptions.ServiceClusterIPRange = *serviceClusterIPRange
|
||||||
serverOptions.StorageConfig.ServerList = []string{"http://127.0.0.1:2379"}
|
serverOptions.Etcd.StorageConfig.ServerList = []string{"http://127.0.0.1:2379"}
|
||||||
genericvalidation.ValidateRunOptions(serverOptions)
|
|
||||||
genericvalidation.VerifyEtcdServersList(serverOptions)
|
genericvalidation.ValidateRunOptions(serverOptions.GenericServerRunOptions)
|
||||||
config := genericapiserver.NewConfig().ApplyOptions(serverOptions).Complete()
|
if errs := serverOptions.Etcd.Validate(); len(errs) > 0 {
|
||||||
|
return utilerrors.NewAggregate(errs)
|
||||||
|
}
|
||||||
|
if errs := serverOptions.SecureServing.Validate(); len(errs) > 0 {
|
||||||
|
return utilerrors.NewAggregate(errs)
|
||||||
|
}
|
||||||
|
if errs := serverOptions.InsecureServing.Validate("insecure-port"); len(errs) > 0 {
|
||||||
|
return utilerrors.NewAggregate(errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := genericapiserver.NewConfig().
|
||||||
|
ApplyOptions(serverOptions.GenericServerRunOptions).
|
||||||
|
ApplySecureServingOptions(serverOptions.SecureServing).
|
||||||
|
ApplyInsecureServingOptions(serverOptions.InsecureServing).
|
||||||
|
ApplyAuthenticationOptions(serverOptions.Authentication).
|
||||||
|
Complete()
|
||||||
if err := config.MaybeGenerateServingCerts(); err != nil {
|
if err := config.MaybeGenerateServingCerts(); err != nil {
|
||||||
// this wasn't treated as fatal for this process before
|
// this wasn't treated as fatal for this process before
|
||||||
fmt.Printf("Error creating cert: %v", err)
|
fmt.Printf("Error creating cert: %v", err)
|
||||||
|
@ -30,10 +30,14 @@ func main() {
|
|||||||
|
|
||||||
// Parse command line flags.
|
// Parse command line flags.
|
||||||
serverRunOptions.AddUniversalFlags(pflag.CommandLine)
|
serverRunOptions.AddUniversalFlags(pflag.CommandLine)
|
||||||
serverRunOptions.AddEtcdStorageFlags(pflag.CommandLine)
|
serverRunOptions.Etcd.AddFlags(pflag.CommandLine)
|
||||||
|
serverRunOptions.SecureServing.AddFlags(pflag.CommandLine)
|
||||||
|
serverRunOptions.SecureServing.AddDeprecatedFlags(pflag.CommandLine)
|
||||||
|
serverRunOptions.InsecureServing.AddFlags(pflag.CommandLine)
|
||||||
|
serverRunOptions.InsecureServing.AddDeprecatedFlags(pflag.CommandLine)
|
||||||
flag.InitFlags()
|
flag.InitFlags()
|
||||||
|
|
||||||
if err := apiserver.Run(serverRunOptions, wait.NeverStop); err != nil {
|
if err := serverRunOptions.Run(wait.NeverStop); err != nil {
|
||||||
glog.Fatalf("Error in bringing up the server: %v", err)
|
glog.Fatalf("Error in bringing up the server: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -36,14 +36,13 @@ go_library(
|
|||||||
"//pkg/apis/extensions:go_default_library",
|
"//pkg/apis/extensions:go_default_library",
|
||||||
"//pkg/apis/extensions/install:go_default_library",
|
"//pkg/apis/extensions/install:go_default_library",
|
||||||
"//pkg/apiserver/authenticator:go_default_library",
|
"//pkg/apiserver/authenticator:go_default_library",
|
||||||
"//pkg/auth/authorizer/union:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||||
"//pkg/auth/user:go_default_library",
|
|
||||||
"//pkg/cloudprovider/providers:go_default_library",
|
"//pkg/cloudprovider/providers:go_default_library",
|
||||||
"//pkg/controller/informers:go_default_library",
|
"//pkg/controller/informers:go_default_library",
|
||||||
"//pkg/generated/openapi:go_default_library",
|
"//pkg/generated/openapi:go_default_library",
|
||||||
"//pkg/genericapiserver:go_default_library",
|
"//pkg/genericapiserver:go_default_library",
|
||||||
"//pkg/genericapiserver/authorizer:go_default_library",
|
"//pkg/genericapiserver/authorizer:go_default_library",
|
||||||
"//pkg/genericapiserver/validation:go_default_library",
|
"//pkg/genericapiserver/options:go_default_library",
|
||||||
"//pkg/registry/cachesize:go_default_library",
|
"//pkg/registry/cachesize:go_default_library",
|
||||||
"//pkg/registry/core/configmap/etcd:go_default_library",
|
"//pkg/registry/core/configmap/etcd:go_default_library",
|
||||||
"//pkg/registry/core/event/etcd:go_default_library",
|
"//pkg/registry/core/event/etcd:go_default_library",
|
||||||
@ -58,13 +57,13 @@ go_library(
|
|||||||
"//pkg/registry/generic/registry:go_default_library",
|
"//pkg/registry/generic/registry:go_default_library",
|
||||||
"//pkg/routes:go_default_library",
|
"//pkg/routes:go_default_library",
|
||||||
"//pkg/runtime/schema:go_default_library",
|
"//pkg/runtime/schema:go_default_library",
|
||||||
|
"//pkg/util/errors:go_default_library",
|
||||||
"//pkg/util/wait:go_default_library",
|
"//pkg/util/wait:go_default_library",
|
||||||
"//pkg/version:go_default_library",
|
"//pkg/version:go_default_library",
|
||||||
"//plugin/pkg/admission/admit:go_default_library",
|
"//plugin/pkg/admission/admit:go_default_library",
|
||||||
"//plugin/pkg/admission/deny:go_default_library",
|
"//plugin/pkg/admission/deny:go_default_library",
|
||||||
"//plugin/pkg/admission/gc:go_default_library",
|
"//plugin/pkg/admission/gc:go_default_library",
|
||||||
"//plugin/pkg/admission/namespace/lifecycle:go_default_library",
|
"//plugin/pkg/admission/namespace/lifecycle:go_default_library",
|
||||||
"//plugin/pkg/auth/authenticator/request/union:go_default_library",
|
|
||||||
"//vendor:github.com/golang/glog",
|
"//vendor:github.com/golang/glog",
|
||||||
"//vendor:github.com/pborman/uuid",
|
"//vendor:github.com/pborman/uuid",
|
||||||
"//vendor:github.com/spf13/cobra",
|
"//vendor:github.com/spf13/cobra",
|
||||||
|
@ -28,14 +28,26 @@ import (
|
|||||||
// Runtime options for the federation-apiserver.
|
// Runtime options for the federation-apiserver.
|
||||||
type ServerRunOptions struct {
|
type ServerRunOptions struct {
|
||||||
GenericServerRunOptions *genericoptions.ServerRunOptions
|
GenericServerRunOptions *genericoptions.ServerRunOptions
|
||||||
EventTTL time.Duration
|
Etcd *genericoptions.EtcdOptions
|
||||||
|
SecureServing *genericoptions.SecureServingOptions
|
||||||
|
InsecureServing *genericoptions.ServingOptions
|
||||||
|
Authentication *genericoptions.BuiltInAuthenticationOptions
|
||||||
|
Authorization *genericoptions.BuiltInAuthorizationOptions
|
||||||
|
|
||||||
|
EventTTL time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServerRunOptions creates a new ServerRunOptions object with default values.
|
// NewServerRunOptions creates a new ServerRunOptions object with default values.
|
||||||
func NewServerRunOptions() *ServerRunOptions {
|
func NewServerRunOptions() *ServerRunOptions {
|
||||||
s := ServerRunOptions{
|
s := ServerRunOptions{
|
||||||
GenericServerRunOptions: genericoptions.NewServerRunOptions().WithEtcdOptions(),
|
GenericServerRunOptions: genericoptions.NewServerRunOptions(),
|
||||||
EventTTL: 1 * time.Hour,
|
Etcd: genericoptions.NewEtcdOptions(),
|
||||||
|
SecureServing: genericoptions.NewSecureServingOptions(),
|
||||||
|
InsecureServing: genericoptions.NewInsecureServingOptions(),
|
||||||
|
Authentication: genericoptions.NewBuiltInAuthenticationOptions().WithAll(),
|
||||||
|
Authorization: genericoptions.NewBuiltInAuthorizationOptions(),
|
||||||
|
|
||||||
|
EventTTL: 1 * time.Hour,
|
||||||
}
|
}
|
||||||
return &s
|
return &s
|
||||||
}
|
}
|
||||||
@ -44,8 +56,11 @@ func NewServerRunOptions() *ServerRunOptions {
|
|||||||
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
|
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
|
||||||
// Add the generic flags.
|
// Add the generic flags.
|
||||||
s.GenericServerRunOptions.AddUniversalFlags(fs)
|
s.GenericServerRunOptions.AddUniversalFlags(fs)
|
||||||
//Add etcd specific flags.
|
s.Etcd.AddFlags(fs)
|
||||||
s.GenericServerRunOptions.AddEtcdStorageFlags(fs)
|
s.SecureServing.AddFlags(fs)
|
||||||
|
s.InsecureServing.AddFlags(fs)
|
||||||
|
s.Authentication.AddFlags(fs)
|
||||||
|
s.Authorization.AddFlags(fs)
|
||||||
|
|
||||||
fs.DurationVar(&s.EventTTL, "event-ttl", s.EventTTL,
|
fs.DurationVar(&s.EventTTL, "event-ttl", s.EventTTL,
|
||||||
"Amount of time to retain events. Default is 1h.")
|
"Amount of time to retain events. Default is 1h.")
|
||||||
|
@ -32,21 +32,20 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/admission"
|
"k8s.io/kubernetes/pkg/admission"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apiserver/authenticator"
|
"k8s.io/kubernetes/pkg/apiserver/authenticator"
|
||||||
authorizerunion "k8s.io/kubernetes/pkg/auth/authorizer/union"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/auth/user"
|
|
||||||
"k8s.io/kubernetes/pkg/controller/informers"
|
"k8s.io/kubernetes/pkg/controller/informers"
|
||||||
"k8s.io/kubernetes/pkg/generated/openapi"
|
"k8s.io/kubernetes/pkg/generated/openapi"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
|
"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
|
||||||
genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation"
|
genericoptions "k8s.io/kubernetes/pkg/genericapiserver/options"
|
||||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||||
"k8s.io/kubernetes/pkg/registry/generic"
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
"k8s.io/kubernetes/pkg/registry/generic/registry"
|
"k8s.io/kubernetes/pkg/registry/generic/registry"
|
||||||
"k8s.io/kubernetes/pkg/routes"
|
"k8s.io/kubernetes/pkg/routes"
|
||||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||||
|
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||||
"k8s.io/kubernetes/pkg/util/wait"
|
"k8s.io/kubernetes/pkg/util/wait"
|
||||||
"k8s.io/kubernetes/pkg/version"
|
"k8s.io/kubernetes/pkg/version"
|
||||||
authenticatorunion "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewAPIServerCommand creates a *cobra.Command object with default parameters
|
// NewAPIServerCommand creates a *cobra.Command object with default parameters
|
||||||
@ -67,11 +66,20 @@ cluster's shared state through which all other components interact.`,
|
|||||||
|
|
||||||
// Run runs the specified APIServer. This should never exit.
|
// Run runs the specified APIServer. This should never exit.
|
||||||
func Run(s *options.ServerRunOptions) error {
|
func Run(s *options.ServerRunOptions) error {
|
||||||
genericvalidation.VerifyEtcdServersList(s.GenericServerRunOptions)
|
if errs := s.Etcd.Validate(); len(errs) > 0 {
|
||||||
|
utilerrors.NewAggregate(errs)
|
||||||
|
}
|
||||||
|
if err := s.GenericServerRunOptions.DefaultExternalAddress(s.SecureServing, s.InsecureServing); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
genericapiserver.DefaultAndValidateRunOptions(s.GenericServerRunOptions)
|
genericapiserver.DefaultAndValidateRunOptions(s.GenericServerRunOptions)
|
||||||
genericConfig := genericapiserver.NewConfig(). // create the new config
|
genericConfig := genericapiserver.NewConfig(). // create the new config
|
||||||
ApplyOptions(s.GenericServerRunOptions). // apply the options selected
|
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)
|
||||||
|
|
||||||
if err := genericConfig.MaybeGenerateServingCerts(); err != nil {
|
if err := genericConfig.MaybeGenerateServingCerts(); err != nil {
|
||||||
glog.Fatalf("Failed to generate service certificate: %v", err)
|
glog.Fatalf("Failed to generate service certificate: %v", err)
|
||||||
@ -80,23 +88,23 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
// TODO: register cluster federation resources here.
|
// TODO: register cluster federation resources here.
|
||||||
resourceConfig := genericapiserver.NewResourceConfig()
|
resourceConfig := genericapiserver.NewResourceConfig()
|
||||||
|
|
||||||
if s.GenericServerRunOptions.StorageConfig.DeserializationCacheSize == 0 {
|
if s.Etcd.StorageConfig.DeserializationCacheSize == 0 {
|
||||||
// When size of cache is not explicitly set, set it to 50000
|
// When size of cache is not explicitly set, set it to 50000
|
||||||
s.GenericServerRunOptions.StorageConfig.DeserializationCacheSize = 50000
|
s.Etcd.StorageConfig.DeserializationCacheSize = 50000
|
||||||
}
|
}
|
||||||
storageGroupsToEncodingVersion, err := s.GenericServerRunOptions.StorageGroupsToEncodingVersion()
|
storageGroupsToEncodingVersion, err := s.GenericServerRunOptions.StorageGroupsToEncodingVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("error generating storage version map: %s", err)
|
glog.Fatalf("error generating storage version map: %s", err)
|
||||||
}
|
}
|
||||||
storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
|
storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
|
||||||
s.GenericServerRunOptions.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs,
|
s.Etcd.StorageConfig, s.GenericServerRunOptions.DefaultStorageMediaType, api.Codecs,
|
||||||
genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion,
|
genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion,
|
||||||
[]schema.GroupVersionResource{}, resourceConfig, s.GenericServerRunOptions.RuntimeConfig)
|
[]schema.GroupVersionResource{}, resourceConfig, s.GenericServerRunOptions.RuntimeConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("error in initializing storage factory: %s", err)
|
glog.Fatalf("error in initializing storage factory: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, override := range s.GenericServerRunOptions.EtcdServersOverrides {
|
for _, override := range s.Etcd.EtcdServersOverrides {
|
||||||
tokens := strings.Split(override, "#")
|
tokens := strings.Split(override, "#")
|
||||||
if len(tokens) != 2 {
|
if len(tokens) != 2 {
|
||||||
glog.Errorf("invalid value of etcd server overrides: %s", override)
|
glog.Errorf("invalid value of etcd server overrides: %s", override)
|
||||||
@ -116,70 +124,30 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
storageFactory.SetEtcdLocation(groupResource, servers)
|
storageFactory.SetEtcdLocation(groupResource, servers)
|
||||||
}
|
}
|
||||||
|
|
||||||
apiAuthenticator, securityDefinitions, err := authenticator.New(authenticator.AuthenticatorConfig{
|
apiAuthenticator, securityDefinitions, err := authenticator.New(s.Authentication.ToAuthenticationConfig(s.SecureServing.ClientCA))
|
||||||
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,
|
|
||||||
KeystoneURL: s.GenericServerRunOptions.KeystoneURL,
|
|
||||||
RequestHeaderConfig: s.GenericServerRunOptions.AuthenticationRequestHeaderConfig(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Invalid Authentication Config: %v", err)
|
glog.Fatalf("Invalid Authentication Config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
privilegedLoopbackToken := uuid.NewRandom().String()
|
privilegedLoopbackToken := uuid.NewRandom().String()
|
||||||
selfClientConfig, err := s.GenericServerRunOptions.NewSelfClientConfig(privilegedLoopbackToken)
|
selfClientConfig, err := genericoptions.NewSelfClientConfig(s.SecureServing, s.InsecureServing, privilegedLoopbackToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to create clientset: %v", err)
|
glog.Fatalf("Failed to create clientset: %v", err)
|
||||||
}
|
}
|
||||||
client, err := s.GenericServerRunOptions.NewSelfClient(privilegedLoopbackToken)
|
client, err := internalclientset.NewForConfig(selfClientConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to create clientset: %v", err)
|
glog.Errorf("Failed to create clientset: %v", err)
|
||||||
}
|
}
|
||||||
sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute)
|
sharedInformers := informers.NewSharedInformerFactory(nil, client, 10*time.Minute)
|
||||||
|
|
||||||
authorizationConfig := authorizer.AuthorizationConfig{
|
authorizerconfig := s.Authorization.ToAuthorizationConfig(sharedInformers)
|
||||||
PolicyFile: s.GenericServerRunOptions.AuthorizationPolicyFile,
|
apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizerconfig)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Invalid Authorization Config: %v", err)
|
glog.Fatalf("Invalid Authorization Config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
admissionControlPluginNames := strings.Split(s.GenericServerRunOptions.AdmissionControl, ",")
|
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)
|
pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer)
|
||||||
|
|
||||||
admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer)
|
admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.GenericServerRunOptions.AdmissionControlConfigFile, pluginInitializer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to initialize plugins: %v", err)
|
glog.Fatalf("Failed to initialize plugins: %v", err)
|
||||||
@ -202,7 +170,7 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes)
|
cachesize.SetWatchCacheSizes(s.GenericServerRunOptions.WatchCacheSizes)
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := genericConfig.New()
|
m, err := genericConfig.Complete().New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,11 @@ auth-provider
|
|||||||
auth-provider
|
auth-provider
|
||||||
auth-provider-arg
|
auth-provider-arg
|
||||||
auth-provider-arg
|
auth-provider-arg
|
||||||
|
authentication-kubeconfig
|
||||||
authentication-token-webhook
|
authentication-token-webhook
|
||||||
authentication-token-webhook-cache-ttl
|
authentication-token-webhook-cache-ttl
|
||||||
authentication-token-webhook-config-file
|
authentication-token-webhook-config-file
|
||||||
|
authorization-kubeconfig
|
||||||
authorization-mode
|
authorization-mode
|
||||||
authorization-policy-file
|
authorization-policy-file
|
||||||
authorization-rbac-super-user
|
authorization-rbac-super-user
|
||||||
|
@ -12,13 +12,17 @@ load(
|
|||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = ["authn.go"],
|
srcs = [
|
||||||
|
"builtin.go",
|
||||||
|
"delegating.go",
|
||||||
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/auth/authenticator:go_default_library",
|
"//pkg/auth/authenticator:go_default_library",
|
||||||
"//pkg/auth/authenticator/bearertoken:go_default_library",
|
"//pkg/auth/authenticator/bearertoken:go_default_library",
|
||||||
"//pkg/auth/group:go_default_library",
|
"//pkg/auth/group:go_default_library",
|
||||||
"//pkg/auth/user:go_default_library",
|
"//pkg/auth/user:go_default_library",
|
||||||
|
"//pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1:go_default_library",
|
||||||
"//pkg/serviceaccount:go_default_library",
|
"//pkg/serviceaccount:go_default_library",
|
||||||
"//pkg/util/cert:go_default_library",
|
"//pkg/util/cert:go_default_library",
|
||||||
"//plugin/pkg/auth/authenticator/password/keystone:go_default_library",
|
"//plugin/pkg/auth/authenticator/password/keystone:go_default_library",
|
||||||
|
@ -62,13 +62,15 @@ type AuthenticatorConfig struct {
|
|||||||
OIDCGroupsClaim string
|
OIDCGroupsClaim string
|
||||||
ServiceAccountKeyFiles []string
|
ServiceAccountKeyFiles []string
|
||||||
ServiceAccountLookup bool
|
ServiceAccountLookup bool
|
||||||
ServiceAccountTokenGetter serviceaccount.ServiceAccountTokenGetter
|
|
||||||
KeystoneURL string
|
KeystoneURL string
|
||||||
KeystoneCAFile string
|
KeystoneCAFile string
|
||||||
WebhookTokenAuthnConfigFile string
|
WebhookTokenAuthnConfigFile string
|
||||||
WebhookTokenAuthnCacheTTL time.Duration
|
WebhookTokenAuthnCacheTTL time.Duration
|
||||||
|
|
||||||
RequestHeaderConfig *RequestHeaderConfig
|
RequestHeaderConfig *RequestHeaderConfig
|
||||||
|
|
||||||
|
// TODO, this is the only non-serializable part of the entire config. Factor it out into a clientconfig
|
||||||
|
ServiceAccountTokenGetter serviceaccount.ServiceAccountTokenGetter
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns an authenticator.Request or an error that supports the standard
|
// New returns an authenticator.Request or an error that supports the standard
|
97
pkg/apiserver/authenticator/delegating.go
Normal file
97
pkg/apiserver/authenticator/delegating.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-openapi/spec"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/auth/authenticator"
|
||||||
|
"k8s.io/kubernetes/pkg/auth/authenticator/bearertoken"
|
||||||
|
"k8s.io/kubernetes/pkg/auth/group"
|
||||||
|
"k8s.io/kubernetes/pkg/auth/user"
|
||||||
|
authenticationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DelegatingAuthenticatorConfig is the minimal configuration needed to create an authenticator
|
||||||
|
// built to delegate authentication to a kube API server
|
||||||
|
type DelegatingAuthenticatorConfig struct {
|
||||||
|
Anonymous bool
|
||||||
|
|
||||||
|
TokenAccessReviewClient authenticationclient.TokenReviewInterface
|
||||||
|
|
||||||
|
// CacheTTL is the length of time that a token authentication answer will be cached.
|
||||||
|
CacheTTL time.Duration
|
||||||
|
|
||||||
|
// ClientCAFile is the CA bundle file used to authenticate client certificates
|
||||||
|
ClientCAFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c DelegatingAuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDefinitions, error) {
|
||||||
|
authenticators := []authenticator.Request{}
|
||||||
|
securityDefinitions := spec.SecurityDefinitions{}
|
||||||
|
|
||||||
|
// x509 client cert auth
|
||||||
|
if len(c.ClientCAFile) > 0 {
|
||||||
|
clientCAs, err := cert.NewPool(c.ClientCAFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("unable to load client CA file %s: %v", c.ClientCAFile, err)
|
||||||
|
}
|
||||||
|
verifyOpts := x509.DefaultVerifyOptions()
|
||||||
|
verifyOpts.Roots = clientCAs
|
||||||
|
authenticators = append(authenticators, x509.New(verifyOpts, x509.CommonNameUserConversion))
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TokenAccessReviewClient != nil {
|
||||||
|
tokenAuth, err := webhooktoken.NewFromInterface(c.TokenAccessReviewClient, c.CacheTTL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
authenticators = append(authenticators, bearertoken.New(tokenAuth))
|
||||||
|
|
||||||
|
securityDefinitions["BearerToken"] = &spec.SecurityScheme{
|
||||||
|
SecuritySchemeProps: spec.SecuritySchemeProps{
|
||||||
|
Type: "apiKey",
|
||||||
|
Name: "authorization",
|
||||||
|
In: "header",
|
||||||
|
Description: "Bearer Token authentication",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(authenticators) == 0 {
|
||||||
|
if c.Anonymous {
|
||||||
|
return anonymous.NewAuthenticator(), &securityDefinitions, nil
|
||||||
|
}
|
||||||
|
return nil, nil, errors.New("No authentication method configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticator := group.NewGroupAdder(unionauth.New(authenticators...), []string{user.AllAuthenticated})
|
||||||
|
if c.Anonymous {
|
||||||
|
authenticator = unionauth.NewFailOnError(authenticator, anonymous.NewAuthenticator())
|
||||||
|
}
|
||||||
|
return authenticator, &securityDefinitions, nil
|
||||||
|
|
||||||
|
}
|
@ -38,14 +38,18 @@ go_library(
|
|||||||
"//pkg/apimachinery:go_default_library",
|
"//pkg/apimachinery:go_default_library",
|
||||||
"//pkg/apimachinery/registered:go_default_library",
|
"//pkg/apimachinery/registered:go_default_library",
|
||||||
"//pkg/apiserver:go_default_library",
|
"//pkg/apiserver:go_default_library",
|
||||||
|
"//pkg/apiserver/authenticator:go_default_library",
|
||||||
"//pkg/apiserver/filters:go_default_library",
|
"//pkg/apiserver/filters:go_default_library",
|
||||||
"//pkg/apiserver/openapi:go_default_library",
|
"//pkg/apiserver/openapi:go_default_library",
|
||||||
"//pkg/apiserver/request:go_default_library",
|
"//pkg/apiserver/request:go_default_library",
|
||||||
"//pkg/auth/authenticator:go_default_library",
|
"//pkg/auth/authenticator:go_default_library",
|
||||||
"//pkg/auth/authorizer:go_default_library",
|
"//pkg/auth/authorizer:go_default_library",
|
||||||
|
"//pkg/auth/authorizer/union:go_default_library",
|
||||||
"//pkg/auth/handlers:go_default_library",
|
"//pkg/auth/handlers:go_default_library",
|
||||||
|
"//pkg/auth/user:go_default_library",
|
||||||
"//pkg/client/restclient:go_default_library",
|
"//pkg/client/restclient:go_default_library",
|
||||||
"//pkg/cloudprovider:go_default_library",
|
"//pkg/cloudprovider:go_default_library",
|
||||||
|
"//pkg/genericapiserver/authorizer:go_default_library",
|
||||||
"//pkg/genericapiserver/filters:go_default_library",
|
"//pkg/genericapiserver/filters:go_default_library",
|
||||||
"//pkg/genericapiserver/mux:go_default_library",
|
"//pkg/genericapiserver/mux:go_default_library",
|
||||||
"//pkg/genericapiserver/openapi/common:go_default_library",
|
"//pkg/genericapiserver/openapi/common:go_default_library",
|
||||||
@ -70,10 +74,12 @@ go_library(
|
|||||||
"//pkg/util/validation:go_default_library",
|
"//pkg/util/validation:go_default_library",
|
||||||
"//pkg/util/wait:go_default_library",
|
"//pkg/util/wait:go_default_library",
|
||||||
"//pkg/version:go_default_library",
|
"//pkg/version:go_default_library",
|
||||||
|
"//plugin/pkg/auth/authenticator/request/union:go_default_library",
|
||||||
"//vendor:github.com/coreos/go-systemd/daemon",
|
"//vendor:github.com/coreos/go-systemd/daemon",
|
||||||
"//vendor:github.com/emicklei/go-restful",
|
"//vendor:github.com/emicklei/go-restful",
|
||||||
"//vendor:github.com/go-openapi/spec",
|
"//vendor:github.com/go-openapi/spec",
|
||||||
"//vendor:github.com/golang/glog",
|
"//vendor:github.com/golang/glog",
|
||||||
|
"//vendor:github.com/pborman/uuid",
|
||||||
"//vendor:github.com/pkg/errors",
|
"//vendor:github.com/pkg/errors",
|
||||||
"//vendor:github.com/prometheus/client_golang/prometheus",
|
"//vendor:github.com/prometheus/client_golang/prometheus",
|
||||||
"//vendor:gopkg.in/natefinch/lumberjack.v2",
|
"//vendor:gopkg.in/natefinch/lumberjack.v2",
|
||||||
|
@ -12,14 +12,17 @@ load(
|
|||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = ["authz.go"],
|
srcs = [
|
||||||
|
"builtin.go",
|
||||||
|
"delegating.go",
|
||||||
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/auth/authorizer:go_default_library",
|
"//pkg/auth/authorizer:go_default_library",
|
||||||
"//pkg/auth/authorizer/abac:go_default_library",
|
"//pkg/auth/authorizer/abac:go_default_library",
|
||||||
"//pkg/auth/authorizer/union:go_default_library",
|
"//pkg/auth/authorizer/union:go_default_library",
|
||||||
|
"//pkg/client/clientset_generated/release_1_5/typed/authorization/v1beta1:go_default_library",
|
||||||
"//pkg/controller/informers:go_default_library",
|
"//pkg/controller/informers:go_default_library",
|
||||||
"//pkg/genericapiserver/options:go_default_library",
|
|
||||||
"//plugin/pkg/auth/authorizer/rbac:go_default_library",
|
"//plugin/pkg/auth/authorizer/rbac:go_default_library",
|
||||||
"//plugin/pkg/auth/authorizer/webhook:go_default_library",
|
"//plugin/pkg/auth/authorizer/webhook:go_default_library",
|
||||||
],
|
],
|
||||||
@ -36,6 +39,5 @@ go_test(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/auth/authorizer:go_default_library",
|
"//pkg/auth/authorizer:go_default_library",
|
||||||
"//pkg/auth/user:go_default_library",
|
"//pkg/auth/user:go_default_library",
|
||||||
"//pkg/genericapiserver/options:go_default_library",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -19,8 +19,6 @@ package authorizer
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/options"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||||
"k8s.io/kubernetes/pkg/auth/user"
|
"k8s.io/kubernetes/pkg/auth/user"
|
||||||
)
|
)
|
||||||
@ -50,67 +48,71 @@ func TestNewAuthorizerFromAuthorizationConfig(t *testing.T) {
|
|||||||
examplePolicyFile := "../../auth/authorizer/abac/example_policy_file.jsonl"
|
examplePolicyFile := "../../auth/authorizer/abac/example_policy_file.jsonl"
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
modes []string
|
|
||||||
config AuthorizationConfig
|
config AuthorizationConfig
|
||||||
wantErr bool
|
wantErr bool
|
||||||
msg string
|
msg string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
// Unknown modes should return errors
|
// Unknown modes should return errors
|
||||||
modes: []string{"DoesNotExist"},
|
config: AuthorizationConfig{AuthorizationModes: []string{"DoesNotExist"}},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
msg: "using a fake mode should have returned an error",
|
msg: "using a fake mode should have returned an error",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// ModeAlwaysAllow and ModeAlwaysDeny should return without authorizationPolicyFile
|
// ModeAlwaysAllow and ModeAlwaysDeny should return without authorizationPolicyFile
|
||||||
// but error if one is given
|
// but error if one is given
|
||||||
modes: []string{options.ModeAlwaysAllow, options.ModeAlwaysDeny},
|
config: AuthorizationConfig{AuthorizationModes: []string{ModeAlwaysAllow, ModeAlwaysDeny}},
|
||||||
msg: "returned an error for valid config",
|
msg: "returned an error for valid config",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// ModeABAC requires a policy file
|
// ModeABAC requires a policy file
|
||||||
modes: []string{options.ModeAlwaysAllow, options.ModeAlwaysDeny, options.ModeABAC},
|
config: AuthorizationConfig{AuthorizationModes: []string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABAC}},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
msg: "specifying ABAC with no policy file should return an error",
|
msg: "specifying ABAC with no policy file should return an error",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// ModeABAC should not error if a valid policy path is provided
|
// ModeABAC should not error if a valid policy path is provided
|
||||||
modes: []string{options.ModeAlwaysAllow, options.ModeAlwaysDeny, options.ModeABAC},
|
config: AuthorizationConfig{
|
||||||
config: AuthorizationConfig{PolicyFile: examplePolicyFile},
|
AuthorizationModes: []string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABAC},
|
||||||
msg: "errored while using a valid policy file",
|
PolicyFile: examplePolicyFile,
|
||||||
|
},
|
||||||
|
msg: "errored while using a valid policy file",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
||||||
// Authorization Policy file cannot be used without ModeABAC
|
// Authorization Policy file cannot be used without ModeABAC
|
||||||
modes: []string{options.ModeAlwaysAllow, options.ModeAlwaysDeny},
|
config: AuthorizationConfig{
|
||||||
config: AuthorizationConfig{PolicyFile: examplePolicyFile},
|
AuthorizationModes: []string{ModeAlwaysAllow, ModeAlwaysDeny},
|
||||||
|
PolicyFile: examplePolicyFile,
|
||||||
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
msg: "should have errored when Authorization Policy File is used without ModeABAC",
|
msg: "should have errored when Authorization Policy File is used without ModeABAC",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// At least one authorizationMode is necessary
|
// At least one authorizationMode is necessary
|
||||||
modes: []string{},
|
|
||||||
config: AuthorizationConfig{PolicyFile: examplePolicyFile},
|
config: AuthorizationConfig{PolicyFile: examplePolicyFile},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
msg: "should have errored when no authorization modes are passed",
|
msg: "should have errored when no authorization modes are passed",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// ModeWebhook requires at minimum a target.
|
// ModeWebhook requires at minimum a target.
|
||||||
modes: []string{options.ModeWebhook},
|
config: AuthorizationConfig{AuthorizationModes: []string{ModeWebhook}},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
msg: "should have errored when config was empty with ModeWebhook",
|
msg: "should have errored when config was empty with ModeWebhook",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Cannot provide webhook flags without ModeWebhook
|
// Cannot provide webhook flags without ModeWebhook
|
||||||
modes: []string{options.ModeAlwaysAllow},
|
config: AuthorizationConfig{
|
||||||
config: AuthorizationConfig{WebhookConfigFile: "authz_webhook_config.yml"},
|
AuthorizationModes: []string{ModeAlwaysAllow},
|
||||||
|
WebhookConfigFile: "authz_webhook_config.yml",
|
||||||
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
msg: "should have errored when Webhook config file is used without ModeWebhook",
|
msg: "should have errored when Webhook config file is used without ModeWebhook",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
_, err := NewAuthorizerFromAuthorizationConfig(tt.modes, tt.config)
|
_, err := NewAuthorizerFromAuthorizationConfig(tt.config)
|
||||||
if tt.wantErr && (err == nil) {
|
if tt.wantErr && (err == nil) {
|
||||||
t.Errorf("NewAuthorizerFromAuthorizationConfig %s", tt.msg)
|
t.Errorf("NewAuthorizerFromAuthorizationConfig %s", tt.msg)
|
||||||
} else if !tt.wantErr && (err != nil) {
|
} else if !tt.wantErr && (err != nil) {
|
||||||
|
@ -25,11 +25,18 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/auth/authorizer/abac"
|
"k8s.io/kubernetes/pkg/auth/authorizer/abac"
|
||||||
"k8s.io/kubernetes/pkg/auth/authorizer/union"
|
"k8s.io/kubernetes/pkg/auth/authorizer/union"
|
||||||
"k8s.io/kubernetes/pkg/controller/informers"
|
"k8s.io/kubernetes/pkg/controller/informers"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/options"
|
|
||||||
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac"
|
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac"
|
||||||
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/webhook"
|
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ModeAlwaysAllow string = "AlwaysAllow"
|
||||||
|
ModeAlwaysDeny string = "AlwaysDeny"
|
||||||
|
ModeABAC string = "ABAC"
|
||||||
|
ModeWebhook string = "Webhook"
|
||||||
|
ModeRBAC string = "RBAC"
|
||||||
|
)
|
||||||
|
|
||||||
// alwaysAllowAuthorizer is an implementation of authorizer.Attributes
|
// alwaysAllowAuthorizer is an implementation of authorizer.Attributes
|
||||||
// which always says yes to an authorization request.
|
// which always says yes to an authorization request.
|
||||||
// It is useful in tests and when using kubernetes in an open manner.
|
// It is useful in tests and when using kubernetes in an open manner.
|
||||||
@ -95,6 +102,8 @@ func NewPrivilegedGroups(groups ...string) *privilegedGroupAuthorizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AuthorizationConfig struct {
|
type AuthorizationConfig struct {
|
||||||
|
AuthorizationModes []string
|
||||||
|
|
||||||
// Options for ModeABAC
|
// Options for ModeABAC
|
||||||
|
|
||||||
// Path to an ABAC policy file.
|
// Path to an ABAC policy file.
|
||||||
@ -118,28 +127,27 @@ type AuthorizationConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewAuthorizerFromAuthorizationConfig returns the right sort of union of multiple authorizer.Authorizer objects
|
// NewAuthorizerFromAuthorizationConfig returns the right sort of union of multiple authorizer.Authorizer objects
|
||||||
// based on the authorizationMode or an error. authorizationMode should be a comma separated values
|
// based on the authorizationMode or an error.
|
||||||
// of options.AuthorizationModeChoices.
|
func NewAuthorizerFromAuthorizationConfig(config AuthorizationConfig) (authorizer.Authorizer, error) {
|
||||||
func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, config AuthorizationConfig) (authorizer.Authorizer, error) {
|
|
||||||
|
|
||||||
if len(authorizationModes) == 0 {
|
if len(config.AuthorizationModes) == 0 {
|
||||||
return nil, errors.New("At least one authorization mode should be passed")
|
return nil, errors.New("At least one authorization mode should be passed")
|
||||||
}
|
}
|
||||||
|
|
||||||
var authorizers []authorizer.Authorizer
|
var authorizers []authorizer.Authorizer
|
||||||
authorizerMap := make(map[string]bool)
|
authorizerMap := make(map[string]bool)
|
||||||
|
|
||||||
for _, authorizationMode := range authorizationModes {
|
for _, authorizationMode := range config.AuthorizationModes {
|
||||||
if authorizerMap[authorizationMode] {
|
if authorizerMap[authorizationMode] {
|
||||||
return nil, fmt.Errorf("Authorization mode %s specified more than once", authorizationMode)
|
return nil, fmt.Errorf("Authorization mode %s specified more than once", authorizationMode)
|
||||||
}
|
}
|
||||||
// Keep cases in sync with constant list above.
|
// Keep cases in sync with constant list above.
|
||||||
switch authorizationMode {
|
switch authorizationMode {
|
||||||
case options.ModeAlwaysAllow:
|
case ModeAlwaysAllow:
|
||||||
authorizers = append(authorizers, NewAlwaysAllowAuthorizer())
|
authorizers = append(authorizers, NewAlwaysAllowAuthorizer())
|
||||||
case options.ModeAlwaysDeny:
|
case ModeAlwaysDeny:
|
||||||
authorizers = append(authorizers, NewAlwaysDenyAuthorizer())
|
authorizers = append(authorizers, NewAlwaysDenyAuthorizer())
|
||||||
case options.ModeABAC:
|
case ModeABAC:
|
||||||
if config.PolicyFile == "" {
|
if config.PolicyFile == "" {
|
||||||
return nil, errors.New("ABAC's authorization policy file not passed")
|
return nil, errors.New("ABAC's authorization policy file not passed")
|
||||||
}
|
}
|
||||||
@ -148,7 +156,7 @@ func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, config Au
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
authorizers = append(authorizers, abacAuthorizer)
|
authorizers = append(authorizers, abacAuthorizer)
|
||||||
case options.ModeWebhook:
|
case ModeWebhook:
|
||||||
if config.WebhookConfigFile == "" {
|
if config.WebhookConfigFile == "" {
|
||||||
return nil, errors.New("Webhook's configuration file not passed")
|
return nil, errors.New("Webhook's configuration file not passed")
|
||||||
}
|
}
|
||||||
@ -159,7 +167,7 @@ func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, config Au
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
authorizers = append(authorizers, webhookAuthorizer)
|
authorizers = append(authorizers, webhookAuthorizer)
|
||||||
case options.ModeRBAC:
|
case ModeRBAC:
|
||||||
rbacAuthorizer := rbac.New(
|
rbacAuthorizer := rbac.New(
|
||||||
config.InformerFactory.Roles().Lister(),
|
config.InformerFactory.Roles().Lister(),
|
||||||
config.InformerFactory.RoleBindings().Lister(),
|
config.InformerFactory.RoleBindings().Lister(),
|
||||||
@ -174,13 +182,13 @@ func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, config Au
|
|||||||
authorizerMap[authorizationMode] = true
|
authorizerMap[authorizationMode] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !authorizerMap[options.ModeABAC] && config.PolicyFile != "" {
|
if !authorizerMap[ModeABAC] && config.PolicyFile != "" {
|
||||||
return nil, errors.New("Cannot specify --authorization-policy-file without mode ABAC")
|
return nil, errors.New("Cannot specify --authorization-policy-file without mode ABAC")
|
||||||
}
|
}
|
||||||
if !authorizerMap[options.ModeWebhook] && config.WebhookConfigFile != "" {
|
if !authorizerMap[ModeWebhook] && config.WebhookConfigFile != "" {
|
||||||
return nil, errors.New("Cannot specify --authorization-webhook-config-file without mode Webhook")
|
return nil, errors.New("Cannot specify --authorization-webhook-config-file without mode Webhook")
|
||||||
}
|
}
|
||||||
if !authorizerMap[options.ModeRBAC] && config.RBACSuperUser != "" {
|
if !authorizerMap[ModeRBAC] && config.RBACSuperUser != "" {
|
||||||
return nil, errors.New("Cannot specify --authorization-rbac-super-user without mode RBAC")
|
return nil, errors.New("Cannot specify --authorization-rbac-super-user without mode RBAC")
|
||||||
}
|
}
|
||||||
|
|
46
pkg/genericapiserver/authorizer/delegating.go
Normal file
46
pkg/genericapiserver/authorizer/delegating.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 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 authorizer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||||
|
authorizationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authorization/v1beta1"
|
||||||
|
webhooksar "k8s.io/kubernetes/plugin/pkg/auth/authorizer/webhook"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DelegatingAuthorizerConfig is the minimal configuration needed to create an authenticator
|
||||||
|
// built to delegate authorization to a kube API server
|
||||||
|
type DelegatingAuthorizerConfig struct {
|
||||||
|
SubjectAccessReviewClient authorizationclient.SubjectAccessReviewInterface
|
||||||
|
|
||||||
|
// AllowCacheTTL is the length of time that a successful authorization response will be cached
|
||||||
|
AllowCacheTTL time.Duration
|
||||||
|
|
||||||
|
// DenyCacheTTL is the length of time that an unsuccessful authorization response will be cached.
|
||||||
|
// You generally want more responsive, "deny, try again" flows.
|
||||||
|
DenyCacheTTL time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c DelegatingAuthorizerConfig) New() (authorizer.Authorizer, error) {
|
||||||
|
return webhooksar.NewFromInterface(
|
||||||
|
c.SubjectAccessReviewClient,
|
||||||
|
c.AllowCacheTTL,
|
||||||
|
c.DenyCacheTTL,
|
||||||
|
)
|
||||||
|
}
|
@ -32,20 +32,25 @@ import (
|
|||||||
|
|
||||||
"github.com/go-openapi/spec"
|
"github.com/go-openapi/spec"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"github.com/pborman/uuid"
|
||||||
"gopkg.in/natefinch/lumberjack.v2"
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/admission"
|
"k8s.io/kubernetes/pkg/admission"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
apiserverauthenticator "k8s.io/kubernetes/pkg/apiserver/authenticator"
|
||||||
apiserverfilters "k8s.io/kubernetes/pkg/apiserver/filters"
|
apiserverfilters "k8s.io/kubernetes/pkg/apiserver/filters"
|
||||||
apiserveropenapi "k8s.io/kubernetes/pkg/apiserver/openapi"
|
apiserveropenapi "k8s.io/kubernetes/pkg/apiserver/openapi"
|
||||||
"k8s.io/kubernetes/pkg/apiserver/request"
|
"k8s.io/kubernetes/pkg/apiserver/request"
|
||||||
"k8s.io/kubernetes/pkg/auth/authenticator"
|
"k8s.io/kubernetes/pkg/auth/authenticator"
|
||||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||||
|
authorizerunion "k8s.io/kubernetes/pkg/auth/authorizer/union"
|
||||||
authhandlers "k8s.io/kubernetes/pkg/auth/handlers"
|
authhandlers "k8s.io/kubernetes/pkg/auth/handlers"
|
||||||
|
"k8s.io/kubernetes/pkg/auth/user"
|
||||||
"k8s.io/kubernetes/pkg/client/restclient"
|
"k8s.io/kubernetes/pkg/client/restclient"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
|
apiserverauthorizer "k8s.io/kubernetes/pkg/genericapiserver/authorizer"
|
||||||
genericfilters "k8s.io/kubernetes/pkg/genericapiserver/filters"
|
genericfilters "k8s.io/kubernetes/pkg/genericapiserver/filters"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/mux"
|
"k8s.io/kubernetes/pkg/genericapiserver/mux"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/openapi/common"
|
"k8s.io/kubernetes/pkg/genericapiserver/openapi/common"
|
||||||
@ -54,9 +59,9 @@ import (
|
|||||||
genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation"
|
genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
|
||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
"k8s.io/kubernetes/pkg/version"
|
"k8s.io/kubernetes/pkg/version"
|
||||||
|
authenticatorunion "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -226,12 +231,77 @@ func NewConfig() *Config {
|
|||||||
defaultOptions := options.NewServerRunOptions()
|
defaultOptions := options.NewServerRunOptions()
|
||||||
// unset fields that can be overridden to avoid setting values so that we won't end up with lingering values.
|
// unset fields that can be overridden to avoid setting values so that we won't end up with lingering values.
|
||||||
// TODO we probably want to run the defaults the other way. A default here drives it in the CLI flags
|
// TODO we probably want to run the defaults the other way. A default here drives it in the CLI flags
|
||||||
defaultOptions.SecurePort = 0
|
|
||||||
defaultOptions.InsecurePort = 0
|
|
||||||
defaultOptions.AuditLogPath = ""
|
defaultOptions.AuditLogPath = ""
|
||||||
return config.ApplyOptions(defaultOptions)
|
return config.ApplyOptions(defaultOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) ApplySecureServingOptions(secureServing *options.SecureServingOptions) *Config {
|
||||||
|
if secureServing == nil || secureServing.ServingOptions.BindPort <= 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
secureServingInfo := &SecureServingInfo{
|
||||||
|
ServingInfo: ServingInfo{
|
||||||
|
BindAddress: net.JoinHostPort(secureServing.ServingOptions.BindAddress.String(), strconv.Itoa(secureServing.ServingOptions.BindPort)),
|
||||||
|
},
|
||||||
|
ServerCert: GeneratableKeyCert{
|
||||||
|
CertKey: CertKey{
|
||||||
|
CertFile: secureServing.ServerCert.CertKey.CertFile,
|
||||||
|
KeyFile: secureServing.ServerCert.CertKey.KeyFile,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SNICerts: []NamedCertKey{},
|
||||||
|
ClientCA: secureServing.ClientCA,
|
||||||
|
}
|
||||||
|
if secureServing.ServerCert.CertKey.CertFile == "" && secureServing.ServerCert.CertKey.KeyFile == "" {
|
||||||
|
secureServingInfo.ServerCert.Generate = true
|
||||||
|
secureServingInfo.ServerCert.CertFile = path.Join(secureServing.ServerCert.CertDirectory, secureServing.ServerCert.PairName+".crt")
|
||||||
|
secureServingInfo.ServerCert.KeyFile = path.Join(secureServing.ServerCert.CertDirectory, secureServing.ServerCert.PairName+".key")
|
||||||
|
}
|
||||||
|
|
||||||
|
secureServingInfo.SNICerts = nil
|
||||||
|
for _, nkc := range secureServing.SNICertKeys {
|
||||||
|
secureServingInfo.SNICerts = append(secureServingInfo.SNICerts, NamedCertKey{
|
||||||
|
CertKey: CertKey{
|
||||||
|
KeyFile: nkc.KeyFile,
|
||||||
|
CertFile: nkc.CertFile,
|
||||||
|
},
|
||||||
|
Names: nkc.Names,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
c.SecureServingInfo = secureServingInfo
|
||||||
|
c.ReadWritePort = secureServing.ServingOptions.BindPort
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) ApplyInsecureServingOptions(insecureServing *options.ServingOptions) *Config {
|
||||||
|
if insecureServing == nil || insecureServing.BindPort <= 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
c.InsecureServingInfo = &ServingInfo{
|
||||||
|
BindAddress: net.JoinHostPort(insecureServing.BindAddress.String(), strconv.Itoa(insecureServing.BindPort)),
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) ApplyAuthenticationOptions(o *options.BuiltInAuthenticationOptions) *Config {
|
||||||
|
if o == nil || o.PasswordFile == nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
c.SupportsBasicAuth = len(o.PasswordFile.BasicAuthFile) > 0
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) ApplyRBACSuperUser(rbacSuperUser string) *Config {
|
||||||
|
c.AuthorizerRBACSuperUser = rbacSuperUser
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// ApplyOptions applies the run options to the method receiver and returns self
|
// ApplyOptions applies the run options to the method receiver and returns self
|
||||||
func (c *Config) ApplyOptions(options *options.ServerRunOptions) *Config {
|
func (c *Config) ApplyOptions(options *options.ServerRunOptions) *Config {
|
||||||
if len(options.AuditLogPath) != 0 {
|
if len(options.AuditLogPath) != 0 {
|
||||||
@ -243,49 +313,6 @@ func (c *Config) ApplyOptions(options *options.ServerRunOptions) *Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.SecurePort > 0 {
|
|
||||||
secureServingInfo := &SecureServingInfo{
|
|
||||||
ServingInfo: ServingInfo{
|
|
||||||
BindAddress: net.JoinHostPort(options.BindAddress.String(), strconv.Itoa(options.SecurePort)),
|
|
||||||
},
|
|
||||||
ServerCert: GeneratableKeyCert{
|
|
||||||
CertKey: CertKey{
|
|
||||||
CertFile: options.TLSCertFile,
|
|
||||||
KeyFile: options.TLSPrivateKeyFile,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SNICerts: []NamedCertKey{},
|
|
||||||
ClientCA: options.ClientCAFile,
|
|
||||||
}
|
|
||||||
if options.TLSCertFile == "" && options.TLSPrivateKeyFile == "" {
|
|
||||||
secureServingInfo.ServerCert.Generate = true
|
|
||||||
secureServingInfo.ServerCert.CertFile = path.Join(options.CertDirectory, "apiserver.crt")
|
|
||||||
secureServingInfo.ServerCert.KeyFile = path.Join(options.CertDirectory, "apiserver.key")
|
|
||||||
}
|
|
||||||
|
|
||||||
secureServingInfo.SNICerts = nil
|
|
||||||
for _, nkc := range options.SNICertKeys {
|
|
||||||
secureServingInfo.SNICerts = append(secureServingInfo.SNICerts, NamedCertKey{
|
|
||||||
CertKey: CertKey{
|
|
||||||
KeyFile: nkc.KeyFile,
|
|
||||||
CertFile: nkc.CertFile,
|
|
||||||
},
|
|
||||||
Names: nkc.Names,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
c.SecureServingInfo = secureServingInfo
|
|
||||||
c.ReadWritePort = options.SecurePort
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.InsecurePort > 0 {
|
|
||||||
insecureServingInfo := &ServingInfo{
|
|
||||||
BindAddress: net.JoinHostPort(options.InsecureBindAddress.String(), strconv.Itoa(options.InsecurePort)),
|
|
||||||
}
|
|
||||||
c.InsecureServingInfo = insecureServingInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
c.AuthorizerRBACSuperUser = options.AuthorizationRBACSuperUser
|
|
||||||
c.CorsAllowedOriginList = options.CorsAllowedOriginList
|
c.CorsAllowedOriginList = options.CorsAllowedOriginList
|
||||||
c.EnableGarbageCollection = options.EnableGarbageCollection
|
c.EnableGarbageCollection = options.EnableGarbageCollection
|
||||||
c.EnableProfiling = options.EnableProfiling
|
c.EnableProfiling = options.EnableProfiling
|
||||||
@ -295,7 +322,6 @@ func (c *Config) ApplyOptions(options *options.ServerRunOptions) *Config {
|
|||||||
c.MaxRequestsInFlight = options.MaxRequestsInFlight
|
c.MaxRequestsInFlight = options.MaxRequestsInFlight
|
||||||
c.MinRequestTimeout = options.MinRequestTimeout
|
c.MinRequestTimeout = options.MinRequestTimeout
|
||||||
c.PublicAddress = options.AdvertiseAddress
|
c.PublicAddress = options.AdvertiseAddress
|
||||||
c.SupportsBasicAuth = len(options.BasicAuthFile) > 0
|
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@ -340,6 +366,25 @@ func (c *Config) Complete() completedConfig {
|
|||||||
c.DiscoveryAddresses = DefaultDiscoveryAddresses{DefaultAddress: c.ExternalAddress}
|
c.DiscoveryAddresses = DefaultDiscoveryAddresses{DefaultAddress: c.ExternalAddress}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the loopbackclientconfig is specified AND it has a token for use against the API server
|
||||||
|
// wrap the authenticator and authorizer in loopback authentication logic
|
||||||
|
if c.Authenticator != nil && c.Authorizer != nil && c.LoopbackClientConfig != nil && len(c.LoopbackClientConfig.BearerToken) > 0 {
|
||||||
|
privilegedLoopbackToken := c.LoopbackClientConfig.BearerToken
|
||||||
|
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 := apiserverauthenticator.NewAuthenticatorFromTokens(tokens)
|
||||||
|
c.Authenticator = authenticatorunion.New(tokenAuthenticator, c.Authenticator)
|
||||||
|
|
||||||
|
tokenAuthorizer := apiserverauthorizer.NewPrivilegedGroups(user.SystemPrivilegedGroup)
|
||||||
|
c.Authorizer = authorizerunion.New(tokenAuthorizer, c.Authorizer)
|
||||||
|
}
|
||||||
|
|
||||||
return completedConfig{c}
|
return completedConfig{c}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +453,7 @@ func (c completedConfig) New() (*GenericAPIServer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MaybeGenerateServingCerts generates serving certificates if requested and needed.
|
// MaybeGenerateServingCerts generates serving certificates if requested and needed.
|
||||||
func (c completedConfig) MaybeGenerateServingCerts(alternateIPs ...net.IP) error {
|
func (c *Config) MaybeGenerateServingCerts(alternateIPs ...net.IP) error {
|
||||||
// It would be nice to set a fqdn subject alt name, but only the kubelets know, the apiserver is clueless
|
// It would be nice to set a fqdn subject alt name, but only the kubelets know, the apiserver is clueless
|
||||||
// alternateDNS = append(alternateDNS, "kubernetes.default.svc.CLUSTER.DNS.NAME")
|
// alternateDNS = append(alternateDNS, "kubernetes.default.svc.CLUSTER.DNS.NAME")
|
||||||
if c.SecureServingInfo != nil && c.SecureServingInfo.ServerCert.Generate && !certutil.CanReadCertOrKey(c.SecureServingInfo.ServerCert.CertFile, c.SecureServingInfo.ServerCert.KeyFile) {
|
if c.SecureServingInfo != nil && c.SecureServingInfo.ServerCert.Generate && !certutil.CanReadCertOrKey(c.SecureServingInfo.ServerCert.CertFile, c.SecureServingInfo.ServerCert.KeyFile) {
|
||||||
@ -485,17 +530,6 @@ func (s *GenericAPIServer) installAPI(c *Config) {
|
|||||||
func DefaultAndValidateRunOptions(options *options.ServerRunOptions) {
|
func DefaultAndValidateRunOptions(options *options.ServerRunOptions) {
|
||||||
genericvalidation.ValidateRunOptions(options)
|
genericvalidation.ValidateRunOptions(options)
|
||||||
|
|
||||||
// If advertise-address is not specified, use bind-address. If bind-address
|
|
||||||
// is not usable (unset, 0.0.0.0, or loopback), we will use the host's default
|
|
||||||
// interface as valid public addr for master (see: util/net#ValidPublicAddrForMaster)
|
|
||||||
if options.AdvertiseAddress == nil || options.AdvertiseAddress.IsUnspecified() {
|
|
||||||
hostIP, err := utilnet.ChooseBindAddress(options.BindAddress)
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalf("Unable to find suitable network address.error='%v' . "+
|
|
||||||
"Try to set the AdvertiseAddress directly or provide a valid BindAddress to fix this.", err)
|
|
||||||
}
|
|
||||||
options.AdvertiseAddress = hostIP
|
|
||||||
}
|
|
||||||
glog.Infof("Will report %v as public IP address.", options.AdvertiseAddress)
|
glog.Infof("Will report %v as public IP address.", options.AdvertiseAddress)
|
||||||
|
|
||||||
// Set default value for ExternalAddress if not specified.
|
// Set default value for ExternalAddress if not specified.
|
||||||
|
@ -13,10 +13,12 @@ load(
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
"authenticator.go",
|
"authentication.go",
|
||||||
|
"authorization.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
"etcd_options.go",
|
"etcd.go",
|
||||||
"server_run_options.go",
|
"server_run_options.go",
|
||||||
|
"serving.go",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
@ -24,8 +26,12 @@ go_library(
|
|||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/apimachinery/registered:go_default_library",
|
"//pkg/apimachinery/registered:go_default_library",
|
||||||
"//pkg/apiserver/authenticator:go_default_library",
|
"//pkg/apiserver/authenticator:go_default_library",
|
||||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
"//pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1:go_default_library",
|
||||||
|
"//pkg/client/clientset_generated/release_1_5/typed/authorization/v1beta1:go_default_library",
|
||||||
"//pkg/client/restclient:go_default_library",
|
"//pkg/client/restclient:go_default_library",
|
||||||
|
"//pkg/client/unversioned/clientcmd:go_default_library",
|
||||||
|
"//pkg/controller/informers:go_default_library",
|
||||||
|
"//pkg/genericapiserver/authorizer:go_default_library",
|
||||||
"//pkg/runtime/schema:go_default_library",
|
"//pkg/runtime/schema:go_default_library",
|
||||||
"//pkg/storage/storagebackend:go_default_library",
|
"//pkg/storage/storagebackend:go_default_library",
|
||||||
"//pkg/util/config:go_default_library",
|
"//pkg/util/config:go_default_library",
|
||||||
|
377
pkg/genericapiserver/options/authentication.go
Normal file
377
pkg/genericapiserver/options/authentication.go
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 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 options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/apiserver/authenticator"
|
||||||
|
authenticationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authentication/v1beta1"
|
||||||
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BuiltInAuthenticationOptions struct {
|
||||||
|
Anonymous *AnonymousAuthenticationOptions
|
||||||
|
AnyToken *AnyTokenAuthenticationOptions
|
||||||
|
Keystone *KeystoneAuthenticationOptions
|
||||||
|
OIDC *OIDCAuthenticationOptions
|
||||||
|
PasswordFile *PasswordFileAuthenticationOptions
|
||||||
|
RequestHeader *RequestHeaderAuthenticationOptions
|
||||||
|
ServiceAccounts *ServiceAccountAuthenticationOptions
|
||||||
|
TokenFile *TokenFileAuthenticationOptions
|
||||||
|
WebHook *WebHookAuthenticationOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnyTokenAuthenticationOptions struct {
|
||||||
|
Allow bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnonymousAuthenticationOptions struct {
|
||||||
|
Allow bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type KeystoneAuthenticationOptions struct {
|
||||||
|
URL string
|
||||||
|
CAFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
type OIDCAuthenticationOptions struct {
|
||||||
|
CAFile string
|
||||||
|
ClientID string
|
||||||
|
IssuerURL string
|
||||||
|
UsernameClaim string
|
||||||
|
GroupsClaim string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasswordFileAuthenticationOptions struct {
|
||||||
|
BasicAuthFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
type RequestHeaderAuthenticationOptions struct {
|
||||||
|
UsernameHeaders []string
|
||||||
|
ClientCAFile string
|
||||||
|
AllowedNames []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceAccountAuthenticationOptions struct {
|
||||||
|
KeyFiles []string
|
||||||
|
Lookup bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type TokenFileAuthenticationOptions struct {
|
||||||
|
TokenFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebHookAuthenticationOptions struct {
|
||||||
|
ConfigFile string
|
||||||
|
CacheTTL time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBuiltInAuthenticationOptions() *BuiltInAuthenticationOptions {
|
||||||
|
return &BuiltInAuthenticationOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) WithAll() *BuiltInAuthenticationOptions {
|
||||||
|
return s.
|
||||||
|
WithAnyonymous().
|
||||||
|
WithAnyToken().
|
||||||
|
WithKeystone().
|
||||||
|
WithOIDC().
|
||||||
|
WithPasswordFile().
|
||||||
|
WithRequestHeader().
|
||||||
|
WithServiceAccounts().
|
||||||
|
WithTokenFile().
|
||||||
|
WithWebHook()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) WithAnyonymous() *BuiltInAuthenticationOptions {
|
||||||
|
s.Anonymous = &AnonymousAuthenticationOptions{Allow: true}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) WithAnyToken() *BuiltInAuthenticationOptions {
|
||||||
|
s.AnyToken = &AnyTokenAuthenticationOptions{}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) WithKeystone() *BuiltInAuthenticationOptions {
|
||||||
|
s.Keystone = &KeystoneAuthenticationOptions{}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) WithOIDC() *BuiltInAuthenticationOptions {
|
||||||
|
s.OIDC = &OIDCAuthenticationOptions{}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) WithPasswordFile() *BuiltInAuthenticationOptions {
|
||||||
|
s.PasswordFile = &PasswordFileAuthenticationOptions{}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) WithRequestHeader() *BuiltInAuthenticationOptions {
|
||||||
|
s.RequestHeader = &RequestHeaderAuthenticationOptions{}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) WithServiceAccounts() *BuiltInAuthenticationOptions {
|
||||||
|
s.ServiceAccounts = &ServiceAccountAuthenticationOptions{}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) WithTokenFile() *BuiltInAuthenticationOptions {
|
||||||
|
s.TokenFile = &TokenFileAuthenticationOptions{}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) WithWebHook() *BuiltInAuthenticationOptions {
|
||||||
|
s.WebHook = &WebHookAuthenticationOptions{
|
||||||
|
CacheTTL: 2 * time.Minute,
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) Validate() []error {
|
||||||
|
allErrors := []error{}
|
||||||
|
return allErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||||
|
if s.Anonymous != nil {
|
||||||
|
fs.BoolVar(&s.Anonymous.Allow, "anonymous-auth", s.Anonymous.Allow, ""+
|
||||||
|
"Enables anonymous requests to the secure port of the API server. "+
|
||||||
|
"Requests that are not rejected by another authentication method are treated as anonymous requests. "+
|
||||||
|
"Anonymous requests have a username of system:anonymous, and a group name of system:unauthenticated.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.AnyToken != nil {
|
||||||
|
fs.BoolVar(&s.AnyToken.Allow, "insecure-allow-any-token", s.AnyToken.Allow, ""+
|
||||||
|
"If set, your server will be INSECURE. Any token will be allowed and user information will be parsed "+
|
||||||
|
"from the token as `username/group1,group2`")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Keystone != nil {
|
||||||
|
fs.StringVar(&s.Keystone.URL, "experimental-keystone-url", s.Keystone.URL,
|
||||||
|
"If passed, activates the keystone authentication plugin.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.Keystone.CAFile, "experimental-keystone-ca-file", s.Keystone.CAFile, ""+
|
||||||
|
"If set, the Keystone server's certificate will be verified by one of the authorities "+
|
||||||
|
"in the experimental-keystone-ca-file, otherwise the host's root CA set will be used.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.OIDC != nil {
|
||||||
|
fs.StringVar(&s.OIDC.IssuerURL, "oidc-issuer-url", s.OIDC.IssuerURL, ""+
|
||||||
|
"The URL of the OpenID issuer, only HTTPS scheme will be accepted. "+
|
||||||
|
"If set, it will be used to verify the OIDC JSON Web Token (JWT).")
|
||||||
|
|
||||||
|
fs.StringVar(&s.OIDC.ClientID, "oidc-client-id", s.OIDC.ClientID,
|
||||||
|
"The client ID for the OpenID Connect client, must be set if oidc-issuer-url is set.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.OIDC.CAFile, "oidc-ca-file", s.OIDC.CAFile, ""+
|
||||||
|
"If set, the OpenID server's certificate will be verified by one of the authorities "+
|
||||||
|
"in the oidc-ca-file, otherwise the host's root CA set will be used.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.OIDC.UsernameClaim, "oidc-username-claim", "sub", ""+
|
||||||
|
"The OpenID claim to use as the user name. Note that claims other than the default ('sub') "+
|
||||||
|
"is not guaranteed to be unique and immutable. This flag is experimental, please see "+
|
||||||
|
"the authentication documentation for further details.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.OIDC.GroupsClaim, "oidc-groups-claim", "", ""+
|
||||||
|
"If provided, the name of a custom OpenID Connect claim for specifying user groups. "+
|
||||||
|
"The claim value is expected to be a string or array of strings. This flag is experimental, "+
|
||||||
|
"please see the authentication documentation for further details.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.PasswordFile != nil {
|
||||||
|
fs.StringVar(&s.PasswordFile.BasicAuthFile, "basic-auth-file", s.PasswordFile.BasicAuthFile, ""+
|
||||||
|
"If set, the file that will be used to admit requests to the secure port of the API server "+
|
||||||
|
"via http basic authentication.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.RequestHeader != nil {
|
||||||
|
fs.StringSliceVar(&s.RequestHeader.UsernameHeaders, "requestheader-username-headers", s.RequestHeader.UsernameHeaders, ""+
|
||||||
|
"List of request headers to inspect for usernames. X-Remote-User is common.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.RequestHeader.ClientCAFile, "requestheader-client-ca-file", s.RequestHeader.ClientCAFile, ""+
|
||||||
|
"Root certificate bundle to use to verify client certificates on incoming requests "+
|
||||||
|
"before trusting usernames in headers specified by --requestheader-username-headers")
|
||||||
|
|
||||||
|
fs.StringSliceVar(&s.RequestHeader.AllowedNames, "requestheader-allowed-names", s.RequestHeader.AllowedNames, ""+
|
||||||
|
"List of client certificate common names to allow to provide usernames in headers "+
|
||||||
|
"specified by --requestheader-username-headers. If empty, any client certificate validated "+
|
||||||
|
"by the authorities in --requestheader-client-ca-file is allowed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.ServiceAccounts != nil {
|
||||||
|
fs.StringArrayVar(&s.ServiceAccounts.KeyFiles, "service-account-key-file", s.ServiceAccounts.KeyFiles, ""+
|
||||||
|
"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.ServiceAccounts.Lookup, "service-account-lookup", s.ServiceAccounts.Lookup,
|
||||||
|
"If true, validate ServiceAccount tokens exist in etcd as part of authentication.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.TokenFile != nil {
|
||||||
|
fs.StringVar(&s.TokenFile.TokenFile, "token-auth-file", s.TokenFile.TokenFile, ""+
|
||||||
|
"If set, the file that will be used to secure the secure port of the API server "+
|
||||||
|
"via token authentication.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.WebHook != nil {
|
||||||
|
fs.StringVar(&s.WebHook.ConfigFile, "authentication-token-webhook-config-file", s.WebHook.ConfigFile, ""+
|
||||||
|
"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.WebHook.CacheTTL, "authentication-token-webhook-cache-ttl", s.WebHook.CacheTTL,
|
||||||
|
"The duration to cache responses from the webhook token authenticator. Default is 2m.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig(clientCAFile string) authenticator.AuthenticatorConfig {
|
||||||
|
ret := authenticator.AuthenticatorConfig{
|
||||||
|
ClientCAFile: clientCAFile,
|
||||||
|
}
|
||||||
|
if s.Anonymous != nil {
|
||||||
|
ret.Anonymous = s.Anonymous.Allow
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.AnyToken != nil {
|
||||||
|
ret.AnyToken = s.AnyToken.Allow
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Keystone != nil {
|
||||||
|
ret.KeystoneURL = s.Keystone.URL
|
||||||
|
ret.KeystoneCAFile = s.Keystone.CAFile
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.OIDC != nil {
|
||||||
|
ret.OIDCCAFile = s.OIDC.CAFile
|
||||||
|
ret.OIDCClientID = s.OIDC.ClientID
|
||||||
|
ret.OIDCGroupsClaim = s.OIDC.GroupsClaim
|
||||||
|
ret.OIDCIssuerURL = s.OIDC.IssuerURL
|
||||||
|
ret.OIDCUsernameClaim = s.OIDC.UsernameClaim
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.PasswordFile != nil {
|
||||||
|
ret.BasicAuthFile = s.PasswordFile.BasicAuthFile
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.RequestHeader != nil {
|
||||||
|
ret.RequestHeaderConfig = s.RequestHeader.AuthenticationRequestHeaderConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.ServiceAccounts != nil {
|
||||||
|
ret.ServiceAccountKeyFiles = s.ServiceAccounts.KeyFiles
|
||||||
|
ret.ServiceAccountLookup = s.ServiceAccounts.Lookup
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.TokenFile != nil {
|
||||||
|
ret.TokenAuthFile = s.TokenFile.TokenFile
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.WebHook != nil {
|
||||||
|
ret.WebhookTokenAuthnConfigFile = s.WebHook.ConfigFile
|
||||||
|
ret.WebhookTokenAuthnCacheTTL = s.WebHook.CacheTTL
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthenticationRequestHeaderConfig returns an authenticator config object for these options
|
||||||
|
// if necessary. nil otherwise.
|
||||||
|
func (s *RequestHeaderAuthenticationOptions) AuthenticationRequestHeaderConfig() *authenticator.RequestHeaderConfig {
|
||||||
|
if len(s.UsernameHeaders) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &authenticator.RequestHeaderConfig{
|
||||||
|
UsernameHeaders: s.UsernameHeaders,
|
||||||
|
ClientCA: s.ClientCAFile,
|
||||||
|
AllowedClientNames: s.AllowedNames,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelegatingAuthenticationOptions provides an easy way for composing API servers to delegate their authentication to
|
||||||
|
// the root kube API server
|
||||||
|
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
|
||||||
|
|
||||||
|
// CacheTTL is the length of time that a token authentication answer will be cached.
|
||||||
|
CacheTTL time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDelegatingAuthenticationOptions() *DelegatingAuthenticationOptions {
|
||||||
|
return &DelegatingAuthenticationOptions{
|
||||||
|
CacheTTL: 5 * time.Minute,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DelegatingAuthenticationOptions) Validate() []error {
|
||||||
|
allErrors := []error{}
|
||||||
|
return allErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DelegatingAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||||
|
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.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DelegatingAuthenticationOptions) ToAuthenticationConfig(clientCAFile string) (authenticator.DelegatingAuthenticatorConfig, error) {
|
||||||
|
tokenClient, err := s.newTokenAccessReview()
|
||||||
|
if err != nil {
|
||||||
|
return authenticator.DelegatingAuthenticatorConfig{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := authenticator.DelegatingAuthenticatorConfig{
|
||||||
|
Anonymous: true,
|
||||||
|
TokenAccessReviewClient: tokenClient,
|
||||||
|
CacheTTL: s.CacheTTL,
|
||||||
|
ClientCAFile: clientCAFile,
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DelegatingAuthenticationOptions) newTokenAccessReview() (authenticationclient.TokenReviewInterface, error) {
|
||||||
|
if len(s.RemoteKubeConfigFile) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.RemoteKubeConfigFile}
|
||||||
|
loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
|
||||||
|
|
||||||
|
clientConfig, err := loader.ClientConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// set high qps/burst limits since this will effectively limit API server responsiveness
|
||||||
|
clientConfig.QPS = 200
|
||||||
|
clientConfig.Burst = 400
|
||||||
|
|
||||||
|
client, err := authenticationclient.NewForConfig(clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.TokenReviews(), nil
|
||||||
|
}
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2016 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 options
|
|
||||||
|
|
||||||
import (
|
|
||||||
"k8s.io/kubernetes/pkg/apiserver/authenticator"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AuthenticationRequestHeaderConfig returns an authenticator config object for these options
|
|
||||||
// if necessary. nil otherwise.
|
|
||||||
func (s *ServerRunOptions) AuthenticationRequestHeaderConfig() *authenticator.RequestHeaderConfig {
|
|
||||||
if len(s.RequestHeaderUsernameHeaders) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &authenticator.RequestHeaderConfig{
|
|
||||||
UsernameHeaders: s.RequestHeaderUsernameHeaders,
|
|
||||||
ClientCA: s.RequestHeaderClientCAFile,
|
|
||||||
AllowedClientNames: s.RequestHeaderAllowedNames,
|
|
||||||
}
|
|
||||||
}
|
|
167
pkg/genericapiserver/options/authorization.go
Normal file
167
pkg/genericapiserver/options/authorization.go
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 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 options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
|
authorizationclient "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/authorization/v1beta1"
|
||||||
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
|
"k8s.io/kubernetes/pkg/controller/informers"
|
||||||
|
"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
|
||||||
|
)
|
||||||
|
|
||||||
|
var AuthorizationModeChoices = []string{authorizer.ModeAlwaysAllow, authorizer.ModeAlwaysDeny, authorizer.ModeABAC, authorizer.ModeWebhook, authorizer.ModeRBAC}
|
||||||
|
|
||||||
|
type BuiltInAuthorizationOptions struct {
|
||||||
|
Mode string
|
||||||
|
PolicyFile string
|
||||||
|
WebhookConfigFile string
|
||||||
|
WebhookCacheAuthorizedTTL time.Duration
|
||||||
|
WebhookCacheUnauthorizedTTL time.Duration
|
||||||
|
RBACSuperUser string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBuiltInAuthorizationOptions() *BuiltInAuthorizationOptions {
|
||||||
|
return &BuiltInAuthorizationOptions{
|
||||||
|
Mode: authorizer.ModeAlwaysAllow,
|
||||||
|
WebhookCacheAuthorizedTTL: 5 * time.Minute,
|
||||||
|
WebhookCacheUnauthorizedTTL: 30 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthorizationOptions) Validate() []error {
|
||||||
|
allErrors := []error{}
|
||||||
|
return allErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthorizationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||||
|
fs.StringVar(&s.Mode, "authorization-mode", s.Mode, ""+
|
||||||
|
"Ordered list of plug-ins to do authorization on secure port. Comma-delimited list of: "+
|
||||||
|
strings.Join(AuthorizationModeChoices, ",")+".")
|
||||||
|
|
||||||
|
fs.StringVar(&s.PolicyFile, "authorization-policy-file", s.PolicyFile, ""+
|
||||||
|
"File with authorization policy in csv format, used with --authorization-mode=ABAC, on the secure port.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.WebhookConfigFile, "authorization-webhook-config-file", s.WebhookConfigFile, ""+
|
||||||
|
"File with webhook configuration in kubeconfig format, used with --authorization-mode=Webhook. "+
|
||||||
|
"The API server will query the remote service to determine access on the API server's secure port.")
|
||||||
|
|
||||||
|
fs.DurationVar(&s.WebhookCacheAuthorizedTTL, "authorization-webhook-cache-authorized-ttl",
|
||||||
|
s.WebhookCacheAuthorizedTTL,
|
||||||
|
"The duration to cache 'authorized' responses from the webhook authorizer. Default is 5m.")
|
||||||
|
|
||||||
|
fs.DurationVar(&s.WebhookCacheUnauthorizedTTL,
|
||||||
|
"authorization-webhook-cache-unauthorized-ttl", s.WebhookCacheUnauthorizedTTL,
|
||||||
|
"The duration to cache 'unauthorized' responses from the webhook authorizer. Default is 30s.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.RBACSuperUser, "authorization-rbac-super-user", s.RBACSuperUser, ""+
|
||||||
|
"If specified, a username which avoids RBAC authorization checks and role binding "+
|
||||||
|
"privilege escalation checks, to be used with --authorization-mode=RBAC.")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BuiltInAuthorizationOptions) ToAuthorizationConfig(informerFactory informers.SharedInformerFactory) authorizer.AuthorizationConfig {
|
||||||
|
modes := []string{}
|
||||||
|
if len(s.Mode) > 0 {
|
||||||
|
modes = strings.Split(s.Mode, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
return authorizer.AuthorizationConfig{
|
||||||
|
AuthorizationModes: modes,
|
||||||
|
PolicyFile: s.PolicyFile,
|
||||||
|
WebhookConfigFile: s.WebhookConfigFile,
|
||||||
|
WebhookCacheAuthorizedTTL: s.WebhookCacheAuthorizedTTL,
|
||||||
|
WebhookCacheUnauthorizedTTL: s.WebhookCacheUnauthorizedTTL,
|
||||||
|
RBACSuperUser: s.RBACSuperUser,
|
||||||
|
InformerFactory: informerFactory,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelegatingAuthorizationOptions provides an easy way for composing API servers to delegate their authorization to
|
||||||
|
// the root kube API server
|
||||||
|
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
|
||||||
|
|
||||||
|
// AllowCacheTTL is the length of time that a successful authorization response will be cached
|
||||||
|
AllowCacheTTL time.Duration
|
||||||
|
|
||||||
|
// DenyCacheTTL is the length of time that an unsuccessful authorization response will be cached.
|
||||||
|
// You generally want more responsive, "deny, try again" flows.
|
||||||
|
DenyCacheTTL time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDelegatingAuthorizationOptions() *DelegatingAuthorizationOptions {
|
||||||
|
return &DelegatingAuthorizationOptions{
|
||||||
|
AllowCacheTTL: 5 * time.Minute,
|
||||||
|
DenyCacheTTL: 30 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DelegatingAuthorizationOptions) Validate() []error {
|
||||||
|
allErrors := []error{}
|
||||||
|
return allErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DelegatingAuthorizationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||||
|
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.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DelegatingAuthorizationOptions) ToAuthorizationConfig() (authorizer.DelegatingAuthorizerConfig, error) {
|
||||||
|
sarClient, err := s.newSubjectAccessReview()
|
||||||
|
if err != nil {
|
||||||
|
return authorizer.DelegatingAuthorizerConfig{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := authorizer.DelegatingAuthorizerConfig{
|
||||||
|
SubjectAccessReviewClient: sarClient,
|
||||||
|
AllowCacheTTL: s.AllowCacheTTL,
|
||||||
|
DenyCacheTTL: s.DenyCacheTTL,
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DelegatingAuthorizationOptions) newSubjectAccessReview() (authorizationclient.SubjectAccessReviewInterface, error) {
|
||||||
|
if len(s.RemoteKubeConfigFile) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.RemoteKubeConfigFile}
|
||||||
|
loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
|
||||||
|
|
||||||
|
clientConfig, err := loader.ClientConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// set high qps/burst limits since this will effectively limit API server responsiveness
|
||||||
|
clientConfig.QPS = 200
|
||||||
|
clientConfig.Burst = 400
|
||||||
|
|
||||||
|
client, err := authorizationclient.NewForConfig(clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.SubjectAccessReviews(), nil
|
||||||
|
}
|
@ -17,20 +17,55 @@ limitations under the License.
|
|||||||
package options
|
package options
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/storage/storagebackend"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultEtcdPathPrefix = "/registry"
|
DefaultEtcdPathPrefix = "/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddEtcdFlags adds flags related to etcd storage for a specific APIServer to the specified FlagSet
|
type EtcdOptions struct {
|
||||||
func (s *ServerRunOptions) AddEtcdStorageFlags(fs *pflag.FlagSet) {
|
StorageConfig storagebackend.Config
|
||||||
|
|
||||||
|
EtcdServersOverrides []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEtcdOptions() *EtcdOptions {
|
||||||
|
return &EtcdOptions{
|
||||||
|
StorageConfig: storagebackend.Config{
|
||||||
|
Prefix: DefaultEtcdPathPrefix,
|
||||||
|
// Default cache size to 0 - if unset, its size will be set based on target
|
||||||
|
// memory usage.
|
||||||
|
DeserializationCacheSize: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *EtcdOptions) Validate() []error {
|
||||||
|
allErrors := []error{}
|
||||||
|
if len(s.StorageConfig.ServerList) == 0 {
|
||||||
|
allErrors = append(allErrors, fmt.Errorf("--etcd-servers must be specified"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return allErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddEtcdFlags adds flags related to etcd storage for a specific APIServer to the specified FlagSet
|
||||||
|
func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
|
||||||
fs.StringSliceVar(&s.EtcdServersOverrides, "etcd-servers-overrides", s.EtcdServersOverrides, ""+
|
fs.StringSliceVar(&s.EtcdServersOverrides, "etcd-servers-overrides", s.EtcdServersOverrides, ""+
|
||||||
"Per-resource etcd servers overrides, comma separated. The individual override "+
|
"Per-resource etcd servers overrides, comma separated. The individual override "+
|
||||||
"format: group/resource#servers, where servers are http://ip:port, semicolon separated.")
|
"format: group/resource#servers, where servers are http://ip:port, semicolon separated.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.StorageConfig.Type, "storage-backend", s.StorageConfig.Type,
|
||||||
|
"The storage backend for persistence. Options: 'etcd2' (default), 'etcd3'.")
|
||||||
|
|
||||||
|
fs.IntVar(&s.StorageConfig.DeserializationCacheSize, "deserialization-cache-size", s.StorageConfig.DeserializationCacheSize,
|
||||||
|
"Number of deserialized json objects to cache in memory.")
|
||||||
|
|
||||||
fs.StringSliceVar(&s.StorageConfig.ServerList, "etcd-servers", s.StorageConfig.ServerList,
|
fs.StringSliceVar(&s.StorageConfig.ServerList, "etcd-servers", s.StorageConfig.ServerList,
|
||||||
"List of etcd servers to connect with (scheme://ip:port), comma separated.")
|
"List of etcd servers to connect with (scheme://ip:port), comma separated.")
|
||||||
|
|
@ -17,19 +17,14 @@ limitations under the License.
|
|||||||
package options
|
package options
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/admission"
|
"k8s.io/kubernetes/pkg/admission"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
|
||||||
"k8s.io/kubernetes/pkg/client/restclient"
|
|
||||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||||
"k8s.io/kubernetes/pkg/storage/storagebackend"
|
|
||||||
"k8s.io/kubernetes/pkg/util/config"
|
"k8s.io/kubernetes/pkg/util/config"
|
||||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||||
|
|
||||||
@ -43,127 +38,89 @@ const (
|
|||||||
|
|
||||||
var DefaultServiceNodePortRange = utilnet.PortRange{Base: 30000, Size: 2768}
|
var DefaultServiceNodePortRange = utilnet.PortRange{Base: 30000, Size: 2768}
|
||||||
|
|
||||||
const (
|
|
||||||
ModeAlwaysAllow string = "AlwaysAllow"
|
|
||||||
ModeAlwaysDeny string = "AlwaysDeny"
|
|
||||||
ModeABAC string = "ABAC"
|
|
||||||
ModeWebhook string = "Webhook"
|
|
||||||
ModeRBAC string = "RBAC"
|
|
||||||
)
|
|
||||||
|
|
||||||
var AuthorizationModeChoices = []string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABAC, ModeWebhook, ModeRBAC}
|
|
||||||
|
|
||||||
// ServerRunOptions contains the options while running a generic api server.
|
// ServerRunOptions contains the options while running a generic api server.
|
||||||
type ServerRunOptions struct {
|
type ServerRunOptions struct {
|
||||||
AdmissionControl string
|
AdmissionControl string
|
||||||
AdmissionControlConfigFile string
|
AdmissionControlConfigFile string
|
||||||
AdvertiseAddress net.IP
|
AdvertiseAddress net.IP
|
||||||
|
|
||||||
// Authorization mode and associated flags.
|
CloudConfigFile string
|
||||||
AuthorizationMode string
|
CloudProvider string
|
||||||
AuthorizationPolicyFile string
|
CorsAllowedOriginList []string
|
||||||
AuthorizationWebhookConfigFile string
|
DefaultStorageMediaType string
|
||||||
AuthorizationWebhookCacheAuthorizedTTL time.Duration
|
DeleteCollectionWorkers int
|
||||||
AuthorizationWebhookCacheUnauthorizedTTL time.Duration
|
AuditLogPath string
|
||||||
AuthorizationRBACSuperUser string
|
AuditLogMaxAge int
|
||||||
|
AuditLogMaxBackups int
|
||||||
AnonymousAuth bool
|
AuditLogMaxSize int
|
||||||
BasicAuthFile string
|
EnableGarbageCollection bool
|
||||||
BindAddress net.IP
|
EnableProfiling bool
|
||||||
CertDirectory string
|
EnableContentionProfiling bool
|
||||||
ClientCAFile string
|
EnableSwaggerUI bool
|
||||||
CloudConfigFile string
|
EnableWatchCache bool
|
||||||
CloudProvider string
|
ExternalHost string
|
||||||
CorsAllowedOriginList []string
|
KubernetesServiceNodePort int
|
||||||
DefaultStorageMediaType string
|
LongRunningRequestRE string
|
||||||
DeleteCollectionWorkers int
|
MasterCount int
|
||||||
AuditLogPath string
|
MasterServiceNamespace string
|
||||||
AuditLogMaxAge int
|
MaxRequestsInFlight int
|
||||||
AuditLogMaxBackups int
|
MinRequestTimeout int
|
||||||
AuditLogMaxSize int
|
RuntimeConfig config.ConfigurationMap
|
||||||
EnableGarbageCollection bool
|
ServiceClusterIPRange net.IPNet // TODO: make this a list
|
||||||
EnableProfiling bool
|
ServiceNodePortRange utilnet.PortRange
|
||||||
EnableContentionProfiling bool
|
StorageVersions string
|
||||||
EnableSwaggerUI bool
|
|
||||||
EnableWatchCache bool
|
|
||||||
EtcdServersOverrides []string
|
|
||||||
StorageConfig storagebackend.Config
|
|
||||||
ExternalHost string
|
|
||||||
InsecureBindAddress net.IP
|
|
||||||
InsecurePort int
|
|
||||||
KeystoneURL string
|
|
||||||
KeystoneCAFile string
|
|
||||||
KubernetesServiceNodePort int
|
|
||||||
LongRunningRequestRE string
|
|
||||||
MasterCount int
|
|
||||||
MasterServiceNamespace string
|
|
||||||
MaxRequestsInFlight int
|
|
||||||
MinRequestTimeout int
|
|
||||||
OIDCCAFile string
|
|
||||||
OIDCClientID string
|
|
||||||
OIDCIssuerURL string
|
|
||||||
OIDCUsernameClaim string
|
|
||||||
OIDCGroupsClaim string
|
|
||||||
RequestHeaderUsernameHeaders []string
|
|
||||||
RequestHeaderClientCAFile string
|
|
||||||
RequestHeaderAllowedNames []string
|
|
||||||
RuntimeConfig config.ConfigurationMap
|
|
||||||
SecurePort int
|
|
||||||
ServiceClusterIPRange net.IPNet // TODO: make this a list
|
|
||||||
ServiceNodePortRange utilnet.PortRange
|
|
||||||
StorageVersions string
|
|
||||||
// The default values for StorageVersions. StorageVersions overrides
|
// The default values for StorageVersions. StorageVersions overrides
|
||||||
// these; you can change this if you want to change the defaults (e.g.,
|
// these; you can change this if you want to change the defaults (e.g.,
|
||||||
// for testing). This is not actually exposed as a flag.
|
// for testing). This is not actually exposed as a flag.
|
||||||
DefaultStorageVersions string
|
DefaultStorageVersions string
|
||||||
TargetRAMMB int
|
TargetRAMMB int
|
||||||
TLSCAFile string
|
TLSCAFile string
|
||||||
TLSCertFile string
|
|
||||||
TLSPrivateKeyFile string
|
|
||||||
SNICertKeys []config.NamedCertKey
|
|
||||||
TokenAuthFile string
|
|
||||||
EnableAnyToken bool
|
|
||||||
WatchCacheSizes []string
|
WatchCacheSizes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServerRunOptions() *ServerRunOptions {
|
func NewServerRunOptions() *ServerRunOptions {
|
||||||
return &ServerRunOptions{
|
return &ServerRunOptions{
|
||||||
AdmissionControl: "AlwaysAdmit",
|
AdmissionControl: "AlwaysAdmit",
|
||||||
AnonymousAuth: true,
|
DefaultStorageMediaType: "application/json",
|
||||||
AuthorizationMode: "AlwaysAllow",
|
DefaultStorageVersions: registered.AllPreferredGroupVersions(),
|
||||||
AuthorizationWebhookCacheAuthorizedTTL: 5 * time.Minute,
|
DeleteCollectionWorkers: 1,
|
||||||
AuthorizationWebhookCacheUnauthorizedTTL: 30 * time.Second,
|
EnableGarbageCollection: true,
|
||||||
BindAddress: net.ParseIP("0.0.0.0"),
|
EnableProfiling: true,
|
||||||
CertDirectory: "/var/run/kubernetes",
|
EnableContentionProfiling: false,
|
||||||
DefaultStorageMediaType: "application/json",
|
EnableWatchCache: true,
|
||||||
DefaultStorageVersions: registered.AllPreferredGroupVersions(),
|
LongRunningRequestRE: DefaultLongRunningRequestRE,
|
||||||
DeleteCollectionWorkers: 1,
|
MasterCount: 1,
|
||||||
EnableGarbageCollection: true,
|
MasterServiceNamespace: api.NamespaceDefault,
|
||||||
EnableProfiling: true,
|
MaxRequestsInFlight: 400,
|
||||||
EnableContentionProfiling: false,
|
MinRequestTimeout: 1800,
|
||||||
EnableWatchCache: true,
|
RuntimeConfig: make(config.ConfigurationMap),
|
||||||
InsecureBindAddress: net.ParseIP("127.0.0.1"),
|
ServiceNodePortRange: DefaultServiceNodePortRange,
|
||||||
InsecurePort: 8080,
|
StorageVersions: registered.AllPreferredGroupVersions(),
|
||||||
LongRunningRequestRE: DefaultLongRunningRequestRE,
|
|
||||||
MasterCount: 1,
|
|
||||||
MasterServiceNamespace: api.NamespaceDefault,
|
|
||||||
MaxRequestsInFlight: 400,
|
|
||||||
MinRequestTimeout: 1800,
|
|
||||||
RuntimeConfig: make(config.ConfigurationMap),
|
|
||||||
SecurePort: 6443,
|
|
||||||
ServiceNodePortRange: DefaultServiceNodePortRange,
|
|
||||||
StorageVersions: registered.AllPreferredGroupVersions(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ServerRunOptions) WithEtcdOptions() *ServerRunOptions {
|
func (s *ServerRunOptions) DefaultExternalAddress(secure *SecureServingOptions, insecure *ServingOptions) error {
|
||||||
o.StorageConfig = storagebackend.Config{
|
if s.AdvertiseAddress == nil || s.AdvertiseAddress.IsUnspecified() {
|
||||||
Prefix: DefaultEtcdPathPrefix,
|
switch {
|
||||||
// Default cache size to 0 - if unset, its size will be set based on target
|
case secure != nil:
|
||||||
// memory usage.
|
hostIP, err := secure.ServingOptions.DefaultExternalAddress()
|
||||||
DeserializationCacheSize: 0,
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to find suitable network address.error='%v'. "+
|
||||||
|
"Try to set the AdvertiseAddress directly or provide a valid BindAddress to fix this.", err)
|
||||||
|
}
|
||||||
|
s.AdvertiseAddress = hostIP
|
||||||
|
|
||||||
|
case insecure != nil:
|
||||||
|
hostIP, err := insecure.DefaultExternalAddress()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to find suitable network address.error='%v'. "+
|
||||||
|
"Try to set the AdvertiseAddress directly or provide a valid BindAddress to fix this.", err)
|
||||||
|
}
|
||||||
|
s.AdvertiseAddress = hostIP
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return o
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StorageGroupsToEncodingVersion returns a map from group name to group version,
|
// StorageGroupsToEncodingVersion returns a map from group name to group version,
|
||||||
@ -212,43 +169,6 @@ func mergeGroupVersionIntoMap(gvList string, dest map[string]schema.GroupVersion
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a clientset which can be used to talk to this apiserver.
|
|
||||||
func (s *ServerRunOptions) NewSelfClient(token string) (clientset.Interface, error) {
|
|
||||||
clientConfig, err := s.NewSelfClientConfig(token)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return clientset.NewForConfig(clientConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a clientconfig which can be used to talk to this apiserver.
|
|
||||||
func (s *ServerRunOptions) NewSelfClientConfig(token string) (*restclient.Config, error) {
|
|
||||||
clientConfig := &restclient.Config{
|
|
||||||
// Increase QPS limits. The client is currently passed to all admission plugins,
|
|
||||||
// and those can be throttled in case of higher load on apiserver - see #22340 and #22422
|
|
||||||
// for more details. Once #22422 is fixed, we may want to remove it.
|
|
||||||
QPS: 50,
|
|
||||||
Burst: 100,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use secure port if the TLSCAFile is specified
|
|
||||||
if s.SecurePort > 0 && len(s.TLSCAFile) > 0 {
|
|
||||||
host := s.BindAddress.String()
|
|
||||||
if host == "0.0.0.0" {
|
|
||||||
host = "localhost"
|
|
||||||
}
|
|
||||||
clientConfig.Host = "https://" + net.JoinHostPort(host, strconv.Itoa(s.SecurePort))
|
|
||||||
clientConfig.CAFile = s.TLSCAFile
|
|
||||||
clientConfig.BearerToken = token
|
|
||||||
} else if s.InsecurePort > 0 {
|
|
||||||
clientConfig.Host = net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort))
|
|
||||||
} else {
|
|
||||||
return nil, errors.New("Unable to set url for apiserver local client")
|
|
||||||
}
|
|
||||||
|
|
||||||
return clientConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddFlags adds flags for a specific APIServer to the specified FlagSet
|
// AddFlags adds flags for a specific APIServer to the specified FlagSet
|
||||||
func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
||||||
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
|
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
|
||||||
@ -267,56 +187,6 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
|||||||
"will be used. If --bind-address is unspecified, the host's default interface will "+
|
"will be used. If --bind-address is unspecified, the host's default interface will "+
|
||||||
"be used.")
|
"be used.")
|
||||||
|
|
||||||
fs.StringVar(&s.AuthorizationMode, "authorization-mode", s.AuthorizationMode, ""+
|
|
||||||
"Ordered list of plug-ins to do authorization on secure port. Comma-delimited list of: "+
|
|
||||||
strings.Join(AuthorizationModeChoices, ",")+".")
|
|
||||||
|
|
||||||
fs.StringVar(&s.AuthorizationPolicyFile, "authorization-policy-file", s.AuthorizationPolicyFile, ""+
|
|
||||||
"File with authorization policy in csv format, used with --authorization-mode=ABAC, on the secure port.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.AuthorizationWebhookConfigFile, "authorization-webhook-config-file", s.AuthorizationWebhookConfigFile, ""+
|
|
||||||
"File with webhook configuration in kubeconfig format, used with --authorization-mode=Webhook. "+
|
|
||||||
"The API server will query the remote service to determine access on the API server's secure port.")
|
|
||||||
|
|
||||||
fs.DurationVar(&s.AuthorizationWebhookCacheAuthorizedTTL, "authorization-webhook-cache-authorized-ttl",
|
|
||||||
s.AuthorizationWebhookCacheAuthorizedTTL,
|
|
||||||
"The duration to cache 'authorized' responses from the webhook authorizer. Default is 5m.")
|
|
||||||
|
|
||||||
fs.DurationVar(&s.AuthorizationWebhookCacheUnauthorizedTTL,
|
|
||||||
"authorization-webhook-cache-unauthorized-ttl", s.AuthorizationWebhookCacheUnauthorizedTTL,
|
|
||||||
"The duration to cache 'unauthorized' responses from the webhook authorizer. Default is 30s.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.AuthorizationRBACSuperUser, "authorization-rbac-super-user", s.AuthorizationRBACSuperUser, ""+
|
|
||||||
"If specified, a username which avoids RBAC authorization checks and role binding "+
|
|
||||||
"privilege escalation checks, to be used with --authorization-mode=RBAC.")
|
|
||||||
|
|
||||||
fs.BoolVar(&s.AnonymousAuth, "anonymous-auth", s.AnonymousAuth, ""+
|
|
||||||
"Enables anonymous requests to the secure port of the API server. "+
|
|
||||||
"Requests that are not rejected by another authentication method are treated as anonymous requests. "+
|
|
||||||
"Anonymous requests have a username of system:anonymous, and a group name of system:unauthenticated.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.BasicAuthFile, "basic-auth-file", s.BasicAuthFile, ""+
|
|
||||||
"If set, the file that will be used to admit requests to the secure port of the API server "+
|
|
||||||
"via http basic authentication.")
|
|
||||||
|
|
||||||
fs.IPVar(&s.BindAddress, "public-address-override", s.BindAddress,
|
|
||||||
"DEPRECATED: see --bind-address instead.")
|
|
||||||
fs.MarkDeprecated("public-address-override", "see --bind-address instead.")
|
|
||||||
|
|
||||||
fs.IPVar(&s.BindAddress, "bind-address", s.BindAddress, ""+
|
|
||||||
"The IP address on which to listen for the --secure-port port. The "+
|
|
||||||
"associated interface(s) must be reachable by the rest of the cluster, and by CLI/web "+
|
|
||||||
"clients. If blank, all interfaces will be used (0.0.0.0).")
|
|
||||||
|
|
||||||
fs.StringVar(&s.CertDirectory, "cert-dir", s.CertDirectory, ""+
|
|
||||||
"The directory where the TLS certs are located (by default /var/run/kubernetes). "+
|
|
||||||
"If --tls-cert-file and --tls-private-key-file are provided, this flag will be ignored.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.ClientCAFile, "client-ca-file", s.ClientCAFile, ""+
|
|
||||||
"If set, any request presenting a client certificate signed by one of "+
|
|
||||||
"the authorities in the client-ca-file is authenticated with an identity "+
|
|
||||||
"corresponding to the CommonName of the client certificate.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.CloudProvider, "cloud-provider", s.CloudProvider,
|
fs.StringVar(&s.CloudProvider, "cloud-provider", s.CloudProvider,
|
||||||
"The provider for cloud services. Empty string for no provider.")
|
"The provider for cloud services. Empty string for no provider.")
|
||||||
|
|
||||||
@ -365,29 +235,6 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
|||||||
fs.StringVar(&s.ExternalHost, "external-hostname", s.ExternalHost,
|
fs.StringVar(&s.ExternalHost, "external-hostname", s.ExternalHost,
|
||||||
"The hostname to use when generating externalized URLs for this master (e.g. Swagger API Docs).")
|
"The hostname to use when generating externalized URLs for this master (e.g. Swagger API Docs).")
|
||||||
|
|
||||||
fs.IPVar(&s.InsecureBindAddress, "insecure-bind-address", s.InsecureBindAddress, ""+
|
|
||||||
"The IP address on which to serve the --insecure-port (set to 0.0.0.0 for all interfaces). "+
|
|
||||||
"Defaults to localhost.")
|
|
||||||
fs.IPVar(&s.InsecureBindAddress, "address", s.InsecureBindAddress,
|
|
||||||
"DEPRECATED: see --insecure-bind-address instead.")
|
|
||||||
fs.MarkDeprecated("address", "see --insecure-bind-address instead.")
|
|
||||||
|
|
||||||
fs.IntVar(&s.InsecurePort, "insecure-port", s.InsecurePort, ""+
|
|
||||||
"The port on which to serve unsecured, unauthenticated access. Default 8080. It is assumed "+
|
|
||||||
"that firewall rules are set up such that this port is not reachable from outside of "+
|
|
||||||
"the cluster and that port 443 on the cluster's public address is proxied to this "+
|
|
||||||
"port. This is performed by nginx in the default setup.")
|
|
||||||
|
|
||||||
fs.IntVar(&s.InsecurePort, "port", s.InsecurePort, "DEPRECATED: see --insecure-port instead.")
|
|
||||||
fs.MarkDeprecated("port", "see --insecure-port instead.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.KeystoneURL, "experimental-keystone-url", s.KeystoneURL,
|
|
||||||
"If passed, activates the keystone authentication plugin.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.KeystoneCAFile, "experimental-keystone-ca-file", s.KeystoneCAFile, ""+
|
|
||||||
"If set, the Keystone server's certificate will be verified by one of the authorities "+
|
|
||||||
"in the experimental-keystone-ca-file, otherwise the host's root CA set will be used.")
|
|
||||||
|
|
||||||
// See #14282 for details on how to test/try this option out.
|
// See #14282 for details on how to test/try this option out.
|
||||||
// TODO: remove this comment once this option is tested in CI.
|
// TODO: remove this comment once this option is tested in CI.
|
||||||
fs.IntVar(&s.KubernetesServiceNodePort, "kubernetes-service-node-port", s.KubernetesServiceNodePort, ""+
|
fs.IntVar(&s.KubernetesServiceNodePort, "kubernetes-service-node-port", s.KubernetesServiceNodePort, ""+
|
||||||
@ -415,49 +262,12 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
|||||||
"handler, which picks a randomized value above this number as the connection timeout, "+
|
"handler, which picks a randomized value above this number as the connection timeout, "+
|
||||||
"to spread out load.")
|
"to spread out load.")
|
||||||
|
|
||||||
fs.StringVar(&s.OIDCIssuerURL, "oidc-issuer-url", s.OIDCIssuerURL, ""+
|
|
||||||
"The URL of the OpenID issuer, only HTTPS scheme will be accepted. "+
|
|
||||||
"If set, it will be used to verify the OIDC JSON Web Token (JWT).")
|
|
||||||
|
|
||||||
fs.StringVar(&s.OIDCClientID, "oidc-client-id", s.OIDCClientID,
|
|
||||||
"The client ID for the OpenID Connect client, must be set if oidc-issuer-url is set.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.OIDCCAFile, "oidc-ca-file", s.OIDCCAFile, ""+
|
|
||||||
"If set, the OpenID server's certificate will be verified by one of the authorities "+
|
|
||||||
"in the oidc-ca-file, otherwise the host's root CA set will be used.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.OIDCUsernameClaim, "oidc-username-claim", "sub", ""+
|
|
||||||
"The OpenID claim to use as the user name. Note that claims other than the default ('sub') "+
|
|
||||||
"is not guaranteed to be unique and immutable. This flag is experimental, please see "+
|
|
||||||
"the authentication documentation for further details.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.OIDCGroupsClaim, "oidc-groups-claim", "", ""+
|
|
||||||
"If provided, the name of a custom OpenID Connect claim for specifying user groups. "+
|
|
||||||
"The claim value is expected to be a string or array of strings. This flag is experimental, "+
|
|
||||||
"please see the authentication documentation for further details.")
|
|
||||||
|
|
||||||
fs.StringSliceVar(&s.RequestHeaderUsernameHeaders, "requestheader-username-headers", s.RequestHeaderUsernameHeaders, ""+
|
|
||||||
"List of request headers to inspect for usernames. X-Remote-User is common.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.RequestHeaderClientCAFile, "requestheader-client-ca-file", s.RequestHeaderClientCAFile, ""+
|
|
||||||
"Root certificate bundle to use to verify client certificates on incoming requests "+
|
|
||||||
"before trusting usernames in headers specified by --requestheader-username-headers")
|
|
||||||
|
|
||||||
fs.StringSliceVar(&s.RequestHeaderAllowedNames, "requestheader-allowed-names", s.RequestHeaderAllowedNames, ""+
|
|
||||||
"List of client certificate common names to allow to provide usernames in headers "+
|
|
||||||
"specified by --requestheader-username-headers. If empty, any client certificate validated "+
|
|
||||||
"by the authorities in --requestheader-client-ca-file is allowed.")
|
|
||||||
|
|
||||||
fs.Var(&s.RuntimeConfig, "runtime-config", ""+
|
fs.Var(&s.RuntimeConfig, "runtime-config", ""+
|
||||||
"A set of key=value pairs that describe runtime configuration that may be passed "+
|
"A set of key=value pairs that describe runtime configuration that may be passed "+
|
||||||
"to apiserver. apis/<groupVersion> key can be used to turn on/off specific api versions. "+
|
"to apiserver. apis/<groupVersion> key can be used to turn on/off specific api versions. "+
|
||||||
"apis/<groupVersion>/<resource> can be used to turn on/off specific resources. api/all and "+
|
"apis/<groupVersion>/<resource> can be used to turn on/off specific resources. api/all and "+
|
||||||
"api/legacy are special keys to control all and legacy api versions respectively.")
|
"api/legacy are special keys to control all and legacy api versions respectively.")
|
||||||
|
|
||||||
fs.IntVar(&s.SecurePort, "secure-port", s.SecurePort, ""+
|
|
||||||
"The port on which to serve HTTPS with authentication and authorization. If 0, "+
|
|
||||||
"don't serve HTTPS at all.")
|
|
||||||
|
|
||||||
fs.IPNetVar(&s.ServiceClusterIPRange, "service-cluster-ip-range", s.ServiceClusterIPRange, ""+
|
fs.IPNetVar(&s.ServiceClusterIPRange, "service-cluster-ip-range", s.ServiceClusterIPRange, ""+
|
||||||
"A CIDR notation IP range from which to assign service cluster IPs. This must not "+
|
"A CIDR notation IP range from which to assign service cluster IPs. This must not "+
|
||||||
"overlap with any IP ranges assigned to nodes for pods.")
|
"overlap with any IP ranges assigned to nodes for pods.")
|
||||||
@ -472,12 +282,6 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
|||||||
fs.Var(&s.ServiceNodePortRange, "service-node-ports", "DEPRECATED: see --service-node-port-range instead")
|
fs.Var(&s.ServiceNodePortRange, "service-node-ports", "DEPRECATED: see --service-node-port-range instead")
|
||||||
fs.MarkDeprecated("service-node-ports", "see --service-node-port-range instead")
|
fs.MarkDeprecated("service-node-ports", "see --service-node-port-range instead")
|
||||||
|
|
||||||
fs.StringVar(&s.StorageConfig.Type, "storage-backend", s.StorageConfig.Type,
|
|
||||||
"The storage backend for persistence. Options: 'etcd2' (default), 'etcd3'.")
|
|
||||||
|
|
||||||
fs.IntVar(&s.StorageConfig.DeserializationCacheSize, "deserialization-cache-size", s.StorageConfig.DeserializationCacheSize,
|
|
||||||
"Number of deserialized json objects to cache in memory.")
|
|
||||||
|
|
||||||
deprecatedStorageVersion := ""
|
deprecatedStorageVersion := ""
|
||||||
fs.StringVar(&deprecatedStorageVersion, "storage-version", deprecatedStorageVersion,
|
fs.StringVar(&deprecatedStorageVersion, "storage-version", deprecatedStorageVersion,
|
||||||
"DEPRECATED: the version to store the legacy v1 resources with. Defaults to server preferred.")
|
"DEPRECATED: the version to store the legacy v1 resources with. Defaults to server preferred.")
|
||||||
@ -493,36 +297,6 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
|||||||
"It defaults to a list of preferred versions of all registered groups, "+
|
"It defaults to a list of preferred versions of all registered groups, "+
|
||||||
"which is derived from the KUBE_API_VERSIONS environment variable.")
|
"which is derived from the KUBE_API_VERSIONS environment variable.")
|
||||||
|
|
||||||
fs.StringVar(&s.TLSCAFile, "tls-ca-file", s.TLSCAFile, "If set, this "+
|
|
||||||
"certificate authority will used for secure access from Admission "+
|
|
||||||
"Controllers. This must be a valid PEM-encoded CA bundle.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.TLSCertFile, "tls-cert-file", s.TLSCertFile, ""+
|
|
||||||
"File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated "+
|
|
||||||
"after server cert). If HTTPS serving is enabled, and --tls-cert-file and "+
|
|
||||||
"--tls-private-key-file are not provided, a self-signed certificate and key "+
|
|
||||||
"are generated for the public address and saved to /var/run/kubernetes.")
|
|
||||||
|
|
||||||
fs.StringVar(&s.TLSPrivateKeyFile, "tls-private-key-file", s.TLSPrivateKeyFile,
|
|
||||||
"File containing the default x509 private key matching --tls-cert-file.")
|
|
||||||
|
|
||||||
fs.Var(config.NewNamedCertKeyArray(&s.SNICertKeys), "tls-sni-cert-key", ""+
|
|
||||||
"A pair of x509 certificate and private key file paths, optionally suffixed with a list of "+
|
|
||||||
"domain patterns which are fully qualified domain names, possibly with prefixed wildcard "+
|
|
||||||
"segments. If no domain patterns are provided, the names of the certificate are "+
|
|
||||||
"extracted. Non-wildcard matches trump over wildcard matches, explicit domain patterns "+
|
|
||||||
"trump over extracted names. For multiple key/certificate pairs, use the "+
|
|
||||||
"--tls-sni-cert-key multiple times. "+
|
|
||||||
"Examples: \"example.key,example.crt\" or \"*.foo.com,foo.com:foo.key,foo.crt\".")
|
|
||||||
|
|
||||||
fs.StringVar(&s.TokenAuthFile, "token-auth-file", s.TokenAuthFile, ""+
|
|
||||||
"If set, the file that will be used to secure the secure port of the API server "+
|
|
||||||
"via token authentication.")
|
|
||||||
|
|
||||||
fs.BoolVar(&s.EnableAnyToken, "insecure-allow-any-token", s.EnableAnyToken, ""+
|
|
||||||
"If set, your server will be INSECURE. Any token will be allowed and user information will be parsed "+
|
|
||||||
"from the token as `username/group1,group2`")
|
|
||||||
|
|
||||||
fs.StringSliceVar(&s.WatchCacheSizes, "watch-cache-sizes", s.WatchCacheSizes, ""+
|
fs.StringSliceVar(&s.WatchCacheSizes, "watch-cache-sizes", s.WatchCacheSizes, ""+
|
||||||
"List of watch cache sizes for every resource (pods, nodes, etc.), comma separated. "+
|
"List of watch cache sizes for every resource (pods, nodes, etc.), comma separated. "+
|
||||||
"The individual override format: resource#size, where size is a number. It takes effect "+
|
"The individual override format: resource#size, where size is a number. It takes effect "+
|
||||||
|
237
pkg/genericapiserver/options/serving.go
Normal file
237
pkg/genericapiserver/options/serving.go
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 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 options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/client/restclient"
|
||||||
|
"k8s.io/kubernetes/pkg/util/config"
|
||||||
|
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServingOptions struct {
|
||||||
|
BindAddress net.IP
|
||||||
|
BindPort int
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecureServingOptions struct {
|
||||||
|
ServingOptions ServingOptions
|
||||||
|
|
||||||
|
// ServerCert is the TLS cert info for serving secure traffic
|
||||||
|
ServerCert GeneratableKeyCert
|
||||||
|
// SNICertKeys are named CertKeys for serving secure traffic with SNI support.
|
||||||
|
SNICertKeys []config.NamedCertKey
|
||||||
|
// ClientCA is the certificate bundle for all the signers that you'll recognize for incoming client certificates
|
||||||
|
ClientCA string
|
||||||
|
|
||||||
|
// ServerCA is the certificate bundle for the signer of your serving certificate. Used for building a loopback
|
||||||
|
// connection to the API server for admission.
|
||||||
|
ServerCA string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CertKey struct {
|
||||||
|
// CertFile is a file containing a PEM-encoded certificate
|
||||||
|
CertFile string
|
||||||
|
// KeyFile is a file containing a PEM-encoded private key for the certificate specified by CertFile
|
||||||
|
KeyFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
type GeneratableKeyCert struct {
|
||||||
|
CertKey CertKey
|
||||||
|
|
||||||
|
// CertDirectory is a directory that will contain the certificates. If the cert and key aren't specifically set
|
||||||
|
// this will be used to derive a match with the "pair-name"
|
||||||
|
CertDirectory string
|
||||||
|
// PairName is the name which will be used with CertDirectory to make a cert and key names
|
||||||
|
// It becomes CertDirector/PairName.crt and CertDirector/PairName.key
|
||||||
|
PairName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSecureServingOptions() *SecureServingOptions {
|
||||||
|
return &SecureServingOptions{
|
||||||
|
ServingOptions: ServingOptions{
|
||||||
|
BindAddress: net.ParseIP("0.0.0.0"),
|
||||||
|
BindPort: 6443,
|
||||||
|
},
|
||||||
|
ServerCert: GeneratableKeyCert{
|
||||||
|
PairName: "apiserver",
|
||||||
|
CertDirectory: "/var/run/kubernetes",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SecureServingOptions) NewSelfClientConfig(token string) *restclient.Config {
|
||||||
|
if s == nil || s.ServingOptions.BindPort <= 0 || len(s.ServerCA) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
clientConfig := &restclient.Config{
|
||||||
|
// Increase QPS limits. The client is currently passed to all admission plugins,
|
||||||
|
// and those can be throttled in case of higher load on apiserver - see #22340 and #22422
|
||||||
|
// for more details. Once #22422 is fixed, we may want to remove it.
|
||||||
|
QPS: 50,
|
||||||
|
Burst: 100,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use secure port if the ServerCA is specified
|
||||||
|
host := s.ServingOptions.BindAddress.String()
|
||||||
|
if host == "0.0.0.0" {
|
||||||
|
host = "localhost"
|
||||||
|
}
|
||||||
|
clientConfig.Host = "https://" + net.JoinHostPort(host, strconv.Itoa(s.ServingOptions.BindPort))
|
||||||
|
clientConfig.CAFile = s.ServerCA
|
||||||
|
clientConfig.BearerToken = token
|
||||||
|
|
||||||
|
return clientConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SecureServingOptions) Validate() []error {
|
||||||
|
errors := []error{}
|
||||||
|
if s == nil {
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
errors = append(errors, s.ServingOptions.Validate("secure-port")...)
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SecureServingOptions) AddFlags(fs *pflag.FlagSet) {
|
||||||
|
fs.IPVar(&s.ServingOptions.BindAddress, "bind-address", s.ServingOptions.BindAddress, ""+
|
||||||
|
"The IP address on which to listen for the --secure-port port. The "+
|
||||||
|
"associated interface(s) must be reachable by the rest of the cluster, and by CLI/web "+
|
||||||
|
"clients. If blank, all interfaces will be used (0.0.0.0).")
|
||||||
|
|
||||||
|
fs.IntVar(&s.ServingOptions.BindPort, "secure-port", s.ServingOptions.BindPort, ""+
|
||||||
|
"The port on which to serve HTTPS with authentication and authorization. If 0, "+
|
||||||
|
"don't serve HTTPS at all.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.ServerCert.CertDirectory, "cert-dir", s.ServerCert.CertDirectory, ""+
|
||||||
|
"The directory where the TLS certs are located (by default /var/run/kubernetes). "+
|
||||||
|
"If --tls-cert-file and --tls-private-key-file are provided, this flag will be ignored.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.ServerCert.CertKey.CertFile, "tls-cert-file", s.ServerCert.CertKey.CertFile, ""+
|
||||||
|
"File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated "+
|
||||||
|
"after server cert). If HTTPS serving is enabled, and --tls-cert-file and "+
|
||||||
|
"--tls-private-key-file are not provided, a self-signed certificate and key "+
|
||||||
|
"are generated for the public address and saved to /var/run/kubernetes.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.ServerCert.CertKey.KeyFile, "tls-private-key-file", s.ServerCert.CertKey.KeyFile,
|
||||||
|
"File containing the default x509 private key matching --tls-cert-file.")
|
||||||
|
|
||||||
|
fs.Var(config.NewNamedCertKeyArray(&s.SNICertKeys), "tls-sni-cert-key", ""+
|
||||||
|
"A pair of x509 certificate and private key file paths, optionally suffixed with a list of "+
|
||||||
|
"domain patterns which are fully qualified domain names, possibly with prefixed wildcard "+
|
||||||
|
"segments. If no domain patterns are provided, the names of the certificate are "+
|
||||||
|
"extracted. Non-wildcard matches trump over wildcard matches, explicit domain patterns "+
|
||||||
|
"trump over extracted names. For multiple key/certificate pairs, use the "+
|
||||||
|
"--tls-sni-cert-key multiple times. "+
|
||||||
|
"Examples: \"example.key,example.crt\" or \"*.foo.com,foo.com:foo.key,foo.crt\".")
|
||||||
|
|
||||||
|
fs.StringVar(&s.ClientCA, "client-ca-file", s.ClientCA, ""+
|
||||||
|
"If set, any request presenting a client certificate signed by one of "+
|
||||||
|
"the authorities in the client-ca-file is authenticated with an identity "+
|
||||||
|
"corresponding to the CommonName of the client certificate.")
|
||||||
|
|
||||||
|
fs.StringVar(&s.ServerCA, "tls-ca-file", s.ServerCA, "If set, this "+
|
||||||
|
"certificate authority will used for secure access from Admission "+
|
||||||
|
"Controllers. This must be a valid PEM-encoded CA bundle.")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SecureServingOptions) AddDeprecatedFlags(fs *pflag.FlagSet) {
|
||||||
|
fs.IPVar(&s.ServingOptions.BindAddress, "public-address-override", s.ServingOptions.BindAddress,
|
||||||
|
"DEPRECATED: see --bind-address instead.")
|
||||||
|
fs.MarkDeprecated("public-address-override", "see --bind-address instead.")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInsecureServingOptions() *ServingOptions {
|
||||||
|
return &ServingOptions{
|
||||||
|
BindAddress: net.ParseIP("127.0.0.1"),
|
||||||
|
BindPort: 8080,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ServingOptions) Validate(portArg string) []error {
|
||||||
|
errors := []error{}
|
||||||
|
|
||||||
|
if s.BindPort < 0 || s.BindPort > 65535 {
|
||||||
|
errors = append(errors, fmt.Errorf("--%v %v must be between 0 and 65535, inclusive. 0 for turning off secure port.", portArg, s.BindPort))
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServingOptions) NewSelfClientConfig(token string) *restclient.Config {
|
||||||
|
if s == nil || s.BindPort <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
clientConfig := &restclient.Config{
|
||||||
|
// Increase QPS limits. The client is currently passed to all admission plugins,
|
||||||
|
// and those can be throttled in case of higher load on apiserver - see #22340 and #22422
|
||||||
|
// for more details. Once #22422 is fixed, we may want to remove it.
|
||||||
|
QPS: 50,
|
||||||
|
Burst: 100,
|
||||||
|
}
|
||||||
|
|
||||||
|
clientConfig.Host = net.JoinHostPort(s.BindAddress.String(), strconv.Itoa(s.BindPort))
|
||||||
|
|
||||||
|
return clientConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServingOptions) DefaultExternalAddress() (net.IP, error) {
|
||||||
|
return utilnet.ChooseBindAddress(s.BindAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServingOptions) AddFlags(fs *pflag.FlagSet) {
|
||||||
|
fs.IPVar(&s.BindAddress, "insecure-bind-address", s.BindAddress, ""+
|
||||||
|
"The IP address on which to serve the --insecure-port (set to 0.0.0.0 for all interfaces). "+
|
||||||
|
"Defaults to localhost.")
|
||||||
|
|
||||||
|
fs.IntVar(&s.BindPort, "insecure-port", s.BindPort, ""+
|
||||||
|
"The port on which to serve unsecured, unauthenticated access. Default 8080. It is assumed "+
|
||||||
|
"that firewall rules are set up such that this port is not reachable from outside of "+
|
||||||
|
"the cluster and that port 443 on the cluster's public address is proxied to this "+
|
||||||
|
"port. This is performed by nginx in the default setup.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServingOptions) AddDeprecatedFlags(fs *pflag.FlagSet) {
|
||||||
|
fs.IPVar(&s.BindAddress, "address", s.BindAddress,
|
||||||
|
"DEPRECATED: see --insecure-bind-address instead.")
|
||||||
|
fs.MarkDeprecated("address", "see --insecure-bind-address instead.")
|
||||||
|
|
||||||
|
fs.IntVar(&s.BindPort, "port", s.BindPort, "DEPRECATED: see --insecure-port instead.")
|
||||||
|
fs.MarkDeprecated("port", "see --insecure-port instead.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a clientconfig which can be used to talk to this apiserver.
|
||||||
|
func NewSelfClientConfig(secureServingOptions *SecureServingOptions, insecureServingOptions *ServingOptions, token string) (*restclient.Config, error) {
|
||||||
|
if cfg := secureServingOptions.NewSelfClientConfig(token); cfg != nil {
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
if cfg := insecureServingOptions.NewSelfClientConfig(token); cfg != nil {
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("Unable to set url for apiserver local client")
|
||||||
|
}
|
@ -12,10 +12,7 @@ load(
|
|||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = ["universal_validation.go"],
|
||||||
"etcd_validation.go",
|
|
||||||
"universal_validation.go",
|
|
||||||
],
|
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/genericapiserver/options:go_default_library",
|
"//pkg/genericapiserver/options:go_default_library",
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 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 validation
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/options"
|
|
||||||
)
|
|
||||||
|
|
||||||
func VerifyEtcdServersList(options *options.ServerRunOptions) {
|
|
||||||
if len(options.StorageConfig.ServerList) == 0 {
|
|
||||||
glog.Fatalf("--etcd-servers must be specified")
|
|
||||||
}
|
|
||||||
}
|
|
@ -49,26 +49,6 @@ func verifyServiceNodePort(options *options.ServerRunOptions) []error {
|
|||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifySecureAndInsecurePort(options *options.ServerRunOptions) []error {
|
|
||||||
errors := []error{}
|
|
||||||
if options.SecurePort < 0 || options.SecurePort > 65535 {
|
|
||||||
errors = append(errors, fmt.Errorf("--secure-port %v must be between 0 and 65535, inclusive. 0 for turning off secure port.", options.SecurePort))
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.InsecurePort < 0 || options.InsecurePort > 65535 {
|
|
||||||
errors = append(errors, fmt.Errorf("--insecure-port %v must be between 0 and 65535, inclusive. 0 for turning off insecure port.", options.InsecurePort))
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.SecurePort == 0 && options.InsecurePort == 0 {
|
|
||||||
glog.Fatalf("--secure-port and --insecure-port cannot be turned off at the same time.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.SecurePort == options.InsecurePort {
|
|
||||||
errors = append(errors, fmt.Errorf("--secure-port and --insecure-port cannot use the same port."))
|
|
||||||
}
|
|
||||||
return errors
|
|
||||||
}
|
|
||||||
|
|
||||||
func ValidateRunOptions(options *options.ServerRunOptions) {
|
func ValidateRunOptions(options *options.ServerRunOptions) {
|
||||||
errors := []error{}
|
errors := []error{}
|
||||||
if errs := verifyClusterIPFlags(options); len(errs) > 0 {
|
if errs := verifyClusterIPFlags(options); len(errs) > 0 {
|
||||||
@ -77,9 +57,6 @@ func ValidateRunOptions(options *options.ServerRunOptions) {
|
|||||||
if errs := verifyServiceNodePort(options); len(errs) > 0 {
|
if errs := verifyServiceNodePort(options); len(errs) > 0 {
|
||||||
errors = append(errors, errs...)
|
errors = append(errors, errs...)
|
||||||
}
|
}
|
||||||
if errs := verifySecureAndInsecurePort(options); len(errs) > 0 {
|
|
||||||
errors = append(errors, errs...)
|
|
||||||
}
|
|
||||||
if err := utilerrors.NewAggregate(errors); err != nil {
|
if err := utilerrors.NewAggregate(errors); err != nil {
|
||||||
glog.Fatalf("Validate server run options failed: %v", err)
|
glog.Fatalf("Validate server run options failed: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ func NewAPIServer() *APIServer {
|
|||||||
// Start starts the apiserver, returns when apiserver is ready.
|
// Start starts the apiserver, returns when apiserver is ready.
|
||||||
func (a *APIServer) Start() error {
|
func (a *APIServer) Start() error {
|
||||||
config := options.NewServerRunOptions()
|
config := options.NewServerRunOptions()
|
||||||
config.GenericServerRunOptions.StorageConfig.ServerList = []string{getEtcdClientURL()}
|
config.Etcd.StorageConfig.ServerList = []string{getEtcdClientURL()}
|
||||||
_, ipnet, err := net.ParseCIDR(clusterIPRange)
|
_, ipnet, err := net.ParseCIDR(clusterIPRange)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -68,15 +68,15 @@ func runDiscoverySummarizer(t *testing.T) string {
|
|||||||
func runAPIServer(t *testing.T, stopCh <-chan struct{}) string {
|
func runAPIServer(t *testing.T, stopCh <-chan struct{}) string {
|
||||||
serverRunOptions := apiserver.NewServerRunOptions()
|
serverRunOptions := apiserver.NewServerRunOptions()
|
||||||
// Change the ports, because otherwise it will fail if examples/apiserver/apiserver_test and this are run in parallel.
|
// Change the ports, because otherwise it will fail if examples/apiserver/apiserver_test and this are run in parallel.
|
||||||
serverRunOptions.SecurePort = 6443 + 3
|
serverRunOptions.SecureServing.ServingOptions.BindPort = 6443 + 3
|
||||||
serverRunOptions.InsecurePort = 8080 + 3
|
serverRunOptions.InsecureServing.BindPort = 8080 + 3
|
||||||
go func() {
|
go func() {
|
||||||
if err := apiserver.Run(serverRunOptions, stopCh); err != nil {
|
if err := serverRunOptions.Run(stopCh); err != nil {
|
||||||
t.Fatalf("Error in bringing up the example apiserver: %v", err)
|
t.Fatalf("Error in bringing up the example apiserver: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
serverURL := fmt.Sprintf("http://localhost:%d", serverRunOptions.InsecurePort)
|
serverURL := fmt.Sprintf("http://localhost:%d", serverRunOptions.InsecureServing.BindPort)
|
||||||
if err := waitForServerUp(serverURL); err != nil {
|
if err := waitForServerUp(serverURL); err != nil {
|
||||||
t.Fatalf("%v", err)
|
t.Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ func TestRunServer(t *testing.T) {
|
|||||||
serverIP := fmt.Sprintf("http://localhost:%d", apiserver.InsecurePort)
|
serverIP := fmt.Sprintf("http://localhost:%d", apiserver.InsecurePort)
|
||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
if err := apiserver.Run(apiserver.NewServerRunOptions(), stopCh); err != nil {
|
if err := apiserver.NewServerRunOptions().Run(stopCh); err != nil {
|
||||||
t.Fatalf("Error in bringing up the server: %v", err)
|
t.Fatalf("Error in bringing up the server: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -63,9 +63,9 @@ func TestRunSecureServer(t *testing.T) {
|
|||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
options := apiserver.NewServerRunOptions()
|
options := apiserver.NewServerRunOptions()
|
||||||
options.InsecurePort = 0
|
options.InsecureServing.BindPort = 0
|
||||||
options.SecurePort = apiserver.SecurePort
|
options.SecureServing.ServingOptions.BindPort = apiserver.SecurePort
|
||||||
if err := apiserver.Run(options, stopCh); err != nil {
|
if err := options.Run(stopCh); err != nil {
|
||||||
t.Fatalf("Error in bringing up the server: %v", err)
|
t.Fatalf("Error in bringing up the server: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -88,11 +88,11 @@ var groupVersions = []schema.GroupVersion{
|
|||||||
|
|
||||||
func TestRun(t *testing.T) {
|
func TestRun(t *testing.T) {
|
||||||
s := options.NewServerRunOptions()
|
s := options.NewServerRunOptions()
|
||||||
s.GenericServerRunOptions.SecurePort = securePort
|
s.SecureServing.ServingOptions.BindPort = securePort
|
||||||
s.GenericServerRunOptions.InsecurePort = insecurePort
|
s.InsecureServing.BindPort = insecurePort
|
||||||
_, ipNet, _ := net.ParseCIDR("10.10.10.0/24")
|
_, ipNet, _ := net.ParseCIDR("10.10.10.0/24")
|
||||||
s.GenericServerRunOptions.ServiceClusterIPRange = *ipNet
|
s.GenericServerRunOptions.ServiceClusterIPRange = *ipNet
|
||||||
s.GenericServerRunOptions.StorageConfig.ServerList = []string{"http://localhost:2379"}
|
s.Etcd.StorageConfig.ServerList = []string{"http://localhost:2379"}
|
||||||
go func() {
|
go func() {
|
||||||
if err := app.Run(s); err != nil {
|
if err := app.Run(s); err != nil {
|
||||||
t.Fatalf("Error in bringing up the server: %v", err)
|
t.Fatalf("Error in bringing up the server: %v", err)
|
||||||
|
Loading…
Reference in New Issue
Block a user