Skip to content

Add User Namespaces - #977

Merged
Yarboa merged 3 commits into
containers:mainfrom
engelmi:add-userns
Jul 9, 2026
Merged

Yarboa merged 3 commits into
containers:mainfrom
engelmi:add-userns

Conversation

@engelmi

@engelmi engelmi commented Jul 1, 2026 •

Copy link
Copy Markdown
Member

This PR adds the support for running QM with User Namespaces. For this, it

  • adds a systemd sysusers configuration to set up qm-specific users on the host,
  • adds the SubUIDMap and SubGIDMap to the quadlet,
  • and creates the necessary entries in /etc/subuid and /etc/subgid during the post-install phase of the RPM install

It also removes the tz workaround since the issues to fix it are resolved:

Summary by Sourcery

Add qm-specific system users and user namespace mappings to support running QM with user namespaces, and clean up obsolete timezone workaround tooling.

Enhancements:

  • Introduce a qm-sysusers configuration defining qm-specific users and groups with fixed IDs for user namespace operation.

Build:

  • Update RPM spec to install a systemd sysusers configuration for qm-specific users and manage subuid/subgid ranges for qm_root during post-install and uninstall.
  • Adjust RPM dependencies to include shadow-utils for user management and tweak SELinux policy-related requirements.

Chores:

  • Remove the comment-tz-local script and its RPM packaging references now that the underlying timezone issues are resolved.

Summary by Sourcery

Add packaging support for QM to run with dedicated user and group namespaces managed via systemd-sysusers and subuid/subgid mappings.

New Features:

  • Define QM-specific system users and groups via a systemd sysusers configuration to back user-namespace-based execution.
  • Provision subuid and subgid ranges for the qm_root user during RPM post-install to enable user namespaces.

Enhancements:

  • Update the RPM spec to bump the package version and ensure required tools (e.g. shadow-utils) are available for user management.

@sourcery-ai

sourcery-ai Bot commented Jul 1, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds qm-specific system users and user-namespace mappings via a systemd sysusers config and RPM post scripts, wires the sysusers file into the package, and updates SELinux-related RPM dependencies while removing an obsolete selinux build requirement.

File-Level Changes

Change Details Files
Wire a systemd sysusers configuration into the RPM and ensure it is installed as part of the package.
  • Install qm-sysusers.conf into the systemd sysusers directory during buildroot installation.
  • List the sysusers file in the main RPM %files section so it is owned by the package.
rpm/qm.spec
qm-sysusers.conf
Ensure qm_root user gets appropriate user-namespace subuid/subgid ranges at install time and that they are cleaned up on uninstall.
  • Run systemd-sysusers from the %post script to create qm users before manipulating them.
  • Add usermod calls in %post to add subuid and subgid ranges for qm_root when missing.
  • Add corresponding usermod cleanup in %postun to remove the qm_root subuid/subgid ranges on package removal.
  • Declare a post-install dependency on shadow-utils to guarantee usermod availability.
rpm/qm.spec
Adjust RPM metadata for versioning and SELinux-related dependencies.
  • Bump RPM Version from 0 to 1.1.
  • Drop bluechi-selinux from BuildRequires.
  • Move selinux-policy-targeted from Recommends to a runtime Recommends, and add selinux-policy-targeted as a Recommends separate from post requirements.
rpm/qm.spec

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces systemd sysusers configuration (qm-sysusers.conf) to manage system users and groups, configures the container to run in the qm_root user namespace, and cleans up the obsolete comment-tz-local workaround. Feedback on these changes suggests explicitly running systemd-sysusers in the RPM %post scriptlet to support older RPM versions, replacing bashisms with POSIX-compliant redirection in %preun, correcting a typo in the container configuration comments, and explicitly defining GIDs for all users in the sysusers configuration to avoid ambiguity.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread rpm/qm.spec Outdated
Comment thread rpm/qm.spec Outdated
Comment thread qm.container Outdated
Comment thread qm-sysusers.conf Outdated
@engelmi
engelmi force-pushed the add-userns branch 3 times, most recently from 4f1448d to 75dd758 Compare July 2, 2026 07:20
@engelmi
engelmi marked this pull request as ready for review July 2, 2026 07:22
@engelmi

engelmi commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

