Skip to content

Commit

Permalink
ci: non-root container image (#437)
Browse files Browse the repository at this point in the history
Make image work in a nonroot environment.

* Docker: fully-qualified image names

Consistency and compatibility with more container runtimes and builders.

* Docker: rewrite to use unprivileged NGINX

Instead of manually modifying the image to work in a non-root
environment, use the official unprivileged NGINX image. To install
packages and perform other privileged tasks, temporarily switch to root
and subsequently switch back.

Additionally, use the native envsubst templating already integrated into
the NGINX images instead of recreating it. The reason it was not
triggering before is that the entrypoint script in the base image checks
if the command is `nginx` or `nginx-debug` and if not just executes the
command directly without running any further setup.

---------

Co-authored-by: Thomas <60181704+tsk9@users.noreply.github.com>
  • Loading branch information
sybereal and tsk9 authored Aug 16, 2023
1 parent 73b071e commit 6912794
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 17 deletions.
5 changes: 5 additions & 0 deletions docker/99-generate-app-config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh

set -e

jq -n 'env | with_entries( select(.key | startswith("EDC_UI_") ) )' > /tmp/app-config.json
35 changes: 20 additions & 15 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,37 +1,42 @@
# Stage 1: Install node modules
FROM node:lts as npm-install
FROM docker.io/library/node:lts as npm-install

WORKDIR /app
COPY ./package*.json /app/
RUN npm install

# Stage 2: Build Project
FROM node:lts as build
FROM docker.io/library/node:lts as build

WORKDIR /app
COPY --from=npm-install /app/node_modules /app/node_modules
COPY ./ /app/
RUN npm run ng build --no-progress --configuration=production

# Stage 3: Serve app with nginx
FROM nginx:1.25.2-alpine
FROM docker.io/nginxinc/nginx-unprivileged:1.25-alpine3.18

RUN apk update && apk add jq esh --no-cache
# Temporarily switch to root to install packages and create symlink in restricted location
USER root
RUN apk add --no-cache jq curl

COPY --from=build /app/dist/edc-demo-client /usr/share/nginx/html
COPY --from=build /app/src/assets /usr/share/nginx/html/assets
COPY docker/default.conf.esh etc/nginx/conf.d/default.conf.esh
COPY docker/default.conf.template etc/nginx/templates/default.conf.template
# Before starting nginx, apply ENV vars to create app-config.json from EDC_UI_* ENV Vars
# Use an entrypoint drop-in instead of modifying the default entrypoint or command,
# so that the automatic envsubst templating is not disabled.
COPY docker/99-generate-app-config.sh /docker-entrypoint.d/99-generate-app-config.sh

ENV NGINX_BIND=""
ENV NGINX_PORT=80
RUN ln -sf /tmp/app-config.json /usr/share/nginx/html/assets/config/app-config.json \
# Nginx is configured to reject symlinks that point to a file owned by a different user, for security reasons
&& chown --no-dereference nginx:root /usr/share/nginx/html/assets/config/app-config.json

HEALTHCHECK --interval=2s --timeout=5s --retries=10 \
CMD curl -f http://${NGINX_BIND:"localhost"}:$NGINX_PORT/ || exit 1
# Switch back to unprivileged user for runtime
USER nginx:nginx

# Before starting nginx, apply ENV vars:
# (1) Apply NGINX_BIND and NGINX_PORT to nginx.conf
# (2) Create app-config.json from EDC_UI_* ENV Vars
CMD esh -o /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.esh \
&& jq -n 'env | with_entries( select(.key | startswith("EDC_UI_") ) )' > /usr/share/nginx/html/assets/config/app-config.json \
&& nginx -g "daemon off;"
ENV NGINX_BIND="0.0.0.0"
ENV NGINX_PORT=8080

HEALTHCHECK --interval=2s --timeout=5s --retries=10 \
CMD curl -f http://$NGINX_BIND:$NGINX_PORT/ || exit 1
7 changes: 5 additions & 2 deletions docker/default.conf.esh → docker/default.conf.template
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
access_log /dev/stdout;
error_log /dev/stderr;
disable_symlinks if_not_owner;

server {
listen <%= $NGINX_BIND %><% if "$NGINX_BIND" ; then -%>:<% fi -%><%= $NGINX_PORT %>;
listen ${NGINX_BIND}:${NGINX_PORT};
server_name localhost;

root /usr/share/nginx/html;
Expand All @@ -9,4 +13,3 @@ server {
try_files $uri $uri/ /index.html;
}
}

0 comments on commit 6912794

Please sign in to comment.