@@ -617,6 +617,11 @@ func (r *BarbicanAPIReconciler) reconcileNormal(ctx context.Context, instance *b
617617
618618 Log .Info (fmt .Sprintf ("[API] Got secrets '%s'" , instance .Name ))
619619
620+ // Verify Application Credentials if available
621+ if res , err := r .verifyApplicationCredentials (ctx , helper , instance , & configVars ); err != nil || res .RequeueAfter > 0 {
622+ return res , err
623+ }
624+
620625 //
621626 // TLS input validation
622627 //
@@ -994,7 +999,7 @@ func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
994999 return err
9951000 }
9961001
997- return ctrl .NewControllerManagedBy (mgr ).
1002+ b := ctrl .NewControllerManagedBy (mgr ).
9981003 For (& barbicanv1beta1.BarbicanAPI {}).
9991004 Owns (& corev1.Service {}).
10001005 Owns (& corev1.Secret {}).
@@ -1007,8 +1012,10 @@ func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
10071012 ).
10081013 Watches (& topologyv1.Topology {},
10091014 handler .EnqueueRequestsFromMapFunc (r .findObjectsForSrc ),
1010- builder .WithPredicates (predicate.GenerationChangedPredicate {})).
1011- Complete (r )
1015+ builder .WithPredicates (predicate.GenerationChangedPredicate {}),
1016+ )
1017+ b = AddACWatches (b )
1018+ return b .Complete (r )
10121019}
10131020
10141021func (r * BarbicanAPIReconciler ) findObjectsForSrc (ctx context.Context , src client.Object ) []reconcile.Request {
@@ -1044,3 +1051,89 @@ func (r *BarbicanAPIReconciler) findObjectsForSrc(ctx context.Context, src clien
10441051
10451052 return requests
10461053}
1054+
1055+ // verifyApplicationCredentials handles Application Credentials validation
1056+ // It only uses AC if it's in a complete/ready state, otherwise continues with password auth
1057+ func (r * BarbicanAPIReconciler ) verifyApplicationCredentials (
1058+ ctx context.Context ,
1059+ _ * helper.Helper ,
1060+ instance * barbicanv1beta1.BarbicanAPI ,
1061+ configVars * map [string ]env.Setter ,
1062+ ) (ctrl.Result , error ) {
1063+ log := r .GetLogger (ctx )
1064+
1065+ // Check for Application Credential - only use it if it's fully ready
1066+ acName := fmt .Sprintf ("ac-%s" , barbican .ServiceName )
1067+ ac := & keystonev1.KeystoneApplicationCredential {}
1068+
1069+ if err := r .Client .Get (ctx , client.ObjectKey {Namespace : instance .Namespace , Name : acName }, ac ); err == nil {
1070+ // AC CR exists - check if it's in ready state
1071+ if r .isACReady (ctx , ac ) {
1072+ // AC is ready - add it to configVars for hash tracking
1073+ secretKey := types.NamespacedName {Namespace : instance .Namespace , Name : ac .Status .SecretName }
1074+ hash , res , err := secret .VerifySecret (
1075+ ctx ,
1076+ secretKey ,
1077+ []string {"AC_ID" , "AC_SECRET" },
1078+ r .Client ,
1079+ 10 * time .Second ,
1080+ )
1081+ if err != nil {
1082+ log .Info ("ApplicationCredential secret verification failed, continuing with password auth" , "error" , err .Error ())
1083+ } else if res .RequeueAfter > 0 {
1084+ return res , nil
1085+ } else {
1086+ // AC is ready and verified - add to configVars for change tracking
1087+ (* configVars )["secret-" + ac .Status .SecretName ] = env .SetValue (hash )
1088+ log .Info ("Using ApplicationCredential authentication" )
1089+ }
1090+ } else {
1091+ // AC exists but not ready - wait for it
1092+ log .Info ("ApplicationCredential exists but not ready, waiting" )
1093+ instance .Status .Conditions .Set (condition .FalseCondition (
1094+ condition .InputReadyCondition ,
1095+ condition .RequestedReason ,
1096+ condition .SeverityInfo ,
1097+ condition .InputReadyWaitingMessage ))
1098+ return ctrl.Result {RequeueAfter : time .Duration (10 ) * time .Second }, nil
1099+ }
1100+ } else if ! k8s_errors .IsNotFound (err ) {
1101+ return ctrl.Result {}, err
1102+ }
1103+
1104+ return ctrl.Result {}, nil
1105+ }
1106+
1107+ // isACReady checks if ApplicationCredential is in a ready state with all required components
1108+ func (r * BarbicanAPIReconciler ) isACReady (ctx context.Context , ac * keystonev1.KeystoneApplicationCredential ) bool {
1109+ log := r .GetLogger (ctx )
1110+
1111+ // Check if AC has completed setup (secret name is populated)
1112+ if ac .Status .SecretName == "" {
1113+ log .V (1 ).Info ("AC not ready: SecretName not populated" , "ac" , ac .Name )
1114+ return false
1115+ }
1116+
1117+ secret := & corev1.Secret {}
1118+ secretKey := types.NamespacedName {Namespace : ac .Namespace , Name : ac .Status .SecretName }
1119+ if err := r .Client .Get (ctx , secretKey , secret ); err != nil {
1120+ log .V (1 ).Info ("AC not ready: Secret not found" , "secret" , secretKey , "error" , err )
1121+ return false
1122+ }
1123+
1124+ acID , acIDExists := secret .Data ["AC_ID" ]
1125+ acSecret , acSecretExists := secret .Data ["AC_SECRET" ]
1126+
1127+ if ! acIDExists || ! acSecretExists {
1128+ log .V (1 ).Info ("AC not ready: Missing required fields" , "secret" , secretKey )
1129+ return false
1130+ }
1131+
1132+ if len (acID ) == 0 || len (acSecret ) == 0 {
1133+ log .V (1 ).Info ("AC not ready: Empty required fields" , "secret" , secretKey )
1134+ return false
1135+ }
1136+
1137+ log .V (1 ).Info ("AC is ready" , "secret" , secretKey )
1138+ return true
1139+ }
0 commit comments