Skip to content

openstack-sync-operator: support multiple clouds with per-resource cloud selection and system vs project scope #2210

Description

@cardoe

Follow-on to #2205. The generic openstack-sync-operator currently supports exactly one cloud per Pod, which forces every sync task to share one credential and one scope.

Current state

components/openstack-sync-operator/templates/deployment.yaml mounts a single secret key at /etc/openstack/clouds.yaml and sets a single container-wide OS_CLOUD:

env:
- name: OS_CLOUD
  value: {{ .Values.openstack.cloud | quote }}
volumeMounts:
- name: openstack-clouds
  mountPath: /etc/openstack/clouds.yaml
  subPath: clouds.yaml

with defaults cloud: understack, cloudsSecretName: infrasetup. Hooks then do connect_openstack(os.environ.get("OS_CLOUD")) — one cloud for the whole process.

What we need

Multiple clouds available to the operator, with each resource declaring which cloud it reconciles against. Some sync tasks need system-scope tokens and others need project-scope, and those require different OS_CLOUD entries. Least privilege is the point: a project-scoped task should not be holding system-scope credentials.

Complications found while reviewing #2205

1. Existing cloud names collide. Both automation secrets use the cloud name understack, differing only in Keystone user:

  • components/openstack/templates/automation-infrasetup.yaml.tpl — user infrasetup-<region>
  • components/openstack/templates/automation-baremetal-manage.yaml.tpl — user baremetal-manage-<region>

They cannot be merged into a single clouds.yaml as-is. Either the entries get unique names, or each secret is mounted at its own path.

2. No system-scope credential exists today. Both of the above are project-scoped (project_domain_name: infra, project_name: baremetal). A system-scope entry is new work: Keystone user + role assignment + system_scope: all in the auth block, wired through External Secrets alongside the existing generators.

3. openstacksdk does not merge multiple clouds.yaml files. It loads the first one found on its search path (plus secure.yaml). So the options are roughly:

  • (a) Assemble one clouds.yaml containing all uniquely-named cloud entries into a single secret, mount it, and have each resource set a cloud name. Simplest, but requires renaming and a single assembled secret.
  • (b) Mount N secrets at N paths and set OS_CLIENT_CONFIG_FILE per reconcile based on the resource's selection. Leaves the existing per-purpose secrets untouched, at the cost of more moving parts.

Scope of work

  • Operator chart: replace the single openstack.cloudsSecretName/cloudsSecretKey/cloud values with a list of cloud sources, mounted accordingly.
  • CRD: add a cloud selector field (e.g. spec.cloud) with a documented default so existing resources keep working. Note the CRDs ship with the operator chart, so this is a schema bump on the operator.
  • Hooks: select the connection per resource rather than per process, and memoize connections per cloud name so a run with many resources doesn't re-authenticate for each one.
  • Validation: fail loudly at startup if a resource or enabled hook names a cloud absent from the mounted config, consistent with the "enabled but not present" check agreed in feat(openstack-sync-operator): Operator for syncing openstack data as kubernetes custom resources #2205.
  • Add the system-scope credential and document which sync tasks need which scope.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions