@@ -89,9 +89,10 @@ func AddServiceAccountProviderControllerToManager(ctx *context.ControllerManager
8989 & source.Kind {Type : & vmwarev1.ProviderServiceAccount {}},
9090 handler .EnqueueRequestsFromMapFunc (r .providerServiceAccountToVSphereCluster ),
9191 ).
92+ // Watches the secrets to re-enqueue once the service account token is set
9293 Watches (
93- & source.Kind {Type : & corev1.ServiceAccount {}},
94- handler .EnqueueRequestsFromMapFunc (r .serviceAccountToVSphereCluster ),
94+ & source.Kind {Type : & corev1.Secret {}},
95+ handler .EnqueueRequestsFromMapFunc (r .secretToVSphereCluster ),
9596 ).
9697 Complete (r )
9798}
@@ -228,18 +229,22 @@ func (r ServiceAccountReconciler) ensureProviderServiceAccounts(ctx *vmwareconte
228229 if err := r .ensureServiceAccountConfigMap (ctx .ClusterContext , pSvcAccount ); err != nil {
229230 return errors .Wrapf (err , "unable to sync configmap for provider serviceaccount %s" , pSvcAccount .Name )
230231 }
232+ // 3. Create secret of Service account token type for the service account
233+ if err := r .ensureServiceAccountSecret (ctx .ClusterContext , pSvcAccount ); err != nil {
234+ return errors .Wrapf (err , "unable to create provider serviceaccount secret %s" , getServiceAccountSecretName (pSvcAccount ))
235+ }
231236
232- // 3 . Create the associated role for the service account
237+ // 4 . Create the associated role for the service account
233238 if err := r .ensureRole (ctx .ClusterContext , pSvcAccount ); err != nil {
234239 return errors .Wrapf (err , "unable to create role for provider serviceaccount %s" , pSvcAccount .Name )
235240 }
236241
237- // 4 . Create the associated roleBinding for the service account
242+ // 5 . Create the associated roleBinding for the service account
238243 if err := r .ensureRoleBinding (ctx .ClusterContext , pSvcAccount ); err != nil {
239244 return errors .Wrapf (err , "unable to create rolebinding for provider serviceaccount %s" , pSvcAccount .Name )
240245 }
241246
242- // 5 . Sync the service account with the target
247+ // 6 . Sync the service account with the target
243248 if err := r .syncServiceAccountSecret (ctx , pSvcAccount ); err != nil {
244249 return errors .Wrapf (err , "unable to sync secret for provider serviceaccount %s" , pSvcAccount .Name )
245250 }
@@ -269,6 +274,34 @@ func (r ServiceAccountReconciler) ensureServiceAccount(ctx *vmwarecontext.Cluste
269274 return nil
270275}
271276
277+ func (r ServiceAccountReconciler ) ensureServiceAccountSecret (ctx * vmwarecontext.ClusterContext , pSvcAccount vmwarev1.ProviderServiceAccount ) error {
278+ secret := corev1.Secret {
279+ Type : corev1 .SecretTypeServiceAccountToken ,
280+ ObjectMeta : metav1.ObjectMeta {
281+ Name : getServiceAccountSecretName (pSvcAccount ),
282+ Namespace : pSvcAccount .Namespace ,
283+ Annotations : map [string ]string {
284+ // denotes that this secret holds the token for the service account
285+ corev1 .ServiceAccountNameKey : getServiceAccountName (pSvcAccount ),
286+ },
287+ },
288+ }
289+
290+ logger := ctx .Logger .WithValues ("providerserviceaccount" , pSvcAccount .Name , "secret" , secret .Name )
291+ err := controllerutil .SetControllerReference (& pSvcAccount , & secret , ctx .Scheme )
292+ if err != nil {
293+ return err
294+ }
295+ logger .V (4 ).Info ("Creating service account secret" )
296+ err = ctx .Client .Create (ctx , & secret )
297+ if err != nil && ! apierrors .IsAlreadyExists (err ) {
298+ // Note: We skip updating the service account because the token controller updates the service account with a
299+ // secret and we don't want to overwrite it with an empty secret.
300+ return err
301+ }
302+ return nil
303+ }
304+
272305func (r ServiceAccountReconciler ) ensureRole (ctx * vmwarecontext.ClusterContext , pSvcAccount vmwarev1.ProviderServiceAccount ) error {
273306 role := rbacv1.Role {
274307 ObjectMeta : metav1.ObjectMeta {
@@ -323,29 +356,23 @@ func (r ServiceAccountReconciler) ensureRoleBinding(ctx *vmwarecontext.ClusterCo
323356
324357func (r ServiceAccountReconciler ) syncServiceAccountSecret (ctx * vmwarecontext.GuestClusterContext , pSvcAccount vmwarev1.ProviderServiceAccount ) error {
325358 logger := ctx .Logger .WithValues ("providerserviceaccount" , pSvcAccount .Name )
326- logger .V (4 ).Info ("Attempting to sync secret for provider service account" )
327- var svcAccount corev1.ServiceAccount
328- err := ctx .Client .Get (ctx , types.NamespacedName {Name : getServiceAccountName (pSvcAccount ), Namespace : pSvcAccount .Namespace }, & svcAccount )
359+ logger .V (4 ).Info ("Attempting to sync token secret for provider service account" )
360+
361+ secretName := getServiceAccountSecretName (pSvcAccount )
362+ logger .V (4 ).Info ("Fetching secret for service account token details" , "secret" , secretName )
363+ var svcAccountTokenSecret corev1.Secret
364+ err := ctx .Client .Get (ctx , types.NamespacedName {Name : secretName , Namespace : pSvcAccount .Namespace }, & svcAccountTokenSecret )
329365 if err != nil {
330366 return err
331367 }
332- // Check if token secret exists
333- if len (svcAccount . Secrets ) == 0 {
334- // Note: We don't have to requeue here because we have a watch on the service account and the cluster should be reconciled
335- // when a secret is added to the service account by the token controller .
336- logger .Info ("Skipping sync secret for provider service account: serviceaccount has no secrets " , "serviceaccount " , svcAccount . Name )
368+ // Check if token data exists
369+ if len (svcAccountTokenSecret . Data ) == 0 {
370+ // Note: We don't have to requeue here because we have a watch on the secret and the cluster should be reconciled
371+ // when a secret has token data populated .
372+ logger .Info ("Skipping sync secret for provider service account: secret has no data " , "secret " , secretName )
337373 return nil
338374 }
339375
340- // Choose the default secret
341- secretRef := svcAccount .Secrets [0 ]
342- logger .V (4 ).Info ("Fetching secret for provider service account" , "secret" , secretRef .Name )
343- var sourceSecret corev1.Secret
344- err = ctx .Client .Get (ctx , types.NamespacedName {Name : secretRef .Name , Namespace : svcAccount .Namespace }, & sourceSecret )
345- if err != nil {
346- return err
347- }
348-
349376 // Create the target namespace if it is not existing
350377 targetNamespace := & corev1.Namespace {
351378 ObjectMeta : metav1.ObjectMeta {
@@ -372,7 +399,7 @@ func (r ServiceAccountReconciler) syncServiceAccountSecret(ctx *vmwarecontext.Gu
372399 }
373400 logger .V (4 ).Info ("Creating or updating secret in cluster" , "namespace" , targetSecret .Namespace , "name" , targetSecret .Name )
374401 _ , err = controllerutil .CreateOrPatch (ctx , ctx .GuestClient , targetSecret , func () error {
375- targetSecret .Data = sourceSecret .Data
402+ targetSecret .Data = svcAccountTokenSecret .Data
376403 return nil
377404 })
378405 return err
@@ -468,6 +495,10 @@ func getServiceAccountName(pSvcAccount vmwarev1.ProviderServiceAccount) string {
468495 return pSvcAccount .Name
469496}
470497
498+ func getServiceAccountSecretName (pSvcAccount vmwarev1.ProviderServiceAccount ) string {
499+ return fmt .Sprintf ("%s-secret" , pSvcAccount .Name )
500+ }
501+
471502func getSystemServiceAccountFullName (pSvcAccount vmwarev1.ProviderServiceAccount ) string {
472503 return fmt .Sprintf ("%s.%s.%s" , systemServiceAccountPrefix , getServiceAccountNamespace (pSvcAccount ), getServiceAccountName (pSvcAccount ))
473504}
@@ -484,6 +515,33 @@ func GetCMNamespaceName() types.NamespacedName {
484515 }
485516}
486517
518+ // secretToVSphereCluster is a mapper function used to enqueue reconcile.Request objects.
519+ // It accepts a Secret object owned by the controller and fetches the service account
520+ // that contains the token and creates a reconcile.Request for the vmwarev1.VSphereCluster object.
521+ func (r ServiceAccountReconciler ) secretToVSphereCluster (o client.Object ) []reconcile.Request {
522+ secret , ok := o .(* corev1.Secret )
523+ if ! ok {
524+ return nil
525+ }
526+
527+ ownerRef := metav1 .GetControllerOf (secret )
528+ if ownerRef != nil && ownerRef .Kind == kindProviderServiceAccount {
529+ if ! metav1 .HasAnnotation (secret .ObjectMeta , corev1 .ServiceAccountNameKey ) {
530+ return nil
531+ }
532+ svcAccountName := secret .GetAnnotations ()[corev1 .ServiceAccountNameKey ]
533+ svcAccount := & corev1.ServiceAccount {}
534+ if err := r .Client .Get (r .Context , client.ObjectKey {
535+ Namespace : secret .Namespace ,
536+ Name : svcAccountName ,
537+ }, svcAccount ); err != nil {
538+ return nil
539+ }
540+ return r .serviceAccountToVSphereCluster (svcAccount )
541+ }
542+ return nil
543+ }
544+
487545// serviceAccountToVSphereCluster is a mapper function used to enqueue reconcile.Request objects.
488546// From the watched object owned by this controller, it creates reconcile.Request object
489547// for the vmwarev1.VSphereCluster object that owns the watched object.
0 commit comments