Skip to content

Commit d266335

Browse files
committed
Application Credential support
1 parent f8d7a89 commit d266335

File tree

10 files changed

+199
-11
lines changed

10 files changed

+199
-11
lines changed

api/go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,5 @@ replace k8s.io/component-base => k8s.io/component-base v0.31.13 //allow-merging
105105
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec //allow-merging
106106

107107
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250627150254-e9823e99808e //allow-merging
108+
109+
replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/Deydra71/keystone-operator/api v0.0.0-20251014080018-27792b7a40a5

config/rbac/role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ rules:
102102
- keystone.openstack.org
103103
resources:
104104
- keystoneapis
105+
- keystoneapplicationcredentials
105106
verbs:
106107
- get
107108
- list

controllers/barbican_controller.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ func (r *BarbicanReconciler) GetLogger(ctx context.Context) logr.Logger {
106106
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneapis,verbs=get;list;watch;
107107
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneservices,verbs=get;list;watch;create;update;patch;delete;
108108
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneendpoints,verbs=get;list;watch;create;update;patch;delete;
109+
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneapplicationcredentials,verbs=get;list;watch
109110
//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete;
110111
//+kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;update;patch;delete;
111112
//+kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch;create;update;patch;delete;
@@ -120,6 +121,7 @@ func (r *BarbicanReconciler) GetLogger(ctx context.Context) logr.Logger {
120121

121122
// service account, role, rolebinding
122123
//+kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;list;watch;create;update;patch
124+
//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch
123125
//+kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=roles,verbs=get;list;watch;create;update;patch
124126
//+kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=rolebindings,verbs=get;list;watch;create;update;patch
125127
//+kubebuilder:rbac:groups="security.openshift.io",resourceNames=anyuid,resources=securitycontextconstraints,verbs=use
@@ -717,6 +719,18 @@ func (r *BarbicanReconciler) generateServiceConfig(
717719
"EnableSecureRBAC": instance.Spec.BarbicanAPI.EnableSecureRBAC,
718720
}
719721

722+
templateParameters["UseApplicationCredentials"] = false
723+
// Try to get Application Credential for this service (via keystone api helper)
724+
if acData, err := keystonev1.GetApplicationCredentialFromSecret(ctx, r.Client, instance.Namespace, barbican.ServiceName); err != nil {
725+
Log.Error(err, "Failed to get ApplicationCredential for service", "service", barbican.ServiceName)
726+
return err
727+
} else if acData != nil {
728+
templateParameters["UseApplicationCredentials"] = true
729+
templateParameters["ACID"] = acData.ID
730+
templateParameters["ACSecret"] = acData.Secret
731+
Log.Info("Using ApplicationCredentials auth", "service", barbican.ServiceName)
732+
}
733+
720734
// To avoid a json parsing error in kolla files, we always need to set PKCS11ClientDataPath
721735
// This gets overridden in the PKCS11 section below if needed.
722736
templateParameters["PKCS11ClientDataPath"] = barbicanv1beta1.DefaultPKCS11ClientDataPath

controllers/barbicanapi_controller.go

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,19 @@ func (r *BarbicanAPIReconciler) reconcileNormal(ctx context.Context, instance *b
630630

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

633+
// Verify Application Credentials if available
634+
ctrlResult, err = keystonev1.VerifyApplicationCredentialsForService(
635+
ctx,
636+
r.Client,
637+
instance.Namespace,
638+
barbican.ServiceName,
639+
&configVars,
640+
10*time.Second,
641+
)
642+
if (err != nil || ctrlResult != ctrl.Result{}) {
643+
return ctrlResult, err
644+
}
645+
633646
//
634647
// TLS input validation
635648
//
@@ -1026,6 +1039,42 @@ func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
10261039
return err
10271040
}
10281041

1042+
// Application Credential secret watching function
1043+
acSecretFn := func(_ context.Context, o client.Object) []reconcile.Request {
1044+
name := o.GetName()
1045+
ns := o.GetNamespace()
1046+
result := []reconcile.Request{}
1047+
1048+
// Only handle Secret objects
1049+
if _, isSecret := o.(*corev1.Secret); !isSecret {
1050+
return nil
1051+
}
1052+
1053+
// Check if this is a barbican AC secret by name pattern (ac-barbican-secret)
1054+
expectedSecretName := keystonev1.GetACSecretName("barbican")
1055+
if name == expectedSecretName {
1056+
// get all BarbicanAPI CRs in this namespace
1057+
barbicanAPIs := &barbicanv1beta1.BarbicanAPIList{}
1058+
listOpts := []client.ListOption{
1059+
client.InNamespace(ns),
1060+
}
1061+
if err := r.List(context.Background(), barbicanAPIs, listOpts...); err != nil {
1062+
return nil
1063+
}
1064+
1065+
// Enqueue reconcile for all barbican API instances
1066+
for _, cr := range barbicanAPIs.Items {
1067+
objKey := client.ObjectKey{
1068+
Namespace: ns,
1069+
Name: cr.Name,
1070+
}
1071+
result = append(result, reconcile.Request{NamespacedName: objKey})
1072+
}
1073+
}
1074+
1075+
return result
1076+
}
1077+
10291078
return ctrl.NewControllerManagedBy(mgr).
10301079
For(&barbicanv1beta1.BarbicanAPI{}).
10311080
Owns(&corev1.Service{}).
@@ -1037,9 +1086,12 @@ func (r *BarbicanAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
10371086
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
10381087
builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}),
10391088
).
1089+
Watches(&corev1.Secret{},
1090+
handler.EnqueueRequestsFromMapFunc(acSecretFn)).
10401091
Watches(&topologyv1.Topology{},
10411092
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
1042-
builder.WithPredicates(predicate.GenerationChangedPredicate{})).
1093+
builder.WithPredicates(predicate.GenerationChangedPredicate{}),
1094+
).
10431095
Complete(r)
10441096
}
10451097

