From 7063da1c7decaa0ee593c8c2e6915e833b1958c3 Mon Sep 17 00:00:00 2001 From: Daniel Tomcej Date: Wed, 22 Nov 2017 12:40:04 -0600 Subject: [PATCH] Add docker security headers via labels --- autogen/gentemplates/gen.go | 64 +++++++ docs/configuration/backends/docker.md | 26 ++- provider/docker/docker.go | 247 +++++++++++++++++++++----- templates/docker.tmpl | 64 +++++++ types/common_label.go | 18 ++ 5 files changed, 369 insertions(+), 50 deletions(-) diff --git a/autogen/gentemplates/gen.go b/autogen/gentemplates/gen.go index a93174bef..da1de84a7 100644 --- a/autogen/gentemplates/gen.go +++ b/autogen/gentemplates/gen.go @@ -205,6 +205,52 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}} basicAuth = [{{range getBasicAuth $container}} "{{.}}", {{end}}] + [frontends."frontend-{{$frontend}}".headers] + {{if hasSSLRedirectHeaders $container}} + SSLRedirect = {{getSSLRedirectHeaders $container}} + {{end}} + {{if hasSSLTemporaryRedirectHeaders $container}} + SSLTemporaryRedirect = {{getSSLTemporaryRedirectHeaders $container}} + {{end}} + {{if hasSSLHostHeaders $container}} + SSLHost = {{getSSLHostHeaders $container}} + {{end}} + {{if hasSTSSecondsHeaders $container}} + STSSeconds = {{getSTSSecondsHeaders $container}} + {{end}} + {{if hasSTSIncludeSubdomainsHeaders $container}} + STSIncludeSubdomains = {{getSTSIncludeSubdomainsHeaders $container}} + {{end}} + {{if hasSTSPreloadHeaders $container}} + STSPreload = {{getSTSPreloadHeaders $container}} + {{end}} + {{if hasForceSTSHeaderHeaders $container}} + ForceSTSHeader = {{getForceSTSHeaderHeaders $container}} + {{end}} + {{if hasFrameDenyHeaders $container}} + FrameDeny = {{getFrameDenyHeaders $container}} + {{end}} + {{if hasCustomFrameOptionsValueHeaders $container}} + CustomFrameOptionsValue = {{getCustomFrameOptionsValueHeaders $container}} + {{end}} + {{if hasContentTypeNosniffHeaders $container}} + ContentTypeNosniff = {{getContentTypeNosniffHeaders $container}} + {{end}} + {{if hasBrowserXSSFilterHeaders $container}} + BrowserXSSFilter = {{getBrowserXSSFilterHeaders $container}} + {{end}} + {{if hasContentSecurityPolicyHeaders $container}} + ContentSecurityPolicy = {{getContentSecurityPolicyHeaders $container}} + {{end}} + {{if hasPublicKeyHeaders $container}} + PublicKey = {{getPublicKeyHeaders $container}} + {{end}} + {{if hasReferrerPolicyHeaders $container}} + ReferrerPolicy = {{getReferrerPolicyHeaders $container}} + {{end}} + {{if hasIsDevelopmentHeaders $container}} + IsDevelopment = {{getIsDevelopmentHeaders $container}} + {{end}} {{if hasRequestHeaders $container}} [frontends."frontend-{{$frontend}}".headers.customrequestheaders] {{range $k, $v := getRequestHeaders $container}} @@ -216,6 +262,24 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}} {{range $k, $v := getResponseHeaders $container}} {{$k}} = "{{$v}}" {{end}} + {{end}} + {{if hasAllowedHostsHeaders $container}} + [frontends."frontend-{{$frontend}}".headers.AllowedHosts] + {{range getAllowedHostsHeaders $container}} + "{{.}}" + {{end}} + {{end}} + {{if hasHostsProxyHeaders $container}} + [frontends."frontend-{{$frontend}}".headers.HostsProxyHeaders] + {{range getHostsProxyHeaders $container}} + "{{.}}" + {{end}} + {{end}} + {{if hasSSLProxyHeaders $container}} + [frontends."frontend-{{$frontend}}".headers.SSLProxyHeaders] + {{range $k, $v := getSSLProxyHeaders $container}} + {{$k}} = "{{$v}}" + {{end}} {{end}} [frontends."frontend-{{$frontend}}".routes."route-frontend-{{$frontend}}"] rule = "{{getFrontendRule $container}}" diff --git a/docs/configuration/backends/docker.md b/docs/configuration/backends/docker.md index be37274f5..20200d28a 100644 --- a/docs/configuration/backends/docker.md +++ b/docs/configuration/backends/docker.md @@ -169,11 +169,33 @@ Labels can be used on containers to override default behaviour. | `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints` | | `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` | | `traefik.frontend.whitelistSourceRange:RANGE` | List of IP-Ranges which are allowed to access. An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | -| `traefik.frontend.headers.customrequestheaders=EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container. Format: `HEADER:value,HEADER2:value2` | -| `traefik.frontend.headers.customresponseheaders=EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client. Format: `HEADER:value,HEADER2:value2` | | `traefik.docker.network` | Set the docker network to use for connections to this container. If a container is linked to several networks, be sure to set the proper network name (you can check with `docker inspect `) otherwise it will randomly pick one (depending on how docker is returning them). For instance when deploying docker `stack` from compose files, the compose defined networks will be prefixed with the `stack` name. | | `traefik.frontend.redirect=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) | +#### Security Headers + +| Label | Description | +|-----------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `traefik.frontend.headers.allowedHosts=EXPR` | Provides a list of allowed hosts that requests will be processed. Format: `Host1,Host2` | +|`traefik.frontend.headers.customrequestheaders=EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container. Format: `HEADER:value,HEADER2:value2` | +| `traefik.frontend.headers.customresponseheaders=EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client. Format: `HEADER:value,HEADER2:value2` | +|`traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored. Format: `HEADER1,HEADER2` | +| `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. | +| `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. | +| `traefik.frontend.headers.SSLHost=HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. | +| `traefik.frontend.headers.SSLProxyHeaders=EXPR` | Header combinations that would signify a proper SSL Request (Such as X-Forwarded-For:https). Format: `HEADER:value,HEADER2:value2` | +| `traefik.frontend.headers.STSSeconds=315360000` | Sets the max-age of the STS header. | +| `traefik.frontend.headers.STSIncludeSubdomains=true` | Adds the IncludeSubdomains section of the STS header. | +| `traefik.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. | +| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. | +| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. | +| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. | +| `traefik.frontend.headers.contentTypeNosniff=true` | Adds the `X-Content-Type-Options` header with the value `nosniff`. | +| `traefik.frontend.headers.browserXSSFilter=true` | Adds the X-XSS-Protection header with the value `1; mode=block`. | +| `traefik.frontend.headers.contentSecurityPolicy=VALUE` | Adds CSP Header with the custom value. | +| `traefik.frontend.headers.publicKey=VALUE` | Adds pinned HTST public key header. | +| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. | +| `traefik.frontend.headers.isDevelopment=false` | This will cause the AllowedHosts, SSLRedirect, and STSSeconds/STSIncludeSubdomains options to be ignored during development. When deploying to production, be sure to set this to false. | ### On Service Services labels can be used for overriding default behaviour diff --git a/provider/docker/docker.go b/provider/docker/docker.go index 4bcfe5474..a0b7059c5 100644 --- a/provider/docker/docker.go +++ b/provider/docker/docker.go @@ -260,46 +260,82 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Configuration { var DockerFuncMap = template.FuncMap{ - "getBackend": p.getBackend, - "getIPAddress": p.getIPAddress, - "getPort": p.getPort, - "getWeight": p.getWeight, - "getDomain": p.getDomain, - "getProtocol": p.getProtocol, - "getPassHostHeader": p.getPassHostHeader, - "getPriority": p.getPriority, - "getEntryPoints": p.getEntryPoints, - "getBasicAuth": p.getBasicAuth, - "getFrontendRule": p.getFrontendRule, - "getRedirect": p.getRedirect, - "hasCircuitBreakerLabel": p.hasCircuitBreakerLabel, - "getCircuitBreakerExpression": p.getCircuitBreakerExpression, - "hasLoadBalancerLabel": p.hasLoadBalancerLabel, - "getLoadBalancerMethod": p.getLoadBalancerMethod, - "hasMaxConnLabels": p.hasMaxConnLabels, - "getMaxConnAmount": p.getMaxConnAmount, - "getMaxConnExtractorFunc": p.getMaxConnExtractorFunc, - "getSticky": p.getSticky, - "getStickinessCookieName": p.getStickinessCookieName, - "hasStickinessLabel": p.hasStickinessLabel, - "getIsBackendLBSwarm": p.getIsBackendLBSwarm, - "hasServices": p.hasServices, - "getServiceNames": p.getServiceNames, - "getServicePort": p.getServicePort, - "getServiceWeight": p.getServiceWeight, - "getServiceProtocol": p.getServiceProtocol, - "getServiceEntryPoints": p.getServiceEntryPoints, - "getServiceBasicAuth": p.getServiceBasicAuth, - "getServiceFrontendRule": p.getServiceFrontendRule, - "getServicePassHostHeader": p.getServicePassHostHeader, - "getServicePriority": p.getServicePriority, - "getServiceBackend": p.getServiceBackend, - "getServiceRedirect": p.getServiceRedirect, - "getWhitelistSourceRange": p.getWhitelistSourceRange, - "getRequestHeaders": p.getRequestHeaders, - "getResponseHeaders": p.getResponseHeaders, - "hasRequestHeaders": p.hasRequestHeaders, - "hasResponseHeaders": p.hasResponseHeaders, + "getBackend": p.getBackend, + "getIPAddress": p.getIPAddress, + "getPort": p.getPort, + "getWeight": p.getWeight, + "getDomain": p.getDomain, + "getProtocol": p.getProtocol, + "getPassHostHeader": p.getPassHostHeader, + "getPriority": p.getPriority, + "getEntryPoints": p.getEntryPoints, + "getBasicAuth": p.getBasicAuth, + "getFrontendRule": p.getFrontendRule, + "getRedirect": p.getRedirect, + "hasCircuitBreakerLabel": p.hasCircuitBreakerLabel, + "getCircuitBreakerExpression": p.getCircuitBreakerExpression, + "hasLoadBalancerLabel": p.hasLoadBalancerLabel, + "getLoadBalancerMethod": p.getLoadBalancerMethod, + "hasMaxConnLabels": p.hasMaxConnLabels, + "getMaxConnAmount": p.getMaxConnAmount, + "getMaxConnExtractorFunc": p.getMaxConnExtractorFunc, + "getSticky": p.getSticky, + "getStickinessCookieName": p.getStickinessCookieName, + "hasStickinessLabel": p.hasStickinessLabel, + "getIsBackendLBSwarm": p.getIsBackendLBSwarm, + "hasServices": p.hasServices, + "getServiceNames": p.getServiceNames, + "getServicePort": p.getServicePort, + "getServiceWeight": p.getServiceWeight, + "getServiceProtocol": p.getServiceProtocol, + "getServiceEntryPoints": p.getServiceEntryPoints, + "getServiceBasicAuth": p.getServiceBasicAuth, + "getServiceFrontendRule": p.getServiceFrontendRule, + "getServicePassHostHeader": p.getServicePassHostHeader, + "getServicePriority": p.getServicePriority, + "getServiceBackend": p.getServiceBackend, + "getServiceRedirect": p.getServiceRedirect, + "getWhitelistSourceRange": p.getWhitelistSourceRange, + "hasRequestHeaders": p.hasLabel(types.LabelFrontendRequestHeader), + "getRequestHeaders": p.getRequestHeaders, + "hasResponseHeaders": p.hasLabel(types.LabelFrontendResponseHeader), + "getResponseHeaders": p.getResponseHeaders, + "hasAllowedHostsHeaders": p.hasLabel(types.LabelFrontendAllowedHosts), + "getAllowedHostsHeaders": p.getAllowedHostsHeaders, + "hasHostsProxyHeaders": p.hasLabel(types.LabelFrontendHostsProxyHeaders), + "getHostsProxyHeaders": p.getHostsProxyHeaders, + "hasSSLRedirectHeaders": p.hasLabel(types.LabelFrontendSSLRedirect), + "getSSLRedirectHeaders": p.getSSLRedirectHeaders, + "hasSSLTemporaryRedirectHeaders": p.hasLabel(types.LabelFrontendSSLTemporaryRedirect), + "getSSLTemporaryRedirectHeaders": p.getSSLTemporaryRedirectHeaders, + "hasSSLHostHeaders": p.hasLabel(types.LabelFrontendSSLHost), + "getSSLHostHeaders": p.getSSLHostHeaders, + "hasSSLProxyHeaders": p.hasLabel(types.LabelFrontendSSLProxyHeaders), + "getSSLProxyHeaders": p.getSSLProxyHeaders, + "hasSTSSecondsHeaders": p.hasLabel(types.LabelFrontendSTSSeconds), + "getSTSSecondsHeaders": p.getSTSSecondsHeaders, + "hasSTSIncludeSubdomainsHeaders": p.hasLabel(types.LabelFrontendSTSIncludeSubdomains), + "getSTSIncludeSubdomainsHeaders": p.getSTSIncludeSubdomainsHeaders, + "hasSTSPreloadHeaders": p.hasLabel(types.LabelFrontendSTSPreload), + "getSTSPreloadHeaders": p.getSTSPreloadHeaders, + "hasForceSTSHeaderHeaders": p.hasLabel(types.LabelFrontendForceSTSHeader), + "getForceSTSHeaderHeaders": p.getForceSTSHeaderHeaders, + "hasFrameDenyHeaders": p.hasLabel(types.LabelFrontendFrameDeny), + "getFrameDenyHeaders": p.getFrameDenyHeaders, + "hasCustomFrameOptionsValueHeaders": p.hasLabel(types.LabelFrontendCustomFrameOptionsValue), + "getCustomFrameOptionsValueHeaders": p.getCustomFrameOptionsValueHeaders, + "hasContentTypeNosniffHeaders": p.hasLabel(types.LabelFrontendContentTypeNosniff), + "getContentTypeNosniffHeaders": p.getContentTypeNosniffHeaders, + "hasBrowserXSSFilterHeaders": p.hasLabel(types.LabelFrontendBrowserXSSFilter), + "getBrowserXSSFilterHeaders": p.getBrowserXSSFilterHeaders, + "hasContentSecurityPolicyHeaders": p.hasLabel(types.LabelFrontendContentSecurityPolicy), + "getContentSecurityPolicyHeaders": p.getContentSecurityPolicyHeaders, + "hasPublicKeyHeaders": p.hasLabel(types.LabelFrontendPublicKey), + "getPublicKeyHeaders": p.getPublicKeyHeaders, + "hasReferrerPolicyHeaders": p.hasLabel(types.LabelFrontendReferrerPolicy), + "getReferrerPolicyHeaders": p.getReferrerPolicyHeaders, + "hasIsDevelopmentHeaders": p.hasLabel(types.LabelFrontendIsDevelopment), + "getIsDevelopmentHeaders": p.getIsDevelopmentHeaders, } // filter containers filteredContainers := fun.Filter(func(container dockerData) bool { @@ -807,14 +843,11 @@ func (p *Provider) getBasicAuth(container dockerData) []string { return []string{} } -func (p *Provider) hasRequestHeaders(container dockerData) bool { - label, err := getLabel(container, types.LabelFrontendRequestHeader) - return err == nil && len(label) > 0 -} - -func (p *Provider) hasResponseHeaders(container dockerData) bool { - label, err := getLabel(container, types.LabelFrontendResponseHeader) - return err == nil && len(label) > 0 +func (p *Provider) hasLabel(label string) func(container dockerData) bool { + return func(container dockerData) bool { + label, err := getLabel(container, label) + return err == nil && len(label) > 0 + } } func (p *Provider) getRequestHeaders(container dockerData) map[string]string { @@ -843,6 +876,124 @@ func parseCustomHeaders(container dockerData, containerType string) map[string]s return customHeaders } +func (p *Provider) getAllowedHostsHeaders(container dockerData) []string { + return getSliceStringHeaders(container, types.LabelFrontendAllowedHosts) +} + +func (p *Provider) getHostsProxyHeaders(container dockerData) []string { + return getSliceStringHeaders(container, types.LabelFrontendHostsProxyHeaders) +} + +func (p *Provider) getSSLRedirectHeaders(container dockerData) bool { + return getBoolHeader(container, types.LabelFrontendSSLRedirect) +} + +func (p *Provider) getSSLTemporaryRedirectHeaders(container dockerData) bool { + return getBoolHeader(container, types.LabelFrontendSSLTemporaryRedirect) +} + +func (p *Provider) getSSLHostHeaders(container dockerData) string { + label, _ := getLabel(container, types.LabelFrontendSSLHost) + return label +} + +func (p *Provider) getSSLProxyHeaders(container dockerData) map[string]string { + ProxyHeaders := make(map[string]string) + if label, err := getLabel(container, types.LabelFrontendSSLProxyHeaders); err == nil { + for _, headers := range strings.Split(label, ",") { + pair := strings.Split(headers, ":") + if len(pair) != 2 { + log.Warnf("Could not load header %v, skipping...", pair) + } else { + ProxyHeaders[pair[0]] = pair[1] + } + } + } + if len(ProxyHeaders) == 0 { + log.Errorf("Could not load any SSL Proxy Headers") + } + return ProxyHeaders +} + +func (p *Provider) getSTSSecondsHeaders(container dockerData) int64 { + label, _ := getLabel(container, types.LabelFrontendSTSSeconds) + i, err := strconv.ParseInt(label, 10, 64) + if err == nil && i > 0 { + return i + } + return 0 +} + +func (p *Provider) getSTSIncludeSubdomainsHeaders(container dockerData) bool { + return getBoolHeader(container, types.LabelFrontendSTSIncludeSubdomains) +} + +func (p *Provider) getSTSPreloadHeaders(container dockerData) bool { + return getBoolHeader(container, types.LabelFrontendSTSPreload) +} + +func (p *Provider) getForceSTSHeaderHeaders(container dockerData) bool { + return getBoolHeader(container, types.LabelFrontendForceSTSHeader) +} + +func (p *Provider) getFrameDenyHeaders(container dockerData) bool { + return getBoolHeader(container, types.LabelFrontendFrameDeny) +} + +func (p *Provider) getCustomFrameOptionsValueHeaders(container dockerData) string { + label, _ := getLabel(container, types.LabelFrontendCustomFrameOptionsValue) + return label +} + +func (p *Provider) getContentTypeNosniffHeaders(container dockerData) bool { + return getBoolHeader(container, types.LabelFrontendContentTypeNosniff) +} + +func (p *Provider) getBrowserXSSFilterHeaders(container dockerData) bool { + return getBoolHeader(container, types.LabelFrontendBrowserXSSFilter) +} + +func (p *Provider) getContentSecurityPolicyHeaders(container dockerData) string { + label, _ := getLabel(container, types.LabelFrontendContentSecurityPolicy) + return label +} + +func (p *Provider) getPublicKeyHeaders(container dockerData) string { + label, _ := getLabel(container, types.LabelFrontendPublicKey) + return label +} + +func (p *Provider) getReferrerPolicyHeaders(container dockerData) string { + label, _ := getLabel(container, types.LabelFrontendReferrerPolicy) + return label +} + +func (p *Provider) getIsDevelopmentHeaders(container dockerData) bool { + return getBoolHeader(container, types.LabelFrontendIsDevelopment) +} + +func getSliceStringHeaders(container dockerData, containerType string) []string { + value := []string{} + if label, err := getLabel(container, containerType); err == nil { + for _, sublabels := range strings.Split(label, ",") { + if len(sublabels) == 0 { + log.Warnf("Could not load header %v, skipping", sublabels) + } else { + value = append(value, sublabels) + } + } + } + if len(value) == 0 { + log.Errorf("Could not load %v headers", containerType) + } + return value +} + +func getBoolHeader(container dockerData, containerType string) bool { + label, err := getLabel(container, containerType) + return err == nil && len(label) > 0 && strings.EqualFold(strings.TrimSpace(label), "true") +} + func (p *Provider) getRedirect(container dockerData) string { if entryPointredirect, err := getLabel(container, types.LabelFrontendRedirect); err == nil { return entryPointredirect diff --git a/templates/docker.tmpl b/templates/docker.tmpl index 54e83672b..b135ae47b 100644 --- a/templates/docker.tmpl +++ b/templates/docker.tmpl @@ -80,6 +80,52 @@ basicAuth = [{{range getBasicAuth $container}} "{{.}}", {{end}}] + [frontends."frontend-{{$frontend}}".headers] + {{if hasSSLRedirectHeaders $container}} + SSLRedirect = {{getSSLRedirectHeaders $container}} + {{end}} + {{if hasSSLTemporaryRedirectHeaders $container}} + SSLTemporaryRedirect = {{getSSLTemporaryRedirectHeaders $container}} + {{end}} + {{if hasSSLHostHeaders $container}} + SSLHost = {{getSSLHostHeaders $container}} + {{end}} + {{if hasSTSSecondsHeaders $container}} + STSSeconds = {{getSTSSecondsHeaders $container}} + {{end}} + {{if hasSTSIncludeSubdomainsHeaders $container}} + STSIncludeSubdomains = {{getSTSIncludeSubdomainsHeaders $container}} + {{end}} + {{if hasSTSPreloadHeaders $container}} + STSPreload = {{getSTSPreloadHeaders $container}} + {{end}} + {{if hasForceSTSHeaderHeaders $container}} + ForceSTSHeader = {{getForceSTSHeaderHeaders $container}} + {{end}} + {{if hasFrameDenyHeaders $container}} + FrameDeny = {{getFrameDenyHeaders $container}} + {{end}} + {{if hasCustomFrameOptionsValueHeaders $container}} + CustomFrameOptionsValue = {{getCustomFrameOptionsValueHeaders $container}} + {{end}} + {{if hasContentTypeNosniffHeaders $container}} + ContentTypeNosniff = {{getContentTypeNosniffHeaders $container}} + {{end}} + {{if hasBrowserXSSFilterHeaders $container}} + BrowserXSSFilter = {{getBrowserXSSFilterHeaders $container}} + {{end}} + {{if hasContentSecurityPolicyHeaders $container}} + ContentSecurityPolicy = {{getContentSecurityPolicyHeaders $container}} + {{end}} + {{if hasPublicKeyHeaders $container}} + PublicKey = {{getPublicKeyHeaders $container}} + {{end}} + {{if hasReferrerPolicyHeaders $container}} + ReferrerPolicy = {{getReferrerPolicyHeaders $container}} + {{end}} + {{if hasIsDevelopmentHeaders $container}} + IsDevelopment = {{getIsDevelopmentHeaders $container}} + {{end}} {{if hasRequestHeaders $container}} [frontends."frontend-{{$frontend}}".headers.customrequestheaders] {{range $k, $v := getRequestHeaders $container}} @@ -91,6 +137,24 @@ {{range $k, $v := getResponseHeaders $container}} {{$k}} = "{{$v}}" {{end}} + {{end}} + {{if hasAllowedHostsHeaders $container}} + [frontends."frontend-{{$frontend}}".headers.AllowedHosts] + {{range getAllowedHostsHeaders $container}} + "{{.}}" + {{end}} + {{end}} + {{if hasHostsProxyHeaders $container}} + [frontends."frontend-{{$frontend}}".headers.HostsProxyHeaders] + {{range getHostsProxyHeaders $container}} + "{{.}}" + {{end}} + {{end}} + {{if hasSSLProxyHeaders $container}} + [frontends."frontend-{{$frontend}}".headers.SSLProxyHeaders] + {{range $k, $v := getSSLProxyHeaders $container}} + {{$k}} = "{{$v}}" + {{end}} {{end}} [frontends."frontend-{{$frontend}}".routes."route-frontend-{{$frontend}}"] rule = "{{getFrontendRule $container}}" diff --git a/types/common_label.go b/types/common_label.go index ed301c6be..b9f751cfd 100644 --- a/types/common_label.go +++ b/types/common_label.go @@ -16,6 +16,24 @@ const ( LabelFrontendEntryPoints = LabelPrefix + "frontend.entryPoints" LabelFrontendRequestHeader = LabelPrefix + "frontend.headers.customrequestheaders" LabelFrontendResponseHeader = LabelPrefix + "frontend.headers.customresponseheaders" + LabelFrontendAllowedHosts = LabelPrefix + "frontend.headers.allowedHosts" + LabelFrontendHostsProxyHeaders = LabelPrefix + "frontend.headers.hostsProxyHeaders" + LabelFrontendSSLRedirect = LabelPrefix + "frontend.headers.SSLRedirect" + LabelFrontendSSLTemporaryRedirect = LabelPrefix + "frontend.headers.SSLTemporaryRedirect" + LabelFrontendSSLHost = LabelPrefix + "frontend.headers.SSLHost" + LabelFrontendSSLProxyHeaders = LabelPrefix + "frontend.headers.SSLProxyHeaders" + LabelFrontendSTSSeconds = LabelPrefix + "frontend.headers.STSSeconds" + LabelFrontendSTSIncludeSubdomains = LabelPrefix + "frontend.headers.STSIncludeSubdomains" + LabelFrontendSTSPreload = LabelPrefix + "frontend.headers.STSPreload" + LabelFrontendForceSTSHeader = LabelPrefix + "frontend.headers.forceSTSHeader" + LabelFrontendFrameDeny = LabelPrefix + "frontend.headers.frameDeny" + LabelFrontendCustomFrameOptionsValue = LabelPrefix + "frontend.headers.customFrameOptionsValue" + LabelFrontendContentTypeNosniff = LabelPrefix + "frontend.headers.contentTypeNosniff" + LabelFrontendBrowserXSSFilter = LabelPrefix + "frontend.headers.browserXSSFilter" + LabelFrontendContentSecurityPolicy = LabelPrefix + "frontend.headers.contentSecurityPolicy" + LabelFrontendPublicKey = LabelPrefix + "frontend.headers.publicKey" + LabelFrontendReferrerPolicy = LabelPrefix + "frontend.headers.referrerPolicy" + LabelFrontendIsDevelopment = LabelPrefix + "frontend.headers.isDevelopment" LabelFrontendPassHostHeader = LabelPrefix + "frontend.passHostHeader" LabelFrontendPassTLSCert = LabelPrefix + "frontend.passTLSCert" LabelFrontendPriority = LabelPrefix + "frontend.priority"