mirror of
https://github.com/NixOS/nix.git
synced 2024-11-21 22:32:26 +00:00
Merge pull request #9854 from the-sun-will-rise-tomorrow/docker-user
docker: Allow building for non-root user
This commit is contained in:
commit
d8d59298e5
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@ -128,7 +128,7 @@ jobs:
|
||||
- run: exec bash -c "nix-channel --update && nix-env -iA nixpkgs.hello && hello"
|
||||
|
||||
docker_push_image:
|
||||
needs: [check_secrets, tests]
|
||||
needs: [check_secrets, tests, vm_tests]
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
@ -194,7 +194,13 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: DeterminateSystems/nix-installer-action@main
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||
- run: nix build -L .#hydraJobs.tests.githubFlakes .#hydraJobs.tests.tarballFlakes .#hydraJobs.tests.functional_user
|
||||
- run: |
|
||||
nix build -L \
|
||||
.#hydraJobs.tests.functional_user \
|
||||
.#hydraJobs.tests.githubFlakes \
|
||||
.#hydraJobs.tests.nix-docker \
|
||||
.#hydraJobs.tests.tarballFlakes \
|
||||
;
|
||||
|
||||
flake_regressions:
|
||||
needs: vm_tests
|
||||
|
@ -57,3 +57,21 @@ $ nix build ./\#hydraJobs.dockerImage.x86_64-linux
|
||||
$ docker load -i ./result/image.tar.gz
|
||||
$ docker run -ti nix:2.5pre20211105
|
||||
```
|
||||
|
||||
# Docker image with non-root Nix
|
||||
|
||||
If you would like to run Nix in a container under a user other than `root`,
|
||||
you can build an image with a non-root single-user installation of Nix
|
||||
by specifying the `uid`, `gid`, `uname`, and `gname` arguments to `docker.nix`:
|
||||
|
||||
```console
|
||||
$ nix build --file docker.nix \
|
||||
--arg uid 1000 \
|
||||
--arg gid 1000 \
|
||||
--argstr uname user \
|
||||
--argstr gname user \
|
||||
--argstr name nix-user \
|
||||
--out-link nix-user.tar.gz
|
||||
$ docker load -i nix-user.tar.gz
|
||||
$ docker run -ti nix-user
|
||||
```
|
||||
|
50
docker.nix
50
docker.nix
@ -9,6 +9,10 @@
|
||||
, maxLayers ? 100
|
||||
, nixConf ? {}
|
||||
, flake-registry ? null
|
||||
, uid ? 0
|
||||
, gid ? 0
|
||||
, uname ? "root"
|
||||
, gname ? "root"
|
||||
}:
|
||||
let
|
||||
defaultPkgs = with pkgs; [
|
||||
@ -50,6 +54,15 @@ let
|
||||
description = "Unprivileged account (don't use!)";
|
||||
};
|
||||
|
||||
} // lib.optionalAttrs (uid != 0) {
|
||||
"${uname}" = {
|
||||
uid = uid;
|
||||
shell = "${pkgs.bashInteractive}/bin/bash";
|
||||
home = "/home/${uname}";
|
||||
gid = gid;
|
||||
groups = [ "${gname}" ];
|
||||
description = "Nix user";
|
||||
};
|
||||
} // lib.listToAttrs (
|
||||
map
|
||||
(
|
||||
@ -70,6 +83,8 @@ let
|
||||
root.gid = 0;
|
||||
nixbld.gid = 30000;
|
||||
nobody.gid = 65534;
|
||||
} // lib.optionalAttrs (gid != 0) {
|
||||
"${gname}".gid = gid;
|
||||
};
|
||||
|
||||
userToPasswd = (
|
||||
@ -150,6 +165,8 @@ let
|
||||
in
|
||||
"${n} = ${vStr}") (defaultNixConf // nixConf))) + "\n";
|
||||
|
||||
userHome = if uid == 0 then "/root" else "/home/${uname}";
|
||||
|
||||
baseSystem =
|
||||
let
|
||||
nixpkgs = pkgs.path;
|
||||
@ -237,26 +254,26 @@ let
|
||||
mkdir -p $out/etc/nix
|
||||
cat $nixConfContentsPath > $out/etc/nix/nix.conf
|
||||
|
||||
mkdir -p $out/root
|
||||
mkdir -p $out/nix/var/nix/profiles/per-user/root
|
||||
mkdir -p $out${userHome}
|
||||
mkdir -p $out/nix/var/nix/profiles/per-user/${uname}
|
||||
|
||||
ln -s ${profile} $out/nix/var/nix/profiles/default-1-link
|
||||
ln -s $out/nix/var/nix/profiles/default-1-link $out/nix/var/nix/profiles/default
|
||||
ln -s /nix/var/nix/profiles/default $out/root/.nix-profile
|
||||
ln -s /nix/var/nix/profiles/default $out${userHome}/.nix-profile
|
||||
|
||||
ln -s ${channel} $out/nix/var/nix/profiles/per-user/root/channels-1-link
|
||||
ln -s $out/nix/var/nix/profiles/per-user/root/channels-1-link $out/nix/var/nix/profiles/per-user/root/channels
|
||||
ln -s ${channel} $out/nix/var/nix/profiles/per-user/${uname}/channels-1-link
|
||||
ln -s $out/nix/var/nix/profiles/per-user/${uname}/channels-1-link $out/nix/var/nix/profiles/per-user/${uname}/channels
|
||||
|
||||
mkdir -p $out/root/.nix-defexpr
|
||||
ln -s $out/nix/var/nix/profiles/per-user/root/channels $out/root/.nix-defexpr/channels
|
||||
echo "${channelURL} ${channelName}" > $out/root/.nix-channels
|
||||
mkdir -p $out${userHome}/.nix-defexpr
|
||||
ln -s $out/nix/var/nix/profiles/per-user/${uname}/channels $out${userHome}/.nix-defexpr/channels
|
||||
echo "${channelURL} ${channelName}" > $out${userHome}/.nix-channels
|
||||
|
||||
mkdir -p $out/bin $out/usr/bin
|
||||
ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env
|
||||
ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/sh
|
||||
|
||||
'' + (lib.optionalString (flake-registry-path != null) ''
|
||||
nixCacheDir="/root/.cache/nix"
|
||||
nixCacheDir="${userHome}/.cache/nix"
|
||||
mkdir -p $out$nixCacheDir
|
||||
globalFlakeRegistryPath="$nixCacheDir/flake-registry.json"
|
||||
ln -s ${flake-registry-path} $out$globalFlakeRegistryPath
|
||||
@ -268,7 +285,7 @@ let
|
||||
in
|
||||
pkgs.dockerTools.buildLayeredImageWithNixDb {
|
||||
|
||||
inherit name tag maxLayers;
|
||||
inherit name tag maxLayers uid gid uname gname;
|
||||
|
||||
contents = [ baseSystem ];
|
||||
|
||||
@ -279,25 +296,28 @@ pkgs.dockerTools.buildLayeredImageWithNixDb {
|
||||
fakeRootCommands = ''
|
||||
chmod 1777 tmp
|
||||
chmod 1777 var/tmp
|
||||
chown -R ${toString uid}:${toString gid} .${userHome}
|
||||
chown -R ${toString uid}:${toString gid} nix
|
||||
'';
|
||||
|
||||
config = {
|
||||
Cmd = [ "/root/.nix-profile/bin/bash" ];
|
||||
Cmd = [ "${userHome}/.nix-profile/bin/bash" ];
|
||||
User = "${toString uid}:${toString gid}";
|
||||
Env = [
|
||||
"USER=root"
|
||||
"USER=${uname}"
|
||||
"PATH=${lib.concatStringsSep ":" [
|
||||
"/root/.nix-profile/bin"
|
||||
"${userHome}/.nix-profile/bin"
|
||||
"/nix/var/nix/profiles/default/bin"
|
||||
"/nix/var/nix/profiles/default/sbin"
|
||||
]}"
|
||||
"MANPATH=${lib.concatStringsSep ":" [
|
||||
"/root/.nix-profile/share/man"
|
||||
"${userHome}/.nix-profile/share/man"
|
||||
"/nix/var/nix/profiles/default/share/man"
|
||||
]}"
|
||||
"SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
|
||||
"GIT_SSL_CAINFO=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
|
||||
"NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
|
||||
"NIX_PATH=/nix/var/nix/profiles/per-user/root/channels:/root/.nix-defexpr/channels"
|
||||
"NIX_PATH=/nix/var/nix/profiles/per-user/${uname}/channels:${userHome}/.nix-defexpr/channels"
|
||||
];
|
||||
};
|
||||
|
||||
|
@ -124,6 +124,8 @@ in
|
||||
|
||||
nix-copy = runNixOSTestFor "x86_64-linux" ./nix-copy.nix;
|
||||
|
||||
nix-docker = runNixOSTestFor "x86_64-linux" ./nix-docker.nix;
|
||||
|
||||
nssPreload = runNixOSTestFor "x86_64-linux" ./nss-preload.nix;
|
||||
|
||||
githubFlakes = runNixOSTestFor "x86_64-linux" ./github-flakes.nix;
|
||||
|
47
tests/nixos/nix-docker-test.sh
Normal file
47
tests/nixos/nix-docker-test.sh
Normal file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env bash
|
||||
# docker.nix test script. Runs inside a built docker.nix container.
|
||||
|
||||
set -eEuo pipefail
|
||||
|
||||
export NIX_CONFIG='substituters = http://cache:5000?trusted=1'
|
||||
|
||||
cd /tmp
|
||||
|
||||
# Test getting a fetched derivation
|
||||
test "$("$(nix-build -E '(import <nixpkgs> {}).hello')"/bin/hello)" = "Hello, world!"
|
||||
|
||||
# Test building a simple derivation
|
||||
# shellcheck disable=SC2016
|
||||
nix-build -E '
|
||||
let
|
||||
pkgs = import <nixpkgs> {};
|
||||
in
|
||||
builtins.derivation {
|
||||
name = "test";
|
||||
system = builtins.currentSystem;
|
||||
builder = "${pkgs.bash}/bin/bash";
|
||||
args = ["-c" "echo OK > $out"];
|
||||
}'
|
||||
test "$(cat result)" = OK
|
||||
|
||||
# Ensure #!/bin/sh shebang works
|
||||
echo '#!/bin/sh' > ./shebang-test
|
||||
echo 'echo OK' >> ./shebang-test
|
||||
chmod +x ./shebang-test
|
||||
test "$(./shebang-test)" = OK
|
||||
|
||||
# Ensure #!/usr/bin/env shebang works
|
||||
echo '#!/usr/bin/env bash' > ./shebang-test
|
||||
echo 'echo OK' >> ./shebang-test
|
||||
chmod +x ./shebang-test
|
||||
test "$(./shebang-test)" = OK
|
||||
|
||||
# Test nix-shell
|
||||
{
|
||||
echo '#!/usr/bin/env nix-shell'
|
||||
echo '#! nix-shell -i bash'
|
||||
echo '#! nix-shell -p hello'
|
||||
echo 'hello'
|
||||
} > ./nix-shell-test
|
||||
chmod +x ./nix-shell-test
|
||||
test "$(./nix-shell-test)" = "Hello, world!"
|
53
tests/nixos/nix-docker.nix
Normal file
53
tests/nixos/nix-docker.nix
Normal file
@ -0,0 +1,53 @@
|
||||
# Test the container built by ../../docker.nix.
|
||||
|
||||
{ lib, config, nixpkgs, hostPkgs, ... }:
|
||||
|
||||
let
|
||||
pkgs = config.nodes.machine.nixpkgs.pkgs;
|
||||
|
||||
nixImage = import ../../docker.nix {
|
||||
inherit (config.nodes.machine.nixpkgs) pkgs;
|
||||
};
|
||||
nixUserImage = import ../../docker.nix {
|
||||
inherit (config.nodes.machine.nixpkgs) pkgs;
|
||||
name = "nix-user";
|
||||
uid = 1000;
|
||||
gid = 1000;
|
||||
uname = "user";
|
||||
gname = "user";
|
||||
};
|
||||
|
||||
containerTestScript = ./nix-docker-test.sh;
|
||||
|
||||
in {
|
||||
name = "nix-docker";
|
||||
|
||||
nodes =
|
||||
{ machine =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.diskSize = 4096;
|
||||
};
|
||||
cache =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ virtualisation.additionalPaths = [ pkgs.stdenv pkgs.hello ];
|
||||
services.harmonia.enable = true;
|
||||
networking.firewall.allowedTCPPorts = [ 5000 ];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
cache.wait_for_unit("harmonia.service")
|
||||
|
||||
machine.succeed("mkdir -p /etc/containers")
|
||||
machine.succeed("""echo '{"default":[{"type":"insecureAcceptAnything"}]}' > /etc/containers/policy.json""")
|
||||
|
||||
machine.succeed("${pkgs.podman}/bin/podman load -i ${nixImage}")
|
||||
machine.succeed("${pkgs.podman}/bin/podman run --rm nix nix --version")
|
||||
machine.succeed("${pkgs.podman}/bin/podman run --rm -i nix < ${containerTestScript}")
|
||||
|
||||
machine.succeed("${pkgs.podman}/bin/podman load -i ${nixUserImage}")
|
||||
machine.succeed("${pkgs.podman}/bin/podman run --rm nix-user nix --version")
|
||||
machine.succeed("${pkgs.podman}/bin/podman run --rm -i nix-user < ${containerTestScript}")
|
||||
machine.succeed("[[ $(${pkgs.podman}/bin/podman run --rm nix-user stat -c %u /nix/store) = 1000 ]]")
|
||||
'';
|
||||
}
|
Loading…
Reference in New Issue
Block a user