controllers/barbicankeystonelistener_controller.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ import (
2929
"github.com/openstack-k8s-operators/barbican-operator/pkg/barbican"
3030
"github.com/openstack-k8s-operators/barbican-operator/pkg/barbicankeystonelistener"
3131
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
32-
33-
// keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
3432
"github.com/openstack-k8s-operators/lib-common/modules/common"
3533
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
3634
"github.com/openstack-k8s-operators/lib-common/modules/common/deployment"
@@ -750,8 +748,10 @@ func (r *BarbicanKeystoneListenerReconciler) SetupWithManager(mgr ctrl.Manager)
750748
).
751749
Watches(&topologyv1.Topology{},
752750
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
753-
builder.WithPredicates(predicate.GenerationChangedPredicate{})).
751+
builder.WithPredicates(predicate.GenerationChangedPredicate{}),
752+
).
754753
Complete(r)
754+
755755
}
756756

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

controllers/barbicanworker_controller.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,8 @@ func (r *BarbicanWorkerReconciler) SetupWithManager(mgr ctrl.Manager) error {
771771
).
772772
Watches(&topologyv1.Topology{},
773773
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
774-
builder.WithPredicates(predicate.GenerationChangedPredicate{})).
774+
builder.WithPredicates(predicate.GenerationChangedPredicate{}),
775+
).
775776
Complete(r)
776777
}
777778

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ require (
5454
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
5555
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
5656
github.com/openshift/api v3.9.0+incompatible // indirect
57-
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20250922082314-c83d83092a04 // indirect
57+
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20250929092825-4c2402451077 // indirect
5858
github.com/pkg/errors v0.9.1 // indirect
5959
github.com/prometheus/client_golang v1.22.0 // indirect
6060
github.com/prometheus/client_model v0.6.2 // indirect
@@ -116,3 +116,5 @@ replace k8s.io/component-base => k8s.io/component-base v0.31.13 //allow-merging
116116
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec //allow-merging
117117

118118
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250627150254-e9823e99808e //allow-merging
119+
120+
replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/Deydra71/keystone-operator/api v0.0.0-20251014080018-27792b7a40a5

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/Deydra71/keystone-operator/api v0.0.0-20251014080018-27792b7a40a5 h1:qpFuqb7xf9rgua2qwOIJYhB9+ePHB0FfQ/mIufzw7Nc=
2+
github.com/Deydra71/keystone-operator/api v0.0.0-20251014080018-27792b7a40a5/go.mod h1:braI3juap0JIy6XOvu0AHqVGkfn2/dbw5BBRv84oSAw=
13
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
24
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
35
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -100,12 +102,10 @@ github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e h1:E1OdwSpqWuDPCedyU
100102
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
101103
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251002120642-c2d58c6fc03e h1:5q47hHT53v0PnNj2pwHHQ1+ZWC3kQLu1jtulTUrJ2cE=
102104
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251002120642-c2d58c6fc03e/go.mod h1:LfqzznghLpo+b9jVgyvqUoOZMcc3Ff0gXSmLLtFsj9w=
103-
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20251002084815-17073bbaef03 h1:6yHHmTZ/AM+RIR3EBuXgrIXTsKE2bGIOfX4v5FrNcho=
104-
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20251002084815-17073bbaef03/go.mod h1:fuXKxuK4eCE9zV/Uk4d/i1Cny77wXWHpVTL9/UKwxbo=
105105
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250929092825-4c2402451077 h1:missBxDwEfOdkHVKd6zyCyaQjSObw9Ge1O4A7WU5EuM=
106106
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250929092825-4c2402451077/go.mod h1:CjsYQ/dUr4eUmBEvM3UFUxvYvl2bAhGfGflaD+N4fWA=
107-
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20250922082314-c83d83092a04 h1:1t4qZshLvaTzytFb9foCBtTtKT4uXzYtVaYTlgYbt+4=
108-
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20250922082314-c83d83092a04/go.mod h1:IO6+EHBk1Ttd4L8mfnMtG58cc36tDyvdxzCytn+hKeE=
107+
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20250929092825-4c2402451077 h1:z576+XURUzBr7S48aJyHryDgnMFtvbOshXgXCbrGt04=
108+
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20250929092825-4c2402451077/go.mod h1:HD4ZmuJ7oul82bAnnpWf9v69webjyQ9pMMCgzuVKVFE=
109109
github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20250929092825-4c2402451077 h1:9tpPDBV2RLXMDgt13ec8XR2OatFriItseqg+Oyvx9GA=
110110
github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20250929092825-4c2402451077/go.mod h1:JPQHkExlxeT6MU3DNJgXXJJG0NMQHlZwxxfbYRaP3eg=
111111
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20250929092825-4c2402451077 h1:h11tW/Ntg9OiKCnKVAMgR+ka12597ai31OeAD1FGa4s=

templates/barbican/config/00-default.conf

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,20 @@ connection={{ .DatabaseConnection }}
1414
[keystone_authtoken]
1515
auth_version = v3
1616
auth_url={{ .KeystoneAuthURL }}
17-
auth_type=password
17+
auth_type = {{ if .UseApplicationCredentials }}v3applicationcredential{{ else }}password{{ end }}
18+
19+
{{ if .UseApplicationCredentials -}}
20+
application_credential_id = {{ .ACID }}
21+
application_credential_secret = {{ .ACSecret }}
22+
{{- else -}}
1823
username={{ .ServiceUser }}
1924
user_domain_name=Default
2025
password = {{ .ServicePassword }}
2126
project_name=service
2227
project_domain_name=Default
2328
interface = internal
2429
{{- end }}
30+
{{- end }}
2531

2632
[oslo_messaging_notifications]
2733
driver=messagingv2

tests/functional/barbican_controller_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ import (
1515
controllers "github.com/openstack-k8s-operators/barbican-operator/controllers"
1616
"github.com/openstack-k8s-operators/barbican-operator/pkg/barbican"
1717
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
18+
keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
1819
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
1920
mariadb_test "github.com/openstack-k8s-operators/mariadb-operator/api/test/helpers"
2021
corev1 "k8s.io/api/core/v1"
22+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2123
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2224
"k8s.io/apimachinery/pkg/types"
2325
)
@@ -1589,6 +1591,114 @@ var _ = Describe("Barbican controller", func() {
15891591
})
15901592
})
15911593

