Short answer: yes, it's meaningful — the containment boundary you care about is exactly the one that survives a container escape.
What a dedicated user actually buys you:
-
The escapee lands with no privileges. A rootless container's root maps to your service user via subuid/subgid. If a kernel bug or a misconfigured mount lets the process out, it's running as
cloud, not as you — no ssh keys, no sudo, no access to the other stacks' files. That's the whole payoff, and it works even when podman itself has a bug. -
Kernel attack surface between users is smaller than you'd think. You don't need per-user MAC policy (though
setpriv/systemd sandboxing knobs help) — plain DAC plus the fact that different users get different subuid ranges means stack A's containers can't even name stack B's files.
On the "small stuff is annoying" side, the fixes are mostly one-time:
- Linger:
loginctl enable-linger cloudso the pod survives without a login session (or better, run quadlets as the user:systemctl --user --machine=cloud@). - Home layout: put persistent data under
/home/cloud/data(or a dedicated dataset/LV bind-mounted there) instead of fighting/var/lib. Backup jobs and disk quotas then line up with the user naturally. - Low ports:
sysctl net.ipv4.ip_unprivileged_port_start=80(ornet.ipv4.ip_unprivileged_port_start=0per-host) so nginx can bind 80/443 rootless. - Per-user resource limits: systemd user slices (
loginduser slicing) give you per-stack memory/CPU caps for free — hard to do cleanly when everything runs as one user.
Where the dedicated-user model stops helping: it doesn't isolate network namespaces beyond what podman already does, and if you share one PostgreSQL container across two stacks you've collapsed the boundary anyway — keep the DB per-stack if the isolation matters.
So: keep the per-stack users. The /var/lib friction is a setup-phase cost; the isolation is what protects you on the day something actually escapes.