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
2 changes: 2 additions & 0 deletions api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,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-20251103091514-244e15fe5d63
11 changes: 11 additions & 0 deletions controllers/manila_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,17 @@ func (r *ManilaReconciler) generateServiceConfig(
// Check if Quorum Queues are enabled
templateParameters["QuorumQueues"] = transportURLQuorumQueues

// Check for Application Credentials
templateParameters["UseApplicationCredentials"] = false
if acData, err := keystonev1.GetApplicationCredentialFromSecret(ctx, r.Client, instance.Namespace, manila.ServiceName); err != nil {
h.GetLogger().Error(err, "Failed to get ApplicationCredential for service", "service", manila.ServiceName)
} else if acData != nil {
templateParameters["UseApplicationCredentials"] = true
templateParameters["ApplicationCredentialID"] = acData.ID
templateParameters["ApplicationCredentialSecret"] = acData.Secret
h.GetLogger().Info("Using ApplicationCredentials auth", "service", manila.ServiceName)
}

// create httpd vhost template parameters
httpdVhostConfig := map[string]any{}
for _, endpt := range []service.Endpoint{service.EndpointInternal, service.EndpointPublic} {
Expand Down
42 changes: 42 additions & 0 deletions controllers/manilaapi_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,41 @@ func (r *ManilaAPIReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Man
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 manila AC secret by name pattern (ac-manila-secret)
if name == keystonev1.GetACSecretName(manila.ServiceName) {
// get all ManilaAPI CRs in this namespace
manilaAPIs := &manilav1beta1.ManilaAPIList{}
listOpts := []client.ListOption{
client.InNamespace(ns),
}
if err := r.List(context.Background(), manilaAPIs, listOpts...); err != nil {
return nil
}

// Enqueue reconcile for all manila API instances
for _, cr := range manilaAPIs.Items {
objKey := client.ObjectKey{
Namespace: ns,
Name: cr.Name,
}
result = append(result, reconcile.Request{NamespacedName: objKey})
}
}

return result
}

// index passwordSecretField
if err := mgr.GetFieldIndexer().IndexField(context.Background(), &manilav1beta1.ManilaAPI{}, passwordSecretField, func(rawObj client.Object) []string {
// Extract the secret name from the spec, if one is provided
Expand Down Expand Up @@ -351,6 +386,8 @@ func (r *ManilaAPIReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Man
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}),
).
Watches(&corev1.Secret{},
handler.EnqueueRequestsFromMapFunc(acSecretFn)).
Watches(&topologyv1.Topology{},
handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc),
builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Expand Down Expand Up @@ -725,6 +762,11 @@ func (r *ManilaAPIReconciler) reconcileNormal(ctx context.Context, instance *man
}
instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage)

// Verify Application Credentials if available
if ctrlResult, err = keystonev1.VerifyApplicationCredentialsForService(ctx, r.Client, instance.Namespace, manila.ServiceName, &configVars, manila.NormalDuration); err != nil || ctrlResult.RequeueAfter > 0 {
return ctrlResult, err
}

//
// TLS input validation
//
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,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-20251103091514-244e15fe5d63
4 changes: 2 additions & 2 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-20251103091514-244e15fe5d63 h1:ug2YPMQJ/+0ifOjFyaPx1YtX0zsVnL02pB2ngacYviw=
github.com/Deydra71/keystone-operator/api v0.0.0-20251103091514-244e15fe5d63/go.mod h1:FMFoO4MjEQ85JpdLtDHxYSZxvJ9KzHua+HdKhpl0KRI=
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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
Expand Down Expand Up @@ -100,8 +102,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.20251030184102-82d2cbaafd35 h1:QFFGu93A+XCvDUxZIgfBE4gB5hEdVQAIw+E8dF1kP/E=
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251030184102-82d2cbaafd35/go.mod h1:qq8BCRxTEmLRriUsQ4HeDUzqltWg32MQPDTMhgbBGK4=
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.20251027074416-ab5c045dbe00 h1:Xih6tYYqiDVllo4fDGHqTPL+M2biO5YLOUmbiTqrW/I=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251027074416-ab5c045dbe00/go.mod h1:PMoNILOdQ1Ij7DyrKgljN6RAiq8pFM2AGsUb6mcxe98=
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20251021145236-2b84ec9fd9bb h1:wToXqX7AS1JV3Kna7RcJfkRart8rSGun2biKNfyY6Zg=
Expand Down
42 changes: 33 additions & 9 deletions templates/manila/config/00-config.conf
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,18 @@ auth_url = {{ .KeystoneInternalURL }}
memcached_servers = {{ .MemcachedServers }}
memcache_pool_dead_retry = 10
memcache_pool_conn_get_timeout = 2
{{ if .UseApplicationCredentials -}}
auth_type = v3applicationcredential
application_credential_id = {{ .ApplicationCredentialID }}
application_credential_secret = {{ .ApplicationCredentialSecret }}
{{ else -}}
auth_type = password
username = {{ .ServiceUser }}
password = {{ .ServicePassword }}
{{- end }}
project_domain_name = Default
user_domain_name = Default
project_name = service
username = {{ .ServiceUser }}
password = {{ .ServicePassword }}
interface = internal
{{if (index . "MemcachedAuthCert")}}
memcache_tls_certfile = {{ .MemcachedAuthCert }}
Expand All @@ -47,19 +53,31 @@ memcache_tls_enabled = true

[neutron]
auth_url = {{ .KeystoneInternalURL }}
auth_type=password
{{ if .UseApplicationCredentials -}}
auth_type = v3applicationcredential
application_credential_id = {{ .ApplicationCredentialID }}
application_credential_secret = {{ .ApplicationCredentialSecret }}
{{ else -}}
auth_type = password
username = {{ .ServiceUser }}
password = {{ .ServicePassword }}
{{- end }}
project_domain_name=Default
project_name=service
user_domain_name=Default
username = {{ .ServiceUser }}
password = {{ .ServicePassword }}

[nova]
interface = internal
{{ if .UseApplicationCredentials -}}
auth_type = v3applicationcredential
application_credential_id = {{ .ApplicationCredentialID }}
application_credential_secret = {{ .ApplicationCredentialSecret }}
{{ else -}}
auth_type = password
auth_url = {{ .KeystoneInternalURL }}
username = {{ .ServiceUser }}
password = {{ .ServicePassword }}
{{- end }}
auth_url = {{ .KeystoneInternalURL }}
user_domain_name = Default
project_name = service
project_domain_name = Default
Expand Down Expand Up @@ -104,12 +122,18 @@ file_event_handler=/var/lib/manila
auth_endpoint = {{ .KeystoneInternalURL }}
barbican_endpoint_type = internal
auth_url = {{ .KeystoneInternalURL }}
auth_type=password
{{ if .UseApplicationCredentials -}}
auth_type = v3applicationcredential
application_credential_id = {{ .ApplicationCredentialID }}
application_credential_secret = {{ .ApplicationCredentialSecret }}
{{ else -}}
auth_type = password
username = {{ .ServiceUser }}
password = {{ .ServicePassword }}
{{- end }}
project_domain_name=Default
project_name=service
user_domain_name=Default
username = {{ .ServiceUser }}
password = {{ .ServicePassword }}

[key_manager]
backend = barbican
103 changes: 103 additions & 0 deletions test/functional/manila_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ import (
. "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers"
mariadb_test "github.com/openstack-k8s-operators/mariadb-operator/api/test/helpers"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"

memcachedv1 "github.com/openstack-k8s-operators/infra-operator/apis/memcached/v1beta1"
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
util "github.com/openstack-k8s-operators/lib-common/modules/common/util"
manilav1 "github.com/openstack-k8s-operators/manila-operator/api/v1beta1"
Expand Down Expand Up @@ -1459,6 +1461,106 @@ var _ = Describe("Manila controller", func() {

})

When("An ApplicationCredential is created for Manila", func() {
var (
acName string
acSecretName string
servicePasswordSecret string
passwordSelector string
)
BeforeEach(func() {
servicePasswordSecret = "ac-test-osp-secret" //nolint:gosec // G101
passwordSelector = "ManilaPassword"

DeferCleanup(th.DeleteInstance, CreateManilaSecret(manilaTest.Instance.Namespace, servicePasswordSecret))
DeferCleanup(th.DeleteInstance, CreateManilaMessageBusSecret(manilaTest.Instance.Namespace, manilaTest.RabbitmqSecretName))
DeferCleanup(
infra.DeleteMemcached,
infra.CreateMemcached(manilaTest.ManilaMemcached.Namespace, manilaTest.MemcachedInstance, memcachedSpec))
infra.SimulateMemcachedReady(manilaTest.ManilaMemcached)

spec := GetDefaultManilaSpec()
spec["secret"] = servicePasswordSecret
DeferCleanup(th.DeleteInstance, CreateManila(manilaTest.Instance, spec))
DeferCleanup(
mariadb.DeleteDBService,
mariadb.CreateDBService(
manilaTest.ManilaDatabaseName.Namespace,
GetManila(manilaTest.Instance).Spec.DatabaseInstance,
corev1.ServiceSpec{
Ports: []corev1.ServicePort{{Port: 3306}},
},
),
)
DeferCleanup(keystone.DeleteKeystoneAPI, keystone.CreateKeystoneAPI(manilaTest.Instance.Namespace))

acName = fmt.Sprintf("ac-%s", manila.ServiceName)
acSecretName = acName + "-secret"
secret := &corev1.Secret{}
secret.Name = acSecretName
secret.Namespace = manilaTest.Instance.Namespace
secret.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: manilaTest.Instance.Namespace,
Name: acName,
},
Spec: keystonev1.KeystoneApplicationCredentialSpec{
UserName: manila.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())

infra.SimulateTransportURLReady(manilaTest.ManilaTransportURL)
mariadb.SimulateMariaDBAccountCompleted(manilaTest.ManilaDatabaseAccount)
mariadb.SimulateMariaDBDatabaseCompleted(manilaTest.ManilaDatabaseName)
})

It("should render ApplicationCredential auth in 00-config.conf", func() {
// Retrieve the generated config secret
configDataMap := th.GetSecret(manilaTest.ManilaConfigSecret)

conf := configDataMap.Data["00-config.conf"]
Expect(string(conf)).Should(
ContainSubstring("auth_type = v3applicationcredential"))
Expect(string(conf)).Should(
ContainSubstring("application_credential_id = test-ac-id"))
Expect(string(conf)).Should(
ContainSubstring("application_credential_secret = test-ac-secret"))
Expect(string(conf)).Should(
Not(ContainSubstring("auth_type = password")))
})
})

})

var _ = Describe("Manila Webhook", func() {
Expand Down Expand Up @@ -1567,4 +1669,5 @@ var _ = Describe("Manila Webhook", func() {
return instance, fmt.Sprintf("manilaShares[%s].topologyRef", instance)
}),
)

})
Loading