mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-20 09:33:52 +00:00
allow multiple of --service-account-issuer
This commit is contained in:
@@ -63,7 +63,7 @@ type Config struct {
|
||||
OIDCRequiredClaims map[string]string
|
||||
ServiceAccountKeyFiles []string
|
||||
ServiceAccountLookup bool
|
||||
ServiceAccountIssuer string
|
||||
ServiceAccountIssuers []string
|
||||
APIAudiences authenticator.Audiences
|
||||
WebhookTokenAuthnConfigFile string
|
||||
WebhookTokenAuthnVersion string
|
||||
@@ -131,8 +131,8 @@ func (config Config) New() (authenticator.Request, *spec.SecurityDefinitions, er
|
||||
}
|
||||
tokenAuthenticators = append(tokenAuthenticators, serviceAccountAuth)
|
||||
}
|
||||
if config.ServiceAccountIssuer != "" {
|
||||
serviceAccountAuth, err := newServiceAccountAuthenticator(config.ServiceAccountIssuer, config.ServiceAccountKeyFiles, config.APIAudiences, config.ServiceAccountTokenGetter)
|
||||
if len(config.ServiceAccountIssuers) > 0 {
|
||||
serviceAccountAuth, err := newServiceAccountAuthenticator(config.ServiceAccountIssuers, config.ServiceAccountKeyFiles, config.APIAudiences, config.ServiceAccountTokenGetter)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -276,12 +276,12 @@ func newLegacyServiceAccountAuthenticator(keyfiles []string, lookup bool, apiAud
|
||||
allPublicKeys = append(allPublicKeys, publicKeys...)
|
||||
}
|
||||
|
||||
tokenAuthenticator := serviceaccount.JWTTokenAuthenticator(serviceaccount.LegacyIssuer, allPublicKeys, apiAudiences, serviceaccount.NewLegacyValidator(lookup, serviceAccountGetter))
|
||||
tokenAuthenticator := serviceaccount.JWTTokenAuthenticator([]string{serviceaccount.LegacyIssuer}, allPublicKeys, apiAudiences, serviceaccount.NewLegacyValidator(lookup, serviceAccountGetter))
|
||||
return tokenAuthenticator, nil
|
||||
}
|
||||
|
||||
// newServiceAccountAuthenticator returns an authenticator.Token or an error
|
||||
func newServiceAccountAuthenticator(iss string, keyfiles []string, apiAudiences authenticator.Audiences, serviceAccountGetter serviceaccount.ServiceAccountTokenGetter) (authenticator.Token, error) {
|
||||
func newServiceAccountAuthenticator(issuers []string, keyfiles []string, apiAudiences authenticator.Audiences, serviceAccountGetter serviceaccount.ServiceAccountTokenGetter) (authenticator.Token, error) {
|
||||
allPublicKeys := []interface{}{}
|
||||
for _, keyfile := range keyfiles {
|
||||
publicKeys, err := keyutil.PublicKeysFromFile(keyfile)
|
||||
@@ -291,7 +291,7 @@ func newServiceAccountAuthenticator(iss string, keyfiles []string, apiAudiences
|
||||
allPublicKeys = append(allPublicKeys, publicKeys...)
|
||||
}
|
||||
|
||||
tokenAuthenticator := serviceaccount.JWTTokenAuthenticator(iss, allPublicKeys, apiAudiences, serviceaccount.NewValidator(serviceAccountGetter))
|
||||
tokenAuthenticator := serviceaccount.JWTTokenAuthenticator(issuers, allPublicKeys, apiAudiences, serviceaccount.NewValidator(serviceAccountGetter))
|
||||
return tokenAuthenticator, nil
|
||||
}
|
||||
|
||||
|
@@ -87,7 +87,7 @@ type OIDCAuthenticationOptions struct {
|
||||
type ServiceAccountAuthenticationOptions struct {
|
||||
KeyFiles []string
|
||||
Lookup bool
|
||||
Issuer string
|
||||
Issuers []string
|
||||
JWKSURI string
|
||||
MaxExpiration time.Duration
|
||||
ExtendExpiration bool
|
||||
@@ -191,14 +191,29 @@ func (o *BuiltInAuthenticationOptions) Validate() []error {
|
||||
allErrors = append(allErrors, fmt.Errorf("oidc-issuer-url and oidc-client-id should be specified together"))
|
||||
}
|
||||
|
||||
if o.ServiceAccounts != nil && len(o.ServiceAccounts.Issuer) > 0 && strings.Contains(o.ServiceAccounts.Issuer, ":") {
|
||||
if _, err := url.Parse(o.ServiceAccounts.Issuer); err != nil {
|
||||
allErrors = append(allErrors, fmt.Errorf("service-account-issuer contained a ':' but was not a valid URL: %v", err))
|
||||
if o.ServiceAccounts != nil && len(o.ServiceAccounts.Issuers) > 0 {
|
||||
seen := make(map[string]bool)
|
||||
for _, issuer := range o.ServiceAccounts.Issuers {
|
||||
if strings.Contains(issuer, ":") {
|
||||
if _, err := url.Parse(issuer); err != nil {
|
||||
allErrors = append(allErrors, fmt.Errorf("service-account-issuer %q contained a ':' but was not a valid URL: %v", issuer, err))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if issuer == "" {
|
||||
allErrors = append(allErrors, fmt.Errorf("service-account-issuer should not be an empty string"))
|
||||
continue
|
||||
}
|
||||
if seen[issuer] {
|
||||
allErrors = append(allErrors, fmt.Errorf("service-account-issuer %q is already specified", issuer))
|
||||
continue
|
||||
}
|
||||
seen[issuer] = true
|
||||
}
|
||||
}
|
||||
|
||||
if o.ServiceAccounts != nil {
|
||||
if len(o.ServiceAccounts.Issuer) == 0 {
|
||||
if len(o.ServiceAccounts.Issuers) == 0 {
|
||||
allErrors = append(allErrors, errors.New("service-account-issuer is a required flag"))
|
||||
}
|
||||
if len(o.ServiceAccounts.KeyFiles) == 0 {
|
||||
@@ -308,7 +323,7 @@ func (o *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.BoolVar(&o.ServiceAccounts.Lookup, "service-account-lookup", o.ServiceAccounts.Lookup,
|
||||
"If true, validate ServiceAccount tokens exist in etcd as part of authentication.")
|
||||
|
||||
fs.StringVar(&o.ServiceAccounts.Issuer, "service-account-issuer", o.ServiceAccounts.Issuer, ""+
|
||||
fs.StringArrayVar(&o.ServiceAccounts.Issuers, "service-account-issuer", o.ServiceAccounts.Issuers, ""+
|
||||
"Identifier of the service account token issuer. The issuer will assert this identifier "+
|
||||
"in \"iss\" claim of issued tokens. This value is a string or URI. If this option is not "+
|
||||
"a valid URI per the OpenID Discovery 1.0 spec, the ServiceAccountIssuerDiscovery feature "+
|
||||
@@ -316,7 +331,9 @@ func (o *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
"that this value comply with the OpenID spec: https://openid.net/specs/openid-connect-discovery-1_0.html. "+
|
||||
"In practice, this means that service-account-issuer must be an https URL. It is also highly "+
|
||||
"recommended that this URL be capable of serving OpenID discovery documents at "+
|
||||
"{service-account-issuer}/.well-known/openid-configuration.")
|
||||
"{service-account-issuer}/.well-known/openid-configuration. "+
|
||||
"When this flag is specified multiple times, the first is used to generate tokens "+
|
||||
"and all are used to determine which issuers are accepted.")
|
||||
|
||||
fs.StringVar(&o.ServiceAccounts.JWKSURI, "service-account-jwks-uri", o.ServiceAccounts.JWKSURI, ""+
|
||||
"Overrides the URI for the JSON Web Key Set in the discovery doc served at "+
|
||||
@@ -406,11 +423,11 @@ func (o *BuiltInAuthenticationOptions) ToAuthenticationConfig() (kubeauthenticat
|
||||
|
||||
ret.APIAudiences = o.APIAudiences
|
||||
if o.ServiceAccounts != nil {
|
||||
if o.ServiceAccounts.Issuer != "" && len(o.APIAudiences) == 0 {
|
||||
ret.APIAudiences = authenticator.Audiences{o.ServiceAccounts.Issuer}
|
||||
if len(o.ServiceAccounts.Issuers) != 0 && len(o.APIAudiences) == 0 {
|
||||
ret.APIAudiences = authenticator.Audiences(o.ServiceAccounts.Issuers)
|
||||
}
|
||||
ret.ServiceAccountKeyFiles = o.ServiceAccounts.KeyFiles
|
||||
ret.ServiceAccountIssuer = o.ServiceAccounts.Issuer
|
||||
ret.ServiceAccountIssuers = o.ServiceAccounts.Issuers
|
||||
ret.ServiceAccountLookup = o.ServiceAccounts.Lookup
|
||||
}
|
||||
|
||||
@@ -464,8 +481,8 @@ func (o *BuiltInAuthenticationOptions) ApplyTo(authInfo *genericapiserver.Authen
|
||||
}
|
||||
|
||||
authInfo.APIAudiences = o.APIAudiences
|
||||
if o.ServiceAccounts != nil && o.ServiceAccounts.Issuer != "" && len(o.APIAudiences) == 0 {
|
||||
authInfo.APIAudiences = authenticator.Audiences{o.ServiceAccounts.Issuer}
|
||||
if o.ServiceAccounts != nil && len(o.ServiceAccounts.Issuers) != 0 && len(o.APIAudiences) == 0 {
|
||||
authInfo.APIAudiences = authenticator.Audiences(o.ServiceAccounts.Issuers)
|
||||
}
|
||||
|
||||
authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromClient(
|
||||
|
@@ -51,34 +51,10 @@ func TestAuthenticationValidate(t *testing.T) {
|
||||
ClientID: "testClientID",
|
||||
},
|
||||
testSA: &ServiceAccountAuthenticationOptions{
|
||||
Issuer: "http://foo.bar.com",
|
||||
Issuers: []string{"http://foo.bar.com"},
|
||||
KeyFiles: []string{"testkeyfile1", "testkeyfile2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "test when OIDC and ServiceAccounts are invalid",
|
||||
testOIDC: &OIDCAuthenticationOptions{
|
||||
UsernameClaim: "sub",
|
||||
SigningAlgs: []string{"RS256"},
|
||||
IssuerURL: "testIssuerURL",
|
||||
},
|
||||
testSA: &ServiceAccountAuthenticationOptions{
|
||||
Issuer: "http://foo.bar.com",
|
||||
},
|
||||
expectErr: "oidc-issuer-url and oidc-client-id should be specified together",
|
||||
},
|
||||
{
|
||||
name: "test when OIDC and ServiceAccounts are invalid",
|
||||
testOIDC: &OIDCAuthenticationOptions{
|
||||
UsernameClaim: "sub",
|
||||
SigningAlgs: []string{"RS256"},
|
||||
IssuerURL: "testIssuerURL",
|
||||
},
|
||||
testSA: &ServiceAccountAuthenticationOptions{
|
||||
Issuer: "http://foo.bar.com",
|
||||
},
|
||||
expectErr: "service-account-key-file is a required flag",
|
||||
},
|
||||
{
|
||||
name: "test when OIDC is invalid",
|
||||
testOIDC: &OIDCAuthenticationOptions{
|
||||
@@ -87,13 +63,13 @@ func TestAuthenticationValidate(t *testing.T) {
|
||||
IssuerURL: "testIssuerURL",
|
||||
},
|
||||
testSA: &ServiceAccountAuthenticationOptions{
|
||||
Issuer: "http://foo.bar.com",
|
||||
Issuers: []string{"http://foo.bar.com"},
|
||||
KeyFiles: []string{"testkeyfile1", "testkeyfile2"},
|
||||
},
|
||||
expectErr: "oidc-issuer-url and oidc-client-id should be specified together",
|
||||
},
|
||||
{
|
||||
name: "test when ServiceAccount is invalid",
|
||||
name: "test when ServiceAccounts doesn't have key file",
|
||||
testOIDC: &OIDCAuthenticationOptions{
|
||||
UsernameClaim: "sub",
|
||||
SigningAlgs: []string{"RS256"},
|
||||
@@ -101,9 +77,61 @@ func TestAuthenticationValidate(t *testing.T) {
|
||||
ClientID: "testClientID",
|
||||
},
|
||||
testSA: &ServiceAccountAuthenticationOptions{
|
||||
Issuer: "http://[::1]:namedport",
|
||||
Issuers: []string{"http://foo.bar.com"},
|
||||
},
|
||||
expectErr: "service-account-issuer contained a ':' but was not a valid URL",
|
||||
expectErr: "service-account-key-file is a required flag",
|
||||
},
|
||||
{
|
||||
name: "test when ServiceAccounts doesn't have issuer",
|
||||
testOIDC: &OIDCAuthenticationOptions{
|
||||
UsernameClaim: "sub",
|
||||
SigningAlgs: []string{"RS256"},
|
||||
IssuerURL: "testIssuerURL",
|
||||
ClientID: "testClientID",
|
||||
},
|
||||
testSA: &ServiceAccountAuthenticationOptions{
|
||||
Issuers: []string{},
|
||||
},
|
||||
expectErr: "service-account-issuer is a required flag",
|
||||
},
|
||||
{
|
||||
name: "test when ServiceAccounts has empty string as issuer",
|
||||
testOIDC: &OIDCAuthenticationOptions{
|
||||
UsernameClaim: "sub",
|
||||
SigningAlgs: []string{"RS256"},
|
||||
IssuerURL: "testIssuerURL",
|
||||
ClientID: "testClientID",
|
||||
},
|
||||
testSA: &ServiceAccountAuthenticationOptions{
|
||||
Issuers: []string{""},
|
||||
},
|
||||
expectErr: "service-account-issuer should not be an empty string",
|
||||
},
|
||||
{
|
||||
name: "test when ServiceAccounts has duplicate issuers",
|
||||
testOIDC: &OIDCAuthenticationOptions{
|
||||
UsernameClaim: "sub",
|
||||
SigningAlgs: []string{"RS256"},
|
||||
IssuerURL: "testIssuerURL",
|
||||
ClientID: "testClientID",
|
||||
},
|
||||
testSA: &ServiceAccountAuthenticationOptions{
|
||||
Issuers: []string{"http://foo.bar.com", "http://foo.bar.com"},
|
||||
},
|
||||
expectErr: "service-account-issuer \"http://foo.bar.com\" is already specified",
|
||||
},
|
||||
{
|
||||
name: "test when ServiceAccount has bad issuer",
|
||||
testOIDC: &OIDCAuthenticationOptions{
|
||||
UsernameClaim: "sub",
|
||||
SigningAlgs: []string{"RS256"},
|
||||
IssuerURL: "testIssuerURL",
|
||||
ClientID: "testClientID",
|
||||
},
|
||||
testSA: &ServiceAccountAuthenticationOptions{
|
||||
Issuers: []string{"http://[::1]:namedport"},
|
||||
},
|
||||
expectErr: "service-account-issuer \"http://[::1]:namedport\" contained a ':' but was not a valid URL",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -154,8 +182,8 @@ func TestToAuthenticationConfig(t *testing.T) {
|
||||
AllowedNames: []string{"kube-aggregator"},
|
||||
},
|
||||
ServiceAccounts: &ServiceAccountAuthenticationOptions{
|
||||
Lookup: true,
|
||||
Issuer: "http://foo.bar.com",
|
||||
Lookup: true,
|
||||
Issuers: []string{"http://foo.bar.com"},
|
||||
},
|
||||
TokenFile: &TokenFileAuthenticationOptions{
|
||||
TokenFile: "/testTokenFile",
|
||||
@@ -176,7 +204,7 @@ func TestToAuthenticationConfig(t *testing.T) {
|
||||
OIDCUsernameClaim: "sub",
|
||||
OIDCSigningAlgs: []string{"RS256"},
|
||||
ServiceAccountLookup: true,
|
||||
ServiceAccountIssuer: "http://foo.bar.com",
|
||||
ServiceAccountIssuers: []string{"http://foo.bar.com"},
|
||||
WebhookTokenAuthnConfigFile: "/token-webhook-config",
|
||||
WebhookTokenAuthnCacheTTL: 180000000000,
|
||||
|
||||
|
Reference in New Issue
Block a user