Skip to content

Commit b0e9d4f

Browse files
committed
Application Credential support
Signed-off-by: Veronika Fisarova <[email protected]>
1 parent 223f7d6 commit b0e9d4f

File tree

10 files changed

+220
-20
lines changed

10 files changed

+220
-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-20250428100042-040976c94314

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: 21 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,25 @@ 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+
if err := r.Client.Get(ctx, acName, ac); err == nil {
671+
// fetch AC Secret
672+
secret := &corev1.Secret{}
673+
secName := types.NamespacedName{Namespace: ac.Namespace, Name: ac.Status.SecretName}
674+
if err := r.Client.Get(ctx, secName, secret); err == nil {
675+
// switch to application credentials auth
676+
templateParameters["UseApplicationCredentials"] = true
677+
templateParameters["ACID"] = string(secret.Data["AC_ID"])
678+
templateParameters["ACSecret"] = string(secret.Data["AC_SECRET"])
679+
Log.Info("Using ApplicationCredentials auth")
680+
}
681+
} else if !k8s_errors.IsNotFound(err) {
682+
return err
683+
}
684+
664685
// To avoid a json parsing error in kolla files, we always need to set PKCS11ClientDataPath
665686
// This gets overridden in the PKCS11 section below if needed.
666687
templateParameters["PKCS11ClientDataPath"] = barbicanv1beta1.DefaultPKCS11ClientDataPath

controllers/barbicanapi_controller.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,36 @@ 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+
err = r.Client.Get(ctx, types.NamespacedName{Namespace: instance.Namespace, Name: acName}, ac)
619+
if k8s_errors.IsNotFound(err) {
620+
Log.Info("No ApplicationCredential CR found, using password auth", "ac", acName)
621+
} else if err != nil {
622+
return ctrl.Result{}, err
623+
} else {
624+
secretName := ac.Status.SecretName
625+
if secretName == "" {
626+
Log.Info("ApplicationCredential created but Secret not yet ready, requeueing", "ac", acName)
627+
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
628+
}
629+
hashAC, res, err := secret.VerifySecret(
630+
ctx,
631+
types.NamespacedName{Name: secretName, Namespace: instance.Namespace},
632+
[]string{"AC_ID", "AC_SECRET"},
633+
helper.GetClient(),
634+
10*time.Second,
635+
)
636+
if err != nil {
637+
return ctrl.Result{}, err
638+
}
639+
if res.RequeueAfter > 0 {
640+
return res, nil
641+
}
642+
configVars["secret-"+secretName] = env.SetValue(hashAC)
643+
}
644+
615645
//
616646
// TLS input validation
617647
//
@@ -985,7 +1015,7 @@ func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
9851015
return err
9861016
}
9871017

988-
return ctrl.NewControllerManagedBy(mgr).
1018+
b := ctrl.NewControllerManagedBy(mgr).
9891019
For(&barbicanv1beta1.BarbicanAPI{}).
9901020
Owns(&corev1.Service{}).
9911021
Owns(&corev1.Secret{}).
@@ -998,8 +1028,10 @@ func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
9981028
).
9991029
Watches(&topologyv1.Topology{},
10001030
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
1001-
builder.WithPredicates(predicate.GenerationChangedPredicate{})).
1002-
Complete(r)
1031+
builder.WithPredicates(predicate.GenerationChangedPredicate{}),
1032+
)
1033+
b = AddACWatches(b)
1034+
return b.Complete(r)
10031035
}
10041036

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

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 {

go.mod

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

9393
// custom RabbitmqClusterSpecCore for OpenStackControlplane (v2.6.0_patches_tag)
9494
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20241017142550-a3524acedd49 //allow-merging
95+
96+
replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/Deydra71/keystone-operator/api v0.0.0-20250428100042-040976c94314

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/Deydra71/keystone-operator/api v0.0.0-20250428100042-040976c94314 h1:8BROw/Rye41WXwj9Bs0P0V1aUaVAMm++R+8Rla+v+WI=
2+
github.com/Deydra71/keystone-operator/api v0.0.0-20250428100042-040976c94314/go.mod h1:VPkYswnrCtlSMTeYjgxTOpfNN7zvxqa+kZ8EWDJaFrg=
13
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
24
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
35
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
@@ -80,8 +82,6 @@ github.com/openshift/api v0.0.0-20240830023148-b7d0481c9094 h1:J1wuGhVxpsHykZBa6
8082
github.com/openshift/api v0.0.0-20240830023148-b7d0481c9094/go.mod h1:CxgbWAlvu2iQB0UmKTtRu1YfepRg1/vJ64n2DlIEVz4=
8183
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250424140239-2d89c1d9f3ec h1:Sr12fbgiUTL/a7qvKCosedKW5gn5S+53DgRJgeveTk4=
8284
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250424140239-2d89c1d9f3ec/go.mod h1:XywwuHkxaBZA+6QsF+N/3f9ekBq3tH0I/gQZzwL89GU=
83-
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20250424160141-6db2b5a653cf h1:RWYHdI5Aia5sUawoD8VgE98YUaQtqFsiQt6pRYMjN4g=
84-
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20250424160141-6db2b5a653cf/go.mod h1:VPkYswnrCtlSMTeYjgxTOpfNN7zvxqa+kZ8EWDJaFrg=
8585
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250423055245-3cb2ae8df6f0 h1:L2YsApIsUga1ku2siRM/kPViRNk756q+g7jrweAHkdo=
8686
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250423055245-3cb2ae8df6f0/go.mod h1:UwHXRIrMSPJD3lFqrA4oKmRXVLFQCRkLAj9x6KLEHiQ=
8787
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20250423055245-3cb2ae8df6f0 h1:FAHrScvlj6w17wvcDhJ0ZnmraMrrOX1CxzvqZK595hA=

templates/barbican/config/00-default.conf

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,19 @@ connection={{ .DatabaseConnection }}
1212

1313
{{ if (index . "KeystoneAuthURL") }}
1414
[keystone_authtoken]
15-
auth_version = v3
16-
auth_url={{ .KeystoneAuthURL }}
17-
auth_type=password
18-
username={{ .ServiceUser }}
19-
user_domain_name=Default
20-
password = {{ .ServicePassword }}
21-
project_name=service
22-
project_domain_name=Default
23-
interface = internal
15+
auth_url = {{ .KeystoneAuthURL }}
16+
auth_type = {{ if .UseApplicationCredentials }}v3applicationcredential{{ else }}password{{ end }}
17+
18+
{{ if .UseApplicationCredentials -}}
19+
application_credential_id = {{ .ACID }}
20+
application_credential_secret = {{ .ACSecret }}
21+
{{- else -}}
22+
username = {{ .ServiceUser }}
23+
user_domain_name = Default
24+
password = {{ .ServicePassword }}
25+
project_name = service
26+
project_domain_name= Default
27+
{{- end }}
2428
{{- end }}
2529

2630
[oslo_messaging_notifications]

0 commit comments

Comments
 (0)