After doing some builds with aib, I figured out that the tz workaround seems to be still needed - so I dropped that commit from this PR.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • The spec file comment explicitly says to keep Version at 0 for upstream and let Packit set it; bumping it to 1.1 may break that workflow and should be double-checked or reverted.
  • You added Requires(post): shadow-utils but usermod is also used in %preun; consider adding Requires(preun): shadow-utils (or a generic scriptlet dependency) to avoid uninstall failures on systems lacking it.
  • The %post script unconditionally runs systemd-sysusers; consider guarding this with a fallback (e.g. command -v systemd-sysusers >/dev/null && systemd-sysusers || :) so that a missing or failing binary doesn’t abort the entire post-install.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The spec file comment explicitly says to keep `Version` at 0 for upstream and let Packit set it; bumping it to `1.1` may break that workflow and should be double-checked or reverted.
- You added `Requires(post): shadow-utils` but `usermod` is also used in `%preun`; consider adding `Requires(preun): shadow-utils` (or a generic scriptlet dependency) to avoid uninstall failures on systems lacking it.
- The `%post` script unconditionally runs `systemd-sysusers`; consider guarding this with a fallback (e.g. `command -v systemd-sysusers >/dev/null && systemd-sysusers || :`) so that a missing or failing binary doesn’t abort the entire post-install.

## Individual Comments

### Comment 1
<location path="rpm/qm.spec" line_range="149-151" />
<code_context>
+systemd-sysusers
+# Add user namespace entries to /etc/subuid and /etc/subgid for the qm_root user
+#
+if ! grep -q "^qm_root:" /etc/subuid 2>/dev/null; then
+   usermod --add-subuids 1000000000-2500000000 qm_root
+fi
+if ! grep -q "^qm_root:" /etc/subgid 2>/dev/null; then
+   usermod --add-subgids 1000000000-2500000000 qm_root
</code_context>
<issue_to_address>
**issue (bug_risk):** Make `usermod --add-subuids/--add-subgids` failures non-fatal to avoid breaking installs.

These `%post` `usermod` calls will currently abort the RPM transaction on any failure (e.g., locked `/etc/subuid`, missing `qm_root`, concurrent edits), whereas `%postun` already treats similar failures as non-fatal with `|| :`. Please apply the same pattern here so install/upgrade doesn’t fail due to non-critical `usermod` issues:

```sh
if ! grep -q '^qm_root:' /etc/subuid 2>/dev/null; then
    usermod --add-subuids 1000000000-2500000000 qm_root || :
fi
if ! grep -q '^qm_root:' /etc/subgid 2>/dev/null; then
    usermod --add-subgids 1000000000-2500000000 qm_root || :
fi
```
</issue_to_address>

### Comment 2
<location path="rpm/qm.spec" line_range="150" />
<code_context>
+# Add user namespace entries to /etc/subuid and /etc/subgid for the qm_root user
+#
+if ! grep -q "^qm_root:" /etc/subuid 2>/dev/null; then
+   usermod --add-subuids 1000000000-2500000000 qm_root
+fi
+if ! grep -q "^qm_root:" /etc/subgid 2>/dev/null; then
</code_context>
<issue_to_address>
**issue (complexity):** Consider introducing reusable macros (and optionally a helper script) for the qm_root user and subuid/subgid range to avoid duplicated scriptlet logic and centralize these parameters.

You can reduce the duplication and make future changes less error‑prone by parameterizing the user and range, and optionally encapsulating the shell logic.

### 1. Define macros for the user and range

Near the top of the spec, define reusable macros:

```spec
%global qm_root_user    qm_root
%global qm_root_subrange 1000000000-2500000000
```

Then use them in `%post` and `%postun`:

```spec
%post
...
systemd-sysusers
# Add user namespace entries to /etc/subuid and /etc/subgid for the qm_root user
if ! grep -q "^%{qm_root_user}:" /etc/subuid 2>/dev/null; then
    usermod --add-subuids %{qm_root_subrange} %{qm_root_user}
fi
if ! grep -q "^%{qm_root_user}:" /etc/subgid 2>/dev/null; then
    usermod --add-subgids %{qm_root_subrange} %{qm_root_user}
fi
```

```spec
%postun
if [ $1 -eq 0 ]; then
    ...
    if grep -q "^%{qm_root_user}:" /etc/subuid 2>/dev/null; then
        usermod --del-subuids %{qm_root_subrange} %{qm_root_user} 2> /dev/null || :
    fi
    if grep -q "^%{qm_root_user}:" /etc/subgid 2>/dev/null; then
        usermod --del-subgids %{qm_root_subrange} %{qm_root_user} 2> /dev/null || :
    fi
fi
```

This keeps the behavior but centralizes the “qm_root + 1000000000‑2500000000” parameters.

### 2. Optional: move subuid/subgid logic into a helper script

If you want to further simplify the spec scriptlets, you can ship a tiny helper script and call it from `%post`/`%postun`:

```sh
# in, e.g., tools/qm-subids.sh (installed to %{_datadir}/qm/qm-subids.sh)
#!/bin/sh
set -eu

user=${1:-qm_root}
range=${2:-1000000000-2500000000}
action=${3:-add}  # "add" or "del"

if [ "$action" = "add" ]; then
    if ! grep -q "^${user}:" /etc/subuid 2>/dev/null; then
        usermod --add-subuids "${range}" "${user}"
    fi
    if ! grep -q "^${user}:" /etc/subgid 2>/dev/null; then
        usermod --add-subgids "${range}" "${user}"
    fi
elif [ "$action" = "del" ]; then
    if grep -q "^${user}:" /etc/subuid 2>/dev/null; then
        usermod --del-subuids "${range}" "${user}" 2>/dev/null || :
    fi
    if grep -q "^${user}:" /etc/subgid 2>/dev/null; then
        usermod --del-subgids "${range}" "${user}" 2>/dev/null || :
    fi
fi
```

Install it and use in the spec:

```spec
%install
...
install -m 0755 tools/qm-subids.sh %{buildroot}%{_datadir}/qm/qm-subids.sh
```

```spec
%post
...
systemd-sysusers
%{_datadir}/qm/qm-subids.sh %{qm_root_user} %{qm_root_subrange} add
```

```spec
%postun
if [ $1 -eq 0 ]; then
    ...
    %{_datadir}/qm/qm-subids.sh %{qm_root_user} %{qm_root_subrange} del
fi
```

This keeps the spec file shorter and centralizes the branching logic, while preserving the current functionality.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread rpm/qm.spec Outdated
Comment thread rpm/qm.spec Outdated
@engelmi
engelmi force-pushed the add-userns branch 3 times, most recently from a436ceb to 9bf3371 Compare July 3, 2026 07:39
Comment thread qm-sysusers.conf Outdated
g qm_systemd-coredump 1000000997
g qm_render 1000000998
g qm_input 1000000999
g qm_nobody 1000065534

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I agree with this idea, i wonder if its correct to hardcode this list in the general qm package. I mean, it is specific to the cs10 user list. Maybe it could be used as a base, and then we replace it in a-i-b with a generated one based on the actual qm users?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe what we want is to add some tool to qm to generate this, and then we'd have a-i-b launch that at build time?

@engelmi engelmi Jul 6, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, a tool for generating the sysusers conf makes sense. There is already the setup script shipped with QM - to bootstrap QM in non-aib environments. So we could do something similar and then invoke it via a custom osbuild-auto stage org.osbuild.qm.userns in aib.

It should be

  • able to get the users from inside of QM (which should always be /etc/qm/passwd with current quadlet configuration)
  • add the subuid/subgid to it as an offset
  • and save it as a sysusers config in the root partition.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably makes sense to move the usermod for the subuid/subgid assignment into that script as well - then its also not hard-coded.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decided to completely isolate the userns support in the new tool (the userns bash script). This way we do not break anything, can use and refine it. And when we are certain nothing breaks, we can make it the default.

@engelmi
engelmi force-pushed the add-userns branch 6 times, most recently from fda4629 to acbf25f Compare July 8, 2026 07:28
engelmi added 3 commits July 8, 2026 09:52
The support for userns is done via a bash script which sets up the
proper systemd-sysusers configuration based on the passwd and group
files from the mounted /etc. It also generates the QM drop-in setting
the SubUIDMAP= and SUBGIDMap= fields set and adds the desired range
of UIDs/GIDs to the subid files.
This tool needs to be invoked manually, so userns are disabled by
default so to not break anything and can be activated on demand.

Signed-off-by: Michael Engel <mengel@redhat.com>
Co-Authored-By: Claude
Signed-off-by: Michael Engel <mengel@redhat.com>
Signed-off-by: Michael Engel <mengel@redhat.com>

@Yarboa Yarboa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
Opened ticket for CI failures
I would expect userns integration tests other then unittest

@engelmi

engelmi commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

LGTM
Opened ticket for CI failures
I would expect userns integration tests other then unittest

Thanks.
The initial intend was to simply run all existing tests with user namespaces enabled (which would be the integration tests you mentioned). However, since the tests are currently failing, adding another component just complicates it. So fixing them is - sort of - a blocker for the integration tests. There are additional complexities (e.g. the mounted rootfs being owned by root etc.), so I'll take care of this after the tests are fixed in a separate PR.
And unit tests are cheap to run etc., so its good to have them for this in place :)

Comment thread setup
@dougsland

Copy link
Copy Markdown
Member

LGTM but have small question

@Yarboa
Yarboa merged commit 97be3e8 into containers:main Jul 9, 2026
25 of 28 checks passed
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.

4 participants