diff --git a/Dockerfile b/Dockerfile index 34dc02ee..c6818809 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,12 +10,11 @@ RUN npm run build # run FROM nginx:alpine +COPY --from=node /app/startup /app/startup COPY --from=node /app/dist/vantage6-UI /usr/share/nginx/html - -# add option to not share server info to nginx config file. Be sure to do this -# in the http block, which is achieved by matching that line -RUN sed -i '/http {/a \ \ \ \ server_tokens off;' /etc/nginx/nginx.conf +# Copy nginx config file to container +COPY nginx.conf /etc/nginx/nginx.conf # When the container starts, replace the env.js with values from environment variables and then startup app -CMD ["/bin/sh", "-c", "envsubst < /usr/share/nginx/html/assets/env.template.js > /usr/share/nginx/html/assets/env.js && exec nginx -g 'daemon off;'"] \ No newline at end of file +CMD ["/bin/sh", "-c", "/app/startup/replace_env_vars.sh && exec nginx -g 'daemon off;'"] \ No newline at end of file diff --git a/README.md b/README.md index 437854ae..923ddea5 100644 --- a/README.md +++ b/README.md @@ -71,3 +71,21 @@ If you don't enter environment variables, the UI points to Note that you can also use another UI image tag than `ui:latest`. For example, you can specify a version of the UI such as `ui:3.6.0`. Another option is to use the tag `ui:cotopaxi`, which defaults to the latest v4 version. + +#### Security settings + +Finally, there is also an environment variable `ALLOWED_ALGORITHM_STORES` that +you can specify. If you do so, the appropriate +[CSP headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) will be +set so that your UI can only access the vantage6 server and algorithm stores +to collect data from. You define them same as other environment variables, with +spaces in between each algorithm store you want to allow traffic from: + +``` +docker run --env ALLOWED_ALGORITHM_STORES="store.cotopaxi.vantage6.ai myotherstore.com" ... +``` + +Note that if you do *not* specify this environment variable, the CSP policy +will be very lenient. In order for the UI to work properly, algorithm store +resources should be obtained, so if no algorithm stores are provided, all +URIs will be allowed. \ No newline at end of file diff --git a/angular.json b/angular.json index 775205b7..e3f84264 100644 --- a/angular.json +++ b/angular.json @@ -41,7 +41,15 @@ "maximumError": "4kb" } ], - "outputHashing": "all" + "outputHashing": "all", + "optimization": { + "scripts": true, + "styles": { + "minify": true, + "inlineCritical": false + }, + "fonts": true + } }, "development": { "buildOptimizer": false, diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 00000000..d4f131db --- /dev/null +++ b/nginx.conf @@ -0,0 +1,46 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + # hide nginx version + server_tokens off; + + #### Add security headers + add_header Strict-Transport-Security "max-age=31536000; includeSubdomains" always; + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-Content-Type-Options "nosniff"; + add_header Cache-Control "no-cache, no-store"; + + # Add CSP policy. Allow the following URLs for the following reasons: + # - fonts.gstatic.com and fonts.googleapis.com: Google Fonts and Material Icons + # - localhost:* and ws://localhost:*: Webpack Dev Server + # - self: own content + # Note that in angular.json, the production 'optimization' configuration was + # updated to the value provided in https://stackoverflow.com/a/71302985/5398197 + # to prevent the need to add 'unsafe-inline' to the default-src directive. + add_header Content-Security-Policy "default-src 'self'; connect-src 'self' ws:// wss://; font-src https://fonts.gstatic.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com"; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + + keepalive_timeout 65; + + include /etc/nginx/conf.d/*.conf; +} \ No newline at end of file diff --git a/src/assets/env.js b/src/assets/env.js index a8a4a083..b0e74dc3 100644 --- a/src/assets/env.js +++ b/src/assets/env.js @@ -6,4 +6,5 @@ window["env"]["server_url"] = "https://cotopaxi.vantage6.ai"; window["env"]["api_path"] = ""; window["env"]["api_url"] = "https://cotopaxi.vantage6.ai"; + window["env"]["allowed_algorithm_stores"] = "*"; })(this); \ No newline at end of file diff --git a/src/assets/env.template.js b/src/assets/env.template.js index 1ab68d19..4e3a158a 100644 --- a/src/assets/env.template.js +++ b/src/assets/env.template.js @@ -6,4 +6,5 @@ window["env"]["api_url"] = "${API_URL}"; window["env"]["server_url"] = "${SERVER_URL}"; window["env"]["api_path"] = "${API_PATH}"; + window["env"]["allowed_algorithm_stores"] = "${ALLOWED_ALGORITHM_STORES}"; })(this); diff --git a/startup/replace_env_vars.sh b/startup/replace_env_vars.sh new file mode 100644 index 00000000..f6ec69e5 --- /dev/null +++ b/startup/replace_env_vars.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +# replace environment variables for angular app +envsubst < /usr/share/nginx/html/assets/env.template.js > /usr/share/nginx/html/assets/env.js + +# replace environment variables for nginx config. There the URL (without http(s)) +# is used in the Content-Security-Policy header. +# TODO the following process to set nginx configuration via sed is not ideal. Consider +# doing it by directly using env vars in nginx.conf (see https://github.com/docker-library/docs/tree/master/nginx#using-environment-variables-in-nginx-configuration-new-in-119) +if [ -z "${SERVER_URL}" ]; then + SERVER_URL="https://cotopaxi.vantage6.ai" +fi +# Remove http(s) from the server url +SERVER_URL_NO_HTTP=$(echo "$SERVER_URL" | sed 's/^https\?:\/\///g') +# escape the slashes in the url +SERVER_URL=$(echo "$SERVER_URL" | sed 's/\//\\\//g') +sed -i "s//$SERVER_URL/g" /etc/nginx/nginx.conf +sed -i "s//$SERVER_URL_NO_HTTP/g" /etc/nginx/nginx.conf + +# also whitelist the allowed algorithm stores in the CSP header +if [ -z "${ALLOWED_ALGORITHM_STORES}" ]; then + ALLOWED_ALGORITHM_STORES="*" +fi +# escape the slashes in the urls +ALLOWED_ALGORITHM_STORES=$(echo "$ALLOWED_ALGORITHM_STORES" | sed 's/\//\\\//g') +sed -i "s//$ALLOWED_ALGORITHM_STORES/g" /etc/nginx/nginx.conf