Skip to content

Commit 46355b1

Browse files
committed
Application Credential support
1 parent d5429ec commit 46355b1

File tree

9 files changed

+200
-8
lines changed

9 files changed

+200
-8
lines changed

api/go.mod

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

106106
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250627150254-e9823e99808e //allow-merging
107+
108+
replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/Deydra71/keystone-operator/api v0.0.0-20251103091514-244e15fe5d63

controllers/barbican_controller.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,18 @@ func (r *BarbicanReconciler) generateServiceConfig(
717717
"EnableSecureRBAC": instance.Spec.BarbicanAPI.EnableSecureRBAC,
718718
}
719719

720+
templateParameters["UseApplicationCredentials"] = false
721+
// Try to get Application Credential for this service (via keystone api helper)
722+
if acData, err := keystonev1.GetApplicationCredentialFromSecret(ctx, r.Client, instance.Namespace, barbican.ServiceName); err != nil {
723+
Log.Error(err, "Failed to get ApplicationCredential for service", "service", barbican.ServiceName)
724+
return err
725+
} else if acData != nil {
726+
templateParameters["UseApplicationCredentials"] = true
727+
templateParameters["ACID"] = acData.ID
728+
templateParameters["ACSecret"] = acData.Secret
729+
Log.Info("Using ApplicationCredentials auth", "service", barbican.ServiceName)
730+
}
731+
720732
// To avoid a json parsing error in kolla files, we always need to set PKCS11ClientDataPath
721733
// This gets overridden in the PKCS11 section below if needed.
722734
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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,5 @@ replace k8s.io/component-base => k8s.io/component-base v0.31.13 //allow-merging
115115
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec //allow-merging
116116

117117
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250627150254-e9823e99808e //allow-merging
118+
119+
replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/Deydra71/keystone-operator/api v0.0.0-20251103091514-244e15fe5d63

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-20251103091514-244e15fe5d63 h1:ug2YPMQJ/+0ifOjFyaPx1YtX0zsVnL02pB2ngacYviw=
2+
github.com/Deydra71/keystone-operator/api v0.0.0-20251103091514-244e15fe5d63/go.mod h1:FMFoO4MjEQ85JpdLtDHxYSZxvJ9KzHua+HdKhpl0KRI=
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,8 +102,6 @@ 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.20251030184102-82d2cbaafd35 h1:QFFGu93A+XCvDUxZIgfBE4gB5hEdVQAIw+E8dF1kP/E=
102104
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251030184102-82d2cbaafd35/go.mod h1:qq8BCRxTEmLRriUsQ4HeDUzqltWg32MQPDTMhgbBGK4=
103-
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20251027074845-ed8154b20ad1 h1:QohvX44nxoV2GwvvOURGXYyDuCn4SCrnwubTKJtzehY=
104-
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20251027074845-ed8154b20ad1/go.mod h1:FMFoO4MjEQ85JpdLtDHxYSZxvJ9KzHua+HdKhpl0KRI=
105105
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251027074416-ab5c045dbe00 h1:Xih6tYYqiDVllo4fDGHqTPL+M2biO5YLOUmbiTqrW/I=
106106
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251027074416-ab5c045dbe00/go.mod h1:PMoNILOdQ1Ij7DyrKgljN6RAiq8pFM2AGsUb6mcxe98=
107107
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20251021145236-2b84ec9fd9bb h1:wToXqX7AS1JV3Kna7RcJfkRart8rSGun2biKNfyY6Zg=

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

0 commit comments

Comments
 (0)