Skip to content

Commit e7a0cd5

Browse files
committed
Application Credential support
Signed-off-by: Veronika Fisarova <[email protected]>
1 parent 6f6f04f commit e7a0cd5

File tree

11 files changed

+374
-20
lines changed

11 files changed

+374
-20
lines changed

api/go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,5 @@ replace github.com/openshift/api => github.com/openshift/api v0.0.0-202408300231
7979

8080
// custom RabbitmqClusterSpecCore for OpenStackControlplane (v2.6.0_patches_tag)
8181
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20241017142550-a3524acedd49 //allow-merging
82+
83+
replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/Deydra71/keystone-operator/api v0.0.0-20250519123217-49620096eb19

config/rbac/role.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ rules:
1616
- patch
1717
- update
1818
- watch
19+
- apiGroups:
20+
- ""
21+
resources:
22+
- secrets
23+
verbs:
24+
- get
25+
- list
26+
- watch
1927
- apiGroups:
2028
- ""
2129
resources:
@@ -203,6 +211,14 @@ rules:
203211
- get
204212
- list
205213
- watch
214+
- apiGroups:
215+
- keystone.openstack.org
216+
resources:
217+
- applicationcredentials
218+
verbs:
219+
- get
220+
- list
221+
- watch
206222
- apiGroups:
207223
- keystone.openstack.org
208224
resources:

controllers/barbican_common.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,20 @@ import (
2424

2525
barbicanv1beta1 "github.com/openstack-k8s-operators/barbican-operator/api/v1beta1"
2626
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
27+
keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
2728
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
2829
"github.com/openstack-k8s-operators/lib-common/modules/common/env"
2930
"github.com/openstack-k8s-operators/lib-common/modules/common/helper"
3031
"github.com/openstack-k8s-operators/lib-common/modules/common/secret"
3132
"github.com/openstack-k8s-operators/lib-common/modules/common/util"
33+
corev1 "k8s.io/api/core/v1"
3234
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35+
"k8s.io/apimachinery/pkg/types"
36+
"sigs.k8s.io/controller-runtime/pkg/builder"
3337
"sigs.k8s.io/controller-runtime/pkg/client"
38+
"sigs.k8s.io/controller-runtime/pkg/handler"
39+
"sigs.k8s.io/controller-runtime/pkg/predicate"
40+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3441
)
3542

3643
type conditionUpdater interface {
@@ -146,3 +153,53 @@ func GenerateSecretStoreTemplateMap(
146153
}
147154
return tempMap, nil
148155
}
156+
157+
// AddACWatches adds ApplicationCredential + Secret watches to the passed controller builder
158+
func AddACWatches(b *builder.Builder) *builder.Builder {
159+
const (
160+
acPrefix = "ac-"
161+
acSecSuffix = "-secret"
162+
)
163+
164+
acMap := handler.MapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
165+
name := obj.GetName()
166+
ns := obj.GetNamespace()
167+
168+
// must begin with "ac-"
169+
if !strings.HasPrefix(name, acPrefix) {
170+
return nil
171+
}
172+
trim := strings.TrimPrefix(name, acPrefix)
173+
// for Secrets also strip "-secret"
174+
if _, isSecret := obj.(*corev1.Secret); isSecret {
175+
if !strings.HasSuffix(trim, acSecSuffix) {
176+
return nil
177+
}
178+
trim = strings.TrimSuffix(trim, acSecSuffix)
179+
}
180+
181+
// enqueue reconcile for each of barbican controllers
182+
svc := trim
183+
return []reconcile.Request{
184+
{NamespacedName: types.NamespacedName{Namespace: ns, Name: svc + "-api"}},
185+
{NamespacedName: types.NamespacedName{Namespace: ns, Name: svc + "-worker"}},
186+
{NamespacedName: types.NamespacedName{Namespace: ns, Name: svc + "-keystone-listener"}},
187+
}
188+
})
189+
190+
// watch the AC CR
191+
b = b.Watches(
192+
&keystonev1.ApplicationCredential{},
193+
handler.EnqueueRequestsFromMapFunc(acMap),
194+
builder.WithPredicates(predicate.GenerationChangedPredicate{}),
195+
)
196+
197+
// watch the AC kube Secret
198+
b = b.Watches(
199+
&corev1.Secret{},
200+
handler.EnqueueRequestsFromMapFunc(acMap),
201+
builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}),
202+
)
203+
204+
return b
205+
}

