Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: subuid and subgid #7

Open
linyinfeng opened this issue Sep 25, 2024 · 5 comments
Open

Feature request: subuid and subgid #7

linyinfeng opened this issue Sep 25, 2024 · 5 comments

Comments

@linyinfeng
Copy link

It would be great if userborn supports generating /etc/subuid and /etc/subgid.

Rootless podman requires these files to work properly:

$ podman ps
ERRO[0000] cannot find UID/GID for user yinfeng: open /etc/subuid: no such file or directory - check rootless mode in man pages.
WARN[0000] Using rootless single mapping into the namespace. This might break some images. Check /etc/subuid and /etc/subgid for adding sub*ids if not using a network user
CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES
$ podman run -it --rm debian
✔ docker.io/library/debian:latest
Trying to pull docker.io/library/debian:latest...
Getting image source signatures
Copying blob 8cd46d290033 done   |
Error: copying system image from manifest list: writing blob: adding layer with blob "sha256:8cd46d290033f265db57fd808ac81c444ec5a5b3f189c3d6d85043b647336913"/""/"sha256:6abe10f2f60150ae9768e117986e4f8af5546137221553228eb5d21066f596b4": unpacking failed (error: exit status 1; output: potentially insufficient UIDs or GIDs available in user namespace (requested 0:42 for /etc/gshadow): Check /etc/subuid and /etc/subgid if configured locally and run "podman system migrate": lchown /etc/gshadow: invalid argument)

Nixpkgs module provides the following options for subuid and subgid. These options will be processed by update-users-groups.pl by default.

  • users.users.<name>.autoSubUidGidRange
  • users.users.<name>.subUidRanges
  • users.users.<name>.subGidRanges
@nikstur
Copy link
Owner

nikstur commented Sep 25, 2024

I think this is best solved by statically generating these files e.g. via systemd-tmpfiles. I don't want to touch the rust binary for this.

@Sporif
Copy link

Sporif commented Nov 2, 2024

This snippet works for me:

environment.etc = let
    mkSubUid = user: ''
      ${user.name}:100000:65536
    '';
    mkSubGid = user: ''
      ${user.group}:100000:65536
    '';
    users = lib.filter (u: u.isNormalUser) (lib.attrValues config.users.users);
  in lib.mkIf config.services.userborn.enable {
    "subuid".text = lib.concatMapStrings mkSubUid users;
    "subgid".text = lib.concatMapStrings mkSubGid users;
};

@YorikSar
Copy link

YorikSar commented Nov 7, 2024

@nikstur Actually, these IDs are stored in different places, including container configurations. It means that they have the same properties as proper UIDs and GIDs: they should be permanent and should not be reused. They also must not overlap1, so solution from @Sporif is not correct. Generating them in Nix is quite tricky and can only be correct with a bunch of assumptions. I got away with it on the infrastructure I manage like this:

  environment.etc = let
    autosubs = lib.pipe config.users.users [
      lib.attrValues
      (lib.filter (u: u.uid != null && u.isNormalUser))
      (lib.concatMapStrings (u: "${toString u.uid}:${toString (100000 + u.uid * 65536)}:65536\n"))
    ];
  in {
    "subuid".text = autosubs;
    "subuid".mode = "0444";
    "subgid".text = autosubs;
    "subgid".mode = "0444";
  };

But this has many assumptions that don't generally apply:

  • all users must have explicit UIDs (had to enforce this one because of sysusers anyway)
  • these UIDs are never reused
  • UID and GID are the same (because I'm lazy)
  • no UID or GID on the system is greater than 100000 (same assumption is in update-users-groups.pl)
  • no UID in the config is greater than 32766

I feel like just like with UIDs and GIDs, userborn could help solving this issue in a more correct and long-term stable manner.

Footnotes

  1. if they overlap, two users will create containers using same subids, and those containers will have access to each other

@Mic92
Copy link
Contributor

Mic92 commented Dec 17, 2024

I think this is best solved by statically generating these files e.g. via systemd-tmpfiles. I don't want to touch the rust binary for this.

This won't work for allocSubUid

sub allocSubUid {
    my ($name, @rest) = @_;

    # TODO: No upper bounds?
    my ($min, $max, $up) = (100000, 100000 * 100, 1);
    my $prevId = $subUidMap->{$name};
    if (defined $prevId && !defined $subUidsUsed{$prevId}) {
        $subUidsUsed{$prevId} = 1;
        return $prevId;
    }

    my $id = allocId(\%subUidsUsed, \%subUidsPrevUsed, $min, $max, $up, sub { my ($uid) = @_; getpwuid($uid) });
    my $offset = $id - 100000;
    my $count = $offset * 65536;
    my $subordinate = 100000 + $count;
    return $subordinate;
}

@nikstur
Copy link
Owner

nikstur commented Feb 26, 2025

From reading the rootless containers docs, the easiest way (and the one they seem to recommend) is to just pre-generate these maps for all possible UIDs & GIDs: https://rootlesscontaine.rs/getting-started/common/subuid/

They provide a python snippet for this pre-calculation.

with open("/etc/subuid", "w") as f:
    for uid in range(1000, 65536):
        f.write("%d:%d:65536\n" %(uid,uid*65536))

with open("/etc/subgid", "w") as f:
    for uid in range(1000, 65536):
        f.write("%d:%d:65536\n" %(uid,uid*65536))

Afaik this would solve all problems elegantly. If system users also need subuids, we can just start form uid 1.

I don't see how another way of doing it would be more correct or secure. I don't see a reason why you wouldn't want to give a subuid range to a certain UID. It feels like this was placed in the Perl script simply because there already was a script and it was easiest to do it there.

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

No branches or pull requests

5 participants