From 2f47be10b4f278cb5230e476b547c76d780f4e9e Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Wed, 16 Mar 2022 14:36:20 -0700 Subject: [PATCH 1/5] override root homedir in /etc/passwd * using only `HOME` envvar to override homedir causes mismatches with anything that asks for it a different way (eg, `echo ~root`) * kicking the can down the road on "why are we overriding /root as root's homedir anyway?" --- Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 91282d779..ca64c50a6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,7 +35,8 @@ RUN /output/install-from-bindep \ # In OpenShift, container will run as a random uid number and gid 0. Make sure things # are writeable by the root group. -RUN for dir in \ +RUN sed -i 's/:root:\/root:/:root:\/home\/runner:/g' /etc/passwd \ + && for dir in \ /home/runner \ /home/runner/.ansible \ /home/runner/.ansible/tmp \ @@ -54,8 +55,6 @@ RUN for dir in \ WORKDIR /runner -ENV HOME=/home/runner - ADD utils/entrypoint.sh /bin/entrypoint RUN chmod +x /bin/entrypoint From 56981836831779219cca6ee4275e885e7e74a53e Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Thu, 17 Mar 2022 19:56:43 -0700 Subject: [PATCH 2/5] more dynamic homedir handling --- Dockerfile | 3 +-- utils/entrypoint.sh | 66 +++++++++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/Dockerfile b/Dockerfile index ca64c50a6..723e6416f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,8 +35,7 @@ RUN /output/install-from-bindep \ # In OpenShift, container will run as a random uid number and gid 0. Make sure things # are writeable by the root group. -RUN sed -i 's/:root:\/root:/:root:\/home\/runner:/g' /etc/passwd \ - && for dir in \ +RUN for dir in \ /home/runner \ /home/runner/.ansible \ /home/runner/.ansible/tmp \ diff --git a/utils/entrypoint.sh b/utils/entrypoint.sh index bf85971da..6fe6210bd 100755 --- a/utils/entrypoint.sh +++ b/utils/entrypoint.sh @@ -1,29 +1,55 @@ #!/usr/bin/env bash -# In OpenShift, containers are run as a random high number uid -# that doesn't exist in /etc/passwd, but Ansible module utils -# require a named user. So if we're in OpenShift, we need to make -# one before Ansible runs. -if [[ (`id -u` -ge 500 || -z "${CURRENT_UID}") ]]; then - - # Only needed for RHEL 8. Try deleting this conditional (not the code) - # sometime in the future. Seems to be fixed on Fedora 32 - # If we are running in rootless podman, this file cannot be overwritten - ROOTLESS_MODE=$(cat /proc/self/uid_map | head -n1 | awk '{ print $2; }') - if [[ "$ROOTLESS_MODE" -eq "0" ]]; then -cat << EOF > /etc/passwd -root:x:0:0:root:/root:/bin/bash -runner:x:`id -u`:`id -g`:,,,:/home/runner:/bin/bash -EOF - fi +# We need to fix a number of problems here that manifest under different container runtimes. If we're running +# as a legit default user that has an entry in /etc/passwd and a valid homedir that's not `/`, we're all good. +# If the username/uid we're running under is not represented in /etc/passwd and/or doesn't have a homedir that's not +# `/` (eg, the container was run with --user and some dynamic unmapped UID from the host with primary GID 0), we need to +# correct that. Some things (eg podman/cri-o today) already create an /etc/passwd entry on the fly in this case, but +# they set the homedir to `/`, which causes potential collisions with mounted/mapped volumes. For consistency, we'll +# just always set every dynamically-created user's homedir to `/home/runner`, which we've already configured in a way +# that should always work (eg, ug+rwx and all dirs owned by the root group). + +# if current user is not listed in /etc/passwd, add an entry with username==uid, primary gid 0, and homedir /home/runner + +# if current user is in /etc/passwd but $HOME == `/`, rewrite that user's homedir in /etc/passwd to /home/runner and +# export HOME=/home/runner for this session only- all new sessions, eg created by exec, should set HOME to match the +# current value in /etc/passwd going forward. + +# if any of this business fails, we probably want to fail fast +if [ -n "$EP_DEBUG" ]; then + set -eux + echo 'hello from entrypoint' +else + set -e +fi + +# FIXME junk output +if ! getent passwd $(whoami || id -u) ; then + if [ -n "$EP_DEBUG" ]; then + echo "hacking missing uid $(id -u) into /etc/passwd" + fi + echo "$(id -u):x:$(id -u):0:container user $(id -u):/home/runner:/bin/bash" >> /etc/passwd + export HOME=/home/runner +fi -cat < /etc/group -root:x:0:runner -runner:x:`id -g`: -EOF +# FIXME junk output +MYHOME=`getent passwd $(whoami) | cut -d: -f6` +# FIXME: we also want to check the case of a generated user who podman set their homedir to WORKDIR; maybe anything with a high UID, or ? +if [ "$MYHOME" != "$HOME" ] || [ $(id -u) -ge 500 ] && [ "$MYHOME" != "/home/runner" ]; then + if [ -n "$EP_DEBUG" ]; then + echo "replacing homedir for user $(whoami)" + fi + # sed -i wants to create a tempfile next to the original, which won't work with /etc permissions in many cases, + # so just do it in memory and overwrite the existing file if we succeeded + NEWPW=$(sed -r "s/(^$(whoami):(.*:){4})(.*:)/\1\/home\/runner:/g" /etc/passwd) + echo "$NEWPW" > /etc/passwd + # ensure the envvar matches what we just set in /etc/passwd for this session; future sessions set automatically + export HOME=/home/runner fi +# FIXME: validate group entries? + if [[ -n "${LAUNCHED_BY_RUNNER}" ]]; then # Special actions to be compatible with old ansible-runner versions, 2.1.x specifically RUNNER_CALLBACKS=$(python3 -c "from ansible_runner.display_callback.callback import awx_display; print(awx_display.__file__)") From 8021e9b2ca6b4cf1cee9159dc8ba8c2a4dbf0262 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Tue, 26 Apr 2022 14:56:44 -0700 Subject: [PATCH 3/5] just make everybody's home /home/runner --- utils/entrypoint.sh | 47 ++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/utils/entrypoint.sh b/utils/entrypoint.sh index 6fe6210bd..391665858 100755 --- a/utils/entrypoint.sh +++ b/utils/entrypoint.sh @@ -1,19 +1,30 @@ #!/usr/bin/env bash -# We need to fix a number of problems here that manifest under different container runtimes. If we're running -# as a legit default user that has an entry in /etc/passwd and a valid homedir that's not `/`, we're all good. -# If the username/uid we're running under is not represented in /etc/passwd and/or doesn't have a homedir that's not -# `/` (eg, the container was run with --user and some dynamic unmapped UID from the host with primary GID 0), we need to -# correct that. Some things (eg podman/cri-o today) already create an /etc/passwd entry on the fly in this case, but -# they set the homedir to `/`, which causes potential collisions with mounted/mapped volumes. For consistency, we'll -# just always set every dynamically-created user's homedir to `/home/runner`, which we've already configured in a way -# that should always work (eg, ug+rwx and all dirs owned by the root group). +# We need to fix a number of problems here that manifest under different container runtimes, as well as paper over some +# things to simplify runner's containerized launch behavior. Since runner currently always expects to bind-mount its +# callback plugins under ~/.ansible, it must have prior knowledge of the user's homedir before the container is launched +# in order to know where to mount in the callback dir. In all cases, we must get a consistent answer from $HOME +# and anything that queries /etc/passwd for a homedir (eg, `~root`), or lots of things (including parts of Ansible +# core itself) will be broken. -# if current user is not listed in /etc/passwd, add an entry with username==uid, primary gid 0, and homedir /home/runner +# If we're running as a legit default user that has an entry in /etc/passwd and a valid homedir, we're all good. -# if current user is in /etc/passwd but $HOME == `/`, rewrite that user's homedir in /etc/passwd to /home/runner and -# export HOME=/home/runner for this session only- all new sessions, eg created by exec, should set HOME to match the -# current value in /etc/passwd going forward. +# If the username/uid we're running under is not represented in /etc/passwd or the current user's homedir is something +# other than /home/runner (eg, the container was run with --user and some dynamic unmapped UID from the host with +# primary GID 0), we need to correct that in order for ansible-runner's callbacks to function properly. Some things +# (eg podman/cri-o today) already create an /etc/passwd entry on the fly in this case, but they set the homedir to +# WORKDIR, which causes potential collisions with mounted/mapped volumes. For consistency, we'll +# just always set the current user's homedir to `/home/runner`, which we've already configured in a way +# that should always work with known container runtimes (eg, ug+rwx and all dirs owned by the root group). + +# If current user is not listed in /etc/passwd, add an entry with username==uid, primary gid 0, and homedir /home/runner + +# If current user is in /etc/passwd but $HOME != `/home/runner`, rewrite that user's homedir in /etc/passwd to +# /home/runner and export HOME=/home/runner for this session only. All new sessions (eg podman exec) should +# automatically set HOME to the value in /etc/passwd going forward. + +# Ideally in the future, we can come up with a better way for the outer runner to dynamically inject its callbacks, or +# rely on the inner runner's copy. This would allow us to restore the typical POSIX user homedir conventions. # if any of this business fails, we probably want to fail fast if [ -n "$EP_DEBUG" ]; then @@ -23,20 +34,18 @@ else set -e fi -# FIXME junk output -if ! getent passwd $(whoami || id -u) ; then +# current user might not exist in /etc/passwd at all +if ! $(whoami &> /dev/null) || ! getent passwd $(whoami || id -u) &> /dev/null ; then if [ -n "$EP_DEBUG" ]; then - echo "hacking missing uid $(id -u) into /etc/passwd" + echo "adding missing uid $(id -u) into /etc/passwd" fi echo "$(id -u):x:$(id -u):0:container user $(id -u):/home/runner:/bin/bash" >> /etc/passwd export HOME=/home/runner fi -# FIXME junk output MYHOME=`getent passwd $(whoami) | cut -d: -f6` -# FIXME: we also want to check the case of a generated user who podman set their homedir to WORKDIR; maybe anything with a high UID, or ? -if [ "$MYHOME" != "$HOME" ] || [ $(id -u) -ge 500 ] && [ "$MYHOME" != "/home/runner" ]; then +if [ "$MYHOME" != "$HOME" ] || [ "$MYHOME" != "/home/runner" ]; then if [ -n "$EP_DEBUG" ]; then echo "replacing homedir for user $(whoami)" fi @@ -48,8 +57,6 @@ if [ "$MYHOME" != "$HOME" ] || [ $(id -u) -ge 500 ] && [ "$MYHOME" != "/home/run export HOME=/home/runner fi -# FIXME: validate group entries? - if [[ -n "${LAUNCHED_BY_RUNNER}" ]]; then # Special actions to be compatible with old ansible-runner versions, 2.1.x specifically RUNNER_CALLBACKS=$(python3 -c "from ansible_runner.display_callback.callback import awx_display; print(awx_display.__file__)") From 0afa6d7a73cb746433280fed944b8e2236981b01 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Tue, 3 May 2022 12:13:56 -0700 Subject: [PATCH 4/5] restore ENV HOME override for builds --- Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Dockerfile b/Dockerfile index 723e6416f..17d2499dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,6 +54,12 @@ RUN for dir in \ WORKDIR /runner +# NB: this appears to be necessary for container builds based on this container, since we can't rely on the entrypoint +# script to run during a build to fix up /etc/passwd. This envvar value, and the fact that all user homedirs are +# set to /home/runner is an implementation detail that may change with future versions of runner and should not be +# assumed by other code or tools. +ENV HOME=/home/runner + ADD utils/entrypoint.sh /bin/entrypoint RUN chmod +x /bin/entrypoint From 06331e9bb189ec77a2c8e2bdf8c341f689a309cb Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Tue, 3 May 2022 12:15:39 -0700 Subject: [PATCH 5/5] comment wording --- utils/entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/entrypoint.sh b/utils/entrypoint.sh index 391665858..e1f2d212c 100755 --- a/utils/entrypoint.sh +++ b/utils/entrypoint.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# We need to fix a number of problems here that manifest under different container runtimes, as well as paper over some +# We need to fix a number of problems here that manifest under different container runtimes, as well as tweak some # things to simplify runner's containerized launch behavior. Since runner currently always expects to bind-mount its # callback plugins under ~/.ansible, it must have prior knowledge of the user's homedir before the container is launched # in order to know where to mount in the callback dir. In all cases, we must get a consistent answer from $HOME