controllers/barbican_controller.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ func (r *BarbicanReconciler) GetLogger(ctx context.Context) logr.Logger {
9494
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneapis,verbs=get;list;watch;
9595
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneservices,verbs=get;list;watch;create;update;patch;delete;
9696
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneendpoints,verbs=get;list;watch;create;update;patch;delete;
97+
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=applicationcredentials,verbs=get;list;watch
9798
//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete;
9899
//+kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;update;patch;delete;
99100
//+kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch;create;update;patch;delete;
@@ -108,6 +109,7 @@ func (r *BarbicanReconciler) GetLogger(ctx context.Context) logr.Logger {
108109

109110
// service account, role, rolebinding
110111
//+kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;list;watch;create;update;patch
112+
//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch
111113
//+kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=roles,verbs=get;list;watch;create;update;patch
112114
//+kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=rolebindings,verbs=get;list;watch;create;update;patch
113115
//+kubebuilder:rbac:groups="security.openshift.io",resourceNames=anyuid,resources=securitycontextconstraints,verbs=use
@@ -661,6 +663,32 @@ func (r *BarbicanReconciler) generateServiceConfig(
661663
"EnableSecureRBAC": instance.Spec.BarbicanAPI.EnableSecureRBAC,
662664
}
663665

666+
templateParameters["UseApplicationCredentials"] = false
667+
// Fetch AC CR
668+
ac := &keystonev1.ApplicationCredential{}
669+
acName := types.NamespacedName{Namespace: instance.Namespace, Name: fmt.Sprintf("ac-%s", barbican.ServiceName)}
670+
// Look up the AC
671+
if err := r.Client.Get(ctx, acName, ac); err == nil {
672+
// Look up the AC secret
673+
secret := &corev1.Secret{}
674+
secName := types.NamespacedName{Namespace: ac.Namespace, Name: ac.Status.SecretName}
675+
if err := r.Client.Get(ctx, secName, secret); err != nil {
676+
if k8s_errors.IsNotFound(err) {
677+
return fmt.Errorf("ApplicationCredential Secret not found, %s", secName)
678+
}
679+
Log.Error(err, "Failed to fetch ApplicationCredential Secret", "secret", secName)
680+
return err
681+
}
682+
683+
templateParameters["UseApplicationCredentials"] = true
684+
templateParameters["ACID"] = string(secret.Data["AC_ID"])
685+
templateParameters["ACSecret"] = string(secret.Data["AC_SECRET"])
686+
Log.Info("Using ApplicationCredentials auth", "AC", secret.Name)
687+
} else if !k8s_errors.IsNotFound(err) {
688+
Log.Error(err, "Failed to fetch ApplicationCredential CR", "ac", acName)
689+
return err
690+
}
691+
664692
// To avoid a json parsing error in kolla files, we always need to set PKCS11ClientDataPath
665693
// This gets overridden in the PKCS11 section below if needed.
666694
templateParameters["PKCS11ClientDataPath"] = barbicanv1beta1.DefaultPKCS11ClientDataPath

controllers/barbicanapi_controller.go

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,29 @@ func (r *BarbicanAPIReconciler) reconcileNormal(ctx context.Context, instance *b
612612

613613
Log.Info(fmt.Sprintf("[API] Got secrets '%s'", instance.Name))
614614

615+
// check for ApplicationCredential
616+
acName := fmt.Sprintf("ac-%s", barbican.ServiceName)
617+
ac := &keystonev1.ApplicationCredential{}
618+
if err := r.Client.Get(ctx, client.ObjectKey{Namespace: instance.Namespace, Name: acName}, ac); err == nil {
619+
if res, err := r.verifyServiceCredentials(ctx, helper, instance.Namespace, ac.Status.SecretName, &configVars); err != nil || res.RequeueAfter > 0 {
620+
return res, err
621+
}
622+
} else if !k8s_errors.IsNotFound(err) {
623+
return ctrl.Result{}, err
624+
} else {
625+
// no ApplicationCredential CR, fall back to password auth
626+
if res, err := r.verifySecret(
627+
ctx,
628+
helper,
629+
instance,
630+
instance.Spec.Secret,
631+
[]string{instance.Spec.PasswordSelectors.Service},
632+
&configVars,
633+
); err != nil || res.RequeueAfter > 0 {
634+
return res, err
635+
}
636+
}
637+
615638
//
616639
// TLS input validation
617640
//
@@ -985,7 +1008,7 @@ func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
9851008
return err
9861009
}
9871010

988-
return ctrl.NewControllerManagedBy(mgr).
1011+
b := ctrl.NewControllerManagedBy(mgr).
9891012
For(&barbicanv1beta1.BarbicanAPI{}).
9901013
Owns(&corev1.Service{}).
9911014
Owns(&corev1.Secret{}).
@@ -998,8 +1021,10 @@ func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
9981021
).
9991022
Watches(&topologyv1.Topology{},
10001023
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
1001-
builder.WithPredicates(predicate.GenerationChangedPredicate{})).
1002-
Complete(r)
1024+
builder.WithPredicates(predicate.GenerationChangedPredicate{}),
1025+
)
1026+
b = AddACWatches(b)
1027+
return b.Complete(r)
10031028
}
10041029

