From 3aa65a063c9931dd91777e1e1627d071d0a00869 Mon Sep 17 00:00:00 2001 From: tacone Date: Mon, 17 May 2021 12:09:48 +0200 Subject: [PATCH 1/8] =?UTF-8?q?svelte:=20run=20app=20as=20an=20unpriviledg?= =?UTF-8?q?ed=20user=20=F0=9F=94=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/svelte/Dockerfile | 14 ++++++++++++-- docker/svelte/docker-compose.dev.yml | 5 ++++- docker/svelte/docker-compose.yml | 18 ++++++++++++++++-- docker/svelte/entrypoint.sh | 16 ++++++++++++++++ scripts/bin/install-files | 2 +- scripts/lib/init | 7 ++++++- 6 files changed, 55 insertions(+), 7 deletions(-) create mode 100755 docker/svelte/entrypoint.sh diff --git a/docker/svelte/Dockerfile b/docker/svelte/Dockerfile index 6bba10b..7ff1b38 100644 --- a/docker/svelte/Dockerfile +++ b/docker/svelte/Dockerfile @@ -1,7 +1,9 @@ FROM node:16-alpine -# we need it to brotli compress the static export -RUN apk add brotli +# we need: +# - brotli compress the static export +# - su-exec to downgrade user permissions ( https://github.com/ncopa/su-exec ) +RUN apk add brotli su-exec # declare the NODE_ENV. This will invalidate the cache from now on if # NODE_ENV changes. @@ -14,6 +16,7 @@ RUN echo 'NODE_ENV set to '${NODE_ENV} # yarn.lock change COPY ./svelte/package.json ./svelte/yarn.loc[k] /deps/ WORKDIR /deps + # we do not download dependencies in dev, because we do it when bootstraping # docker-compose # (we need to use the dev deps because of https://github.com/sveltejs/sapper/issues/592) @@ -39,3 +42,10 @@ ENV BUILD_COMMAND ${BUILD_COMMAND} RUN echo 'BUILD_COMMAND set to '${BUILD_COMMAND} RUN if [ "$NODE_ENV" = 'production' ]; then sh -c "$BUILD_COMMAND"; else echo 'Skipping export'; fi + +# 🔑 +ARG USER_ID +ENV USER_ID ${USER_ID} +RUN echo 'USER_ID set to ${USER_ID}' + +RUN adduser -S app -u ${USER_ID} || echo USER ${USER_ID} already exists. diff --git a/docker/svelte/docker-compose.dev.yml b/docker/svelte/docker-compose.dev.yml index a2d788a..061448a 100644 --- a/docker/svelte/docker-compose.dev.yml +++ b/docker/svelte/docker-compose.dev.yml @@ -32,4 +32,7 @@ services: # and download the depencencies there so they can be parsed # by the IDE # 🚀 - command: sh -c "yarn && yarn run dev" \ No newline at end of file + command: >- + sh -c " + yarn && yarn run dev + " \ No newline at end of file diff --git a/docker/svelte/docker-compose.yml b/docker/svelte/docker-compose.yml index df52ead..1ca6d02 100644 --- a/docker/svelte/docker-compose.yml +++ b/docker/svelte/docker-compose.yml @@ -16,15 +16,21 @@ services: yarn run build && brotli-compress /app/build/assets - # env variables needed by the build + # the UID we'll use to run the app, use 0 if you want root + USER_ID: ${USER_ID} # 🔑 + # other env variables needed by the build NODE_ENV: production VITE_GRAPHQL_ENDPOINT: ${GRAPHQL_ENDPOINT} + # 🚪 a custom entrypoint to fix permissions + entrypoint: /entrypoint.sh # 🔑 + # 🌳 environment: - NODE_ENV=production - VITE_GRAPHQL_ENDPOINT=${GRAPHQL_ENDPOINT} - YARN_DISABLE_SELF_UPDATE_CHECK=true + - YARN_CACHE_FOLDER=/usr/local/share/.cache/yarn # 🔗 ports: @@ -36,14 +42,22 @@ services: # 🛡️ make everything read-only except the volumes read_only: true + # use root here, we'll change the user in the entrypoint + # to $USER_ID + # 🔑 + user: "0" + # 📂 volumes: + # a custom entrypoint to fix permissions (depends on su-exec) + - ./docker/svelte/entrypoint.sh:/entrypoint.sh # 🔑 + # make these directories writable - ./data/svelte:/app/.svelte-kit - /tmp/survey/svelte:/tmp # share yarn cache folder with the other containers - - ./data/yarn:/usr/local/share/.cache/yarn/ + - ./data/yarn-${USER_ID}:/usr/local/share/.cache/yarn # utility scripts - ./scripts/bin/install-files:/usr/local/bin/install-files:ro diff --git a/docker/svelte/entrypoint.sh b/docker/svelte/entrypoint.sh new file mode 100755 index 0000000..1fdb055 --- /dev/null +++ b/docker/svelte/entrypoint.sh @@ -0,0 +1,16 @@ +#!/bin/sh +set -e + +fix_directory_permission() { + + mkdir -p "$1" + chown -R $USER_ID $1 +} + +fix_directory_permission ${YARN_CACHE_FOLDER} +fix_directory_permission /tmp +fix_directory_permission /app/.svelte-kit +fix_directory_permission /static-svelte + +# note that we need to have su-exec available in our container +exec su-exec $USER_ID "$@" diff --git a/scripts/bin/install-files b/scripts/bin/install-files index 1153eb0..82a3d01 100755 --- a/scripts/bin/install-files +++ b/scripts/bin/install-files @@ -41,7 +41,7 @@ _install_files () { rm -rf $NEXT # copy the file to the next path - cp -Rp $SOURCE $NEXT + cp -R $SOURCE $NEXT # swiftly rename current to previous and next to current mv $CURRENT $PREVIOUS diff --git a/scripts/lib/init b/scripts/lib/init index a425cdd..20f9ddf 100644 --- a/scripts/lib/init +++ b/scripts/lib/init @@ -1,10 +1,11 @@ #!/bin/bash -# --- Environment Variables +# --- Base Environment Variables SCRIPTS=$(dirname "$0") THIS=$(basename "$0") ROOT=$(realpath $SCRIPTS/..) +DATA=$ROOT/data # --- Common functions @@ -21,3 +22,7 @@ handle-node-commands "$@" # in some cases (like global help) we just want to stop the execution immediately [ $STOP ] && exit 0 + +# --- Other Environment Variables + +config USER_ID "$UID" From 4e536484892dcf593bccc318fa6750628a1bc70b Mon Sep 17 00:00:00 2001 From: tacone Date: Tue, 18 May 2021 18:03:25 +0200 Subject: [PATCH 2/8] docker: convert environment sections to objects --- docker/backend/docker-compose.dev.yml | 2 +- docker/backend/docker-compose.yml | 10 +++++----- docker/frontend/docker-compose.dev.yml | 2 +- docker/frontend/docker-compose.yml | 8 ++++---- docker/svelte/docker-compose.dev.yml | 2 +- docker/svelte/docker-compose.yml | 8 ++++---- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docker/backend/docker-compose.dev.yml b/docker/backend/docker-compose.dev.yml index d051e2d..6d60e73 100644 --- a/docker/backend/docker-compose.dev.yml +++ b/docker/backend/docker-compose.dev.yml @@ -14,7 +14,7 @@ services: # 🌳 environment: - - NODE_ENV=development + NODE_ENV: development # 👻 restart: "no" diff --git a/docker/backend/docker-compose.yml b/docker/backend/docker-compose.yml index d993218..26e7b5d 100644 --- a/docker/backend/docker-compose.yml +++ b/docker/backend/docker-compose.yml @@ -19,11 +19,11 @@ services: # 🌳 environment: - - NODE_ENV=production - - DATABASE_URL=${POSTGRES_CONNECTION_URL}/${POSTGRES_DATABASE} - - SHADOW_DATABASE_URL=${POSTGRES_CONNECTION_URL}/${POSTGRES_DATABASE}_shadow - - ROOT_DATABASE_URL=${POSTGRES_CONNECTION_URL}/${POSTGRES_DATABASE}_root - - YARN_DISABLE_SELF_UPDATE_CHECK=true + NODE_ENV: production + DATABASE_URL: ${POSTGRES_CONNECTION_URL}/${POSTGRES_DATABASE} + SHADOW_DATABASE_URL: ${POSTGRES_CONNECTION_URL}/${POSTGRES_DATABASE}_shadow + ROOT_DATABASE_URL: ${POSTGRES_CONNECTION_URL}/${POSTGRES_DATABASE}_root + YARN_DISABLE_SELF_UPDATE_CHECK: "true" # 🔗 ports: diff --git a/docker/frontend/docker-compose.dev.yml b/docker/frontend/docker-compose.dev.yml index 9c2e4e3..7755b5c 100644 --- a/docker/frontend/docker-compose.dev.yml +++ b/docker/frontend/docker-compose.dev.yml @@ -14,7 +14,7 @@ services: # 🌳 environment: - - NODE_ENV=development + NODE_ENV: development # 👻 restart: "no" diff --git a/docker/frontend/docker-compose.yml b/docker/frontend/docker-compose.yml index 00552b6..751acdf 100644 --- a/docker/frontend/docker-compose.yml +++ b/docker/frontend/docker-compose.yml @@ -23,10 +23,10 @@ services: # 🌳 environment: - - NODE_ENV=production - - NEXT_PUBLIC_GRAPHQL_ENDPOINT=${GRAPHQL_ENDPOINT} - - NEXT_TELEMETRY_DISABLED=1 - - YARN_DISABLE_SELF_UPDATE_CHECK=true + NODE_ENV: production + NEXT_PUBLIC_GRAPHQL_ENDPOINT: ${GRAPHQL_ENDPOINT} + NEXT_TELEMETRY_DISABLED: 1 + YARN_DISABLE_SELF_UPDATE_CHECK: "true" # 🔗 ports: diff --git a/docker/svelte/docker-compose.dev.yml b/docker/svelte/docker-compose.dev.yml index 061448a..9a4ff15 100644 --- a/docker/svelte/docker-compose.dev.yml +++ b/docker/svelte/docker-compose.dev.yml @@ -14,7 +14,7 @@ services: # 🌳 environment: - - NODE_ENV=development + NODE_ENV: development # 🔗 ports: diff --git a/docker/svelte/docker-compose.yml b/docker/svelte/docker-compose.yml index 1ca6d02..f1489c5 100644 --- a/docker/svelte/docker-compose.yml +++ b/docker/svelte/docker-compose.yml @@ -27,10 +27,10 @@ services: # 🌳 environment: - - NODE_ENV=production - - VITE_GRAPHQL_ENDPOINT=${GRAPHQL_ENDPOINT} - - YARN_DISABLE_SELF_UPDATE_CHECK=true - - YARN_CACHE_FOLDER=/usr/local/share/.cache/yarn + NODE_ENV: production + VITE_GRAPHQL_ENDPOINT: ${GRAPHQL_ENDPOINT} + YARN_DISABLE_SELF_UPDATE_CHECK: "true" + YARN_CACHE_FOLDER: /usr/local/share/.cache/yarn # 🔗 ports: From 1bb1ce8b02e9ce1aef313dca3ddf89ceee49a8d2 Mon Sep 17 00:00:00 2001 From: tacone Date: Tue, 18 May 2021 18:19:10 +0200 Subject: [PATCH 3/8] refactoring entrypoint and permissions fix --- docker/svelte/docker-compose.yml | 6 +++++- docker/svelte/entrypoint.sh | 16 ---------------- scripts/bin/entrypoint.sh | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 17 deletions(-) delete mode 100755 docker/svelte/entrypoint.sh create mode 100755 scripts/bin/entrypoint.sh diff --git a/docker/svelte/docker-compose.yml b/docker/svelte/docker-compose.yml index f1489c5..c9a918a 100644 --- a/docker/svelte/docker-compose.yml +++ b/docker/svelte/docker-compose.yml @@ -31,6 +31,10 @@ services: VITE_GRAPHQL_ENDPOINT: ${GRAPHQL_ENDPOINT} YARN_DISABLE_SELF_UPDATE_CHECK: "true" YARN_CACHE_FOLDER: /usr/local/share/.cache/yarn + chown_yarn: /usr/local/share/.cache/yarn + chown_tmp: /tmp + chown_svelte: /app/.svelte-kit + chown_static_files: /static-svelte # 🔗 ports: @@ -50,7 +54,7 @@ services: # 📂 volumes: # a custom entrypoint to fix permissions (depends on su-exec) - - ./docker/svelte/entrypoint.sh:/entrypoint.sh # 🔑 + - ./scripts/bin/entrypoint.sh:/entrypoint.sh # 🔑 # make these directories writable - ./data/svelte:/app/.svelte-kit diff --git a/docker/svelte/entrypoint.sh b/docker/svelte/entrypoint.sh deleted file mode 100755 index 1fdb055..0000000 --- a/docker/svelte/entrypoint.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -set -e - -fix_directory_permission() { - - mkdir -p "$1" - chown -R $USER_ID $1 -} - -fix_directory_permission ${YARN_CACHE_FOLDER} -fix_directory_permission /tmp -fix_directory_permission /app/.svelte-kit -fix_directory_permission /static-svelte - -# note that we need to have su-exec available in our container -exec su-exec $USER_ID "$@" diff --git a/scripts/bin/entrypoint.sh b/scripts/bin/entrypoint.sh new file mode 100755 index 0000000..0609522 --- /dev/null +++ b/scripts/bin/entrypoint.sh @@ -0,0 +1,18 @@ +#!/bin/sh +set -e + +fix_owner() { + mkdir -p "$1" + chown -R $USER_ID $1 +} + +# fix writable folders with the right owner +for i in $(env | grep chown_ | sed 's/^.*=//') +do + fix_owner "$i" +done + + +# note that we need to have su-exec available in our container +exec su-exec $USER_ID "$@" +fix_directory_permission \ No newline at end of file From 48e0bd887506cefe0b31c4461797fce6b2093784 Mon Sep 17 00:00:00 2001 From: tacone Date: Tue, 18 May 2021 21:47:31 +0200 Subject: [PATCH 4/8] docker: fix entrypoint --- scripts/bin/entrypoint.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/bin/entrypoint.sh b/scripts/bin/entrypoint.sh index 0609522..df88919 100755 --- a/scripts/bin/entrypoint.sh +++ b/scripts/bin/entrypoint.sh @@ -3,7 +3,7 @@ set -e fix_owner() { mkdir -p "$1" - chown -R $USER_ID $1 + chown -R $USER_ID $1 } # fix writable folders with the right owner @@ -15,4 +15,3 @@ done # note that we need to have su-exec available in our container exec su-exec $USER_ID "$@" -fix_directory_permission \ No newline at end of file From 2b16052341935e5f06311a9c640cd0f358a28176 Mon Sep 17 00:00:00 2001 From: tacone Date: Tue, 18 May 2021 21:55:31 +0200 Subject: [PATCH 5/8] docker: replace-files shouldn't preserve permissions --- scripts/bin/replace-files | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bin/replace-files b/scripts/bin/replace-files index 8a4caf0..1e819c0 100755 --- a/scripts/bin/replace-files +++ b/scripts/bin/replace-files @@ -32,7 +32,7 @@ _replace_files () { set -ex rm -rf $DESTINATION/* - cp $SOURCE/* $DESTINATION -Rp + cp $SOURCE/* $DESTINATION -R } _replace_files "$@" From 0d7aa2a1e63ff1f708da79c5a615a5097ff4dc59 Mon Sep 17 00:00:00 2001 From: tacone Date: Tue, 18 May 2021 21:59:56 +0200 Subject: [PATCH 6/8] =?UTF-8?q?frontend:=20run=20app=20as=20an=20unprivile?= =?UTF-8?q?dged=20user=20=F0=9F=94=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit notes: - dev mode doesn't work if source files belong to a different owner than $USER_ID - dev/production command will have root permissions as it doesn't execute the entrypoint other than that everything is pretty cool --- docker/frontend/Dockerfile | 14 +++++++++++--- docker/frontend/docker-compose.dev.yml | 2 +- docker/frontend/docker-compose.yml | 24 +++++++++++++++++++++--- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/docker/frontend/Dockerfile b/docker/frontend/Dockerfile index 885564b..8a18a96 100644 --- a/docker/frontend/Dockerfile +++ b/docker/frontend/Dockerfile @@ -1,7 +1,9 @@ FROM node:16-alpine -# we need it to brotli compress the static export -RUN apk add brotli +# we need: +# - brotli compress the static export +# - su-exec to downgrade user permissions ( https://github.com/ncopa/su-exec ) +RUN apk add brotli su-exec # declare the NODE_ENV. This will invalidate the cache from now on if # NODE_ENV changes. @@ -43,4 +45,10 @@ RUN echo 'BUILD_COMMAND set to '${BUILD_COMMAND} RUN if [ "$NODE_ENV" = 'production' ]; then sh -c "$BUILD_COMMAND"; else echo 'Skipping export'; fi -RUN if [ "$NODE_ENV" = 'production' ]; then cp /app/.next /next-build-files -Rp; fi \ No newline at end of file +RUN if [ "$NODE_ENV" = 'production' ]; then cp /app/.next /build-files -Rp; fi + +# 🔑 +ARG USER_ID +RUN echo 'USER_ID set to ${USER_ID}' + +RUN adduser -S app -u ${USER_ID} || echo USER ${USER_ID} already exists. diff --git a/docker/frontend/docker-compose.dev.yml b/docker/frontend/docker-compose.dev.yml index 7755b5c..cd6f80d 100644 --- a/docker/frontend/docker-compose.dev.yml +++ b/docker/frontend/docker-compose.dev.yml @@ -27,4 +27,4 @@ services: # and download the depencencies there so they can be parsed # by the IDE # 🚀 - command: sh -c "yarn && yarn run dev" \ No newline at end of file + command: sh -c "yarn && whoami && yarn run dev" \ No newline at end of file diff --git a/docker/frontend/docker-compose.yml b/docker/frontend/docker-compose.yml index 751acdf..c9bfb4e 100644 --- a/docker/frontend/docker-compose.yml +++ b/docker/frontend/docker-compose.yml @@ -16,17 +16,27 @@ services: yarn run build && brotli-compress /app/.next/static - # env variables needed by the build + # the UID we'll use to run the app, use 0 if you want root + USER_ID: ${USER_ID} # 🔑 + # other env variables needed by the build NODE_ENV: production NEXT_TELEMETRY_DISABLED: 1 NEXT_PUBLIC_GRAPHQL_ENDPOINT: ${GRAPHQL_ENDPOINT} + # 🚪 a custom entrypoint to fix permissions + entrypoint: /entrypoint.sh # 🔑 + # 🌳 environment: NODE_ENV: production NEXT_PUBLIC_GRAPHQL_ENDPOINT: ${GRAPHQL_ENDPOINT} NEXT_TELEMETRY_DISABLED: 1 YARN_DISABLE_SELF_UPDATE_CHECK: "true" + USER_ID: ${USER_ID} + chown_yarn: /usr/local/share/.cache/yarn + chown_tmp: /tmp + chown_app: /app/.next + chown_static_files: /static # 🔗 ports: @@ -38,14 +48,22 @@ services: # 🛡️ make everything read-only except the volumes read_only: true + # always use root here, we'll change the user in the entrypoint + # to $USER_ID + # 🔑 + user: "0" + # 📂 volumes: + # a custom entrypoint to fix permissions (depends on su-exec) + - ./scripts/bin/entrypoint.sh:/entrypoint.sh # 🔑 + # make these directories writable - ./data/next:/app/.next # so we can write in /app/.next - /tmp/survey/frontend:/tmp # share yarn cache folder with the other containers - - ./data/yarn:/usr/local/share/.cache/yarn/ + - ./data/yarn-${USER_ID}:/usr/local/share/.cache/yarn # utility scripts - ./scripts/bin/install-files:/usr/local/bin/install-files:ro @@ -62,7 +80,7 @@ services: # 🚀 command: >- sh -c ' - replace-files /next-build-files /app/.next + replace-files /build-files /app/.next && install-files /app/.next/static /static && yarn run start ' From f54d5ae7192909c35bacf442ddacfa21bb626f83 Mon Sep 17 00:00:00 2001 From: tacone Date: Tue, 18 May 2021 23:02:00 +0200 Subject: [PATCH 7/8] svelte: fix build, refactor, document docker-compose --- docker/svelte/Dockerfile | 2 ++ docker/svelte/docker-compose.yml | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docker/svelte/Dockerfile b/docker/svelte/Dockerfile index 7ff1b38..162eaef 100644 --- a/docker/svelte/Dockerfile +++ b/docker/svelte/Dockerfile @@ -43,6 +43,8 @@ RUN echo 'BUILD_COMMAND set to '${BUILD_COMMAND} RUN if [ "$NODE_ENV" = 'production' ]; then sh -c "$BUILD_COMMAND"; else echo 'Skipping export'; fi +RUN if [ "$NODE_ENV" = 'production' ]; then cp /app/.svelte-kit /build-files -Rp; fi + # 🔑 ARG USER_ID ENV USER_ID ${USER_ID} diff --git a/docker/svelte/docker-compose.yml b/docker/svelte/docker-compose.yml index c9a918a..2f711bd 100644 --- a/docker/svelte/docker-compose.yml +++ b/docker/svelte/docker-compose.yml @@ -30,10 +30,9 @@ services: NODE_ENV: production VITE_GRAPHQL_ENDPOINT: ${GRAPHQL_ENDPOINT} YARN_DISABLE_SELF_UPDATE_CHECK: "true" - YARN_CACHE_FOLDER: /usr/local/share/.cache/yarn chown_yarn: /usr/local/share/.cache/yarn chown_tmp: /tmp - chown_svelte: /app/.svelte-kit + chown_app: /app/.svelte-kit chown_static_files: /static-svelte # 🔗 @@ -46,7 +45,7 @@ services: # 🛡️ make everything read-only except the volumes read_only: true - # use root here, we'll change the user in the entrypoint + # always use root here, we'll change the user in the entrypoint # to $USER_ID # 🔑 user: "0" @@ -78,8 +77,9 @@ services: # 🚀 command: >- sh -c ' - replace-files /build-files /app/.svelte-kit - install-files /app/build/assets /static-svelte && yarn run start + replace-files /build-files /app/.svelte-kit && + install-files /app/build/assets /static-svelte && + yarn run start ' # 📂 From e3967ae2a6bb50c902d035f338caa97e162540b8 Mon Sep 17 00:00:00 2001 From: tacone Date: Tue, 18 May 2021 23:30:00 +0200 Subject: [PATCH 8/8] =?UTF-8?q?backend:=20run=20app=20as=20an=20unpriviled?= =?UTF-8?q?ged=20user=20=F0=9F=94=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/.gmrc | 4 ++++ docker/backend/Dockerfile | 20 +++++++++++++++----- docker/backend/docker-compose.dev.yml | 2 ++ docker/backend/docker-compose.yml | 24 ++++++++++++++++++++++-- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/backend/.gmrc b/backend/.gmrc index 417f732..fc54a65 100644 --- a/backend/.gmrc +++ b/backend/.gmrc @@ -99,6 +99,10 @@ // NOTE: this script does nothing when envvar `IN_TESTS` is `1` "command": "node src/dump-db.js" }, + { + "_": "command", + "command": "chmod +r migrations -R" + }, ], /* diff --git a/docker/backend/Dockerfile b/docker/backend/Dockerfile index ceba79c..add99d6 100644 --- a/docker/backend/Dockerfile +++ b/docker/backend/Dockerfile @@ -1,20 +1,20 @@ FROM node:16-alpine -RUN apk add --no-cache postgresql-client +RUN apk add --no-cache postgresql-client su-exec # copy the deps files, download and cache dependencies COPY ./backend/package.json ./backend/yarn.loc[k] /deps/ WORKDIR /deps -ARG BUILD_COMMAND -ENV BUILD_COMMAND ${BUILD_COMMAND} -RUN echo 'BUILD_COMMAND set to '${BUILD_COMMAND} - +# declare the NODE_ENV. This will invalidate the cache from now on if +# NODE_ENV changes. ARG NODE_ENV ENV NODE_ENV ${NODE_ENV} RUN echo 'NODE_ENV set to '${NODE_ENV} +ENV YARN_CACHE_FOLDER /usr/local/share/.cache/yarn + RUN [ "$NODE_ENV" = 'production' ] && yarn --frozen-lockfile || echo "Skipping dependencies download during non-production build" # copy the application code @@ -25,4 +25,14 @@ RUN [ "$NODE_ENV" = 'production' ] && mv -f package.json /app && mv -f yarn.lock WORKDIR /app +ARG BUILD_COMMAND +ENV BUILD_COMMAND ${BUILD_COMMAND} +RUN echo 'BUILD_COMMAND set to '${BUILD_COMMAND} + RUN if [ "$NODE_ENV" = 'production' ]; then $BUILD_COMMAND || echo 'Skipping export'; fi + +# 🔑 +ARG USER_ID +RUN echo 'USER_ID set to ${USER_ID}' + +RUN adduser -S app -u ${USER_ID} || echo USER ${USER_ID} already exists. diff --git a/docker/backend/docker-compose.dev.yml b/docker/backend/docker-compose.dev.yml index 6d60e73..a34199f 100644 --- a/docker/backend/docker-compose.dev.yml +++ b/docker/backend/docker-compose.dev.yml @@ -15,6 +15,8 @@ services: # 🌳 environment: NODE_ENV: development + chown_app: /app/generated + chown_migrations: /app/migrations # 👻 restart: "no" diff --git a/docker/backend/docker-compose.yml b/docker/backend/docker-compose.yml index 26e7b5d..ebfd940 100644 --- a/docker/backend/docker-compose.yml +++ b/docker/backend/docker-compose.yml @@ -14,9 +14,14 @@ services: args: BUILD_COMMAND: yarn run build - # env variables needed by the build + # the UID we'll use to run the app, use 0 if you want root + USER_ID: ${USER_ID} # 🔑 + # other env variables needed by the build NODE_ENV: production + # 🚪 a custom entrypoint to fix permissions + entrypoint: /entrypoint.sh # 🔑 + # 🌳 environment: NODE_ENV: production @@ -24,6 +29,8 @@ services: SHADOW_DATABASE_URL: ${POSTGRES_CONNECTION_URL}/${POSTGRES_DATABASE}_shadow ROOT_DATABASE_URL: ${POSTGRES_CONNECTION_URL}/${POSTGRES_DATABASE}_root YARN_DISABLE_SELF_UPDATE_CHECK: "true" + USER_ID: ${USER_ID} + chown_tmp: /tmp # 🔗 ports: @@ -35,10 +42,23 @@ services: # 🛡️ make everything read-only except the volumes read_only: true + # always use root here, we'll change the user in the entrypoint + # to $USER_ID + # 🔑 + user: "0" + # 📂 volumes: - - ./data/yarn:/usr/local/share/.cache/yarn/ + # a custom entrypoint to fix permissions (depends on su-exec) + - ./scripts/bin/entrypoint.sh:/entrypoint.sh # 🔑 + + # make these directories writable - /tmp/survey/backend:/tmp + + # share yarn cache folder with the other containers + - ./data/yarn-${USER_ID}:/usr/local/share/.cache/yarn + + # utility scripts - ./scripts/bin/wait-port:/usr/local/bin/wait-port:ro # 🔧