diff --git a/docker-unified/Dockerfile b/docker-unified/Dockerfile index 0a205e681..14927a7eb 100644 --- a/docker-unified/Dockerfile +++ b/docker-unified/Dockerfile @@ -214,6 +214,7 @@ RUN apk add --update-cache \ su-exec \ supervisor \ tzdata \ + unzip \ && rm -rf /var/cache/apk/* # Create non-root user to run app @@ -261,18 +262,18 @@ COPY docker-unified/nginx/logrotate.sh / RUN chmod +x /logrotate.sh # Copy configuration templates -COPY docker-unified/confd/nginx-config.toml /etc/confd/conf.d/ -COPY docker-unified/confd/nginx-config.conf.tmpl /etc/confd/templates/ -COPY docker-unified/confd/app-id.toml /etc/confd/conf.d/ -COPY docker-unified/confd/app-id.conf.tmpl /etc/confd/templates/ +COPY docker-unified/hbs/nginx-config.hbs /etc/hbs/ +COPY docker-unified/hbs/app-id.hbs /etc/hbs/ +COPY docker-unified/hbs/config.yaml /etc/hbs/ -# Download confd tool for generating final configurations -RUN if [ "$TARGETPLATFORM" = "linux/amd64" ] ; then curl -L --output confd.tar.gz https://github.com/abtreece/confd/releases/download/v0.19.1/confd-v0.19.1-linux-amd64.tar.gz; fi -RUN if [ "$TARGETPLATFORM" = "linux/arm/v7" ] ; then curl -L --output confd.tar.gz https://github.com/abtreece/confd/releases/download/v0.19.1/confd-v0.19.1-linux-arm7.tar.gz; fi -RUN if [ "$TARGETPLATFORM" = "linux/arm64" ] ; then curl -L --output confd.tar.gz https://github.com/abtreece/confd/releases/download/v0.19.1/confd-v0.19.1-linux-arm64.tar.gz; fi +# Download hbs tool for generating final configurations +RUN if [ "$TARGETPLATFORM" = "linux/amd64" ] ; then curl -L --output hbs.zip https://github.com/bitwarden/Handlebars.conf/releases/download/v1.2.0/hbs_linux-musl-x64_dotnet.zip; fi +RUN if [ "$TARGETPLATFORM" = "linux/arm/v7" ] ; then curl -L --output hbs.zip https://github.com/bitwarden/Handlebars.conf/releases/download/v1.2.0/hbs_linux-arm_dotnet.zip; fi +RUN if [ "$TARGETPLATFORM" = "linux/arm64" ] ; then curl -L --output hbs.zip https://github.com/bitwarden/Handlebars.conf/releases/download/v1.2.0/hbs_linux-arm64_dotnet.zip; fi -# Extract confd -RUN tar -xvzo -C /usr/local/bin -f confd.tar.gz && rm confd.tar.gz +# Extract hbs +RUN unzip hbs.zip -d /usr/local/bin && rm hbs.zip +RUN chmod +x /usr/local/bin/hbs # Copy entrypoint script and make it executable COPY docker-unified/entrypoint.sh /entrypoint.sh diff --git a/docker-unified/confd/app-id.toml b/docker-unified/confd/app-id.toml deleted file mode 100644 index 701c208bb..000000000 --- a/docker-unified/confd/app-id.toml +++ /dev/null @@ -1,6 +0,0 @@ -[template] -src = "app-id.conf.tmpl" -dest = "/app/Web/app-id.json" -keys = [ - "globalSettings__baseServiceUri__vault" -] diff --git a/docker-unified/confd/nginx-config.toml b/docker-unified/confd/nginx-config.toml deleted file mode 100644 index c3693c401..000000000 --- a/docker-unified/confd/nginx-config.toml +++ /dev/null @@ -1,17 +0,0 @@ -[template] -src = "nginx-config.conf.tmpl" -dest = "/etc/nginx/http.d/bitwarden.conf" -keys = [ - "BW_ENABLE_SSL_CA", - "BW_SSL_CA_CERT", - "BW_CSP", - "BW_ENABLE_KEY_CONNECTOR", - "BW_KEY_CONNECTOR_INTERNAL_URL", - "BW_REAL_IPS", - "BW_ENABLE_SSL", - "BW_SSL_CERT", - "BW_SSL_CIPHERS", - "BW_SSL_KEY", - "BW_SSL_PROTOCOLS", - "BW_ICONS_PROXY_TO_CLOUD" -] diff --git a/docker-unified/entrypoint.sh b/docker-unified/entrypoint.sh index a3e8af82e..8f33a5306 100644 --- a/docker-unified/entrypoint.sh +++ b/docker-unified/entrypoint.sh @@ -66,7 +66,7 @@ fi # Launch a loop to rotate nginx logs on a daily basis /bin/sh -c "/logrotate.sh loop >/dev/null 2>&1 &" -/usr/local/bin/confd -onetime -backend env +/usr/local/bin/hbs # Enable/Disable services sed -i "s/autostart=true/autostart=${BW_ENABLE_ADMIN}/" /etc/supervisor.d/admin.ini diff --git a/docker-unified/confd/app-id.conf.tmpl b/docker-unified/hbs/app-id.hbs similarity index 71% rename from docker-unified/confd/app-id.conf.tmpl rename to docker-unified/hbs/app-id.hbs index ef50fcafb..eed8768b4 100644 --- a/docker-unified/confd/app-id.conf.tmpl +++ b/docker-unified/hbs/app-id.hbs @@ -6,7 +6,7 @@ "minor": 0 }, "ids": [ - "{{ getenv "globalSettings__baseServiceUri__vault" "https://localhost" }}", + "{{{String.Coalesce env.globalSettings__baseServiceUri__vault "https://localhost"}}}", "ios:bundle-id:com.8bit.bitwarden", "android:apk-key-hash:dUGFzUzf3lmHSLBDBIv+WaFyZMI" ] diff --git a/docker-unified/hbs/config.yaml b/docker-unified/hbs/config.yaml new file mode 100644 index 000000000..2dc04a658 --- /dev/null +++ b/docker-unified/hbs/config.yaml @@ -0,0 +1,7 @@ +helper_categories: + - String +templates: + - src: /etc/hbs/app-id.hbs + dest: /app/Web/app-id.json + - src: /etc/hbs/nginx-config.hbs + dest: /etc/nginx/http.d/bitwarden.conf \ No newline at end of file diff --git a/docker-unified/confd/nginx-config.conf.tmpl b/docker-unified/hbs/nginx-config.hbs similarity index 54% rename from docker-unified/confd/nginx-config.conf.tmpl rename to docker-unified/hbs/nginx-config.hbs index 43730181f..7890e7fea 100644 --- a/docker-unified/confd/nginx-config.conf.tmpl +++ b/docker-unified/hbs/nginx-config.hbs @@ -1,28 +1,33 @@ server { listen 80 default_server; #listen [::]:80 default_server; - server_name {{ getenv "BW_DOMAIN" "localhost" }}; -{{ if eq (getenv "BW_ENABLE_SSL") "true" }} + server_name {{{String.Coalesce env.BW_DOMAIN "localhost"}}}; +{{#if (String.Equal env.BW_ENABLE_SSL "true")}} - return 301 https://{{ getenv "BW_DOMAIN" "localhost" }}$request_uri; + return 301 https://{{{String.Coalesce env.BW_DOMAIN "localhost"}}}$request_uri; } server { listen 443 ssl http2; #listen [::]:443 ssl http2; - server_name {{ getenv "BW_DOMAIN" "localhost" }}; + server_name {{{String.Coalesce env.BW_DOMAIN "localhost"}}}; - ssl_certificate /etc/bitwarden/{{ getenv "BW_SSL_CERT" "ssl.crt" }}; - ssl_certificate_key /etc/bitwarden/{{ getenv "BW_SSL_KEY" "ssl.key" }}; + ssl_certificate /etc/bitwarden/{{{String.Coalesce env.BW_SSL_CERT "ssl.crt"}}}; + ssl_certificate_key /etc/bitwarden/{{{String.Coalesce env.BW_SSL_KEY "ssl.key"}}}; ssl_session_timeout 30m; ssl_session_cache shared:SSL:20m; ssl_session_tickets off; +{{#if (String.Equal env.BW_ENABLE_SSL_DH "true")}} - ssl_protocols {{ getenv "BW_SSL_PROTOCOLS" "TLSv1.2" }}; - ssl_ciphers "{{ getenv "BW_SSL_CIPHERS" "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256" }}"; + # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits + ssl_dhparam /etc/bitwarden/{{{String.Coalesce env.BW_SSL_DH_CERT "dh.pem"}}}; +{{/if}} + + ssl_protocols {{{String.Coalesce env.BW_SSL_PROTOCOLS "TLSv1.2"}}}; + ssl_ciphers "{{{String.Coalesce env.BW_SSL_CIPHERS "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"}}}"; # Enables server-side protection from BEAST attacks ssl_prefer_server_ciphers on; -{{ if eq (getenv "BW_ENABLE_SSL_CA") "true" }} +{{#if (String.Equal env.BW_ENABLE_SSL_CA "true")}} # OCSP Stapling --- # Fetch OCSP records from URL in ssl_certificate and cache them @@ -30,29 +35,29 @@ server { ssl_stapling_verify on; # Verify chain of trust of OCSP response using Root CA and Intermediate certs - ssl_trusted_certificate /etc/bitwarden/{{ getenv "BW_SSL_CA_CERT" "ca.crt" }}; + ssl_trusted_certificate /etc/bitwarden/{{{String.Coalesce env.BW_SSL_CA_CERT "ca.crt"}}}; resolver 1.1.1.1 1.0.0.1 9.9.9.9 149.112.112.112 valid=300s; -{{ end }} +{{/if}} include /etc/nginx/security-headers-ssl.conf; -{{ end }} +{{/if}} include /etc/nginx/security-headers.conf; -{{ if getenv "BW_REAL_IPS" }} +{{#if (String.IsNotNullOrWhitespace env.BW_REAL_IPS)}} -{{ range (getenv "BW_REAL_IPS") }} - set_real_ip_from {{ .Key }}; -{{ end }} +{{#each (String.Split env.BW_REAL_IPS ",")}} + set_real_ip_from {{{String.Trim .}}}; +{{/each}} real_ip_header X-Forwarded-For; real_ip_recursive on; -{{ end }} +{{/if}} location / { root /app/Web; -{{ if eq (getenv "BW_ENABLE_SSL") "true" }} +{{#if (String.Equal env.BW_ENABLE_SSL "true")}} include /etc/nginx/security-headers-ssl.conf; -{{ end }} +{{/if}} include /etc/nginx/security-headers.conf; - add_header Content-Security-Policy "{{ getenv "BW_CSP" "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://haveibeenpwned.com https://www.gravatar.com; child-src 'self' https://*.duosecurity.com https://*.duofederal.com; frame-src 'self' https://*.duosecurity.com https://*.duofederal.com; connect-src 'self' https://api.pwnedpasswords.com https://2fa.directory; object-src 'self' blob:;" }}"; + add_header Content-Security-Policy "{{{String.Coalesce env.BW_CSP "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://haveibeenpwned.com https://www.gravatar.com; child-src 'self' https://*.duosecurity.com https://*.duofederal.com; frame-src 'self' https://*.duosecurity.com https://*.duofederal.com; connect-src 'self' https://api.pwnedpasswords.com https://2fa.directory; object-src 'self' blob:;"}}}"; add_header X-Frame-Options SAMEORIGIN; add_header X-Robots-Tag "noindex, nofollow"; } @@ -64,9 +69,9 @@ server { location = /app-id.json { root /app/Web; -{{ if eq (getenv "BW_ENABLE_SSL") "true" }} +{{#if (String.Equal env.BW_ENABLE_SSL "true")}} include /etc/nginx/security-headers-ssl.conf; -{{ end }} +{{/if}} include /etc/nginx/security-headers.conf; proxy_hide_header Content-Type; add_header Content-Type $fido_content_type; @@ -81,14 +86,14 @@ server { } location /icons/ { -{{ if eq (getenv "BW_ICONS_PROXY_TO_CLOUD") "true" }} +{{#if (String.Equal env.BW_ICONS_PROXY_TO_CLOUD "true")}} proxy_pass https://icons.bitwarden.net/; proxy_set_header Host icons.bitwarden.net; proxy_set_header X-Forwarded-For $remote_addr; proxy_ssl_server_name on; -{{ else }} +{{else}} proxy_pass http://localhost:5004/; -{{ end }} +{{/if}} } location /notifications/ { @@ -107,38 +112,38 @@ server { location /sso { proxy_pass http://localhost:5007; -{{ if eq (getenv "BW_ENABLE_SSL") "true" }} +{{#if (String.Equal env.BW_ENABLE_SSL "true")}} include /etc/nginx/security-headers-ssl.conf; -{{ end }} +{{/if}} include /etc/nginx/security-headers.conf; add_header X-Frame-Options SAMEORIGIN; } location /identity { proxy_pass http://localhost:5005; -{{ if eq (getenv "BW_ENABLE_SSL") "true" }} +{{#if (String.Equal env.BW_ENABLE_SSL "true")}} include /etc/nginx/security-headers-ssl.conf; -{{ end }} +{{/if}} include /etc/nginx/security-headers.conf; add_header X-Frame-Options SAMEORIGIN; } location /admin { proxy_pass http://localhost:5000; -{{ if eq (getenv "BW_ENABLE_SSL") "true" }} +{{#if (String.Equal env.BW_ENABLE_SSL "true")}} include /etc/nginx/security-headers-ssl.conf; -{{ end }} +{{/if}} include /etc/nginx/security-headers.conf; add_header X-Frame-Options SAMEORIGIN; } -{{ if eq (getenv "BW_ENABLE_KEY_CONNECTOR") "true" }} - location /key-connector/ { - proxy_pass {{ getenv "BW_KEY_CONNECTOR_INTERNAL_URL"}}/; - } -{{ end }} - location /scim/ { proxy_pass http://localhost:5002/; } +{{#if (String.Equal env.BW_ENABLE_KEY_CONNECTOR "true")}} + + location /key-connector/ { + proxy_pass {{{env.BW_KEY_CONNECTOR_INTERNAL_URL}}}/; + } +{{/if}} }