Skip to content

Commit e683b4d

Browse files
committed
Application Credential support
Adds the end-to-end support for consuming Keystone ApplicationCredentials (AC) in the Placement operator, enabling Placement pod to use AC-based authentication when available. Signed-off-by: Veronika Fisarova <[email protected]>
1 parent 5e65ce7 commit e683b4d

File tree

12 files changed

+177
-11
lines changed

12 files changed

+177
-11
lines changed

api/bases/placement.openstack.org_placementapis.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ spec:
5757
description: APITimeout for HAProxy, Apache
5858
minimum: 10
5959
type: integer
60+
auth:
61+
description: Auth - Parameters related to authentication
62+
properties:
63+
applicationCredentialSecret:
64+
description: ApplicationCredentialSecret - Secret containing Application
65+
Credential ID and Secret
66+
type: string
67+
type: object
6068
containerImage:
6169
description: PlacementAPI Container Image URL (will be set to environmental
6270
default if empty)

api/go.mod

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.24.4
44

55
require (
66
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251223124749-eedb97238c5f
7+
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20251206133124-593df0a7a9e1
78
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251230215914-6ba873b49a35
89
k8s.io/api v0.31.14
910
k8s.io/apimachinery v0.31.14
@@ -15,7 +16,6 @@ require (
1516
github.com/cespare/xxhash/v2 v2.3.0 // indirect
1617
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
1718
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
18-
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
1919
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
2020
github.com/fsnotify/fsnotify v1.9.0 // indirect
2121
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
@@ -30,13 +30,17 @@ require (
3030
github.com/google/go-cmp v0.7.0 // indirect
3131
github.com/google/gofuzz v1.2.0 // indirect
3232
github.com/google/uuid v1.6.0 // indirect
33+
github.com/gophercloud/gophercloud/v2 v2.8.0 // indirect
3334
github.com/imdario/mergo v0.3.16 // indirect
3435
github.com/josharian/intern v1.0.0 // indirect
3536
github.com/json-iterator/go v1.1.12 // indirect
3637
github.com/mailru/easyjson v0.9.0 // indirect
3738
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
3839
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
3940
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
41+
github.com/openshift/api v3.9.0+incompatible // indirect
42+
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20251122131503-b76943960b6c // indirect
43+
github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20251122131503-b76943960b6c // indirect
4044
github.com/pkg/errors v0.9.1 // indirect
4145
github.com/prometheus/client_golang v1.22.0 // indirect
4246
github.com/prometheus/client_model v0.6.2 // indirect
@@ -93,3 +97,5 @@ replace k8s.io/component-base => k8s.io/component-base v0.31.14 //allow-merging
9397
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec //allow-merging
9498

9599
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250627150254-e9823e99808e //allow-merging
100+
101+
replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/Deydra71/keystone-operator/api v0.0.0-20251211085602-3e1a3e022c81

api/go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/Deydra71/keystone-operator/api v0.0.0-20251211085602-3e1a3e022c81 h1:plax+NFgJJL1SrERyXAnf3jOHRhLTtBlJ2oc7d84EoU=
2+
github.com/Deydra71/keystone-operator/api v0.0.0-20251211085602-3e1a3e022c81/go.mod h1:b98Jl8eyUw8V07l9YiuQnoMlnWC748oV8IhXH15NCC4=
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=
@@ -48,6 +50,8 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J
4850
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
4951
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
5052
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
53+
github.com/gophercloud/gophercloud/v2 v2.8.0 h1:of2+8tT6+FbEYHfYC8GBu8TXJNsXYSNm9KuvpX7Neqo=
54+
github.com/gophercloud/gophercloud/v2 v2.8.0/go.mod h1:Ki/ILhYZr/5EPebrPL9Ej+tUg4lqx71/YH2JWVeU+Qk=
5155
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
5256
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
5357
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -78,10 +82,16 @@ github.com/onsi/ginkgo/v2 v2.27.3 h1:ICsZJ8JoYafeXFFlFAG75a7CxMsJHwgKwtO+82SE9L8
7882
github.com/onsi/ginkgo/v2 v2.27.3/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
7983
github.com/onsi/gomega v1.38.3 h1:eTX+W6dobAYfFeGC2PV6RwXRu/MyT+cQguijutvkpSM=
8084
github.com/onsi/gomega v1.38.3/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
85+
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e h1:E1OdwSpqWuDPCedyUt0GEdoAE+r5TXy7YS21yNEo+2U=
86+
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
8187
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251223124749-eedb97238c5f h1:xcCGJ/g5vvbWhtEJCbv8UeBneI5yrMawm+CXRsJrJZo=
8288
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251223124749-eedb97238c5f/go.mod h1:ex8ou6/3ms6ovR+CMXD6XhTlNakm1GhB6UZgagVRNW8=
8389
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251230215914-6ba873b49a35 h1:pF3mJ3nwq6r4qwom+rEWZNquZpcQW/iftHlJ1KPIDsk=
8490
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251230215914-6ba873b49a35/go.mod h1:kycZyoe7OZdW1HUghr2nI3N7wSJtNahXf6b/ypD14f4=
91+
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20251122131503-b76943960b6c h1:l7FO+XoQRnD4aT5p/JXVY2uezQLdC7D50KrwrTmzCfg=
92+
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20251122131503-b76943960b6c/go.mod h1:zOX7Y05keiSppIvLabuyh42QHBMhCcoskAtxFRbwXKo=
93+
github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20251122131503-b76943960b6c h1:dVIaDL5BeIdJjERGaN/XlcvZVplfkzh0uUfiVUHj/6Q=
94+
github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20251122131503-b76943960b6c/go.mod h1:fy1lvz3uuzzh01DKKdgroXvmJgMpJBsvl2r9eTtAll0=
8595
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
8696
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
8797
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=

api/v1beta1/placementapi_types.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ limitations under the License.
1717
package v1beta1
1818

1919
import (
20+
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
2021
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
2122
"github.com/openstack-k8s-operators/lib-common/modules/common/service"
2223
"github.com/openstack-k8s-operators/lib-common/modules/common/tls"
2324
"github.com/openstack-k8s-operators/lib-common/modules/common/util"
24-
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
25-
"k8s.io/apimachinery/pkg/util/validation/field"
2625
corev1 "k8s.io/api/core/v1"
2726
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/apimachinery/pkg/util/validation/field"
2828
)
2929

3030
const (
@@ -126,6 +126,11 @@ type PlacementAPISpecCore struct {
126126
// TLS - Parameters related to the TLS
127127
TLS tls.API `json:"tls,omitempty"`
128128

129+
// +kubebuilder:validation:Optional
130+
// +operator-sdk:csv:customresourcedefinitions:type=spec
131+
// Auth - Parameters related to authentication
132+
Auth AuthSpec `json:"auth,omitempty"`
133+
129134
// +kubebuilder:validation:Optional
130135
// TopologyRef to apply the Topology defined by the associated CR referenced
131136
// by name
@@ -139,6 +144,14 @@ type APIOverrideSpec struct {
139144
Service map[service.Endpoint]service.RoutedOverrideSpec `json:"service,omitempty"`
140145
}
141146

147+
// AuthSpec defines authentication parameters
148+
type AuthSpec struct {
149+
// +kubebuilder:validation:Optional
150+
// +operator-sdk:csv:customresourcedefinitions:type=spec
151+
// ApplicationCredentialSecret - Secret containing Application Credential ID and Secret
152+
ApplicationCredentialSecret string `json:"applicationCredentialSecret,omitempty"`
153+
}
154+
142155
// PasswordSelector to identify the DB and AdminUser password from the Secret
143156
type PasswordSelector struct {
144157
// +kubebuilder:validation:Optional

api/v1beta1/placementapi_webhook.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ package v1beta1
2424
import (
2525
"fmt"
2626

27+
keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
2728
"github.com/openstack-k8s-operators/lib-common/modules/common/service"
2829
apierrors "k8s.io/apimachinery/pkg/api/errors"
2930
"k8s.io/apimachinery/pkg/runtime"
@@ -68,7 +69,10 @@ func (spec *PlacementAPISpec) Default() {
6869
if spec.APITimeout == 0 {
6970
spec.APITimeout = placementAPIDefaults.APITimeout
7071
}
71-
72+
// Default ApplicationCredentialSecret to standard AC secret name if not specified
73+
if spec.Auth.ApplicationCredentialSecret == "" {
74+
spec.Auth.ApplicationCredentialSecret = keystonev1.GetACSecretName("placement")
75+
}
7276
}
7377

7478
// Default - set defaults for this PlacementAPI core spec (this version is used by the OpenStackControlplane webhook)

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/placement.openstack.org_placementapis.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ spec:
5757
description: APITimeout for HAProxy, Apache
5858
minimum: 10
5959
type: integer
60+
auth:
61+
description: Auth - Parameters related to authentication
62+
properties:
63+
applicationCredentialSecret:
64+
description: ApplicationCredentialSecret - Secret containing Application
65+
Credential ID and Secret
66+
type: string
67+
type: object
6068
containerImage:
6169
description: PlacementAPI Container Image URL (will be set to environmental
6270
default if empty)

go.mod

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

144144
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250627150254-e9823e99808e //allow-merging
145+
146+
replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/Deydra71/keystone-operator/api v0.0.0-20251211085602-3e1a3e022c81

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-20251211085602-3e1a3e022c81 h1:plax+NFgJJL1SrERyXAnf3jOHRhLTtBlJ2oc7d84EoU=
2+
github.com/Deydra71/keystone-operator/api v0.0.0-20251211085602-3e1a3e022c81/go.mod h1:b98Jl8eyUw8V07l9YiuQnoMlnWC748oV8IhXH15NCC4=
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/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
@@ -120,8 +122,6 @@ github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e h1:E1OdwSpqWuDPCedyU
120122
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
121123
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251223124749-eedb97238c5f h1:xcCGJ/g5vvbWhtEJCbv8UeBneI5yrMawm+CXRsJrJZo=
122124
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251223124749-eedb97238c5f/go.mod h1:ex8ou6/3ms6ovR+CMXD6XhTlNakm1GhB6UZgagVRNW8=
123-
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20251206133124-593df0a7a9e1 h1:qcgbrF9c0axkaDcFGfIA2wGz8bkaxPuXHj3mdKAyz6M=
124-
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20251206133124-593df0a7a9e1/go.mod h1:0XsZ6Fc4hTV6a/BBP8+jiH8LR+IP5z9aStdPTDHALNk=
125125
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251230215914-6ba873b49a35 h1:pF3mJ3nwq6r4qwom+rEWZNquZpcQW/iftHlJ1KPIDsk=
126126
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251230215914-6ba873b49a35/go.mod h1:kycZyoe7OZdW1HUghr2nI3N7wSJtNahXf6b/ypD14f4=
127127
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20251122131503-b76943960b6c h1:l7FO+XoQRnD4aT5p/JXVY2uezQLdC7D50KrwrTmzCfg=

internal/controller/placementapi_controller.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,7 @@ const (
849849
tlsAPIInternalField = ".spec.tls.api.internal.secretName"
850850
tlsAPIPublicField = ".spec.tls.api.public.secretName"
851851
topologyField = ".spec.topologyRef.Name"
852+
authAppCredSecretField = ".spec.auth.applicationCredentialSecret" // #nosec G101
852853
)
853854

854855
var allWatchFields = []string{
@@ -857,6 +858,7 @@ var allWatchFields = []string{
857858
tlsAPIInternalField,
858859
tlsAPIPublicField,
859860
topologyField,
861+
authAppCredSecretField,
860862
}
861863

862864
// SetupWithManager sets up the controller with the Manager.
@@ -921,6 +923,18 @@ func (r *PlacementAPIReconciler) SetupWithManager(mgr ctrl.Manager) error {
921923
return err
922924
}
923925

926+
// index authAppCredSecretField
927+
if err := mgr.GetFieldIndexer().IndexField(context.Background(), &placementv1.PlacementAPI{}, authAppCredSecretField, func(rawObj client.Object) []string {
928+
// Extract the application credential secret name from the spec, if one is provided
929+
cr := rawObj.(*placementv1.PlacementAPI)
930+
if cr.Spec.Auth.ApplicationCredentialSecret == "" {
931+
return nil
932+
}
933+
return []string{cr.Spec.Auth.ApplicationCredentialSecret}
934+
}); err != nil {
935+
return err
936+
}
937+
924938
return ctrl.NewControllerManagedBy(mgr).
925939
For(&placementv1.PlacementAPI{}).
926940
Owns(&mariadbv1.MariaDBDatabase{}).
@@ -1378,6 +1392,28 @@ func (r *PlacementAPIReconciler) generateServiceConfigMaps(
13781392
),
13791393
}
13801394

1395+
templateParameters["UseApplicationCredentials"] = false
1396+
// Try to get Application Credential for this service
1397+
if instance.Spec.Auth.ApplicationCredentialSecret != "" {
1398+
secret := &corev1.Secret{}
1399+
key := types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.Auth.ApplicationCredentialSecret}
1400+
if err := r.Get(ctx, key, secret); err != nil {
1401+
if !k8s_errors.IsNotFound(err) {
1402+
h.GetLogger().Error(err, "Failed to get ApplicationCredential secret", "secret", key)
1403+
return err
1404+
}
1405+
} else {
1406+
acID, okID := secret.Data[keystonev1.ACIDSecretKey]
1407+
acSecret, okSecret := secret.Data[keystonev1.ACSecretSecretKey]
1408+
if okID && len(acID) > 0 && okSecret && len(acSecret) > 0 {
1409+
templateParameters["UseApplicationCredentials"] = true
1410+
templateParameters["ACID"] = string(acID)
1411+
templateParameters["ACSecret"] = string(acSecret)
1412+
h.GetLogger().Info("Using ApplicationCredentials auth", "secret", key)
1413+
}
1414+
}
1415+
}
1416+
13811417
// create httpd vhost template parameters
13821418
httpdVhostConfig := map[string]any{}
13831419
for _, endpt := range []service.Endpoint{service.EndpointInternal, service.EndpointPublic} {

0 commit comments

Comments
 (0)