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"
|
- run: exec bash -c "nix-channel --update && nix-env -iA nixpkgs.hello && hello"
|
||||||
|
|
||||||
docker_push_image:
|
docker_push_image:
|
||||||
needs: [check_secrets, tests]
|
needs: [check_secrets, tests, vm_tests]
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
@ -194,7 +194,13 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: DeterminateSystems/nix-installer-action@main
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
- uses: DeterminateSystems/magic-nix-cache-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:
|
flake_regressions:
|
||||||
needs: vm_tests
|
needs: vm_tests
|
||||||
|
@ -57,3 +57,21 @@ $ nix build ./\#hydraJobs.dockerImage.x86_64-linux
|
|||||||
$ docker load -i ./result/image.tar.gz
|
$ docker load -i ./result/image.tar.gz
|
||||||
$ docker run -ti nix:2.5pre20211105
|
$ 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
|
, maxLayers ? 100
|
||||||
, nixConf ? {}
|
, nixConf ? {}
|
||||||
, flake-registry ? null
|
, flake-registry ? null
|
||||||
|
, uid ? 0
|
||||||
|
, gid ? 0
|
||||||
|
, uname ? "root"
|
||||||
|
, gname ? "root"
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
defaultPkgs = with pkgs; [
|
defaultPkgs = with pkgs; [
|
||||||
@ -50,6 +54,15 @@ let
|
|||||||
description = "Unprivileged account (don't use!)";
|
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 (
|
} // lib.listToAttrs (
|
||||||
map
|
map
|
||||||
(
|
(
|
||||||
@ -70,6 +83,8 @@ let
|
|||||||
root.gid = 0;
|
root.gid = 0;
|
||||||
nixbld.gid = 30000;
|
nixbld.gid = 30000;
|
||||||
nobody.gid = 65534;
|
nobody.gid = 65534;
|
||||||
|
} // lib.optionalAttrs (gid != 0) {
|
||||||
|
"${gname}".gid = gid;
|
||||||
};
|
};
|
||||||
|
|
||||||
userToPasswd = (
|
userToPasswd = (
|
||||||
@ -150,6 +165,8 @@ let
|
|||||||
in
|
in
|
||||||
"${n} = ${vStr}") (defaultNixConf // nixConf))) + "\n";
|
"${n} = ${vStr}") (defaultNixConf // nixConf))) + "\n";
|
||||||
|
|
||||||
|
userHome = if uid == 0 then "/root" else "/home/${uname}";
|
||||||
|
|
||||||
baseSystem =
|
baseSystem =
|
||||||
let
|
let
|
||||||
nixpkgs = pkgs.path;
|
nixpkgs = pkgs.path;
|
||||||
@ -237,26 +254,26 @@ let
|
|||||||
mkdir -p $out/etc/nix
|
mkdir -p $out/etc/nix
|
||||||
cat $nixConfContentsPath > $out/etc/nix/nix.conf
|
cat $nixConfContentsPath > $out/etc/nix/nix.conf
|
||||||
|
|
||||||
mkdir -p $out/root
|
mkdir -p $out${userHome}
|
||||||
mkdir -p $out/nix/var/nix/profiles/per-user/root
|
mkdir -p $out/nix/var/nix/profiles/per-user/${uname}
|
||||||
|
|
||||||
ln -s ${profile} $out/nix/var/nix/profiles/default-1-link
|
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 $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 ${channel} $out/nix/var/nix/profiles/per-user/${uname}/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 $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
|
mkdir -p $out${userHome}/.nix-defexpr
|
||||||
ln -s $out/nix/var/nix/profiles/per-user/root/channels $out/root/.nix-defexpr/channels
|
ln -s $out/nix/var/nix/profiles/per-user/${uname}/channels $out${userHome}/.nix-defexpr/channels
|
||||||
echo "${channelURL} ${channelName}" > $out/root/.nix-channels
|
echo "${channelURL} ${channelName}" > $out${userHome}/.nix-channels
|
||||||
|
|
||||||
mkdir -p $out/bin $out/usr/bin
|
mkdir -p $out/bin $out/usr/bin
|
||||||
ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env
|
ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env
|
||||||
ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/sh
|
ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/sh
|
||||||
|
|
||||||
'' + (lib.optionalString (flake-registry-path != null) ''
|
'' + (lib.optionalString (flake-registry-path != null) ''
|
||||||
nixCacheDir="/root/.cache/nix"
|
nixCacheDir="${userHome}/.cache/nix"
|
||||||
mkdir -p $out$nixCacheDir
|
mkdir -p $out$nixCacheDir
|
||||||
globalFlakeRegistryPath="$nixCacheDir/flake-registry.json"
|
globalFlakeRegistryPath="$nixCacheDir/flake-registry.json"
|
||||||
ln -s ${flake-registry-path} $out$globalFlakeRegistryPath
|
ln -s ${flake-registry-path} $out$globalFlakeRegistryPath
|
||||||
@ -268,7 +285,7 @@ let
|
|||||||
in
|
in
|
||||||
pkgs.dockerTools.buildLayeredImageWithNixDb {
|
pkgs.dockerTools.buildLayeredImageWithNixDb {
|
||||||
|
|
||||||
inherit name tag maxLayers;
|
inherit name tag maxLayers uid gid uname gname;
|
||||||
|
|
||||||
contents = [ baseSystem ];
|
contents = [ baseSystem ];
|
||||||
|
|
||||||
@ -279,25 +296,28 @@ pkgs.dockerTools.buildLayeredImageWithNixDb {
|
|||||||
fakeRootCommands = ''
|
fakeRootCommands = ''
|
||||||
chmod 1777 tmp
|
chmod 1777 tmp
|
||||||
chmod 1777 var/tmp
|
chmod 1777 var/tmp
|
||||||
|
chown -R ${toString uid}:${toString gid} .${userHome}
|
||||||
|
chown -R ${toString uid}:${toString gid} nix
|
||||||
'';
|
'';
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
Cmd = [ "/root/.nix-profile/bin/bash" ];
|
Cmd = [ "${userHome}/.nix-profile/bin/bash" ];
|
||||||
|
User = "${toString uid}:${toString gid}";
|
||||||
Env = [
|
Env = [
|
||||||
"USER=root"
|
"USER=${uname}"
|
||||||
"PATH=${lib.concatStringsSep ":" [
|
"PATH=${lib.concatStringsSep ":" [
|
||||||
"/root/.nix-profile/bin"
|
"${userHome}/.nix-profile/bin"
|
||||||
"/nix/var/nix/profiles/default/bin"
|
"/nix/var/nix/profiles/default/bin"
|
||||||
"/nix/var/nix/profiles/default/sbin"
|
"/nix/var/nix/profiles/default/sbin"
|
||||||
]}"
|
]}"
|
||||||
"MANPATH=${lib.concatStringsSep ":" [
|
"MANPATH=${lib.concatStringsSep ":" [
|
||||||
"/root/.nix-profile/share/man"
|
"${userHome}/.nix-profile/share/man"
|
||||||
"/nix/var/nix/profiles/default/share/man"
|
"/nix/var/nix/profiles/default/share/man"
|
||||||
]}"
|
]}"
|
||||||
"SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
|
"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"
|
"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_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-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;
|
nssPreload = runNixOSTestFor "x86_64-linux" ./nss-preload.nix;
|
||||||
|
|
||||||
githubFlakes = runNixOSTestFor "x86_64-linux" ./github-flakes.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