@@ -512,6 +512,19 @@ func (r *SwiftProxyReconciler) Reconcile(ctx context.Context, req ctrl.Request)
512512 return ctrlResult , err
513513 }
514514
515+ // Check for Application Credentials
516+ ctrlResult , err = r .verifyApplicationCredentials (
517+ ctx ,
518+ r .GetLogger (ctx ),
519+ helper .GetClient (),
520+ instance .Namespace ,
521+ "swift" ,
522+ & envVars ,
523+ )
524+ if (err != nil || ctrlResult != ctrl.Result {}) {
525+ return ctrlResult , err
526+ }
527+
515528 // Get the service password and pass it to the template
516529 sps , _ , err := secret .GetSecret (ctx , helper , instance .Spec .Secret , instance .Namespace )
517530 if err != nil {
@@ -578,6 +591,20 @@ func (r *SwiftProxyReconciler) Reconcile(ctx context.Context, req ctrl.Request)
578591 return ctrl.Result {}, err
579592 }
580593
594+ // Get Application Credential data if available
595+ useAC := false
596+ acID := ""
597+ acSecret := ""
598+ // Try to get Application Credential for this service (via keystone api helper)
599+ if acData , err := keystonev1 .GetApplicationCredentialFromSecret (ctx , r .Client , instance .Namespace , swift .ServiceName ); err != nil {
600+ Log .Error (err , "Failed to get ApplicationCredential for service" , "service" , swift .ServiceName )
601+ } else if acData != nil {
602+ useAC = true
603+ acID = acData .ID
604+ acSecret = acData .Secret
605+ Log .Info ("Using ApplicationCredentials auth" , "service" , swift .ServiceName )
606+ }
607+
581608 // Create a Secret populated with content from templates/
582609 tpl := swiftproxy .SecretTemplates (
583610 instance ,
@@ -591,6 +618,9 @@ func (r *SwiftProxyReconciler) Reconcile(ctx context.Context, req ctrl.Request)
591618 os .GetRegion (),
592619 transportURLString ,
593620 instance .Spec .APITimeout ,
621+ useAC ,
622+ acID ,
623+ acSecret ,
594624 )
595625 err = secret .EnsureSecrets (ctx , helper , instance , tpl , & envVars )
596626 if err != nil {
@@ -846,7 +876,43 @@ func (r *SwiftProxyReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Ma
846876 return nil
847877 }
848878
849- return ctrl .NewControllerManagedBy (mgr ).
879+ // Application Credential secret watching function
880+ acSecretFn := func (_ context.Context , o client.Object ) []reconcile.Request {
881+ name := o .GetName ()
882+ ns := o .GetNamespace ()
883+ result := []reconcile.Request {}
884+
885+ // Only handle Secret objects
886+ if _ , isSecret := o .(* corev1.Secret ); ! isSecret {
887+ return nil
888+ }
889+
890+ // Check if this is a swift AC secret by name pattern (ac-swift-secret)
891+ expectedSecretName := keystonev1 .GetACSecretName ("swift" )
892+ if name == expectedSecretName {
893+ // get all SwiftProxy CRs in this namespace
894+ swiftProxies := & swiftv1beta1.SwiftProxyList {}
895+ listOpts := []client.ListOption {
896+ client .InNamespace (ns ),
897+ }
898+ if err := r .List (context .Background (), swiftProxies , listOpts ... ); err != nil {
899+ return nil
900+ }
901+
902+ // Enqueue reconcile for all swift proxy instances
903+ for _ , cr := range swiftProxies .Items {
904+ objKey := client.ObjectKey {
905+ Namespace : ns ,
906+ Name : cr .Name ,
907+ }
908+ result = append (result , reconcile.Request {NamespacedName : objKey })
909+ }
910+ }
911+
912+ return result
913+ }
914+
915+ b := ctrl .NewControllerManagedBy (mgr ).
850916 For (& swiftv1beta1.SwiftProxy {}).
851917 Owns (& corev1.Secret {}).
852918 Owns (& keystonev1.KeystoneService {}).
@@ -859,15 +925,17 @@ func (r *SwiftProxyReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Ma
859925 handler .EnqueueRequestsFromMapFunc (r .findObjectsForSrc ),
860926 builder .WithPredicates (predicate.ResourceVersionChangedPredicate {}),
861927 ).
928+ Watches (& corev1.Secret {},
929+ handler .EnqueueRequestsFromMapFunc (acSecretFn )).
862930 Watches (& memcachedv1.Memcached {},
863931 handler .EnqueueRequestsFromMapFunc (memcachedFn )).
864932 Watches (& topologyv1.Topology {},
865933 handler .EnqueueRequestsFromMapFunc (r .findObjectsForSrc ),
866934 builder .WithPredicates (predicate.GenerationChangedPredicate {})).
867935 Watches (& keystonev1.KeystoneAPI {},
868936 handler .EnqueueRequestsFromMapFunc (r .findObjectForSrc ),
869- builder .WithPredicates (keystonev1 .KeystoneAPIStatusChangedPredicate )).
870- Complete (r )
937+ builder .WithPredicates (keystonev1 .KeystoneAPIStatusChangedPredicate ))
938+ return b . Complete (r )
871939}
872940
873941func (r * SwiftProxyReconciler ) findObjectsForSrc (ctx context.Context , src client.Object ) []reconcile.Request {
@@ -1031,3 +1099,46 @@ func (r *SwiftProxyReconciler) transportURLCreateOrUpdate(
10311099
10321100 return transportURL , op , err
10331101}
1102+
1103+ // verifyApplicationCredentials checks if ApplicationCredential secret exists and adds it to configVars
1104+ // The AC secret is created by the keystone-operator's AC controller when the AC is ready.
1105+ // If the secret exists and is valid, we use AC auth. Otherwise, we fall back to password auth.
1106+ func (r * SwiftProxyReconciler ) verifyApplicationCredentials (
1107+ ctx context.Context ,
1108+ log logr.Logger ,
1109+ client client.Client ,
1110+ namespace string ,
1111+ serviceName string ,
1112+ configVars * map [string ]env.Setter ,
1113+ ) (ctrl.Result , error ) {
1114+ // Check if AC secret exists (created by keystone AC controller)
1115+ acSecretName := keystonev1 .GetACSecretName (serviceName )
1116+ secretKey := types.NamespacedName {Namespace : namespace , Name : acSecretName }
1117+
1118+ hash , res , err := secret .VerifySecret (
1119+ ctx ,
1120+ secretKey ,
1121+ []string {"AC_ID" , "AC_SECRET" },
1122+ client ,
1123+ 10 * time .Second ,
1124+ )
1125+
1126+ // VerifySecret returns res.RequeueAfter > 0 when secret not found (not an error)
1127+ // For AC, this is optional, so we just skip it instead of requeueing
1128+ if res .RequeueAfter > 0 {
1129+ log .V (1 ).Info ("ApplicationCredential secret not found, using password auth" )
1130+ return ctrl.Result {}, nil
1131+ }
1132+
1133+ if err != nil {
1134+ // Actual error (not NotFound) - log and continue with password auth
1135+ log .Info ("ApplicationCredential secret verification failed, continuing with password auth" , "error" , err .Error ())
1136+ return ctrl.Result {}, nil
1137+ }
1138+
1139+ // AC secret exists and is valid - add to configVars for hash tracking
1140+ (* configVars )["secret-" + acSecretName ] = env .SetValue (hash )
1141+ log .Info ("Using ApplicationCredential authentication" )
1142+
1143+ return ctrl.Result {}, nil
1144+ }
0 commit comments