From da0a683f2f92f8369178ed0f7d940e28128093aa Mon Sep 17 00:00:00 2001 From: James Williams Date: Wed, 23 Sep 2020 12:24:59 +0100 Subject: [PATCH] configure traefik http security headers --- .gitignore | 1 + cookiecutter.json | 1 + .../compose/production/traefik/traefik.yml | 31 +++++++++++++++++++ .../config/settings/production.py | 21 ++++++++----- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index f753fec91..c4a37a436 100644 --- a/.gitignore +++ b/.gitignore @@ -215,3 +215,4 @@ tags .idea/ .pytest_cache/ +.vscode/ diff --git a/cookiecutter.json b/cookiecutter.json index 4a580036d..9829c0ca4 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -1,6 +1,7 @@ { "project_name": "My Awesome Project", "project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_')|replace('.', '_')|trim() }}", + "_extensions": ["cookiecutter.extensions.RandomStringExtension"], "description": "Behold My Awesome Project!", "author_name": "Daniel Roy Greenfeld", "domain_name": "example.com", diff --git a/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml b/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml index 7b56063f3..a1e4f6be3 100644 --- a/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml +++ b/{{cookiecutter.project_slug}}/compose/production/traefik/traefik.yml @@ -1,3 +1,4 @@ +--- log: level: INFO @@ -30,6 +31,20 @@ certificatesResolvers: httpChallenge: entryPoint: web +tls: + # https://docs.traefik.io/https/tls/#tls-options + options: + default: + # see https://caniuse.com/tls1-2 for browsers that support TLS 1.2 + minVersion: VersionTLS12 + # see https://caniuse.com/sni for browsers that support SNI + sniStrict: true + # https://wiki.mozilla.org/Security/Server_Side_TLS + cipherSuites: # use only elliptic curve (the strongest) ciphers + - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + http: routers: web-secure-router: @@ -42,6 +57,7 @@ http: - web-secure middlewares: - csrf + - security-headers service: django tls: # https://docs.traefik.io/master/routing/routers/#certresolver @@ -52,6 +68,8 @@ http: rule: "Host(`{{ cookiecutter.domain_name }}`)" entryPoints: - flower + middlewares: + - security-headers service: flower tls: # https://docs.traefik.io/master/routing/routers/#certresolver @@ -64,6 +82,19 @@ http: # https://docs.djangoproject.com/en/dev/ref/csrf/#ajax headers: hostsProxyHeaders: ["X-CSRFToken"] + security-headers: + # https://docs.traefik.io/middlewares/headers/#general + headers: + # TODO increase stsSeconds to *at least* 31536000 (1 year) once HTTPS works + stsSeconds: 60 + stsIncludeSubdomains: true + stsPreload: true + frameDeny: true + contentTypeNosniff: true + browserXssFilter: true + customResponseHeaders: + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server + server: {{ random_ascii_string(10) }} # hide server version services: django: diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index bd0acfbd4..485a419a9 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -43,17 +43,14 @@ CACHES = { # SECURITY # ------------------------------------------------------------------------------ -# https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header -SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") +{%- if cookiecutter.use_docker -%} +# NOTE headers are managed by the security-headers middleware in traefik.yml +{%- else -%} +# TODO set security headers in your load balancer if possible and remove these # https://docs.djangoproject.com/en/dev/ref/settings/#secure-ssl-redirect SECURE_SSL_REDIRECT = env.bool("DJANGO_SECURE_SSL_REDIRECT", default=True) -# https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-secure -SESSION_COOKIE_SECURE = True -# https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-secure -CSRF_COOKIE_SECURE = True -# https://docs.djangoproject.com/en/dev/topics/security/#ssl-https # https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-seconds -# TODO: set this to 60 seconds first and then to 518400 once you prove the former works +# TODO increase this to *at least* 31536000 (1 year) once HTTPS works SECURE_HSTS_SECONDS = 60 # https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-include-subdomains SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool( @@ -65,6 +62,14 @@ SECURE_HSTS_PRELOAD = env.bool("DJANGO_SECURE_HSTS_PRELOAD", default=True) SECURE_CONTENT_TYPE_NOSNIFF = env.bool( "DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True ) +{%- endif -%} +# https://docs.djangoproject.com/en/dev/topics/security/#ssl-https +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header +SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") +# https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-secure +SESSION_COOKIE_SECURE = True +# https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-secure +CSRF_COOKIE_SECURE = True {% if cookiecutter.cloud_provider != 'None' -%} # STORAGES