|
115 | 115 | extraFlags+=("--private-network") |
116 | 116 | fi |
117 | 117 |
|
| 118 | + NIX_BIND_OPT="" |
| 119 | + if [ -n "$PRIVATE_USERS" ]; then |
| 120 | + extraFlags+=("--private-users=$PRIVATE_USERS") |
| 121 | + if [ "$PRIVATE_USERS" = "pick" ] || ( [ "$PRIVATE_USERS" != "identity" ] && [ "$PRIVATE_USERS" -gt 0 ] ); then |
| 122 | + # when user namespacing is enabled, we use `idmap` mount option |
| 123 | + # so that bind mounts under /nix get proper owner (and not nobody/nogroup). |
| 124 | + NIX_BIND_OPT=":idmap" |
| 125 | + fi |
| 126 | + fi |
| 127 | +
|
118 | 128 | if [ -n "$HOST_ADDRESS" ] || [ -n "$LOCAL_ADDRESS" ] || |
119 | 129 | [ -n "$HOST_ADDRESS6" ] || [ -n "$LOCAL_ADDRESS6" ]; then |
120 | 130 | extraFlags+=("--network-veth") |
@@ -171,13 +181,14 @@ let |
171 | 181 | $EXTRA_NSPAWN_FLAGS \ |
172 | 182 | --notify-ready=yes \ |
173 | 183 | --kill-signal=SIGRTMIN+3 \ |
174 | | - --bind-ro=/nix/store \ |
175 | | - --bind-ro=/nix/var/nix/db \ |
176 | | - --bind-ro=/nix/var/nix/daemon-socket \ |
177 | | - --bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \ |
178 | | - --bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots" \ |
| 184 | + --bind-ro=/nix/store:/nix/store$NIX_BIND_OPT \ |
| 185 | + --bind-ro=/nix/var/nix/db:/nix/var/nix/db$NIX_BIND_OPT \ |
| 186 | + --bind-ro=/nix/var/nix/daemon-socket:/nix/var/nix/daemon-socket$NIX_BIND_OPT \ |
| 187 | + --bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles$NIX_BIND_OPT" \ |
| 188 | + --bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots$NIX_BIND_OPT" \ |
179 | 189 | ${optionalString (!cfg.ephemeral) "--link-journal=try-guest"} \ |
180 | 190 | --setenv PRIVATE_NETWORK="$PRIVATE_NETWORK" \ |
| 191 | + --setenv PRIVATE_USERS="$PRIVATE_USERS" \ |
181 | 192 | --setenv HOST_BRIDGE="$HOST_BRIDGE" \ |
182 | 193 | --setenv HOST_ADDRESS="$HOST_ADDRESS" \ |
183 | 194 | --setenv LOCAL_ADDRESS="$LOCAL_ADDRESS" \ |
|
650 | 661 | ''; |
651 | 662 | }; |
652 | 663 |
|
| 664 | + privateUsers = mkOption { |
| 665 | + type = types.either types.ints.u32 (types.enum [ "no" "identity" "pick" ]); |
| 666 | + default = "no"; |
| 667 | + description = '' |
| 668 | + Whether to give the container its own private UIDs/GIDs space (user namespacing). |
| 669 | + Disabled by default (`no`). |
| 670 | +
|
| 671 | + If set to a number (usually above host's UID/GID range: 65536), |
| 672 | + user namespacing is enabled and the container UID/GIDs will start at that number. |
| 673 | +
|
| 674 | + If set to `identity`, mostly equivalent to `0`, this will only provide |
| 675 | + process capability isolation (no UID/GID isolation, as they are the same as host). |
| 676 | +
|
| 677 | + If set to `pick`, user namespacing is enabled and the UID/GID range is automatically chosen, |
| 678 | + so that no overlapping UID/GID ranges are assigned to multiple containers. |
| 679 | + This is the recommanded option as it enhances container security massively and operates fully automatically in most cases. |
| 680 | +
|
| 681 | + See https://www.freedesktop.org/software/systemd/man/latest/systemd-nspawn.html#--private-users= for details. |
| 682 | + ''; |
| 683 | + }; |
| 684 | + |
653 | 685 | interfaces = mkOption { |
654 | 686 | type = types.listOf types.str; |
655 | 687 | default = []; |
|
862 | 894 | additionalCapabilities = cfg.additionalCapabilities |
863 | 895 | ++ [ "CAP_NET_ADMIN" ]; |
864 | 896 | } |
| 897 | + ) // ( |
| 898 | + optionalAttrs (!cfg.enableTun && cfg.privateNetwork |
| 899 | + && (cfg.privateUsers == "pick" || (builtins.isInt cfg.privateUsers && cfg.privateUsers > 0 ))) |
| 900 | + { |
| 901 | + allowedDevices = cfg.allowedDevices |
| 902 | + ++ [ { node = "/dev/net/tun"; modifier = "rwm"; } ]; |
| 903 | + } |
865 | 904 | ); |
866 | 905 | in |
867 | 906 | recursiveUpdate unit { |
|
923 | 962 | ${optionalString (cfg.networkNamespace != null) '' |
924 | 963 | NETWORK_NAMESPACE_PATH=${cfg.networkNamespace} |
925 | 964 | ''} |
| 965 | + PRIVATE_USERS=${toString cfg.privateUsers} |
926 | 966 | INTERFACES="${toString cfg.interfaces}" |
927 | 967 | MACVLANS="${toString cfg.macvlans}" |
928 | 968 | ${optionalString cfg.autoStart '' |
|
0 commit comments