Domain 2 capstone -- run a service the way it should be run
Task
Bring the Services and User Management domain together: a containerised application with persistent data, its own network, least privilege, a dedicated service account on the host, a systemd unit that manages it, and a scheduled backup. Prove each property rather than assuming it.
Steps
-
Least-privilege image. Build the app image with a non-root
USER, a pinned base tag, and dependencies installed before source is copied. Prove the container runs as a non-root user. - Data and network. Run the app and its database on a user-defined network with a named volume for the data, the database reachable by name, and the published port bound to loopback behind a reverse proxy.
-
Host account. Create a dedicated service account with
nologinand no password to own the deployment, and confirm it cannot be logged into. -
systemd management. Generate or write a systemd unit that runs the container,
enable --nowit, and prove it starts on boot -- the enable-versus-start distinction -- and restarts on failure. - Rootless. Run the whole thing rootless with Podman and explain what a container escape yields under rootless versus under a root daemon.
- Backup. Add a systemd timer that dumps the database with the application's own tool (not a tar of the live data directory) to a location the container cannot write to, and prove a restore works.
- Prove persistence. Restart the host, and confirm the service comes back and the data is intact.
- Write an evidence summary tying each property to the command that proves it.
Verify
podman inspect app --format '{{.Config.User}}' # non-root
podman exec app getent hosts db # resolves by name
getent passwd svc-app | cut -d: -f7 # nologin
systemctl is-enabled container-app # enabled
ss -tlnp | grep ':8080' # 127.0.0.1 only
# after a host reboot:
systemctl is-active container-app && \
podman exec db psql -tAc 'select count(*) from items' # running, data intact
The capstone passes when the service survives a reboot with its data, runs as a non-root user rootless, is reachable only where intended, and has a restore you have actually performed. A backup you have not restored does not count, and a unit you started but did not enable will not survive the reboot that tests it.
Notes
The domain's recurring lessons all appear here: data outside a volume is lost; enable is not start; a service account should not be able to log in; rootless turns an escape into an unprivileged user; and a backup is a hypothesis until restored. The capstone is where they stop being separate facts and become one running system.