- Initialize state dirs and users at container launch to work with shared volumes

- Use chainloading to change user permissions
- Allow shared Nix store paths in the PATH environment variable
This commit is contained in:
Sander van der Burg 2021-03-27 15:46:11 +01:00 committed by Sander van der Burg
parent 219cd6d639
commit 8d8dbcc8ad
4 changed files with 60 additions and 52 deletions

View File

@ -8,6 +8,7 @@
, useHostNetwork ? false
, mapStateDirVolumes ? []
, cmd ? ""
, environment ? {}
, storePaths ? []
, dependencies ? []
, postInstall ? ""
@ -22,7 +23,7 @@ let
_dockerCreateParameters = dockerCreateParametersList
++ lib.optional useHostNixStore { name = "volume"; value = "/nix/store:/nix/store"; }
++ lib.optional useHostNetwork { name = "network"; value = "host"; }
++ map (mapStateDirVolume: { name = "volume"; value = "${mapStateDirVolume}:${mapStateDirVolume}"; }) mapStateDirVolumes;
++ map (mapStateDirVolume: { name = "volume"; value = "${mapStateDirVolume}:${mapStateDirVolume}:z"; }) mapStateDirVolumes;
priority = if dependencies == [] then 1
else builtins.head (builtins.sort (a: b: a > b) (map (dependency: dependency.priority) dependencies)) + 1;

View File

