// TODO: when Secrets in kapi.ServiceAccount get changed to MountSecrets and represented by LocalObjectReferences, this can be // refactored to reuse the addition code better // linkSecretsToServiceAccount links secrets to the service account, either as pull secrets, mount secrets, or both. func (o LinkSecretOptions) linkSecretsToServiceAccount(serviceaccount *kapi.ServiceAccount) error { updated := false newSecrets, failLater, err := o.GetSecrets() if err != nil { return err } newSecretNames := o.GetSecretNames(newSecrets) if o.ForMount { currentSecrets := o.GetMountSecretNames(serviceaccount) secretsToLink := newSecretNames.Difference(currentSecrets) for _, secretName := range secretsToLink.List() { serviceaccount.Secrets = append(serviceaccount.Secrets, kapi.ObjectReference{Name: secretName}) updated = true } } if o.ForPull { currentSecrets := o.GetPullSecretNames(serviceaccount) secretsToLink := newSecretNames.Difference(currentSecrets) for _, secretName := range secretsToLink.List() { serviceaccount.ImagePullSecrets = append(serviceaccount.ImagePullSecrets, kapi.LocalObjectReference{Name: secretName}) updated = true } } if updated { _, err = o.ClientInterface.ServiceAccounts(o.Namespace).Update(serviceaccount) return err } if failLater { return errors.New("Some secrets could not be linked") } return nil }
// TODO: when Secrets in kapi.ServiceAccount get changed to MountSecrets and represented by LocalObjectReferences, this can be // refactored to reuse the addition code better // addSecretsToServiceAccount adds secrets to the service account, either as pull secrets, mount secrets, or both. func (o AddSecretOptions) addSecretsToServiceAccount(serviceaccount *kapi.ServiceAccount) error { updated := false newSecrets, err := o.getSecrets() if err != nil { return err } newSecretNames := getSecretNames(newSecrets) if o.ForMount { currentSecrets := getMountSecretNames(serviceaccount) secretsToAdd := newSecretNames.Difference(currentSecrets) for _, secretName := range secretsToAdd.List() { serviceaccount.Secrets = append(serviceaccount.Secrets, kapi.ObjectReference{Name: secretName}) updated = true } } if o.ForPull { currentSecrets := getPullSecretNames(serviceaccount) secretsToAdd := newSecretNames.Difference(currentSecrets) for _, secretName := range secretsToAdd.List() { serviceaccount.ImagePullSecrets = append(serviceaccount.ImagePullSecrets, kapi.LocalObjectReference{Name: secretName}) updated = true } } if updated { _, err = o.ClientInterface.ServiceAccounts(o.Namespace).Update(serviceaccount) return err } return nil }
// removeSecretReferenceIfNeeded updates the given ServiceAccount to remove a reference to the given secretName if needed. // Returns whether an update was performed, and any error that occurred func (e *TokensController) removeSecretReferenceIfNeeded(serviceAccount *api.ServiceAccount, secretName string) (bool, error) { // See if the account even referenced the secret if !getSecretReferences(serviceAccount).Has(secretName) { return false, nil } // We don't want to update the cache's copy of the service account // so remove the secret from a freshly retrieved copy of the service account serviceAccounts := e.client.ServiceAccounts(serviceAccount.Namespace) serviceAccount, err := serviceAccounts.Get(serviceAccount.Name) if err != nil { return false, err } // Double-check to see if the account still references the secret if !getSecretReferences(serviceAccount).Has(secretName) { return false, nil } secrets := []api.ObjectReference{} for _, s := range serviceAccount.Secrets { if s.Name != secretName { secrets = append(secrets, s) } } serviceAccount.Secrets = secrets _, err = serviceAccounts.Update(serviceAccount) if err != nil { return false, err } return true, nil }
// unlinkSecretsFromServiceAccount detaches pull and mount secrets from the service account. func (o UnlinkSecretOptions) unlinkSecretsFromServiceAccount(serviceaccount *kapi.ServiceAccount) error { // All of the requested secrets must be present in either the Mount or Pull secrets // If any of them are not present, we'll return an error and push no changes. rmSecrets, failLater, err := o.GetSecrets() if err != nil { return err } rmSecretNames := o.GetSecretNames(rmSecrets) newMountSecrets := []kapi.ObjectReference{} newPullSecrets := []kapi.LocalObjectReference{} // Check the mount secrets for i := len(serviceaccount.Secrets) - 1; i >= 0; i-- { found := false for _, secretname := range rmSecretNames.List() { if secretname == serviceaccount.Secrets[i].Name { found = true // Skip adding this to the updated list } } if !found { // Copy this back in, since it doesn't match the ones we're removing newMountSecrets = append(newMountSecrets, serviceaccount.Secrets[i]) } } // Check the image pull secrets for i := len(serviceaccount.ImagePullSecrets) - 1; i >= 0; i-- { found := false for _, secretname := range rmSecretNames.List() { if secretname == serviceaccount.ImagePullSecrets[i].Name { found = true // Skip adding this to the updated list } } if !found { // Copy this back in, since it doesn't match the one we're removing newPullSecrets = append(newPullSecrets, serviceaccount.ImagePullSecrets[i]) } } // Save the updated Secret lists back to the server serviceaccount.Secrets = newMountSecrets serviceaccount.ImagePullSecrets = newPullSecrets _, err = o.ClientInterface.ServiceAccounts(o.Namespace).Update(serviceaccount) if err != nil { return err } if failLater { return errors.New("Some secrets could not be unlinked") } return nil }
// createSecret creates a secret of type ServiceAccountToken for the given ServiceAccount func (e *TokensController) createSecret(serviceAccount *api.ServiceAccount) error { // Build the secret secret := &api.Secret{ ObjectMeta: api.ObjectMeta{ Name: secret.Strategy.GenerateName(fmt.Sprintf("%s-token-", serviceAccount.Name)), Namespace: serviceAccount.Namespace, Annotations: map[string]string{ api.ServiceAccountNameKey: serviceAccount.Name, api.ServiceAccountUIDKey: string(serviceAccount.UID), }, }, Type: api.SecretTypeServiceAccountToken, Data: map[string][]byte{}, } // Generate the token token, err := e.token.GenerateToken(*serviceAccount, *secret) if err != nil { return err } secret.Data[api.ServiceAccountTokenKey] = []byte(token) if e.rootCA != nil && len(e.rootCA) > 0 { secret.Data[api.ServiceAccountRootCAKey] = e.rootCA } // Save the secret if _, err := e.client.Secrets(serviceAccount.Namespace).Create(secret); err != nil { return err } // We don't want to update the cache's copy of the service account // so add the secret to a freshly retrieved copy of the service account serviceAccounts := e.client.ServiceAccounts(serviceAccount.Namespace) serviceAccount, err = serviceAccounts.Get(serviceAccount.Name) if err != nil { return err } serviceAccount.Secrets = append(serviceAccount.Secrets, api.ObjectReference{Name: secret.Name}) _, err = serviceAccounts.Update(serviceAccount) if err != nil { // we weren't able to use the token, try to clean it up. glog.V(2).Infof("Deleting secret %s/%s because reference couldn't be added (%v)", secret.Namespace, secret.Name, err) if err := e.client.Secrets(secret.Namespace).Delete(secret.Name); err != nil { glog.Error(err) // if we fail, just log it } } if apierrors.IsConflict(err) { // nothing to do. We got a conflict, that means that the service account was updated. We simply need to return because we'll get an update notification later return nil } return err }
// unlinkSecretsFromServiceAccount detaches pull and mount secrets from the service account. func (o UnlinkSecretOptions) unlinkSecretsFromServiceAccount(serviceaccount *kapi.ServiceAccount) error { // All of the requested secrets must be present in either the Mount or Pull secrets // If any of them are not present, we'll return an error and push no changes. rmSecrets, hasNotFound, err := o.GetSecrets(true) if err != nil { return err } rmSecretNames := o.GetSecretNames(rmSecrets) newMountSecrets := []kapi.ObjectReference{} newPullSecrets := []kapi.LocalObjectReference{} updated := false // Check the mount secrets for _, secret := range serviceaccount.Secrets { if !rmSecretNames.Has(secret.Name) { // Copy this back in, since it doesn't match the ones we're removing newMountSecrets = append(newMountSecrets, secret) } else { updated = true } } // Check the image pull secrets for _, imagePullSecret := range serviceaccount.ImagePullSecrets { if !rmSecretNames.Has(imagePullSecret.Name) { // Copy this back in, since it doesn't match the one we're removing newPullSecrets = append(newPullSecrets, imagePullSecret) } else { updated = true } } if updated { // Save the updated Secret lists back to the server serviceaccount.Secrets = newMountSecrets serviceaccount.ImagePullSecrets = newPullSecrets _, err = o.ClientInterface.ServiceAccounts(o.Namespace).Update(serviceaccount) if err != nil { return err } if hasNotFound { return fmt.Errorf("Unlinked deleted secrets from %s/%s service account", o.Namespace, serviceaccount.Name) } return nil } else { return errors.New("No valid secrets found or secrets not linked to service account") } }