mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 15:05:27 +00:00
KEP-4633: Allow health-only anonymous auth mode.
Signed-off-by: Vinayak Goyal <vinaygo@google.com>
This commit is contained in:
parent
85ede67ac9
commit
5e6a4937f5
@ -243,9 +243,7 @@ func TestAddFlags(t *testing.T) {
|
||||
EnableContentionProfiling: true,
|
||||
},
|
||||
Authentication: &kubeoptions.BuiltInAuthenticationOptions{
|
||||
Anonymous: &kubeoptions.AnonymousAuthenticationOptions{
|
||||
Allow: false,
|
||||
},
|
||||
Anonymous: s.Authentication.Anonymous,
|
||||
ClientCert: &apiserveroptions.ClientCertAuthenticationOptions{
|
||||
ClientCA: "/client-ca",
|
||||
},
|
||||
@ -335,6 +333,6 @@ func TestAddFlags(t *testing.T) {
|
||||
s.Authorization.AreLegacyFlagsSet = nil
|
||||
|
||||
if !reflect.DeepEqual(expected, s) {
|
||||
t.Errorf("Got different run options than expected.\nDifference detected on:\n%s", cmp.Diff(expected, s, cmpopts.IgnoreUnexported(admission.Plugins{}, kubeoptions.OIDCAuthenticationOptions{})))
|
||||
t.Errorf("Got different run options than expected.\nDifference detected on:\n%s", cmp.Diff(expected, s, cmpopts.IgnoreUnexported(admission.Plugins{}, kubeoptions.OIDCAuthenticationOptions{}, kubeoptions.AnonymousAuthenticationOptions{})))
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
eventv1 "k8s.io/api/events/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
apiserveroptions "k8s.io/apiserver/pkg/server/options"
|
||||
cpconfig "k8s.io/cloud-provider/config"
|
||||
serviceconfig "k8s.io/cloud-provider/controllers/service/config"
|
||||
@ -430,6 +431,7 @@ func TestAddFlags(t *testing.T) {
|
||||
ExtraHeaderPrefixes: []string{"x-remote-extra-"},
|
||||
},
|
||||
RemoteKubeConfigFileOptional: true,
|
||||
Anonymous: &apiserver.AnonymousAuthConfig{Enabled: true},
|
||||
},
|
||||
Authorization: &apiserveroptions.DelegatingAuthorizationOptions{
|
||||
AllowCacheTTL: 10 * time.Second,
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"reflect"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticatorfactory"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
@ -77,7 +78,7 @@ func BuildAuthn(client authenticationclient.AuthenticationV1Interface, authn kub
|
||||
}
|
||||
|
||||
authenticatorConfig := authenticatorfactory.DelegatingAuthenticatorConfig{
|
||||
Anonymous: authn.Anonymous.Enabled,
|
||||
Anonymous: &apiserver.AnonymousAuthConfig{Enabled: authn.Anonymous.Enabled},
|
||||
CacheTTL: authn.Webhook.CacheTTL.Duration,
|
||||
ClientCertificateCAContentProvider: dynamicCAContentFromFile,
|
||||
}
|
||||
|
@ -35,9 +35,8 @@ import (
|
||||
cliflag "k8s.io/component-base/cli/flag"
|
||||
"k8s.io/component-base/logs"
|
||||
"k8s.io/component-base/metrics"
|
||||
netutils "k8s.io/utils/net"
|
||||
|
||||
kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
|
||||
netutils "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
func TestAddFlags(t *testing.T) {
|
||||
@ -229,9 +228,7 @@ func TestAddFlags(t *testing.T) {
|
||||
EnableContentionProfiling: true,
|
||||
},
|
||||
Authentication: &kubeoptions.BuiltInAuthenticationOptions{
|
||||
Anonymous: &kubeoptions.AnonymousAuthenticationOptions{
|
||||
Allow: false,
|
||||
},
|
||||
Anonymous: s.Authentication.Anonymous,
|
||||
ClientCert: &apiserveroptions.ClientCertAuthenticationOptions{
|
||||
ClientCA: "/client-ca",
|
||||
},
|
||||
@ -290,6 +287,6 @@ func TestAddFlags(t *testing.T) {
|
||||
s.Authorization.AreLegacyFlagsSet = nil
|
||||
|
||||
if !reflect.DeepEqual(expected, s) {
|
||||
t.Errorf("Got different run options than expected.\nDifference detected on:\n%s", cmp.Diff(expected, s, cmpopts.IgnoreUnexported(admission.Plugins{}, kubeoptions.OIDCAuthenticationOptions{})))
|
||||
t.Errorf("Got different run options than expected.\nDifference detected on:\n%s", cmp.Diff(expected, s, cmpopts.IgnoreUnexported(admission.Plugins{}, kubeoptions.OIDCAuthenticationOptions{}, kubeoptions.AnonymousAuthenticationOptions{})))
|
||||
}
|
||||
}
|
||||
|
@ -1203,6 +1203,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
||||
|
||||
genericfeatures.AggregatedDiscoveryEndpoint: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.33
|
||||
|
||||
genericfeatures.AnonymousAuthConfigurableEndpoints: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
genericfeatures.APIListChunking: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32
|
||||
|
||||
genericfeatures.APIPriorityAndFairness: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31
|
||||
|
@ -55,7 +55,10 @@ import (
|
||||
|
||||
// Config contains the data on how to authenticate a request to the Kube API Server
|
||||
type Config struct {
|
||||
Anonymous bool
|
||||
// Anonymous holds the effective anonymous config, specified either via config file
|
||||
// (hoisted out of AuthenticationConfig) or via flags (constructed from flag-specified values).
|
||||
Anonymous apiserver.AnonymousAuthConfig
|
||||
|
||||
BootstrapToken bool
|
||||
|
||||
TokenAuthFile string
|
||||
@ -212,8 +215,8 @@ func (config Config) New(serverLifecycle context.Context) (authenticator.Request
|
||||
}
|
||||
|
||||
if len(authenticators) == 0 {
|
||||
if config.Anonymous {
|
||||
return anonymous.NewAuthenticator(), nil, &securityDefinitionsV2, securitySchemesV3, nil
|
||||
if config.Anonymous.Enabled {
|
||||
return anonymous.NewAuthenticator(config.Anonymous.Conditions), nil, &securityDefinitionsV2, securitySchemesV3, nil
|
||||
}
|
||||
return nil, nil, &securityDefinitionsV2, securitySchemesV3, nil
|
||||
}
|
||||
@ -222,10 +225,10 @@ func (config Config) New(serverLifecycle context.Context) (authenticator.Request
|
||||
|
||||
authenticator = group.NewAuthenticatedGroupAdder(authenticator)
|
||||
|
||||
if config.Anonymous {
|
||||
if config.Anonymous.Enabled {
|
||||
// If the authenticator chain returns an error, return an error (don't consider a bad bearer token
|
||||
// or invalid username/password combination anonymous).
|
||||
authenticator = union.NewFailOnError(authenticator, anonymous.NewAuthenticator())
|
||||
authenticator = union.NewFailOnError(authenticator, anonymous.NewAuthenticator(config.Anonymous.Conditions))
|
||||
}
|
||||
|
||||
return authenticator, updateAuthenticationConfig, &securityDefinitionsV2, securitySchemesV3, nil
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@ -32,6 +33,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver/install"
|
||||
@ -95,7 +97,8 @@ type BuiltInAuthenticationOptions struct {
|
||||
|
||||
// AnonymousAuthenticationOptions contains anonymous authentication options for API Server
|
||||
type AnonymousAuthenticationOptions struct {
|
||||
Allow bool
|
||||
Allow bool
|
||||
areFlagsSet func() bool
|
||||
}
|
||||
|
||||
// BootstrapTokenAuthenticationOptions contains bootstrap token authentication options for API Server
|
||||
@ -169,7 +172,10 @@ func (o *BuiltInAuthenticationOptions) WithAll() *BuiltInAuthenticationOptions {
|
||||
|
||||
// WithAnonymous set default value for anonymous authentication
|
||||
func (o *BuiltInAuthenticationOptions) WithAnonymous() *BuiltInAuthenticationOptions {
|
||||
o.Anonymous = &AnonymousAuthenticationOptions{Allow: true}
|
||||
o.Anonymous = &AnonymousAuthenticationOptions{
|
||||
Allow: true,
|
||||
areFlagsSet: func() bool { return false },
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
@ -294,6 +300,14 @@ func (o *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
return
|
||||
}
|
||||
|
||||
fs.StringVar(&o.AuthenticationConfigFile, "authentication-config", o.AuthenticationConfigFile, ""+
|
||||
"File with Authentication Configuration to configure the JWT Token authenticator or the anonymous authenticator. "+
|
||||
"Note: This feature is in Alpha since v1.29."+
|
||||
"--feature-gate=StructuredAuthenticationConfiguration=true needs to be set for enabling this feature."+
|
||||
"This feature is mutually exclusive with the oidc-* flags."+
|
||||
"To configure anonymous authenticator you need to enable --feature-gate=AnonymousAuthConfigurableEndpoints."+
|
||||
"When you configure anonymous authenticator in the authentication config you cannot use the --anonymous-auth flag.")
|
||||
|
||||
fs.StringSliceVar(&o.APIAudiences, "api-audiences", o.APIAudiences, ""+
|
||||
"Identifiers of the API. The service account token authenticator will validate that "+
|
||||
"tokens used against the API are bound to at least one of these audiences. If the "+
|
||||
@ -305,6 +319,10 @@ func (o *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
"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.")
|
||||
|
||||
o.Anonymous.areFlagsSet = func() bool {
|
||||
return fs.Changed("anonymous-auth")
|
||||
}
|
||||
}
|
||||
|
||||
if o.BootstrapToken != nil {
|
||||
@ -358,12 +376,6 @@ func (o *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
"If set, the claim is verified to be present in the ID Token with a matching value. "+
|
||||
"Repeat this flag to specify multiple claims.")
|
||||
|
||||
fs.StringVar(&o.AuthenticationConfigFile, "authentication-config", o.AuthenticationConfigFile, ""+
|
||||
"File with Authentication Configuration to configure the JWT Token authenticator. "+
|
||||
"Note: This feature is in Alpha since v1.29."+
|
||||
"--feature-gate=StructuredAuthenticationConfiguration=true needs to be set for enabling this feature."+
|
||||
"This feature is mutually exclusive with the oidc-* flags.")
|
||||
|
||||
o.OIDC.areFlagsConfigured = func() bool {
|
||||
return fs.Changed(oidcIssuerURLFlag) ||
|
||||
fs.Changed(oidcClientIDFlag) ||
|
||||
@ -452,10 +464,6 @@ func (o *BuiltInAuthenticationOptions) ToAuthenticationConfig() (kubeauthenticat
|
||||
TokenFailureCacheTTL: o.TokenFailureCacheTTL,
|
||||
}
|
||||
|
||||
if o.Anonymous != nil {
|
||||
ret.Anonymous = o.Anonymous.Allow
|
||||
}
|
||||
|
||||
if o.BootstrapToken != nil {
|
||||
ret.BootstrapToken = o.BootstrapToken.Enable
|
||||
}
|
||||
@ -469,12 +477,18 @@ func (o *BuiltInAuthenticationOptions) ToAuthenticationConfig() (kubeauthenticat
|
||||
}
|
||||
|
||||
// When the StructuredAuthenticationConfiguration feature is enabled and the authentication config file is provided,
|
||||
// load the authentication config from the file.
|
||||
// load the authentication config from the file, otherwise set up an empty configuration.
|
||||
if len(o.AuthenticationConfigFile) > 0 {
|
||||
var err error
|
||||
if ret.AuthenticationConfig, ret.AuthenticationConfigData, err = loadAuthenticationConfig(o.AuthenticationConfigFile); err != nil {
|
||||
return kubeauthenticator.Config{}, err
|
||||
}
|
||||
} else {
|
||||
ret.AuthenticationConfig = &apiserver.AuthenticationConfiguration{}
|
||||
}
|
||||
|
||||
// Set up JWT authenticators from config file or from flags
|
||||
if len(o.AuthenticationConfigFile) > 0 {
|
||||
// all known signing algs are allowed when using authentication config
|
||||
// TODO: what we really want to express is 'any alg is fine as long it matches a public key'
|
||||
ret.OIDCSigningAlgs = oidc.AllValidSigningAlgorithms()
|
||||
@ -532,20 +546,30 @@ func (o *BuiltInAuthenticationOptions) ToAuthenticationConfig() (kubeauthenticat
|
||||
jwtAuthenticator.ClaimValidationRules = claimValidationRules
|
||||
}
|
||||
|
||||
authConfig := &apiserver.AuthenticationConfiguration{
|
||||
JWT: []apiserver.JWTAuthenticator{jwtAuthenticator},
|
||||
}
|
||||
ret.AuthenticationConfig.JWT = []apiserver.JWTAuthenticator{jwtAuthenticator}
|
||||
|
||||
ret.AuthenticationConfig = authConfig
|
||||
ret.OIDCSigningAlgs = o.OIDC.SigningAlgs
|
||||
}
|
||||
|
||||
if ret.AuthenticationConfig != nil {
|
||||
if err := apiservervalidation.ValidateAuthenticationConfiguration(ret.AuthenticationConfig, ret.ServiceAccountIssuers).ToAggregate(); err != nil {
|
||||
return kubeauthenticator.Config{}, err
|
||||
// Set up anonymous authenticator from config file or flags
|
||||
if o.Anonymous != nil {
|
||||
switch {
|
||||
case ret.AuthenticationConfig.Anonymous != nil && o.Anonymous.areFlagsSet():
|
||||
// Flags and config file are mutually exclusive
|
||||
return kubeauthenticator.Config{}, field.Forbidden(field.NewPath("anonymous"), "--anonynous-auth flag cannot be set when anonymous field is configured in authentication configuration file")
|
||||
case ret.AuthenticationConfig.Anonymous != nil:
|
||||
// Use the config-file-specified values
|
||||
ret.Anonymous = *ret.AuthenticationConfig.Anonymous
|
||||
default:
|
||||
// Use the flag-specified values
|
||||
ret.Anonymous = apiserver.AnonymousAuthConfig{Enabled: o.Anonymous.Allow}
|
||||
}
|
||||
}
|
||||
|
||||
if err := apiservervalidation.ValidateAuthenticationConfiguration(ret.AuthenticationConfig, ret.ServiceAccountIssuers).ToAggregate(); err != nil {
|
||||
return kubeauthenticator.Config{}, err
|
||||
}
|
||||
|
||||
if o.RequestHeader != nil {
|
||||
var err error
|
||||
ret.RequestHeaderConfig, err = o.RequestHeader.ToAuthenticationRequestHeaderConfig()
|
||||
@ -667,6 +691,10 @@ func (o *BuiltInAuthenticationOptions) ApplyTo(
|
||||
authenticationconfigmetrics.RegisterMetrics()
|
||||
trackedAuthenticationConfigData := authenticatorConfig.AuthenticationConfigData
|
||||
var mu sync.Mutex
|
||||
|
||||
// ensure anonymous config doesn't change on reload
|
||||
originalFileAnonymousConfig := authenticatorConfig.AuthenticationConfig.DeepCopy().Anonymous
|
||||
|
||||
go filesystem.WatchUntil(
|
||||
ctx,
|
||||
time.Minute,
|
||||
@ -700,7 +728,11 @@ func (o *BuiltInAuthenticationOptions) ApplyTo(
|
||||
return
|
||||
}
|
||||
|
||||
if err := apiservervalidation.ValidateAuthenticationConfiguration(authConfig, authenticatorConfig.ServiceAccountIssuers).ToAggregate(); err != nil {
|
||||
validationErrs := apiservervalidation.ValidateAuthenticationConfiguration(authConfig, authenticatorConfig.ServiceAccountIssuers)
|
||||
if !reflect.DeepEqual(originalFileAnonymousConfig, authConfig.Anonymous) {
|
||||
validationErrs = append(validationErrs, field.Forbidden(field.NewPath("anonymous"), "changed from initial configuration file"))
|
||||
}
|
||||
if err := validationErrs.ToAggregate(); err != nil {
|
||||
klog.ErrorS(err, "failed to validate authentication config")
|
||||
authenticationconfigmetrics.RecordAuthenticationConfigAutomaticReloadFailure(apiServerID)
|
||||
// this config is not semantically valid and never will be, update the tracker so we stop retrying
|
||||
|
@ -46,6 +46,7 @@ import (
|
||||
func TestAuthenticationValidate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
testAnonymous *AnonymousAuthenticationOptions
|
||||
testOIDC *OIDCAuthenticationOptions
|
||||
testSA *ServiceAccountAuthenticationOptions
|
||||
testWebHook *WebHookAuthenticationOptions
|
||||
@ -236,11 +237,21 @@ func TestAuthenticationValidate(t *testing.T) {
|
||||
disabledFeatures: []featuregate.Feature{kubefeatures.ServiceAccountTokenNodeBindingValidation},
|
||||
expectErr: "the \"ServiceAccountTokenNodeBinding\" feature gate can only be enabled if the \"ServiceAccountTokenNodeBindingValidation\" feature gate is also enabled",
|
||||
},
|
||||
{
|
||||
name: "test when authentication config file and anonymous-auth flags are set AnonymousAuthConfigurableEndpoints disabled",
|
||||
disabledFeatures: []featuregate.Feature{features.AnonymousAuthConfigurableEndpoints},
|
||||
testAuthenticationConfigFile: "configfile",
|
||||
testAnonymous: &AnonymousAuthenticationOptions{
|
||||
Allow: true,
|
||||
areFlagsSet: func() bool { return true },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testcase := range testCases {
|
||||
t.Run(testcase.name, func(t *testing.T) {
|
||||
options := NewBuiltInAuthenticationOptions()
|
||||
options.Anonymous = testcase.testAnonymous
|
||||
options.OIDC = testcase.testOIDC
|
||||
options.ServiceAccounts = testcase.testSA
|
||||
options.WebHook = testcase.testWebHook
|
||||
@ -304,7 +315,7 @@ func TestToAuthenticationConfig(t *testing.T) {
|
||||
|
||||
expectConfig := kubeauthenticator.Config{
|
||||
APIAudiences: authenticator.Audiences{"http://foo.bar.com"},
|
||||
Anonymous: false,
|
||||
Anonymous: apiserver.AnonymousAuthConfig{Enabled: false},
|
||||
BootstrapToken: false,
|
||||
ClientCAContentProvider: nil, // this is nil because you can't compare functions
|
||||
TokenAuthFile: "/testTokenFile",
|
||||
@ -455,8 +466,290 @@ func TestBuiltInAuthenticationOptionsAddFlags(t *testing.T) {
|
||||
// nil these out because you cannot compare functions
|
||||
opts.OIDC.areFlagsConfigured = nil
|
||||
|
||||
if !opts.Anonymous.areFlagsSet() {
|
||||
t.Fatalf("Anonymous flags should be configured")
|
||||
}
|
||||
|
||||
// nil these out because you cannot compare functions
|
||||
opts.Anonymous.areFlagsSet = nil
|
||||
|
||||
if !reflect.DeepEqual(opts, expected) {
|
||||
t.Error(cmp.Diff(opts, expected, cmp.AllowUnexported(OIDCAuthenticationOptions{})))
|
||||
t.Error(cmp.Diff(opts, expected, cmp.AllowUnexported(OIDCAuthenticationOptions{}, AnonymousAuthenticationOptions{})))
|
||||
}
|
||||
}
|
||||
|
||||
func TestToAuthenticationConfig_Anonymous(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StructuredAuthenticationConfiguration, true)
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
expectConfig kubeauthenticator.Config
|
||||
enableAnonymousEndpoints bool
|
||||
expectErr string
|
||||
}{
|
||||
{
|
||||
name: "flag-none",
|
||||
args: []string{},
|
||||
expectConfig: kubeauthenticator.Config{
|
||||
Anonymous: apiserver.AnonymousAuthConfig{Enabled: true},
|
||||
AuthenticationConfig: &apiserver.AuthenticationConfiguration{},
|
||||
TokenSuccessCacheTTL: 10 * time.Second,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "flag-anonymous-enabled",
|
||||
args: []string{"--anonymous-auth=True"},
|
||||
expectConfig: kubeauthenticator.Config{
|
||||
Anonymous: apiserver.AnonymousAuthConfig{Enabled: true},
|
||||
AuthenticationConfig: &apiserver.AuthenticationConfiguration{},
|
||||
TokenSuccessCacheTTL: 10 * time.Second,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "flag-anonymous-disabled",
|
||||
args: []string{"--anonymous-auth=False"},
|
||||
expectConfig: kubeauthenticator.Config{
|
||||
Anonymous: apiserver.AnonymousAuthConfig{Enabled: false},
|
||||
AuthenticationConfig: &apiserver.AuthenticationConfiguration{},
|
||||
TokenSuccessCacheTTL: 10 * time.Second,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "file-anonymous-disabled-AnonymousAuthConfigurableEndpoints-disabled",
|
||||
args: []string{
|
||||
"--authentication-config=" + writeTempFile(t, `
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: AuthenticationConfiguration
|
||||
anonymous:
|
||||
enabled: false
|
||||
`),
|
||||
},
|
||||
expectErr: "anonymous is not supported when when AnonymousAuthConfigurableEnpoints feature gate is disabled",
|
||||
},
|
||||
{
|
||||
name: "file-anonymous-disabled-AnonymousAuthConfigurableEndpoints-enabled",
|
||||
enableAnonymousEndpoints: true,
|
||||
args: []string{
|
||||
"--authentication-config=" + writeTempFile(t, `
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: AuthenticationConfiguration
|
||||
anonymous:
|
||||
enabled: false
|
||||
`),
|
||||
},
|
||||
expectConfig: kubeauthenticator.Config{
|
||||
Anonymous: apiserver.AnonymousAuthConfig{Enabled: false},
|
||||
TokenSuccessCacheTTL: 10 * time.Second,
|
||||
AuthenticationConfig: &apiserver.AuthenticationConfiguration{
|
||||
Anonymous: &apiserver.AnonymousAuthConfig{Enabled: false},
|
||||
},
|
||||
AuthenticationConfigData: `
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: AuthenticationConfiguration
|
||||
anonymous:
|
||||
enabled: false
|
||||
`,
|
||||
OIDCSigningAlgs: []string{"ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "RS384", "RS512"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "file-anonymous-enabled-AnonymousAuthConfigurableEndpoints-enabled",
|
||||
enableAnonymousEndpoints: true,
|
||||
args: []string{
|
||||
"--authentication-config=" + writeTempFile(t, `
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: AuthenticationConfiguration
|
||||
anonymous:
|
||||
enabled: true
|
||||
`),
|
||||
},
|
||||
expectConfig: kubeauthenticator.Config{
|
||||
Anonymous: apiserver.AnonymousAuthConfig{Enabled: true},
|
||||
TokenSuccessCacheTTL: 10 * time.Second,
|
||||
AuthenticationConfig: &apiserver.AuthenticationConfiguration{
|
||||
Anonymous: &apiserver.AnonymousAuthConfig{Enabled: true},
|
||||
},
|
||||
AuthenticationConfigData: `
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: AuthenticationConfiguration
|
||||
anonymous:
|
||||
enabled: true
|
||||
`,
|
||||
OIDCSigningAlgs: []string{"ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "RS384", "RS512"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "file-anonymous-disabled-with-conditions-AnonymousAuthConfigurableEndpoints-enabled",
|
||||
enableAnonymousEndpoints: true,
|
||||
args: []string{
|
||||
"--authentication-config=" + writeTempFile(t, `
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: AuthenticationConfiguration
|
||||
anonymous:
|
||||
enabled: false
|
||||
conditions:
|
||||
- path: "/livez"
|
||||
`),
|
||||
},
|
||||
expectErr: "enabled should be set to true when conditions are defined",
|
||||
},
|
||||
{
|
||||
name: "file-anonymous-missing-with-conditions-AnonymousAuthConfigurableEndpoints-enabled",
|
||||
enableAnonymousEndpoints: true,
|
||||
args: []string{
|
||||
"--authentication-config=" + writeTempFile(t, `
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: AuthenticationConfiguration
|
||||
anonymous:
|
||||
conditions:
|
||||
- path: "/livez"
|
||||
`),
|
||||
},
|
||||
expectErr: "enabled should be set to true when conditions are defined",
|
||||
},
|
||||
{
|
||||
name: "file-anonymous-enabled-with-conditions-AnonymousAuthConfigurableEndpoints-enabled",
|
||||
enableAnonymousEndpoints: true,
|
||||
args: []string{
|
||||
"--authentication-config=" + writeTempFile(t, `
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: AuthenticationConfiguration
|
||||
anonymous:
|
||||
enabled: true
|
||||
conditions:
|
||||
- path: "/livez"
|
||||
`),
|
||||
},
|
||||
expectConfig: kubeauthenticator.Config{
|
||||
Anonymous: apiserver.AnonymousAuthConfig{
|
||||
Enabled: true,
|
||||
Conditions: []apiserver.AnonymousAuthCondition{
|
||||
{
|
||||
Path: "/livez",
|
||||
},
|
||||
},
|
||||
},
|
||||
TokenSuccessCacheTTL: 10 * time.Second,
|
||||
AuthenticationConfig: &apiserver.AuthenticationConfiguration{
|
||||
Anonymous: &apiserver.AnonymousAuthConfig{
|
||||
Enabled: true,
|
||||
Conditions: []apiserver.AnonymousAuthCondition{
|
||||
{
|
||||
Path: "/livez",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AuthenticationConfigData: `
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: AuthenticationConfiguration
|
||||
anonymous:
|
||||
enabled: true
|
||||
conditions:
|
||||
- path: "/livez"
|
||||
`,
|
||||
OIDCSigningAlgs: []string{"ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "RS384", "RS512"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "flag-anonymous-enabled-file-anonymous-enabled-AnonymousAuthConfigurableEndpoints-enabled",
|
||||
enableAnonymousEndpoints: true,
|
||||
args: []string{"--anonymous-auth=True",
|
||||
"--authentication-config=" + writeTempFile(t, `
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: AuthenticationConfiguration
|
||||
anonymous:
|
||||
enabled: true
|
||||
`),
|
||||
},
|
||||
expectErr: "--anonynous-auth flag cannot be set when anonymous field is configured in authentication configuration file",
|
||||
},
|
||||
{
|
||||
name: "flag-anonymous-enabled-file-anonymous-notset-AnonymousAuthConfigurableEndpoints-enabled",
|
||||
enableAnonymousEndpoints: true,
|
||||
args: []string{"--anonymous-auth=True",
|
||||
"--authentication-config=" + writeTempFile(t, `
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: AuthenticationConfiguration
|
||||
jwt:
|
||||
- issuer:
|
||||
url: https://test-issuer
|
||||
audiences: [ "🐼" ]
|
||||
claimMappings:
|
||||
username:
|
||||
claim: sub
|
||||
prefix: ""
|
||||
`),
|
||||
},
|
||||
expectConfig: kubeauthenticator.Config{
|
||||
TokenSuccessCacheTTL: 10 * time.Second,
|
||||
Anonymous: apiserver.AnonymousAuthConfig{Enabled: true},
|
||||
AuthenticationConfig: &apiserver.AuthenticationConfiguration{
|
||||
JWT: []apiserver.JWTAuthenticator{
|
||||
{
|
||||
Issuer: apiserver.Issuer{
|
||||
URL: "https://test-issuer",
|
||||
Audiences: []string{"🐼"},
|
||||
},
|
||||
ClaimMappings: apiserver.ClaimMappings{
|
||||
Username: apiserver.PrefixedClaimOrExpression{
|
||||
Claim: "sub",
|
||||
Prefix: pointer.String(""),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AuthenticationConfigData: `
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: AuthenticationConfiguration
|
||||
jwt:
|
||||
- issuer:
|
||||
url: https://test-issuer
|
||||
audiences: [ "🐼" ]
|
||||
claimMappings:
|
||||
username:
|
||||
claim: sub
|
||||
prefix: ""
|
||||
`,
|
||||
OIDCSigningAlgs: []string{"ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "RS384", "RS512"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testcase := range testCases {
|
||||
t.Run(testcase.name, func(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AnonymousAuthConfigurableEndpoints, testcase.enableAnonymousEndpoints)
|
||||
opts := NewBuiltInAuthenticationOptions().WithAnonymous()
|
||||
pf := pflag.NewFlagSet("test-builtin-authentication-opts", pflag.ContinueOnError)
|
||||
opts.AddFlags(pf)
|
||||
|
||||
if err := pf.Parse(testcase.args); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resultConfig, err := opts.ToAuthenticationConfig()
|
||||
|
||||
if testcase.expectErr != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("Got err: %v; Want err: %v", err, testcase.expectErr)
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), testcase.expectErr) {
|
||||
t.Fatalf("Got err: %v; Want err: %v", err, testcase.expectErr)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(resultConfig, testcase.expectConfig) {
|
||||
t.Error(cmp.Diff(resultConfig, testcase.expectConfig))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,6 +165,25 @@ type AuthenticationConfiguration struct {
|
||||
metav1.TypeMeta
|
||||
|
||||
JWT []JWTAuthenticator
|
||||
|
||||
// If present --anonymous-auth must not be set
|
||||
Anonymous *AnonymousAuthConfig
|
||||
}
|
||||
|
||||
// AnonymousAuthConfig provides the configuration for the anonymous authenticator.
|
||||
type AnonymousAuthConfig struct {
|
||||
Enabled bool
|
||||
|
||||
// If set, anonymous auth is only allowed if the request meets one of the
|
||||
// conditions.
|
||||
Conditions []AnonymousAuthCondition
|
||||
}
|
||||
|
||||
// AnonymousAuthCondition describes the condition under which anonymous auth
|
||||
// should be enabled.
|
||||
type AnonymousAuthCondition struct {
|
||||
// Path for which anonymous auth is enabled.
|
||||
Path string
|
||||
}
|
||||
|
||||
// JWTAuthenticator provides the configuration for a single JWT authenticator.
|
||||
|
@ -185,6 +185,25 @@ type AuthenticationConfiguration struct {
|
||||
// "<username claim>": "username"
|
||||
// }
|
||||
JWT []JWTAuthenticator `json:"jwt"`
|
||||
|
||||
// If present --anonymous-auth must not be set
|
||||
Anonymous *AnonymousAuthConfig `json:"anonymous,omitempty"`
|
||||
}
|
||||
|
||||
// AnonymousAuthConfig provides the configuration for the anonymous authenticator.
|
||||
type AnonymousAuthConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// If set, anonymous auth is only allowed if the request meets one of the
|
||||
// conditions.
|
||||
Conditions []AnonymousAuthCondition `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
// AnonymousAuthCondition describes the condition under which anonymous auth
|
||||
// should be enabled.
|
||||
type AnonymousAuthCondition struct {
|
||||
// Path for which anonymous auth is enabled.
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator provides the configuration for a single JWT authenticator.
|
||||
|
@ -57,6 +57,26 @@ func RegisterConversions(s *runtime.Scheme) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*AnonymousAuthCondition)(nil), (*apiserver.AnonymousAuthCondition)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_AnonymousAuthCondition_To_apiserver_AnonymousAuthCondition(a.(*AnonymousAuthCondition), b.(*apiserver.AnonymousAuthCondition), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*apiserver.AnonymousAuthCondition)(nil), (*AnonymousAuthCondition)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_apiserver_AnonymousAuthCondition_To_v1alpha1_AnonymousAuthCondition(a.(*apiserver.AnonymousAuthCondition), b.(*AnonymousAuthCondition), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*AnonymousAuthConfig)(nil), (*apiserver.AnonymousAuthConfig)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_AnonymousAuthConfig_To_apiserver_AnonymousAuthConfig(a.(*AnonymousAuthConfig), b.(*apiserver.AnonymousAuthConfig), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*apiserver.AnonymousAuthConfig)(nil), (*AnonymousAuthConfig)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_apiserver_AnonymousAuthConfig_To_v1alpha1_AnonymousAuthConfig(a.(*apiserver.AnonymousAuthConfig), b.(*AnonymousAuthConfig), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*AuthenticationConfiguration)(nil), (*apiserver.AuthenticationConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_AuthenticationConfiguration_To_apiserver_AuthenticationConfiguration(a.(*AuthenticationConfiguration), b.(*apiserver.AuthenticationConfiguration), scope)
|
||||
}); err != nil {
|
||||
@ -324,6 +344,48 @@ func Convert_apiserver_AdmissionPluginConfiguration_To_v1alpha1_AdmissionPluginC
|
||||
return autoConvert_apiserver_AdmissionPluginConfiguration_To_v1alpha1_AdmissionPluginConfiguration(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_AnonymousAuthCondition_To_apiserver_AnonymousAuthCondition(in *AnonymousAuthCondition, out *apiserver.AnonymousAuthCondition, s conversion.Scope) error {
|
||||
out.Path = in.Path
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_AnonymousAuthCondition_To_apiserver_AnonymousAuthCondition is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_AnonymousAuthCondition_To_apiserver_AnonymousAuthCondition(in *AnonymousAuthCondition, out *apiserver.AnonymousAuthCondition, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_AnonymousAuthCondition_To_apiserver_AnonymousAuthCondition(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apiserver_AnonymousAuthCondition_To_v1alpha1_AnonymousAuthCondition(in *apiserver.AnonymousAuthCondition, out *AnonymousAuthCondition, s conversion.Scope) error {
|
||||
out.Path = in.Path
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_apiserver_AnonymousAuthCondition_To_v1alpha1_AnonymousAuthCondition is an autogenerated conversion function.
|
||||
func Convert_apiserver_AnonymousAuthCondition_To_v1alpha1_AnonymousAuthCondition(in *apiserver.AnonymousAuthCondition, out *AnonymousAuthCondition, s conversion.Scope) error {
|
||||
return autoConvert_apiserver_AnonymousAuthCondition_To_v1alpha1_AnonymousAuthCondition(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_AnonymousAuthConfig_To_apiserver_AnonymousAuthConfig(in *AnonymousAuthConfig, out *apiserver.AnonymousAuthConfig, s conversion.Scope) error {
|
||||
out.Enabled = in.Enabled
|
||||
out.Conditions = *(*[]apiserver.AnonymousAuthCondition)(unsafe.Pointer(&in.Conditions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_AnonymousAuthConfig_To_apiserver_AnonymousAuthConfig is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_AnonymousAuthConfig_To_apiserver_AnonymousAuthConfig(in *AnonymousAuthConfig, out *apiserver.AnonymousAuthConfig, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_AnonymousAuthConfig_To_apiserver_AnonymousAuthConfig(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apiserver_AnonymousAuthConfig_To_v1alpha1_AnonymousAuthConfig(in *apiserver.AnonymousAuthConfig, out *AnonymousAuthConfig, s conversion.Scope) error {
|
||||
out.Enabled = in.Enabled
|
||||
out.Conditions = *(*[]AnonymousAuthCondition)(unsafe.Pointer(&in.Conditions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_apiserver_AnonymousAuthConfig_To_v1alpha1_AnonymousAuthConfig is an autogenerated conversion function.
|
||||
func Convert_apiserver_AnonymousAuthConfig_To_v1alpha1_AnonymousAuthConfig(in *apiserver.AnonymousAuthConfig, out *AnonymousAuthConfig, s conversion.Scope) error {
|
||||
return autoConvert_apiserver_AnonymousAuthConfig_To_v1alpha1_AnonymousAuthConfig(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_AuthenticationConfiguration_To_apiserver_AuthenticationConfiguration(in *AuthenticationConfiguration, out *apiserver.AuthenticationConfiguration, s conversion.Scope) error {
|
||||
if in.JWT != nil {
|
||||
in, out := &in.JWT, &out.JWT
|
||||
@ -336,6 +398,7 @@ func autoConvert_v1alpha1_AuthenticationConfiguration_To_apiserver_Authenticatio
|
||||
} else {
|
||||
out.JWT = nil
|
||||
}
|
||||
out.Anonymous = (*apiserver.AnonymousAuthConfig)(unsafe.Pointer(in.Anonymous))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -356,6 +419,7 @@ func autoConvert_apiserver_AuthenticationConfiguration_To_v1alpha1_Authenticatio
|
||||
} else {
|
||||
out.JWT = nil
|
||||
}
|
||||
out.Anonymous = (*AnonymousAuthConfig)(unsafe.Pointer(in.Anonymous))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,43 @@ func (in *AdmissionPluginConfiguration) DeepCopy() *AdmissionPluginConfiguration
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AnonymousAuthCondition) DeepCopyInto(out *AnonymousAuthCondition) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AnonymousAuthCondition.
|
||||
func (in *AnonymousAuthCondition) DeepCopy() *AnonymousAuthCondition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AnonymousAuthCondition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AnonymousAuthConfig) DeepCopyInto(out *AnonymousAuthConfig) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]AnonymousAuthCondition, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AnonymousAuthConfig.
|
||||
func (in *AnonymousAuthConfig) DeepCopy() *AnonymousAuthConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AnonymousAuthConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AuthenticationConfiguration) DeepCopyInto(out *AuthenticationConfiguration) {
|
||||
*out = *in
|
||||
@ -89,6 +126,11 @@ func (in *AuthenticationConfiguration) DeepCopyInto(out *AuthenticationConfigura
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Anonymous != nil {
|
||||
in, out := &in.Anonymous, &out.Anonymous
|
||||
*out = new(AnonymousAuthConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -156,6 +156,25 @@ type AuthenticationConfiguration struct {
|
||||
// "<username claim>": "username"
|
||||
// }
|
||||
JWT []JWTAuthenticator `json:"jwt"`
|
||||
|
||||
// If present --anonymous-auth must not be set
|
||||
Anonymous *AnonymousAuthConfig `json:"anonymous,omitempty"`
|
||||
}
|
||||
|
||||
// AnonymousAuthConfig provides the configuration for the anonymous authenticator.
|
||||
type AnonymousAuthConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// If set, anonymous auth is only allowed if the request meets one of the
|
||||
// conditions.
|
||||
Conditions []AnonymousAuthCondition `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
// AnonymousAuthCondition describes the condition under which anonymous auth
|
||||
// should be enabled.
|
||||
type AnonymousAuthCondition struct {
|
||||
// Path for which anonymous auth is enabled.
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator provides the configuration for a single JWT authenticator.
|
||||
|
@ -37,6 +37,26 @@ func init() {
|
||||
// RegisterConversions adds conversion functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterConversions(s *runtime.Scheme) error {
|
||||
if err := s.AddGeneratedConversionFunc((*AnonymousAuthCondition)(nil), (*apiserver.AnonymousAuthCondition)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1beta1_AnonymousAuthCondition_To_apiserver_AnonymousAuthCondition(a.(*AnonymousAuthCondition), b.(*apiserver.AnonymousAuthCondition), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*apiserver.AnonymousAuthCondition)(nil), (*AnonymousAuthCondition)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_apiserver_AnonymousAuthCondition_To_v1beta1_AnonymousAuthCondition(a.(*apiserver.AnonymousAuthCondition), b.(*AnonymousAuthCondition), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*AnonymousAuthConfig)(nil), (*apiserver.AnonymousAuthConfig)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1beta1_AnonymousAuthConfig_To_apiserver_AnonymousAuthConfig(a.(*AnonymousAuthConfig), b.(*apiserver.AnonymousAuthConfig), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*apiserver.AnonymousAuthConfig)(nil), (*AnonymousAuthConfig)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_apiserver_AnonymousAuthConfig_To_v1beta1_AnonymousAuthConfig(a.(*apiserver.AnonymousAuthConfig), b.(*AnonymousAuthConfig), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*AuthenticationConfiguration)(nil), (*apiserver.AuthenticationConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1beta1_AuthenticationConfiguration_To_apiserver_AuthenticationConfiguration(a.(*AuthenticationConfiguration), b.(*apiserver.AuthenticationConfiguration), scope)
|
||||
}); err != nil {
|
||||
@ -260,6 +280,48 @@ func RegisterConversions(s *runtime.Scheme) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_AnonymousAuthCondition_To_apiserver_AnonymousAuthCondition(in *AnonymousAuthCondition, out *apiserver.AnonymousAuthCondition, s conversion.Scope) error {
|
||||
out.Path = in.Path
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_AnonymousAuthCondition_To_apiserver_AnonymousAuthCondition is an autogenerated conversion function.
|
||||
func Convert_v1beta1_AnonymousAuthCondition_To_apiserver_AnonymousAuthCondition(in *AnonymousAuthCondition, out *apiserver.AnonymousAuthCondition, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_AnonymousAuthCondition_To_apiserver_AnonymousAuthCondition(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apiserver_AnonymousAuthCondition_To_v1beta1_AnonymousAuthCondition(in *apiserver.AnonymousAuthCondition, out *AnonymousAuthCondition, s conversion.Scope) error {
|
||||
out.Path = in.Path
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_apiserver_AnonymousAuthCondition_To_v1beta1_AnonymousAuthCondition is an autogenerated conversion function.
|
||||
func Convert_apiserver_AnonymousAuthCondition_To_v1beta1_AnonymousAuthCondition(in *apiserver.AnonymousAuthCondition, out *AnonymousAuthCondition, s conversion.Scope) error {
|
||||
return autoConvert_apiserver_AnonymousAuthCondition_To_v1beta1_AnonymousAuthCondition(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_AnonymousAuthConfig_To_apiserver_AnonymousAuthConfig(in *AnonymousAuthConfig, out *apiserver.AnonymousAuthConfig, s conversion.Scope) error {
|
||||
out.Enabled = in.Enabled
|
||||
out.Conditions = *(*[]apiserver.AnonymousAuthCondition)(unsafe.Pointer(&in.Conditions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_AnonymousAuthConfig_To_apiserver_AnonymousAuthConfig is an autogenerated conversion function.
|
||||
func Convert_v1beta1_AnonymousAuthConfig_To_apiserver_AnonymousAuthConfig(in *AnonymousAuthConfig, out *apiserver.AnonymousAuthConfig, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_AnonymousAuthConfig_To_apiserver_AnonymousAuthConfig(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apiserver_AnonymousAuthConfig_To_v1beta1_AnonymousAuthConfig(in *apiserver.AnonymousAuthConfig, out *AnonymousAuthConfig, s conversion.Scope) error {
|
||||
out.Enabled = in.Enabled
|
||||
out.Conditions = *(*[]AnonymousAuthCondition)(unsafe.Pointer(&in.Conditions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_apiserver_AnonymousAuthConfig_To_v1beta1_AnonymousAuthConfig is an autogenerated conversion function.
|
||||
func Convert_apiserver_AnonymousAuthConfig_To_v1beta1_AnonymousAuthConfig(in *apiserver.AnonymousAuthConfig, out *AnonymousAuthConfig, s conversion.Scope) error {
|
||||
return autoConvert_apiserver_AnonymousAuthConfig_To_v1beta1_AnonymousAuthConfig(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_AuthenticationConfiguration_To_apiserver_AuthenticationConfiguration(in *AuthenticationConfiguration, out *apiserver.AuthenticationConfiguration, s conversion.Scope) error {
|
||||
if in.JWT != nil {
|
||||
in, out := &in.JWT, &out.JWT
|
||||
@ -272,6 +334,7 @@ func autoConvert_v1beta1_AuthenticationConfiguration_To_apiserver_Authentication
|
||||
} else {
|
||||
out.JWT = nil
|
||||
}
|
||||
out.Anonymous = (*apiserver.AnonymousAuthConfig)(unsafe.Pointer(in.Anonymous))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -292,6 +355,7 @@ func autoConvert_apiserver_AuthenticationConfiguration_To_v1beta1_Authentication
|
||||
} else {
|
||||
out.JWT = nil
|
||||
}
|
||||
out.Anonymous = (*AnonymousAuthConfig)(unsafe.Pointer(in.Anonymous))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,43 @@ import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AnonymousAuthCondition) DeepCopyInto(out *AnonymousAuthCondition) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AnonymousAuthCondition.
|
||||
func (in *AnonymousAuthCondition) DeepCopy() *AnonymousAuthCondition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AnonymousAuthCondition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AnonymousAuthConfig) DeepCopyInto(out *AnonymousAuthConfig) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]AnonymousAuthCondition, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AnonymousAuthConfig.
|
||||
func (in *AnonymousAuthConfig) DeepCopy() *AnonymousAuthConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AnonymousAuthConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AuthenticationConfiguration) DeepCopyInto(out *AuthenticationConfiguration) {
|
||||
*out = *in
|
||||
@ -36,6 +73,11 @@ func (in *AuthenticationConfiguration) DeepCopyInto(out *AuthenticationConfigura
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Anonymous != nil {
|
||||
in, out := &in.Anonymous, &out.Anonymous
|
||||
*out = new(AnonymousAuthConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,15 @@ func ValidateAuthenticationConfiguration(c *api.AuthenticationConfiguration, dis
|
||||
}
|
||||
}
|
||||
|
||||
if c.Anonymous != nil {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.AnonymousAuthConfigurableEndpoints) {
|
||||
allErrs = append(allErrs, field.Forbidden(field.NewPath("anonymous"), "anonymous is not supported when when AnonymousAuthConfigurableEnpoints feature gate is disabled"))
|
||||
}
|
||||
if !c.Anonymous.Enabled && len(c.Anonymous.Conditions) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(field.NewPath("anonymous", "conditions"), c.Anonymous.Conditions, "enabled should be set to true when conditions are defined"))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,43 @@ func (in *AdmissionPluginConfiguration) DeepCopy() *AdmissionPluginConfiguration
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AnonymousAuthCondition) DeepCopyInto(out *AnonymousAuthCondition) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AnonymousAuthCondition.
|
||||
func (in *AnonymousAuthCondition) DeepCopy() *AnonymousAuthCondition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AnonymousAuthCondition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AnonymousAuthConfig) DeepCopyInto(out *AnonymousAuthConfig) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]AnonymousAuthCondition, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AnonymousAuthConfig.
|
||||
func (in *AnonymousAuthConfig) DeepCopy() *AnonymousAuthConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AnonymousAuthConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AuthenticationConfiguration) DeepCopyInto(out *AuthenticationConfiguration) {
|
||||
*out = *in
|
||||
@ -111,6 +148,11 @@ func (in *AuthenticationConfiguration) DeepCopyInto(out *AuthenticationConfigura
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Anonymous != nil {
|
||||
in, out := &in.Anonymous, &out.Anonymous
|
||||
*out = new(AnonymousAuthConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/group"
|
||||
"k8s.io/apiserver/pkg/authentication/request/anonymous"
|
||||
@ -39,7 +40,7 @@ import (
|
||||
// DelegatingAuthenticatorConfig is the minimal configuration needed to create an authenticator
|
||||
// built to delegate authentication to a kube API server
|
||||
type DelegatingAuthenticatorConfig struct {
|
||||
Anonymous bool
|
||||
Anonymous *apiserver.AnonymousAuthConfig
|
||||
|
||||
// TokenAccessReviewClient is a client to do token review. It can be nil. Then every token is ignored.
|
||||
TokenAccessReviewClient authenticationclient.AuthenticationV1Interface
|
||||
@ -112,15 +113,15 @@ func (c DelegatingAuthenticatorConfig) New() (authenticator.Request, *spec.Secur
|
||||
}
|
||||
|
||||
if len(authenticators) == 0 {
|
||||
if c.Anonymous {
|
||||
return anonymous.NewAuthenticator(), &securityDefinitions, nil
|
||||
if c.Anonymous != nil && c.Anonymous.Enabled {
|
||||
return anonymous.NewAuthenticator(c.Anonymous.Conditions), &securityDefinitions, nil
|
||||
}
|
||||
return nil, nil, errors.New("No authentication method configured")
|
||||
return nil, nil, errors.New("no authentication method configured")
|
||||
}
|
||||
|
||||
authenticator := group.NewAuthenticatedGroupAdder(unionauth.New(authenticators...))
|
||||
if c.Anonymous {
|
||||
authenticator = unionauth.NewFailOnError(authenticator, anonymous.NewAuthenticator())
|
||||
if c.Anonymous != nil && c.Anonymous.Enabled {
|
||||
authenticator = unionauth.NewFailOnError(authenticator, anonymous.NewAuthenticator(c.Anonymous.Conditions))
|
||||
}
|
||||
return authenticator, &securityDefinitions, nil
|
||||
}
|
||||
|
@ -19,25 +19,44 @@ package anonymous
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
)
|
||||
|
||||
const (
|
||||
anonymousUser = user.Anonymous
|
||||
|
||||
anonymousUser = user.Anonymous
|
||||
unauthenticatedGroup = user.AllUnauthenticated
|
||||
)
|
||||
|
||||
func NewAuthenticator() authenticator.Request {
|
||||
return authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
|
||||
auds, _ := authenticator.AudiencesFrom(req.Context())
|
||||
return &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: anonymousUser,
|
||||
Groups: []string{unauthenticatedGroup},
|
||||
},
|
||||
Audiences: auds,
|
||||
}, true, nil
|
||||
})
|
||||
type Authenticator struct {
|
||||
allowedPaths map[string]bool
|
||||
}
|
||||
|
||||
func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) {
|
||||
if len(a.allowedPaths) > 0 && !a.allowedPaths[req.URL.Path] {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
auds, _ := authenticator.AudiencesFrom(req.Context())
|
||||
return &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: anonymousUser,
|
||||
Groups: []string{unauthenticatedGroup},
|
||||
},
|
||||
Audiences: auds,
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
// NewAuthenticator returns a new anonymous authenticator.
|
||||
// When conditions is empty all requests are authenticated as anonymous.
|
||||
// When conditions are non-empty only those requests that match the at-least one
|
||||
// condition are authenticated as anonymous.
|
||||
func NewAuthenticator(conditions []apiserver.AnonymousAuthCondition) authenticator.Request {
|
||||
allowedPaths := make(map[string]bool)
|
||||
for _, c := range conditions {
|
||||
allowedPaths[c.Path] = true
|
||||
}
|
||||
|
||||
return &Authenticator{allowedPaths: allowedPaths}
|
||||
}
|
||||
|
@ -18,15 +18,16 @@ package anonymous
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
)
|
||||
|
||||
func TestAnonymous(t *testing.T) {
|
||||
var a authenticator.Request = NewAuthenticator()
|
||||
a := NewAuthenticator(nil)
|
||||
r, ok, err := a.AuthenticateRequest(&http.Request{})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
@ -41,3 +42,85 @@ func TestAnonymous(t *testing.T) {
|
||||
t.Fatalf("Expected group %s, got %v", user.AllUnauthenticated, r.User.GetGroups())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnonymousRestricted(t *testing.T) {
|
||||
a := NewAuthenticator([]apiserver.AnonymousAuthCondition{
|
||||
{
|
||||
Path: "/healthz",
|
||||
},
|
||||
{
|
||||
Path: "/readyz",
|
||||
},
|
||||
{
|
||||
Path: "/livez",
|
||||
},
|
||||
})
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
path string
|
||||
want user.DefaultInfo
|
||||
wantAllowed bool
|
||||
}{
|
||||
{
|
||||
desc: "/healthz",
|
||||
path: "https://123.123.123.123/healthz",
|
||||
want: user.DefaultInfo{
|
||||
Name: anonymousUser,
|
||||
Groups: []string{unauthenticatedGroup},
|
||||
},
|
||||
wantAllowed: true,
|
||||
},
|
||||
{
|
||||
desc: "/readyz",
|
||||
path: "https://123.123.123.123/readyz",
|
||||
want: user.DefaultInfo{
|
||||
Name: anonymousUser,
|
||||
Groups: []string{unauthenticatedGroup},
|
||||
},
|
||||
wantAllowed: true,
|
||||
},
|
||||
{
|
||||
desc: "/livez",
|
||||
path: "https://123.123.123.123/livez",
|
||||
want: user.DefaultInfo{
|
||||
Name: anonymousUser,
|
||||
Groups: []string{unauthenticatedGroup},
|
||||
},
|
||||
wantAllowed: true,
|
||||
},
|
||||
{
|
||||
desc: "/api",
|
||||
path: "https://123.123.123.123/api",
|
||||
wantAllowed: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
u, err := url.Parse(tc.path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r, allowed, err := a.AuthenticateRequest(&http.Request{URL: u})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if tc.wantAllowed != allowed {
|
||||
t.Fatalf("want allowed: %v, got allowed: %v", tc.wantAllowed, allowed)
|
||||
}
|
||||
|
||||
if !tc.wantAllowed {
|
||||
return
|
||||
}
|
||||
|
||||
if r.User.GetName() != tc.want.Name {
|
||||
t.Fatalf("Expected username %s, got %s", user.Anonymous, r.User.GetName())
|
||||
}
|
||||
if !sets.NewString(r.User.GetGroups()...).Equal(sets.NewString(tc.want.Groups...)) {
|
||||
t.Fatalf("Expected group %s, got %v", tc.want.Groups, r.User.GetGroups())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -487,7 +487,7 @@ func TestUnauthenticatedHTTP2ClientConnectionClose(t *testing.T) {
|
||||
case "error":
|
||||
return nil, false, errors.New("authn err")
|
||||
case "anonymous":
|
||||
return anonymous.NewAuthenticator().AuthenticateRequest(r)
|
||||
return anonymous.NewAuthenticator(nil).AuthenticateRequest(r)
|
||||
case "anonymous_group":
|
||||
return &authenticator.Response{User: &user.DefaultInfo{Groups: []string{user.AllUnauthenticated}}}, true, nil
|
||||
default:
|
||||
|
@ -53,6 +53,13 @@ const (
|
||||
// caching with ETags containing all APIResources known to the apiserver.
|
||||
AggregatedDiscoveryEndpoint featuregate.Feature = "AggregatedDiscoveryEndpoint"
|
||||
|
||||
// owner: @vinayakankugoyal
|
||||
// kep: https://kep.k8s.io/4633
|
||||
// alpha: v1.31
|
||||
//
|
||||
// Allows us to enable anonymous auth for only certain apiserver endpoints.
|
||||
AnonymousAuthConfigurableEndpoints featuregate.Feature = "AnonymousAuthConfigurableEndpoints"
|
||||
|
||||
// owner: @smarterclayton
|
||||
// alpha: v1.8
|
||||
// beta: v1.9
|
||||
@ -329,6 +336,8 @@ func init() {
|
||||
// available throughout Kubernetes binaries.
|
||||
var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
|
||||
|
||||
AnonymousAuthConfigurableEndpoints: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
AggregatedDiscoveryEndpoint: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.33
|
||||
|
||||
AdmissionWebhookMatchConditions: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.33
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticatorfactory"
|
||||
"k8s.io/apiserver/pkg/authentication/request/headerrequest"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
@ -222,8 +223,8 @@ type DelegatingAuthenticationOptions struct {
|
||||
// CustomRoundTripperFn allows for specifying a middleware function for custom HTTP behaviour for the authentication webhook client.
|
||||
CustomRoundTripperFn transport.WrapperFunc
|
||||
|
||||
// DisableAnonymous gives user an option to disable Anonymous authentication.
|
||||
DisableAnonymous bool
|
||||
// Anonymous gives user an option to enable/disable Anonymous authentication.
|
||||
Anonymous *apiserver.AnonymousAuthConfig
|
||||
}
|
||||
|
||||
func NewDelegatingAuthenticationOptions() *DelegatingAuthenticationOptions {
|
||||
@ -238,6 +239,7 @@ func NewDelegatingAuthenticationOptions() *DelegatingAuthenticationOptions {
|
||||
},
|
||||
WebhookRetryBackoff: DefaultAuthWebhookRetryBackoff(),
|
||||
TokenRequestTimeout: 10 * time.Second,
|
||||
Anonymous: &apiserver.AnonymousAuthConfig{Enabled: true},
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,7 +307,7 @@ func (s *DelegatingAuthenticationOptions) ApplyTo(authenticationInfo *server.Aut
|
||||
}
|
||||
|
||||
cfg := authenticatorfactory.DelegatingAuthenticatorConfig{
|
||||
Anonymous: !s.DisableAnonymous,
|
||||
Anonymous: &apiserver.AnonymousAuthConfig{Enabled: true},
|
||||
CacheTTL: s.CacheTTL,
|
||||
WebhookRetryBackoff: s.WebhookRetryBackoff,
|
||||
TokenAccessReviewTimeout: s.TokenRequestTimeout,
|
||||
|
@ -298,7 +298,7 @@ func (fakeAuthProviderConfigPersister) Persist(map[string]string) error {
|
||||
|
||||
var fakeAuthProviderConfigPersisterError = errors.New("fakeAuthProviderConfigPersisterError")
|
||||
|
||||
func TestAnonymousConfig(t *testing.T) {
|
||||
func TestAnonymousAuthConfig(t *testing.T) {
|
||||
f := fuzz.New().NilChance(0.0).NumElements(1, 1)
|
||||
f.Funcs(
|
||||
func(r *runtime.Codec, f fuzz.Continue) {
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/spf13/pflag"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
apiserverapis "k8s.io/apiserver/pkg/apis/apiserver"
|
||||
apiserver "k8s.io/apiserver/pkg/server"
|
||||
apiserveroptions "k8s.io/apiserver/pkg/server/options"
|
||||
appconfig "k8s.io/cloud-provider/app/config"
|
||||
@ -136,6 +137,7 @@ func TestDefaultFlags(t *testing.T) {
|
||||
ExtraHeaderPrefixes: []string{"x-remote-extra-"},
|
||||
},
|
||||
RemoteKubeConfigFileOptional: true,
|
||||
Anonymous: &apiserverapis.AnonymousAuthConfig{Enabled: true},
|
||||
},
|
||||
Authorization: &apiserveroptions.DelegatingAuthorizationOptions{
|
||||
AllowCacheTTL: 10 * time.Second,
|
||||
@ -295,6 +297,7 @@ func TestAddFlags(t *testing.T) {
|
||||
ExtraHeaderPrefixes: []string{"x-remote-extra-"},
|
||||
},
|
||||
RemoteKubeConfigFileOptional: true,
|
||||
Anonymous: &apiserverapis.AnonymousAuthConfig{Enabled: true},
|
||||
},
|
||||
Authorization: &apiserveroptions.DelegatingAuthorizationOptions{
|
||||
AllowCacheTTL: 10 * time.Second,
|
||||
|
Loading…
Reference in New Issue
Block a user