@@ -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 //
@@ -1007,6 +1012,42 @@ func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
10071012 return err
10081013 }
10091014
1015+ // Application Credential secret watching function
1016+ acSecretFn := func (_ context.Context , o client.Object ) []reconcile.Request {
1017+ name := o .GetName ()
1018+ ns := o .GetNamespace ()
1019+ result := []reconcile.Request {}
1020+
1021+ // Only handle Secret objects
1022+ if _ , isSecret := o .(* corev1.Secret ); ! isSecret {
1023+ return nil
1024+ }
1025+
1026+ // Check if this is a barbican AC secret by name pattern (ac-barbican-secret)
1027+ expectedSecretName := keystonev1 .GetACSecretName ("barbican" )
1028+ if name == expectedSecretName {
1029+ // get all BarbicanAPI CRs in this namespace
1030+ barbicanAPIs := & barbicanv1beta1.BarbicanAPIList {}
1031+ listOpts := []client.ListOption {
1032+ client .InNamespace (ns ),
1033+ }
1034+ if err := r .Client .List (context .Background (), barbicanAPIs , listOpts ... ); err != nil {
1035+ return nil
1036+ }
1037+
1038+ // Enqueue reconcile for all barbican API instances
1039+ for _ , cr := range barbicanAPIs .Items {
1040+ objKey := client.ObjectKey {
1041+ Namespace : ns ,
1042+ Name : cr .Name ,
1043+ }
1044+ result = append (result , reconcile.Request {NamespacedName : objKey })
1045+ }
1046+ }
1047+
1048+ return result
1049+ }
1050+
10101051 return ctrl .NewControllerManagedBy (mgr ).
10111052 For (& barbicanv1beta1.BarbicanAPI {}).
10121053 Owns (& corev1.Service {}).
@@ -1018,9 +1059,12 @@ func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
10181059 handler .EnqueueRequestsFromMapFunc (r .findObjectsForSrc ),
10191060 builder .WithPredicates (predicate.ResourceVersionChangedPredicate {}),
10201061 ).
1062+ Watches (& corev1.Secret {},
1063+ handler .EnqueueRequestsFromMapFunc (acSecretFn )).
10211064 Watches (& topologyv1.Topology {},
10221065 handler .EnqueueRequestsFromMapFunc (r .findObjectsForSrc ),
1023- builder .WithPredicates (predicate.GenerationChangedPredicate {})).
1066+ builder .WithPredicates (predicate.GenerationChangedPredicate {}),
1067+ ).
10241068 Complete (r )
10251069}
10261070
@@ -1057,3 +1101,89 @@ func (r *BarbicanAPIReconciler) findObjectsForSrc(ctx context.Context, src clien
10571101
10581102 return requests
10591103}
1104+
1105+ // verifyApplicationCredentials handles Application Credentials validation
1106+ // It only uses AC if it's in a complete/ready state, otherwise continues with password auth
1107+ func (r * BarbicanAPIReconciler ) verifyApplicationCredentials (
1108+ ctx context.Context ,
1109+ _ * helper.Helper ,
1110+ instance * barbicanv1beta1.BarbicanAPI ,
1111+ configVars * map [string ]env.Setter ,
1112+ ) (ctrl.Result , error ) {
1113+ log := r .GetLogger (ctx )
1114+
1115+ // Check for Application Credential - only use it if it's fully ready
1116+ acName := fmt .Sprintf ("ac-%s" , barbican .ServiceName )
1117+ ac := & keystonev1.KeystoneApplicationCredential {}
1118+
1119+ if err := r .Client .Get (ctx , client.ObjectKey {Namespace : instance .Namespace , Name : acName }, ac ); err == nil {
1120+ // AC CR exists - check if it's in ready state
1121+ if r .isACReady (ctx , ac ) {
1122+ // AC is ready - add it to configVars for hash tracking
1123+ secretKey := types.NamespacedName {Namespace : instance .Namespace , Name : ac .Status .SecretName }
1124+ hash , res , err := secret .VerifySecret (
1125+ ctx ,
1126+ secretKey ,
1127+ []string {"AC_ID" , "AC_SECRET" },
1128+ r .Client ,
1129+ 10 * time .Second ,
1130+ )
1131+ if err != nil {
1132+ log .Info ("ApplicationCredential secret verification failed, continuing with password auth" , "error" , err .Error ())
1133+ } else if res .RequeueAfter > 0 {
1134+ return res , nil
1135+ } else {
1136+ // AC is ready and verified - add to configVars for change tracking
1137+ (* configVars )["secret-" + ac .Status .SecretName ] = env .SetValue (hash )
1138+ log .Info ("Using ApplicationCredential authentication" )
1139+ }
1140+ } else {
1141+ // AC exists but not ready - wait for it
1142+ log .Info ("ApplicationCredential exists but not ready, waiting" )
1143+ instance .Status .Conditions .Set (condition .FalseCondition (
1144+ condition .InputReadyCondition ,
1145+ condition .RequestedReason ,
1146+ condition .SeverityInfo ,
1147+ condition .InputReadyWaitingMessage ))
1148+ return ctrl.Result {RequeueAfter : time .Duration (10 ) * time .Second }, nil
1149+ }
1150+ } else if ! k8s_errors .IsNotFound (err ) {
1151+ return ctrl.Result {}, err
1152+ }
1153+
1154+ return ctrl.Result {}, nil
1155+ }
1156+
1157+ // isACReady checks if ApplicationCredential is in a ready state with all required components
1158+ func (r * BarbicanAPIReconciler ) isACReady (ctx context.Context , ac * keystonev1.KeystoneApplicationCredential ) bool {
1159+ log := r .GetLogger (ctx )
1160+
1161+ // Check if AC has completed setup (secret name is populated)
1162+ if ac .Status .SecretName == "" {
1163+ log .V (1 ).Info ("AC not ready: SecretName not populated" , "ac" , ac .Name )
1164+ return false
1165+ }
1166+
1167+ secret := & corev1.Secret {}
1168+ secretKey := types.NamespacedName {Namespace : ac .Namespace , Name : ac .Status .SecretName }
1169+ if err := r .Client .Get (ctx , secretKey , secret ); err != nil {
1170+ log .V (1 ).Info ("AC not ready: Secret not found" , "secret" , secretKey , "error" , err )
1171+ return false
1172+ }
1173+
1174+ acID , acIDExists := secret .Data ["AC_ID" ]
1175+ acSecret , acSecretExists := secret .Data ["AC_SECRET" ]
1176+
1177+ if ! acIDExists || ! acSecretExists {
1178+ log .V (1 ).Info ("AC not ready: Missing required fields" , "secret" , secretKey )
1179+ return false
1180+ }
1181+
1182+ if len (acID ) == 0 || len (acSecret ) == 0 {
1183+ log .V (1 ).Info ("AC not ready: Empty required fields" , "secret" , secretKey )
1184+ return false
1185+ }
1186+
1187+ log .V (1 ).Info ("AC is ready" , "secret" , secretKey )
1188+ return true
1189+ }
0 commit comments