Skip to content

Commit c07ae18

Browse files
committed
[SPARK-43368] Use libnss_wrapper to fake passwd entry
### What changes were proposed in this pull request? Use `libnss_wrapper` to fake passwd entry instead of changing passwd to resolve random UID problem. And also we only attempt to setup fake passwd entry for driver/executor, but for cmd like `bash`, the fake passwd will not be set. ### Why are the changes needed? In the past, we add the entry to `/etc/passwd` directly for current UID, it's mainly for [OpenShift anonymous random `uid` case](docker-library/official-images#13089 (comment)) (See also in apache-spark-on-k8s/spark#404), but this way bring the pontential security issue about widely permision of `/etc/passwd`. According to DOI reviewer [suggestion](docker-library/official-images#13089 (comment)), we'd better to resolve this problem by using [libnss_wrapper](https://cwrap.org/nss_wrapper.html). It's a library to help set a fake passwd entry by setting `LD_PRELOAD`, `NSS_WRAPPER_PASSWD`, `NSS_WRAPPER_GROUP`. Such as random UID is `1000`, the env will be: ``` spark6f41b8e5be9b:/opt/spark/work-dir$ id -u 1000 spark6f41b8e5be9b:/opt/spark/work-dir$ id -g 1000 spark6f41b8e5be9b:/opt/spark/work-dir$ whoami spark spark6f41b8e5be9b:/opt/spark/work-dir$ echo $LD_PRELOAD /usr/lib/libnss_wrapper.so spark6f41b8e5be9b:/opt/spark/work-dir$ echo $NSS_WRAPPER_PASSWD /tmp/tmp.r5x4SMX35B spark6f41b8e5be9b:/opt/spark/work-dir$ cat /tmp/tmp.r5x4SMX35B spark:x:1000:1000:${SPARK_USER_NAME:-anonymous uid}:/opt/spark:/bin/false spark6f41b8e5be9b:/opt/spark/work-dir$ echo $NSS_WRAPPER_GROUP /tmp/tmp.XcnnYuD68r spark6f41b8e5be9b:/opt/spark/work-dir$ cat /tmp/tmp.XcnnYuD68r spark:x:1000: ``` ### Does this PR introduce _any_ user-facing change? Yes, setup fake ENV rather than changing `/etc/passwd`. ### How was this patch tested? #### 1. Without `attempt_setup_fake_passwd_entry`, the user is `I have no name!` ``` # docker run -it --rm --user 1000:1000 spark-test bash groups: cannot find name for group ID 1000 I have no name!998110cd5a26:/opt/spark/work-dir$ I have no name!0fea1d27d67d:/opt/spark/work-dir$ id -u 1000 I have no name!0fea1d27d67d:/opt/spark/work-dir$ id -g 1000 I have no name!0fea1d27d67d:/opt/spark/work-dir$ whoami whoami: cannot find name for user ID 1000 ``` #### 2. Mannual stub the `attempt_setup_fake_passwd_entry`, the user is `spark`. 2.1 Apply a tmp change to cmd ```patch diff --git a/entrypoint.sh.template b/entrypoint.sh.template index 08fc925..77d5b04 100644 --- a/entrypoint.sh.template +++ b/entrypoint.sh.template -118,6 +118,7 case "$1" in *) # Non-spark-on-k8s command provided, proceeding in pass-through mode... + attempt_setup_fake_passwd_entry exec "$" ;; esac ``` 2.2 Build and run the image, specify a random UID/GID 1000 ```bash $ docker build . -t spark-test $ docker run -it --rm --user 1000:1000 spark-test bash # the user is set to spark rather than unknow user spark6f41b8e5be9b:/opt/spark/work-dir$ spark6f41b8e5be9b:/opt/spark/work-dir$ id -u 1000 spark6f41b8e5be9b:/opt/spark/work-dir$ id -g 1000 spark6f41b8e5be9b:/opt/spark/work-dir$ whoami spark ``` ``` # NSS env is set right spark6f41b8e5be9b:/opt/spark/work-dir$ echo $LD_PRELOAD /usr/lib/libnss_wrapper.so spark6f41b8e5be9b:/opt/spark/work-dir$ echo $NSS_WRAPPER_PASSWD /tmp/tmp.r5x4SMX35B spark6f41b8e5be9b:/opt/spark/work-dir$ cat /tmp/tmp.r5x4SMX35B spark:x:1000:1000:${SPARK_USER_NAME:-anonymous uid}:/opt/spark:/bin/false spark6f41b8e5be9b:/opt/spark/work-dir$ echo $NSS_WRAPPER_GROUP /tmp/tmp.XcnnYuD68r spark6f41b8e5be9b:/opt/spark/work-dir$ cat /tmp/tmp.XcnnYuD68r spark:x:1000: ``` #### 3. If specify current exsiting user (such as `spark`, `root`), no fake setup ```bash # docker run -it --rm --user 0 spark-test bash roote5bf55d4df22:/opt/spark/work-dir# echo $LD_PRELOAD ``` ```bash # docker run -it --rm spark-test bash sparkdef8d8ca4e7d:/opt/spark/work-dir$ echo $LD_PRELOAD ``` Closes #45 from Yikun/SPARK-43368. Authored-by: Yikun Jiang <[email protected]> Signed-off-by: Yikun Jiang <[email protected]>
1 parent 2dc12d9 commit c07ae18

File tree

4 files changed

+50
-38
lines changed

4 files changed

+50
-38
lines changed

3.4.0/scala2.12-java11-ubuntu/Dockerfile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ RUN groupadd --system --gid=${spark_uid} spark && \
2424
RUN set -ex; \
2525
apt-get update; \
2626
ln -s /lib /lib64; \
27-
apt install -y gnupg2 wget bash tini libc6 libpam-modules krb5-user libnss3 procps net-tools gosu; \
27+
apt install -y gnupg2 wget bash tini libc6 libpam-modules krb5-user libnss3 procps net-tools gosu libnss-wrapper; \
2828
mkdir -p /opt/spark; \
2929
mkdir /opt/spark/python; \
3030
mkdir -p /opt/spark/examples; \
@@ -33,7 +33,6 @@ RUN set -ex; \
3333
touch /opt/spark/RELEASE; \
3434
chown -R spark:spark /opt/spark; \
3535
echo "auth required pam_wheel.so use_uid" >> /etc/pam.d/su; \
36-
chgrp root /etc/passwd && chmod ug+rw /etc/passwd; \
3736
rm -rf /var/cache/apt/*; \
3837
rm -rf /var/lib/apt/lists/*
3938

3.4.0/scala2.12-java11-ubuntu/entrypoint.sh

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,28 @@
1515
# See the License for the specific language governing permissions and
1616
# limitations under the License.
1717
#
18-
19-
# Check whether there is a passwd entry for the container UID
20-
myuid=$(id -u)
21-
mygid=$(id -g)
22-
# turn off -e for getent because it will return error code in anonymous uid case
23-
set +e
24-
uidentry=$(getent passwd $myuid)
25-
set -e
26-
27-
# If there is no passwd entry for the container UID, attempt to create one
28-
if [ -z "$uidentry" ] ; then
29-
if [ -w /etc/passwd ] ; then
30-
echo "$myuid:x:$myuid:$mygid:${SPARK_USER_NAME:-anonymous uid}:$SPARK_HOME:/bin/false" >> /etc/passwd
31-
else
32-
echo "Container ENTRYPOINT failed to add passwd entry for anonymous UID"
33-
fi
34-
fi
18+
attempt_setup_fake_passwd_entry() {
19+
# Check whether there is a passwd entry for the container UID
20+
local myuid; myuid="$(id -u)"
21+
# If there is no passwd entry for the container UID, attempt to fake one
22+
# You can also refer to the https://github.com/docker-library/official-images/pull/13089#issuecomment-1534706523
23+
# It's to resolve OpenShift random UID case.
24+
# See also: https://github.com/docker-library/postgres/pull/448
25+
if ! getent passwd "$myuid" &> /dev/null; then
26+
local wrapper
27+
for wrapper in {/usr,}/lib{/*,}/libnss_wrapper.so; do
28+
if [ -s "$wrapper" ]; then
29+
NSS_WRAPPER_PASSWD="$(mktemp)"
30+
NSS_WRAPPER_GROUP="$(mktemp)"
31+
export LD_PRELOAD="$wrapper" NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
32+
local mygid; mygid="$(id -g)"
33+
printf 'spark:x:%s:%s:${SPARK_USER_NAME:-anonymous uid}:%s:/bin/false\n' "$myuid" "$mygid" "$SPARK_HOME" > "$NSS_WRAPPER_PASSWD"
34+
printf 'spark:x:%s:\n' "$mygid" > "$NSS_WRAPPER_GROUP"
35+
break
36+
fi
37+
done
38+
fi
39+
}
3540

3641
if [ -z "$JAVA_HOME" ]; then
3742
JAVA_HOME=$(java -XshowSettings:properties -version 2>&1 > /dev/null | grep 'java.home' | awk '{print $3}')
@@ -85,6 +90,7 @@ case "$1" in
8590
--deploy-mode client
8691
"$@"
8792
)
93+
attempt_setup_fake_passwd_entry
8894
# Execute the container CMD under tini for better hygiene
8995
exec $(switch_spark_if_root) /usr/bin/tini -s -- "${CMD[@]}"
9096
;;
@@ -105,6 +111,7 @@ case "$1" in
105111
--resourceProfileId $SPARK_RESOURCE_PROFILE_ID
106112
--podName $SPARK_EXECUTOR_POD_NAME
107113
)
114+
attempt_setup_fake_passwd_entry
108115
# Execute the container CMD under tini for better hygiene
109116
exec $(switch_spark_if_root) /usr/bin/tini -s -- "${CMD[@]}"
110117
;;

Dockerfile.template

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ RUN groupadd --system --gid=${spark_uid} spark && \
2424
RUN set -ex; \
2525
apt-get update; \
2626
ln -s /lib /lib64; \
27-
apt install -y gnupg2 wget bash tini libc6 libpam-modules krb5-user libnss3 procps net-tools gosu; \
27+
apt install -y gnupg2 wget bash tini libc6 libpam-modules krb5-user libnss3 procps net-tools gosu libnss-wrapper; \
2828
mkdir -p /opt/spark; \
2929
mkdir /opt/spark/python; \
3030
mkdir -p /opt/spark/examples; \
@@ -33,7 +33,6 @@ RUN set -ex; \
3333
touch /opt/spark/RELEASE; \
3434
chown -R spark:spark /opt/spark; \
3535
echo "auth required pam_wheel.so use_uid" >> /etc/pam.d/su; \
36-
chgrp root /etc/passwd && chmod ug+rw /etc/passwd; \
3736
rm -rf /var/cache/apt/*; \
3837
rm -rf /var/lib/apt/lists/*
3938

entrypoint.sh.template

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,28 @@
1515
# See the License for the specific language governing permissions and
1616
# limitations under the License.
1717
#
18-
19-
# Check whether there is a passwd entry for the container UID
20-
myuid=$(id -u)
21-
mygid=$(id -g)
22-
# turn off -e for getent because it will return error code in anonymous uid case
23-
set +e
24-
uidentry=$(getent passwd $myuid)
25-
set -e
26-
27-
# If there is no passwd entry for the container UID, attempt to create one
28-
if [ -z "$uidentry" ] ; then
29-
if [ -w /etc/passwd ] ; then
30-
echo "$myuid:x:$myuid:$mygid:${SPARK_USER_NAME:-anonymous uid}:$SPARK_HOME:/bin/false" >> /etc/passwd
31-
else
32-
echo "Container ENTRYPOINT failed to add passwd entry for anonymous UID"
33-
fi
34-
fi
18+
attempt_setup_fake_passwd_entry() {
19+
# Check whether there is a passwd entry for the container UID
20+
local myuid; myuid="$(id -u)"
21+
# If there is no passwd entry for the container UID, attempt to fake one
22+
# You can also refer to the https://github.com/docker-library/official-images/pull/13089#issuecomment-1534706523
23+
# It's to resolve OpenShift random UID case.
24+
# See also: https://github.com/docker-library/postgres/pull/448
25+
if ! getent passwd "$myuid" &> /dev/null; then
26+
local wrapper
27+
for wrapper in {/usr,}/lib{/*,}/libnss_wrapper.so; do
28+
if [ -s "$wrapper" ]; then
29+
NSS_WRAPPER_PASSWD="$(mktemp)"
30+
NSS_WRAPPER_GROUP="$(mktemp)"
31+
export LD_PRELOAD="$wrapper" NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
32+
local mygid; mygid="$(id -g)"
33+
printf 'spark:x:%s:%s:${SPARK_USER_NAME:-anonymous uid}:%s:/bin/false\n' "$myuid" "$mygid" "$SPARK_HOME" > "$NSS_WRAPPER_PASSWD"
34+
printf 'spark:x:%s:\n' "$mygid" > "$NSS_WRAPPER_GROUP"
35+
break
36+
fi
37+
done
38+
fi
39+
}
3540

3641
if [ -z "$JAVA_HOME" ]; then
3742
JAVA_HOME=$(java -XshowSettings:properties -version 2>&1 > /dev/null | grep 'java.home' | awk '{print $3}')
@@ -85,6 +90,7 @@ case "$1" in
8590
--deploy-mode client
8691
"$@"
8792
)
93+
attempt_setup_fake_passwd_entry
8894
# Execute the container CMD under tini for better hygiene
8995
exec $(switch_spark_if_root) /usr/bin/tini -s -- "${CMD[@]}"
9096
;;
@@ -105,6 +111,7 @@ case "$1" in
105111
--resourceProfileId $SPARK_RESOURCE_PROFILE_ID
106112
--podName $SPARK_EXECUTOR_POD_NAME
107113
)
114+
attempt_setup_fake_passwd_entry
108115
# Execute the container CMD under tini for better hygiene
109116
exec $(switch_spark_if_root) /usr/bin/tini -s -- "${CMD[@]}"
110117
;;

0 commit comments

Comments
 (0)