feat(consulcatalog): add custom Headers tags.
This commit is contained in:
parent
8e7ac513b6
commit
238acd9330
3 changed files with 180 additions and 0 deletions
|
@ -55,6 +55,7 @@ func (p *CatalogProvider) buildConfiguration(catalog []catalogUpdate) *types.Con
|
||||||
"getErrorPages": p.getErrorPages,
|
"getErrorPages": p.getErrorPages,
|
||||||
"hasRateLimit": p.getFuncHasAttributePrefix(label.BaseFrontendRateLimit),
|
"hasRateLimit": p.getFuncHasAttributePrefix(label.BaseFrontendRateLimit),
|
||||||
"getRateLimit": p.getRateLimit,
|
"getRateLimit": p.getRateLimit,
|
||||||
|
"getHeaders": p.getHeaders,
|
||||||
}
|
}
|
||||||
|
|
||||||
var allNodes []*api.ServiceEntry
|
var allNodes []*api.ServiceEntry
|
||||||
|
@ -336,6 +337,37 @@ func (p *CatalogProvider) getRateLimit(tags []string) *types.RateLimit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *CatalogProvider) getHeaders(tags []string) *types.Headers {
|
||||||
|
headers := &types.Headers{
|
||||||
|
CustomRequestHeaders: p.getMapAttribute(label.SuffixFrontendRequestHeaders, tags),
|
||||||
|
CustomResponseHeaders: p.getMapAttribute(label.SuffixFrontendResponseHeaders, tags),
|
||||||
|
SSLProxyHeaders: p.getMapAttribute(label.SuffixFrontendHeadersSSLProxyHeaders, tags),
|
||||||
|
AllowedHosts: p.getSliceAttribute(label.SuffixFrontendHeadersAllowedHosts, tags),
|
||||||
|
HostsProxyHeaders: p.getSliceAttribute(label.SuffixFrontendHeadersHostsProxyHeaders, tags),
|
||||||
|
SSLHost: p.getAttribute(label.SuffixFrontendHeadersSSLHost, tags, ""),
|
||||||
|
CustomFrameOptionsValue: p.getAttribute(label.SuffixFrontendHeadersCustomFrameOptionsValue, tags, ""),
|
||||||
|
ContentSecurityPolicy: p.getAttribute(label.SuffixFrontendHeadersContentSecurityPolicy, tags, ""),
|
||||||
|
PublicKey: p.getAttribute(label.SuffixFrontendHeadersPublicKey, tags, ""),
|
||||||
|
ReferrerPolicy: p.getAttribute(label.SuffixFrontendHeadersReferrerPolicy, tags, ""),
|
||||||
|
STSSeconds: p.getInt64Attribute(label.SuffixFrontendHeadersSTSSeconds, tags, 0),
|
||||||
|
SSLRedirect: p.getBoolAttribute(label.SuffixFrontendHeadersSSLRedirect, tags, false),
|
||||||
|
SSLTemporaryRedirect: p.getBoolAttribute(label.SuffixFrontendHeadersSSLTemporaryRedirect, tags, false),
|
||||||
|
STSIncludeSubdomains: p.getBoolAttribute(label.SuffixFrontendHeadersSTSIncludeSubdomains, tags, false),
|
||||||
|
STSPreload: p.getBoolAttribute(label.SuffixFrontendHeadersSTSPreload, tags, false),
|
||||||
|
ForceSTSHeader: p.getBoolAttribute(label.SuffixFrontendHeadersForceSTSHeader, tags, false),
|
||||||
|
FrameDeny: p.getBoolAttribute(label.SuffixFrontendHeadersFrameDeny, tags, false),
|
||||||
|
ContentTypeNosniff: p.getBoolAttribute(label.SuffixFrontendHeadersContentTypeNosniff, tags, false),
|
||||||
|
BrowserXSSFilter: p.getBoolAttribute(label.SuffixFrontendHeadersBrowserXSSFilter, tags, false),
|
||||||
|
IsDevelopment: p.getBoolAttribute(label.SuffixFrontendHeadersIsDevelopment, tags, false),
|
||||||
|
}
|
||||||
|
|
||||||
|
if !headers.HasSecureHeadersDefined() && !headers.HasCustomHeadersDefined() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return headers
|
||||||
|
}
|
||||||
|
|
||||||
// Base functions
|
// Base functions
|
||||||
|
|
||||||
func (p *CatalogProvider) parseTagsToNeutralLabels(tags []string) map[string]string {
|
func (p *CatalogProvider) parseTagsToNeutralLabels(tags []string) map[string]string {
|
||||||
|
@ -372,6 +404,16 @@ func (p *CatalogProvider) getFuncSliceAttribute(name string) func(tags []string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *CatalogProvider) getMapAttribute(name string, tags []string) map[string]string {
|
||||||
|
rawValue := getTag(p.getPrefixedName(name), tags, "")
|
||||||
|
|
||||||
|
if len(rawValue) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return label.ParseMapValue(p.getPrefixedName(name), rawValue)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *CatalogProvider) getFuncIntAttribute(name string, defaultValue int) func(tags []string) int {
|
func (p *CatalogProvider) getFuncIntAttribute(name string, defaultValue int) func(tags []string) int {
|
||||||
return func(tags []string) int {
|
return func(tags []string) int {
|
||||||
return p.getIntAttribute(name, tags, defaultValue)
|
return p.getIntAttribute(name, tags, defaultValue)
|
||||||
|
|
|
@ -1166,3 +1166,88 @@ func TestCatalogProviderGetRateLimit(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCatalogProviderGetHeaders(t *testing.T) {
|
||||||
|
p := &CatalogProvider{
|
||||||
|
Prefix: "traefik",
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
tags []string
|
||||||
|
expected *types.Headers
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "should return nil when no tags",
|
||||||
|
tags: []string{},
|
||||||
|
expected: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "should return a struct when has tags",
|
||||||
|
tags: []string{
|
||||||
|
label.TraefikFrontendRequestHeaders + "=Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8",
|
||||||
|
label.TraefikFrontendResponseHeaders + "=Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8",
|
||||||
|
label.TraefikFrontendSSLProxyHeaders + "=Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8",
|
||||||
|
label.TraefikFrontendAllowedHosts + "=foo,bar,bor",
|
||||||
|
label.TraefikFrontendHostsProxyHeaders + "=foo,bar,bor",
|
||||||
|
label.TraefikFrontendSSLHost + "=foo",
|
||||||
|
label.TraefikFrontendCustomFrameOptionsValue + "=foo",
|
||||||
|
label.TraefikFrontendContentSecurityPolicy + "=foo",
|
||||||
|
label.TraefikFrontendPublicKey + "=foo",
|
||||||
|
label.TraefikFrontendReferrerPolicy + "=foo",
|
||||||
|
label.TraefikFrontendSTSSeconds + "=666",
|
||||||
|
label.TraefikFrontendSSLRedirect + "=true",
|
||||||
|
label.TraefikFrontendSSLTemporaryRedirect + "=true",
|
||||||
|
label.TraefikFrontendSTSIncludeSubdomains + "=true",
|
||||||
|
label.TraefikFrontendSTSPreload + "=true",
|
||||||
|
label.TraefikFrontendForceSTSHeader + "=true",
|
||||||
|
label.TraefikFrontendFrameDeny + "=true",
|
||||||
|
label.TraefikFrontendContentTypeNosniff + "=true",
|
||||||
|
label.TraefikFrontendBrowserXSSFilter + "=true",
|
||||||
|
label.TraefikFrontendIsDevelopment + "=true",
|
||||||
|
},
|
||||||
|
expected: &types.Headers{
|
||||||
|
CustomRequestHeaders: map[string]string{
|
||||||
|
"Access-Control-Allow-Methods": "POST,GET,OPTIONS",
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
},
|
||||||
|
CustomResponseHeaders: map[string]string{
|
||||||
|
"Access-Control-Allow-Methods": "POST,GET,OPTIONS",
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
},
|
||||||
|
SSLProxyHeaders: map[string]string{
|
||||||
|
"Access-Control-Allow-Methods": "POST,GET,OPTIONS",
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
},
|
||||||
|
AllowedHosts: []string{"foo", "bar", "bor"},
|
||||||
|
HostsProxyHeaders: []string{"foo", "bar", "bor"},
|
||||||
|
SSLHost: "foo",
|
||||||
|
CustomFrameOptionsValue: "foo",
|
||||||
|
ContentSecurityPolicy: "foo",
|
||||||
|
PublicKey: "foo",
|
||||||
|
ReferrerPolicy: "foo",
|
||||||
|
STSSeconds: 666,
|
||||||
|
SSLRedirect: true,
|
||||||
|
SSLTemporaryRedirect: true,
|
||||||
|
STSIncludeSubdomains: true,
|
||||||
|
STSPreload: true,
|
||||||
|
ForceSTSHeader: true,
|
||||||
|
FrameDeny: true,
|
||||||
|
ContentTypeNosniff: true,
|
||||||
|
BrowserXSSFilter: true,
|
||||||
|
IsDevelopment: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
result := p.getHeaders(test.tags)
|
||||||
|
|
||||||
|
assert.Equal(t, test.expected, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -101,6 +101,59 @@
|
||||||
|
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{ $headers := getHeaders $service.Attributes }}
|
||||||
|
{{ if $headers }}
|
||||||
|
[frontends."frontend-{{ $service.ServiceName }}".headers]
|
||||||
|
SSLRedirect = {{ $headers.SSLRedirect }}
|
||||||
|
SSLTemporaryRedirect = {{ $headers.SSLTemporaryRedirect }}
|
||||||
|
SSLHost = "{{ $headers.SSLHost }}"
|
||||||
|
STSSeconds = {{ $headers.STSSeconds }}
|
||||||
|
STSIncludeSubdomains = {{ $headers.STSIncludeSubdomains }}
|
||||||
|
STSPreload = {{ $headers.STSPreload }}
|
||||||
|
ForceSTSHeader = {{ $headers.ForceSTSHeader }}
|
||||||
|
FrameDeny = {{ $headers.FrameDeny }}
|
||||||
|
CustomFrameOptionsValue = "{{ $headers.CustomFrameOptionsValue }}"
|
||||||
|
ContentTypeNosniff = {{ $headers.ContentTypeNosniff }}
|
||||||
|
BrowserXSSFilter = {{ $headers.BrowserXSSFilter }}
|
||||||
|
ContentSecurityPolicy = "{{ $headers.ContentSecurityPolicy }}"
|
||||||
|
PublicKey = "{{ $headers.PublicKey }}"
|
||||||
|
ReferrerPolicy = "{{ $headers.ReferrerPolicy }}"
|
||||||
|
IsDevelopment = {{ $headers.IsDevelopment }}
|
||||||
|
|
||||||
|
{{ if $headers.AllowedHosts }}
|
||||||
|
AllowedHosts = [{{ range $headers.AllowedHosts }}
|
||||||
|
"{{.}}",
|
||||||
|
{{end}}]
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{ if $headers.HostsProxyHeaders }}
|
||||||
|
HostsProxyHeaders = [{{ range $headers.HostsProxyHeaders }}
|
||||||
|
"{{.}}",
|
||||||
|
{{end}}]
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{ if $headers.CustomRequestHeaders }}
|
||||||
|
[frontends."frontend-{{ $service.ServiceName }}".headers.customRequestHeaders]
|
||||||
|
{{ range $k, $v := $headers.CustomRequestHeaders }}
|
||||||
|
{{$k}} = "{{$v}}"
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{ if $headers.CustomResponseHeaders }}
|
||||||
|
[frontends."frontend-{{ $service.ServiceName }}".headers.customResponseHeaders]
|
||||||
|
{{ range $k, $v := $headers.CustomResponseHeaders }}
|
||||||
|
{{$k}} = "{{$v}}"
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{ if $headers.SSLProxyHeaders }}
|
||||||
|
[frontends."frontend-{{ $service.ServiceName }}".headers.SSLProxyHeaders]
|
||||||
|
{{range $k, $v := $headers.SSLProxyHeaders}}
|
||||||
|
{{$k}} = "{{$v}}"
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
[frontends."frontend-{{ $service.ServiceName }}".routes."route-host-{{ $service.ServiceName }}"]
|
[frontends."frontend-{{ $service.ServiceName }}".routes."route-host-{{ $service.ServiceName }}"]
|
||||||
rule = "{{ getFrontendRule $service }}"
|
rule = "{{ getFrontendRule $service }}"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue