From c0bbdeda220090aa75f373983bae4b370e8d6a1a Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Wed, 15 Jul 2015 08:53:21 -0400 Subject: [PATCH] Add CA data to service account tokens if missing or different --- pkg/serviceaccount/tokens_controller.go | 26 ++++++--- pkg/serviceaccount/tokens_controller_test.go | 60 ++++++++++++++++++-- 2 files changed, 74 insertions(+), 12 deletions(-) diff --git a/pkg/serviceaccount/tokens_controller.go b/pkg/serviceaccount/tokens_controller.go index 5462781c3c..a680f38e64 100644 --- a/pkg/serviceaccount/tokens_controller.go +++ b/pkg/serviceaccount/tokens_controller.go @@ -17,6 +17,7 @@ limitations under the License. package serviceaccount import ( + "bytes" "fmt" "time" @@ -336,22 +337,31 @@ func (e *TokensController) generateTokenIfNeeded(serviceAccount *api.ServiceAcco secret.Data = map[string][]byte{} } - tokenData, ok := secret.Data[api.ServiceAccountTokenKey] - if ok && len(tokenData) > 0 { + caData := secret.Data[api.ServiceAccountRootCAKey] + needsCA := len(e.rootCA) > 0 && bytes.Compare(caData, e.rootCA) != 0 + + tokenData := secret.Data[api.ServiceAccountTokenKey] + needsToken := len(tokenData) == 0 + + if !needsCA && !needsToken { return nil } - if e.rootCA != nil && len(e.rootCA) > 0 { + + // Set the CA + if needsCA { secret.Data[api.ServiceAccountRootCAKey] = e.rootCA } // Generate the token - token, err := e.token.GenerateToken(*serviceAccount, *secret) - if err != nil { - return err + if needsToken { + token, err := e.token.GenerateToken(*serviceAccount, *secret) + if err != nil { + return err + } + secret.Data[api.ServiceAccountTokenKey] = []byte(token) } - // Set the token and annotations - secret.Data[api.ServiceAccountTokenKey] = []byte(token) + // Set annotations secret.Annotations[api.ServiceAccountNameKey] = serviceAccount.Name secret.Annotations[api.ServiceAccountUIDKey] = string(serviceAccount.UID) diff --git a/pkg/serviceaccount/tokens_controller_test.go b/pkg/serviceaccount/tokens_controller_test.go index 5871ba6ec8..26e6b8076c 100644 --- a/pkg/serviceaccount/tokens_controller_test.go +++ b/pkg/serviceaccount/tokens_controller_test.go @@ -107,7 +107,8 @@ func createdTokenSecret() *api.Secret { }, Type: api.SecretTypeServiceAccountToken, Data: map[string][]byte{ - "token": []byte("ABC"), + "token": []byte("ABC"), + "ca.crt": []byte("CA Data"), }, } } @@ -127,7 +128,8 @@ func serviceAccountTokenSecret() *api.Secret { }, Type: api.SecretTypeServiceAccountToken, Data: map[string][]byte{ - "token": []byte("ABC"), + "token": []byte("ABC"), + "ca.crt": []byte("CA Data"), }, } } @@ -135,7 +137,21 @@ func serviceAccountTokenSecret() *api.Secret { // serviceAccountTokenSecretWithoutTokenData returns an existing ServiceAccountToken secret that lacks token data func serviceAccountTokenSecretWithoutTokenData() *api.Secret { secret := serviceAccountTokenSecret() - secret.Data = nil + delete(secret.Data, api.ServiceAccountTokenKey) + return secret +} + +// serviceAccountTokenSecretWithoutCAData returns an existing ServiceAccountToken secret that lacks ca data +func serviceAccountTokenSecretWithoutCAData() *api.Secret { + secret := serviceAccountTokenSecret() + delete(secret.Data, api.ServiceAccountRootCAKey) + return secret +} + +// serviceAccountTokenSecretWithCAData returns an existing ServiceAccountToken secret with the specified ca data +func serviceAccountTokenSecretWithCAData(data []byte) *api.Secret { + secret := serviceAccountTokenSecret() + secret.Data[api.ServiceAccountRootCAKey] = data return secret } @@ -321,6 +337,24 @@ func TestTokenCreation(t *testing.T) { {Action: "update-secret", Value: serviceAccountTokenSecret()}, }, }, + "added token secret without ca data": { + ClientObjects: []runtime.Object{serviceAccountTokenSecretWithoutCAData()}, + ExistingServiceAccount: serviceAccount(tokenSecretReferences()), + + AddedSecret: serviceAccountTokenSecretWithoutCAData(), + ExpectedActions: []testclient.FakeAction{ + {Action: "update-secret", Value: serviceAccountTokenSecret()}, + }, + }, + "added token secret with mismatched ca data": { + ClientObjects: []runtime.Object{serviceAccountTokenSecretWithCAData([]byte("mismatched"))}, + ExistingServiceAccount: serviceAccount(tokenSecretReferences()), + + AddedSecret: serviceAccountTokenSecretWithCAData([]byte("mismatched")), + ExpectedActions: []testclient.FakeAction{ + {Action: "update-secret", Value: serviceAccountTokenSecret()}, + }, + }, "updated secret without serviceaccount": { ClientObjects: []runtime.Object{serviceAccountTokenSecret()}, @@ -346,6 +380,24 @@ func TestTokenCreation(t *testing.T) { {Action: "update-secret", Value: serviceAccountTokenSecret()}, }, }, + "updated token secret without ca data": { + ClientObjects: []runtime.Object{serviceAccountTokenSecretWithoutCAData()}, + ExistingServiceAccount: serviceAccount(tokenSecretReferences()), + + UpdatedSecret: serviceAccountTokenSecretWithoutCAData(), + ExpectedActions: []testclient.FakeAction{ + {Action: "update-secret", Value: serviceAccountTokenSecret()}, + }, + }, + "updated token secret with mismatched ca data": { + ClientObjects: []runtime.Object{serviceAccountTokenSecretWithCAData([]byte("mismatched"))}, + ExistingServiceAccount: serviceAccount(tokenSecretReferences()), + + UpdatedSecret: serviceAccountTokenSecretWithCAData([]byte("mismatched")), + ExpectedActions: []testclient.FakeAction{ + {Action: "update-secret", Value: serviceAccountTokenSecret()}, + }, + }, "deleted secret without serviceaccount": { DeletedSecret: serviceAccountTokenSecret(), @@ -378,7 +430,7 @@ func TestTokenCreation(t *testing.T) { client := testclient.NewSimpleFake(tc.ClientObjects...) - controller := NewTokensController(client, TokensControllerOptions{TokenGenerator: generator}) + controller := NewTokensController(client, TokensControllerOptions{TokenGenerator: generator, RootCA: []byte("CA Data")}) // Tell the token controller whether its stores have been synced controller.serviceAccountsSynced = func() bool { return !tc.ServiceAccountsSyncPending }