Skip to content

Commit 293d380

Browse files
committed
Application Credential support
Signed-off-by: Veronika Fisarova <[email protected]>
1 parent 117d547 commit 293d380

File tree

11 files changed

+367
-12
lines changed

11 files changed

+367
-12
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-20250718124530-83b0609d1c8c

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:
@@ -211,6 +219,14 @@ rules:
211219
- get
212220
- list
213221
- watch
222+
- apiGroups:
223+
- keystone.openstack.org
224+
resources:
225+
- keystoneapplicationcredentials
226+
verbs:
227+
- get
228+
- list
229+
- watch
214230
- apiGroups:
215231
- keystone.openstack.org
216232
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 KeystoneApplicationCredential + 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.KeystoneApplicationCredential{},
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
@@ -99,6 +99,7 @@ func (r *BarbicanReconciler) GetLogger(ctx context.Context) logr.Logger {
9999
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneapis,verbs=get;list;watch;
100100
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneservices,verbs=get;list;watch;create;update;patch;delete;
101101
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneendpoints,verbs=get;list;watch;create;update;patch;delete;
102+
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneapplicationcredentials,verbs=get;list;watch
102103
//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete;
103104
//+kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;update;patch;delete;
104105
//+kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch;create;update;patch;delete;
@@ -113,6 +114,7 @@ func (r *BarbicanReconciler) GetLogger(ctx context.Context) logr.Logger {
113114

114115
// service account, role, rolebinding
115116
//+kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;list;watch;create;update;patch
117+
//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch
116118
//+kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=roles,verbs=get;list;watch;create;update;patch
117119
//+kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=rolebindings,verbs=get;list;watch;create;update;patch
118120
//+kubebuilder:rbac:groups="security.openshift.io",resourceNames=anyuid,resources=securitycontextconstraints,verbs=use
@@ -705,6 +707,32 @@ func (r *BarbicanReconciler) generateServiceConfig(
705707
"EnableSecureRBAC": instance.Spec.BarbicanAPI.EnableSecureRBAC,
706708
}
707709

710+
templateParameters["UseApplicationCredentials"] = false
711+
// Fetch AC CR
712+
ac := &keystonev1.KeystoneApplicationCredential{}
713+
acName := types.NamespacedName{Namespace: instance.Namespace, Name: fmt.Sprintf("ac-%s", barbican.ServiceName)}
714+
// Look up the AC
715+
if err := r.Client.Get(ctx, acName, ac); err == nil {
716+
// Look up the AC secret
717+
secret := &corev1.Secret{}
718+
secName := types.NamespacedName{Namespace: ac.Namespace, Name: ac.Status.SecretName}
719+
if err := r.Client.Get(ctx, secName, secret); err != nil {
720+
if k8s_errors.IsNotFound(err) {
721+
return fmt.Errorf("ApplicationCredential Secret not found, %s", secName)
722+
}
723+
Log.Error(err, "Failed to fetch ApplicationCredential Secret", "secret", secName)
724+
return err
725+
}
726+
727+
templateParameters["UseApplicationCredentials"] = true
728+
templateParameters["ACID"] = string(secret.Data["AC_ID"])
729+
templateParameters["ACSecret"] = string(secret.Data["AC_SECRET"])
730+
Log.Info("Using ApplicationCredentials auth", "AC", secret.Name)
731+
} else if !k8s_errors.IsNotFound(err) {
732+
Log.Error(err, "Failed to fetch ApplicationCredential CR", "ac", acName)
733+
return err
734+
}
735+
708736
// To avoid a json parsing error in kolla files, we always need to set PKCS11ClientDataPath
709737
// This gets overridden in the PKCS11 section below if needed.
710738
templateParameters["PKCS11ClientDataPath"] = barbicanv1beta1.DefaultPKCS11ClientDataPath

controllers/barbicanapi_controller.go

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

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

620+
// check for ApplicationCredential
621+
acName := fmt.Sprintf("ac-%s", barbican.ServiceName)
622+
ac := &keystonev1.KeystoneApplicationCredential{}
623+
if err := r.Client.Get(ctx, client.ObjectKey{Namespace: instance.Namespace, Name: acName}, ac); err == nil {
624+
if res, err := r.verifyServiceCredentials(ctx, instance.Namespace, ac.Status.SecretName, &configVars); err != nil || res.RequeueAfter > 0 {
625+
return res, err
626+
}
627+
} else if !k8s_errors.IsNotFound(err) {
628+
return ctrl.Result{}, err
629+
} else {
630+
// no ApplicationCredential CR, fall back to password auth
631+
if res, err := r.verifySecret(
632+
ctx,
633+
helper,
634+
instance,
635+
instance.Spec.Secret,
636+
[]string{instance.Spec.PasswordSelectors.Service},
637+
&configVars,
638+
); err != nil || res.RequeueAfter > 0 {
639+
return res, err
640+
}
641+
}
642+
620643
//
621644
// TLS input validation
622645
//
@@ -994,7 +1017,7 @@ func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
9941017
return err
9951018
}
9961019

997-
return ctrl.NewControllerManagedBy(mgr).
1020+
b := ctrl.NewControllerManagedBy(mgr).
9981021
For(&barbicanv1beta1.BarbicanAPI{}).
9991022
Owns(&corev1.Service{}).
10001023
Owns(&corev1.Secret{}).
@@ -1007,8 +1030,10 @@ func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
10071030
).
10081031
Watches(&topologyv1.Topology{},
10091032
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
1010-
builder.WithPredicates(predicate.GenerationChangedPredicate{})).
1011-
Complete(r)
1033+
builder.WithPredicates(predicate.GenerationChangedPredicate{}),
1034+
)
1035+
b = AddACWatches(b)
1036+
return b.Complete(r)
10121037
}
10131038

