Add helpers for removing kolla - #728
Merged
Merged
Conversation
stuggi
added a commit
to stuggi/barbican-operator
that referenced
this pull request
Aug 6, 2026
Removes kolla_start/kolla_set_configs/config.json staging across all five Barbican workloads (API, worker, keystone-listener, db-sync, pkcs11-prep), replacing it with direct volume mounts at final config paths and hardcoded service commands. Key changes: - Replace kolla_start with /usr/sbin/httpd -DFOREGROUND (API), barbican-worker (worker), barbican-keystone-listener (listener), barbican-manage db upgrade (dbsync) - Remove all kolla_set_configs, KOLLA_CONFIG_STRATEGY, KOLLA_BOOTSTRAP env vars and the kolla_extend_start script - Delete all config.json templates (barbican-api-config.json, barbican-dbsync-config.json, barbican-worker-config.json, barbican-keystone-listener-config.json, barbican-pkcs11-prep-config.json) and launcher scripts (barbican-worker, barbican-keystone-listener) - Remove PKCS11ClientDataPath from template parameters (no longer needed without kolla config.json staging) - Mount configs via SubPath to /etc/barbican/, /etc/httpd/, /etc/my.cnf, /var/www/cgi-bin/barbican/main - Add emptyDir volumes for writable paths (/run/httpd, /var/log/httpd, /var/log/barbican) using lib-common volume.WritableDirVolume/Mount helpers with standardized constants (volume.RunHttpdVolumeName, volume.VarLogHttpdVolumeName, etc.) - Use pod.RestrictiveSecurityContext and RestrictivePodSecurityContext from lib-common for all workloads, setting ReadOnlyRootFilesystem, dropping ALL capabilities, and enabling seccomp RuntimeDefault - Set AutomountServiceAccountToken=false on all workloads -- none need k8s API access (ServiceAccountName is kept for SCC binding) - Import BarbicanUID from lib-common modules/serviceuser - Config Secret DefaultMode set to 0440 (owner-read + group-read, most restrictive -- all SubPath mounts are ReadOnly: true) - Override TLS CertMount/KeyMount to /etc/pki/tls/ for Apache - Grant nonroot-v2 SCC alongside anyuid in both the +kubebuilder:rbac marker and the hardcoded rbacRules slice passed to ReconcileRbac() (the RBAC lives in two places -- the marker feeds the operator's ClusterRole, while rbacRules creates the runtime Role/RoleBinding for the workload ServiceAccount; both must be updated) - Update httpd.conf: User/Group barbican - Support custom config overwrite keys via dynamic SubPath mounts into /etc/barbican/ with backwards-compatible directory mount at /etc/barbican/barbican.conf.d/ - Update functional and kuttl tests Found and fixed two real staging-vs-final path bugs that only kolla's copy step was masking: BarbicanAPI's per-endpoint TLS cert/key were falling back to lib-common's default staging mount instead of the path 10-barbican_wsgi_main.conf actually expects, and HSM/PKCS11 client data was mounted at an internal staging constant instead of the user-configured ClientDataPath the vendor library reads from. Note: the PKCS11 prep Job still runs as root (RunAsUser: 0) because the vendor HSM client library setup performed by generate_pkcs11_keys.sh is not verified to work under a non-root UID without real HSM hardware. The anyuid SCC grant is legitimate for this workload and cannot be dropped while the pkcs11-prep Job shares a ServiceAccount with the other Barbican services. Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/keystone-operator
that referenced
this pull request
Aug 6, 2026
Eliminate kolla_start/kolla_set_configs and the config.json staging
pattern. Configs are now mounted directly to final paths via SubPath
volume mounts, removing the need for root privilege escalation at
container startup.
Key changes:
- Replace kolla_start with /usr/sbin/httpd -DFOREGROUND
- Remove kolla_set_configs from bootstrap command
- Remove all KOLLA_CONFIG_STRATEGY and KOLLA_BOOTSTRAP env vars
- Delete keystone-api-config.json (no longer needed)
- Mount configs via SubPath to /etc/keystone/, /etc/httpd/, /etc/my.cnf
- Add emptyDir volumes for writable paths (/run/httpd, /tmp, /var/log)
using lib-common volume.WritableDirVolume/Mount helpers with
standardized constants (volume.RunHttpdVolumeName, TmpVolumeName, etc.)
- Use pod.RestrictiveSecurityContext and RestrictivePodSecurityContext
from lib-common for all workloads (deployment, bootstrap, dbsync,
cronjob), setting ReadOnlyRootFilesystem, dropping ALL capabilities,
and enabling seccomp RuntimeDefault
- Set AutomountServiceAccountToken=false on all workloads — none need
k8s API access (ServiceAccountName is kept for SCC binding)
- Import KeystoneUID from lib-common modules/serviceuser
- Override TLS CertMount/KeyMount to /etc/pki/tls/ for Apache
- Migrate SCC from anyuid to nonroot-v2
- Update httpd.conf: User/Group keystone, PidFile /run/httpd/httpd.pid
- Support custom httpd config keys via dynamic SubPath mounts
- Config Secret DefaultMode set to 0440 (owner-read + group-read,
most restrictive — all SubPath mounts are ReadOnly: true anyway)
- Update functional and kuttl tests
Testing on a cluster surfaced a permission denial starting httpd:
httpd: Syntax error on line 16 of /etc/httpd/conf/httpd.conf:
Could not open configuration file /etc/httpd/conf.d/auth_openidc.conf:
Permission denied
mod_auth_openidc's auth_openidc.conf ships root:apache 0640 and is
baked into the container image rather than volume-mounted, so FSGroup
does not apply to it. Under the previous kolla/anyuid setup this was
never an issue: the httpd master process ran as root and could read
any file regardless of group. TCIB never adds the keystone service
user to the apache group (uid_gid_manage.sh only ever adds it to
"kolla"), so running the whole pod as non-root keystone requires the
apache group to be granted explicitly at the pod level via
RestrictivePodSecurityContext's new supplementalGroups parameter and
lib-common's serviceuser.ApacheGID constant.
Testing further surfaced httpd failing to start with:
(13)Permission denied: AH00091: httpd: could not open error log
file /etc/httpd/logs/error_log.
AH00015: Unable to open logs
/etc/httpd/logs is a symlink to /var/log/httpd (root:root 0700 in the
image). httpd.conf only redirected ErrorLog/CustomLog to /dev/stdout
inside <VirtualHost> blocks, so the global/startup error log fell back
to Apache's compiled-in default of "logs/error_log" relative to
ServerRoot. Fixed by adding a top-level ErrorLog directive, plus a
var-log-httpd emptyDir mounted at /var/log/httpd as defense-in-depth
for any other RPM-shipped conf.d file that references relative
"logs/*" paths.
ErrorLog (both the top-level and per-vhost directives) is sent to
/dev/stderr rather than /dev/stdout, following the convention used by
the official Apache httpd container image and OpenShift Logging's
per-stream labeling, keeping error diagnostics distinguishable from
routine access logs (CustomLog stays on /dev/stdout).
Testing also surfaced a keystone WARNING:
keystone.common.fernet_utils [...] key_repository is world readable:
/etc/keystone/fernet-keys
The fernet-keys and credential-keys Secret volumes had no DefaultMode
set, so Kubernetes defaulted to 0644 (world-readable), unlike
config-data which was already hardened to 0440. Fixed by setting
DefaultMode 0440 on both, matching config-data and silencing the
warning.
Jira: OSPRH-33504
Jira: OSPRH-33503
Depends-On: openstack-k8s-operators/lib-common#728
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/barbican-operator
that referenced
this pull request
Aug 6, 2026
Removes kolla_start/kolla_set_configs/config.json staging across all five Barbican workloads (API, worker, keystone-listener, db-sync, pkcs11-prep), replacing it with direct volume mounts at final config paths and hardcoded service commands. Key changes: - Replace kolla_start with /usr/sbin/httpd -DFOREGROUND (API), barbican-worker (worker), barbican-keystone-listener (listener), barbican-manage db upgrade (dbsync) - Remove all kolla_set_configs, KOLLA_CONFIG_STRATEGY, KOLLA_BOOTSTRAP env vars and the kolla_extend_start script - Delete all config.json templates (barbican-api-config.json, barbican-dbsync-config.json, barbican-worker-config.json, barbican-keystone-listener-config.json, barbican-pkcs11-prep-config.json) and launcher scripts (barbican-worker, barbican-keystone-listener) - Remove PKCS11ClientDataPath from template parameters (no longer needed without kolla config.json staging) - Mount configs via SubPath to /etc/barbican/, /etc/httpd/, /etc/my.cnf, /var/www/cgi-bin/barbican/main - Add emptyDir volumes for writable paths (/run/httpd, /var/log/httpd, /var/log/barbican) using lib-common volume.WritableDirVolume/Mount helpers with standardized constants (volume.RunHttpdVolumeName, volume.VarLogHttpdVolumeName, etc.) - Use pod.RestrictiveSecurityContext and RestrictivePodSecurityContext from lib-common for all workloads, setting ReadOnlyRootFilesystem, dropping ALL capabilities, and enabling seccomp RuntimeDefault - Set AutomountServiceAccountToken=false on all workloads -- none need k8s API access (ServiceAccountName is kept for SCC binding) - Import BarbicanUID from lib-common modules/serviceuser - Config Secret DefaultMode set to 0440 (owner-read + group-read, most restrictive -- all SubPath mounts are ReadOnly: true) - Override TLS CertMount/KeyMount to /etc/pki/tls/ for Apache - Grant nonroot-v2 SCC alongside anyuid in both the +kubebuilder:rbac marker and the hardcoded rbacRules slice passed to ReconcileRbac() (the RBAC lives in two places -- the marker feeds the operator's ClusterRole, while rbacRules creates the runtime Role/RoleBinding for the workload ServiceAccount; both must be updated) - Update httpd.conf: User/Group barbican - Support custom config overwrite keys via dynamic SubPath mounts into /etc/barbican/ with backwards-compatible directory mount at /etc/barbican/barbican.conf.d/ - Update functional and kuttl tests Found and fixed two real staging-vs-final path bugs that only kolla's copy step was masking: BarbicanAPI's per-endpoint TLS cert/key were falling back to lib-common's default staging mount instead of the path 10-barbican_wsgi_main.conf actually expects, and HSM/PKCS11 client data was mounted at an internal staging constant instead of the user-configured ClientDataPath the vendor library reads from. Note: the PKCS11 prep Job still runs as root (RunAsUser: 0) because the vendor HSM client library setup performed by generate_pkcs11_keys.sh is not verified to work under a non-root UID without real HSM hardware. The anyuid SCC grant is legitimate for this workload and cannot be dropped while the pkcs11-prep Job shares a ServiceAccount with the other Barbican services. Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/keystone-operator
that referenced
this pull request
Aug 6, 2026
Eliminate kolla_start/kolla_set_configs and the config.json staging
pattern. Configs are now mounted directly to final paths via SubPath
volume mounts, removing the need for root privilege escalation at
container startup.
Key changes:
- Replace kolla_start with /usr/sbin/httpd -DFOREGROUND
- Remove kolla_set_configs from bootstrap command
- Remove all KOLLA_CONFIG_STRATEGY and KOLLA_BOOTSTRAP env vars
- Delete keystone-api-config.json (no longer needed)
- Mount configs via SubPath to /etc/keystone/, /etc/httpd/, /etc/my.cnf
- Add emptyDir volumes for writable paths (/run/httpd, /tmp, /var/log)
using lib-common volume.WritableDirVolume/Mount helpers with
standardized constants (volume.RunHttpdVolumeName, TmpVolumeName, etc.)
- Use pod.RestrictiveSecurityContext and RestrictivePodSecurityContext
from lib-common for all workloads (deployment, bootstrap, dbsync,
cronjob), setting ReadOnlyRootFilesystem, dropping ALL capabilities,
and enabling seccomp RuntimeDefault
- Set AutomountServiceAccountToken=false on all workloads — none need
k8s API access (ServiceAccountName is kept for SCC binding)
- Import KeystoneUID from lib-common modules/serviceuser
- Override TLS CertMount/KeyMount to /etc/pki/tls/ for Apache
- Migrate SCC from anyuid to nonroot-v2
- Update httpd.conf: User/Group keystone, PidFile /run/httpd/httpd.pid
- Support custom httpd config keys via dynamic SubPath mounts
- Config Secret DefaultMode set to 0440 (owner-read + group-read,
most restrictive — all SubPath mounts are ReadOnly: true anyway)
- Update functional and kuttl tests
Testing on a cluster surfaced a permission denial starting httpd:
httpd: Syntax error on line 16 of /etc/httpd/conf/httpd.conf:
Could not open configuration file /etc/httpd/conf.d/auth_openidc.conf:
Permission denied
mod_auth_openidc's auth_openidc.conf ships root:apache 0640 and is
baked into the container image rather than volume-mounted, so FSGroup
does not apply to it. Under the previous kolla/anyuid setup this was
never an issue: the httpd master process ran as root and could read
any file regardless of group. TCIB never adds the keystone service
user to the apache group (uid_gid_manage.sh only ever adds it to
"kolla"), so running the whole pod as non-root keystone requires the
apache group to be granted explicitly at the pod level via
RestrictivePodSecurityContext's new supplementalGroups parameter and
lib-common's serviceuser.ApacheGID constant.
Testing further surfaced httpd failing to start with:
(13)Permission denied: AH00091: httpd: could not open error log
file /etc/httpd/logs/error_log.
AH00015: Unable to open logs
/etc/httpd/logs is a symlink to /var/log/httpd (root:root 0700 in the
image). httpd.conf only redirected ErrorLog/CustomLog to /dev/stdout
inside <VirtualHost> blocks, so the global/startup error log fell back
to Apache's compiled-in default of "logs/error_log" relative to
ServerRoot. Fixed by adding a top-level ErrorLog directive, plus a
var-log-httpd emptyDir mounted at /var/log/httpd as defense-in-depth
for any other RPM-shipped conf.d file that references relative
"logs/*" paths.
ErrorLog (both the top-level and per-vhost directives) is sent to
/dev/stderr rather than /dev/stdout, following the convention used by
the official Apache httpd container image and OpenShift Logging's
per-stream labeling, keeping error diagnostics distinguishable from
routine access logs (CustomLog stays on /dev/stdout).
Testing also surfaced a keystone WARNING:
keystone.common.fernet_utils [...] key_repository is world readable:
/etc/keystone/fernet-keys
The fernet-keys and credential-keys Secret volumes had no DefaultMode
set, so Kubernetes defaulted to 0644 (world-readable), unlike
config-data which was already hardened to 0440. Fixed by setting
DefaultMode 0440 on both, matching config-data and silencing the
warning.
Jira: OSPRH-33504
Jira: OSPRH-33503
Depends-On: openstack-k8s-operators/lib-common#728
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/cinder-operator
that referenced
this pull request
Aug 6, 2026
Eliminate kolla_start/kolla_set_configs and the config.json staging
pattern across all 4 cinder workloads (api, scheduler, volume,
backup). Configs are now mounted directly to final paths via SubPath
volume mounts, removing the need for root privilege escalation at
container startup. Cinder's Pattern A conf.d-overlay config mechanism
(parent Cinder CR renders global config, each child merges its own
snippets into cinder.conf.d) is native to cinder/oslo.config and
untouched by this change.
Key changes:
- Replace kolla_start with direct commands per workload
(httpd -DFOREGROUND, cinder-scheduler/-volume/-backup --config-dir)
- Remove all KOLLA_CONFIG_STRATEGY env vars and the 5 kolla
config.json templates
- Mount configs via SubPath to /etc/cinder/, /etc/httpd/, /etc/my.cnf
- Replace kolla's run-on-host shim copy (multipath/iscsi/lvm tooling
for cinder-volume/backup) with SubPath mounts of the existing
scripts secret at each host-binary destination path
- Use pod.RestrictiveSecurityContext and RestrictivePodSecurityContext
from lib-common for cinder-api/scheduler and both probe sidecars;
cinder-volume/backup keep Privileged: true (genuine LVM/iSCSI/
multipath device access need) but now pin RunAsUser/RunAsGroup/
RunAsNonRoot instead of defaulting to root
- Set AutomountServiceAccountToken=false on all workloads
- Import CinderUID from lib-common modules/serviceuser, drop the
now-unused local CinderUserID/CinderGroupID constants
- Override TLS CertMount/KeyMount to /etc/pki/tls/ for cinder-api
- Migrate SCC rbacRules from [anyuid, privileged] to
[privileged, nonroot-v2] — anyuid is no longer needed anywhere in
this repo
- Harden the db-sync/online-data-migrations Job (previously
RunAsUser: 0) and db-purge CronJob to the same restrictive context
- Standardize all config-data secret DefaultMode from 0644 to 0440
across every volume definition: per-service config-data-custom
secrets (cinderapi, cinderbackup, cinderscheduler, cindervolume),
the parent config-data secret (cinder/volumes.go), and the
db-sync/online-data-migrations Job and db-purge CronJob config
secrets. Scripts volumes retain their executable 0755 mode.
- Adopt lib-common volume.WritableDirVolume/WritableDirVolumeMount
helpers for all emptyDir volumes: tmp (cinder/volumes.go),
run-httpd and logs (cinderapi/volumes.go), replacing inline
EmptyDir constructions with the shared constants
(volume.TmpVolumeName, volume.TmpMountPath, volume.RunHttpdVolumeName,
volume.RunHttpdMountPath)
- Update httpd.conf: User/Group cinder, PidFile /run/httpd/httpd.pid,
ErrorLog to stderr (Include conf.d/*.conf and ssl.conf generation
intentionally left untouched, pending a separate discussion with
the code's owner)
ReadOnlyRootFilesystem fallout, found via real-cluster testing:
- Memcached mTLS: CreateMTLSVolumeMounts(nil, nil) mounts the client
cert/key/CA at their staging defaults
(/var/lib/config-data/mtls/{certs,private}), not at the
/etc/pki/tls/{certs,private} paths the rendered cinder.conf
actually references (MemcachedAuthCert/Key/Ca, wired from
memcachedv1.CertMountPath()/KeyMountPath()/CaMountPath()). Kolla's
config.json used to bridge that gap by copying between the two;
with kolla gone, pass CertMountPath/KeyMountPath overrides so the
mount lands directly where the config expects it.
- cinder-api crashed on every request with "OSError: [Errno 30]
Read-only file system: '/var/lib/cinder/groups'": tooz's local
file-based coordination backend (the default when no
[coordination] backend_url is configured) creates that directory
on every WSGI worker start. Same risk for [oslo_concurrency]
lock_path=/var/locks/openstack/cinder, set globally for all 4
services but previously only mounted (as hostPath) for
volume/backup. Fixed for cinder-api/scheduler by mounting writable
emptyDirs — narrowly, via SubPath onto tooz's two fixed
subdirectories (state_path/groups, state_path/tmp) rather than
shadowing all of /var/lib/cinder, since the image may bake real
content there (e.g. the cinder user's home directory files).
cinder-volume/backup were never given ReadOnlyRootFilesystem and
are unaffected regardless of backend driver.
- Same treatment for /var/lib/cinder/.cache: RHEL's
python3-setuptools/pkg_resources downstream patch caches
iter_entry_points() scans under $HOME/.cache/python-entrypoints/
<hash> on every process start. Confirmed via real-cluster
inspection across multiple operators in this effort (glance,
neutron) -- a platform-level Python behavior, not cinder-specific,
wherever ReadOnlyRootFilesystem meets a service's home directory
with no full PVC covering it. keystone and neutron independently
hit the identical class of gap with three different ad-hoc shapes,
so this (and the groups/tmp mounts above) now go through a shared
lib-common helper, pod.WritableHomeDirVolume/WritableHomeDirMounts
-- same paths, no behavior change. The same lib-common addition
also provides pod.PrivilegedSecurityContext(uid), which replaced
the hand-built Privileged SecurityContext structs in
cindervolume/cinderbackup's statefulsets (glance-operator had the
identical struct independently).
- Update functional and kuttl tests
- var-lib-cinder-coordination's groups/tmp/.cache mounts now source
homeDir from serviceuser.Registry["cinder"].Home instead of a
repeated "/var/lib/cinder" literal, closing the follow-up noted
when pod.WritableHomeDirMounts was added
- Drop ReadOnlyRootFilesystem from this POC's SecurityContext hardening
(kept RunAsNonRoot/capability-drop/seccomp/nonroot-v2): it was the
single biggest source of debugging overhead across every operator in
this effort for comparatively little marginal benefit at this POC
stage. Removed the now-unnecessary var-lib-cinder-coordination
(groups/tmp/.cache) and the api/scheduler-specific var-locks-cinder
emptyDir as a result -- cinder-volume/backup's real hostPath mounts
of the same names are untouched, those were never RORFS-related.
The pre-revert state is preserved on branch remove-kolla-rorfs for
anyone revisiting RORFS later
Jira: OSPRH-33504
Jira: OSPRH-33503
Depends-On: openstack-k8s-operators/lib-common#728
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/cinder-operator
that referenced
this pull request
Aug 6, 2026
Eliminate kolla_start/kolla_set_configs and the config.json staging pattern across all 4 cinder workloads (api, scheduler, volume, backup). Configs are now mounted directly to final paths via SubPath volume mounts, removing the need for root privilege escalation at container startup. Cinder's Pattern A conf.d-overlay config mechanism (parent Cinder CR renders global config, each child merges its own snippets into cinder.conf.d) is native to cinder/oslo.config and untouched by this change. Key changes: - Replace kolla_start with direct commands per workload (httpd -DFOREGROUND, cinder-scheduler/-volume/-backup --config-dir) - Remove all KOLLA_CONFIG_STRATEGY env vars and the 5 kolla config.json templates - Mount configs via SubPath to /etc/cinder/, /etc/httpd/, /etc/my.cnf - Mount ssl.conf from lib-common CommonTemplates at /etc/httpd/conf.d/ssl.conf to override the RPM-shipped default (which references the non-existent localhost.crt) - Replace kolla's run-on-host shim copy (multipath/iscsi/lvm tooling for cinder-volume/backup) with SubPath mounts of the existing scripts secret at each host-binary destination path - Use pod.RestrictiveSecurityContext and RestrictivePodSecurityContext from lib-common for cinder-api/scheduler and both probe sidecars; cinder-volume/backup keep Privileged: true (genuine LVM/iSCSI/ multipath device access need) but now pin RunAsUser/RunAsGroup/ RunAsNonRoot instead of defaulting to root - Set AutomountServiceAccountToken=false on all workloads - Import CinderUID from lib-common modules/serviceuser, drop the now-unused local CinderUserID/CinderGroupID constants - Override TLS CertMount/KeyMount to /etc/pki/tls/ for cinder-api - Migrate SCC rbacRules from [anyuid, privileged] to [privileged, nonroot-v2] — anyuid is no longer needed anywhere in this repo - Harden the db-sync/online-data-migrations Job (previously RunAsUser: 0) and db-purge CronJob to the same restrictive context - Standardize all config-data secret DefaultMode to 0440 (owner-read + group-read) across every volume definition - Adopt lib-common volume.WritableDirVolume/WritableDirVolumeMount helpers for all emptyDir volumes (tmp, run-httpd, logs), replacing inline EmptyDir constructions with standardized constants - Update httpd.conf: User/Group cinder, PidFile /run/httpd/httpd.pid, ErrorLog to stderr - Update functional and kuttl tests Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/designate-operator
that referenced
this pull request
Aug 6, 2026
Eliminate kolla_start/kolla_set_configs and the config.json staging
pattern for designate-api, -central, -worker, -producer, and -mdns. The
crudini-based config-merge init container (parent + child config
secrets merged into a config-data-merged emptyDir) is kept exactly
as-is -- only kolla's staging-to-final copy step is replaced with
SubPath mounts of the same emptyDir at final paths.
Key changes:
- Replace kolla_start with the real per-service command
(designate-central/-worker/-producer/-mdns --config-file ...
--config-dir ...; /usr/sbin/httpd -DFOREGROUND for designate-api)
- designate-producer and designate-mdns previously had no explicit
Command at all -- they silently relied on the image's kolla-based
default ENTRYPOINT; both needed a Command added, not just replaced
- db-sync: exec bootstrap.sh directly instead of through kolla_start
- Mount designate.conf/custom.conf/my.cnf via SubPath from the merged
emptyDir to their final paths; designate-api additionally mounts
httpd.conf/ssl.conf the same way, plus new run-httpd/var-log-httpd
emptyDirs
- Add GetConfigOverwriteVolumeMounts() to mount DefaultConfigOverwrite
keys (e.g. policy.yaml) individually, since they are not
unconditionally present
- Remove all KOLLA_CONFIG_STRATEGY env vars and delete the 6 now
unreferenced *-config.json templates (api, central, worker, producer,
mdns, db-sync)
- Use pod.RestrictiveSecurityContext/RestrictivePodSecurityContext from
lib-common (serviceuser.DesignateUID) on all 5 migrated services plus
the pool_update.go Jobs (PoolUpdateJob, PoolListJob)
- Init containers (SimpleInitContainer, InitContainer) changed from
RunAsUser: 0 to RestrictiveSecurityContext(DesignateUID) -- init.sh
only does cp/crudini into an emptyDir, no root needed
- init.sh: cp -a changed to cp -r to avoid attempting ownership
preservation that silently fails as non-root
- Fix the TLS cert staging-path bug on designate-api: the per-endpoint
TLS loop had no CertMount/KeyMount override, so certs landed at
lib-common's default staging path while the rendered httpd.conf's
SSLCertificateFile/SSLCertificateKeyFile already pointed at
/etc/pki/tls/{certs,private}/<endpt>.{crt,key}
- httpd.conf: User/Group apache -> designate
- RBAC: add nonroot-v2 additively (anyuid;privileged;nonroot-v2) in
both the kubebuilder marker and the runtime rbacRules slice
- DefaultMode 0440 for all config/secret volume mounts
(ProcessVolumes modeMap, backendbind9 volumes, worker projected vol,
pool_update PoolUpdateJob/PoolListJob config volumes)
- AutomountServiceAccountToken: ptr.To(false) added to all workloads
(api, central, mdns, producer, worker, unbound, backendbind9,
db-sync job, pool-update/pool-list jobs)
- designate-unbound SecurityContext hardened: added pod-level
RestrictivePodSecurityContext(DesignateUID) with per-container
RunAsUser: 0 + RunAsNonRoot: false override (ironic dnsmasq pattern)
-- unbound must start as root to bind port 53
- backendbind9 inline emptyDir volumes replaced with lib-common
volume.WritableDirVolume() helpers
- Removed stale "Keeps kolla happy" comment from init.sh
- Update functional and kuttl tests
The predictableips init container keeps root + NET_ADMIN/CHOWN for
multus network interface setup (netlink address add) and crudini
config ownership preservation. SYS_ADMIN/SYS_NICE were removed as
they are unused by setipalias.py.
designate-backend-bind9 and designate-unbound keep RunAsUser 0
unchanged: both self-drop privileges after binding port 53.
designate-backend-bind9's own kolla removal is deliberately deferred:
its config generation runs through a bespoke per-pod init.sh that
selects an RNDC/TSIG key by StatefulSet pod ordinal, does a
whole-directory copy into /etc/named, and relies on kolla's own
"permissions" block -- meaningfully more complex than every other
service's shared merge script, and since bind9 stays root anyway
(no hardening benefit), the risk outweighed the consistency benefit.
Its KOLLA_CONFIG_STRATEGY env var was deliberately left in place:
removing just the env var while keeping kolla_start would silently
flip its copy strategy from COPY_ALWAYS to kolla's default COPY_ONCE.
Jira: OSPRH-33504
Jira: OSPRH-33503
Depends-On: openstack-k8s-operators/lib-common#728
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/glance-operator
that referenced
this pull request
Aug 6, 2026
Eliminate kolla_start/kolla_set_configs and the config.json staging pattern for GlanceAPI, db-sync, and all CronJobs. Configs are now mounted directly to final paths via SubPath volume mounts. Key changes: - Replace kolla_start with direct exec commands (httpd -DFOREGROUND, glance-api via dumb-init wrapper, tail log sidecar) - Inline kolla_extend_start's worker_self_reference_url logic into the container command as a shell snippet (workerSelfReferenceScript), needed for distributed image import when GLANCE_DOMAIN is set - Replace kolla config.json copy pattern with SubPath mounts for glance.conf.d snippets (00/02/03-config.conf), my.cnf, httpd.conf, wsgi/proxypass vhost configs, and ssl.conf - Mount run-on-host nsenter shims via per-binary SubPath VolumeMounts (runOnHostVolumeMount) instead of kolla config_files copy directives - Delete all config.json templates, kolla_extend_start script, and kolla-era security context helpers (BaseSecurityContext, HttpdSecurityContext, APISecurityContext, dbSyncSecurityContext) - Use lib-common pod.RestrictivePodSecurityContext / RestrictiveSecurityContext and pod.PrivilegedSecurityContext (Cinder backend) with serviceuser.GlanceUID across all workloads (StatefulSet, db-sync Job, db-purge CronJob, image-cache cleaner/pruner CronJobs) - Add AutomountServiceAccountToken: false to all pod specs - SCC requirement lowered from anyuid to nonroot-v2 (privileged retained for Cinder backends) - Image-cache CronJobs no longer force privileged mode; node colocation handled by pod affinity (ColocateWithPod) - Config Secret DefaultMode standardized to 0440 (owner-read + group-read) across all workloads via package-level configMode var - Writable emptyDir paths use lib-common volume.WritableDirVolume / WritableDirVolumeMount helpers with standardized constants (volume.RunHttpdVolumeName, volume.RunHttpdMountPath) - Replace inline GetConfigSecretVolumes with lib-common volume.ConfigSecretVolumes helper - Remove dead constants (GlanceUID, GlanceGID, GlanceDBSyncCommand, HttpdRunVolume) and unused volume helper functions (GetEphemeralVolume, GetLogVolumeMount, GetHttpdRunVolumeMount, GetConfigSecretVolumes) - httpd.conf: run as glance user (not apache), PidFile in /run/httpd, ErrorLog to /dev/stderr - Update troubleshooting docs and hack script for kolla-free workflow - Update kuttl and functional test assertions for new volume counts, DefaultMode values, and container commands Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/designate-operator
that referenced
this pull request
Aug 6, 2026
Eliminate kolla_start/kolla_set_configs and the config.json staging
pattern for designate-api, -central, -worker, -producer, and -mdns. The
crudini-based config-merge init container (parent + child config
secrets merged into a config-data-merged emptyDir) is kept exactly
as-is -- only kolla's staging-to-final copy step is replaced with
SubPath mounts of the same emptyDir at final paths.
Key changes:
- Replace kolla_start with the real per-service command
(designate-central/-worker/-producer/-mdns --config-file ...
--config-dir ...; /usr/sbin/httpd -DFOREGROUND for designate-api)
- designate-producer and designate-mdns previously had no explicit
Command at all -- they silently relied on the image's kolla-based
default ENTRYPOINT; both needed a Command added, not just replaced
- db-sync: exec bootstrap.sh directly instead of through kolla_start
- Mount designate.conf/custom.conf/my.cnf via SubPath from the merged
emptyDir to their final paths; designate-api additionally mounts
httpd.conf/ssl.conf the same way, plus new run-httpd/var-log-httpd
emptyDirs
- Add GetConfigOverwriteVolumeMounts() to mount DefaultConfigOverwrite
keys (e.g. policy.yaml) individually, since they are not
unconditionally present
- Remove all KOLLA_CONFIG_STRATEGY env vars and delete the 6 now
unreferenced *-config.json templates (api, central, worker, producer,
mdns, db-sync)
- Use pod.RestrictiveSecurityContext/RestrictivePodSecurityContext from
lib-common (serviceuser.DesignateUID) on all 5 migrated services plus
the pool_update.go Jobs (PoolUpdateJob, PoolListJob)
- Init containers (SimpleInitContainer, InitContainer) changed from
RunAsUser: 0 to RestrictiveSecurityContext(DesignateUID) -- init.sh
only does cp/crudini into an emptyDir, no root needed
- init.sh: cp -a changed to cp -r to avoid attempting ownership
preservation that silently fails as non-root
- Fix the TLS cert staging-path bug on designate-api: the per-endpoint
TLS loop had no CertMount/KeyMount override, so certs landed at
lib-common's default staging path while the rendered httpd.conf's
SSLCertificateFile/SSLCertificateKeyFile already pointed at
/etc/pki/tls/{certs,private}/<endpt>.{crt,key}
- httpd.conf: User/Group apache -> designate
- RBAC: add nonroot-v2 additively (anyuid;privileged;nonroot-v2) in
both the kubebuilder marker and the runtime rbacRules slice
- DefaultMode 0440 for all config/secret volume mounts
(ProcessVolumes modeMap, backendbind9 volumes, worker projected vol,
pool_update PoolUpdateJob/PoolListJob config volumes)
- AutomountServiceAccountToken: ptr.To(false) added to all workloads
(api, central, mdns, producer, worker, unbound, backendbind9,
db-sync job, pool-update/pool-list jobs)
- designate-unbound SecurityContext hardened: added pod-level
RestrictivePodSecurityContext(DesignateUID) with per-container
RunAsUser: 0 + RunAsNonRoot: false override (ironic dnsmasq pattern)
-- unbound must start as root to bind port 53
- backendbind9 inline emptyDir volumes replaced with lib-common
volume.WritableDirVolume() helpers
- Removed stale "Keeps kolla happy" comment from init.sh
- Update functional and kuttl tests
The predictableips init container keeps root + NET_ADMIN/CHOWN for
multus network interface setup (netlink address add) and crudini
config ownership preservation. SYS_ADMIN/SYS_NICE were removed as
they are unused by setipalias.py.
designate-backend-bind9 and designate-unbound keep RunAsUser 0
unchanged: both self-drop privileges after binding port 53.
designate-backend-bind9's own kolla removal is deliberately deferred:
its config generation runs through a bespoke per-pod init.sh that
selects an RNDC/TSIG key by StatefulSet pod ordinal, does a
whole-directory copy into /etc/named, and relies on kolla's own
"permissions" block -- meaningfully more complex than every other
service's shared merge script, and since bind9 stays root anyway
(no hardening benefit), the risk outweighed the consistency benefit.
Its KOLLA_CONFIG_STRATEGY env var was deliberately left in place:
removing just the env var while keeping kolla_start would silently
flip its copy strategy from COPY_ALWAYS to kolla's default COPY_ONCE.
Jira: OSPRH-33504
Jira: OSPRH-33503
Depends-On: openstack-k8s-operators/lib-common#728
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/heat-operator
that referenced
this pull request
Aug 6, 2026
Eliminate kolla_start and the config.json staging pattern for
heat-api, heat-cfnapi, and heat-engine. Pattern A (conf.d overlay):
the child config secret is already mounted at its final path
(/etc/heat/heat.conf.d), so removing kolla is mostly deleting the
staging mount and config.json rather than restructuring a merge
pipeline. db-sync and db-purge already bypassed kolla before this
change and are only lightly upgraded for SecurityContext consistency.
Key changes:
- Replace kolla_start with the real per-service command
(/usr/sbin/httpd -DFOREGROUND for heat-api/heat-cfnapi;
/usr/bin/heat-engine --config-dir /etc/heat/heat.conf.d for
heat-engine)
- Remove the kolla config.json SubPath mount and the
/var/lib/config-data/default whole-directory mount from
GetVolumeMounts; add heat-api/heat-cfnapi-specific SubPath mounts for
httpd.conf and ssl.conf, plus a new run-httpd emptyDir at
/run/httpd (PidFile was undefined in httpd.conf, with no writable
path once non-root)
- Remove all KOLLA_CONFIG_STRATEGY env vars and delete the 3 now
unreferenced *-config.json templates (api, cfnapi, engine)
- Use pod.RestrictiveSecurityContext/RestrictivePodSecurityContext from
lib-common (serviceuser.HeatUID) on heat-api, heat-cfnapi,
heat-engine, db-sync, and db-purge; delete the now-fully-unreferenced
GetHeatSecurityContext/GetHeatDBSecurityContext helpers
- Fix the TLS cert staging-path bug on heat-api/heat-cfnapi: the
per-endpoint TLS loop had no CertMount/KeyMount override, so certs
landed at lib-common's default staging path while the rendered
httpd.conf's SSLCertificateFile/SSLCertificateKeyFile already pointed
at /etc/pki/tls/{certs,private}/<endpt>.{crt,key}
- Fix the memcached mTLS staging-path bug on all three services
(heat-api, heat-cfnapi, heat-engine): CreateMTLSVolumeMounts(nil,
nil) defaults to lib-common's staging directory, while the rendered
00-default.conf's memcache_tls_certfile/tls_certfile etc. already
read from the final /etc/pki/tls/certs path
- Fix missing DefaultMode on the parent config-data secret volume:
GetVolumes set DefaultMode on config-data-custom but not on the
parent config-data volume, leaving it at the Kubernetes default 0644
instead of the intended restrictive mode
- Tighten all DefaultMode values from 0644 to 0440 (owner+group read,
no write, no world access) across config-data-custom, config-data,
db-purge-config-data, and config secret volumes; replace the local
GetConfigSecretVolumes with volume.ConfigSecretVolumes from
lib-common which also uses 0440
- Set AutomountServiceAccountToken: false on all workloads (heat-api,
heat-cfnapi, heat-engine deployments; db-sync job; db-purge cronjob)
to prevent unnecessary SA token projection
- Adopt lib-common volume helpers: replace inline emptyDir
constructions with volume.WritableDirVolume/WritableDirVolumeMount
using volume.RunHttpdVolumeName/RunHttpdMountPath constants
- httpd.conf: User/Group apache -> heat
- RBAC: clean anyuid -> nonroot-v2 swap in both the kubebuilder marker
and the runtime rbacRules slice -- confirmed nothing in this repo
needs elevated privilege or extra capabilities anywhere
- Update functional and kuttl tests
The memcached mTLS bug was almost missed: an initial pass concluded no
fix was needed here, reasoning by analogy that it would be as
vestigial as a similar-looking case found elsewhere in this effort.
Re-verifying directly against lib-common's memcached_funcs.go source
before trusting that conclusion showed it was wrong -- the staging and
final paths genuinely differ here, and heat has the exact same bug
class already found and fixed on keystone, cinder, and nova.
Jira: OSPRH-33504
Jira: OSPRH-33503
Depends-On: openstack-k8s-operators/lib-common#728
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/horizon-operator
that referenced
this pull request
Aug 6, 2026
Eleventh operator in the remove-kolla effort. Replaces the kolla_start/kolla_set_configs/config.json staging pattern with direct volume mounts to final config paths and direct service commands, and hardens the pod's SecurityContext from scratch. SecurityContext: horizon's kolla-era httpd/horizon worker processes always ran as apache (confirmed via `ps -ef` on a running kolla pod), never under a dedicated per-service system user the way keystone/manila do -- openstack-dashboard's RPM has never shipped its own user. Rather than migrate to serviceuser.HorizonUID like every other operator (which would silently break read/write access to any ExtraMount-backed content still owned apache:apache from before this migration), the pod keeps apache (serviceuser.ApacheUID, added to lib-common's serviceuser registry alongside the pre-existing ApacheGID) as its primary identity, with serviceuser.HorizonUID granted as a supplemental group instead. RBAC is additive (hostmount-anyuid;nonroot-v2), since horizon's documented custom-theme ExtraMount mechanism can plausibly need NFS. Custom theme mechanism: preserved via a non-root "theme-setup" init container that seeds a writable EmptyDir with the image's own baked -in themes plus any user-supplied *.tar.gz theme (via theme_setup, renamed from kolla_theme_setup since it was never actually an image-baked kolla script -- it's always lived in this repo). .horizon-secret: re-materialized via a dedicated "secret-setup" init container into a pod-owned EmptyDir with real 0600 permissions, since Kubernetes always mounts Secret-backed files root-owned with at least group-read forced on, which horizon's own secret_key.read_from_file() rejects as insecure. Writes through a whole-directory mount (no SubPath) so the file exists as a real file before any later container references it via a SubPath mount of the same path -- a SubPath mount of a not-yet-existing path is otherwise auto-created by kubelet as a directory, permanently, which cannot be fixed by any command running inside the container that mounts it that way. kolla_extend_start logic: kolla_start unconditionally ran this image-baked, per-service hook before exec'ing the final command. For horizon it does real, active work this migration must not drop: per-service dashboard panel enabling (Designate/Heat/Ironic/Manila/ Octavia/Watcher/CloudKitty) and settings-changed-detection driving "manage.py collectstatic"/"compress". Brought in-repo as templates/horizon/bin/dashboard_setup (a trimmed adaptation, not a runtime dependency on the image continuing to ship the original script), run by a "dashboard-setup" init container after theme-setup and secret-setup. Horizon has a unique 3-init-container pipeline: theme-setup seeds themes, secret-setup re-materializes the secret key with correct 0600 permissions, and dashboard-setup enables dashboard panels and regenerates static assets. All three must run in order. run-httpd mount path: fixed from /etc/httpd/run (a non-canonical symlink target) to /run/httpd (the actual PID file directory httpd expects at runtime). Config volume mode: ConfigMap-backed config-data volume changed from 0640 to 0440 (read-only for owner and group) since the service only needs to read its config, not write it. EmptyDir volumes: adopted lib-common volume.WritableDirVolume() and volume.WritableDirVolumeMount() helpers for all emptyDir volumes (logs, run-httpd, var-log-httpd, themes, dashboard-enabled, dashboard-static, settings-hash, horizon-secret). Generic httpd volumes (run-httpd, var-log-httpd) use the volume package's named constants; service-specific ones use string literals. Also fixes: API/WSGI and memcached-mTLS staging-path bugs (final paths already expected by httpd.conf/local_settings.py, but not supplied by lib-common's default staging-path helpers); a missing top-level httpd ErrorLog directive (same startup-crash risk found on keystone); STATIC_ROOT never being set in local_settings.py, causing collectstatic to write to Django's own package-relative default instead of the path httpd.conf's static Alias and the dashboard-static EmptyDir actually serve from. Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/horizon-operator
that referenced
this pull request
Aug 6, 2026
Replaces the kolla_start/kolla_set_configs/config.json staging pattern with direct volume mounts to final config paths and direct service commands, and hardens the pod's SecurityContext. SecurityContext: horizon's kolla-era httpd/horizon worker processes always ran as apache (confirmed via `ps -ef` on a running kolla pod), never under a dedicated per-service system user the way keystone/manila do -- openstack-dashboard's RPM has never shipped its own user. Rather than migrate to serviceuser.HorizonUID like every other operator (which would silently break read/write access to any ExtraMount-backed content still owned apache:apache from before this migration), the pod keeps apache (serviceuser.ApacheUID) as its primary identity, with serviceuser.HorizonUID granted as a supplemental group instead. RBAC is additive (hostmount-anyuid;nonroot-v2), since horizon's documented custom-theme ExtraMount mechanism can plausibly need NFS. Custom theme mechanism: preserved via a non-root "theme-setup" init container that seeds a writable EmptyDir with the image's own baked-in themes plus any user-supplied *.tar.gz theme (via theme_setup, renamed from kolla_theme_setup since it was never actually an image-baked kolla script -- it's always lived in this repo). .horizon-secret: re-materialized via a dedicated "secret-setup" init container into a pod-owned EmptyDir with real 0600 permissions, since Kubernetes always mounts Secret-backed files root-owned with at least group-read forced on, which horizon's own secret_key.read_from_file() rejects as insecure. Writes through a whole-directory mount (no SubPath) so the file exists as a real file before any later container references it via a SubPath mount of the same path -- a SubPath mount of a not-yet-existing path is otherwise auto-created by kubelet as a directory, permanently. kolla_extend_start logic: brought in-repo as templates/horizon/bin/dashboard_setup (a trimmed adaptation, not a runtime dependency on the image continuing to ship the original script), run by a "dashboard-setup" init container after theme-setup and secret-setup. Handles per-service dashboard panel enabling (Designate/Heat/Ironic/Manila/Octavia/Watcher/CloudKitty) and settings-changed-detection driving "manage.py collectstatic"/ "compress". Removed the dead heat_policy.json copy from config_heat_dashboard -- the image now ships heat_policy.yaml directly via RPM into /etc/openstack-dashboard/, so the script's .json reference was a no-op. Changed cp -a to cp -r in config_dashboard since ownership preservation silently fails as non-root. Horizon has a unique 3-init-container pipeline: theme-setup seeds themes, secret-setup re-materializes the secret key with correct 0600 permissions, and dashboard-setup enables dashboard panels and regenerates static assets. All three must run in order. Other key changes: - run-httpd mount path: /etc/httpd/run -> /run/httpd (canonical) - Config volume DefaultMode: 0640 -> 0440 - EmptyDir volumes: adopted lib-common volume.WritableDirVolume() helpers with standardized constants - Fix TLS/mTLS staging-path bugs (final paths expected by httpd.conf but not supplied by lib-common's default helpers) - Fix missing top-level httpd ErrorLog directive - Fix STATIC_ROOT in local_settings.py (was unset, causing collectstatic to write to Django's package-relative default) - AutomountServiceAccountToken: false - Update functional and kuttl tests Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/horizon-operator
that referenced
this pull request
Aug 6, 2026
Replaces the kolla_start/kolla_set_configs/config.json staging pattern with direct volume mounts to final config paths and direct service commands, and hardens the pod's SecurityContext. SecurityContext: horizon's kolla-era httpd/horizon worker processes always ran as apache (confirmed via `ps -ef` on a running kolla pod), never under a dedicated per-service system user the way keystone/manila do -- openstack-dashboard's RPM has never shipped its own user. Rather than migrate to serviceuser.HorizonUID like every other operator (which would silently break read/write access to any ExtraMount-backed content still owned apache:apache from before this migration), the pod keeps apache (serviceuser.ApacheUID) as its primary identity, with serviceuser.HorizonUID granted as a supplemental group instead. RBAC is additive (hostmount-anyuid;nonroot-v2), since horizon's documented custom-theme ExtraMount mechanism can plausibly need NFS. Custom theme mechanism: preserved via a non-root "theme-setup" init container that seeds a writable EmptyDir with the image's own baked-in themes plus any user-supplied *.tar.gz theme (via theme_setup, renamed from kolla_theme_setup since it was never actually an image-baked kolla script -- it's always lived in this repo). .horizon-secret: re-materialized via a dedicated "secret-setup" init container into a pod-owned EmptyDir with real 0600 permissions, since Kubernetes always mounts Secret-backed files root-owned with at least group-read forced on, which horizon's own secret_key.read_from_file() rejects as insecure. Writes through a whole-directory mount (no SubPath) so the file exists as a real file before any later container references it via a SubPath mount of the same path -- a SubPath mount of a not-yet-existing path is otherwise auto-created by kubelet as a directory, permanently. kolla_extend_start logic: brought in-repo as templates/horizon/bin/dashboard_setup (a trimmed adaptation, not a runtime dependency on the image continuing to ship the original script), run by a "dashboard-setup" init container after theme-setup and secret-setup. Handles per-service dashboard panel enabling (Designate/Heat/Ironic/Manila/Octavia/Watcher/CloudKitty) and settings-changed-detection driving "manage.py collectstatic"/ "compress". Removed the dead heat_policy.json copy from config_heat_dashboard -- the image now ships heat_policy.yaml directly via RPM into /etc/openstack-dashboard/, so the script's .json reference was a no-op. Changed cp -a to cp -r in config_dashboard since ownership preservation silently fails as non-root. Horizon has a unique 3-init-container pipeline: theme-setup seeds themes, secret-setup re-materializes the secret key with correct 0600 permissions, and dashboard-setup enables dashboard panels and regenerates static assets. All three must run in order. Other key changes: - run-httpd mount path: /etc/httpd/run -> /run/httpd (canonical) - Config volume DefaultMode: 0640 -> 0440 - EmptyDir volumes: adopted lib-common volume.WritableDirVolume() helpers with standardized constants - Fix TLS/mTLS staging-path bugs (final paths expected by httpd.conf but not supplied by lib-common's default helpers) - Fix missing top-level httpd ErrorLog directive - Fix STATIC_ROOT in local_settings.py (was unset, causing collectstatic to write to Django's package-relative default) - AutomountServiceAccountToken: false - Update functional and kuttl tests Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/ironic-operator
that referenced
this pull request
Aug 6, 2026
Fourteenth operator in the remove-kolla effort. Replaces the kolla_start/kolla_set_configs/config.json staging pattern with direct volume mounts to final config paths and direct service commands, across ironic-api, ironic-conductor, ironic-inspector, ironic-neutron-agent, and both db-sync jobs. RBAC: IronicAPI/Conductor/Inspector/NeutronAgent share one ServiceAccount/Role when owned by the parent Ironic CR, so they cannot get independently different SCC grants. The shared Role grants anyuid;privileged;nonroot-v2 -- conductor/inspector genuinely need anyuid+privileged for PXE chroot (SYS_CHROOT/SETFCAP) and DHCP/TFTP sub-1024-port binding (NET_ADMIN/NET_RAW), while nonroot-v2 is included to match every other operator in the effort that lists elevated SCCs. This means ironic-api runs fully non-root at the pod/container level even though its SCC grant is technically still broader than it needs; giving it a genuinely separate ServiceAccount was rejected as a bigger, riskier change than this migration's actual goal warranted. Mixed-privilege pods (conductor, inspector) carry a pod-level RestrictivePodSecurityContext for their non-root siblings, with dnsmasq (root, NET_ADMIN/NET_RAW for raw DHCP) and pxe-init (root, SYS_CHROOT/SETFCAP for chroot-based IPA CA-cert patching) explicitly overriding RunAsUser/RunAsNonRoot back to root on their own container SecurityContext -- a container's own explicit fields always override the pod-level default for that container. AutomountServiceAccountToken set to false on all workloads including conductor -- get_net_ip reads network status from the DownwardAPI volume (/etc/podinfo/network-status), not from the k8s API, and VerifyNetworkStatusFromAnnotation runs in the controller (operator manager), not in the pod. Adopts lib-common volume helpers (WritableDirVolume/WritableDirVolumeMount) for emptyDir volumes, using constants for run-httpd and string literals for ironic-specific volumes (var-lib-ironic, logs, etc.). Config secret DefaultMode tightened from 0640 to 0440. Also fixes: the standard TLS cert/key staging-path bug on ironic-api's and ironic-inspector's httpd (same class as every other httpd-fronted operator in this effort); httpd.conf User/Group changed from apache to ironic on ironic-api specifically, matching its pre-existing WSGIDaemonProcess user=ironic evidence, while ironic-inspector's proxy httpd and both httpboot instances keep apache (no such evidence exists for them). Config delivery uses three variants of the EmptyDir-seed pattern: plain final-path Secret SubPath mounts (the common case), a single merged file written by the init container's crudini-merge step before the main container starts (03-init-container-conductor.conf), and a dynamically pxe-init-generated dnsmasq.conf (not sourced from any Secret at all) -- all safe because the writer runs in an earlier, separate container through a whole-directory mount of the same volume, never via SubPath from within the same container that reads it back. dbsync.sh (a genuinely non-trivial script, not reimplemented) had only its one kolla-specific line (sudo -E kolla_set_configs) removed. Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/ironic-operator
that referenced
this pull request
Aug 6, 2026
Replaces the kolla_start/kolla_set_configs/config.json staging pattern with direct volume mounts to final config paths and direct service commands, across ironic-api, ironic-conductor, ironic-inspector, ironic-neutron-agent, and both db-sync jobs. RBAC: IronicAPI/Conductor/Inspector/NeutronAgent share one ServiceAccount/Role when owned by the parent Ironic CR, so they cannot get independently different SCC grants. The shared Role grants anyuid;privileged;nonroot-v2 -- conductor/inspector genuinely need anyuid+privileged for PXE chroot (SYS_CHROOT/SETFCAP) and DHCP/TFTP sub-1024-port binding (NET_ADMIN/NET_RAW), while nonroot-v2 is included to match every other operator in the effort. Mixed-privilege pods (conductor, inspector) carry a pod-level RestrictivePodSecurityContext for their non-root siblings, with dnsmasq and pxe-init explicitly overriding RunAsUser/RunAsNonRoot back to root on their own container SecurityContext. Both dnsmasq and pxe-init Drop ALL capabilities first, then add back only the specific caps they need (NET_ADMIN/NET_RAW for dnsmasq, SYS_CHROOT/SETFCAP for pxe-init). AutomountServiceAccountToken set to false on all workloads including conductor -- get_net_ip reads network status from the DownwardAPI volume (/etc/podinfo/network-status), not from the k8s API. Writable paths: - run-httpd emptyDir added to conductor (was missing entirely) and mount added to both conductor's and inspector's httpboot containers -- httpd cannot write its PID file without writable /run/httpd - Adopts lib-common volume.WritableDirVolume/WritableDirVolumeMount helpers with constants for run-httpd, string literals for ironic-specific volumes (var-lib-ironic, logs, etc.) Config secret DefaultMode tightened from 0640 to 0440. Also fixes: the standard TLS cert/key staging-path bug on ironic-api's and ironic-inspector's httpd; httpd.conf User/Group changed from apache to ironic on ironic-api specifically, matching its pre-existing WSGIDaemonProcess user=ironic evidence, while ironic-inspector's proxy httpd and both httpboot instances keep apache (no such evidence). Config delivery uses three variants of the EmptyDir-seed pattern: plain final-path Secret SubPath mounts, a single merged file written by the init container's crudini-merge step (03-init-container-conductor.conf), and a dynamically pxe-init-generated dnsmasq.conf -- all safe because the writer runs in an earlier container through a whole-directory mount. dbsync.sh had only its one kolla-specific line (sudo -E kolla_set_configs) removed. Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
Open
6 tasks
stuggi
added a commit
to stuggi/ironic-operator
that referenced
this pull request
Aug 6, 2026
Replaces the kolla_start/kolla_set_configs/config.json staging pattern with direct volume mounts to final config paths and direct service commands, across ironic-api, ironic-conductor, ironic-inspector, ironic-neutron-agent, and both db-sync jobs. RBAC: IronicAPI/Conductor/Inspector/NeutronAgent share one ServiceAccount/Role when owned by the parent Ironic CR, so they cannot get independently different SCC grants. The shared Role grants anyuid;privileged;nonroot-v2 -- conductor/inspector genuinely need anyuid+privileged for PXE chroot (SYS_CHROOT/SETFCAP) and DHCP/TFTP sub-1024-port binding (NET_ADMIN/NET_RAW), while nonroot-v2 is included to match every other operator in the effort. Mixed-privilege pods (conductor, inspector) carry a pod-level RestrictivePodSecurityContext for their non-root siblings, with dnsmasq and pxe-init explicitly overriding RunAsUser/RunAsNonRoot back to root on their own container SecurityContext. Both dnsmasq and pxe-init Drop ALL capabilities first, then add back only the specific caps they need (NET_ADMIN/NET_RAW for dnsmasq, SYS_CHROOT/SETFCAP for pxe-init). AutomountServiceAccountToken set to false on all workloads including conductor -- get_net_ip reads network status from the DownwardAPI volume (/etc/podinfo/network-status), not from the k8s API. Writable paths: - run-httpd emptyDir added to conductor (was missing entirely) and mount added to both conductor's and inspector's httpboot containers -- httpd cannot write its PID file without writable /run/httpd - Adopts lib-common volume.WritableDirVolume/WritableDirVolumeMount helpers with constants for run-httpd, string literals for ironic-specific volumes (var-lib-ironic, logs, etc.) Config secret DefaultMode tightened from 0640 to 0440. Also fixes: the standard TLS cert/key staging-path bug on ironic-api's and ironic-inspector's httpd; httpd.conf User/Group changed from apache to ironic on ironic-api specifically, matching its pre-existing WSGIDaemonProcess user=ironic evidence, while ironic-inspector's proxy httpd and both httpboot instances keep apache (no such evidence). Config delivery uses three variants of the EmptyDir-seed pattern: plain final-path Secret SubPath mounts, a single merged file written by the init container's crudini-merge step (03-init-container-conductor.conf), and a dynamically pxe-init-generated dnsmasq.conf -- all safe because the writer runs in an earlier container through a whole-directory mount. dbsync.sh had only its one kolla-specific line (sudo -E kolla_set_configs) removed. Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/manila-operator
that referenced
this pull request
Aug 6, 2026
Remove kolla_start / kolla config.json / KOLLA_CONFIG_STRATEGY from all
manila workloads (API, scheduler, share, dbsync job, cronjob). Each
service binary is now launched directly:
- manila-api: /usr/sbin/httpd -DFOREGROUND
- manila-scheduler: /usr/bin/manila-scheduler --config-dir ...
- manila-share: /usr/bin/manila-share --config-dir ...
Config files (httpd.conf, 10-manila_wsgi.conf) are mounted directly via
SubPath from the config-data secret instead of being copied by kolla at
startup. The deleted kolla config.json templates and the ssl.conf common
template reference are no longer needed.
Harden the security posture:
- Replace inline SecurityContext with pod.RestrictivePodSecurityContext
and pod.RestrictiveSecurityContext from lib-common (using
serviceuser.ManilaUID / serviceuser.ApacheGID).
- Add AutomountServiceAccountToken: ptr.To(false) to all workload
PodSpecs (API statefulset, scheduler statefulset, share statefulset,
dbsync job, db-purge cronjob).
- Change secret DefaultMode from 0644/0640 to 0440 across all volume
definitions using a package-level configMode variable.
- Switch SCC requirement from anyuid to hostmount-anyuid + nonroot-v2.
Adopt lib-common volume helpers:
- Replace inline emptyDir volumes/mounts for run-httpd, var-log-httpd,
and logs with volume.WritableDirVolume / volume.WritableDirVolumeMount
from lib-common/modules/common/volume.
- Remove GetConfigSecretVolumes (replaced by volume.ConfigSecretVolumes
in lib-common).
- Fix run-httpd mount path from /etc/httpd/run to the canonical
/run/httpd (matching lib-common's volume.RunHttpdMountPath constant).
Update httpd.conf to run as manila:manila (not apache:apache) since
containers no longer start as root.
Remove ManilaUserID / ManilaGroupID constants (replaced by
serviceuser.ManilaUID from lib-common).
Update MTLS volume mounts to use explicit cert/key mount paths instead
of nil (matching the infra-operator API change).
Update kuttl and functional tests to match the new volume counts,
mount paths, commands, and security context.
Jira: OSPRH-33504
Jira: OSPRH-33503
Depends-On: openstack-k8s-operators/lib-common#728
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/neutron-operator
that referenced
this pull request
Aug 6, 2026
Eliminate kolla_start and the config.json staging pattern across all neutron-operator workloads (neutron-api, neutron-httpd, db-sync). Configs are now mounted directly to final paths via SubPath volume mounts. neutron-operator already uses Pattern B (two self-contained Secrets: one for neutron-api/db-sync, one for neutron-httpd), like keystone/placement/glance — no conf.d-merge logic to reproduce. This repo already tried and reverted a kolla-removal attempt in 2023 (7a750f1, reverted by 62a2f29). That attempt replaced kolla with a custom init-container needing sudo, which forced AllowPrivilegeEscalation: true and blocked dropping ALL capabilities — a worse security posture than kolla itself. This migration does not repeat that mistake: all config rendering happens server-side in the Go controller, Secrets are mounted read-only via SubPath, and no runtime script/sudo is involved anywhere, the same proven approach already used for keystone/placement/cinder/glance. Key changes: - Replace kolla_start with direct commands per container/job (neutron-server, httpd -DFOREGROUND, neutron-db-manage) taken straight from each removed config.json's "command" field; the db-sync Job previously had no explicit Command/Args at all, relying on the image's default entrypoint — now explicit like every other workload - Remove KOLLA_CONFIG_STRATEGY env var and the 3 kolla config.json templates - Mount config-data keys via SubPath directly to /etc/neutron/neutron.conf.d/*.conf, /etc/httpd/conf(.d)/*, /etc/my.cnf; policy.yaml is mounted conditionally, only when set via spec.defaultConfigOverwrite (an unconditional mount would break any NeutronAPI that doesn't set it, since the secret key wouldn't exist) - BUG FIX: Add DefaultMode 0440 to both the "config" and "httpd-config" Secret volumes. Neither had a DefaultMode set, meaning k8s defaulted to 0644 (world-readable). These Secrets contain DB credentials, transport URLs, and service passwords that should only be readable by the service user and group — not by every process in the container - Adopt lib-common volume helpers (volume.WritableDirVolume, volume.WritableDirVolumeMount) with named constants (volume.RunHttpdVolumeName, volume.RunHttpdMountPath) for the run-httpd emptyDir, replacing inline constructions; removes the local GetHttpdRunVolume() function - Fix memcached mTLS cert/key mounting: CreateMTLSVolumeMounts(nil, nil) mounted at the staging default path instead of where the rendered config actually references them (same bug already found and fixed in cinder-operator, keystone-operator, and glance-operator) - Fix the OVN DB TLS cert mounts: the tls.Service literal only set CaMount, hardcoded to a kolla staging path even though 01-neutron.conf's ovn_nb_ca_cert/ovn_sb_ca_cert already pointed at the final /etc/pki/tls/certs/ovndbca.crt destination; CertMount/ KeyMount were left unset entirely, so the client cert/key (ovn_{nb,sb}_certificate/private_key) defaulted to a different kolla staging path with nothing there, crashing neutron-server at ML2/OVN driver init with FileNotFoundError on ovndb.crt. Found via real-cluster testing -- no functional or kuttl test exercises Spec.TLS.Ovn at all, so this was invisible to `make test` - Use pod.RestrictiveSecurityContext/RestrictivePodSecurityContext from lib-common for all three workloads — no privileged/host-access exception needed anywhere in this repo (unlike cinder/glance) - Set AutomountServiceAccountToken=false on all workloads - Migrate SCC rbacRules from [anyuid] to [nonroot-v2] only — no privileged fallback needed anywhere in this repo, the first operator in this effort with that simpler end state - Update functional and kuttl tests Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/watcher-operator
that referenced
this pull request
Aug 7, 2026
Replaces the kolla_start/kolla_set_configs/config.json staging pattern with direct volume mounts to final config paths and direct service commands for watcher-api, watcher-applier, watcher-decision-engine, db-sync, and db-purge. Key changes: - Replace kolla_start with direct commands per workload (httpd -DFOREGROUND, watcher-applier/decision-engine --config-dir, watcher-db-manage upgrade, watcher-db-manage purge) - Remove KOLLA_CONFIG_STRATEGY env vars and 5 config.json templates - Mount configs via SubPath to /etc/watcher/watcher.conf.d/, /etc/httpd/, /etc/my.cnf - Use pod.RestrictiveSecurityContext/RestrictivePodSecurityContext from lib-common (serviceuser.WatcherUID) on all workloads; db-sync and db-purge were missing pod-level SecurityContext -- added - AutomountServiceAccountToken: false on all 5 workloads - SCC: clean anyuid -> nonroot-v2 swap - httpd.conf: User/Group apache -> watcher (WSGIDaemonProcess user=watcher evidence proves dedicated system user exists) - ApacheGID as supplemental group for RPM-shipped conf.d files - DefaultMode 0440 on all config Secrets; deduplicated triplicated config0440AccessMode vars to single package-level declaration - Removed dead WatcherUserID constant (migrated to serviceuser.WatcherUID) - Removed local GetLogVolume/GetLogVolumeMount wrapper functions, replaced all call sites with direct volume.WritableDirVolume/ WritableDirVolumeMount calls - Replaced local GetRunHttpdVolume/Mount, GetVarLogHttpdVolume/Mount, GetConfigSecretVolumes with lib-common volume helpers - Fix watcher-api probe assignment: startup probe was on the log sidecar (tail -F) instead of the httpd container, and the log sidecar had HTTP probes testing httpd's port instead of its own process. Moved startup probe to httpd, removed all probes from log sidecar. - Fix db-sync: removed GetVolumeMounts/GetVolumes calls that added conflicting SubPath mounts from the shared config-data volume into /etc/watcher/watcher.conf.d/ (directory doesn't exist in image); db-sync uses its own db-sync-config-data volume with whole-directory mount instead - Fix db-purge: run watcher-db-manage purge directly instead of via shell script; removed dbpurge.sh template, scripts secret, and script volume/mount; purge age passed as CLI arg - Also fixes: TLS cert/key and memcached mTLS staging-path bugs; missing /run/httpd and /var/log/httpd emptyDirs - Update functional and kuttl tests Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/horizon-operator
that referenced
this pull request
Aug 7, 2026
Replaces the kolla_start/kolla_set_configs/config.json staging pattern with direct volume mounts to final config paths and direct service commands, and hardens the pod's SecurityContext. SecurityContext: horizon's kolla-era httpd/horizon worker processes always ran as apache (confirmed via `ps -ef` on a running kolla pod), never under a dedicated per-service system user the way keystone/manila do -- openstack-dashboard's RPM has never shipped its own user. Rather than migrate to serviceuser.HorizonUID like every other operator (which would silently break read/write access to any ExtraMount-backed content still owned apache:apache from before this migration), the pod keeps apache (serviceuser.ApacheUID) as its RunAsUser, with serviceuser.HorizonGID as RunAsGroup and FSGroup so the process has group-level access to any horizon-owned files. No supplemental groups are needed: apache-owned files are accessible via UID match (owner bits), and horizon-owned files are accessible via the primary GID. RBAC is additive (hostmount-anyuid;nonroot-v2), since horizon's documented custom-theme ExtraMount mechanism can plausibly need NFS. Custom theme mechanism: preserved via a non-root "theme-setup" init container that seeds a writable EmptyDir with the image's own baked-in themes plus any user-supplied *.tar.gz theme (via theme_setup, renamed from kolla_theme_setup since it was never actually an image-baked kolla script -- it's always lived in this repo). .horizon-secret: re-materialized via a dedicated "secret-setup" init container into a pod-owned EmptyDir with real 0600 permissions, since Kubernetes always mounts Secret-backed files root-owned with at least group-read forced on, which horizon's own secret_key.read_from_file() rejects as insecure. Writes through a whole-directory mount (no SubPath) so the file exists as a real file before any later container references it via a SubPath mount of the same path -- a SubPath mount of a not-yet-existing path is otherwise auto-created by kubelet as a directory, permanently. kolla_extend_start logic: brought in-repo as templates/horizon/bin/dashboard_setup (a trimmed adaptation, not a runtime dependency on the image continuing to ship the original script), run by a "dashboard-setup" init container after theme-setup and secret-setup. Handles per-service dashboard panel enabling (Designate/Heat/Ironic/Manila/Octavia/Watcher/CloudKitty) and settings-changed-detection driving "manage.py collectstatic"/ "compress". Removed the dead heat_policy.json copy from config_heat_dashboard -- the image now ships heat_policy.yaml directly via RPM into /etc/openstack-dashboard/, so the script's .json reference was a no-op. Changed cp -a to cp -r in config_dashboard since ownership preservation silently fails as non-root. Horizon has a unique 3-init-container pipeline: theme-setup seeds themes, secret-setup re-materializes the secret key with correct 0600 permissions, and dashboard-setup enables dashboard panels and regenerates static assets. All three must run in order. Other key changes: - run-httpd mount path: /etc/httpd/run -> /run/httpd (canonical) - Config volume DefaultMode: 0640 -> 0440 - EmptyDir volumes: adopted lib-common volume.WritableDirVolume() helpers with standardized constants - Fix TLS/mTLS staging-path bugs (final paths expected by httpd.conf but not supplied by lib-common's default helpers) - Fix missing top-level httpd ErrorLog directive - Fix STATIC_ROOT in local_settings.py (was unset, causing collectstatic to write to Django's package-relative default) - AutomountServiceAccountToken: false - Update functional and kuttl tests Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/designate-operator
that referenced
this pull request
Aug 10, 2026
Eliminate kolla_start/kolla_set_configs and the config.json staging
pattern from ALL Designate services, including designate-backend-bind9.
The crudini-based config-merge init container (parent + child config
secrets merged into a config-data-merged emptyDir) is kept exactly
as-is -- only kolla's staging-to-final copy step is replaced with
SubPath mounts of the same emptyDir at final paths.
Key changes:
- Replace kolla_start with the real per-service command
(designate-central/-worker/-producer/-mdns --config-file ...
--config-dir ...; /usr/sbin/httpd -DFOREGROUND for designate-api;
/usr/sbin/named -g -d 3 -u named -c /etc/named.conf -f for bind9)
- designate-producer and designate-mdns previously had no explicit
Command at all -- they silently relied on the image's kolla-based
default ENTRYPOINT; both needed a Command added, not just replaced
- db-sync: exec bootstrap.sh directly instead of through kolla_start
- Mount designate.conf/custom.conf/my.cnf via SubPath from the merged
emptyDir to their final paths; designate-api additionally mounts
httpd.conf/ssl.conf the same way, plus new run-httpd/var-log-httpd
emptyDirs
- designate-backend-bind9: replace kolla_start with explicit named
command and args; mount merged named.conf and named/ directory via
SubPath at /etc/named.conf and /etc/named; add emptyDir for
/run/named; pod-level FSGroup: serviceuser.NamedGID (25) makes all
volumes accessible to the named user after BIND drops privileges
(-u named); main container gets explicit RunAsUser: 0 +
RunAsNonRoot: false since named must start as root to bind port 53
- Add GetConfigOverwriteVolumeMounts() to mount DefaultConfigOverwrite
keys (e.g. policy.yaml) individually, since they are not
unconditionally present
- Remove all KOLLA_CONFIG_STRATEGY env vars and delete the 7 now
unreferenced *-config.json templates (api, central, worker, producer,
mdns, db-sync, bind9)
- Use pod.RestrictiveSecurityContext/RestrictivePodSecurityContext from
lib-common (serviceuser.DesignateUID) on all 5 non-bind9 services
plus the pool_update.go Jobs (PoolUpdateJob, PoolListJob)
- Init containers (SimpleInitContainer, InitContainer) changed from
RunAsUser: 0 to RestrictiveSecurityContext(DesignateUID) -- init.sh
only does cp/crudini into an emptyDir, no root needed
- SimpleInitContainer accepts optional SecurityContext override via
InitContainerDetails for callers that need root (bind9)
- init.sh: remove cp of /etc/designate/designate.conf from the image;
merge_config_dir handles it via its cp-on-first-encounter path
- common.sh: chmod 0660 after cp to make merged config files
group-writable -- needed because Secret volumes have DefaultMode
0440, and predictableips (running as root without DAC_OVERRIDE)
needs group write access for crudini --set
- init.sh / backendbind9 init.sh: rm -rf merged dir at startup for
crash+restart idempotency -- EmptyDir retains partial state across
init container restarts
- Fix the TLS cert staging-path bug on designate-api: the per-endpoint
TLS loop had no CertMount/KeyMount override, so certs landed at
lib-common's default staging path while the rendered httpd.conf's
SSLCertificateFile/SSLCertificateKeyFile already pointed at
/etc/pki/tls/{certs,private}/<endpt>.{crt,key}
- httpd.conf: User/Group apache -> designate
- RBAC: add nonroot-v2 additively (anyuid;privileged;nonroot-v2) in
both the kubebuilder marker and the runtime rbacRules slice
- DefaultMode 0440 for all config/secret volume mounts
(ProcessVolumes modeMap, backendbind9 volumes, worker projected vol,
pool_update PoolUpdateJob/PoolListJob config volumes)
- AutomountServiceAccountToken: ptr.To(false) added to all workloads
(api, central, mdns, producer, worker, unbound, backendbind9,
db-sync job, pool-update/pool-list jobs)
- designate-unbound SecurityContext hardened: added pod-level
RestrictivePodSecurityContext(DesignateUID) with per-container
RunAsUser: 0 + RunAsNonRoot: false override (ironic dnsmasq pattern)
-- unbound must start as root to bind port 53
- backendbind9 inline emptyDir volumes replaced with lib-common
volume.WritableDirVolume() helpers
- Update functional and kuttl tests
The predictableips init container keeps root + NET_ADMIN/CHOWN for
multus network interface setup (netlink address add) and crudini
config ownership preservation.
designate-backend-bind9 and designate-unbound run as root
(RunAsUser: 0): both self-drop privileges after binding port 53.
backendbind9 uses FSGroup: NamedGID so BIND can read config and
write to runtime/persistent volumes after dropping to the named user.
Jira: OSPRH-33504
Jira: OSPRH-33503
Depends-On: openstack-k8s-operators/lib-common#728
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/barbican-operator
that referenced
this pull request
Aug 10, 2026
Removes kolla_start/kolla_set_configs/config.json staging across all five Barbican workloads (API, worker, keystone-listener, db-sync, pkcs11-prep), replacing it with direct volume mounts at final config paths and hardcoded service commands. Key changes: - Replace kolla_start with /usr/sbin/httpd -DFOREGROUND (API), barbican-worker (worker), barbican-keystone-listener (listener), barbican-manage db upgrade (dbsync) - Remove all kolla_set_configs, KOLLA_CONFIG_STRATEGY, KOLLA_BOOTSTRAP env vars and the kolla_extend_start script - Delete all config.json templates (barbican-api-config.json, barbican-dbsync-config.json, barbican-worker-config.json, barbican-keystone-listener-config.json, barbican-pkcs11-prep-config.json) and launcher scripts (barbican-worker, barbican-keystone-listener) - Remove PKCS11ClientDataPath from template parameters (no longer needed without kolla config.json staging) - Mount configs via SubPath to /etc/barbican/, /etc/httpd/, /etc/my.cnf, /var/www/cgi-bin/barbican/main - Add emptyDir volumes for writable paths (/run/httpd, /var/log/httpd, /var/log/barbican) using lib-common volume.WritableDirVolume/Mount helpers with standardized constants (volume.RunHttpdVolumeName, volume.VarLogHttpdVolumeName, etc.) - Use pod.RestrictiveSecurityContext and RestrictivePodSecurityContext from lib-common for all workloads, setting ReadOnlyRootFilesystem, dropping ALL capabilities, and enabling seccomp RuntimeDefault - Set AutomountServiceAccountToken=false on all workloads -- none need k8s API access (ServiceAccountName is kept for SCC binding) - Import BarbicanUID from lib-common modules/serviceuser - Config Secret DefaultMode set to 0440 (owner-read + group-read, most restrictive -- all SubPath mounts are ReadOnly: true) - Override TLS CertMount/KeyMount to /etc/pki/tls/ for Apache - Grant nonroot-v2 SCC alongside anyuid in both the +kubebuilder:rbac marker and the hardcoded rbacRules slice passed to ReconcileRbac() (the RBAC lives in two places -- the marker feeds the operator's ClusterRole, while rbacRules creates the runtime Role/RoleBinding for the workload ServiceAccount; both must be updated) - Update httpd.conf: User/Group barbican - Support custom config overwrite keys via dynamic SubPath mounts into /etc/barbican/ with backwards-compatible directory mount at /etc/barbican/barbican.conf.d/ - Update functional and kuttl tests Found and fixed two real staging-vs-final path bugs that only kolla's copy step was masking: BarbicanAPI's per-endpoint TLS cert/key were falling back to lib-common's default staging mount instead of the path 10-barbican_wsgi_main.conf actually expects, and HSM/PKCS11 client data was mounted at an internal staging constant instead of the user-configured ClientDataPath the vendor library reads from. Note: the PKCS11 prep Job still runs as root (RunAsUser: 0) because the vendor HSM client library setup performed by generate_pkcs11_keys.sh is not verified to work under a non-root UID without real HSM hardware. The anyuid SCC grant is legitimate for this workload and cannot be dropped while the pkcs11-prep Job shares a ServiceAccount with the other Barbican services. Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/cinder-operator
that referenced
this pull request
Aug 10, 2026
Eliminate kolla_start/kolla_set_configs and the config.json staging pattern across all 4 cinder workloads (api, scheduler, volume, backup). Configs are now mounted directly to final paths via SubPath volume mounts, removing the need for root privilege escalation at container startup. Cinder's Pattern A conf.d-overlay config mechanism (parent Cinder CR renders global config, each child merges its own snippets into cinder.conf.d) is native to cinder/oslo.config and untouched by this change. Key changes: - Replace kolla_start with direct commands per workload (httpd -DFOREGROUND, cinder-scheduler/-volume/-backup --config-dir) - Remove all KOLLA_CONFIG_STRATEGY env vars and the 5 kolla config.json templates - Mount configs via SubPath to /etc/cinder/, /etc/httpd/, /etc/my.cnf - Mount ssl.conf from lib-common CommonTemplates at /etc/httpd/conf.d/ssl.conf to override the RPM-shipped default (which references the non-existent localhost.crt) - Replace kolla's run-on-host shim copy (multipath/iscsi/lvm tooling for cinder-volume/backup) with SubPath mounts of the existing scripts secret at each host-binary destination path - Use pod.RestrictiveSecurityContext and RestrictivePodSecurityContext from lib-common for cinder-api/scheduler and both probe sidecars; cinder-volume/backup keep Privileged: true (genuine LVM/iSCSI/ multipath device access need) but now pin RunAsUser/RunAsGroup/ RunAsNonRoot instead of defaulting to root - Set AutomountServiceAccountToken=false on all workloads - Import CinderUID from lib-common modules/serviceuser, drop the now-unused local CinderUserID/CinderGroupID constants - Override TLS CertMount/KeyMount to /etc/pki/tls/ for cinder-api - Migrate SCC rbacRules from [anyuid, privileged] to [privileged, nonroot-v2] — anyuid is no longer needed anywhere in this repo - Harden the db-sync/online-data-migrations Job (previously RunAsUser: 0) and db-purge CronJob to the same restrictive context - Standardize all config-data secret DefaultMode to 0440 (owner-read + group-read) across every volume definition - Adopt lib-common volume.WritableDirVolume/WritableDirVolumeMount helpers for all emptyDir volumes (tmp, run-httpd, logs), replacing inline EmptyDir constructions with standardized constants - Update httpd.conf: User/Group cinder, PidFile /run/httpd/httpd.pid, ErrorLog to stderr - Update functional and kuttl tests Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/glance-operator
that referenced
this pull request
Aug 10, 2026
Eliminate kolla_start/kolla_set_configs and the config.json staging pattern for GlanceAPI, db-sync, and all CronJobs. Configs are now mounted directly to final paths via SubPath volume mounts. Key changes: - Replace kolla_start with direct exec commands (httpd -DFOREGROUND, glance-api via dumb-init wrapper, tail log sidecar) - Inline kolla_extend_start's worker_self_reference_url logic into the container command as a shell snippet (workerSelfReferenceScript), needed for distributed image import when GLANCE_DOMAIN is set - Replace kolla config.json copy pattern with SubPath mounts for glance.conf.d snippets (00/02/03-config.conf), my.cnf, httpd.conf, wsgi/proxypass vhost configs, and ssl.conf - Add writable EmptyDir volume (ConfigDirVolume) at /etc/glance/glance.conf.d/ so the entrypoint can write runtime config (e.g. worker_self_reference_url). SubPath mounts cause the kubelet to create the parent directory as root:root 0755, which is not writable by the non-root glance user; the EmptyDir provides a writable directory with FSGroup-based group ownership, and the read-only SubPath config file mounts overlay on top. - Mount run-on-host nsenter shims via per-binary SubPath VolumeMounts (runOnHostVolumeMount) instead of kolla config_files copy directives - Delete all config.json templates, kolla_extend_start script, and kolla-era security context helpers (BaseSecurityContext, HttpdSecurityContext, APISecurityContext, dbSyncSecurityContext) - Use lib-common pod.RestrictivePodSecurityContext / RestrictiveSecurityContext and pod.PrivilegedSecurityContext (Cinder backend) with serviceuser.GlanceUID across all workloads (StatefulSet, db-sync Job, db-purge CronJob, image-cache cleaner/pruner CronJobs) - Add AutomountServiceAccountToken: false to all pod specs - SCC requirement lowered from anyuid to nonroot-v2 (privileged retained for Cinder backends) - Image-cache CronJobs no longer force privileged mode; node colocation handled by pod affinity (ColocateWithPod) - Config Secret DefaultMode standardized to 0440 (owner-read + group-read) across all workloads via package-level configMode var - Writable emptyDir paths use lib-common volume.WritableDirVolume / WritableDirVolumeMount helpers with standardized constants (volume.RunHttpdVolumeName, volume.RunHttpdMountPath) - Replace inline GetConfigSecretVolumes with lib-common volume.ConfigSecretVolumes helper - Remove dead constants (GlanceUID, GlanceGID, GlanceDBSyncCommand, HttpdRunVolume) and unused volume helper functions (GetEphemeralVolume, GetLogVolumeMount, GetHttpdRunVolumeMount, GetConfigSecretVolumes) - httpd.conf: run as glance user (not apache), PidFile in /run/httpd, ErrorLog to /dev/stderr - Update troubleshooting docs and hack script for kolla-free workflow - Update kuttl and functional test assertions for new volume counts, DefaultMode values, and container commands Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/heat-operator
that referenced
this pull request
Aug 10, 2026
Eliminate kolla_start and the config.json staging pattern for
heat-api, heat-cfnapi, and heat-engine. Pattern A (conf.d overlay):
the child config secret is already mounted at its final path
(/etc/heat/heat.conf.d), so removing kolla is mostly deleting the
staging mount and config.json rather than restructuring a merge
pipeline. db-sync and db-purge already bypassed kolla before this
change and are only lightly upgraded for SecurityContext consistency.
Key changes:
- Replace kolla_start with the real per-service command
(/usr/sbin/httpd -DFOREGROUND for heat-api/heat-cfnapi;
/usr/bin/heat-engine --config-dir /etc/heat/heat.conf.d for
heat-engine)
- Remove the kolla config.json SubPath mount and the
/var/lib/config-data/default whole-directory mount from
GetVolumeMounts; add heat-api/heat-cfnapi-specific SubPath mounts for
httpd.conf and ssl.conf, plus a new run-httpd emptyDir at
/run/httpd (PidFile was undefined in httpd.conf, with no writable
path once non-root)
- Remove all KOLLA_CONFIG_STRATEGY env vars and delete the 3 now
unreferenced *-config.json templates (api, cfnapi, engine)
- Use pod.RestrictiveSecurityContext/RestrictivePodSecurityContext from
lib-common (serviceuser.HeatUID) on heat-api, heat-cfnapi,
heat-engine, db-sync, and db-purge; delete the now-fully-unreferenced
GetHeatSecurityContext/GetHeatDBSecurityContext helpers
- Fix the TLS cert staging-path bug on heat-api/heat-cfnapi: the
per-endpoint TLS loop had no CertMount/KeyMount override, so certs
landed at lib-common's default staging path while the rendered
httpd.conf's SSLCertificateFile/SSLCertificateKeyFile already pointed
at /etc/pki/tls/{certs,private}/<endpt>.{crt,key}
- Fix the memcached mTLS staging-path bug on all three services
(heat-api, heat-cfnapi, heat-engine): CreateMTLSVolumeMounts(nil,
nil) defaults to lib-common's staging directory, while the rendered
00-default.conf's memcache_tls_certfile/tls_certfile etc. already
read from the final /etc/pki/tls/certs path
- Fix missing DefaultMode on the parent config-data secret volume:
GetVolumes set DefaultMode on config-data-custom but not on the
parent config-data volume, leaving it at the Kubernetes default 0644
instead of the intended restrictive mode
- Tighten all DefaultMode values from 0644 to 0440 (owner+group read,
no write, no world access) across config-data-custom, config-data,
db-purge-config-data, and config secret volumes; replace the local
GetConfigSecretVolumes with volume.ConfigSecretVolumes from
lib-common which also uses 0440
- Set AutomountServiceAccountToken: false on all workloads (heat-api,
heat-cfnapi, heat-engine deployments; db-sync job; db-purge cronjob)
to prevent unnecessary SA token projection
- Adopt lib-common volume helpers: replace inline emptyDir
constructions with volume.WritableDirVolume/WritableDirVolumeMount
using volume.RunHttpdVolumeName/RunHttpdMountPath constants
- httpd.conf: User/Group apache -> heat
- RBAC: clean anyuid -> nonroot-v2 swap in both the kubebuilder marker
and the runtime rbacRules slice -- confirmed nothing in this repo
needs elevated privilege or extra capabilities anywhere
- Update functional and kuttl tests
The memcached mTLS bug was almost missed: an initial pass concluded no
fix was needed here, reasoning by analogy that it would be as
vestigial as a similar-looking case found elsewhere in this effort.
Re-verifying directly against lib-common's memcached_funcs.go source
before trusting that conclusion showed it was wrong -- the staging and
final paths genuinely differ here, and heat has the exact same bug
class already found and fixed on keystone, cinder, and nova.
Jira: OSPRH-33504
Jira: OSPRH-33503
Depends-On: openstack-k8s-operators/lib-common#728
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/horizon-operator
that referenced
this pull request
Aug 10, 2026
Replaces the kolla_start/kolla_set_configs/config.json staging pattern with direct volume mounts to final config paths and direct service commands, and hardens the pod's SecurityContext. SecurityContext: horizon's kolla-era httpd/horizon worker processes always ran as apache (confirmed via `ps -ef` on a running kolla pod), never under a dedicated per-service system user the way keystone/manila do -- openstack-dashboard's RPM has never shipped its own user. Rather than migrate to serviceuser.HorizonUID like every other operator (which would silently break read/write access to any ExtraMount-backed content still owned apache:apache from before this migration), the pod keeps apache (serviceuser.ApacheUID) as its RunAsUser, with serviceuser.HorizonGID as RunAsGroup and FSGroup so the process has group-level access to any horizon-owned files. No supplemental groups are needed: apache-owned files are accessible via UID match (owner bits), and horizon-owned files are accessible via the primary GID. RBAC is additive (hostmount-anyuid;nonroot-v2), since horizon's documented custom-theme ExtraMount mechanism can plausibly need NFS. Custom theme mechanism: preserved via a non-root "theme-setup" init container that seeds a writable EmptyDir with the image's own baked-in themes plus any user-supplied *.tar.gz theme (via theme_setup, renamed from kolla_theme_setup since it was never actually an image-baked kolla script -- it's always lived in this repo). .horizon-secret: re-materialized via a dedicated "secret-setup" init container into a pod-owned EmptyDir with real 0600 permissions, since Kubernetes always mounts Secret-backed files root-owned with at least group-read forced on, which horizon's own secret_key.read_from_file() rejects as insecure. Writes through a whole-directory mount (no SubPath) so the file exists as a real file before any later container references it via a SubPath mount of the same path -- a SubPath mount of a not-yet-existing path is otherwise auto-created by kubelet as a directory, permanently. kolla_extend_start logic: brought in-repo as templates/horizon/bin/dashboard_setup (a trimmed adaptation, not a runtime dependency on the image continuing to ship the original script), run by a "dashboard-setup" init container after theme-setup and secret-setup. Handles per-service dashboard panel enabling (Designate/Heat/Ironic/Manila/Octavia/Watcher/CloudKitty) and settings-changed-detection driving "manage.py collectstatic"/ "compress". Removed the dead heat_policy.json copy from config_heat_dashboard -- the image now ships heat_policy.yaml directly via RPM into /etc/openstack-dashboard/, so the script's .json reference was a no-op. Changed cp -a to cp -r in config_dashboard since ownership preservation silently fails as non-root. Horizon has a unique 3-init-container pipeline: theme-setup seeds themes, secret-setup re-materializes the secret key with correct 0600 permissions, and dashboard-setup enables dashboard panels and regenerates static assets. All three must run in order. Other key changes: - run-httpd mount path: /etc/httpd/run -> /run/httpd (canonical) - Config volume DefaultMode: 0640 -> 0440 - EmptyDir volumes: adopted lib-common volume.WritableDirVolume() helpers with standardized constants - Fix TLS/mTLS staging-path bugs (final paths expected by httpd.conf but not supplied by lib-common's default helpers) - Fix missing top-level httpd ErrorLog directive - Fix STATIC_ROOT in local_settings.py (was unset, causing collectstatic to write to Django's package-relative default) - AutomountServiceAccountToken: false - Update functional and kuttl tests Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/ironic-operator
that referenced
this pull request
Aug 10, 2026
Replaces the kolla_start/kolla_set_configs/config.json staging pattern with direct volume mounts to final config paths and direct service commands, across ironic-api, ironic-conductor, ironic-inspector, ironic-neutron-agent, and both db-sync jobs. RBAC: IronicAPI/Conductor/Inspector/NeutronAgent share one ServiceAccount/Role when owned by the parent Ironic CR, so they cannot get independently different SCC grants. The shared Role grants anyuid;privileged;nonroot-v2 -- conductor/inspector genuinely need anyuid+privileged for PXE chroot (SYS_CHROOT/SETFCAP) and DHCP/TFTP sub-1024-port binding (NET_ADMIN/NET_RAW), while nonroot-v2 is included to match every other operator in the effort. Mixed-privilege pods (conductor, inspector) carry a pod-level RestrictivePodSecurityContext for their non-root siblings, with dnsmasq and pxe-init explicitly overriding RunAsUser/RunAsNonRoot back to root on their own container SecurityContext. Both dnsmasq and pxe-init Drop ALL capabilities first, then add back only the specific caps they need (NET_ADMIN/NET_RAW for dnsmasq, SYS_CHROOT/SETFCAP for pxe-init). AutomountServiceAccountToken set to false on all workloads including conductor -- get_net_ip reads network status from the DownwardAPI volume (/etc/podinfo/network-status), not from the k8s API. Writable paths: - run-httpd emptyDir added to conductor (was missing entirely) and mount added to both conductor's and inspector's httpboot containers -- httpd cannot write its PID file without writable /run/httpd - Adopts lib-common volume.WritableDirVolume/WritableDirVolumeMount helpers with constants for run-httpd, string literals for ironic-specific volumes (var-lib-ironic, logs, etc.) Config secret DefaultMode tightened from 0640 to 0440. Also fixes: the standard TLS cert/key staging-path bug on ironic-api's and ironic-inspector's httpd; httpd.conf User/Group changed from apache to ironic on ironic-api specifically, matching its pre-existing WSGIDaemonProcess user=ironic evidence, while ironic-inspector's proxy httpd and both httpboot instances keep apache (no such evidence). Config delivery uses three variants of the EmptyDir-seed pattern: plain final-path Secret SubPath mounts, a single merged file written by the init container's crudini-merge step (03-init-container-conductor.conf), and a dynamically pxe-init-generated dnsmasq.conf -- all safe because the writer runs in an earlier container through a whole-directory mount. dbsync.sh had only its one kolla-specific line (sudo -E kolla_set_configs) removed. Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/keystone-operator
that referenced
this pull request
Aug 10, 2026
Eliminate kolla_start/kolla_set_configs and the config.json staging
pattern. Configs are now mounted directly to final paths via SubPath
volume mounts, removing the need for root privilege escalation at
container startup.
Key changes:
- Replace kolla_start with /usr/sbin/httpd -DFOREGROUND
- Remove kolla_set_configs from bootstrap command
- Remove all KOLLA_CONFIG_STRATEGY and KOLLA_BOOTSTRAP env vars
- Delete keystone-api-config.json (no longer needed)
- Mount configs via SubPath to /etc/keystone/, /etc/httpd/, /etc/my.cnf
- Add emptyDir volumes for writable paths (/run/httpd, /tmp, /var/log)
using lib-common volume.WritableDirVolume/Mount helpers with
standardized constants (volume.RunHttpdVolumeName, TmpVolumeName, etc.)
- Use pod.RestrictiveSecurityContext and RestrictivePodSecurityContext
from lib-common for all workloads (deployment, bootstrap, dbsync,
cronjob), setting ReadOnlyRootFilesystem, dropping ALL capabilities,
and enabling seccomp RuntimeDefault
- Set AutomountServiceAccountToken=false on all workloads — none need
k8s API access (ServiceAccountName is kept for SCC binding)
- Import KeystoneUID from lib-common modules/serviceuser
- Override TLS CertMount/KeyMount to /etc/pki/tls/ for Apache
- Migrate SCC from anyuid to nonroot-v2
- Update httpd.conf: User/Group keystone, PidFile /run/httpd/httpd.pid
- Support custom httpd config keys via dynamic SubPath mounts
- Config Secret DefaultMode set to 0440 (owner-read + group-read,
most restrictive — all SubPath mounts are ReadOnly: true anyway)
- Update functional and kuttl tests
Testing on a cluster surfaced a permission denial starting httpd:
httpd: Syntax error on line 16 of /etc/httpd/conf/httpd.conf:
Could not open configuration file /etc/httpd/conf.d/auth_openidc.conf:
Permission denied
mod_auth_openidc's auth_openidc.conf ships root:apache 0640 and is
baked into the container image rather than volume-mounted, so FSGroup
does not apply to it. Under the previous kolla/anyuid setup this was
never an issue: the httpd master process ran as root and could read
any file regardless of group. TCIB never adds the keystone service
user to the apache group (uid_gid_manage.sh only ever adds it to
"kolla"), so running the whole pod as non-root keystone requires the
apache group to be granted explicitly at the pod level via
RestrictivePodSecurityContext's new supplementalGroups parameter and
lib-common's serviceuser.ApacheGID constant.
Testing further surfaced httpd failing to start with:
(13)Permission denied: AH00091: httpd: could not open error log
file /etc/httpd/logs/error_log.
AH00015: Unable to open logs
/etc/httpd/logs is a symlink to /var/log/httpd (root:root 0700 in the
image). httpd.conf only redirected ErrorLog/CustomLog to /dev/stdout
inside <VirtualHost> blocks, so the global/startup error log fell back
to Apache's compiled-in default of "logs/error_log" relative to
ServerRoot. Fixed by adding a top-level ErrorLog directive, plus a
var-log-httpd emptyDir mounted at /var/log/httpd as defense-in-depth
for any other RPM-shipped conf.d file that references relative
"logs/*" paths.
ErrorLog (both the top-level and per-vhost directives) is sent to
/dev/stderr rather than /dev/stdout, following the convention used by
the official Apache httpd container image and OpenShift Logging's
per-stream labeling, keeping error diagnostics distinguishable from
routine access logs (CustomLog stays on /dev/stdout).
Testing also surfaced a keystone WARNING:
keystone.common.fernet_utils [...] key_repository is world readable:
/etc/keystone/fernet-keys
The fernet-keys and credential-keys Secret volumes had no DefaultMode
set, so Kubernetes defaulted to 0644 (world-readable), unlike
config-data which was already hardened to 0440. Fixed by setting
DefaultMode 0440 on both, matching config-data and silencing the
warning.
Jira: OSPRH-33504
Jira: OSPRH-33503
Depends-On: openstack-k8s-operators/lib-common#728
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/manila-operator
that referenced
this pull request
Aug 10, 2026
Remove kolla_start / kolla config.json / KOLLA_CONFIG_STRATEGY from all
manila workloads (API, scheduler, share, dbsync job, cronjob). Each
service binary is now launched directly:
- manila-api: /usr/sbin/httpd -DFOREGROUND
- manila-scheduler: /usr/bin/manila-scheduler --config-dir ...
- manila-share: /usr/bin/manila-share --config-dir ...
Config files (httpd.conf, 10-manila_wsgi.conf) are mounted directly via
SubPath from the config-data secret instead of being copied by kolla at
startup. The deleted kolla config.json templates and the ssl.conf common
template reference are no longer needed.
Harden the security posture:
- Replace inline SecurityContext with pod.RestrictivePodSecurityContext
and pod.RestrictiveSecurityContext from lib-common (using
serviceuser.ManilaUID / serviceuser.ApacheGID).
- Add AutomountServiceAccountToken: ptr.To(false) to all workload
PodSpecs (API statefulset, scheduler statefulset, share statefulset,
dbsync job, db-purge cronjob).
- Change secret DefaultMode from 0644/0640 to 0440 across all volume
definitions using a package-level configMode variable.
- Switch SCC requirement from anyuid to hostmount-anyuid + nonroot-v2.
Adopt lib-common volume helpers:
- Replace inline emptyDir volumes/mounts for run-httpd, var-log-httpd,
and logs with volume.WritableDirVolume / volume.WritableDirVolumeMount
from lib-common/modules/common/volume.
- Remove GetConfigSecretVolumes (replaced by volume.ConfigSecretVolumes
in lib-common).
- Fix run-httpd mount path from /etc/httpd/run to the canonical
/run/httpd (matching lib-common's volume.RunHttpdMountPath constant).
Update httpd.conf to run as manila:manila (not apache:apache) since
containers no longer start as root.
Remove ManilaUserID / ManilaGroupID constants (replaced by
serviceuser.ManilaUID from lib-common).
Update MTLS volume mounts to use explicit cert/key mount paths instead
of nil (matching the infra-operator API change).
Update kuttl and functional tests to match the new volume counts,
mount paths, commands, and security context.
Jira: OSPRH-33504
Jira: OSPRH-33503
Depends-On: openstack-k8s-operators/lib-common#728
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/neutron-operator
that referenced
this pull request
Aug 10, 2026
Eliminate kolla_start and the config.json staging pattern across all neutron-operator workloads (neutron-api, neutron-httpd, db-sync). Configs are now mounted directly to final paths via SubPath volume mounts. neutron-operator already uses Pattern B (two self-contained Secrets: one for neutron-api/db-sync, one for neutron-httpd), like keystone/placement/glance — no conf.d-merge logic to reproduce. This repo already tried and reverted a kolla-removal attempt in 2023 (7a750f1, reverted by 62a2f29). That attempt replaced kolla with a custom init-container needing sudo, which forced AllowPrivilegeEscalation: true and blocked dropping ALL capabilities — a worse security posture than kolla itself. This migration does not repeat that mistake: all config rendering happens server-side in the Go controller, Secrets are mounted read-only via SubPath, and no runtime script/sudo is involved anywhere, the same proven approach already used for keystone/placement/cinder/glance. Key changes: - Replace kolla_start with direct commands per container/job (neutron-server, httpd -DFOREGROUND, neutron-db-manage) taken straight from each removed config.json's "command" field; the db-sync Job previously had no explicit Command/Args at all, relying on the image's default entrypoint — now explicit like every other workload - Remove KOLLA_CONFIG_STRATEGY env var and the 3 kolla config.json templates - Mount config-data keys via SubPath directly to /etc/neutron/neutron.conf.d/*.conf, /etc/httpd/conf(.d)/*, /etc/my.cnf; policy.yaml is mounted conditionally, only when set via spec.defaultConfigOverwrite (an unconditional mount would break any NeutronAPI that doesn't set it, since the secret key wouldn't exist) - BUG FIX: Add DefaultMode 0440 to both the "config" and "httpd-config" Secret volumes. Neither had a DefaultMode set, meaning k8s defaulted to 0644 (world-readable). These Secrets contain DB credentials, transport URLs, and service passwords that should only be readable by the service user and group — not by every process in the container - Adopt lib-common volume helpers (volume.WritableDirVolume, volume.WritableDirVolumeMount) with named constants (volume.RunHttpdVolumeName, volume.RunHttpdMountPath) for the run-httpd emptyDir, replacing inline constructions; removes the local GetHttpdRunVolume() function - Fix memcached mTLS cert/key mounting: CreateMTLSVolumeMounts(nil, nil) mounted at the staging default path instead of where the rendered config actually references them (same bug already found and fixed in cinder-operator, keystone-operator, and glance-operator) - Fix the OVN DB TLS cert mounts: the tls.Service literal only set CaMount, hardcoded to a kolla staging path even though 01-neutron.conf's ovn_nb_ca_cert/ovn_sb_ca_cert already pointed at the final /etc/pki/tls/certs/ovndbca.crt destination; CertMount/ KeyMount were left unset entirely, so the client cert/key (ovn_{nb,sb}_certificate/private_key) defaulted to a different kolla staging path with nothing there, crashing neutron-server at ML2/OVN driver init with FileNotFoundError on ovndb.crt. Found via real-cluster testing -- no functional or kuttl test exercises Spec.TLS.Ovn at all, so this was invisible to `make test` - Use pod.RestrictiveSecurityContext/RestrictivePodSecurityContext from lib-common for all three workloads — no privileged/host-access exception needed anywhere in this repo (unlike cinder/glance) - Set AutomountServiceAccountToken=false on all workloads - Migrate SCC rbacRules from [anyuid] to [nonroot-v2] only — no privileged fallback needed anywhere in this repo, the first operator in this effort with that simpler end state - Update functional and kuttl tests Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/nova-operator
that referenced
this pull request
Aug 10, 2026
Eliminate kolla_start/kolla_set_configs and the config.json staging pattern for the placement service. Configs are now mounted directly to final paths via SubPath volume mounts, removing the need for root privilege escalation at container startup. Second operator in the remove-kolla effort, following keystone-operator. Key changes: - Delete placement-api-config.json / placement-dbsync-config.json - Mount configs via SubPath to /etc/placement/, /etc/httpd/, /etc/my.cnf - Add emptyDir volumes for writable paths (/run/httpd, /tmp, /var/log/httpd) using lib-common volume.WritableDirVolume() and volume.WritableDirVolumeMount() helpers with named constants (RunHttpdVolumeName, TmpVolumeName, VarLogHttpdVolumeName); the pre-existing /var/log/placement "logs" emptyDir (used by the oslo.log tailing sidecar) is unrelated to kolla and unchanged - Standardize config-data Secret DefaultMode to 0440 (was 0640), matching the lib-common configSecretMode convention - Replace kolla_start with /usr/sbin/httpd -DFOREGROUND (api container) and placement-manage db sync (db-sync job) - Remove KOLLA_CONFIG_STRATEGY and KOLLA_BOOTSTRAP env vars - Use pod.RestrictiveSecurityContext and RestrictivePodSecurityContext from lib-common on all 3 containers (-log, -api, -db-sync), setting ReadOnlyRootFilesystem, dropping ALL capabilities, and enabling seccomp RuntimeDefault - Set AutomountServiceAccountToken=false on both workloads - Import PlacementUID from lib-common modules/serviceuser - Override TLS CertMount/KeyMount to /etc/pki/tls/ for Apache - Migrate placement's SCC from anyuid to nonroot-v2 -- additive change in this multi-controller operator: nova and cyborg keep their own anyuid markers/rbacRules untouched, config/rbac/role.yaml gains a new nonroot-v2 rule alongside the existing anyuid one - httpd.conf: User/Group placement, PidFile /run/httpd/httpd.pid, re-enable Include conf.d/*.conf (previously disabled due to a syntax error that no longer applies once kolla's generated ssl.conf is what's actually loaded), vhost ErrorLog to stderr - policy.yaml mounted conditionally on DefaultConfigOverwrite, matching prior (narrow) kolla behavior -- no scope expansion - Adopt lib-common volume helpers (volume.WritableDirVolume, volume.WritableDirVolumeMount) for all emptyDir volumes and mounts, using constants for run-httpd, var-log-httpd, and tmp names/paths - Update functional and kuttl tests Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/octavia-operator
that referenced
this pull request
Aug 10, 2026
Eliminate kolla_start and the config.json staging pattern across all Octavia workloads. The crudini config-merge init container (Pattern C: merges parent + child config into a config-data-merged emptyDir) is kept exactly as-is -- only kolla's staging-to-final copy step is replaced with SubPath mounts of the same emptyDir at final paths. Key changes: - octavia-api: replace kolla_start with /usr/sbin/httpd -DFOREGROUND; mount httpd.conf/ssl.conf via SubPath to /etc/httpd/conf[.d]/; add run-httpd emptyDir at /etc/httpd/run (not the canonical /run/httpd because octavia's httpd.conf uses PidFile relative to ServerRoot) - octavia-driver-agent: add explicit Command (/usr/bin/octavia-driver-agent --config-file ... --config-dir ...) - octavia-worker/housekeeping/healthmanager: exec octavia_controller_start.sh <role> directly - octavia-rsyslog: exec /usr/sbin/rsyslogd -n directly; add NET_BIND_SERVICE capability for privileged port 514 binding; delete the now-redundant octavia_rsyslog_start.sh wrapper - db-sync: exec bootstrap.sh directly - All root init containers (amphora, rsyslog, image-upload): add RunAsNonRoot: false to override pod-level RunAsNonRoot: true from RestrictivePodSecurityContext; add Drop: ALL + explicit Add for needed capabilities (amphora: NET_ADMIN/NET_RAW/SYS_ADMIN/SYS_NICE, rsyslog: NET_ADMIN/NET_RAW/SYS_ADMIN/SYS_NICE) - Add GetConfigOverwriteVolumeMounts() for conditional policy.yaml - Remove all KOLLA_CONFIG_STRATEGY/KOLLA_BOOTSTRAP env vars and 7 config.json templates - Use pod.RestrictiveSecurityContext/RestrictivePodSecurityContext from lib-common (serviceuser.OctaviaUID) on all main containers - Fix TLS cert staging-path bug on octavia-api and driver-agent - httpd.conf: User/Group apache -> octavia - RBAC: add nonroot-v2 additively (anyuid;privileged;nonroot-v2) - DefaultMode 0440 across all volumes - Adopt lib-common volume.WritableDirVolume helpers - AutomountServiceAccountToken: false on all workloads - Update functional and kuttl tests The amphora-controller/rsyslog init containers keep RunAsUser:0 and elevated capabilities (NET_ADMIN/NET_RAW genuinely used for network setup; SYS_ADMIN/SYS_NICE left in place pending verification). octavia-image-upload's init container keeps RunAsUser:0 (external image entrypoint, not verifiable without real cluster). Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/watcher-operator
that referenced
this pull request
Aug 10, 2026
Replaces the kolla_start/kolla_set_configs/config.json staging pattern with direct volume mounts to final config paths and direct service commands for watcher-api, watcher-applier, watcher-decision-engine, db-sync, and db-purge. Key changes: - Replace kolla_start with direct commands per workload (httpd -DFOREGROUND, watcher-applier/decision-engine --config-dir, watcher-db-manage upgrade, watcher-db-manage purge) - Remove KOLLA_CONFIG_STRATEGY env vars and 5 config.json templates - Mount configs via SubPath to /etc/watcher/watcher.conf.d/, /etc/httpd/, /etc/my.cnf - Use pod.RestrictiveSecurityContext/RestrictivePodSecurityContext from lib-common (serviceuser.WatcherUID) on all workloads; db-sync and db-purge were missing pod-level SecurityContext -- added - AutomountServiceAccountToken: false on all 5 workloads - SCC: clean anyuid -> nonroot-v2 swap - httpd.conf: User/Group apache -> watcher (WSGIDaemonProcess user=watcher evidence proves dedicated system user exists) - ApacheGID as supplemental group for RPM-shipped conf.d files - DefaultMode 0440 on all config Secrets; deduplicated triplicated config0440AccessMode vars to single package-level declaration - Removed dead WatcherUserID constant (migrated to serviceuser.WatcherUID) - Removed local GetLogVolume/GetLogVolumeMount wrapper functions, replaced all call sites with direct volume.WritableDirVolume/ WritableDirVolumeMount calls - Replaced local GetRunHttpdVolume/Mount, GetVarLogHttpdVolume/Mount, GetConfigSecretVolumes with lib-common volume helpers - Fix watcher-api probe assignment: startup probe was on the log sidecar (tail -F) instead of the httpd container, and the log sidecar had HTTP probes testing httpd's port instead of its own process. Moved startup probe to httpd, removed all probes from log sidecar. - Fix db-sync: removed GetVolumeMounts/GetVolumes calls that added conflicting SubPath mounts from the shared config-data volume into /etc/watcher/watcher.conf.d/ (directory doesn't exist in image); db-sync uses its own db-sync-config-data volume with whole-directory mount instead - Fix db-purge: run watcher-db-manage purge directly instead of via shell script; removed dbpurge.sh template, scripts secret, and script volume/mount; purge age passed as CLI arg - Also fixes: TLS cert/key and memcached mTLS staging-path bugs; missing /run/httpd and /var/log/httpd emptyDirs - Update functional and kuttl tests Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
stuggi
added a commit
to stuggi/nova-operator
that referenced
this pull request
Aug 10, 2026
…rityContext Removes kolla_start/kolla_set_configs/config.json staging across all of nova-operator's own services (API, metadata, scheduler, novncproxy, conductor, db-sync, db-purge, in-cluster ironic-backed compute) and the three nova-manage Jobs (cell-mapping, cell-delete, host-discover), replacing it with direct volume mounts at final config paths and hardcoded service commands. Migrates SecurityContext to lib-common's pod.RestrictiveSecurityContext/RestrictivePodSecurityContext (nonroot-v2 SCC) across the board -- unlike barbican, none of these workloads need root/privileged access, so this is a clean anyuid-to-nonroot-v2 swap on nova's own RBAC marker (anyuid survives in the aggregate role only via cyborg's separate, untouched marker). The lib-common revision this pulls in also changes those two helpers to take an explicit gid parameter instead of deriving it from uid, so every nova-operator call site now passes serviceuser.NovaGID alongside serviceuser.NovaUID. Along the way, found and fixed the same class of staging-vs-final path bug already seen in keystone/cinder (memcached mTLS) and keystone/barbican (API TLS certs): every nova component talking to memcached was mounting its mTLS cert at the default staging path instead of where 01-nova.conf actually expects it, and the API/metadata/novncproxy TLS certs (plus novncproxy's Vencrypt certs, which use their own distinct /etc/pki/nova-novncproxy/ path convention) had the same gap. All fixed by passing explicit CertMount/ KeyMount overrides matching what each service's own rendered config expects. Script mount path changed from /var/lib/openstack/bin (a kolla staging path — kolla's config.json copied scripts from there to /bin/) to /usr/local/bin/container-scripts, matching the convention used by every other operator. This applies to the two remaining nova-manage Job scripts (ensure_cell_mapping.sh, delete_cell.sh); the conductor's dbsync.sh and dbpurge.sh, and the host-discover Job's host_discover.sh, are removed outright rather than relocated, since all three were simple enough to build as an inline bash -c command in Go. CellDBSyncJob composes "nova-manage api_db sync && nova-manage db sync --local_cell" directly from instance.Spec.CellName (skipping the api_db sync leg for cells other than cell0), DBPurgeCronJob computes the archive/purge cutoff dates once via time.Now().AddDate and short-circuits archive_deleted_rows/purge's known non-error exit codes (0 or 1; 0 or 3) into shell truthiness so the container only exits non-zero on a real failure, and HostDiscoveryJob hardcodes "nova-manage cell_v2 discover_hosts --by-service --verbose" directly (dropping its now-unused scriptName parameter, threaded through ensureNovaComputeDiscover, since it no longer mounts the shared nova-manage scripts Secret). With no scripts left under templates/nova/conductor, the conductor controller switches from GenerateConfigsWithScripts to GenerateConfigs so it no longer creates an empty, unused -scripts Secret; the shared nova-manage scripts Secret is unaffected since cell-mapping and cell-delete still use it. Standardizes config Secret DefaultMode from 0640 to 0440 (read-only for owner and group, matching the lib-common configSecretMode convention used by volume.ConfigSecretVolumes). Adds AutomountServiceAccountToken: false to every nova workload PodSpec (API, metadata, scheduler, conductor, novncproxy, compute, db-sync, db-purge, cell-mapping, cell-delete, and host-discover) since none of these pods need the projected SA token. Adopts lib-common volume helpers: replaces local GetRunHttpdVolume() and GetVarLogHttpdVolume() wrappers with volume.WritableDirVolume() and volume.WritableDirVolumeMount() from lib-common/modules/common/volume, and uses volume.WritableDirVolume() for the nova log emptyDir as well. Inline emptyDir volume mount constructions in API and metadata deployment files are replaced with volume.WritableDirVolumeMount() calls using lib-common's canonical RunHttpdVolumeName/VarLogHttpdVolumeName constants. Jira: OSPRH-33504 Jira: OSPRH-33503 Depends-On: openstack-k8s-operators/lib-common#728 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
Pod and container-level SecurityContext builders that enforce the hardened baseline every operator adopts after removing kolla: - RestrictivePodSecurityContext(uid, supplementalGroups...): pod-level RunAsUser/RunAsGroup/FSGroup=uid, RunAsNonRoot=true, seccomp RuntimeDefault, optional supplemental groups (e.g. ApacheGID) - RestrictiveSecurityContext(uid, addCapabilities...): container-level RunAsUser/RunAsGroup=uid, RunAsNonRoot=true, drop ALL capabilities (then add back any explicitly requested), no privilege escalation, seccomp RuntimeDefault - RestrictiveSecurityContextWithGID(uid, gid, addCapabilities...): same but allows a different RunAsGroup - PrivilegedSecurityContext(uid): for workloads needing full host device access (Ceph RBD via os-brick in glance/cinder) Jira: OSPRH-33504 Jira: OSPRH-33503 Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
Generic volume helpers for writable emptyDir paths needed by all
service operators after the kolla entrypoint removal:
- WritableDirVolume(name, sizeLimit...): creates an emptyDir Volume
- WritableDirVolumeMount(name, mountPath): creates a VolumeMount
- WritableDirSubPathMounts(name, baseDir, subdirs...): SubPath mounts
for writable subdirectories of a base path (e.g. service home dir)
- ConfigSecretVolumes(secretNames): config Secrets at
/var/lib/config-data/secret-{idx} with DefaultMode 0440
Well-known constants for standardized volume names and mount paths:
RunHttpdVolumeName/MountPath — /run/httpd (httpd PID file)
VarLogHttpdVolumeName/MountPath — /var/log/httpd (httpd log fallback)
TmpVolumeName/MountPath — /tmp
HomeDirCacheSubdir — .cache (RHEL pkg_resources cache)
Replaces the per-operator copy-pasted GetRunHttpdVolume,
GetVarLogHttpdVolume, GetLogVolume, GetConfigSecretVolumes helpers
with one generic pair + constants.
Jira: OSPRH-33504
Jira: OSPRH-33503
Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
SSLSessionCache pointed to /var/cache/mod_ssl/scache which does not exist in the container image. All httpd-fronted services now run as non-root service users and cannot create directories under /var/cache/. Move the session cache to /run/httpd/ssl_scache, which every operator already mounts as a writable emptyDir — matching SSLStaplingCache which was already at /run/httpd/ssl_stapling. Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
abays
reviewed
Aug 13, 2026
abays
reviewed
Aug 13, 2026
abays
reviewed
Aug 13, 2026
abays
reviewed
Aug 13, 2026
abays
reviewed
Aug 13, 2026
Single source of truth for all container image user identities, matching TCIB's _SUPPORTED_USERS in uid_gid_manage.sh. Go operators import constants directly (e.g. users.KeystoneUID); non-Go consumers use zz_generated_uid_gid.yaml (regenerated by make generate-uids-gids). Includes all 43 users from TCIB: - OpenStack services: aodh, barbican, ceilometer, cinder, cloudkitty, cyborg, designate, glance, heat, horizon, ironic, ironic-inspector, keystone, manila, neutron, nova, octavia, placement, swift, watcher - Infrastructure: memcached, mysql, rabbitmq, redis, valkey, haproxy - System/auxiliary: apache (48), qemu (107), tss (59), ansible (227), named (25), kolla, libvirt, nfast, openvswitch, hugetlbfs - Networking: frr, frrvty, ovn-bgp - Testing: horizontest, rally, tempest, tobiko - Admin: cloud-admin Every service account with a home directory is also a member of the kolla group (matching the s2i-openstack-containers uid_gid_manage registry), plus: barbican->nfast, nova->qemu/libvirt/tss, frr->frrvty, keystone->apache. Home directories match TCIB (memcached->/run/memcache, redis->/run/redis, etc.). valkey (42460) intentionally shares redis's UID (drop-in replacement). The module is named "users" rather than "serviceuser" since it also covers non-OpenStack system accounts (apache, qemu, named, ...). make verify-uids-gids is wired into pre-commit, gated on modules/users/registry.go, so the generated YAML can't drift from the Go source of truth. Jira: OSPRH-33504 Jira: OSPRH-33503 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Martin Schuppert <mschuppert@redhat.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add modules/users UID/GID registry
Single source of truth for all container image user identities, matching TCIB's _SUPPORTED_USERS in uid_gid_manage.sh. Go operators import constants directly (e.g. serviceuser.KeystoneUID); non-Go consumers use zz_generated_uid_gid.yaml (regenerated by make generate-uids-gids).
Includes all 42 users from TCIB:
- OpenStack services: aodh, barbican, ceilometer, cinder, cloudkitty, cyborg, designate, glance, heat, horizon, ironic, ironic-inspector, keystone, manila, neutron, nova, octavia, placement, swift, watcher
- Infrastructure: memcached, mysql, rabbitmq, redis, valkey, haproxy
- System/auxiliary: apache (48), qemu (107), tss (59), ansible (227), kolla (for now kept), libvirt, nfast, openvswitch, hugetlbfs
- Networking: frr, frrvty, ovn-bgp
- Testing: horizontest, rally, tempest, tobiko
- Admin: cloud-admin
Groups match TCIB: barbican→nfast, nova→libvirt/qemu/tss, frr→frrvty, keystone→apache. Home directories match TCIB (memcached→/run/memcache, redis→/run/redis, etc.).
valkey (42460) intentionally shares redis's UID (drop-in replacement).
Add SecurityContext helpers for kolla removal
Pod and container-level SecurityContext builders that enforce the hardened baseline every operator adopts after removing kolla:
Add modules/common/volume package
Generic volume helpers for writable emptyDir paths needed by all service operators after the kolla entrypoint removal:
Well-known constants for standardized volume names and mount paths:
Replaces the per-operator copy-pasted GetRunHttpdVolume, GetVarLogHttpdVolume, GetLogVolume, GetConfigSecretVolumes helpers with one generic pair + constants.