Skip to content

Commit 541dfe9

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 <vfisarov@redhat.com>
1 parent 0dcd5c9 commit 541dfe9

12 files changed

Lines changed: 164 additions & 10 deletions

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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,5 @@ replace k8s.io/component-base => k8s.io/component-base v0.31.14 //allow-merging
9595
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec //allow-merging
9696

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

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: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ func (spec *PlacementAPISpec) Default() {
6868
if spec.APITimeout == 0 {
6969
spec.APITimeout = placementAPIDefaults.APITimeout
7070
}
71-
7271
}
7372

7473
// 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)

config/manifests/bases/placement-operator.clusterserviceversion.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ spec:
2424
kind: PlacementAPI
2525
name: placementapis.placement.openstack.org
2626
specDescriptors:
27+
- description: Auth - Parameters related to authentication
28+
displayName: Auth
29+
path: auth
30+
- description: ApplicationCredentialSecret - Secret containing Application Credential
31+
ID and Secret
32+
displayName: Application Credential Secret
33+
path: auth.applicationCredentialSecret
2734
- description: TLS - Parameters related to the TLS
2835
displayName: TLS
2936
path: tls

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.20260108154501-11e5091cddf1 h1:zAbZVtpldi1TU/CO9aU2ZByzcsi+N3aIv6snpSjBVLY=
122124
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20260108154501-11e5091cddf1/go.mod h1:ZXwFlspJCdZEUjMbmaf61t5AMB4u2vMyAMMoe/vJroE=
123-
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20260109123729-8c46aa6cb459 h1:5p1EssFXwriFNoxDZsO8a4r0GnruIVD/d7dNBzcglR8=
124-
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20260109123729-8c46aa6cb459/go.mod h1:djqR/hwPpIld/siGG6JTa3YuI6QGMf4e7aphVRBhlAk=
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.20251230215914-6ba873b49a35 h1:IdcI8DFvW8rXtchONSzbDmhhRp1YyO2YaBJDBXr44Gk=

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)