Commit 1ee55781 authored by Jordan Liggitt's avatar Jordan Liggitt

Ensure service account does not exist before deleting added/updated tokens

parent e5637273
...@@ -181,16 +181,12 @@ func (e *TokensController) serviceAccountDeleted(obj interface{}) { ...@@ -181,16 +181,12 @@ func (e *TokensController) serviceAccountDeleted(obj interface{}) {
// secretAdded reacts to a Secret create by ensuring the referenced ServiceAccount exists, and by adding a token to the secret if needed // secretAdded reacts to a Secret create by ensuring the referenced ServiceAccount exists, and by adding a token to the secret if needed
func (e *TokensController) secretAdded(obj interface{}) { func (e *TokensController) secretAdded(obj interface{}) {
secret := obj.(*api.Secret) secret := obj.(*api.Secret)
serviceAccount, err := e.getServiceAccount(secret) serviceAccount, err := e.getServiceAccount(secret, true)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
return return
} }
if serviceAccount == nil { if serviceAccount == nil {
// We shouldn't delete a secret based on an invalid serviceAccount reference until the serviceAccount store is synced
if !e.serviceAccountsSynced() {
return
}
glog.V(2).Infof( glog.V(2).Infof(
"Deleting new secret %s/%s because service account %s (uid=%s) was not found", "Deleting new secret %s/%s because service account %s (uid=%s) was not found",
secret.Namespace, secret.Name, secret.Namespace, secret.Name,
...@@ -206,16 +202,12 @@ func (e *TokensController) secretAdded(obj interface{}) { ...@@ -206,16 +202,12 @@ func (e *TokensController) secretAdded(obj interface{}) {
// secretUpdated reacts to a Secret update (or re-list) by deleting the secret (if the referenced ServiceAccount does not exist) // secretUpdated reacts to a Secret update (or re-list) by deleting the secret (if the referenced ServiceAccount does not exist)
func (e *TokensController) secretUpdated(oldObj interface{}, newObj interface{}) { func (e *TokensController) secretUpdated(oldObj interface{}, newObj interface{}) {
newSecret := newObj.(*api.Secret) newSecret := newObj.(*api.Secret)
newServiceAccount, err := e.getServiceAccount(newSecret) newServiceAccount, err := e.getServiceAccount(newSecret, true)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
return return
} }
if newServiceAccount == nil { if newServiceAccount == nil {
// We shouldn't delete a secret based on an invalid serviceAccount reference until the serviceAccount store is synced
if !e.serviceAccountsSynced() {
return
}
glog.V(2).Infof( glog.V(2).Infof(
"Deleting updated secret %s/%s because service account %s (uid=%s) was not found", "Deleting updated secret %s/%s because service account %s (uid=%s) was not found",
newSecret.Namespace, newSecret.Name, newSecret.Namespace, newSecret.Name,
...@@ -237,7 +229,7 @@ func (e *TokensController) secretDeleted(obj interface{}) { ...@@ -237,7 +229,7 @@ func (e *TokensController) secretDeleted(obj interface{}) {
return return
} }
serviceAccount, err := e.getServiceAccount(secret) serviceAccount, err := e.getServiceAccount(secret, false)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
return return
...@@ -408,7 +400,7 @@ func (e *TokensController) removeSecretReferenceIfNeeded(serviceAccount *api.Ser ...@@ -408,7 +400,7 @@ func (e *TokensController) removeSecretReferenceIfNeeded(serviceAccount *api.Ser
// getServiceAccount returns the ServiceAccount referenced by the given secret. If the secret is not // getServiceAccount returns the ServiceAccount referenced by the given secret. If the secret is not
// of type ServiceAccountToken, or if the referenced ServiceAccount does not exist, nil is returned // of type ServiceAccountToken, or if the referenced ServiceAccount does not exist, nil is returned
func (e *TokensController) getServiceAccount(secret *api.Secret) (*api.ServiceAccount, error) { func (e *TokensController) getServiceAccount(secret *api.Secret, fetchOnCacheMiss bool) (*api.ServiceAccount, error) {
name, uid := serviceAccountNameAndUID(secret) name, uid := serviceAccountNameAndUID(secret)
if len(name) == 0 { if len(name) == 0 {
return nil, nil return nil, nil
...@@ -433,6 +425,21 @@ func (e *TokensController) getServiceAccount(secret *api.Secret) (*api.ServiceAc ...@@ -433,6 +425,21 @@ func (e *TokensController) getServiceAccount(secret *api.Secret) (*api.ServiceAc
return serviceAccount, nil return serviceAccount, nil
} }
if fetchOnCacheMiss {
serviceAccount, err := e.client.ServiceAccounts(secret.Namespace).Get(name)
if apierrors.IsNotFound(err) {
return nil, nil
}
if err != nil {
return nil, err
}
if len(uid) > 0 && uid != string(serviceAccount.UID) {
// If UID is specified, it must match
return nil, nil
}
return serviceAccount, nil
}
return nil, nil return nil, nil
} }
......
...@@ -302,17 +302,10 @@ func TestTokenCreation(t *testing.T) { ...@@ -302,17 +302,10 @@ func TestTokenCreation(t *testing.T) {
AddedSecret: serviceAccountTokenSecret(), AddedSecret: serviceAccountTokenSecret(),
ExpectedActions: []testclient.FakeAction{ ExpectedActions: []testclient.FakeAction{
{Action: "get-serviceaccount", Value: "default"},
{Action: "delete-secret", Value: "token-secret-1"}, {Action: "delete-secret", Value: "token-secret-1"},
}, },
}, },
"added secret without serviceaccount with unsynced service account store": {
ClientObjects: []runtime.Object{serviceAccountTokenSecret()},
ServiceAccountsSyncPending: true,
AddedSecret: serviceAccountTokenSecret(),
ExpectedActions: []testclient.FakeAction{},
},
"added secret with serviceaccount": { "added secret with serviceaccount": {
ExistingServiceAccount: serviceAccount(tokenSecretReferences()), ExistingServiceAccount: serviceAccount(tokenSecretReferences()),
...@@ -334,17 +327,10 @@ func TestTokenCreation(t *testing.T) { ...@@ -334,17 +327,10 @@ func TestTokenCreation(t *testing.T) {
UpdatedSecret: serviceAccountTokenSecret(), UpdatedSecret: serviceAccountTokenSecret(),
ExpectedActions: []testclient.FakeAction{ ExpectedActions: []testclient.FakeAction{
{Action: "get-serviceaccount", Value: "default"},
{Action: "delete-secret", Value: "token-secret-1"}, {Action: "delete-secret", Value: "token-secret-1"},
}, },
}, },
"updated secret without serviceaccount with unsynced service account store": {
ClientObjects: []runtime.Object{serviceAccountTokenSecret()},
ServiceAccountsSyncPending: true,
UpdatedSecret: serviceAccountTokenSecret(),
ExpectedActions: []testclient.FakeAction{},
},
"updated secret with serviceaccount": { "updated secret with serviceaccount": {
ExistingServiceAccount: serviceAccount(tokenSecretReferences()), ExistingServiceAccount: serviceAccount(tokenSecretReferences()),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment