Fix custom headers template

This commit is contained in:
Ludovic Fernandez 2018-01-02 10:10:04 +01:00 committed by Traefiker
parent 75533b2beb
commit bfd142b13b
11 changed files with 151 additions and 96 deletions

View file

@ -219,6 +219,7 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
replacement = "{{getRedirectReplacement $container}}"
{{end}}
{{ if hasHeaders $container}}
[frontends."frontend-{{$frontend}}".headers]
{{if hasSSLRedirectHeaders $container}}
SSLRedirect = {{getSSLRedirectHeaders $container}}
@ -265,6 +266,16 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
{{if hasIsDevelopmentHeaders $container}}
IsDevelopment = {{getIsDevelopmentHeaders $container}}
{{end}}
{{if hasAllowedHostsHeaders $container}}
AllowedHosts = [{{range getAllowedHostsHeaders $container}}
"{{.}}",
{{end}}]
{{end}}
{{if hasHostsProxyHeaders $container}}
HostsProxyHeaders = [{{range getHostsProxyHeaders $container}}
"{{.}}",
{{end}}]
{{end}}
{{if hasRequestHeaders $container}}
[frontends."frontend-{{$frontend}}".headers.customrequestheaders]
{{range $k, $v := getRequestHeaders $container}}
@ -277,24 +288,14 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
{{$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}}
{{end}}
[frontends."frontend-{{$frontend}}".routes."route-frontend-{{$frontend}}"]
rule = "{{getFrontendRule $container}}"
{{end}}
@ -445,6 +446,7 @@ var _templatesKubernetesTmpl = []byte(`[backends]{{range $backendName, $backend
replacement = "{{$frontend.RedirectReplacement}}"
{{end}}
{{ if $frontend.Headers }}
[frontends."{{$frontendName}}".headers]
SSLRedirect = {{$frontend.Headers.SSLRedirect}}
SSLTemporaryRedirect = {{$frontend.Headers.SSLTemporaryRedirect}}
@ -461,36 +463,41 @@ var _templatesKubernetesTmpl = []byte(`[backends]{{range $backendName, $backend
PublicKey = "{{$frontend.Headers.PublicKey}}"
ReferrerPolicy = "{{$frontend.Headers.ReferrerPolicy}}"
IsDevelopment = {{$frontend.Headers.IsDevelopment}}
{{if $frontend.Headers.CustomRequestHeaders}}
{{if $frontend.Headers.AllowedHosts}}
AllowedHosts = [{{range $frontend.Headers.AllowedHosts}}
"{{.}}",
{{end}}]
{{end}}
{{if $frontend.Headers.HostsProxyHeaders}}
HostsProxyHeaders = [{{range $frontend.Headers.HostsProxyHeaders}}
"{{.}}",
{{end}}]
{{end}}
{{if $frontend.Headers.CustomRequestHeaders}}
[frontends."{{$frontendName}}".headers.customrequestheaders]
{{range $k, $v := $frontend.Headers.CustomRequestHeaders}}
{{$k}} = "{{$v}}"
{{end}}
{{end}}
{{if $frontend.Headers.CustomResponseHeaders}}
{{end}}
{{if $frontend.Headers.CustomResponseHeaders}}
[frontends."{{$frontendName}}".headers.customresponseheaders]
{{range $k, $v := $frontend.Headers.CustomResponseHeaders}}
{{$k}} = "{{$v}}"
{{end}}
{{end}}
{{if $frontend.Headers.AllowedHosts}}
[frontends."{{$frontendName}}".headers.AllowedHosts]
{{range $frontend.Headers.AllowedHosts}}
"{{.}}"
{{end}}
{{end}}
{{if $frontend.Headers.HostsProxyHeaders}}
[frontends."{{$frontendName}}".headers.HostsProxyHeaders]
{{range $frontend.Headers.HostsProxyHeaders}}
"{{.}}"
{{end}}
{{end}}
{{if $frontend.Headers.SSLProxyHeaders}}
{{if $frontend.Headers.SSLProxyHeaders}}
[frontends."{{$frontendName}}".headers.SSLProxyHeaders]
{{range $k, $v := $frontend.Headers.SSLProxyHeaders}}
{{$k}} = "{{$v}}"
{{end}}
{{end}}
{{end}}
{{range $routeName, $route := $frontend.Routes}}
[frontends."{{$frontendName}}".routes."{{$routeName}}"]
rule = "{{$route.Rule}}"

View file

@ -24,14 +24,16 @@ type HeaderStruct struct {
}
// NewHeaderFromStruct constructs a new header instance from supplied frontend header struct.
func NewHeaderFromStruct(headers types.Headers) *HeaderStruct {
o := HeaderOptions{
CustomRequestHeaders: headers.CustomRequestHeaders,
CustomResponseHeaders: headers.CustomResponseHeaders,
func NewHeaderFromStruct(headers *types.Headers) *HeaderStruct {
if headers == nil || !headers.HasCustomHeadersDefined() {
return nil
}
return &HeaderStruct{
opt: o,
opt: HeaderOptions{
CustomRequestHeaders: headers.CustomRequestHeaders,
CustomResponseHeaders: headers.CustomResponseHeaders,
},
}
}

View file

@ -17,16 +17,14 @@ var myHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// newHeader constructs a new header instance with supplied options.
func newHeader(options ...HeaderOptions) *HeaderStruct {
var o HeaderOptions
var opt HeaderOptions
if len(options) == 0 {
o = HeaderOptions{}
opt = HeaderOptions{}
} else {
o = options[0]
opt = options[0]
}
return &HeaderStruct{
opt: o,
}
return &HeaderStruct{opt: opt}
}
func TestNoConfig(t *testing.T) {

View file

@ -6,7 +6,11 @@ import (
)
// NewSecure constructs a new Secure instance with supplied options.
func NewSecure(headers types.Headers) *secure.Secure {
func NewSecure(headers *types.Headers) *secure.Secure {
if headers == nil || !headers.HasSecureHeadersDefined() {
return nil
}
opt := secure.Options{
AllowedHosts: headers.AllowedHosts,
HostsProxyHeaders: headers.HostsProxyHeaders,

View file

@ -290,6 +290,7 @@ func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Con
"getServiceBackend": getServiceBackend,
"getWhitelistSourceRange": getFuncSliceStringLabel(types.LabelTraefikFrontendWhitelistSourceRange),
"hasHeaders": hasHeaders,
"hasRequestHeaders": hasLabel(types.LabelFrontendRequestHeaders),
"getRequestHeaders": getFuncMapLabel(types.LabelFrontendRequestHeaders),
"hasResponseHeaders": hasLabel(types.LabelFrontendResponseHeaders),
@ -895,3 +896,15 @@ func hasRedirect(container dockerData) bool {
return hasLabel(types.LabelFrontendRedirectEntryPoint)(container) ||
hasLabel(types.LabelFrontendRedirectReplacement)(container) && hasLabel(types.LabelFrontendRedirectRegex)(container)
}
// TODO will be rewrite when merge on master
func hasHeaders(container dockerData) bool {
// LabelPrefix + "frontend.headers.
for key := range container.Labels {
if strings.HasPrefix(key, types.LabelPrefix+"frontend.headers.") {
return true
}
}
return false
}

View file

@ -208,7 +208,7 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
priority := getPriority(i)
headers := types.Headers{
headers := &types.Headers{
CustomRequestHeaders: getMapAnnotation(i, annotationKubernetesCustomRequestHeaders),
CustomResponseHeaders: getMapAnnotation(i, annotationKubernetesCustomResponseHeaders),
AllowedHosts: getSliceAnnotation(i, annotationKubernetesAllowedHosts),
@ -364,7 +364,7 @@ func (p *Provider) loadConfig(templateObjects types.Configuration) *types.Config
}
func getSTSSeconds(i *v1beta1.Ingress) int64 {
value, err := strconv.ParseInt(i.ObjectMeta.Annotations[annotationKubernetesHSTSMaxAge], 10, 64)
value, err := strconv.ParseInt(i.Annotations[annotationKubernetesHSTSMaxAge], 10, 64)
if err == nil && value > 0 {
return value
}

View file

@ -280,6 +280,7 @@ func TestLoadIngresses(t *testing.T) {
"foo/bar": {
Backend: "foo/bar",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/bar": {
Rule: "PathPrefix:/bar",
@ -292,6 +293,7 @@ func TestLoadIngresses(t *testing.T) {
"foo/namedthing": {
Backend: "foo/namedthing",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/namedthing": {
Rule: "PathPrefix:/namedthing",
@ -304,6 +306,7 @@ func TestLoadIngresses(t *testing.T) {
"bar": {
Backend: "bar",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"bar": {
Rule: "Host:bar",
@ -409,6 +412,7 @@ func TestRuleType(t *testing.T) {
expected := map[string]*types.Frontend{
"host/path": {
Backend: "host/path",
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/path": {
Rule: fmt.Sprintf("%s:/path", test.frontendRuleType),
@ -494,6 +498,7 @@ func TestGetPassHostHeader(t *testing.T) {
Frontends: map[string]*types.Frontend{
"foo/bar": {
Backend: "foo/bar",
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/bar": {
Rule: "PathPrefix:/bar",
@ -580,6 +585,7 @@ func TestGetPassTLSCert(t *testing.T) {
Backend: "foo/bar",
PassTLSCert: true,
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/bar": {
Rule: "PathPrefix:/bar",
@ -682,6 +688,7 @@ func TestOnlyReferencesServicesFromOwnNamespace(t *testing.T) {
"foo": {
Backend: "foo",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"foo": {
Rule: "Host:foo",
@ -762,6 +769,7 @@ func TestHostlessIngress(t *testing.T) {
Frontends: map[string]*types.Frontend{
"/bar": {
Backend: "/bar",
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/bar": {
Rule: "PathPrefix:/bar",
@ -980,6 +988,7 @@ func TestServiceAnnotations(t *testing.T) {
"foo/bar": {
Backend: "foo/bar",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/bar": {
Rule: "PathPrefix:/bar",
@ -992,6 +1001,7 @@ func TestServiceAnnotations(t *testing.T) {
"bar": {
Backend: "bar",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"bar": {
Rule: "Host:bar",
@ -1445,6 +1455,7 @@ func TestIngressAnnotations(t *testing.T) {
"foo/bar": {
Backend: "foo/bar",
PassHostHeader: false,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/bar": {
Rule: "PathPrefix:/bar",
@ -1457,6 +1468,7 @@ func TestIngressAnnotations(t *testing.T) {
"other/stuff": {
Backend: "other/stuff",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/stuff": {
Rule: "PathPrefix:/stuff",
@ -1469,6 +1481,7 @@ func TestIngressAnnotations(t *testing.T) {
"other/": {
Backend: "other/",
PassHostHeader: true,
Headers: &types.Headers{},
EntryPoints: []string{"http", "https"},
Routes: map[string]types.Route{
"/": {
@ -1483,6 +1496,7 @@ func TestIngressAnnotations(t *testing.T) {
Backend: "other/sslstuff",
PassHostHeader: true,
PassTLSCert: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/sslstuff": {
Rule: "PathPrefix:/sslstuff",
@ -1495,6 +1509,7 @@ func TestIngressAnnotations(t *testing.T) {
"basic/auth": {
Backend: "basic/auth",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/auth": {
Rule: "PathPrefix:/auth",
@ -1508,6 +1523,7 @@ func TestIngressAnnotations(t *testing.T) {
"redirect/https": {
Backend: "redirect/https",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/https": {
Rule: "PathPrefix:/https",
@ -1524,6 +1540,7 @@ func TestIngressAnnotations(t *testing.T) {
"test/whitelist-source-range": {
Backend: "test/whitelist-source-range",
PassHostHeader: true,
Headers: &types.Headers{},
WhitelistSourceRange: []string{
"1.1.1.1/24",
"1234:abcd::42/32",
@ -1540,6 +1557,7 @@ func TestIngressAnnotations(t *testing.T) {
"rewrite/api": {
Backend: "rewrite/api",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/api": {
Rule: "PathPrefix:/api;ReplacePath:/",
@ -1641,6 +1659,7 @@ func TestPriorityHeaderValue(t *testing.T) {
Backend: "foo/bar",
PassHostHeader: true,
Priority: 1337,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/bar": {
Rule: "PathPrefix:/bar",
@ -1742,6 +1761,7 @@ func TestInvalidPassTLSCertValue(t *testing.T) {
Backend: "foo/bar",
PassTLSCert: false,
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/bar": {
Rule: "PathPrefix:/bar",
@ -1842,6 +1862,7 @@ func TestInvalidPassHostHeaderValue(t *testing.T) {
"foo/bar": {
Backend: "foo/bar",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"/bar": {
Rule: "PathPrefix:/bar",
@ -2143,6 +2164,7 @@ func TestMissingResources(t *testing.T) {
"fully_working": {
Backend: "fully_working",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"fully_working": {
Rule: "Host:fully_working",
@ -2152,6 +2174,7 @@ func TestMissingResources(t *testing.T) {
"missing_endpoints": {
Backend: "missing_endpoints",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"missing_endpoints": {
Rule: "Host:missing_endpoints",
@ -2161,6 +2184,7 @@ func TestMissingResources(t *testing.T) {
"missing_endpoint_subsets": {
Backend: "missing_endpoint_subsets",
PassHostHeader: true,
Headers: &types.Headers{},
Routes: map[string]types.Route{
"missing_endpoint_subsets": {
Rule: "Host:missing_endpoint_subsets",

View file

@ -980,10 +980,9 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
continue frontend
}
var headerMiddleware *middlewares.HeaderStruct
headerMiddleware := middlewares.NewHeaderFromStruct(frontend.Headers)
var responseModifier func(res *http.Response) error
if frontend.Headers.HasCustomHeadersDefined() {
headerMiddleware = middlewares.NewHeaderFromStruct(frontend.Headers)
if headerMiddleware != nil {
responseModifier = headerMiddleware.ModifyResponseHeaders
}
@ -1166,8 +1165,9 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
log.Debugf("Adding header middleware for frontend %s", frontendName)
n.Use(headerMiddleware)
}
if frontend.Headers.HasSecureHeadersDefined() {
secureMiddleware := middlewares.NewSecure(frontend.Headers)
if secureMiddleware != nil {
log.Debugf("Adding secure middleware for frontend %s", frontendName)
n.UseFunc(secureMiddleware.HandlerFuncWithNext)
}

View file

@ -94,6 +94,7 @@
replacement = "{{getRedirectReplacement $container}}"
{{end}}
{{ if hasHeaders $container}}
[frontends."frontend-{{$frontend}}".headers]
{{if hasSSLRedirectHeaders $container}}
SSLRedirect = {{getSSLRedirectHeaders $container}}
@ -140,6 +141,16 @@
{{if hasIsDevelopmentHeaders $container}}
IsDevelopment = {{getIsDevelopmentHeaders $container}}
{{end}}
{{if hasAllowedHostsHeaders $container}}
AllowedHosts = [{{range getAllowedHostsHeaders $container}}
"{{.}}",
{{end}}]
{{end}}
{{if hasHostsProxyHeaders $container}}
HostsProxyHeaders = [{{range getHostsProxyHeaders $container}}
"{{.}}",
{{end}}]
{{end}}
{{if hasRequestHeaders $container}}
[frontends."frontend-{{$frontend}}".headers.customrequestheaders]
{{range $k, $v := getRequestHeaders $container}}
@ -152,24 +163,14 @@
{{$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}}
{{end}}
[frontends."frontend-{{$frontend}}".routes."route-frontend-{{$frontend}}"]
rule = "{{getFrontendRule $container}}"
{{end}}

View file

@ -42,6 +42,7 @@
replacement = "{{$frontend.RedirectReplacement}}"
{{end}}
{{ if $frontend.Headers }}
[frontends."{{$frontendName}}".headers]
SSLRedirect = {{$frontend.Headers.SSLRedirect}}
SSLTemporaryRedirect = {{$frontend.Headers.SSLTemporaryRedirect}}
@ -58,36 +59,41 @@
PublicKey = "{{$frontend.Headers.PublicKey}}"
ReferrerPolicy = "{{$frontend.Headers.ReferrerPolicy}}"
IsDevelopment = {{$frontend.Headers.IsDevelopment}}
{{if $frontend.Headers.CustomRequestHeaders}}
{{if $frontend.Headers.AllowedHosts}}
AllowedHosts = [{{range $frontend.Headers.AllowedHosts}}
"{{.}}",
{{end}}]
{{end}}
{{if $frontend.Headers.HostsProxyHeaders}}
HostsProxyHeaders = [{{range $frontend.Headers.HostsProxyHeaders}}
"{{.}}",
{{end}}]
{{end}}
{{if $frontend.Headers.CustomRequestHeaders}}
[frontends."{{$frontendName}}".headers.customrequestheaders]
{{range $k, $v := $frontend.Headers.CustomRequestHeaders}}
{{$k}} = "{{$v}}"
{{end}}
{{end}}
{{if $frontend.Headers.CustomResponseHeaders}}
{{end}}
{{if $frontend.Headers.CustomResponseHeaders}}
[frontends."{{$frontendName}}".headers.customresponseheaders]
{{range $k, $v := $frontend.Headers.CustomResponseHeaders}}
{{$k}} = "{{$v}}"
{{end}}
{{end}}
{{if $frontend.Headers.AllowedHosts}}
[frontends."{{$frontendName}}".headers.AllowedHosts]
{{range $frontend.Headers.AllowedHosts}}
"{{.}}"
{{end}}
{{end}}
{{if $frontend.Headers.HostsProxyHeaders}}
[frontends."{{$frontendName}}".headers.HostsProxyHeaders]
{{range $frontend.Headers.HostsProxyHeaders}}
"{{.}}"
{{end}}
{{end}}
{{if $frontend.Headers.SSLProxyHeaders}}
{{if $frontend.Headers.SSLProxyHeaders}}
[frontends."{{$frontendName}}".headers.SSLProxyHeaders]
{{range $k, $v := $frontend.Headers.SSLProxyHeaders}}
{{$k}} = "{{$v}}"
{{end}}
{{end}}
{{end}}
{{range $routeName, $route := $frontend.Routes}}
[frontends."{{$frontendName}}".routes."{{$routeName}}"]
rule = "{{$route.Rule}}"

View file

@ -113,14 +113,14 @@ type Headers struct {
}
// HasCustomHeadersDefined checks to see if any of the custom header elements have been set
func (h Headers) HasCustomHeadersDefined() bool {
return len(h.CustomResponseHeaders) != 0 ||
len(h.CustomRequestHeaders) != 0
func (h *Headers) HasCustomHeadersDefined() bool {
return h != nil && (len(h.CustomResponseHeaders) != 0 ||
len(h.CustomRequestHeaders) != 0)
}
// HasSecureHeadersDefined checks to see if any of the secure header elements have been set
func (h Headers) HasSecureHeadersDefined() bool {
return len(h.AllowedHosts) != 0 ||
func (h *Headers) HasSecureHeadersDefined() bool {
return h != nil && (len(h.AllowedHosts) != 0 ||
len(h.HostsProxyHeaders) != 0 ||
h.SSLRedirect ||
h.SSLTemporaryRedirect ||
@ -137,7 +137,7 @@ func (h Headers) HasSecureHeadersDefined() bool {
h.ContentSecurityPolicy != "" ||
h.PublicKey != "" ||
h.ReferrerPolicy != "" ||
h.IsDevelopment
h.IsDevelopment)
}
// Frontend holds frontend configuration.
@ -150,7 +150,7 @@ type Frontend struct {
Priority int `json:"priority"`
BasicAuth []string `json:"basicAuth"`
WhitelistSourceRange []string `json:"whitelistSourceRange,omitempty"`
Headers Headers `json:"headers,omitempty"`
Headers *Headers `json:"headers,omitempty"`
Errors map[string]ErrorPage `json:"errors,omitempty"`
RateLimit *RateLimit `json:"ratelimit,omitempty"`
Redirect *Redirect `json:"redirect,omitempty"`