10051030
func (r *BarbicanAPIReconciler) findObjectsForSrc(ctx context.Context, src client.Object) []reconcile.Request {
@@ -1035,3 +1060,49 @@ func (r *BarbicanAPIReconciler) findObjectsForSrc(ctx context.Context, src clien
10351060

10361061
return requests
10371062
}
1063+
1064+
// verifyServiceCredentials checks for the AC Secret, requeues if not ready,
1065+
// and puts the hash into configVars
1066+
func (r *BarbicanAPIReconciler) verifyServiceCredentials(
1067+
ctx context.Context,
1068+
helper *helper.Helper,
1069+
namespace string,
1070+
secretName string,
1071+
configVars *map[string]env.Setter,
1072+
) (ctrl.Result, error) {
1073+
log := r.GetLogger(ctx)
1074+
1075+
if secretName == "" {
1076+
log.Info("AC SecretName not populated yet, requeueing")
1077+
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
1078+
}
1079+
1080+
sec := &corev1.Secret{}
1081+
key := types.NamespacedName{Namespace: namespace, Name: secretName}
1082+
if err := r.Client.Get(ctx, key, sec); err != nil {
1083+
if k8s_errors.IsNotFound(err) {
1084+
log.Info("AC Secret not found, requeueing", "secret", key)
1085+
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
1086+
}
1087+
log.Error(err, "Failed to fetch AC Secret", "secret", key)
1088+
return ctrl.Result{}, err
1089+
}
1090+
1091+
hash, res, err := secret.VerifySecret(
1092+
ctx,
1093+
key,
1094+
[]string{"AC_ID", "AC_SECRET"},
1095+
r.Client,
1096+
10*time.Second,
1097+
)
1098+
if err != nil {
1099+
log.Error(err, "Failed to verify AC Secret", "secret", key)
1100+
return ctrl.Result{}, err
1101+
}
1102+
if res.RequeueAfter > 0 {
1103+
return res, nil
1104+
}
1105+
1106+
(*configVars)["secret-"+secretName] = env.SetValue(hash)
1107+
return ctrl.Result{}, nil
1108+
}

controllers/barbicankeystonelistener_controller.go

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/openstack-k8s-operators/barbican-operator/pkg/barbican"
2828
"github.com/openstack-k8s-operators/barbican-operator/pkg/barbicankeystonelistener"
2929
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
30+
keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
3031

3132
// keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
3233
"github.com/openstack-k8s-operators/lib-common/modules/common"
@@ -401,6 +402,36 @@ func (r *BarbicanKeystoneListenerReconciler) reconcileNormal(ctx context.Context
401402

402403
Log.Info(fmt.Sprintf("[KeystoneListener] Got secrets '%s'", instance.Name))
403404

405+
// check for ApplicationCredential
406+
acName := fmt.Sprintf("ac-%s", barbican.ServiceName)
407+
ac := &keystonev1.ApplicationCredential{}
408+
err = r.Client.Get(ctx, types.NamespacedName{Namespace: instance.Namespace, Name: acName}, ac)
409+
if k8s_errors.IsNotFound(err) {
410+
Log.Info("No ApplicationCredential CR found, using password auth", "ac", acName)
411+
} else if err != nil {
412+
return ctrl.Result{}, err
413+
} else {
414+
secretName := ac.Status.SecretName
415+
if secretName == "" {
416+
Log.Info("ApplicationCredential created but Secret not yet ready, requeueing", "ac", acName)
417+
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
418+
}
419+
hashAC, res, err := secret.VerifySecret(
420+
ctx,
421+
types.NamespacedName{Name: secretName, Namespace: instance.Namespace},
422+
[]string{"AC_ID", "AC_SECRET"},
423+
helper.GetClient(),
424+
10*time.Second,
425+
)
426+
if err != nil {
427+
return ctrl.Result{}, err
428+
}
429+
if res.RequeueAfter > 0 {
430+
return res, nil
431+
}
432+
configVars["secret-"+secretName] = env.SetValue(hashAC)
433+
}
434+
404435
//
405436
// TLS input validation
406437
//
@@ -695,7 +726,7 @@ func (r *BarbicanKeystoneListenerReconciler) SetupWithManager(mgr ctrl.Manager)
695726
return err
696727
}
697728

698-
return ctrl.NewControllerManagedBy(mgr).
729+
b := ctrl.NewControllerManagedBy(mgr).
699730
For(&barbicanv1beta1.BarbicanKeystoneListener{}).
700731
// Owns(&corev1.Service{}).
701732
// Owns(&corev1.Secret{}).
@@ -708,8 +739,11 @@ func (r *BarbicanKeystoneListenerReconciler) SetupWithManager(mgr ctrl.Manager)
708739
).
709740
Watches(&topologyv1.Topology{},
710741
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
711-
builder.WithPredicates(predicate.GenerationChangedPredicate{})).
712-
Complete(r)
742+
builder.WithPredicates(predicate.GenerationChangedPredicate{}),
743+
)
744+
b = AddACWatches(b)
745+
return b.Complete(r)
746+
713747
}
714748

