k8s.io/kubernetes@v1.29.3/pkg/controller/serviceaccount/tokens_controller.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package serviceaccount 18 19 import ( 20 "bytes" 21 "context" 22 "fmt" 23 "time" 24 25 v1 "k8s.io/api/core/v1" 26 apierrors "k8s.io/apimachinery/pkg/api/errors" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/types" 29 utilerrors "k8s.io/apimachinery/pkg/util/errors" 30 utilruntime "k8s.io/apimachinery/pkg/util/runtime" 31 "k8s.io/apimachinery/pkg/util/sets" 32 "k8s.io/apimachinery/pkg/util/wait" 33 apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount" 34 informers "k8s.io/client-go/informers/core/v1" 35 clientset "k8s.io/client-go/kubernetes" 36 listersv1 "k8s.io/client-go/listers/core/v1" 37 "k8s.io/client-go/tools/cache" 38 clientretry "k8s.io/client-go/util/retry" 39 "k8s.io/client-go/util/workqueue" 40 "k8s.io/klog/v2" 41 "k8s.io/kubernetes/pkg/serviceaccount" 42 ) 43 44 // RemoveTokenBackoff is the recommended (empirical) retry interval for removing 45 // a secret reference from a service account when the secret is deleted. It is 46 // exported for use by custom secret controllers. 47 var RemoveTokenBackoff = wait.Backoff{ 48 Steps: 10, 49 Duration: 100 * time.Millisecond, 50 Jitter: 1.0, 51 } 52 53 // TokensControllerOptions contains options for the TokensController 54 type TokensControllerOptions struct { 55 // TokenGenerator is the generator to use to create new tokens 56 TokenGenerator serviceaccount.TokenGenerator 57 // ServiceAccountResync is the time.Duration at which to fully re-list service accounts. 58 // If zero, re-list will be delayed as long as possible 59 ServiceAccountResync time.Duration 60 // SecretResync is the time.Duration at which to fully re-list secrets. 61 // If zero, re-list will be delayed as long as possible 62 SecretResync time.Duration 63 // This CA will be added in the secrets of service accounts 64 RootCA []byte 65 66 // MaxRetries controls the maximum number of times a particular key is retried before giving up 67 // If zero, a default max is used 68 MaxRetries int 69 } 70 71 // NewTokensController returns a new *TokensController. 72 func NewTokensController(serviceAccounts informers.ServiceAccountInformer, secrets informers.SecretInformer, cl clientset.Interface, options TokensControllerOptions) (*TokensController, error) { 73 maxRetries := options.MaxRetries 74 if maxRetries == 0 { 75 maxRetries = 10 76 } 77 78 e := &TokensController{ 79 client: cl, 80 token: options.TokenGenerator, 81 rootCA: options.RootCA, 82 83 syncServiceAccountQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "serviceaccount_tokens_service"), 84 syncSecretQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "serviceaccount_tokens_secret"), 85 86 maxRetries: maxRetries, 87 } 88 89 e.serviceAccounts = serviceAccounts.Lister() 90 e.serviceAccountSynced = serviceAccounts.Informer().HasSynced 91 serviceAccounts.Informer().AddEventHandlerWithResyncPeriod( 92 cache.ResourceEventHandlerFuncs{ 93 AddFunc: e.queueServiceAccountSync, 94 UpdateFunc: e.queueServiceAccountUpdateSync, 95 DeleteFunc: e.queueServiceAccountSync, 96 }, 97 options.ServiceAccountResync, 98 ) 99 100 secretCache := secrets.Informer().GetIndexer() 101 e.updatedSecrets = cache.NewIntegerResourceVersionMutationCache(secretCache, secretCache, 60*time.Second, true) 102 e.secretSynced = secrets.Informer().HasSynced 103 secrets.Informer().AddEventHandlerWithResyncPeriod( 104 cache.FilteringResourceEventHandler{ 105 FilterFunc: func(obj interface{}) bool { 106 switch t := obj.(type) { 107 case *v1.Secret: 108 return t.Type == v1.SecretTypeServiceAccountToken 109 default: 110 utilruntime.HandleError(fmt.Errorf("object passed to %T that is not expected: %T", e, obj)) 111 return false 112 } 113 }, 114 Handler: cache.ResourceEventHandlerFuncs{ 115 AddFunc: e.queueSecretSync, 116 UpdateFunc: e.queueSecretUpdateSync, 117 DeleteFunc: e.queueSecretSync, 118 }, 119 }, 120 options.SecretResync, 121 ) 122 123 return e, nil 124 } 125 126 // TokensController manages ServiceAccountToken secrets for ServiceAccount objects 127 type TokensController struct { 128 client clientset.Interface 129 token serviceaccount.TokenGenerator 130 131 rootCA []byte 132 133 serviceAccounts listersv1.ServiceAccountLister 134 // updatedSecrets is a wrapper around the shared cache which allows us to record 135 // and return our local mutations (since we're very likely to act on an updated 136 // secret before the watch reports it). 137 updatedSecrets cache.MutationCache 138 139 // Since we join two objects, we'll watch both of them with controllers. 140 serviceAccountSynced cache.InformerSynced 141 secretSynced cache.InformerSynced 142 143 // syncServiceAccountQueue handles service account events: 144 // * ensures tokens are removed for service accounts which no longer exist 145 // key is "<namespace>/<name>/<uid>" 146 syncServiceAccountQueue workqueue.RateLimitingInterface 147 148 // syncSecretQueue handles secret events: 149 // * deletes tokens whose service account no longer exists 150 // * updates tokens with missing token or namespace data, or mismatched ca data 151 // * ensures service account secret references are removed for tokens which are deleted 152 // key is a secretQueueKey{} 153 syncSecretQueue workqueue.RateLimitingInterface 154 155 maxRetries int 156 } 157 158 // Run runs controller blocks until stopCh is closed 159 func (e *TokensController) Run(ctx context.Context, workers int) { 160 // Shut down queues 161 defer utilruntime.HandleCrash() 162 defer e.syncServiceAccountQueue.ShutDown() 163 defer e.syncSecretQueue.ShutDown() 164 165 if !cache.WaitForNamedCacheSync("tokens", ctx.Done(), e.serviceAccountSynced, e.secretSynced) { 166 return 167 } 168 169 logger := klog.FromContext(ctx) 170 logger.V(5).Info("Starting workers") 171 for i := 0; i < workers; i++ { 172 go wait.UntilWithContext(ctx, e.syncServiceAccount, 0) 173 go wait.UntilWithContext(ctx, e.syncSecret, 0) 174 } 175 <-ctx.Done() 176 logger.V(1).Info("Shutting down") 177 } 178 179 func (e *TokensController) queueServiceAccountSync(obj interface{}) { 180 if serviceAccount, ok := obj.(*v1.ServiceAccount); ok { 181 e.syncServiceAccountQueue.Add(makeServiceAccountKey(serviceAccount)) 182 } 183 } 184 185 func (e *TokensController) queueServiceAccountUpdateSync(oldObj interface{}, newObj interface{}) { 186 if serviceAccount, ok := newObj.(*v1.ServiceAccount); ok { 187 e.syncServiceAccountQueue.Add(makeServiceAccountKey(serviceAccount)) 188 } 189 } 190 191 // complete optionally requeues key, then calls queue.Done(key) 192 func (e *TokensController) retryOrForget(logger klog.Logger, queue workqueue.RateLimitingInterface, key interface{}, requeue bool) { 193 if !requeue { 194 queue.Forget(key) 195 return 196 } 197 198 requeueCount := queue.NumRequeues(key) 199 if requeueCount < e.maxRetries { 200 queue.AddRateLimited(key) 201 return 202 } 203 204 logger.V(4).Info("retried several times", "key", key, "count", requeueCount) 205 queue.Forget(key) 206 } 207 208 func (e *TokensController) queueSecretSync(obj interface{}) { 209 if secret, ok := obj.(*v1.Secret); ok { 210 e.syncSecretQueue.Add(makeSecretQueueKey(secret)) 211 } 212 } 213 214 func (e *TokensController) queueSecretUpdateSync(oldObj interface{}, newObj interface{}) { 215 if secret, ok := newObj.(*v1.Secret); ok { 216 e.syncSecretQueue.Add(makeSecretQueueKey(secret)) 217 } 218 } 219 220 func (e *TokensController) syncServiceAccount(ctx context.Context) { 221 logger := klog.FromContext(ctx) 222 key, quit := e.syncServiceAccountQueue.Get() 223 if quit { 224 return 225 } 226 defer e.syncServiceAccountQueue.Done(key) 227 228 retry := false 229 defer func() { 230 e.retryOrForget(logger, e.syncServiceAccountQueue, key, retry) 231 }() 232 233 saInfo, err := parseServiceAccountKey(key) 234 if err != nil { 235 logger.Error(err, "Parsing service account key") 236 return 237 } 238 239 sa, err := e.getServiceAccount(saInfo.namespace, saInfo.name, saInfo.uid, false) 240 switch { 241 case err != nil: 242 logger.Error(err, "Getting service account") 243 retry = true 244 case sa == nil: 245 // service account no longer exists, so delete related tokens 246 logger.V(4).Info("Service account deleted, removing tokens", "namespace", saInfo.namespace, "serviceaccount", saInfo.name) 247 sa = &v1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Namespace: saInfo.namespace, Name: saInfo.name, UID: saInfo.uid}} 248 retry, err = e.deleteTokens(sa) 249 if err != nil { 250 logger.Error(err, "Error deleting serviceaccount tokens", "namespace", saInfo.namespace, "serviceaccount", saInfo.name) 251 } 252 } 253 } 254 255 func (e *TokensController) syncSecret(ctx context.Context) { 256 key, quit := e.syncSecretQueue.Get() 257 if quit { 258 return 259 } 260 defer e.syncSecretQueue.Done(key) 261 262 logger := klog.FromContext(ctx) 263 // Track whether or not we should retry this sync 264 retry := false 265 defer func() { 266 e.retryOrForget(logger, e.syncSecretQueue, key, retry) 267 }() 268 269 secretInfo, err := parseSecretQueueKey(key) 270 if err != nil { 271 logger.Error(err, "Parsing secret queue key") 272 return 273 } 274 275 secret, err := e.getSecret(secretInfo.namespace, secretInfo.name, secretInfo.uid, false) 276 switch { 277 case err != nil: 278 logger.Error(err, "Getting secret") 279 retry = true 280 case secret == nil: 281 // If the service account exists 282 if sa, saErr := e.getServiceAccount(secretInfo.namespace, secretInfo.saName, secretInfo.saUID, false); saErr == nil && sa != nil { 283 // secret no longer exists, so delete references to this secret from the service account 284 if err := clientretry.RetryOnConflict(RemoveTokenBackoff, func() error { 285 return e.removeSecretReference(secretInfo.namespace, secretInfo.saName, secretInfo.saUID, secretInfo.name) 286 }); err != nil { 287 logger.Error(err, "Removing secret reference") 288 } 289 } 290 default: 291 // Ensure service account exists 292 sa, saErr := e.getServiceAccount(secretInfo.namespace, secretInfo.saName, secretInfo.saUID, true) 293 switch { 294 case saErr != nil: 295 logger.Error(saErr, "Getting service account") 296 retry = true 297 case sa == nil: 298 // Delete token 299 logger.V(4).Info("Service account does not exist, deleting token", "secret", klog.KRef(secretInfo.namespace, secretInfo.name)) 300 if retriable, err := e.deleteToken(secretInfo.namespace, secretInfo.name, secretInfo.uid); err != nil { 301 logger.Error(err, "Deleting serviceaccount token", "secret", klog.KRef(secretInfo.namespace, secretInfo.name), "serviceAccount", klog.KRef(secretInfo.namespace, secretInfo.saName)) 302 retry = retriable 303 } 304 default: 305 // Update token if needed 306 if retriable, err := e.generateTokenIfNeeded(logger, sa, secret); err != nil { 307 logger.Error(err, "Populating serviceaccount token", "secret", klog.KRef(secretInfo.namespace, secretInfo.name), "serviceAccount", klog.KRef(secretInfo.namespace, secretInfo.saName)) 308 retry = retriable 309 } 310 } 311 } 312 } 313 314 func (e *TokensController) deleteTokens(serviceAccount *v1.ServiceAccount) ( /*retry*/ bool, error) { 315 tokens, err := e.listTokenSecrets(serviceAccount) 316 if err != nil { 317 // don't retry on cache lookup errors 318 return false, err 319 } 320 retry := false 321 errs := []error{} 322 for _, token := range tokens { 323 r, err := e.deleteToken(token.Namespace, token.Name, token.UID) 324 if err != nil { 325 errs = append(errs, err) 326 } 327 if r { 328 retry = true 329 } 330 } 331 return retry, utilerrors.NewAggregate(errs) 332 } 333 334 func (e *TokensController) deleteToken(ns, name string, uid types.UID) ( /*retry*/ bool, error) { 335 var opts metav1.DeleteOptions 336 if len(uid) > 0 { 337 opts.Preconditions = &metav1.Preconditions{UID: &uid} 338 } 339 err := e.client.CoreV1().Secrets(ns).Delete(context.TODO(), name, opts) 340 // NotFound doesn't need a retry (it's already been deleted) 341 // Conflict doesn't need a retry (the UID precondition failed) 342 if err == nil || apierrors.IsNotFound(err) || apierrors.IsConflict(err) { 343 return false, nil 344 } 345 // Retry for any other error 346 return true, err 347 } 348 349 func (e *TokensController) secretUpdateNeeded(secret *v1.Secret) (bool, bool, bool) { 350 caData := secret.Data[v1.ServiceAccountRootCAKey] 351 needsCA := len(e.rootCA) > 0 && !bytes.Equal(caData, e.rootCA) 352 353 needsNamespace := len(secret.Data[v1.ServiceAccountNamespaceKey]) == 0 354 355 tokenData := secret.Data[v1.ServiceAccountTokenKey] 356 needsToken := len(tokenData) == 0 357 358 return needsCA, needsNamespace, needsToken 359 } 360 361 // generateTokenIfNeeded populates the token data for the given Secret if not already set 362 func (e *TokensController) generateTokenIfNeeded(logger klog.Logger, serviceAccount *v1.ServiceAccount, cachedSecret *v1.Secret) ( /* retry */ bool, error) { 363 // Check the cached secret to see if changes are needed 364 if needsCA, needsNamespace, needsToken := e.secretUpdateNeeded(cachedSecret); !needsCA && !needsToken && !needsNamespace { 365 return false, nil 366 } 367 368 // We don't want to update the cache's copy of the secret 369 // so add the token to a freshly retrieved copy of the secret 370 secrets := e.client.CoreV1().Secrets(cachedSecret.Namespace) 371 liveSecret, err := secrets.Get(context.TODO(), cachedSecret.Name, metav1.GetOptions{}) 372 if err != nil { 373 // Retry for any error other than a NotFound 374 return !apierrors.IsNotFound(err), err 375 } 376 if liveSecret.ResourceVersion != cachedSecret.ResourceVersion { 377 // our view of the secret is not up to date 378 // we'll get notified of an update event later and get to try again 379 logger.V(2).Info("Secret is not up to date, skipping token population", "secret", klog.KRef(liveSecret.Namespace, liveSecret.Name)) 380 return false, nil 381 } 382 383 needsCA, needsNamespace, needsToken := e.secretUpdateNeeded(liveSecret) 384 if !needsCA && !needsToken && !needsNamespace { 385 return false, nil 386 } 387 388 if liveSecret.Annotations == nil { 389 liveSecret.Annotations = map[string]string{} 390 } 391 if liveSecret.Data == nil { 392 liveSecret.Data = map[string][]byte{} 393 } 394 395 // Set the CA 396 if needsCA { 397 liveSecret.Data[v1.ServiceAccountRootCAKey] = e.rootCA 398 } 399 // Set the namespace 400 if needsNamespace { 401 liveSecret.Data[v1.ServiceAccountNamespaceKey] = []byte(liveSecret.Namespace) 402 } 403 404 // Generate the token 405 if needsToken { 406 token, err := e.token.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *liveSecret)) 407 if err != nil { 408 return false, err 409 } 410 liveSecret.Data[v1.ServiceAccountTokenKey] = []byte(token) 411 } 412 413 // Set annotations 414 liveSecret.Annotations[v1.ServiceAccountNameKey] = serviceAccount.Name 415 liveSecret.Annotations[v1.ServiceAccountUIDKey] = string(serviceAccount.UID) 416 417 // Save the secret 418 _, err = secrets.Update(context.TODO(), liveSecret, metav1.UpdateOptions{}) 419 if apierrors.IsConflict(err) || apierrors.IsNotFound(err) { 420 // if we got a Conflict error, the secret was updated by someone else, and we'll get an update notification later 421 // if we got a NotFound error, the secret no longer exists, and we don't need to populate a token 422 return false, nil 423 } 424 if err != nil { 425 return true, err 426 } 427 return false, nil 428 } 429 430 // removeSecretReference updates the given ServiceAccount to remove a reference to the given secretName if needed. 431 func (e *TokensController) removeSecretReference(saNamespace string, saName string, saUID types.UID, secretName string) error { 432 // We don't want to update the cache's copy of the service account 433 // so remove the secret from a freshly retrieved copy of the service account 434 serviceAccounts := e.client.CoreV1().ServiceAccounts(saNamespace) 435 serviceAccount, err := serviceAccounts.Get(context.TODO(), saName, metav1.GetOptions{}) 436 // Ignore NotFound errors when attempting to remove a reference 437 if apierrors.IsNotFound(err) { 438 return nil 439 } 440 if err != nil { 441 return err 442 } 443 444 // Short-circuit if the UID doesn't match 445 if len(saUID) > 0 && saUID != serviceAccount.UID { 446 return nil 447 } 448 449 // Short-circuit if the secret is no longer referenced 450 if !getSecretReferences(serviceAccount).Has(secretName) { 451 return nil 452 } 453 454 // Remove the secret 455 secrets := []v1.ObjectReference{} 456 for _, s := range serviceAccount.Secrets { 457 if s.Name != secretName { 458 secrets = append(secrets, s) 459 } 460 } 461 serviceAccount.Secrets = secrets 462 _, err = serviceAccounts.Update(context.TODO(), serviceAccount, metav1.UpdateOptions{}) 463 // Ignore NotFound errors when attempting to remove a reference 464 if apierrors.IsNotFound(err) { 465 return nil 466 } 467 return err 468 } 469 470 func (e *TokensController) getServiceAccount(ns string, name string, uid types.UID, fetchOnCacheMiss bool) (*v1.ServiceAccount, error) { 471 // Look up in cache 472 sa, err := e.serviceAccounts.ServiceAccounts(ns).Get(name) 473 if err != nil && !apierrors.IsNotFound(err) { 474 return nil, err 475 } 476 if sa != nil { 477 // Ensure UID matches if given 478 if len(uid) == 0 || uid == sa.UID { 479 return sa, nil 480 } 481 } 482 483 if !fetchOnCacheMiss { 484 return nil, nil 485 } 486 487 // Live lookup 488 sa, err = e.client.CoreV1().ServiceAccounts(ns).Get(context.TODO(), name, metav1.GetOptions{}) 489 if apierrors.IsNotFound(err) { 490 return nil, nil 491 } 492 if err != nil { 493 return nil, err 494 } 495 // Ensure UID matches if given 496 if len(uid) == 0 || uid == sa.UID { 497 return sa, nil 498 } 499 return nil, nil 500 } 501 502 func (e *TokensController) getSecret(ns string, name string, uid types.UID, fetchOnCacheMiss bool) (*v1.Secret, error) { 503 // Look up in cache 504 obj, exists, err := e.updatedSecrets.GetByKey(makeCacheKey(ns, name)) 505 if err != nil { 506 return nil, err 507 } 508 if exists { 509 secret, ok := obj.(*v1.Secret) 510 if !ok { 511 return nil, fmt.Errorf("expected *v1.Secret, got %#v", secret) 512 } 513 // Ensure UID matches if given 514 if len(uid) == 0 || uid == secret.UID { 515 return secret, nil 516 } 517 } 518 519 if !fetchOnCacheMiss { 520 return nil, nil 521 } 522 523 // Live lookup 524 secret, err := e.client.CoreV1().Secrets(ns).Get(context.TODO(), name, metav1.GetOptions{}) 525 if apierrors.IsNotFound(err) { 526 return nil, nil 527 } 528 if err != nil { 529 return nil, err 530 } 531 // Ensure UID matches if given 532 if len(uid) == 0 || uid == secret.UID { 533 return secret, nil 534 } 535 return nil, nil 536 } 537 538 // listTokenSecrets returns a list of all of the ServiceAccountToken secrets that 539 // reference the given service account's name and uid 540 func (e *TokensController) listTokenSecrets(serviceAccount *v1.ServiceAccount) ([]*v1.Secret, error) { 541 namespaceSecrets, err := e.updatedSecrets.ByIndex("namespace", serviceAccount.Namespace) 542 if err != nil { 543 return nil, err 544 } 545 546 items := []*v1.Secret{} 547 for _, obj := range namespaceSecrets { 548 secret := obj.(*v1.Secret) 549 550 if apiserverserviceaccount.IsServiceAccountToken(secret, serviceAccount) { 551 items = append(items, secret) 552 } 553 } 554 return items, nil 555 } 556 557 func getSecretReferences(serviceAccount *v1.ServiceAccount) sets.String { 558 references := sets.NewString() 559 for _, secret := range serviceAccount.Secrets { 560 references.Insert(secret.Name) 561 } 562 return references 563 } 564 565 // serviceAccountQueueKey holds information we need to sync a service account. 566 // It contains enough information to look up the cached service account, 567 // or delete owned tokens if the service account no longer exists. 568 type serviceAccountQueueKey struct { 569 namespace string 570 name string 571 uid types.UID 572 } 573 574 func makeServiceAccountKey(sa *v1.ServiceAccount) interface{} { 575 return serviceAccountQueueKey{ 576 namespace: sa.Namespace, 577 name: sa.Name, 578 uid: sa.UID, 579 } 580 } 581 582 func parseServiceAccountKey(key interface{}) (serviceAccountQueueKey, error) { 583 queueKey, ok := key.(serviceAccountQueueKey) 584 if !ok || len(queueKey.namespace) == 0 || len(queueKey.name) == 0 || len(queueKey.uid) == 0 { 585 return serviceAccountQueueKey{}, fmt.Errorf("invalid serviceaccount key: %#v", key) 586 } 587 return queueKey, nil 588 } 589 590 // secretQueueKey holds information we need to sync a service account token secret. 591 // It contains enough information to look up the cached service account, 592 // or delete the secret reference if the secret no longer exists. 593 type secretQueueKey struct { 594 namespace string 595 name string 596 uid types.UID 597 saName string 598 // optional, will be blank when syncing tokens missing the service account uid annotation 599 saUID types.UID 600 } 601 602 func makeSecretQueueKey(secret *v1.Secret) interface{} { 603 return secretQueueKey{ 604 namespace: secret.Namespace, 605 name: secret.Name, 606 uid: secret.UID, 607 saName: secret.Annotations[v1.ServiceAccountNameKey], 608 saUID: types.UID(secret.Annotations[v1.ServiceAccountUIDKey]), 609 } 610 } 611 612 func parseSecretQueueKey(key interface{}) (secretQueueKey, error) { 613 queueKey, ok := key.(secretQueueKey) 614 if !ok || len(queueKey.namespace) == 0 || len(queueKey.name) == 0 || len(queueKey.uid) == 0 || len(queueKey.saName) == 0 { 615 return secretQueueKey{}, fmt.Errorf("invalid secret key: %#v", key) 616 } 617 return queueKey, nil 618 } 619 620 // produce the same key format as cache.MetaNamespaceKeyFunc 621 func makeCacheKey(namespace, name string) string { 622 return namespace + "/" + name 623 }