10141039
func (r *BarbicanAPIReconciler) findObjectsForSrc(ctx context.Context, src client.Object) []reconcile.Request {
@@ -1044,3 +1069,48 @@ func (r *BarbicanAPIReconciler) findObjectsForSrc(ctx context.Context, src clien
10441069

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

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"
@@ -406,6 +407,36 @@ func (r *BarbicanKeystoneListenerReconciler) reconcileNormal(ctx context.Context
406407

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

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

707-
return ctrl.NewControllerManagedBy(mgr).
738+
b := ctrl.NewControllerManagedBy(mgr).
708739
For(&barbicanv1beta1.BarbicanKeystoneListener{}).
709740
// Owns(&corev1.Service{}).
710741
// Owns(&corev1.Secret{}).
@@ -717,8 +748,11 @@ func (r *BarbicanKeystoneListenerReconciler) SetupWithManager(mgr ctrl.Manager)
717748
).
718749
Watches(&topologyv1.Topology{},
719750
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
720-
builder.WithPredicates(predicate.GenerationChangedPredicate{})).
721-
Complete(r)
751+
builder.WithPredicates(predicate.GenerationChangedPredicate{}),
752+
)
753+
b = AddACWatches(b)
754+
return b.Complete(r)
755+
722756
}
723757

724758
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"
@@ -404,6 +405,35 @@ func (r *BarbicanWorkerReconciler) reconcileNormal(ctx context.Context, instance
404405

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

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

729-
return ctrl.NewControllerManagedBy(mgr).
759+
b := ctrl.NewControllerManagedBy(mgr).
730760
For(&barbicanv1beta1.BarbicanWorker{}).
731761
// Owns(&corev1.Service{}).
732762
// Owns(&corev1.Secret{}).
@@ -739,8 +769,10 @@ func (r *BarbicanWorkerReconciler) SetupWithManager(mgr ctrl.Manager) error {
739769
).
740770
Watches(&topologyv1.Topology{},
741771
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
742-
builder.WithPredicates(predicate.GenerationChangedPredicate{})).
743-
Complete(r)
772+
builder.WithPredicates(predicate.GenerationChangedPredicate{}),
773+
)
774+
b = AddACWatches(b)
775+
return b.Complete(r)
744776
}
745777

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

0 commit comments

Comments
 (0)