Skip to content

openshell-gateway fails on Ubuntu 24.04: user namespace creation denied by AppArmor (apparmor_restrict_unprivileged_userns=1) #1895

@pragmaxim

Description

@pragmaxim

Summary

On Ubuntu 24.04, openshell-gateway.service (the systemd --user unit shipped by the
openshell package) cannot create a usable user namespace: AppArmor transitions the
unconfined gateway process into the stock unprivileged_userns profile and then denies
CAP_SYS_ADMIN inside the namespace. As a result the gateway's sandbox setup fails and no
sandboxed command can run.

This is the Ubuntu 24.04 default kernel.apparmor_restrict_unprivileged_userns=1 behavior,
and OpenShell currently ships nothing to accommodate it.

Environment

  • Ubuntu 24.04, kernel 6.17.0-35-generic, x86_64
  • openshell 0.0.40-1 (from the .deb)
  • kernel.apparmor_restrict_unprivileged_userns = 1 (distro default)

Symptom

The consuming sandbox client fails when setting up the namespace, with:

write /proc/self/setgroups (nested userns is capability-restricted;
caller must provide CAP_SYS_ADMIN): Permission denied

Root cause (kernel audit evidence)

At the moment of failure, dmesg / the audit log shows the gateway being launched and its
user-namespace creation transitioned, immediately followed by a CAP_SYS_ADMIN denial:

apparmor="AUDIT"  operation="userns_create" class="namespace"
    info="Userns create - transitioning profile" profile="unconfined"
    comm="(-gateway)" execpath="/usr/lib/systemd/systemd-executor"
    target="unprivileged_userns"
apparmor="DENIED" operation="capable" class="cap"
    profile="unprivileged_userns" capability=21 capname="sys_admin"

Two contributing factors:

  1. Unconfined → unprivileged_userns transition. Because the gateway runs with no
    AppArmor profile, Ubuntu 24.04's apparmor_restrict_unprivileged_userns=1 transitions it
    into the restrictive unprivileged_userns stub on userns_create, which strips
    CAP_SYS_ADMIN — exactly what's needed to write setgroups and set up the sandbox
    mounts.

  2. PrivateTmp=true on a user service compounds it. openshell-gateway.service sets
    PrivateTmp=true. For a systemd --user (unprivileged) manager, honoring PrivateTmp
    requires creating a mount namespace, which in turn forces creation of a user
    namespace
    at service launch — so the gateway hits the restriction even before its own
    logic runs.

Note that the documented Ubuntu 24.04 remedy of adding an AppArmor profile for
/usr/bin/bwrap does not help here, because the binary creating the failing namespace
is systemd-executor launching the gateway unit — not bwrap.

Suggested fixes (any one unblocks it; ship-side preferred)

  1. Ship an AppArmor profile for the gateway binary that grants userns, so it isn't
    transitioned into unprivileged_userns. e.g.:

    # /etc/apparmor.d/openshell-gateway
    abi <abi/4.0>,
    include <tunables/global>
    profile openshell-gateway /usr/bin/openshell-gateway flags=(unconfined) {
      userns,
      include if exists <local/openshell-gateway>
    }
    
  2. Drop / make optional the namespace-requiring directive in the user unit (e.g.
    PrivateTmp=true) so systemd --user doesn't need a user namespace just to launch the
    gateway. The gateway's persistent state already lives under StateDirectory, not
    /tmp.

  3. Document the Ubuntu 24.04 requirement and detect/log it clearly at startup, since the
    downstream error (setgroups / CAP_SYS_ADMIN) is opaque and points users at the wrong
    component (bubblewrap).

Workaround used

Removing the package (apt remove openshell) and falling back to the other sandbox runtime
present on the host restored command execution. The global AppArmor restriction was left
untouched, confirming the gateway's namespace setup was the failing element rather than the
kernel policy needing to be disabled.

Additional notes

A per-host setup may have two agent-sandbox runtimes installed at once (OpenShell plus
another). When OpenShell's gateway is broken as above, it can break sandboxed command
execution on the host. Clearer startup diagnostics (suggestion 3) would make this much
faster to attribute.

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:triage-neededOpened without agent diagnostics and needs triage

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions