From fa03e7d5e72e66d4112d55c6dfa547a8b072fc07 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Sat, 17 Jun 2023 13:45:38 +0900 Subject: [PATCH] feat: docker non-root uid and gid --- .github/workflows/docker_build_push.yml | 6 +- .gitignore | 1 + CHANGELOG.md | 1 + Cargo.toml | 2 +- docker/{amd64/Dockerfile => Dockerfile.amd64} | 27 ++-- .../Dockerfile => Dockerfile.amd64-slim} | 23 +-- docker/amd64-slim/run.sh | 60 -------- docker/amd64/run.sh | 61 -------- docker/docker-compose.yml | 9 +- docker/entrypoint.sh | 141 +++++++++++++++++- docker/run.sh | 10 ++ 11 files changed, 184 insertions(+), 157 deletions(-) rename docker/{amd64/Dockerfile => Dockerfile.amd64} (59%) rename docker/{amd64-slim/Dockerfile => Dockerfile.amd64-slim} (57%) delete mode 100644 docker/amd64-slim/run.sh delete mode 100644 docker/amd64/run.sh create mode 100644 docker/run.sh diff --git a/.github/workflows/docker_build_push.yml b/.github/workflows/docker_build_push.yml index 2e5b38e..1dfd260 100644 --- a/.github/workflows/docker_build_push.yml +++ b/.github/workflows/docker_build_push.yml @@ -38,7 +38,7 @@ jobs: push: true tags: | ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:latest - file: ./docker/amd64/Dockerfile + file: ./docker/Dockerfile.amd64 - name: Release build and push x86_64-slim if: ${{ env.BRANCH == 'main' }} @@ -48,7 +48,7 @@ jobs: push: true tags: | ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:slim, ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:latest-slim - file: ./docker/amd64-slim/Dockerfile + file: ./docker/Dockerfile.amd64-slim - name: Nightly build and push x86_64 if: ${{ env.BRANCH == 'develop' }} @@ -58,4 +58,4 @@ jobs: push: true tags: | ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:nightly - file: ./docker/amd64/Dockerfile + file: ./docker/Dockerfile.amd64 diff --git a/.gitignore b/.gitignore index 02474f4..6797716 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .vscode .private +docker/log # Generated by Cargo diff --git a/CHANGELOG.md b/CHANGELOG.md index 20a4a1c..17ab849 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Update `h3` with `quinn-0.10` or higher. - Implement the session persistance function for load balancing using sticky cookie (initial implementation). Enabled in `default-features`. +- Update `Dockerfile`s to change UID and GID to non-root users. Now they can be set as you like by specifying through env vars. ## 0.2.0 diff --git a/Cargo.toml b/Cargo.toml index d91af0c..8d955ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,7 +73,7 @@ chrono = { version = "0.4.26", default-features = false, features = [ "clock", ], optional = true } base64 = { version = "0.21.2", optional = true } -sha2 = { version = "0.10.6", default-features = false, optional = true } +sha2 = { version = "0.10.7", default-features = false, optional = true } [target.'cfg(not(target_env = "msvc"))'.dependencies] diff --git a/docker/amd64/Dockerfile b/docker/Dockerfile.amd64 similarity index 59% rename from docker/amd64/Dockerfile rename to docker/Dockerfile.amd64 index 8f7ecf7..da27439 100644 --- a/docker/amd64/Dockerfile +++ b/docker/Dockerfile.amd64 @@ -30,26 +30,27 @@ RUN apt-get update && apt-get install -qy --no-install-recommends $BUILD_DEPS && FROM base AS runner ENV TAG_NAME=amd64 -ENV RUNTIME_DEPS logrotate ca-certificates +ENV RUNTIME_DEPS logrotate ca-certificates gosu RUN apt-get update && \ apt-get install -qy --no-install-recommends $RUNTIME_DEPS && \ apt-get -qy clean && \ - apt-get -qy autoremove &&\ - rm -fr /tmp/* /var/tmp/* /var/cache/apt/* /var/lib/apt/lists/* /var/log/apt/* /var/log/*.log &&\ - mkdir -p /opt/rpxy/sbin &&\ - mkdir -p /var/log/rpxy && \ - touch /var/log/rpxy/rpxy.log + apt-get -qy autoremove && \ + rm -fr /tmp/* /var/tmp/* /var/cache/apt/* /var/lib/apt/lists/* /var/log/apt/* /var/log/*.log && \ + find / -type d -path /proc -prune -o -type f -perm /u+s -ignore_readdir_race -exec chmod u-s {} \; && \ + find / -type d -path /proc -prune -o -type f -perm /g+s -ignore_readdir_race -exec chmod g-s {} \; && \ + mkdir -p /rpxy/bin &&\ + mkdir -p /rpxy/log -COPY --from=builder /tmp/target/release/rpxy /opt/rpxy/sbin/rpxy -COPY ./docker/${TAG_NAME}/run.sh / -COPY ./docker/entrypoint.sh / +COPY --from=builder /tmp/target/release/rpxy /rpxy/bin/rpxy +COPY ./docker/run.sh /rpxy +COPY ./docker/entrypoint.sh /rpxy -RUN chmod 755 /run.sh && \ - chmod 755 /entrypoint.sh +RUN chmod +x /rpxy/run.sh && \ + chmod +x /rpxy/entrypoint.sh EXPOSE 80 443 -CMD ["/entrypoint.sh"] +CMD ["/usr/bin/bash" "/rpxy/entrypoint.sh"] -ENTRYPOINT ["/entrypoint.sh"] +ENTRYPOINT ["/usr/bin/bash", "/rpxy/entrypoint.sh"] diff --git a/docker/amd64-slim/Dockerfile b/docker/Dockerfile.amd64-slim similarity index 57% rename from docker/amd64-slim/Dockerfile rename to docker/Dockerfile.amd64-slim index 9e5b9d4..fb0246e 100644 --- a/docker/amd64-slim/Dockerfile +++ b/docker/Dockerfile.amd64-slim @@ -20,26 +20,27 @@ LABEL maintainer="Jun Kurihara" ENV TAG_NAME=amd64-slim ENV TARGET_DIR=x86_64-unknown-linux-musl -ENV RUNTIME_DEPS logrotate ca-certificates +ENV RUNTIME_DEPS logrotate ca-certificates su-exec RUN apk add --no-cache ${RUNTIME_DEPS} && \ update-ca-certificates && \ - mkdir -p /opt/rpxy/sbin &&\ - mkdir -p /var/log/rpxy && \ - touch /var/log/rpxy/rpxy.log + find / -type d -path /proc -prune -o -type f -perm /u+s -exec chmod u-s {} \; && \ + find / -type d -path /proc -prune -o -type f -perm /g+s -exec chmod g-s {} \; && \ + mkdir -p /rpxy/bin &&\ + mkdir -p /rpxy/log -COPY --from=builder /tmp/target/${TARGET_DIR}/release/rpxy /opt/rpxy/sbin/rpxy -COPY ./docker/${TAG_NAME}/run.sh / -COPY ./docker/entrypoint.sh / +COPY --from=builder /tmp/target/${TARGET_DIR}/release/rpxy /rpxy/bin/rpxy +COPY ./docker/run.sh /rpxy +COPY ./docker/entrypoint.sh /rpxy -RUN chmod 755 /run.sh && \ - chmod 755 /entrypoint.sh +RUN chmod +x /rpxy/run.sh && \ + chmod +x /rpxy/entrypoint.sh ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt ENV SSL_CERT_DIR=/etc/ssl/certs EXPOSE 80 443 -CMD ["/entrypoint.sh"] +CMD ["/rpxy/entrypoint.sh"] -ENTRYPOINT ["/entrypoint.sh"] +ENTRYPOINT ["/rpxy/entrypoint.sh"] diff --git a/docker/amd64-slim/run.sh b/docker/amd64-slim/run.sh deleted file mode 100644 index 1d99125..0000000 --- a/docker/amd64-slim/run.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env sh - -LOG_FILE=/var/log/rpxy/rpxy.log -CONFIG_FILE=/etc/rpxy.toml -LOG_SIZE=10M -LOG_NUM=10 - -# logrotate -if [ $LOGROTATE_NUM ]; then - LOG_NUM=${LOGROTATE_NUM} -fi -if [ $LOGROTATE_SIZE ]; then - LOG_SIZE=${LOGROTATE_SIZE} -fi - -cat > /etc/logrotate.conf << EOF -# see "man logrotate" for details -# rotate log files weekly -weekly -# use the adm group by default, since this is the owning group -# of /var/log/syslog. -su root adm -# keep 4 weeks worth of backlogs -rotate 4 -# create new (empty) log files after rotating old ones -create -# use date as a suffix of the rotated file -#dateext -# uncomment this if you want your log files compressed -#compress -# packages drop log rotation information into this directory -include /etc/logrotate.d -# system-specific logs may be also be configured here. -EOF - -cat > /etc/logrotate.d/rpxy.conf << EOF -${LOG_FILE} { - dateext - daily - missingok - rotate ${LOG_NUM} - notifempty - compress - delaycompress - dateformat -%Y-%m-%d-%s - size ${LOG_SIZE} - copytruncate -} -EOF - -cp -f /etc/periodic/daily/logrotate /etc/periodic/15min -crond restart - -# debug level logging -if [ -z $LOG_LEVEL ]; then - LOG_LEVEL=info -fi -echo "rpxy: Logging with level ${LOG_LEVEL}" - -RUST_LOG=${LOG_LEVEL} /opt/rpxy/sbin/rpxy --config ${CONFIG_FILE} diff --git a/docker/amd64/run.sh b/docker/amd64/run.sh deleted file mode 100644 index bace2c9..0000000 --- a/docker/amd64/run.sh +++ /dev/null @@ -1,61 +0,0 @@ - -#!/usr/bin/env sh - -LOG_FILE=/var/log/rpxy/rpxy.log -CONFIG_FILE=/etc/rpxy.toml -LOG_SIZE=10M -LOG_NUM=10 - -# logrotate -if [ $LOGROTATE_NUM ]; then - LOG_NUM=${LOGROTATE_NUM} -fi -if [ $LOGROTATE_SIZE ]; then - LOG_SIZE=${LOGROTATE_SIZE} -fi - -cat > /etc/logrotate.conf << EOF -# see "man logrotate" for details -# rotate log files weekly -weekly -# use the adm group by default, since this is the owning group -# of /var/log/syslog. -su root adm -# keep 4 weeks worth of backlogs -rotate 4 -# create new (empty) log files after rotating old ones -create -# use date as a suffix of the rotated file -#dateext -# uncomment this if you want your log files compressed -#compress -# packages drop log rotation information into this directory -include /etc/logrotate.d -# system-specific logs may be also be configured here. -EOF - -cat > /etc/logrotate.d/rpxy << EOF -${LOG_FILE} { - dateext - daily - missingok - rotate ${LOG_NUM} - notifempty - compress - delaycompress - dateformat -%Y-%m-%d-%s - size ${LOG_SIZE} - copytruncate -} -EOF - -cp -p /etc/cron.daily/logrotate /etc/cron.hourly/ -service cron start - -# debug level logging -if [ -z $LOG_LEVEL ]; then - LOG_LEVEL=info -fi -echo "rpxy: Logging with level ${LOG_LEVEL}" - -RUST_LOG=${LOG_LEVEL} /opt/rpxy/sbin/rpxy --config ${CONFIG_FILE} diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 9a64db2..716d0de 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -3,19 +3,24 @@ services: rpxy-rp: image: jqtype/rpxy container_name: rpxy + init: true restart: unless-stopped ports: - 127.0.0.1:8080:8080 - 127.0.0.1:8443:8443 build: context: ../ - dockerfile: ./docker/amd64/Dockerfile + dockerfile: ./docker/Dockerfile.amd64 environment: - LOG_LEVEL=debug - - LOG_TO_FILE=false + - LOG_TO_FILE=true + - HOST_USER=jun + - HOST_UID=501 + - HOST_GID=501 tty: false privileged: true volumes: + - ./log:/rpxy/log - ../example-certs/server.crt:/certs/server.crt:ro - ../example-certs/server.key:/certs/server.key:ro - ../config-example.toml:/etc/rpxy.toml:ro diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 055f745..f2b5a94 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,14 +1,143 @@ #!/usr/bin/env sh -LOG_FILE=/var/log/rpxy/rpxy.log +LOG_DIR=/rpxy/log +LOG_FILE=${LOG_DIR}/rpxy.log +LOG_SIZE=10M +LOG_NUM=10 -if [ -z ${LOG_TO_FILE} ]; then - LOG_TO_FILE=false +LOGGING=${LOG_TO_FILE:-false} +USER=${HOST_USER:-rpxy} +USER_ID=${HOST_UID:-900} +GROUP_ID=${HOST_GID:-900} + +####################################### +# Setup logrotate +function setup_logrotate () { + if [ $LOGROTATE_NUM ]; then + LOG_NUM=${LOGROTATE_NUM} + fi + if [ $LOGROTATE_SIZE ]; then + LOG_SIZE=${LOGROTATE_SIZE} + fi + + cat > /etc/logrotate.conf << EOF +# see "man logrotate" for details +# rotate log files weekly +weekly +# use the adm group by default, since this is the owning group +# of /var/log/syslog. +# su root adm +# keep 4 weeks worth of backlogs +rotate 4 +# create new (empty) log files after rotating old ones +create +# use date as a suffix of the rotated file +#dateext +# uncomment this if you want your log files compressed +#compress +# packages drop log rotation information into this directory +include /etc/logrotate.d +# system-specific logs may be also be configured here. +EOF + + cat > /etc/logrotate.d/rpxy.conf << EOF +${LOG_FILE} { + dateext + daily + missingok + rotate ${LOG_NUM} + notifempty + compress + delaycompress + dateformat -%Y-%m-%d-%s + size ${LOG_SIZE} + copytruncate + su ${USER} ${USER} +} +EOF +} + +####################################### +function setup_ubuntu () { + # Check the existence of the user, if not exist, create it. + if [ ! $(id ${USER}) ]; then + echo "rpxy: Create user ${USER} with ${USER_ID}:${GROUP_ID}" + groupadd -g ${GROUP_ID} ${USER} + useradd -u ${USER_ID} -g ${GROUP_ID} ${USER} + fi + + # for crontab when logging + if "${LOGGING}"; then + # Set up logrotate + setup_logrotate + + # Setup cron + mkdir -p /etc/cron.15min/ + cp -p /etc/cron.daily/logrotate /etc/cron.15min/ + echo "*/15 * * * * root cd / && run-parts --report /etc/cron.15min" >> /etc/crontab + # cp -p /etc/cron.daily/logrotate /etc/cron.hourly/ + service cron start + fi +} + +####################################### +function setup_alpine () { + # Check the existence of the user, if not exist, create it. + if [ ! $(id ${USER}) ]; then + echo "rpxy: Create user ${USER} with ${USER_ID}:${GROUP_ID}" + addgroup -g ${GROUP_ID} ${USER} + adduser -H -D -u ${USER_ID} -G ${USER} ${USER} + fi + + # for crontab when logging + if "${LOGGING}"; then + # Set up logrotate + setup_logrotate + + # Setup cron + cp -f /etc/periodic/daily/logrotate /etc/periodic/15min + crond -b -l 8 + fi +} + +####################################### + +if [ $(whoami) != "root" -o $(id -u) -ne 0 -a $(id -g) -ne 0 ]; then + echo "Do not execute 'docker run' or 'docker-compose up' with a specific user through '-u'." + echo "If you want to run 'rpxy' with a specific user, use HOST_USER, HOST_UID and HOST_GID environment variables." + exit 1 fi -if "${LOG_TO_FILE}"; then +# Check gosu or su-exec, determine linux distribution, and set up user +if [ $(command -v gosu) ]; then + # Ubuntu Linux + alias gosu='gosu' + setup_ubuntu + LINUX="Ubuntu" +elif [ $(command -v su-exec) ]; then + # Alpine Linux + alias gosu='su-exec' + setup_alpine + LINUX="Alpine" +else + echo "Unknown distribution!" + exit 1 +fi + +# Check the given user and its uid:gid +if [ $(id -u ${USER}) -ne ${USER_ID} -a $(id -g ${USER}) -ne ${GROUP_ID} ]; then + echo "${USER} exists or was previously created. However, its uid and gid are inconsistent. Please recreate your container." + exit 1 +fi + +# Change permission according to the given user +chown -R ${USER_ID}:${USER_ID} /rpxy + +# Run rpxy +echo "rpxy: Start with user: ${USER} (${USER_ID}:${USER_ID})" +if "${LOGGING}"; then echo "rpxy: Start with writing log file" - /run.sh 2>&1 | tee $LOG_FILE + gosu ${USER} sh -c "/rpxy/run.sh 2>&1 | tee ${LOG_FILE}" else echo "rpxy: Start without writing log file" - /run.sh 2>&1 + gosu ${USER} sh -c "/rpxy/run.sh 2>&1" fi diff --git a/docker/run.sh b/docker/run.sh new file mode 100644 index 0000000..6f83ff8 --- /dev/null +++ b/docker/run.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env sh +CONFIG_FILE=/etc/rpxy.toml + +# debug level logging +if [ -z $LOG_LEVEL ]; then + LOG_LEVEL=info +fi +echo "rpxy: Logging with level ${LOG_LEVEL}" + +RUST_LOG=${LOG_LEVEL} /rpxy/bin/rpxy --config ${CONFIG_FILE}