715749
func (r *BarbicanKeystoneListenerReconciler) findObjectsForSrc(ctx context.Context, src client.Object) []reconcile.Request {

controllers/barbicanworker_controller.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/openstack-k8s-operators/barbican-operator/pkg/barbican"
2929
"github.com/openstack-k8s-operators/barbican-operator/pkg/barbicanworker"
3030
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
31+
keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
3132

3233
"github.com/openstack-k8s-operators/lib-common/modules/common"
3334
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
@@ -399,6 +400,35 @@ func (r *BarbicanWorkerReconciler) reconcileNormal(ctx context.Context, instance
399400

400401
Log.Info(fmt.Sprintf("[Worker] Got secrets '%s'", instance.Name))
401402

403+
// check for ApplicationCredential
404+
acName := fmt.Sprintf("ac-%s", barbican.ServiceName)
405+
ac := &keystonev1.ApplicationCredential{}
406+
err = r.Client.Get(ctx, types.NamespacedName{Namespace: instance.Namespace, Name: acName}, ac)
407+
if k8s_errors.IsNotFound(err) {
408+
Log.Info("No ApplicationCredential CR found, using password auth", "ac", acName)
409+
} else if err != nil {
410+
return ctrl.Result{}, err
411+
} else {
412+
secretName := ac.Status.SecretName
413+
if secretName == "" {
414+
Log.Info("ApplicationCredential created but Secret not yet ready, requeueing", "ac", acName)
415+
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
416+
}
417+
hashAC, res, err := secret.VerifySecret(
418+
ctx,
419+
types.NamespacedName{Name: secretName, Namespace: instance.Namespace},
420+
[]string{"AC_ID", "AC_SECRET"},
421+
helper.GetClient(),
422+
10*time.Second,
423+
)
424+
if err != nil {
425+
return ctrl.Result{}, err
426+
}
427+
if res.RequeueAfter > 0 {
428+
return res, nil
429+
}
430+
configVars["secret-"+secretName] = env.SetValue(hashAC)
431+
}
402432
//
403433
// TLS input validation
404434
//
@@ -717,7 +747,7 @@ func (r *BarbicanWorkerReconciler) SetupWithManager(mgr ctrl.Manager) error {
717747
return err
718748
}
719749

720-
return ctrl.NewControllerManagedBy(mgr).
750+
b := ctrl.NewControllerManagedBy(mgr).
721751
For(&barbicanv1beta1.BarbicanWorker{}).
722752
// Owns(&corev1.Service{}).
723753
// Owns(&corev1.Secret{}).
@@ -730,8 +760,10 @@ func (r *BarbicanWorkerReconciler) SetupWithManager(mgr ctrl.Manager) error {
730760
).
731761
Watches(&topologyv1.Topology{},
732762
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
733-
builder.WithPredicates(predicate.GenerationChangedPredicate{})).
734-
Complete(r)
763+
builder.WithPredicates(predicate.GenerationChangedPredicate{}),
764+
)
765+
b = AddACWatches(b)
766+
return b.Complete(r)
735767
}
736768

737769
func (r *BarbicanWorkerReconciler) findObjectsForSrc(ctx context.Context, src client.Object) []reconcile.Request {

0 commit comments

Comments
 (0)