diff --git a/bin/docker-compose b/bin/docker-compose index e69978b..d6577ad 100755 --- a/bin/docker-compose +++ b/bin/docker-compose @@ -48,6 +48,10 @@ function __main__() { if [[ "$SIBLING_CONTAINERS_ENABLED" == "true" ]]; then compose_file_flags+=("-f $TOOLKIT_ROOT/lib/docker-compose.sibling-containers.yml") fi + if [[ "$NGINX_ENABLED" == "true" ]]; then + compose_file_flags+=("-f $TOOLKIT_ROOT/lib/docker-compose.nginx.yml") + fi + # Include docker-compose.override.yml if it is present if [[ -f "$TOOLKIT_ROOT/config/docker-compose.override.yml" ]]; then @@ -94,6 +98,7 @@ function __main__() { export REDIS_DATA_PATH export REDIS_HOST export REDIS_PORT + export OL_DOMAINS # shellcheck disable=SC2068 exec docker-compose -p "$project_name" ${compose_file_flags[@]} "$@" diff --git a/doc/README.md b/doc/README.md index 6f3fe64..7673e79 100644 --- a/doc/README.md +++ b/doc/README.md @@ -23,6 +23,7 @@ documentation on the [Overleaf Wiki](https://github.com/overleaf/overleaf/wiki) - [Configuration Overview](./configuration.md) - [overleaf.rc](./overleaf-rc.md) +- [TLS proxy](./tls-proxy.md) ## Persistent Data diff --git a/doc/overleaf-rc.md b/doc/overleaf-rc.md index 2272f33..2007945 100644 --- a/doc/overleaf-rc.md +++ b/doc/overleaf-rc.md @@ -105,3 +105,7 @@ Specifies the Redis port to use when `REDIS_ENABLED` is `false` Sets the path to the directory that will be mounted into the `redis` container, and used to store the Redis database. This can be either a full path (beginning with a `/`), or relative to the base directory of the toolkit. This option only affects the local `redis` container that is created when `REDIS_ENABLED` is `true`. - Default: data/redis + +### `OL_DOMAINS` + +A comma separated list of host names for which a TLS certificate will be generated when using the [TLS Proxy](./tls-proxy.md) \ No newline at end of file diff --git a/doc/tls-proxy.md b/doc/tls-proxy.md new file mode 100644 index 0000000..cfa3d04 --- /dev/null +++ b/doc/tls-proxy.md @@ -0,0 +1,57 @@ +## TLS Proxy for Overleaf Toolkit environment + +This provides an nginx proxy for overleaf-toolkit with TLS certificates loaded. + +The first time you bring up the toolkit environment, this will generate TLS certificates for the web server(s) and a CA certificate in `tls_proxy/certs`. + +The TLS certificates will be generated for a comma-separated list of domains specified in the `OL_DOMAINS` environment variable. The default value is for `localhost` and `overleaf-toolkit.com`. + +For local testing you can add `overleaf-toolkit.com` to your `/etc/hosts` file. + + +**Mac users note:** Apache may be running on your machine by default. If the toolkit environment fails to come up, you should run `sudo apachectl stop`. To make this change permanent, run: `sudo launchctl unload -w /Applications/Server.app/Contents/ServerRoot/System/Library/LaunchDaemons/com.apple.serviceproxy.plist`. + +You will need to configure your system to trust the new CA certificate, so that you get a green padlock in your browser and can use command-line tools like `curl`. + +The new root CA certificate you need to trust will be `tls_proxy/certs/minica.pem` and you should add it thusly: + +### On Mac + +Run this command: + +``` +sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain tls_proxy/certs/minica.pem +``` + +##### Using Firefox? + +You need to manually add the certificate to Firefox. +To do so go to Firefox's settings and search for the "Certificates" section. Click "View Certificates..." then "Import...". + +### On Linux + +Linux is more complicated, as not all trust stores work the same way and it can differ based on distribution. + +To add the certificate to the system-wide trust store so that command-line tools work, run these commands, after bringing up the toolkit env: + +``` +sudo mkdir -p /usr/local/share/ca-certificates +sudo cp tls_proxy/certs/minica.pem /usr/local/share/ca-certificates/minica.crt +# note different extension here +sudo update-ca-certificates +``` + +Unfortunately, your *browser* will not trust the system CA store. Instead you need to run (as your normal user, not root): + +``` +certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "Overleaf Minica" -i tls_proxy/certs/minica.pem +``` +If running Chromium as a snap (e.g. on Ubuntu > 20.04) run +``` +certutil -d $HOME/snap/chromium/current/.pki/nssdb -A -t "C,," -n "Overleaf Minica" -i tls_proxy/certs/minica.pem +``` + +This should work, but might not in all cases. If your browser still does not trust the site certificate at https://localhost/ you may need to manually add it to the list of trusted certificates in your browser's settings. + +``` + diff --git a/lib/config-seed/overleaf.rc b/lib/config-seed/overleaf.rc index e525211..ff40fea 100644 --- a/lib/config-seed/overleaf.rc +++ b/lib/config-seed/overleaf.rc @@ -18,3 +18,7 @@ MONGO_DATA_PATH=data/mongo # Redis configuration REDIS_ENABLED=true REDIS_DATA_PATH=data/redis + +# TLS Proxy +NGINX_ENABLED=false +OL_DOMAINS=localhost,*.localhost,overleaf-toolkit.com,*.overleaf-toolkit.com diff --git a/lib/docker-compose.nginx.yml b/lib/docker-compose.nginx.yml new file mode 100644 index 0000000..6401c1c --- /dev/null +++ b/lib/docker-compose.nginx.yml @@ -0,0 +1,16 @@ +--- +version: '2.2' +services: + + tls_proxy: + build: ../tls_proxy + ports: + - 127.0.0.1:443:18443 + volumes: + - ./../tls_proxy/certs:/certs + - ./../tls_proxy/nginx.conf:/etc/nginx/nginx.conf + environment: + OL_DOMAINS: "${OL_DOMAINS}" + restart: on-failure:5 + depends_on: + - sharelatex \ No newline at end of file diff --git a/tls_proxy/Dockerfile b/tls_proxy/Dockerfile new file mode 100644 index 0000000..3ee10d9 --- /dev/null +++ b/tls_proxy/Dockerfile @@ -0,0 +1,15 @@ +FROM golang:alpine AS build +RUN apk add git +RUN go get github.com/jsha/minica + +FROM nginx:alpine + +VOLUME /certs + +COPY --from=build /go/bin/minica /usr/bin/minica +ADD run.sh /run.sh +ADD nginx.conf /etc/nginx/nginx.conf + +EXPOSE 18443 + +CMD /run.sh diff --git a/tls_proxy/certs/.gitignore b/tls_proxy/certs/.gitignore new file mode 100644 index 0000000..cfaad76 --- /dev/null +++ b/tls_proxy/certs/.gitignore @@ -0,0 +1 @@ +*.pem diff --git a/tls_proxy/nginx.conf b/tls_proxy/nginx.conf new file mode 100644 index 0000000..e8762bb --- /dev/null +++ b/tls_proxy/nginx.conf @@ -0,0 +1,70 @@ +user nginx; +worker_processes 1; + +error_log /dev/stderr notice; + +events { + worker_connections 1024; + use epoll; +} + +http { + resolver 127.0.0.11 ipv6=off valid=30s; + + include 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 /dev/stdout main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + + keepalive_timeout 65; + + gzip on; + + + + server { + listen 18443 ssl; + server_name _; # Catch all, see http://nginx.org/en/docs/http/server_names.html + + server_name overleaf-toolkit.com; + ssl_certificate /certs/nginx_certificate.pem; + ssl_certificate_key /certs/nginx_key.pem; + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + + # used cloudflares ciphers https://github.com/cloudflare/sslconfig/blob/master/conf + ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; + + # config to enable HSTS(HTTP Strict Transport Security) https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security + # to avoid ssl stripping https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping + add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; + + server_tokens off; + + add_header X-Frame-Options SAMEORIGIN; + + add_header X-Content-Type-Options nosniff; + + client_max_body_size 50M; + + location / { + proxy_pass http://sharelatex:80; # change to whatever host/port the docker container is listening on. + proxy_set_header X-Forwarded-Proto $scheme; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_read_timeout 3m; + proxy_send_timeout 3m; + } + } +} \ No newline at end of file diff --git a/tls_proxy/run.sh b/tls_proxy/run.sh new file mode 100755 index 0000000..08676ac --- /dev/null +++ b/tls_proxy/run.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +CERT_FOLDER=${OL_DOMAINS%%,*} + +cd /certs +rm -rf $CERT_FOLDER + +/usr/bin/minica --domains $OL_DOMAINS && \ + cat $CERT_FOLDER/cert.pem minica.pem > nginx_certificate.pem && \ + cp $CERT_FOLDER/key.pem nginx_key.pem && \ + chmod a+r *.pem && \ + rm -rf $CERT_FOLDER + +nginx -g "daemon off;" +