Skip to content

Convert Podman Quadlet deployment from rootful to rootless - #19

Open
pablomh wants to merge 13 commits into
masterfrom
rootless
Open

Convert Podman Quadlet deployment from rootful to rootless#19
pablomh wants to merge 13 commits into
masterfrom
rootless

Conversation

@pablomh

@pablomh pablomh commented Mar 26, 2026

Copy link
Copy Markdown
Owner

Splits the rootless conversion into 13 focused commits. See rootless_rebase PR #12 for the full context and CI history.

pablomh and others added 13 commits March 26, 2026 22:22
Introduces a new role that creates and configures the foremanctl system
user for running Podman Quadlet services in rootless mode:
- Creates system user/group with configurable home, shell, subuid/subgid
- Configures unprivileged port binding via sysctl
- Enables systemd lingering for the user
- Creates user-scope Quadlet and systemd directories
- Updates check_subuid_subgid to use the new role variables
- Adds acl package to pre_install (required for Ansible become_user)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- deploy.yaml: add rootless_user role setup play, map XDG_RUNTIME_DIR
- vars/base.yaml: add foremanctl user/group/home/quadlet dir variables
- vars/default_certificates.yml: use foremanctl_home for cert directory
- vars/installer_certificates.yml: update cert directory to foremanctl_home
- systemd_target: run as rootless user with scope=user

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- certificates: set owner/group to foremanctl_user on all generated
  cert files and directories so they can be read by the rootless user
- checks: use systemctl --machine=foremanctl@ --user to inspect
  user-scope services; check linger and unprivileged port settings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Run the PostgreSQL Podman Quadlet as the foremanctl rootless user:
- Wrap all container operations in become_user: foremanctl block
- Use podman unshare to set container UID/GID ownership on data dir
- Add scope: user to systemd tasks and handlers
- Add container UID/GID defaults
- Slurp SSL cert/key as root before become_user block to avoid
  permission denied when creating podman secrets from /root/ paths
- Add postgresql.container.d/ssl.conf Quadlet override to mount
  SSL secrets into the container
- Add REGISTRY_AUTH_FILE to image pull

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Run the Redis Podman Quadlet as the foremanctl rootless user:
- Wrap container operations in become_user: foremanctl block
- Use podman unshare to set container UID/GID ownership on data dir
- Add scope: user to systemd tasks and handler
- Add container UID/GID and data dir defaults
- Add REGISTRY_AUTH_FILE to image pull

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Run Candlepin Podman Quadlet as the foremanctl rootless user:
- Wrap all container/secret operations in become_user: foremanctl block
- Add scope: user to systemd tasks and handler
- Move log directory creation outside become_user (runs as root)
- Add REGISTRY_AUTH_FILE to image pull
- Add candlepin-db-ca secret for external database SSL CA cert
- Mount candlepin-db-ca in the container at candlepin_database_ssl_ca_path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Run Pulp Podman Quadlets as the foremanctl rootless user:
- Wrap all container/secret operations in become_user: foremanctl block
- Use podman unshare to set container UID/GID ownership on /var/lib/pulp
- Add scope: user to systemd tasks and handlers
- Add REGISTRY_AUTH_FILE to all three image pulls (api, content, worker)
- Add pulp-db-ca secret for external database SSL CA cert, mount in all
  containers including migration and admin-password one-shot containers
- Add After=foreman.target to all Pulp service unit files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Run Foreman and Dynflow Podman Quadlets as the foremanctl rootless user:
- Wrap all container/secret operations in become_user: foremanctl block
- Add scope: user to systemd tasks and handlers
- Add foreman-db-ca secret for external database SSL CA cert; use
  foreman_database_ssl_ca_path (container path) in DATABASE_URL
- Mount foreman-db-ca in all containers (foreman, dynflow, db-migrate)
- Add After=foreman.target ordering to Foreman and Dynflow units
- Flush handlers after proxy registration so Refresh Foreman Proxy
  fires after the proxy is already registered

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Run Foreman Proxy Podman Quadlet as the foremanctl rootless user:
- Wrap all container/secret operations in become_user: foremanctl block
- Add scope: user to systemd tasks and handler
- Add Refresh Foreman Proxy handler for post-registration proxy refresh
- Move feature loops inside become_user block; create container.d dir
  in foremanctl_quadlet_dir instead of /etc/containers/systemd
- Adapt feature.yaml to use foremanctl_quadlet_dir and foremanctl
  owner/group for container.d override files
- Adapt remote_execution_ssh feature task: generate SSH key in
  foremanctl_home instead of /root
- Flush handlers after proxy registration (not before)
- Add fapolicyd workaround to CI for Ansible become_user with foremanctl

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Pass --user=foremanctl to forge test so tests check user-scope
  systemd services instead of root Podman containers
- Use systemctl --machine=foremanctl@ --user to stop foreman.target
  in the upgrade job (it is now a user-scope target)
- Add fapolicyd rule to allow Ansible become_user with foremanctl:
  Python module files placed in /var/tmp/ need to be executable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a --user pytest option so the test suite can check services in
either rootful (Podman containers) or rootless (user-scope systemd)
mode without code duplication:

- conftest.py: add GenericService abstraction that checks either podman
  containers or user-scope systemctl depending on the --user option;
  add user, user_uid, user_service and database_user_service fixtures;
  fix certificates fixture to read ca_directory from the template
- target_lifecycle_test.py: use --machine=foremanctl@ --user for
  systemctl stop/start/restart; extend timeout for external DB mode
- All service tests (foreman, candlepin, pulp, redis, postgresql,
  foreman_proxy, foreman_target): use user_service fixture to check
  services via user-scope systemd when --user=foremanctl is passed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- remote-database: add rootless_user role setup play so the database
  host also runs PostgreSQL as a rootless user
- deploy-dev: add rootless_user role setup for the development env
- docs/certificates.md: document that certificate files are now owned
  by foremanctl instead of root

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Provides a migration path for existing rootful deployments to the new
rootless Podman Quadlet setup. Handles stopping root-level services,
transferring data directory ownership, and starting the new user-scope
services.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant