Skip to content

Commit

Permalink
Run containers as any arbitrary UID and GID
Browse files Browse the repository at this point in the history
  • Loading branch information
mjnaderi committed Aug 13, 2024
1 parent ca5f244 commit 8d6d104
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 33 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ Start server and client services:
KEY1_BASE64=$(cat key1.base64)
KEY2_PUB=$(cat key2.pub)
docker run --name tunnel-server --rm -it --init \
--user 12345:12345 \
-e SERVER_ED25519_PRIVATE_KEY_BASE64="$KEY1_BASE64" \
-e CLIENT_AUTHORIZED_KEYS="$KEY2_PUB" \
-e SSHD_PERMIT_LISTEN="0.0.0.0:4444" \
Expand All @@ -146,6 +147,7 @@ docker run --name tunnel-server --rm -it --init \
KEY2_BASE64=$(cat key2.base64)
KEY1_PUB=$(cat key1.pub)
docker run --name tunnel-client --rm -it --init --add-host=host.docker.internal:host-gateway \
--user 12345:12345 \
-e SERVER_ED25519_PUBLIC_KEY="$KEY1_PUB" \
-e CLIENT_ED25519_PRIVATE_KEY_BASE64="$KEY2_BASE64" \
-e SSH_HOSTNAME="host.docker.internal" \
Expand Down Expand Up @@ -175,6 +177,7 @@ services:
tunnel-server:
image: ghcr.io/querateam/docker-ssh-tunnel/server
restart: always
user: 12345:12345
environment:
SERVER_ED25519_PRIVATE_KEY_BASE64: ... value of key1.base64 ...
CLIENT_AUTHORIZED_KEYS: ... value of key2.pub ...
Expand All @@ -186,6 +189,7 @@ services:
tunnel-client:
image: ghcr.io/querateam/docker-ssh-tunnel/client
restart: always
user: 12345:12345
environment:
SERVER_ED25519_PUBLIC_KEY: ... value of key1.pub ...
CLIENT_ED25519_PRIVATE_KEY_BASE64: ... value of key2.base64 ...
Expand Down
9 changes: 1 addition & 8 deletions client/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
FROM alpine:3.20

# Install openssh-client and autossh
RUN apk add --no-cache openssh-client autossh

# Create tunnel user
ARG TUNNEL_USER=tunnel
RUN adduser -D $TUNNEL_USER
RUN chmod 750 /home/$TUNNEL_USER
RUN apk add --no-cache openssh-client autossh nss_wrapper

# Copy entrypoint script
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

USER tunnel

ENTRYPOINT ["/entrypoint.sh"]
21 changes: 15 additions & 6 deletions client/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
#!/bin/sh

# Ensure script is run by "tunnel" user
if [ "$(id -un)" != "tunnel" ]; then
echo "This script must be run as the 'tunnel' user. Exiting..."
# Ensure the script is not run by the "root" user.
if [ "$(id -u)" = "0" ]; then
echo "This image should not be run as the 'root' user. Exiting..."
exit 1
fi

mkdir -p $HOME/.ssh
chmod 700 $HOME/.ssh

if [ -z "$SSH_HOSTNAME" ]; then
echo "SSH_HOSTNAME is not set. Exiting..."
exit 1
fi

# We don't want to depend on the existence of a real user and a home directory,
# so we can run the container as any non-root user with any uid and gid.
# We achieve this by creating a "fake" home directory,
# and using nss_wrapper to "fake" /etc/passwd contents, so "ssh" thinks the user exists.
# https://cwrap.org/nss_wrapper.html
export HOME="/tmp/tunnel"
echo "tunnel:x:$(id -u):$(id -g):Tunnel User:${HOME}:/bin/false" >/tmp/passwd
echo "tunnel:x:$(id -g):tunnel" >/tmp/group
export LD_PRELOAD=/usr/lib/libnss_wrapper.so NSS_WRAPPER_PASSWD=/tmp/passwd NSS_WRAPPER_GROUP=/tmp/group
mkdir -p "$HOME/.ssh"
chmod -R 700 "$HOME"

################################
# setup keys #
################################
Expand Down
9 changes: 1 addition & 8 deletions server/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,7 @@
FROM alpine:3.20

# Install openssh-server
RUN apk add --no-cache openssh-server

# Create tunnel user
ARG TUNNEL_USER=tunnel
RUN adduser -D $TUNNEL_USER
# https://github.com/camptocamp/puppet-accounts/issues/35#issuecomment-366412237
RUN sed -i s/$TUNNEL_USER:!/"$TUNNEL_USER:*"/g /etc/shadow
RUN chmod 750 /home/$TUNNEL_USER
RUN apk add --no-cache openssh-server nss_wrapper

# Copy entrypoint script
COPY entrypoint.sh /entrypoint.sh
Expand Down
40 changes: 29 additions & 11 deletions server/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
#!/bin/sh

# Ensure the script is not run by the "root" user.
if [ "$(id -u)" = "0" ]; then
echo "This image should not be run as the 'root' user. Exiting..."
exit 1
fi

# We don't want to depend on the existence of a real user and a home directory,
# so we can run the container as any non-root user with any uid and gid.
# We achieve this by creating a "fake" home directory,
# and using nss_wrapper to "fake" /etc/passwd contents, so "ssh" thinks the user exists.
# https://cwrap.org/nss_wrapper.html
export HOME="/tmp/tunnel"
echo "tunnel:x:$(id -u):$(id -g):Tunnel User:${HOME}:/bin/false" >/tmp/passwd
echo "tunnel:x:$(id -g):tunnel" >/tmp/group
export LD_PRELOAD=/usr/lib/libnss_wrapper.so NSS_WRAPPER_PASSWD=/tmp/passwd NSS_WRAPPER_GROUP=/tmp/group
mkdir -p "$HOME/sshd" "$HOME/.ssh"
chmod -R 700 "$HOME"

################################
# setup host key #
################################
Expand All @@ -8,12 +26,12 @@ if [ -z "$SERVER_ED25519_PRIVATE_KEY_BASE64" ]; then
exit 1
else
echo "Setting up the host key from the environment variable..."
echo "$SERVER_ED25519_PRIVATE_KEY_BASE64" | base64 -d >/etc/ssh/ssh_host_ed25519_key
chmod 600 /etc/ssh/ssh_host_ed25519_key
echo "$SERVER_ED25519_PRIVATE_KEY_BASE64" | base64 -d >"$HOME/sshd/ssh_host_ed25519_key"
chmod 600 "$HOME/sshd/ssh_host_ed25519_key"
fi
if [ -n "$SERVER_ED25519_PUBLIC_KEY" ]; then
echo "$SERVER_ED25519_PUBLIC_KEY" >/etc/ssh/ssh_host_ed25519_key.pub
chmod 644 /etc/ssh/ssh_host_ed25519_key.pub
echo "$SERVER_ED25519_PUBLIC_KEY" >"$HOME/sshd/ssh_host_ed25519_key.pub"
chmod 644 "$HOME/sshd/ssh_host_ed25519_key.pub"
fi

################################
Expand All @@ -23,21 +41,21 @@ if [ -z "$CLIENT_AUTHORIZED_KEYS" ]; then
echo "CLIENT_AUTHORIZED_KEYS is not set. Exiting..."
exit 1
else
mkdir -p /home/tunnel/.ssh
chmod 700 /home/tunnel/.ssh
# Split the CLIENT_AUTHORIZED_KEYS variable by semicolon and add each to authorized_keys
echo "$CLIENT_AUTHORIZED_KEYS" | tr ';' '\n' | while IFS= read -r key; do
# Process each key here
echo "$key" >>/home/tunnel/.ssh/authorized_keys
echo "$key" >>"$HOME/.ssh/authorized_keys"
done
chmod 600 /home/tunnel/.ssh/authorized_keys
chown -R tunnel:tunnel /home/tunnel/.ssh
chmod 600 "$HOME/.ssh/authorized_keys"
fi

################################
# sshd_config options #
################################
printf "\
AuthorizedKeysFile .ssh/authorized_keys
HostKey ${HOME}/sshd/ssh_host_ed25519_key
PidFile none
Port ${SSHD_PORT:-22}
PermitRootLogin ${SSHD_PERMIT_ROOT_LOGIN:-no}
PermitEmptyPasswords ${SSHD_PERMIT_EMPTY_PASSWORDS:-no}
Expand All @@ -58,9 +76,9 @@ X11Forwarding ${SSHD_X11_FORWARDING:-no}
AllowAgentForwarding ${SSHD_ALLOW_AGENT_FORWARDING:-no}
ForceCommand ${SSHD_FORCE_COMMAND:-"/sbin/nologin"}
AllowUsers ${SSHD_ALLOW_USERS:-tunnel}
" >/etc/ssh/sshd_config.d/tunnel.conf
" >"$HOME/sshd/sshd.conf"

################################
# Start sshd #
################################
exec /usr/sbin/sshd -D -e
exec /usr/sbin/sshd -D -e -f "$HOME/sshd/sshd.conf"

0 comments on commit 8d6d104

Please sign in to comment.