Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add an easy way to configure users and groups and /tmp #129

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,39 @@ Function arguments are:
building the layer. This is mainly useful to ignore the
configuration file from the container layer.

### `nix2container.layers.shadow`

Helper to create a layer and quickly customize the users and groups available
inside the container. [Usage example here](./examples/shadow.nix).

Function arguments:

- **`includeRoot`** (defaults to `false`): enable to add a `root` user (uid 0).

- **`users`** (defaults to `[{uname = "somebody"; uid = 1000;}]`): non-root
users configuration. Valid keys are:

- **`uname`**: user name.

- **`uid`**: user id, usually something between 1000 and 3000.

- **`gname`** (defaults to the same as `uname`): main group name.

- **`gid`** (defaults to the same as `gid`): main group id.

- **`home`** (defaults to `/home/${uname}`): user's home dir. It will
belong to `uname` and `gname`, with mode `u=rwx,g=rx,o=`.

- **`shell`** (defaults to `pkgs.runtimeShell`): user's shell.

- **`extraGroups`** (defaults to `[]`): list of attrsets with extra
groups to create in the image and add to the user. Valid keys are `gid`
(optional) and `gname`.

### `nix2container.layers.tmp`

This prebuilt layer will help you to add a working `/tmp` dir to your image.
[Usage example here](./examples/tmp.nix).

## Isolate dependencies in dedicated layers

Expand Down
108 changes: 104 additions & 4 deletions default.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ pkgs ? import <nixpkgs> { }, system }:
{ pkgs ? import <nixpkgs> { }, system ? pkgs.system }:
let
l = pkgs.lib // builtins;

Expand Down Expand Up @@ -477,8 +477,108 @@ let
pkgs.lib.throwIf (contents != null && copyToRoot != null)
"You can not specify both contents and copyToRoot."
;
in
{

# Similar to dockerTools.shadowSetup, but simpler to integrate here
layers.shadow = {
# Enable to include a root user in the container
includeRoot ? false,
# List of users attrsets. Valid keys: see addUser.
users ? [
{
uname = "somebody";
uid = 1000;
}
],
}: let
rootUser = {
uname = "root";
uid = 0;
home = "/root";
};
addGroup = {
gname,
gid ? null,
}: let
gidFlag = l.optionalString (gid != null) "-g ${l.toString gid}";
in ''
groupadd -P $out ${gidFlag} ${gname}
'';
addUser = {
extraGroups ? [], # List of attrsets. Valid keys: see addGroup.
gid ? uid,
gname ? uname,
home ? "/home/${uname}",
shell ? pkgs.runtimeShell,
uid,
uname,
}: let
eG =
l.optionalString (l.length extraGroups > 0)
"-G ${l.concatStringsSep "," extraGroups}";
allGroups = [{inherit gname gid;}] ++ extraGroups;
addAllGroups = l.concatMapStrings addGroup allGroups;
in ''
${addAllGroups}
useradd -P $out -u ${l.toString uid} -g ${l.toString gid} -Md ${home} -s ${shell} ${eG} ${uname}
mkdir -p $out${home}
'';
allUsers = l.optionals includeRoot [rootUser] ++ users;
shadowSetup =
pkgs.runCommand "shadow-setup" {
nativeBuildInputs = [pkgs.shadow];
} ''
mkdir -p $out/etc/pam.d
touch $out/etc/login.defs $out/etc/passwd $out/etc/group

cat > $out/etc/pam.d/other <<EOF
account sufficient pam_unix.so
auth sufficient pam_rootok.so
password requisite pam_unix.so nullok yescrypt
session required pam_unix.so
EOF

${l.concatMapStrings addUser allUsers}
'';
userPerms = {
gid ? uid,
gname ? uname,
home ? "/home/${uname}",
uid,
uname,
...
}: {
inherit gid gname uid uname;
mode = "u=rwx,g=rx,o=";
regex = home;
};
in
buildLayer {
copyToRoot = shadowSetup;
perms = l.forEach allUsers userPerms;
};

layers.tmp = buildLayer {
copyToRoot = pkgs.runCommand "tmp-dir" {
outputHash = "sha256-AVwrjJdGCmzJ8JlT6x69JkHlFlRvOJ4hcqNt10YNoAU=";
outputHashAlgo = "sha256";
outputHashMode = "recursive";
preferLocalBuild = true;
} ''
mkdir -p $out/tmp
'';
perms = [
{ path = "/tmp"; regex = ".*"; mode = "a=rwxt"; }
];
};
in {
inherit nix2container-bin skopeo-nix2container;
nix2container = { inherit buildImage buildLayer pullImage pullImageFromManifest; };
nix2container = {
inherit
buildImage
buildLayer
pullImage
pullImageFromManifest
layers
;
};
}
1 change: 1 addition & 0 deletions examples/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
nix = pkgs.callPackage ./nix.nix { inherit nix2container; };
nix-user = pkgs.callPackage ./nix-user.nix { inherit nix2container; };
ownership = pkgs.callPackage ./ownership.nix { inherit nix2container; };
shadow-tmp = pkgs.callPackage ./shadow-tmp.nix { inherit nix2container; };
}
19 changes: 19 additions & 0 deletions examples/shadow-tmp.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
pkgs,
nix2container,
}:
nix2container.buildImage {
name = "shadow-tmp";
tag = "latest";

layers = [
(nix2container.layers.shadow {includeRoot = true;})
nix2container.layers.tmp
];

copyToRoot = [pkgs.coreutils];

config = {
User = "somebody";
};
}
25 changes: 23 additions & 2 deletions tests/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ let
image,
command ? "",
grepFlags ? "",
runFlags ? "",
pattern,
}: pkgs.writeScriptBin "test-script" ''
${image.copyToPodman}/bin/copy-to-podman
${pkgs.podman}/bin/podman run ${image.imageName}:${image.imageTag} ${command} | ${pkgs.gnugrep}/bin/grep ${grepFlags} '${pattern}'
${pkgs.podman}/bin/podman run ${runFlags} ${image.imageName}:${image.imageTag} ${command} | ${pkgs.gnugrep}/bin/grep ${grepFlags} '${pattern}'
ret=$?
if [ $ret -ne 0 ];
then
Expand Down Expand Up @@ -86,6 +87,27 @@ let
grepFlags = "-Pz";
pattern = "(?s)\[PASS].*\[PASS].*\[PASS].*drwxr-xr-x \\d+ user user 4096 Jan 1 1970 store";
};
shadow-somebody = testScript {
image = examples.shadow-tmp;
command = "id";
pattern = "uid=1000(somebody) gid=1000(somebody) groups=1000(somebody)";
};
shadow-root = testScript {
image = examples.shadow-tmp;
runFlags = "-u root";
command = "id";
pattern = "uid=0(root) gid=0(root) groups=0(root)";
};
tmp-stat = testScript {
image = examples.shadow-tmp;
command = "stat -c %a /tmp";
pattern = "1777";
};
tmp-mktemp = testScript {
image = examples.shadow-tmp;
command = "mktemp";
pattern = "/tmp/tmp.";
};
# Ensure the Nix database is correctly initialized by querying the
# closure of the Nix binary.
# The store path is in a dedicated layer
Expand Down Expand Up @@ -159,4 +181,3 @@ let
${scripts}
'';
in tests // { inherit all; }