1594+
When("An ApplicationCredential is created for Barbican", func() {
1595+
var (
1596+
acName string
1597+
acSecretName string
1598+
)
1599+
BeforeEach(func() {
1600+
DeferCleanup(k8sClient.Delete, ctx,
1601+
CreateBarbicanMessageBusSecret(
1602+
barbicanTest.Instance.Namespace,
1603+
barbicanTest.RabbitmqSecretName,
1604+
),
1605+
)
1606+
DeferCleanup(k8sClient.Delete, ctx,
1607+
CreateBarbicanSecret(
1608+
barbicanTest.Instance.Namespace, SecretName))
1609+
DeferCleanup(th.DeleteInstance,
1610+
CreateBarbican(barbicanTest.Instance, GetDefaultBarbicanSpec()))
1611+
DeferCleanup(
1612+
mariadb.DeleteDBService,
1613+
mariadb.CreateDBService(
1614+
barbicanTest.Instance.Namespace,
1615+
GetBarbican(barbicanTest.Instance).Spec.DatabaseInstance,
1616+
corev1.ServiceSpec{
1617+
Ports: []corev1.ServicePort{{Port: 3306}}}))
1618+
1619+
DeferCleanup(keystone.DeleteKeystoneAPI,
1620+
keystone.CreateKeystoneAPI(barbicanTest.Instance.Namespace),
1621+
)
1622+
1623+
acName = fmt.Sprintf("ac-%s", barbican.ServiceName)
1624+
acSecretName = acName + "-secret"
1625+
secret := &corev1.Secret{
1626+
ObjectMeta: metav1.ObjectMeta{
1627+
Namespace: barbicanTest.Instance.Namespace,
1628+
Name: acSecretName,
1629+
},
1630+
Data: map[string][]byte{
1631+
"AC_ID": []byte("foo"),
1632+
"AC_SECRET": []byte("supersecretacsecret"),
1633+
},
1634+
}
1635+
DeferCleanup(k8sClient.Delete, ctx, secret)
1636+
Expect(k8sClient.Create(ctx, secret)).To(Succeed())
1637+
1638+
ac := &keystonev1.KeystoneApplicationCredential{
1639+
ObjectMeta: metav1.ObjectMeta{
1640+
Namespace: barbicanTest.Instance.Namespace,
1641+
Name: acName,
1642+
},
1643+
Spec: keystonev1.KeystoneApplicationCredentialSpec{
1644+
UserName: barbican.ServiceName,
1645+
Secret: SecretName,
1646+
PasswordSelector: "BarbicanPassword",
1647+
Roles: []string{"admin", "member"},
1648+
AccessRules: []keystonev1.ACRule{{Service: "identity", Method: "POST", Path: "/auth/tokens"}},
1649+
ExpirationDays: 30,
1650+
GracePeriodDays: 5,
1651+
},
1652+
}
1653+
DeferCleanup(k8sClient.Delete, ctx, ac)
1654+
Expect(k8sClient.Create(ctx, ac)).To(Succeed())
1655+
1656+
fetched := &keystonev1.KeystoneApplicationCredential{}
1657+
key := types.NamespacedName{Namespace: ac.Namespace, Name: ac.Name}
1658+
Expect(k8sClient.Get(ctx, key, fetched)).To(Succeed())
1659+
1660+
fetched.Status.SecretName = acSecretName
1661+
now := metav1.Now()
1662+
readyCond := condition.Condition{
1663+
Type: condition.ReadyCondition,
1664+
Status: corev1.ConditionTrue,
1665+
Reason: condition.ReadyReason,
1666+
Message: condition.ReadyMessage,
1667+
LastTransitionTime: now,
1668+
}
1669+
fetched.Status.Conditions = condition.Conditions{readyCond}
1670+
Expect(k8sClient.Status().Update(ctx, fetched)).To(Succeed())
1671+
1672+
infra.SimulateTransportURLReady(barbicanTest.BarbicanTransportURL)
1673+
mariadb.SimulateMariaDBAccountCompleted(barbicanTest.BarbicanDatabaseAccount)
1674+
mariadb.SimulateMariaDBDatabaseCompleted(barbicanTest.BarbicanDatabaseName)
1675+
1676+
th.SimulateJobSuccess(barbicanTest.BarbicanDBSync)
1677+
1678+
keystone.SimulateKeystoneEndpointReady(barbicanTest.BarbicanKeystoneEndpoint)
1679+
})
1680+
1681+
It("should render ApplicationCredential auth in 00-default.conf", func() {
1682+
keystone.SimulateKeystoneEndpointReady(barbicanTest.BarbicanKeystoneEndpoint)
1683+
1684+
var cfgSecret corev1.Secret
1685+
Eventually(func(g Gomega) {
1686+
cfgSecret = th.GetSecret(barbicanTest.BarbicanAPIConfigSecret)
1687+
g.Expect(cfgSecret).NotTo(BeNil())
1688+
}, timeout, interval).Should(Succeed())
1689+
1690+
conf := string(cfgSecret.Data["00-default.conf"])
1691+
1692+
// check for rendered AC lines
1693+
Expect(conf).To(ContainSubstring(
1694+
"application_credential_id = foo"),
1695+
)
1696+
Expect(conf).To(ContainSubstring(
1697+
"application_credential_secret = supersecretacsecret"),
1698+
)
1699+
})
1700+
})
1701+
15921702
// Run MariaDBAccount suite tests. these are pre-packaged ginkgo tests
15931703
// that exercise standard account create / update patterns that should be
15941704
// common to all controllers that ensure MariaDBAccount CRs.

0 commit comments

Comments
 (0)