Add the missing pass-client-tls annotation to the kubernetes provider

This commit is contained in:
Jean-Baptiste Doumenjou 2018-10-29 16:02:06 +01:00 committed by Traefiker Bot
parent 7eeecd23ac
commit 450471d30a
7 changed files with 183 additions and 65 deletions

View file

@ -1379,6 +1379,28 @@ var _templatesKubernetesTmpl = []byte(`[backends]
{{end}}
{{end}}
{{if $frontend.PassTLSClientCert }}
[frontends."{{ $frontendName }}".passTLSClientCert]
pem = {{ $frontend.PassTLSClientCert.PEM }}
{{ $infos := $frontend.PassTLSClientCert.Infos }}
{{if $infos }}
[frontends."{{ $frontendName }}".passTLSClientCert.infos]
notAfter = {{ $infos.NotAfter }}
notBefore = {{ $infos.NotBefore }}
sans = {{ $infos.Sans }}
{{ $subject := $infos.Subject }}
{{if $subject }}
[frontends."{{ $frontendName }}".passTLSClientCert.infos.subject]
country = {{ $subject.Country }}
province = {{ $subject.Province }}
locality = {{ $subject.Locality }}
organization = {{ $subject.Organization }}
commonName = {{ $subject.CommonName }}
serialNumber = {{ $subject.SerialNumber }}
{{end}}
{{end}}
{{end}}
{{if $frontend.Headers }}
[frontends."{{ $frontendName }}".headers]
SSLRedirect = {{ $frontend.Headers.SSLRedirect }}

View file

@ -146,29 +146,35 @@ If either of those configuration options exist, then the backend communication p
The following general annotations are applicable on the Ingress object:
| Annotation | Description |
|---------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.ingress.kubernetes.io/error-pages: <YML>` | (1) See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.ingress.kubernetes.io/frontend-entry-points: http,https` | Override the default frontend endpoints. |
| `traefik.ingress.kubernetes.io/pass-tls-cert: "true"` | Override the default frontend PassTLSCert value. Default: `false`. |
| `traefik.ingress.kubernetes.io/preserve-host: "true"` | Forward client `Host` header to the backend. |
| `traefik.ingress.kubernetes.io/priority: "3"` | Override the default frontend rule priority. |
| `traefik.ingress.kubernetes.io/rate-limit: <YML>` | (2) See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.ingress.kubernetes.io/redirect-entry-point: https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS). |
| `traefik.ingress.kubernetes.io/redirect-permanent: "true"` | Return 301 instead of 302. |
| `traefik.ingress.kubernetes.io/redirect-regex: ^http://localhost/(.*)` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-replacement`. |
| `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. |
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. |
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Overrides the default frontend rule type. Only path-related matchers can be specified [(`Path`, `PathPrefix`, `PathStrip`, `PathPrefixStrip`)](/basics/#path-matcher-usage-guidelines). |
| `traefik.ingress.kubernetes.io/request-modifier: AddPrefix: /users` | Adds a [request modifier](/basics/#modifiers) to the backend request. |
| `traefik.ingress.kubernetes.io/whitelist-source-range: "1.2.3.0/24, fe80::/16"` | A comma-separated list of IP ranges permitted for access (6). |
| `ingress.kubernetes.io/whitelist-x-forwarded-for: "true"` | Use `X-Forwarded-For` header as valid source of IP for the white list. |
| `traefik.ingress.kubernetes.io/app-root: "/index.html"` | Redirects all requests for `/` to the defined path. (4) |
| `traefik.ingress.kubernetes.io/service-weights: <YML>` | Set ingress backend weights specified as percentage or decimal numbers in YAML. (5)
| `ingress.kubernetes.io/protocol: <NAME>` | Set the protocol Traefik will use to communicate with pods.
| Annotation | Description |
|---------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.ingress.kubernetes.io/app-root: "/index.html"` | Redirects all requests for `/` to the defined path. (1) |
| `traefik.ingress.kubernetes.io/error-pages: <YML>` | See [custom error pages](/configuration/commons/#custom-error-pages) section. (2) |
| `traefik.ingress.kubernetes.io/frontend-entry-points: http,https` | Override the default frontend endpoints. |
| `traefik.ingress.kubernetes.io/pass-client-tls-cert: <YML>` | Forward the client certificate following the configuration in YAML. (3) |
| `traefik.ingress.kubernetes.io/pass-tls-cert: "true"` | Override the default frontend PassTLSCert value. Default: `false`.(DEPRECATED) |
| `traefik.ingress.kubernetes.io/preserve-host: "true"` | Forward client `Host` header to the backend. |
| `traefik.ingress.kubernetes.io/priority: "3"` | Override the default frontend rule priority. |
| `traefik.ingress.kubernetes.io/rate-limit: <YML>` | See [rate limiting](/configuration/commons/#rate-limiting) section. (4) |
| `traefik.ingress.kubernetes.io/redirect-entry-point: https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS). |
| `traefik.ingress.kubernetes.io/redirect-permanent: "true"` | Return 301 instead of 302. |
| `traefik.ingress.kubernetes.io/redirect-regex: ^http://localhost/(.*)` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-replacement`. |
| `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. |
| `traefik.ingress.kubernetes.io/request-modifier: AddPrefix: /users` | Adds a [request modifier](/basics/#modifiers) to the backend request. |
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. |
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Overrides the default frontend rule type. Only path-related matchers can be specified [(`Path`, `PathPrefix`, `PathStrip`, `PathPrefixStrip`)](/basics/#path-matcher-usage-guidelines).(5) |
| `traefik.ingress.kubernetes.io/service-weights: <YML>` | Set ingress backend weights specified as percentage or decimal numbers in YAML. (6) |
| `traefik.ingress.kubernetes.io/whitelist-source-range: "1.2.3.0/24, fe80::/16"` | A comma-separated list of IP ranges permitted for access (7). |
| `ingress.kubernetes.io/whitelist-x-forwarded-for: "true"` | Use `X-Forwarded-For` header as valid source of IP for the white list. |
| `ingress.kubernetes.io/protocol: <NAME>` | Set the protocol Traefik will use to communicate with pods. |
<1> `traefik.ingress.kubernetes.io/app-root`:
Non-root paths will not be affected by this annotation and handled normally.
This annotation may not be combined with other redirect annotations.
Trying to do so will result in the other redirects being ignored.
This annotation can be used in combination with `traefik.ingress.kubernetes.io/redirect-permanent` to configure whether the `app-root` redirect is a 301 or a 302.
<1> `traefik.ingress.kubernetes.io/error-pages` example:
<2> `traefik.ingress.kubernetes.io/error-pages` example:
```yaml
foo:
@ -184,7 +190,31 @@ fii:
query: /bir
```
<2> `traefik.ingress.kubernetes.io/rate-limit` example:
<3> `traefik.ingress.kubernetes.io/pass-client-tls-cert` example:
```yaml
# add escaped pem in the `X-Forwarded-Tls-Client-Cert` header
pem: true
# add escaped certificate following infos in the `X-Forwarded-Tls-Client-Cert-Infos` header
infos:
notafter: true
notbefore: true
sans: true
subject:
country: true
province: true
locality: true
organization: true
commonname: true
serialnumber: true
```
If `pem` is set, it will add a `X-Forwarded-Tls-Client-Cert` header that contains the escaped pem as value.
If at least one flag of the `infos` part is set, it will add a `X-Forwarded-Tls-Client-Cert-Infos` header that contains an escaped string composed of the client certificate data selected by the infos flags.
This infos part is composed like the following example (not escaped):
```Subject="C=FR,ST=SomeState,L=Lyon,O=Cheese,CN=*.cheese.org",NB=1531900816,NA=1563436816,SAN=*.cheese.org,*.cheese.net,cheese.in,test@cheese.org,test@cheese.net,10.0.1.0,10.0.1.2```
<4> `traefik.ingress.kubernetes.io/rate-limit` example:
```yaml
extractorfunc: client.ip
@ -199,16 +229,10 @@ rateset:
burst: 18
```
<3> `traefik.ingress.kubernetes.io/rule-type`
<5> `traefik.ingress.kubernetes.io/rule-type`
Note: `ReplacePath` is deprecated in this annotation, use the `traefik.ingress.kubernetes.io/request-modifier` annotation instead. Default: `PathPrefix`.
<4> `traefik.ingress.kubernetes.io/app-root`:
Non-root paths will not be affected by this annotation and handled normally.
This annotation may not be combined with other redirect annotations.
Trying to do so will result in the other redirects being ignored.
This annotation can be used in combination with `traefik.ingress.kubernetes.io/redirect-permanent` to configure whether the `app-root` redirect is a 301 or a 302.
<5> `traefik.ingress.kubernetes.io/service-weights`:
<6> `traefik.ingress.kubernetes.io/service-weights`:
Service weights enable to split traffic across multiple backing services in a fine-grained manner.
Example:
@ -236,7 +260,7 @@ For each path definition, this annotation will fail if:
See also the [user guide section traffic splitting](/user-guide/kubernetes/#traffic-splitting).
<6> `traefik.ingress.kubernetes.io/whitelist-source-range`:
<7> `traefik.ingress.kubernetes.io/whitelist-source-range`:
All source IPs are permitted if the list is empty or a single range is ill-formatted.
Please note, you may have to set `service.spec.externalTrafficPolicy` to the value `Local` to preserve the source IP of the request for filtering.
Please see [this link](https://kubernetes.io/docs/tutorials/services/source-ip/) for more information.

View file

@ -22,7 +22,8 @@ const (
annotationKubernetesWhiteListSourceRange = "ingress.kubernetes.io/whitelist-source-range"
annotationKubernetesWhiteListUseXForwardedFor = "ingress.kubernetes.io/whitelist-x-forwarded-for"
annotationKubernetesPreserveHost = "ingress.kubernetes.io/preserve-host"
annotationKubernetesPassTLSCert = "ingress.kubernetes.io/pass-tls-cert"
annotationKubernetesPassTLSCert = "ingress.kubernetes.io/pass-tls-cert" // Deprecated
annotationKubernetesPassTLSClientCert = "ingress.kubernetes.io/pass-client-tls-cert"
annotationKubernetesFrontendEntryPoints = "ingress.kubernetes.io/frontend-entry-points"
annotationKubernetesPriority = "ingress.kubernetes.io/priority"
annotationKubernetesCircuitBreakerExpression = "ingress.kubernetes.io/circuit-breaker-expression"

View file

@ -382,12 +382,34 @@ func limitPeriod(period time.Duration) func(*types.Rate) {
}
}
// Deprecated
func passTLSCert() func(*types.Frontend) {
return func(f *types.Frontend) {
f.PassTLSCert = true
}
}
func passTLSClientCert() func(*types.Frontend) {
return func(f *types.Frontend) {
f.PassTLSClientCert = &types.TLSClientHeaders{
PEM: true,
Infos: &types.TLSClientCertificateInfos{
NotAfter: true,
NotBefore: true,
Subject: &types.TLSCLientCertificateSubjectInfos{
Country: true,
Province: true,
Locality: true,
Organization: true,
CommonName: true,
SerialNumber: true,
},
Sans: true,
},
}
}
}
func routes(opts ...func(*types.Route) string) func(*types.Frontend) {
return func(f *types.Frontend) {
f.Routes = make(map[string]types.Route)

View file

@ -62,7 +62,7 @@ type Provider struct {
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"`
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"`
DisablePassHostHeaders bool `description:"Kubernetes disable PassHost Headers" export:"true"`
EnablePassTLSCert bool `description:"Kubernetes enable Pass TLS Client Certs" export:"true"`
EnablePassTLSCert bool `description:"Kubernetes enable Pass TLS Client Certs" export:"true"` // Deprecated
Namespaces Namespaces `description:"Kubernetes namespaces" export:"true"`
LabelSelector string `description:"Kubernetes Ingress label selector to use" export:"true"`
IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for" export:"true"`
@ -275,22 +275,23 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
}
passHostHeader := getBoolValue(i.Annotations, annotationKubernetesPreserveHost, !p.DisablePassHostHeaders)
passTLSCert := getBoolValue(i.Annotations, annotationKubernetesPassTLSCert, p.EnablePassTLSCert)
passTLSCert := getBoolValue(i.Annotations, annotationKubernetesPassTLSCert, p.EnablePassTLSCert) // Deprecated
entryPoints := getSliceStringValue(i.Annotations, annotationKubernetesFrontendEntryPoints)
frontend = &types.Frontend{
Backend: baseName,
PassHostHeader: passHostHeader,
PassTLSCert: passTLSCert,
Routes: make(map[string]types.Route),
Priority: priority,
WhiteList: getWhiteList(i),
Redirect: getFrontendRedirect(i, baseName, pa.Path),
EntryPoints: entryPoints,
Headers: getHeader(i),
Errors: getErrorPages(i),
RateLimit: getRateLimit(i),
Auth: auth,
Backend: baseName,
PassHostHeader: passHostHeader,
PassTLSCert: passTLSCert,
PassTLSClientCert: getPassTLSClientCert(i),
Routes: make(map[string]types.Route),
Priority: priority,
WhiteList: getWhiteList(i),
Redirect: getFrontendRedirect(i, baseName, pa.Path),
EntryPoints: entryPoints,
Headers: getHeader(i),
Errors: getErrorPages(i),
RateLimit: getRateLimit(i),
Auth: auth,
}
}
@ -532,22 +533,23 @@ func (p *Provider) addGlobalBackend(cl Client, i *extensionsv1beta1.Ingress, tem
}
passHostHeader := getBoolValue(i.Annotations, annotationKubernetesPreserveHost, !p.DisablePassHostHeaders)
passTLSCert := getBoolValue(i.Annotations, annotationKubernetesPassTLSCert, p.EnablePassTLSCert)
passTLSCert := getBoolValue(i.Annotations, annotationKubernetesPassTLSCert, p.EnablePassTLSCert) // Deprecated
priority := getIntValue(i.Annotations, annotationKubernetesPriority, 0)
entryPoints := getSliceStringValue(i.Annotations, annotationKubernetesFrontendEntryPoints)
templateObjects.Frontends[defaultFrontendName] = &types.Frontend{
Backend: defaultBackendName,
PassHostHeader: passHostHeader,
PassTLSCert: passTLSCert,
Routes: make(map[string]types.Route),
Priority: priority,
WhiteList: getWhiteList(i),
Redirect: getFrontendRedirect(i, defaultFrontendName, "/"),
EntryPoints: entryPoints,
Headers: getHeader(i),
Errors: getErrorPages(i),
RateLimit: getRateLimit(i),
Backend: defaultBackendName,
PassHostHeader: passHostHeader,
PassTLSCert: passTLSCert,
PassTLSClientCert: getPassTLSClientCert(i),
Routes: make(map[string]types.Route),
Priority: priority,
WhiteList: getWhiteList(i),
Redirect: getFrontendRedirect(i, defaultFrontendName, "/"),
EntryPoints: entryPoints,
Headers: getHeader(i),
Errors: getErrorPages(i),
RateLimit: getRateLimit(i),
}
templateObjects.Frontends[defaultFrontendName].Routes["/"] = types.Route{
@ -1084,6 +1086,22 @@ func getRateLimit(i *extensionsv1beta1.Ingress) *types.RateLimit {
return rateLimit
}
func getPassTLSClientCert(i *extensionsv1beta1.Ingress) *types.TLSClientHeaders {
var passTLSClientCert *types.TLSClientHeaders
passRaw := getStringValue(i.Annotations, annotationKubernetesPassTLSClientCert, "")
if len(passRaw) > 0 {
passTLSClientCert = &types.TLSClientHeaders{}
err := yaml.Unmarshal([]byte(passRaw), passTLSClientCert)
if err != nil {
log.Error(err)
return nil
}
}
return passTLSClientCert
}
func templateSafeString(value string) error {
_, err := strconv.Unquote(`"` + value + `"`)
return err

View file

@ -728,6 +728,7 @@ func TestGetPassHostHeader(t *testing.T) {
assert.Equal(t, expected, actual)
}
// Deprecated
func TestGetPassTLSCert(t *testing.T) {
ingresses := []*extensionsv1beta1.Ingress{
buildIngress(iNamespace("awesome"),
@ -1102,6 +1103,20 @@ func TestIngressAnnotations(t *testing.T) {
buildIngress(
iNamespace("testing"),
iAnnotation(annotationKubernetesPassTLSCert, "true"),
iAnnotation(annotationKubernetesPassTLSClientCert, `
pem: true
infos:
notafter: true
notbefore: true
sans: true
subject:
country: true
province: true
locality: true
organization: true
commonname: true
serialnumber: true
`),
iAnnotation(annotationKubernetesIngressClass, traefikDefaultRealm),
iRules(
iRule(
@ -1500,13 +1515,7 @@ rateset:
),
frontend("other/sslstuff",
passHostHeader(),
passTLSCert(),
routes(
route("/sslstuff", "PathPrefix:/sslstuff"),
route("other", "Host:other")),
),
frontend("other/sslstuff",
passHostHeader(),
passTLSClientCert(),
passTLSCert(),
routes(
route("/sslstuff", "PathPrefix:/sslstuff"),

View file

@ -129,6 +129,28 @@
{{end}}
{{end}}
{{if $frontend.PassTLSClientCert }}
[frontends."{{ $frontendName }}".passTLSClientCert]
pem = {{ $frontend.PassTLSClientCert.PEM }}
{{ $infos := $frontend.PassTLSClientCert.Infos }}
{{if $infos }}
[frontends."{{ $frontendName }}".passTLSClientCert.infos]
notAfter = {{ $infos.NotAfter }}
notBefore = {{ $infos.NotBefore }}
sans = {{ $infos.Sans }}
{{ $subject := $infos.Subject }}
{{if $subject }}
[frontends."{{ $frontendName }}".passTLSClientCert.infos.subject]
country = {{ $subject.Country }}
province = {{ $subject.Province }}
locality = {{ $subject.Locality }}
organization = {{ $subject.Organization }}
commonName = {{ $subject.CommonName }}
serialNumber = {{ $subject.SerialNumber }}
{{end}}
{{end}}
{{end}}
{{if $frontend.Headers }}
[frontends."{{ $frontendName }}".headers]
SSLRedirect = {{ $frontend.Headers.SSLRedirect }}