From 5733967290f19f5e1ee43ef057b9b31c647ba80d Mon Sep 17 00:00:00 2001 From: adisbladis Date: Tue, 28 Apr 2020 22:30:34 +0100 Subject: [PATCH 1/2] nixos.users-groups: Set up subuid/subgid mappings for all normal users This is required by (among others) Podman to run containers in rootless mode. Other distributions such as Fedora and Ubuntu already set up these mappings. The scheme with a start UID/GID offset starting at 100000 and increasing in 65536 increments is copied from Fedora. --- nixos/modules/config/update-users-groups.pl | 55 +++++++++++++++++++++ nixos/modules/config/users-groups.nix | 24 +-------- nixos/modules/virtualisation/containers.nix | 38 ++++---------- nixos/tests/podman.nix | 3 -- 4 files changed, 66 insertions(+), 54 deletions(-) diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl index 15e448b787a..e1c7a46e430 100644 --- a/nixos/modules/config/update-users-groups.pl +++ b/nixos/modules/config/update-users-groups.pl @@ -281,3 +281,58 @@ foreach my $u (values %usersOut) { } updateFile("/etc/shadow", \@shadowNew, 0600); + +# Rewrite /etc/subuid & /etc/subgid to include default container mappings + +my $subUidMapFile = "/var/lib/nixos/auto-subuid-map"; +my $subUidMap = -e $subUidMapFile ? decode_json(read_file($subUidMapFile)) : {}; + +my (%subUidsUsed, %subUidsPrevUsed); + +$subUidsPrevUsed{$_} = 1 foreach values %{$subUidMap}; + +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; +} + +my @subGids; +my @subUids; +foreach my $u (values %usersOut) { + my $name = $u->{name}; + + foreach my $range (@{$u->{subUidRanges}}) { + my $value = join(":", ($name, $range->{startUid}, $range->{count})); + push @subUids, $value; + } + + foreach my $range (@{$u->{subGidRanges}}) { + my $value = join(":", ($name, $range->{startGid}, $range->{count})); + push @subGids, $value; + } + + if($u->{isNormalUser}) { + my $subordinate = allocSubUid($name); + $subUidMap->{$name} = $subordinate; + my $value = join(":", ($name, $subordinate, 65536)); + push @subUids, $value; + push @subGids, $value; + } +} + +updateFile("/etc/subuid", join("\n", @subUids) . "\n"); +updateFile("/etc/subgid", join("\n", @subGids) . "\n"); +updateFile($subUidMapFile, encode_json($subUidMap) . "\n"); diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index 7e5f3582ae8..ee64f785f5b 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -375,18 +375,6 @@ let }; }; - mkSubuidEntry = user: concatStrings ( - map (range: "${user.name}:${toString range.startUid}:${toString range.count}\n") - user.subUidRanges); - - subuidFile = concatStrings (map mkSubuidEntry (attrValues cfg.users)); - - mkSubgidEntry = user: concatStrings ( - map (range: "${user.name}:${toString range.startGid}:${toString range.count}\n") - user.subGidRanges); - - subgidFile = concatStrings (map mkSubgidEntry (attrValues cfg.users)); - idsAreUnique = set: idAttr: !(fold (name: args@{ dup, acc }: let id = builtins.toString (builtins.getAttr idAttr (builtins.getAttr name set)); @@ -406,6 +394,7 @@ let { inherit (u) name uid group description home createHome isSystemUser password passwordFile hashedPassword + isNormalUser subUidRanges subGidRanges initialPassword initialHashedPassword; shell = utils.toShellPath u.shell; }) cfg.users; @@ -567,16 +556,7 @@ in { # Install all the user shells environment.systemPackages = systemShells; - environment.etc = { - subuid = { - text = subuidFile; - mode = "0644"; - }; - subgid = { - text = subgidFile; - mode = "0644"; - }; - } // (mapAttrs' (name: { packages, ... }: { + environment.etc = (mapAttrs' (name: { packages, ... }: { name = "profiles/per-user/${name}"; value.source = pkgs.buildEnv { name = "user-environment"; diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index 105f0f2710e..55546ebfda8 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -23,6 +23,15 @@ in maintainers = [] ++ lib.teams.podman.members; }; + + imports = [ + ( + lib.mkRemovedOptionModule + [ "virtualisation" "containers" "users" ] + "All users with `isNormaUser = true` set now get appropriate subuid/subgid mappings." + ) + ]; + options.virtualisation.containers = { enable = @@ -99,15 +108,6 @@ in ''; }; - users = mkOption { - default = []; - type = types.listOf types.str; - description = '' - List of users to set up subuid/subgid mappings for. - This is a requirement for running rootless containers. - ''; - }; - }; config = lib.mkIf cfg.enable { @@ -122,26 +122,6 @@ in registries = lib.mapAttrs (n: v: { registries = v; }) cfg.registries; }; - users.extraUsers = builtins.listToAttrs ( - ( - builtins.foldl' ( - acc: user: { - values = acc.values ++ [ - { - name = user; - value = { - subUidRanges = [ { startUid = acc.offset; count = 65536; } ]; - subGidRanges = [ { startGid = acc.offset; count = 65536; } ]; - }; - } - ]; - offset = acc.offset + 65536; - } - ) - { values = []; offset = 100000; } (lib.unique cfg.users) - ).values - ); - environment.etc."containers/policy.json".source = if cfg.policy != {} then pkgs.writeText "policy.json" (builtins.toJSON cfg.policy) else copyFile "${pkgs.skopeo.src}/default-policy.json"; diff --git a/nixos/tests/podman.nix b/nixos/tests/podman.nix index 7a83689a49a..aea1516c4f7 100644 --- a/nixos/tests/podman.nix +++ b/nixos/tests/podman.nix @@ -12,9 +12,6 @@ import ./make-test-python.nix ( { pkgs, ... }: { virtualisation.podman.enable = true; - virtualisation.containers.users = [ - "alice" - ]; users.users.alice = { isNormalUser = true; From ce49f8cbd08ae71e6446345318f7775644b6bd20 Mon Sep 17 00:00:00 2001 From: adisbladis Date: Mon, 13 Jul 2020 13:22:53 +0200 Subject: [PATCH 2/2] nixos/doc/manual/release-notes: Add release notes for subuid/subgid mappings --- nixos/doc/manual/release-notes/rl-2009.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nixos/doc/manual/release-notes/rl-2009.xml b/nixos/doc/manual/release-notes/rl-2009.xml index 688671efffc..97b94c5756a 100644 --- a/nixos/doc/manual/release-notes/rl-2009.xml +++ b/nixos/doc/manual/release-notes/rl-2009.xml @@ -124,6 +124,12 @@ systemd.services.mysql.serviceConfig.ReadWritePaths = [ "/var/data" ]; services.postfix.sslCACert was replaced by services.postfix.tlsTrustedAuthorities which now defaults to system certifcate authorities. + + + Subordinate GID and UID mappings are now set up automatically for all normal users. + This will make container tools like Podman work as non-root users out of the box. + +