From 07d5c061eacec0a3b145947a9b95a11b705ea5d3 Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Sat, 12 Aug 2023 14:26:22 +0200 Subject: [PATCH 1/5] test/system: Test that group and user IDs work These tests assume that the group and user information on the host operating system can be provided by different plugins for the GNU Name Service Switch (or NSS) functionality of the GNU C Library. eg., on enterprise FreeIPA set-ups. However, it's expected that everything inside the Toolbx container will be provided by /etc/group, /etc/passwd, /etc/shadow, etc.. While /etc/group and /etc/passwd can be read by any user, /etc/shadow can only be read by root. However, it's awkward to use sudo(8) in the test cases involving /etc/shadow, because they ensure that root and $USER don't need passwords to authenticate inside the container, and sudo(8) itself depends on that. If sudo(8) is used, the test suite can behave unexpectedly if Toolbx didn't set up the container correctly. eg., it can get blocked waiting for a password. Hence, 'podman unshare' is used instead to enter the container's initial user namespace, where $USER from the host appears as root. This is sufficient because the test cases only need to read /etc/shadow inside the Toolbx container. https://github.com/containers/toolbox/pull/1355 --- test/system/206-user.bats | 520 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 520 insertions(+) create mode 100644 test/system/206-user.bats diff --git a/test/system/206-user.bats b/test/system/206-user.bats new file mode 100644 index 000000000000..fdb2a33da88c --- /dev/null +++ b/test/system/206-user.bats @@ -0,0 +1,520 @@ +# shellcheck shell=bats +# +# Copyright © 2023 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +load 'libs/bats-support/load' +load 'libs/bats-assert/load' +load 'libs/helpers' + +setup() { + bats_require_minimum_version 1.7.0 + _setup_environment + cleanup_containers +} + +teardown() { + cleanup_containers +} + +@test "user: separate namespace" { + local ns_host + ns_host=$(readlink /proc/$$/ns/user) + + create_default_container + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run sh -c 'readlink /proc/$$/ns/user' + + assert_success + assert_line --index 0 --regexp '^user:\[[[:digit:]]+\]$' + refute_line --index 0 "$ns_host" + + if check_bats_version 1.10.0; then + assert [ ${#lines[@]} -eq 1 ] + else + assert [ ${#lines[@]} -eq 2 ] + fi + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: root in shadow(5) inside the default container" { + local default_container + default_container="$(get_system_id)-toolbox-$(get_system_version)" + + create_default_container + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount "$default_container")" + + "$TOOLBOX" run true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount "$default_container" + + assert_success + assert_line --regexp '^root::.+$' + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: root in shadow(5) inside Arch Linux" { + create_distro_container arch latest arch-toolbox-latest + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount arch-toolbox-latest)" + + "$TOOLBOX" run --distro arch true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount arch-toolbox-latest + + assert_success + assert_line --regexp '^root::.+$' + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: root in shadow(5) inside Fedora 34" { + create_distro_container fedora 34 fedora-toolbox-34 + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount fedora-toolbox-34)" + + "$TOOLBOX" run --distro fedora --release 34 true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount fedora-toolbox-34 + + assert_success + assert_line --regexp '^root::.+$' + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: root in shadow(5) inside RHEL 8.7" { + create_distro_container rhel 8.7 rhel-toolbox-8.7 + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount rhel-toolbox-8.7)" + + "$TOOLBOX" run --distro rhel --release 8.7 true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount rhel-toolbox-8.7 + + assert_success + assert_line --regexp '^root::.+$' + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: root in shadow(5) inside Ubuntu 16.04" { + create_distro_container ubuntu 16.04 ubuntu-toolbox-16.04 + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount ubuntu-toolbox-16.04)" + + "$TOOLBOX" run --distro ubuntu --release 16.04 true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount ubuntu-toolbox-16.04 + + assert_success + assert_line --regexp '^root::.+$' + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: root in shadow(5) inside Ubuntu 18.04" { + create_distro_container ubuntu 18.04 ubuntu-toolbox-18.04 + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount ubuntu-toolbox-18.04)" + + "$TOOLBOX" run --distro ubuntu --release 18.04 true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount ubuntu-toolbox-18.04 + + assert_success + assert_line --regexp '^root::.+$' + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: root in shadow(5) inside Ubuntu 20.04" { + create_distro_container ubuntu 20.04 ubuntu-toolbox-20.04 + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount ubuntu-toolbox-20.04)" + + "$TOOLBOX" run --distro ubuntu --release 20.04 true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount ubuntu-toolbox-20.04 + + assert_success + assert_line --regexp '^root::.+$' + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in passwd(5) inside the default container" { + local user_gecos + user_gecos="$(getent passwd "$USER" | cut --delimiter : --fields 5)" + + local user_id_real + user_id_real="$(id --real --user)" + + create_default_container + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run sh -c 'cat /etc/passwd' + + assert_success + assert_line --regexp "^$USER::$user_id_real:$user_id_real:$user_gecos:$HOME:$SHELL$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in passwd(5) inside Arch Linux" { + local user_gecos + user_gecos="$(getent passwd "$USER" | cut --delimiter : --fields 5)" + + local user_id_real + user_id_real="$(id --real --user)" + + create_distro_container arch latest arch-toolbox-latest + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run --distro arch sh -c 'cat /etc/passwd' + + assert_success + assert_line --regexp "^$USER::$user_id_real:$user_id_real:$user_gecos:$HOME:$SHELL$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in passwd(5) inside Fedora 34" { + local user_gecos + user_gecos="$(getent passwd "$USER" | cut --delimiter : --fields 5)" + + local user_id_real + user_id_real="$(id --real --user)" + + create_distro_container fedora 34 fedora-toolbox-34 + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run --distro fedora --release 34 sh -c 'cat /etc/passwd' + + assert_success + assert_line --regexp "^$USER::$user_id_real:$user_id_real:$user_gecos:$HOME:$SHELL$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in passwd(5) inside RHEL 8.7" { + local user_gecos + user_gecos="$(getent passwd "$USER" | cut --delimiter : --fields 5)" + + local user_id_real + user_id_real="$(id --real --user)" + + create_distro_container rhel 8.7 rhel-toolbox-8.7 + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run --distro rhel --release 8.7 sh -c 'cat /etc/passwd' + + assert_success + assert_line --regexp "^$USER::$user_id_real:$user_id_real:$user_gecos:$HOME:$SHELL$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in passwd(5) inside Ubuntu 16.04" { + local user_gecos + user_gecos="$(getent passwd "$USER" | cut --delimiter : --fields 5)" + + local user_id_real + user_id_real="$(id --real --user)" + + create_distro_container ubuntu 16.04 ubuntu-toolbox-16.04 + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run --distro ubuntu --release 16.04 sh -c 'cat /etc/passwd' + + assert_success + assert_line --regexp "^$USER::$user_id_real:$user_id_real:$user_gecos:$HOME:$SHELL$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in passwd(5) inside Ubuntu 18.04" { + local user_gecos + user_gecos="$(getent passwd "$USER" | cut --delimiter : --fields 5)" + + local user_id_real + user_id_real="$(id --real --user)" + + create_distro_container ubuntu 18.04 ubuntu-toolbox-18.04 + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run --distro ubuntu --release 18.04 sh -c 'cat /etc/passwd' + + assert_success + assert_line --regexp "^$USER::$user_id_real:$user_id_real:$user_gecos:$HOME:$SHELL$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in passwd(5) inside Ubuntu 20.04" { + local user_gecos + user_gecos="$(getent passwd "$USER" | cut --delimiter : --fields 5)" + + local user_id_real + user_id_real="$(id --real --user)" + + create_distro_container ubuntu 20.04 ubuntu-toolbox-20.04 + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run --distro ubuntu --release 20.04 sh -c 'cat /etc/passwd' + + assert_success + assert_line --regexp "^$USER::$user_id_real:$user_id_real:$user_gecos:$HOME:$SHELL$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in shadow(5) inside the default container" { + local default_container + default_container="$(get_system_id)-toolbox-$(get_system_version)" + + create_default_container + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount "$default_container")" + + "$TOOLBOX" run true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount "$default_container" + + assert_success + refute_line --regexp "^$USER:.*$" + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in shadow(5) inside Arch Linux" { + create_distro_container arch latest arch-toolbox-latest + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount arch-toolbox-latest)" + + "$TOOLBOX" run --distro arch true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount arch-toolbox-latest + + assert_success + refute_line --regexp "^$USER:.*$" + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in shadow(5) inside Fedora 34" { + create_distro_container fedora 34 fedora-toolbox-34 + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount fedora-toolbox-34)" + + "$TOOLBOX" run --distro fedora --release 34 true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount fedora-toolbox-34 + + assert_success + refute_line --regexp "^$USER:.*$" + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in shadow(5) inside RHEL 8.7" { + create_distro_container rhel 8.7 rhel-toolbox-8.7 + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount rhel-toolbox-8.7)" + + "$TOOLBOX" run --distro rhel --release 8.7 true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount rhel-toolbox-8.7 + + assert_success + refute_line --regexp "^$USER:.*$" + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in shadow(5) inside Ubuntu 16.04" { + create_distro_container ubuntu 16.04 ubuntu-toolbox-16.04 + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount ubuntu-toolbox-16.04)" + + "$TOOLBOX" run --distro ubuntu --release 16.04 true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount ubuntu-toolbox-16.04 + + assert_success + refute_line --regexp "^$USER:.*$" + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in shadow(5) inside Ubuntu 18.04" { + create_distro_container ubuntu 18.04 ubuntu-toolbox-18.04 + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount ubuntu-toolbox-18.04)" + + "$TOOLBOX" run --distro ubuntu --release 18.04 true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount ubuntu-toolbox-18.04 + + assert_success + refute_line --regexp "^$USER:.*$" + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in shadow(5) inside Ubuntu 20.04" { + create_distro_container ubuntu 20.04 ubuntu-toolbox-20.04 + container_root_file_system="$("$PODMAN" unshare "$PODMAN" mount ubuntu-toolbox-20.04)" + + "$TOOLBOX" run --distro ubuntu --release 20.04 true + + run --keep-empty-lines --separate-stderr "$PODMAN" unshare cat "$container_root_file_system/etc/shadow" + "$PODMAN" unshare "$PODMAN" unmount ubuntu-toolbox-20.04 + + assert_success + refute_line --regexp "^$USER:.*$" + assert [ ${#lines[@]} -gt 0 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in group(5) inside the default container" { + create_default_container + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run sh -c 'cat /etc/group' + + assert_success + assert_line --regexp "^(sudo|wheel):x:[[:digit:]]+:$USER$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in group(5) inside Arch Linux" { + create_distro_container arch latest arch-toolbox-latest + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run --distro arch sh -c 'cat /etc/group' + + assert_success + assert_line --regexp "^wheel:x:[[:digit:]]+:$USER$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in group(5) inside Fedora 34" { + create_distro_container fedora 34 fedora-toolbox-34 + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run --distro fedora --release 34 sh -c 'cat /etc/group' + + assert_success + assert_line --regexp "^wheel:x:[[:digit:]]+:$USER$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in group(5) inside RHEL 8.7" { + create_distro_container rhel 8.7 rhel-toolbox-8.7 + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run --distro rhel --release 8.7 sh -c 'cat /etc/group' + + assert_success + assert_line --regexp "^wheel:x:[[:digit:]]+:$USER$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in group(5) inside Ubuntu 16.04" { + create_distro_container ubuntu 16.04 ubuntu-toolbox-16.04 + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run --distro ubuntu --release 16.04 sh -c 'cat /etc/group' + + assert_success + assert_line --regexp "^sudo:x:[[:digit:]]+:$USER$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in group(5) inside Ubuntu 18.04" { + create_distro_container ubuntu 18.04 ubuntu-toolbox-18.04 + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run --distro ubuntu --release 18.04 sh -c 'cat /etc/group' + + assert_success + assert_line --regexp "^sudo:x:[[:digit:]]+:$USER$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "user: $USER in group(5) inside Ubuntu 20.04" { + create_distro_container ubuntu 20.04 ubuntu-toolbox-20.04 + + run --keep-empty-lines --separate-stderr "$TOOLBOX" run --distro ubuntu --release 20.04 sh -c 'cat /etc/group' + + assert_success + assert_line --regexp "^sudo:x:[[:digit:]]+:$USER$" + assert [ ${#lines[@]} -gt 1 ] + + # shellcheck disable=SC2154 + assert [ ${#stderr_lines[@]} -eq 0 ] +} -- 2.41.0 From 22ba72f3152650d538437bf298ebde4a63e2adc9 Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Wed, 4 Nov 2020 00:55:31 +0100 Subject: [PATCH 2/5] Deprecate the --monitor-host option of 'init-container' The --monitor-host option was added to the 'init-container' command in commit 8b84b5e4604921fa to accommodate Podman versions older than 1.2.0 that didn't have the '--dns none' and '--no-hosts' options for 'podman create'. These options are necessary to keep the Toolbx container's /etc/resolv.conf and /etc/hosts files synchronized with those of the host. Note that Podman 1.2.0 was already available a few months before commit 8b84b5e4604921fa introduced the --monitor-host option. The chances of someone using an older Podman back then was already on the decline, and it's very unlikely that a container created with such a Podman has survived till this date. Commit b6b484fa792b442a raised the minimum required Podman version to 1.4.0, and made the '--dns none' and '--no-hosts' options a hard requirement. The minimum required Podman version was again raised recently in commit 8e80dd5db1e6f40b to 1.6.4. Therefore, these days, there's no need to separately use the --monitor-host option of 'init-container' for newly created containers to indicate that the Podman version wasn't older than 1.2.0. Given all this, it's time to stop using the --monitor-host option of 'init-container', and assume that it's always set. The option is still accepted to retain compatibility with existing Toolbx containers. For containers that were created with the --monitor-host option, a deprecation notice will be shown as: $ podman start --attach CONTAINER Flag --monitor-host has been deprecated, it does nothing ... https://github.com/containers/toolbox/pull/617 --- doc/toolbox-init-container.1.md | 32 +++--------- src/cmd/create.go | 1 - src/cmd/initContainer.go | 86 ++++++++++++++++----------------- 3 files changed, 49 insertions(+), 70 deletions(-) diff --git a/doc/toolbox-init-container.1.md b/doc/toolbox-init-container.1.md index 45c9a77939f2..51a7b1ee643d 100644 --- a/doc/toolbox-init-container.1.md +++ b/doc/toolbox-init-container.1.md @@ -9,7 +9,6 @@ toolbox\-init\-container - Initialize a running container *--home-link* *--media-link* *--mnt-link* - *--monitor-host* *--shell SHELL* *--uid UID* *--user USER* @@ -76,31 +75,12 @@ Make `/mnt` a symbolic link to `/var/mnt`. **--monitor-host** -Ensures that certain configuration files inside the toolbox container are kept -synchronized with their counterparts on the host, and bind mounts some paths -from the host's file system into the container. - -The synchronized files are: - -- `/etc/host.conf` -- `/etc/hosts` -- `/etc/localtime` -- `/etc/resolv.conf` -- `/etc/timezone` - -The bind mounted paths are: - -- `/etc/machine-id` -- `/run/libvirt` -- `/run/systemd/journal` -- `/run/systemd/resolve` -- `/run/udev/data` -- `/tmp` -- `/var/lib/flatpak` -- `/var/lib/libvirt` -- `/var/lib/systemd/coredump` -- `/var/log/journal` -- `/var/mnt` +Deprecated, does nothing. + +Crucial configuration files inside the toolbox container are always kept +synchronized with their counterparts on the host, and various subsets of the +host's file system hierarchy are always bind mounted to their corresponding +locations inside the toolbox container. **--shell** SHELL diff --git a/src/cmd/create.go b/src/cmd/create.go index 2a103f01ed2d..6cec99258847 100644 --- a/src/cmd/create.go +++ b/src/cmd/create.go @@ -393,7 +393,6 @@ func createContainer(container, image, release, authFile string, showCommandToEn "--shell", userShell, "--uid", currentUser.Uid, "--user", currentUser.Username, - "--monitor-host", } entryPoint = append(entryPoint, slashHomeLink...) diff --git a/src/cmd/initContainer.go b/src/cmd/initContainer.go index c4cd1b02d298..cb132bffc817 100644 --- a/src/cmd/initContainer.go +++ b/src/cmd/initContainer.go @@ -107,8 +107,12 @@ func init() { flags.BoolVar(&initContainerFlags.monitorHost, "monitor-host", - false, - "Ensure that certain configuration files inside the toolbox container are in sync with the host") + true, + "Deprecated, does nothing") + if err := flags.MarkDeprecated("monitor-host", "it does nothing"); err != nil { + panicMsg := fmt.Sprintf("cannot mark --monitor-host as deprecated: %s", err) + panic(panicMsg) + } flags.StringVar(&initContainerFlags.shell, "shell", @@ -163,59 +167,55 @@ func initContainer(cmd *cobra.Command, args []string) error { defer toolboxEnvFile.Close() - if initContainerFlags.monitorHost { - logrus.Debug("Monitoring host") - - if utils.PathExists("/run/host/etc") { - logrus.Debug("Path /run/host/etc exists") - - if _, err := os.Readlink("/etc/host.conf"); err != nil { - if err := redirectPath("/etc/host.conf", - "/run/host/etc/host.conf", - false); err != nil { - return err - } - } + if utils.PathExists("/run/host/etc") { + logrus.Debug("Path /run/host/etc exists") - if _, err := os.Readlink("/etc/hosts"); err != nil { - if err := redirectPath("/etc/hosts", - "/run/host/etc/hosts", - false); err != nil { - return err - } + if _, err := os.Readlink("/etc/host.conf"); err != nil { + if err := redirectPath("/etc/host.conf", + "/run/host/etc/host.conf", + false); err != nil { + return err } + } - if localtimeTarget, err := os.Readlink("/etc/localtime"); err != nil || - localtimeTarget != "/run/host/etc/localtime" { - if err := redirectPath("/etc/localtime", - "/run/host/etc/localtime", - false); err != nil { - return err - } + if _, err := os.Readlink("/etc/hosts"); err != nil { + if err := redirectPath("/etc/hosts", + "/run/host/etc/hosts", + false); err != nil { + return err } + } - if err := updateTimeZoneFromLocalTime(); err != nil { + if localtimeTarget, err := os.Readlink("/etc/localtime"); err != nil || + localtimeTarget != "/run/host/etc/localtime" { + if err := redirectPath("/etc/localtime", + "/run/host/etc/localtime", + false); err != nil { return err } + } + + if err := updateTimeZoneFromLocalTime(); err != nil { + return err + } - if _, err := os.Readlink("/etc/resolv.conf"); err != nil { - if err := redirectPath("/etc/resolv.conf", - "/run/host/etc/resolv.conf", - false); err != nil { - return err - } + if _, err := os.Readlink("/etc/resolv.conf"); err != nil { + if err := redirectPath("/etc/resolv.conf", + "/run/host/etc/resolv.conf", + false); err != nil { + return err } + } - for _, mount := range initContainerMounts { - if err := mountBind(mount.containerPath, mount.source, mount.flags); err != nil { - return err - } + for _, mount := range initContainerMounts { + if err := mountBind(mount.containerPath, mount.source, mount.flags); err != nil { + return err } + } - if utils.PathExists("/sys/fs/selinux") { - if err := mountBind("/sys/fs/selinux", "/usr/share/empty", ""); err != nil { - return err - } + if utils.PathExists("/sys/fs/selinux") { + if err := mountBind("/sys/fs/selinux", "/usr/share/empty", ""); err != nil { + return err } } } -- 2.41.0 From 66a791ff10234023b858b7a28dd98985b054eca1 Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Tue, 7 Mar 2023 16:13:04 +0100 Subject: [PATCH 3/5] cmd/initContainer: Bind mount locations regardless of /run/host/etc Bind mounting the locations at runtime doesn't really have anything to do with whether /run/host/etc is present inside the Toolbx container. The only possible exception could have been /etc/machine-id, but it isn't, because the bind mount is only performed if the source at /run/host/etc/machine-id is present. This is a historical mistake that has persisted for a long time, since, in practice, /run/host/etc will almost always exist inside the Toolbx container. It's time to finally correct it. Fallout from 9436bbece01d7aa4dc91b4013ed9f80d0b8d34f4 https://github.com/containers/toolbox/pull/1255 --- src/cmd/initContainer.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/cmd/initContainer.go b/src/cmd/initContainer.go index cb132bffc817..153e5ccb824e 100644 --- a/src/cmd/initContainer.go +++ b/src/cmd/initContainer.go @@ -206,18 +206,6 @@ func initContainer(cmd *cobra.Command, args []string) error { return err } } - - for _, mount := range initContainerMounts { - if err := mountBind(mount.containerPath, mount.source, mount.flags); err != nil { - return err - } - } - - if utils.PathExists("/sys/fs/selinux") { - if err := mountBind("/sys/fs/selinux", "/usr/share/empty", ""); err != nil { - return err - } - } } if initContainerFlags.mediaLink { @@ -236,6 +224,18 @@ func initContainer(cmd *cobra.Command, args []string) error { } } + for _, mount := range initContainerMounts { + if err := mountBind(mount.containerPath, mount.source, mount.flags); err != nil { + return err + } + } + + if utils.PathExists("/sys/fs/selinux") { + if err := mountBind("/sys/fs/selinux", "/usr/share/empty", ""); err != nil { + return err + } + } + if _, err := user.Lookup(initContainerFlags.user); err != nil { if err := configureUsers(initContainerFlags.uid, initContainerFlags.user, -- 2.41.0 From d416f1b4abd0782526c011b078442856c733e718 Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Tue, 15 Aug 2023 20:57:46 +0200 Subject: [PATCH 4/5] cmd/initContainer: Simplify code by removing a function parameter Until now, configureUsers() was pushing the burden of deciding whether to add a new user or modify an existing one on the callers, even though it can trivially decide itself. Involving the caller loosens the encapsulation of the user configuration logic by spreading it across configureUsers() and it's caller, and adds an extra function parameter that needs to be carefully set and is vulnerable to programmer errors. Fallout from 9ea6fe5852ea8f5225114d825e8e6813e2a3cfea https://github.com/containers/toolbox/pull/1356 --- src/cmd/initContainer.go | 62 ++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/src/cmd/initContainer.go b/src/cmd/initContainer.go index 153e5ccb824e..02c389635378 100644 --- a/src/cmd/initContainer.go +++ b/src/cmd/initContainer.go @@ -236,24 +236,12 @@ func initContainer(cmd *cobra.Command, args []string) error { } } - if _, err := user.Lookup(initContainerFlags.user); err != nil { - if err := configureUsers(initContainerFlags.uid, - initContainerFlags.user, - initContainerFlags.home, - initContainerFlags.shell, - initContainerFlags.homeLink, - false); err != nil { - return err - } - } else { - if err := configureUsers(initContainerFlags.uid, - initContainerFlags.user, - initContainerFlags.home, - initContainerFlags.shell, - initContainerFlags.homeLink, - true); err != nil { - return err - } + if err := configureUsers(initContainerFlags.uid, + initContainerFlags.user, + initContainerFlags.home, + initContainerFlags.shell, + initContainerFlags.homeLink); err != nil { + return err } if utils.PathExists("/etc/krb5.conf.d") && !utils.PathExists("/etc/krb5.conf.d/kcm_default_ccache") { @@ -386,9 +374,7 @@ func initContainerHelp(cmd *cobra.Command, args []string) { } } -func configureUsers(targetUserUid int, - targetUser, targetUserHome, targetUserShell string, - homeLink, targetUserExists bool) error { +func configureUsers(targetUserUid int, targetUser, targetUserHome, targetUserShell string, homeLink bool) error { if homeLink { if err := redirectPath("/home", "/var/home", true); err != nil { return err @@ -400,45 +386,45 @@ func configureUsers(targetUserUid int, return fmt.Errorf("failed to get group for sudo: %w", err) } - if targetUserExists { - logrus.Debugf("Modifying user %s with UID %d:", targetUser, targetUserUid) + if _, err := user.Lookup(targetUser); err != nil { + logrus.Debugf("Adding user %s with UID %d:", targetUser, targetUserUid) - usermodArgs := []string{ - "--append", + useraddArgs := []string{ "--groups", sudoGroup, - "--home", targetUserHome, + "--home-dir", targetUserHome, + "--no-create-home", "--shell", targetUserShell, "--uid", fmt.Sprint(targetUserUid), targetUser, } - logrus.Debug("usermod") - for _, arg := range usermodArgs { + logrus.Debug("useradd") + for _, arg := range useraddArgs { logrus.Debugf("%s", arg) } - if err := shell.Run("usermod", nil, nil, nil, usermodArgs...); err != nil { - return fmt.Errorf("failed to modify user %s with UID %d: %w", targetUser, targetUserUid, err) + if err := shell.Run("useradd", nil, nil, nil, useraddArgs...); err != nil { + return fmt.Errorf("failed to add user %s with UID %d: %w", targetUser, targetUserUid, err) } } else { - logrus.Debugf("Adding user %s with UID %d:", targetUser, targetUserUid) + logrus.Debugf("Modifying user %s with UID %d:", targetUser, targetUserUid) - useraddArgs := []string{ + usermodArgs := []string{ + "--append", "--groups", sudoGroup, - "--home-dir", targetUserHome, - "--no-create-home", + "--home", targetUserHome, "--shell", targetUserShell, "--uid", fmt.Sprint(targetUserUid), targetUser, } - logrus.Debug("useradd") - for _, arg := range useraddArgs { + logrus.Debug("usermod") + for _, arg := range usermodArgs { logrus.Debugf("%s", arg) } - if err := shell.Run("useradd", nil, nil, nil, useraddArgs...); err != nil { - return fmt.Errorf("failed to add user %s with UID %d: %w", targetUser, targetUserUid, err) + if err := shell.Run("usermod", nil, nil, nil, usermodArgs...); err != nil { + return fmt.Errorf("failed to modify user %s with UID %d: %w", targetUser, targetUserUid, err) } } -- 2.41.0 From e673dc792438c64683237d26b21d005ffb008fd5 Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Tue, 22 Aug 2023 23:29:43 +0200 Subject: [PATCH 5/5] cmd/initContainer: Simplify removing the user's password It's one less invocation of an external command, which is good because spawning a new process is generally expensive. One positive side-effect of this is that on some Active Directory set-ups, the entry point no longer fails with: Error: failed to remove password for user login@company.com: failed to invoke passwd(1) ... because of: # passwd --delete login@company.com passwd: Libuser error at line: 210 - name contains invalid char `@'. This is purely an accident, and isn't meant to be an intential change to support Active Directory. Tools like useradd(8) and usermod(8) from Shadow aren't meant to work with Active Directory users, and, hence, it can still break in other ways. For that, one option is to expose $USER from the host operating system to the Toolbx container through a Varlink interface that can be used by nss-systemd inside the container. Based on an idea from Si. https://github.com/containers/toolbox/issues/585 --- src/cmd/initContainer.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/cmd/initContainer.go b/src/cmd/initContainer.go index 02c389635378..91b53cee7d0d 100644 --- a/src/cmd/initContainer.go +++ b/src/cmd/initContainer.go @@ -393,6 +393,7 @@ func configureUsers(targetUserUid int, targetUser, targetUserHome, targetUserShe "--groups", sudoGroup, "--home-dir", targetUserHome, "--no-create-home", + "--password", "", "--shell", targetUserShell, "--uid", fmt.Sprint(targetUserUid), targetUser, @@ -413,6 +414,7 @@ func configureUsers(targetUserUid int, targetUser, targetUserHome, targetUserShe "--append", "--groups", sudoGroup, "--home", targetUserHome, + "--password", "", "--shell", targetUserShell, "--uid", fmt.Sprint(targetUserUid), targetUser, @@ -428,12 +430,6 @@ func configureUsers(targetUserUid int, targetUser, targetUserHome, targetUserShe } } - logrus.Debugf("Removing password for user %s", targetUser) - - if err := shell.Run("passwd", nil, nil, nil, "--delete", targetUser); err != nil { - return fmt.Errorf("failed to remove password for user %s: %w", targetUser, err) - } - logrus.Debug("Removing password for user root") if err := shell.Run("passwd", nil, nil, nil, "--delete", "root"); err != nil { -- 2.41.0