diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 27880351ab..82d47f3d01 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -360,7 +360,11 @@ func CreateKubeAPIServerConfig( } } - issuer = serviceaccount.JWTTokenGenerator(s.Authentication.ServiceAccounts.Issuer, sk) + issuer, err = serviceaccount.JWTTokenGenerator(s.Authentication.ServiceAccounts.Issuer, sk) + if err != nil { + lastErr = fmt.Errorf("failed to build token generator: %v", err) + return + } apiAudiences = s.Authentication.ServiceAccounts.APIAudiences maxExpiration = s.Authentication.ServiceAccounts.MaxExpiration } diff --git a/cmd/kube-controller-manager/app/controllermanager.go b/cmd/kube-controller-manager/app/controllermanager.go index ad74c7ada3..aefbd6dac6 100644 --- a/cmd/kube-controller-manager/app/controllermanager.go +++ b/cmd/kube-controller-manager/app/controllermanager.go @@ -516,12 +516,16 @@ func (c serviceAccountTokenControllerStarter) startServiceAccountTokenController rootCA = c.rootClientBuilder.ConfigOrDie("tokens-controller").CAData } + tokenGenerator, err := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, privateKey) + if err != nil { + return nil, false, fmt.Errorf("failed to build token generator: %v", err) + } controller, err := serviceaccountcontroller.NewTokensController( ctx.InformerFactory.Core().V1().ServiceAccounts(), ctx.InformerFactory.Core().V1().Secrets(), c.rootClientBuilder.ClientOrDie("tokens-controller"), serviceaccountcontroller.TokensControllerOptions{ - TokenGenerator: serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, privateKey), + TokenGenerator: tokenGenerator, RootCA: rootCA, }, ) diff --git a/pkg/serviceaccount/jwt.go b/pkg/serviceaccount/jwt.go index 73960d7f13..3a3c7cb005 100644 --- a/pkg/serviceaccount/jwt.go +++ b/pkg/serviceaccount/jwt.go @@ -54,25 +54,13 @@ type TokenGenerator interface { // JWTTokenGenerator returns a TokenGenerator that generates signed JWT tokens, using the given privateKey. // privateKey is a PEM-encoded byte array of a private RSA key. // JWTTokenAuthenticator() -func JWTTokenGenerator(iss string, privateKey interface{}) TokenGenerator { - return &jwtTokenGenerator{ - iss: iss, - privateKey: privateKey, - } -} - -type jwtTokenGenerator struct { - iss string - privateKey interface{} -} - -func (j *jwtTokenGenerator) GenerateToken(claims *jwt.Claims, privateClaims interface{}) (string, error) { +func JWTTokenGenerator(iss string, privateKey interface{}) (TokenGenerator, error) { var alg jose.SignatureAlgorithm - switch privateKey := j.privateKey.(type) { + switch pk := privateKey.(type) { case *rsa.PrivateKey: alg = jose.RS256 case *ecdsa.PrivateKey: - switch privateKey.Curve { + switch pk.Curve { case elliptic.P256(): alg = jose.ES256 case elliptic.P384(): @@ -80,25 +68,38 @@ func (j *jwtTokenGenerator) GenerateToken(claims *jwt.Claims, privateClaims inte case elliptic.P521(): alg = jose.ES512 default: - return "", fmt.Errorf("unknown private key curve, must be 256, 384, or 521") + return nil, fmt.Errorf("unknown private key curve, must be 256, 384, or 521") } + case jose.OpaqueSigner: + alg = jose.SignatureAlgorithm(pk.Public().Algorithm) default: - return "", fmt.Errorf("unknown private key type %T, must be *rsa.PrivateKey or *ecdsa.PrivateKey", j.privateKey) + return nil, fmt.Errorf("unknown private key type %T, must be *rsa.PrivateKey, *ecdsa.PrivateKey, or jose.OpaqueSigner", privateKey) } signer, err := jose.NewSigner( jose.SigningKey{ Algorithm: alg, - Key: j.privateKey, + Key: privateKey, }, nil, ) if err != nil { - return "", err + return nil, err } + return &jwtTokenGenerator{ + iss: iss, + signer: signer, + }, nil +} +type jwtTokenGenerator struct { + iss string + signer jose.Signer +} + +func (j *jwtTokenGenerator) GenerateToken(claims *jwt.Claims, privateClaims interface{}) (string, error) { // claims are applied in reverse precedence - return jwt.Signed(signer). + return jwt.Signed(j.signer). Claims(privateClaims). Claims(claims). Claims(&jwt.Claims{ diff --git a/pkg/serviceaccount/jwt_test.go b/pkg/serviceaccount/jwt_test.go index 0f0c52f0f1..4f7d82e288 100644 --- a/pkg/serviceaccount/jwt_test.go +++ b/pkg/serviceaccount/jwt_test.go @@ -127,7 +127,10 @@ func TestTokenGenerateAndValidate(t *testing.T) { } // Generate the RSA token - rsaGenerator := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, getPrivateKey(rsaPrivateKey)) + rsaGenerator, err := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, getPrivateKey(rsaPrivateKey)) + if err != nil { + t.Fatalf("error making generator: %v", err) + } rsaToken, err := rsaGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *rsaSecret)) if err != nil { t.Fatalf("error generating token: %v", err) @@ -140,7 +143,10 @@ func TestTokenGenerateAndValidate(t *testing.T) { } // Generate the ECDSA token - ecdsaGenerator := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, getPrivateKey(ecdsaPrivateKey)) + ecdsaGenerator, err := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, getPrivateKey(ecdsaPrivateKey)) + if err != nil { + t.Fatalf("error making generator: %v", err) + } ecdsaToken, err := ecdsaGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *ecdsaSecret)) if err != nil { t.Fatalf("error generating token: %v", err) @@ -153,7 +159,10 @@ func TestTokenGenerateAndValidate(t *testing.T) { } // Generate signer with same keys as RSA signer but different issuer - badIssuerGenerator := serviceaccount.JWTTokenGenerator("foo", getPrivateKey(rsaPrivateKey)) + badIssuerGenerator, err := serviceaccount.JWTTokenGenerator("foo", getPrivateKey(rsaPrivateKey)) + if err != nil { + t.Fatalf("error making generator: %v", err) + } badIssuerToken, err := badIssuerGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *rsaSecret)) if err != nil { t.Fatalf("error generating token: %v", err) diff --git a/test/integration/auth/svcaccttoken_test.go b/test/integration/auth/svcaccttoken_test.go index 0978de010b..6ab3d7bf20 100644 --- a/test/integration/auth/svcaccttoken_test.go +++ b/test/integration/auth/svcaccttoken_test.go @@ -81,7 +81,11 @@ func TestServiceAccountTokenCreate(t *testing.T) { serviceaccount.NewValidator(aud, serviceaccountgetter.NewGetterFromClient(gcs)), ), ) - masterConfig.ExtraConfig.ServiceAccountIssuer = serviceaccount.JWTTokenGenerator(iss, sk) + tokenGenerator, err := serviceaccount.JWTTokenGenerator(iss, sk) + if err != nil { + t.Fatalf("err: %v", err) + } + masterConfig.ExtraConfig.ServiceAccountIssuer = tokenGenerator masterConfig.ExtraConfig.ServiceAccountAPIAudiences = aud masterConfig.ExtraConfig.ServiceAccountMaxExpiration = maxExpirationDuration diff --git a/test/integration/serviceaccount/service_account_test.go b/test/integration/serviceaccount/service_account_test.go index 52d957ca11..23a41d5338 100644 --- a/test/integration/serviceaccount/service_account_test.go +++ b/test/integration/serviceaccount/service_account_test.go @@ -436,11 +436,15 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie apiServer.Close() } + tokenGenerator, err := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, serviceAccountKey) + if err != nil { + return rootClientset, clientConfig, stop, err + } tokenController, err := serviceaccountcontroller.NewTokensController( informers.Core().V1().ServiceAccounts(), informers.Core().V1().Secrets(), rootClientset, - serviceaccountcontroller.TokensControllerOptions{TokenGenerator: serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, serviceAccountKey)}, + serviceaccountcontroller.TokensControllerOptions{TokenGenerator: tokenGenerator}, ) if err != nil { return rootClientset, clientConfig, stop, err