diff --git a/README.md b/README.md index 5651f15..f2ec2a2 100644 --- a/README.md +++ b/README.md @@ -16,4 +16,18 @@ Self-learning project for terraform 1. Setup DigitalOcean 2. Add DO infrastructure via ansible -3. Add traefik for proper proxying \ No newline at end of file +3. Add traefik for proper proxying + +# Security Headers note + +The following security headers are applied using traefik on all traefik frontend docker backends: + +- HSTS: 2592000 seconds (1 week) +- Redirect HTTP->HTTPS +- contentTypeNosniff: true +- browserXSSFilter: true +- XFO: Allow-From muximux +- referrerPolicy: no-referrer +- X-Powered-By: Allomancy +- X-Server: BlackBox +- X-Clacks-Overhead "GNU Terry Pratchett" diff --git a/docker/conf/traefik.toml b/docker/conf/traefik.toml index e2d5403..1e1699b 100644 --- a/docker/conf/traefik.toml +++ b/docker/conf/traefik.toml @@ -32,13 +32,37 @@ defaultEntryPoints = ["http", "https"] [frontends.ebooks] backend = "ebooks" passHostHeader = true + [frontends.ebooks.headers] + SSLRedirect = true + SSLTemporaryRedirect = true + STSSeconds = 2592000 + CustomFrameOptionsValue = "ALLOW-FROM https://muximux.bb8.fun/" + ContentTypeNosniff = true + BrowserXssFilter = true + ReferrerPolicy = "no-referrer" [frontends.ebooks.headers.customrequestheaders] X-Forwarded-Proto = "https" -[frontends.ebooks.routes.domain] - rule = "Host:ebooks.in.bb8.fun,ebooks.bb8.fun" + [frontends.ebooks.headers.customresponseheaders] + X-Powered-By = "Allomancy" + Server = "BlackBox" + X-Clacks-Overhead = "GNU Terry Pratchett" + [frontends.ebooks.routes.domain] + rule = "Host:ebooks.in.bb8.fun,ebooks.bb8.fun" [frontends.scan] backend = "scan" + [frontends.scan.headers] + SSLRedirect = true + SSLTemporaryRedirect = true + STSSeconds = 2592000 + FrameDeny = true + ContentTypeNosniff = true + BrowserXssFilter = true + ReferrerPolicy = "no-referrer" + [frontends.scan.headers.customresponseheaders] + X-Powered-By = "Allomancy" + Server = "BlackBox" + X-Clacks-Overhead = "GNU Terry Pratchett" [frontends.scan.routes.domain] rule = "Host:scan.bb8.fun" diff --git a/docker/data.tf b/docker/data.tf index e018608..12d45a9 100644 --- a/docker/data.tf +++ b/docker/data.tf @@ -27,7 +27,7 @@ data "docker_registry_image" "couchpotato" { } data "docker_registry_image" "traefik" { - name = "traefik:latest" + name = "traefik:cancoillotte-alpine" } # The gitea latest is built against master diff --git a/docker/main.tf b/docker/main.tf index dd88d02..dec9c13 100644 --- a/docker/main.tf +++ b/docker/main.tf @@ -6,6 +6,14 @@ resource docker_container "transmission" { "traefik.frontend.auth.basic" = "${var.basic_auth}" "traefik.port" = 9091 "traefik.enable" = "true" + "traefik.frontend.headers.SSLTemporaryRedirect" = "true" + "traefik.frontend.headers.STSSeconds" = "${var.hsts_max_age}" + "traefik.frontend.headers.STSIncludeSubdomains" = "false" + "traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" + "traefik.frontend.headers.contentTypeNosniff" = "true" + "traefik.frontend.headers.browserXSSFilter" = "true" + "traefik.frontend.headers.referrerPolicy" = "${var.refpolicy}" + "traefik.frontend.headers.customresponseheaders" = "${var.xpoweredby}" } ports { @@ -54,6 +62,14 @@ resource docker_container "gitea" { labels { "traefik.port" = 3000 "traefik.enable" = "true" + "traefik.frontend.headers.SSLTemporaryRedirect" = "true" + "traefik.frontend.headers.STSSeconds" = "${var.hsts_max_age}" + "traefik.frontend.headers.STSIncludeSubdomains" = "false" + "traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" + "traefik.frontend.headers.contentTypeNosniff" = "true" + "traefik.frontend.headers.browserXSSFilter" = "true" + "traefik.frontend.headers.referrerPolicy" = "${var.refpolicy}" + "traefik.frontend.headers.customresponseheaders" = "${var.xpoweredby}" } ports { @@ -126,6 +142,14 @@ resource "docker_container" "emby" { "traefik.frontend.auth.basic" = "${var.basic_auth}" "traefik.port" = 8096 "traefik.enable" = "true" + "traefik.frontend.headers.SSLTemporaryRedirect" = "true" + "traefik.frontend.headers.STSSeconds" = "${var.hsts_max_age}" + "traefik.frontend.headers.STSIncludeSubdomains" = "false" + "traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" + "traefik.frontend.headers.contentTypeNosniff" = "true" + "traefik.frontend.headers.browserXSSFilter" = "true" + "traefik.frontend.headers.referrerPolicy" = "${var.refpolicy}" + "traefik.frontend.headers.customresponseheaders" = "${var.xpoweredby}" } memory = 2048 @@ -166,6 +190,14 @@ resource "docker_container" "flexget" { "traefik.frontend.auth.basic" = "${var.basic_auth}" "traefik.port" = 5050 "traefik.enable" = "true" + "traefik.frontend.headers.SSLTemporaryRedirect" = "true" + "traefik.frontend.headers.STSSeconds" = "${var.hsts_max_age}" + "traefik.frontend.headers.STSIncludeSubdomains" = "false" + "traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" + "traefik.frontend.headers.contentTypeNosniff" = "true" + "traefik.frontend.headers.browserXSSFilter" = "true" + "traefik.frontend.headers.referrerPolicy" = "${var.refpolicy}" + "traefik.frontend.headers.customresponseheaders" = "${var.xpoweredby}" } memory = 256 @@ -206,6 +238,14 @@ resource "docker_container" "couchpotato" { "traefik.frontend.auth.basic" = "${var.basic_auth}" "traefik.port" = 5050 "traefik.enable" = "true" + "traefik.frontend.headers.SSLTemporaryRedirect" = "true" + "traefik.frontend.headers.STSSeconds" = "${var.hsts_max_age}" + "traefik.frontend.headers.STSIncludeSubdomains" = "false" + "traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" + "traefik.frontend.headers.contentTypeNosniff" = "true" + "traefik.frontend.headers.browserXSSFilter" = "true" + "traefik.frontend.headers.referrerPolicy" = "${var.refpolicy}" + "traefik.frontend.headers.customresponseheaders" = "${var.xpoweredby}" } memory = 256 @@ -327,6 +367,14 @@ resource "docker_container" "airsonic" { "traefik.frontend.passHostHeader" = "false" "traefik.port" = 4040 "traefik.enable" = "true" + "traefik.frontend.headers.SSLTemporaryRedirect" = "true" + "traefik.frontend.headers.STSSeconds" = "${var.hsts_max_age}" + "traefik.frontend.headers.STSIncludeSubdomains" = "false" + "traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" + "traefik.frontend.headers.contentTypeNosniff" = "true" + "traefik.frontend.headers.browserXSSFilter" = "true" + "traefik.frontend.headers.referrerPolicy" = "${var.refpolicy}" + "traefik.frontend.headers.customresponseheaders" = "${var.xpoweredby}" } } @@ -358,6 +406,14 @@ resource "docker_container" "sickrage" { "traefik.frontend.auth.basic" = "${var.basic_auth}" "traefik.port" = 8081 "traefik.enable" = "true" + "traefik.frontend.headers.SSLTemporaryRedirect" = "true" + "traefik.frontend.headers.STSSeconds" = "${var.hsts_max_age}" + "traefik.frontend.headers.STSIncludeSubdomains" = "false" + "traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" + "traefik.frontend.headers.contentTypeNosniff" = "true" + "traefik.frontend.headers.browserXSSFilter" = "true" + "traefik.frontend.headers.referrerPolicy" = "${var.refpolicy}" + "traefik.frontend.headers.customresponseheaders" = "${var.xpoweredby}" } env = [ @@ -395,6 +451,14 @@ resource "docker_container" "headphones" { "traefik.frontend.auth.basic" = "${var.basic_auth}" "traefik.port" = 8181 "traefik.enable" = "true" + "traefik.frontend.headers.SSLTemporaryRedirect" = "true" + "traefik.frontend.headers.STSSeconds" = "${var.hsts_max_age}" + "traefik.frontend.headers.STSIncludeSubdomains" = "false" + "traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" + "traefik.frontend.headers.contentTypeNosniff" = "true" + "traefik.frontend.headers.browserXSSFilter" = "true" + "traefik.frontend.headers.referrerPolicy" = "${var.refpolicy}" + "traefik.frontend.headers.customresponseheaders" = "${var.xpoweredby}" } # lounge:tatooine @@ -436,6 +500,14 @@ resource "docker_container" "wiki" { labels { "traefik.port" = 9999 "traefik.enable" = "true" + "traefik.frontend.headers.SSLTemporaryRedirect" = "true" + "traefik.frontend.headers.STSSeconds" = "${var.hsts_max_age}" + "traefik.frontend.headers.STSIncludeSubdomains" = "false" + "traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" + "traefik.frontend.headers.contentTypeNosniff" = "true" + "traefik.frontend.headers.browserXSSFilter" = "true" + "traefik.frontend.headers.referrerPolicy" = "${var.refpolicy}" + "traefik.frontend.headers.customresponseheaders" = "${var.xpoweredby}" } env = [ @@ -487,6 +559,14 @@ resource "docker_container" "muximux" { "traefik.frontend.auth.basic" = "${var.basic_auth}" "traefik.port" = 80 "traefik.enable" = "true" + "traefik.frontend.headers.SSLTemporaryRedirect" = "true" + "traefik.frontend.headers.STSSeconds" = "${var.hsts_max_age}" + "traefik.frontend.headers.STSIncludeSubdomains" = "false" + "traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" + "traefik.frontend.headers.contentTypeNosniff" = "true" + "traefik.frontend.headers.browserXSSFilter" = "true" + "traefik.frontend.headers.referrerPolicy" = "${var.refpolicy}" + "traefik.frontend.headers.customresponseheaders" = "${var.xpoweredby}" } # lounge:tatooine diff --git a/docker/variables.tf b/docker/variables.tf index c2d5feb..51c90de 100644 --- a/docker/variables.tf +++ b/docker/variables.tf @@ -24,3 +24,20 @@ variable "cloudflare_email" { variable "basic_auth" { default = "tatooine:$2y$05$iPbatint3Gulbs6kUtyALO9Yq5sBJ..aiF82bcIziH4ytz9nFoPr6,reddit:$2y$05$ghKxSydYCpAT8r2VVMDmWO/BBecghGfLsRJUkr3ii7XxPyxBqp8Oy" } + +# 30 days +variable "hsts_max_age" { + default = "2592000" +} + +variable "xfo_allow" { + default = "ALLOW-FROM https://muximux.bb8.fun/" +} + +variable "xpoweredby" { + default = "X-Powered-By:Allomancy,X-Server:Blackbox" +} + +variable "refpolicy" { + default = "no-referrer" +}