diff --git a/docs/configuration/backends/docker.md b/docs/configuration/backends/docker.md index 616dac299..65b3b3e90 100644 --- a/docs/configuration/backends/docker.md +++ b/docs/configuration/backends/docker.md @@ -169,6 +169,8 @@ 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. | ### On Service diff --git a/provider/docker/docker.go b/provider/docker/docker.go index 2b7f80454..2f8e94a9b 100644 --- a/provider/docker/docker.go +++ b/provider/docker/docker.go @@ -291,6 +291,10 @@ func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Con "getServicePriority": p.getServicePriority, "getServiceBackend": p.getServiceBackend, "getWhitelistSourceRange": p.getWhitelistSourceRange, + "getRequestHeaders": p.getRequestHeaders, + "getResponseHeaders": p.getResponseHeaders, + "hasRequestHeaders": p.hasRequestHeaders, + "hasResponseHeaders": p.hasResponseHeaders, } // filter containers filteredContainers := fun.Filter(func(container dockerData) bool { @@ -726,6 +730,41 @@ 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) getRequestHeaders(container dockerData) map[string]string { + return parseCustomHeaders(container, types.LabelFrontendRequestHeader) +} + +func (p *Provider) getResponseHeaders(container dockerData) map[string]string { + return parseCustomHeaders(container, types.LabelFrontendResponseHeader) +} + +func parseCustomHeaders(container dockerData, containerType string) map[string]string { + customHeaders := make(map[string]string) + if label, err := getLabel(container, containerType); 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 { + customHeaders[pair[0]] = pair[1] + } + } + } + if len(customHeaders) == 0 { + log.Errorf("Could not load any custom headers") + } + return customHeaders +} func isContainerEnabled(container dockerData, exposedByDefault bool) bool { return exposedByDefault && container.Labels[types.LabelEnable] != "false" || container.Labels[types.LabelEnable] == "true" } diff --git a/templates/docker.tmpl b/templates/docker.tmpl index c2a7cf54b..efea8c377 100644 --- a/templates/docker.tmpl +++ b/templates/docker.tmpl @@ -78,6 +78,18 @@ basicAuth = [{{range getBasicAuth $container}} "{{.}}", {{end}}] + {{if hasRequestHeaders $container}} + [frontends."frontend-{{$frontend}}".headers.customrequestheaders] + {{range $k, $v := getRequestHeaders $container}} + {{$k}} = "{{$v}}" + {{end}} + {{end}} + {{if hasResponseHeaders $container}} + [frontends."frontend-{{$frontend}}".headers.customresponseheaders] + {{range $k, $v := getResponseHeaders $container}} + {{$k}} = "{{$v}}" + {{end}} + {{end}} [frontends."frontend-{{$frontend}}".routes."route-frontend-{{$frontend}}"] rule = "{{getFrontendRule $container}}" {{end}} diff --git a/types/common_label.go b/types/common_label.go index 1f974615a..271673fc7 100644 --- a/types/common_label.go +++ b/types/common_label.go @@ -14,6 +14,8 @@ const ( LabelWeight = LabelPrefix + "weight" LabelFrontendAuthBasic = LabelPrefix + "frontend.auth.basic" LabelFrontendEntryPoints = LabelPrefix + "frontend.entryPoints" + LabelFrontendRequestHeader = LabelPrefix + "frontend.headers.customrequestheaders" + LabelFrontendResponseHeader = LabelPrefix + "frontend.headers.customresoponseheaders" LabelFrontendPassHostHeader = LabelPrefix + "frontend.passHostHeader" LabelFrontendPriority = LabelPrefix + "frontend.priority" LabelFrontendRule = LabelPrefix + "frontend.rule"