@ -1,4 +1,4 @@
{ createDockerContainer, dockerTools, stdenv, lib, writeTextFile, findutils, glibc, dysnomia, basePackages, runtimeDir, stateDir, forceDisableUserChange, createCredentials }:
{ createDockerContainer, dockerTools, stdenv, lib, writeTextFile, findutils, glibc, shadow, dysnomia, pkgs, basePackages, runtimeDir, stateDir, forceDisableUserChange, createCredentials }:
{ name
, description
@ -22,7 +22,6 @@
}:
# TODO:
# umask unsupported
# nice unsupported
let
@ -30,7 +29,9 @@ let
inherit lib;
};
commonTools = (import ../../../tools {}).common;
commonTools = (import ../../../tools {
inherit pkgs;
}).common;
generateForegroundProxy = import ../util/generate-foreground-proxy.nix {
inherit stdenv lib writeTextFile;
@ -40,31 +41,43 @@ let
inherit user forceDisableUserChange;
};
_initialize =
''
nixproc-init-state --state-dir ${stateDir} --runtime-dir ${runtimeDir}
''
+ lib.optionalString (!forceDisableUserChange && credentialsSpec != null) ''
dysnomia-addgroups ${credentialsSpec}
dysnomia-addusers ${credentialsSpec}
''
+ lib.optionalString (umask != null) ''
umask ${umask}
''
+ initialize;
cmd = if foregroundProcess != null
then
if initialize == ""
then [ foregroundProcess ] ++ foregroundProcessArgs
else
let
wrapper = generateForegroundProxy ({
wrapDaemon = false;
executable = foregroundProcess;
user = _user;
inherit name initialize runtimeDir stdenv;
} // lib.optionalAttrs (instanceName != null) {
inherit instanceName;
} // lib.optionalAttrs (pidFile != null) {
inherit pidFile;
});
in
[ wrapper ] ++ foregroundProcessArgs
let
wrapper = generateForegroundProxy ({
wrapDaemon = false;
executable = foregroundProcess;
user = _user;
initialize = _initialize;
inherit name runtimeDir stdenv;
} // lib.optionalAttrs (instanceName != null) {
inherit instanceName;
} // lib.optionalAttrs (pidFile != null) {
inherit pidFile;
});
in
[ wrapper ] ++ foregroundProcessArgs
else
let
wrapper = generateForegroundProxy ({
wrapDaemon = true;
executable = daemon;
user = _user;
inherit name runtimeDir initialize stdenv;
initialize = _initialize;
inherit name runtimeDir stdenv;
} // lib.optionalAttrs (instanceName != null) {
inherit instanceName;
} // lib.optionalAttrs (pidFile != null) {
@ -77,9 +90,17 @@ let
# Instead, we mount the host system's Nix store so that the software is still accessible inside the container.
cmdWithoutContext = map (arg: if builtins.isAttrs arg then builtins.unsafeDiscardStringContext arg else toString arg) cmd;
# Add all packes added to PATH to the store paths making it possible to not
# garbage collect them, but discard their context so that the packages are
# not included in the image
storePaths = basePackages ++ [ commonTools ]
++ lib.optionals (!forceDisableUserChange && credentialsSpec != null) [ shadow findutils glibc.bin dysnomia ]
++ path;
_environment = util.appendPathToEnvironment {
inherit environment;
path = basePackages ++ path ++ [ "/" ]; # Also give permission to /bin to allow any package added to contents can be used
path = map (pathComponent: if builtins.isAttrs pathComponent then builtins.unsafeDiscardStringContext pathComponent else toString pathComponent) storePaths
++ [ "" ]; # Also give permission to /bin to allow any package added to contents can be used
};
credentialsSpec = createCredentials credentials;
@ -88,9 +109,19 @@ let
inherit name;
tag = "latest";
runAsRoot = import ../docker/setup.nix {
inherit dockerTools commonTools lib dysnomia findutils glibc stateDir runtimeDir forceDisableUserChange credentialsSpec;
};
runAsRoot = ''
${dockerTools.shadowSetup}
# Always create these global state directories, because they are needed quite often
mkdir -p /run /tmp
chmod 1777 /tmp
mkdir -p /var
ln -sfn /run /var/run
''
+ lib.optionalString forceDisableUserChange ''
groupadd -r nogroup
useradd -r nobody -g nogroup -d /dev/null
'';
config = {
Cmd = cmdWithoutContext;
@ -98,8 +129,6 @@ let
Env = map (varName: "${varName}=${toString (builtins.getAttr varName _environment)}") (builtins.attrNames _environment);
} // lib.optionalAttrs (directory != null) {
WorkingDir = directory;
} // lib.optionalAttrs (_user != null && initialize == "") {
User = _user;
};
};
@ -113,7 +142,7 @@ let
dockerImage = dockerTools.buildImage dockerImageArgs;
generatedDockerContainerArgs = {
inherit name dockerImage postInstall cmd dependencies;
inherit name dockerImage postInstall cmd storePaths dependencies;
dockerImageTag = "${name}:latest";
useHostNixStore = true;
useHostNetwork = true;

View File

@ -1,23 +0,0 @@
{dockerTools, commonTools, lib, dysnomia, findutils, glibc, stateDir, runtimeDir, forceDisableUserChange, credentialsSpec}:
''
${dockerTools.shadowSetup}
# Always create these global state directories, because they are needed quite often
mkdir -p /run /tmp
chmod 1777 /tmp
# Initialize common state directories
${commonTools}/bin/nixproc-init-state --state-dir ${stateDir} --runtime-dir ${runtimeDir}
${lib.optionalString (!forceDisableUserChange && credentialsSpec != null) ''
export PATH=$PATH:${findutils}/bin:${glibc.bin}/bin
${dysnomia}/bin/dysnomia-addgroups ${credentialsSpec}
${dysnomia}/bin/dysnomia-addusers ${credentialsSpec}
''}
${lib.optionalString forceDisableUserChange ''
groupadd -r nogroup
useradd -r nobody -g nogroup -d /dev/null
''}
''

View File

@ -99,8 +99,9 @@ let
};
generateDockerContainer = import ../../backends/docker/generate-docker-container.nix {
inherit (pkgs) stdenv writeTextFile lib dockerTools findutils glibc dysnomia;
inherit (pkgs) stdenv writeTextFile lib dockerTools findutils glibc dysnomia shadow;
inherit createDockerContainer basePackages runtimeDir stateDir forceDisableUserChange createCredentials;
inherit pkgs;
};
s6-rc = import ../../backends/s6-rc {