Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ go 1.24.4
require (
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251103072528-9eb684fef4ef
github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20251103072528-9eb684fef4ef
k8s.io/api v0.31.13
k8s.io/apimachinery v0.31.13
k8s.io/client-go v0.31.13 // indirect
k8s.io/api v0.31.14
k8s.io/apimachinery v0.31.14
k8s.io/client-go v0.31.14 // indirect
sigs.k8s.io/controller-runtime v0.19.7
)

Expand Down Expand Up @@ -48,6 +48,7 @@ require (
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/spf13/pflag v1.0.7 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.uber.org/zap v1.27.1 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
Expand Down Expand Up @@ -92,3 +93,5 @@ replace k8s.io/component-base => k8s.io/component-base v0.31.13 //allow-merging
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec //allow-merging

replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250627150254-e9823e99808e //allow-merging

replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/Deydra71/keystone-operator/api v0.0.0-20251201081347-2823ce61c025
3 changes: 1 addition & 2 deletions api/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
Expand Down
10 changes: 6 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ require (
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20251103072528-9eb684fef4ef
github.com/openstack-k8s-operators/mariadb-operator/api v0.6.1-0.20251106091552-44d4046a8d6c
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.31.13
k8s.io/apimachinery v0.31.13
k8s.io/client-go v0.31.13
k8s.io/api v0.31.14
k8s.io/apimachinery v0.31.14
k8s.io/client-go v0.31.14
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d
sigs.k8s.io/controller-runtime v0.19.7
)
Expand Down Expand Up @@ -88,7 +88,7 @@ require (
go.opentelemetry.io/otel/trace v1.34.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.uber.org/zap v1.27.1 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.42.0 // indirect
Expand Down Expand Up @@ -149,3 +149,5 @@ replace k8s.io/component-base => k8s.io/component-base v0.31.13 //allow-merging
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec //allow-merging

replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250627150254-e9823e99808e //allow-merging

replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/Deydra71/keystone-operator/api v0.0.0-20251201081347-2823ce61c025
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/Deydra71/keystone-operator/api v0.0.0-20251201081347-2823ce61c025 h1:9tVdplONUg5JpgAczs7wV4Swkc0mqAueWVT58cin9ZY=
github.com/Deydra71/keystone-operator/api v0.0.0-20251201081347-2823ce61c025/go.mod h1:b98Jl8eyUw8V07l9YiuQnoMlnWC748oV8IhXH15NCC4=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
Expand Down Expand Up @@ -132,8 +134,6 @@ github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e h1:E1OdwSpqWuDPCedyU
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251110170511-c2d4a351a7c3 h1:gKazSLpq0Ytn4OLzNtSKQpLswAdki8u8mXZgpJy83bE=
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251110170511-c2d4a351a7c3/go.mod h1:Y9LqOS1wYhn7RT4jFknINdWa+ziYEIOU1jLNxkxiCsw=
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20251027074845-ed8154b20ad1 h1:QohvX44nxoV2GwvvOURGXYyDuCn4SCrnwubTKJtzehY=
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20251027074845-ed8154b20ad1/go.mod h1:FMFoO4MjEQ85JpdLtDHxYSZxvJ9KzHua+HdKhpl0KRI=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251103072528-9eb684fef4ef h1:1j7kk+D4ZdIXm6C/IwEjuTzIuvWUytxO39E/x94JY7k=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251103072528-9eb684fef4ef/go.mod h1:kUT/SyuxZiOcX8ZuvpFN3PaQa2V8uQon8YwY+1RoQWM=
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20251103072528-9eb684fef4ef h1:Ql4G7sRHpqWFGwXypN7MorDGUWv4jz5n34ayzVt3R9E=
Expand Down Expand Up @@ -210,8 +210,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
Expand Down
61 changes: 61 additions & 0 deletions internal/controller/designateapi_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,40 @@ func (r *DesignateAPIReconciler) SetupWithManager(ctx context.Context, mgr ctrl.
return nil
}

// Application Credential secret watching function
acSecretFn := func(_ context.Context, o client.Object) []reconcile.Request {
name := o.GetName()
ns := o.GetNamespace()
result := []reconcile.Request{}

// Only handle Secret objects
if _, isSecret := o.(*corev1.Secret); !isSecret {
return nil
}

// Check if this is a designate AC secret by name pattern (ac-designate-secret)
expectedSecretName := keystonev1.GetACSecretName("designate")
if name == expectedSecretName {
// get all DesignateAPI CRs in this namespace
designateAPIs := &designatev1beta1.DesignateAPIList{}
listOpts := []client.ListOption{
client.InNamespace(ns),
}
if err := r.List(context.Background(), designateAPIs, listOpts...); err != nil {
return nil
}

for _, cr := range designateAPIs.Items {
name := client.ObjectKey{
Namespace: ns,
Name: cr.Name,
}
result = append(result, reconcile.Request{NamespacedName: name})
}
}
return result
}

return ctrl.NewControllerManagedBy(mgr).
For(&designatev1beta1.DesignateAPI{}).
Owns(&keystonev1.KeystoneService{}).
Expand All @@ -385,6 +419,8 @@ func (r *DesignateAPIReconciler) SetupWithManager(ctx context.Context, mgr ctrl.
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}),
).
Watches(&corev1.Secret{},
handler.EnqueueRequestsFromMapFunc(acSecretFn)).
Watches(&networkv1.NetworkAttachmentDefinition{},
handler.EnqueueRequestsFromMapFunc(nadFn)).
Watches(&topologyv1.Topology{},
Expand Down Expand Up @@ -741,6 +777,19 @@ func (r *DesignateAPIReconciler) reconcileNormal(ctx context.Context, instance *

// run check OpenStack secret - end

// Verify Application Credentials if available
ctrlResult, err = keystonev1.VerifyApplicationCredentialsForService(
ctx,
r.Client,
instance.Namespace,
designate.ServiceName,
&configMapVars,
10*time.Second,
)
if (err != nil || ctrlResult != ctrl.Result{}) {
return ctrlResult, err
}

//
// TLS input validation
//
Expand Down Expand Up @@ -1198,6 +1247,18 @@ func (r *DesignateAPIReconciler) generateServiceConfigMaps(
}
templateParameters["AdminPassword"] = string(adminPasswordSecret.Data["DesignatePassword"])

templateParameters["UseApplicationCredentials"] = false
// Try to get Application Credential for this service (via keystone api helper)
if acData, err := keystonev1.GetApplicationCredentialFromSecret(ctx, r.Client, instance.Namespace, designate.ServiceName); err != nil {
Log.Error(err, "Failed to get ApplicationCredential for service", "service", designate.ServiceName)
return err
} else if acData != nil {
templateParameters["UseApplicationCredentials"] = true
templateParameters["ACID"] = acData.ID
templateParameters["ACSecret"] = acData.Secret
Log.Info("Using ApplicationCredentials auth", "service", designate.ServiceName)
}

cms := []util.Template{
// Custom ConfigMap
{
Expand Down
11 changes: 8 additions & 3 deletions templates/designateapi/config/designate.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ enable_host_header=True
enabled_extensions_admin=quotas

[keystone_authtoken]
auth_type={{ if .UseApplicationCredentials }}v3applicationcredential{{ else }}password{{ end }}
{{ if .UseApplicationCredentials -}}
application_credential_id={{ .ACID }}
application_credential_secret={{ .ACSecret }}
{{- else -}}
username={{ .ServiceUser }}
password={{ .AdminPassword }}
user_domain_name=Default
project_name=service
project_domain_name=Default
user_domain_name=Default
auth_type=password
password={{ .AdminPassword }}
{{- end }}
region_name=regionOne
www_authenticate_uri={{ .KeystonePublicURL }}
auth_url={{ .KeystoneInternalURL }}
Expand Down
112 changes: 112 additions & 0 deletions test/functional/designateapi_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ import (
"github.com/google/uuid"
. "github.com/onsi/ginkgo/v2" //revive:disable:dot-imports
. "github.com/onsi/gomega" //revive:disable:dot-imports
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"

corev1 "k8s.io/api/core/v1"

"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
//revive:disable-next-line:dot-imports
"github.com/openstack-k8s-operators/designate-operator/internal/designate"
keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
. "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers"

mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1"
Expand Down Expand Up @@ -235,6 +237,116 @@ var _ = Describe("DesignateAPI controller", func() {
})
})

When("An ApplicationCredential is created for Designate", func() {
var (
acName string
acSecretName string
servicePasswordSecret string
passwordSelector string
keystoneAPIName types.NamespacedName
)
BeforeEach(func() {
servicePasswordSecret = SecretName
passwordSelector = "DesignatePassword"

keystoneAPIName = keystone.CreateKeystoneAPI(namespace)
DeferCleanup(keystone.DeleteKeystoneAPI, keystoneAPIName)
keystoneInternalEndpoint := fmt.Sprintf("http://keystone-for-%s-internal", designateAPIName.Name)
keystonePublicEndpoint := fmt.Sprintf("http://keystone-for-%s-public", designateAPIName.Name)
SimulateKeystoneReady(keystoneAPIName, keystonePublicEndpoint, keystoneInternalEndpoint)

DeferCleanup(k8sClient.Delete, ctx, CreateDesignateSecret(namespace))
DeferCleanup(k8sClient.Delete, ctx, CreateTransportURLSecret(transportURLSecretName))

spec := GetDefaultDesignateAPISpec()
spec["secret"] = servicePasswordSecret
spec["transportURLSecret"] = RabbitmqSecretName
DeferCleanup(th.DeleteInstance,
CreateDesignateAPI(designateAPIName, spec))

mariaDBDatabaseName := mariadb.CreateMariaDBDatabase(namespace, designate.DatabaseCRName, mariadbv1.MariaDBDatabaseSpec{})
mariaDBDatabase := mariadb.GetMariaDBDatabase(mariaDBDatabaseName)
DeferCleanup(k8sClient.Delete, ctx, mariaDBDatabase)

designateAPI := GetDesignateAPI(designateAPIName)
apiMariaDBAccount, apiMariaDBSecret := mariadb.CreateMariaDBAccountAndSecret(
types.NamespacedName{
Namespace: namespace,
Name: designateAPI.Spec.DatabaseAccount,
}, mariadbv1.MariaDBAccountSpec{})
DeferCleanup(k8sClient.Delete, ctx, apiMariaDBAccount)
DeferCleanup(k8sClient.Delete, ctx, apiMariaDBSecret)

acName = fmt.Sprintf("ac-%s", designate.ServiceName)
acSecretName = acName + "-secret"
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: acSecretName,
Namespace: namespace,
},
Data: map[string][]byte{
"AC_ID": []byte("test-ac-id"),
"AC_SECRET": []byte("test-ac-secret"),
},
}
DeferCleanup(k8sClient.Delete, ctx, secret)
Expect(k8sClient.Create(ctx, secret)).To(Succeed())

ac := &keystonev1.KeystoneApplicationCredential{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: acName,
},
Spec: keystonev1.KeystoneApplicationCredentialSpec{
UserName: designate.ServiceName,
Secret: servicePasswordSecret,
PasswordSelector: passwordSelector,
Roles: []string{"admin", "member"},
AccessRules: []keystonev1.ACRule{{Service: "identity", Method: "POST", Path: "/auth/tokens"}},
ExpirationDays: 30,
GracePeriodDays: 5,
},
}
DeferCleanup(k8sClient.Delete, ctx, ac)
Expect(k8sClient.Create(ctx, ac)).To(Succeed())

fetched := &keystonev1.KeystoneApplicationCredential{}
key := types.NamespacedName{Namespace: ac.Namespace, Name: ac.Name}
Expect(k8sClient.Get(ctx, key, fetched)).To(Succeed())

fetched.Status.SecretName = acSecretName
now := metav1.Now()
readyCond := condition.Condition{
Type: condition.ReadyCondition,
Status: corev1.ConditionTrue,
Reason: condition.ReadyReason,
Message: condition.ReadyMessage,
LastTransitionTime: now,
}
fetched.Status.Conditions = condition.Conditions{readyCond}
Expect(k8sClient.Status().Update(ctx, fetched)).To(Succeed())
})

It("should render ApplicationCredential auth in designate.conf", func() {
Eventually(func(g Gomega) {
cfgSecret := th.GetSecret(types.NamespacedName{
Namespace: namespace,
Name: fmt.Sprintf("%s-config-data", designateAPIName.Name),
})
g.Expect(cfgSecret).NotTo(BeNil())

conf := string(cfgSecret.Data["designate.conf"])

g.Expect(conf).To(ContainSubstring(
"application_credential_id=test-ac-id"),
)
g.Expect(conf).To(ContainSubstring(
"application_credential_secret=test-ac-secret"),
)
}, timeout, interval).Should(Succeed())
})
})

// NAD

// Networks Annotation
Expand Down