diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl index 15e448b787aa..e1c7a46e4304 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 7e5f3582ae80..ee64f785f5bf 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 105f0f2710ec..55546ebfda8e 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 7a83689a49a4..aea1516c4f75 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;