Define TLS options on the Router configuration for Kubernetes
Co-authored-by: juliens <julien@containo.us>
This commit is contained in:
parent
69cf05df9a
commit
80b35575df
48 changed files with 2374 additions and 53 deletions
|
@ -71,6 +71,38 @@ labels:
|
|||
- "traefik.http.middlewares.foo-add-prefix.addprefix.prefix=/foo"
|
||||
```
|
||||
|
||||
```toml tab="File"
|
||||
[tlsOptions]
|
||||
[tlsOptions.default]
|
||||
minVersion = "VersionTLS12"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: tlsoptions.traefik.containo.us
|
||||
|
||||
spec:
|
||||
group: traefik.containo.us
|
||||
version: v1alpha1
|
||||
names:
|
||||
kind: TLSOption
|
||||
plural: tlsoptions
|
||||
singular: tlsoption
|
||||
scope: Namespaced
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: mytlsoption
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
```
|
||||
|
||||
```toml tab="File"
|
||||
# As Toml Configuration File
|
||||
[providers]
|
||||
|
|
13
docs/content/providers/crd_tls_option.yml
Normal file
13
docs/content/providers/crd_tls_option.yml
Normal file
|
@ -0,0 +1,13 @@
|
|||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: tlsoptions.traefik.containo.us
|
||||
|
||||
spec:
|
||||
group: traefik.containo.us
|
||||
version: v1alpha1
|
||||
names:
|
||||
kind: TLSOption
|
||||
plural: tlsoptions
|
||||
singular: tlsoption
|
||||
scope: Namespaced
|
|
@ -230,6 +230,51 @@ spec:
|
|||
|
||||
More information about available middlewares in the dedicated [middlewares section](../middlewares/overview.md).
|
||||
|
||||
### Traefik TLS Option Definition
|
||||
|
||||
Additionally, to allow for the use of tls options in an IngressRoute, we defined the CRD below for the TLSOption kind.
|
||||
More information about TLS Options is available in the dedicated [TLS Configuration Options](../../https/tls/#tls-options).
|
||||
|
||||
```yaml
|
||||
--8<-- "content/providers/crd_tls_option.yml"
|
||||
```
|
||||
|
||||
Once the TLSOption kind has been registered with the Kubernetes cluster or defined in the File Provider, it can then be used in IngressRoute definitions, such as:
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: mytlsoption
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: ingressroutebar
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`bar.com`) && PathPrefix(`/stripit`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
tls:
|
||||
options:
|
||||
name: mytlsoption
|
||||
namespace: default
|
||||
```
|
||||
|
||||
!!! note "TLS Option reference and namespace"
|
||||
If the optional `namespace` attribute is not set, the configuration will be applied with the namespace of the IngressRoute.
|
||||
|
||||
### TLS
|
||||
|
||||
To allow for TLS, we made use of the `Secret` kind, as it was already defined, and it can be directly used in an `IngressRoute`:
|
||||
|
|
|
@ -26,6 +26,21 @@ spec:
|
|||
singular: middleware
|
||||
scope: Namespaced
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: tlsoptions.traefik.containo.us
|
||||
|
||||
spec:
|
||||
group: traefik.containo.us
|
||||
version: v1alpha1
|
||||
names:
|
||||
kind: TLSOption
|
||||
plural: tlsoptions
|
||||
singular: tlsoption
|
||||
scope: Namespaced
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
|
@ -85,6 +100,9 @@ spec:
|
|||
# use an empty tls object for TLS with Let's Encrypt
|
||||
tls:
|
||||
secretName: supersecret
|
||||
options:
|
||||
name: myTLSOption
|
||||
namespace: default
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
|
@ -104,3 +122,6 @@ spec:
|
|||
tls:
|
||||
secretName: foosecret
|
||||
passthrough: false
|
||||
options:
|
||||
name: myTLSOption
|
||||
namespace: default
|
||||
|
|
|
@ -44,7 +44,6 @@ level = "DEBUG"
|
|||
[[http.services.service2.LoadBalancer.Servers]]
|
||||
URL = "http://127.0.0.1:9020"
|
||||
|
||||
|
||||
[[tls]]
|
||||
[tls.certificate]
|
||||
certFile = "fixtures/https/snitest.com.cert"
|
||||
|
|
|
@ -41,3 +41,18 @@ spec:
|
|||
plural: ingressroutetcps
|
||||
singular: ingressroutetcp
|
||||
scope: Namespaced
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: tlsoptions.traefik.containo.us
|
||||
|
||||
spec:
|
||||
group: traefik.containo.us
|
||||
version: v1alpha1
|
||||
names:
|
||||
kind: TLSOption
|
||||
plural: tlsoptions
|
||||
singular: tlsoption
|
||||
scope: Namespaced
|
||||
|
|
|
@ -15,3 +15,7 @@ spec:
|
|||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
|
||||
tls:
|
||||
options:
|
||||
name: mytlsoption
|
||||
|
|
12
integration/fixtures/k8s/03-tlsoption.yml
Normal file
12
integration/fixtures/k8s/03-tlsoption.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: mytlsoption
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
snistrict: true
|
||||
ciphersuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
|
@ -12,3 +12,6 @@ spec:
|
|||
services:
|
||||
- name: whoamitcp
|
||||
port: 8080
|
||||
tls:
|
||||
options:
|
||||
name: mytlsoption
|
||||
|
|
|
@ -191,7 +191,7 @@ func (s *HTTPSSuite) TestWithTLSOptions(c *check.C) {
|
|||
c.Assert(err.Error(), checker.Contains, "protocol version not supported")
|
||||
|
||||
// with unknown tls option
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("unknown TLS options: unknown"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("unknown TLS options: unknown@file"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
|
|
31
integration/testdata/rawdata-crd.json
vendored
31
integration/testdata/rawdata-crd.json
vendored
|
@ -6,7 +6,10 @@
|
|||
],
|
||||
"service": "default/test-crd-6b204d94623b3df4370c",
|
||||
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/bar`)",
|
||||
"priority": 12
|
||||
"priority": 12,
|
||||
"tls": {
|
||||
"options": "default/mytlsoption"
|
||||
}
|
||||
},
|
||||
"default/test2-crd-23c7f4c450289ee29016@kubernetescrd": {
|
||||
"entryPoints": [
|
||||
|
@ -36,10 +39,10 @@
|
|||
"loadbalancer": {
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://10.42.0.4:80"
|
||||
"url": "http://10.42.0.2:80"
|
||||
},
|
||||
{
|
||||
"url": "http://10.42.0.5:80"
|
||||
"url": "http://10.42.0.6:80"
|
||||
}
|
||||
],
|
||||
"passHostHeader": true
|
||||
|
@ -48,18 +51,18 @@
|
|||
"default/test-crd-6b204d94623b3df4370c@kubernetescrd"
|
||||
],
|
||||
"serverStatus": {
|
||||
"http://10.42.0.4:80": "UP",
|
||||
"http://10.42.0.5:80": "UP"
|
||||
"http://10.42.0.2:80": "UP",
|
||||
"http://10.42.0.6:80": "UP"
|
||||
}
|
||||
},
|
||||
"default/test2-crd-23c7f4c450289ee29016@kubernetescrd": {
|
||||
"loadbalancer": {
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://10.42.0.4:80"
|
||||
"url": "http://10.42.0.2:80"
|
||||
},
|
||||
{
|
||||
"url": "http://10.42.0.5:80"
|
||||
"url": "http://10.42.0.6:80"
|
||||
}
|
||||
],
|
||||
"passHostHeader": true
|
||||
|
@ -68,8 +71,8 @@
|
|||
"default/test2-crd-23c7f4c450289ee29016@kubernetescrd"
|
||||
],
|
||||
"serverStatus": {
|
||||
"http://10.42.0.4:80": "UP",
|
||||
"http://10.42.0.5:80": "UP"
|
||||
"http://10.42.0.2:80": "UP",
|
||||
"http://10.42.0.6:80": "UP"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -79,7 +82,11 @@
|
|||
"footcp"
|
||||
],
|
||||
"service": "default/test3-crd-673acf455cb2dab0b43a",
|
||||
"rule": "HostSNI(`*`)"
|
||||
"rule": "HostSNI(`*`)",
|
||||
"tls": {
|
||||
"passthrough": false,
|
||||
"options": "default/mytlsoption"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tcpServices": {
|
||||
|
@ -87,10 +94,10 @@
|
|||
"loadbalancer": {
|
||||
"servers": [
|
||||
{
|
||||
"address": "10.42.0.2:8080"
|
||||
"address": "10.42.0.3:8080"
|
||||
},
|
||||
{
|
||||
"address": "10.42.0.3:8080"
|
||||
"address": "10.42.0.4:8080"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -49,6 +49,7 @@ type Client interface {
|
|||
GetIngressRoutes() []*v1alpha1.IngressRoute
|
||||
GetIngressRouteTCPs() []*v1alpha1.IngressRouteTCP
|
||||
GetMiddlewares() []*v1alpha1.Middleware
|
||||
GetTLSOptions() []*v1alpha1.TLSOption
|
||||
|
||||
GetIngresses() []*extensionsv1beta1.Ingress
|
||||
GetService(namespace, name string) (*corev1.Service, bool, error)
|
||||
|
@ -158,6 +159,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
|
|||
factoryCrd.Traefik().V1alpha1().IngressRoutes().Informer().AddEventHandler(eventHandler)
|
||||
factoryCrd.Traefik().V1alpha1().Middlewares().Informer().AddEventHandler(eventHandler)
|
||||
factoryCrd.Traefik().V1alpha1().IngressRouteTCPs().Informer().AddEventHandler(eventHandler)
|
||||
factoryCrd.Traefik().V1alpha1().TLSOptions().Informer().AddEventHandler(eventHandler)
|
||||
|
||||
factoryKube := informers.NewFilteredSharedInformerFactory(c.csKube, resyncPeriod, ns, nil)
|
||||
factoryKube.Extensions().V1beta1().Ingresses().Informer().AddEventHandler(eventHandler)
|
||||
|
@ -241,6 +243,21 @@ func (c *clientWrapper) GetMiddlewares() []*v1alpha1.Middleware {
|
|||
return result
|
||||
}
|
||||
|
||||
// GetTLSOptions
|
||||
func (c *clientWrapper) GetTLSOptions() []*v1alpha1.TLSOption {
|
||||
var result []*v1alpha1.TLSOption
|
||||
|
||||
for ns, factory := range c.factoriesCrd {
|
||||
options, err := factory.Traefik().V1alpha1().TLSOptions().Lister().List(c.labelSelector)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to list tls options in namespace %s: %s", ns, err)
|
||||
}
|
||||
result = append(result, options...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// GetIngresses returns all Ingresses for observed namespaces in the cluster.
|
||||
func (c *clientWrapper) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
var result []*extensionsv1beta1.Ingress
|
||||
|
|
|
@ -37,6 +37,7 @@ type clientMock struct {
|
|||
ingressRoutes []*v1alpha1.IngressRoute
|
||||
ingressRouteTCPs []*v1alpha1.IngressRouteTCP
|
||||
middlewares []*v1alpha1.Middleware
|
||||
tlsOptions []*v1alpha1.TLSOption
|
||||
|
||||
watchChan chan interface{}
|
||||
}
|
||||
|
@ -63,6 +64,8 @@ func newClientMock(paths ...string) clientMock {
|
|||
c.ingressRouteTCPs = append(c.ingressRouteTCPs, o)
|
||||
case *v1alpha1.Middleware:
|
||||
c.middlewares = append(c.middlewares, o)
|
||||
case *v1alpha1.TLSOption:
|
||||
c.tlsOptions = append(c.tlsOptions, o)
|
||||
case *v1beta12.Ingress:
|
||||
c.ingresses = append(c.ingresses, o)
|
||||
case *corev1.Secret:
|
||||
|
@ -88,6 +91,20 @@ func (c clientMock) GetMiddlewares() []*v1alpha1.Middleware {
|
|||
return c.middlewares
|
||||
}
|
||||
|
||||
func (c clientMock) GetTLSOptions() []*v1alpha1.TLSOption {
|
||||
return c.tlsOptions
|
||||
}
|
||||
|
||||
func (c clientMock) GetTLSOption(namespace, name string) (*v1alpha1.TLSOption, bool, error) {
|
||||
for _, option := range c.tlsOptions {
|
||||
if option.Namespace == namespace && option.Name == name {
|
||||
return option, true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
func (c clientMock) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
return c.ingresses
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secretCA1
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secretCA2
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
snistrict: true
|
||||
ciphersuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
clientca:
|
||||
secretnames:
|
||||
- secretCA1
|
||||
- secretUnknown
|
||||
- emptySecret
|
||||
optional: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: supersecret
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: HostSNI(`foo.com`)
|
||||
services:
|
||||
- name: whoamitcp
|
||||
port: 8000
|
||||
|
||||
tls:
|
||||
options:
|
||||
name: foo
|
|
@ -0,0 +1,69 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secretCA1
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secretCA2
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
snistrict: true
|
||||
ciphersuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
clientca:
|
||||
secretnames:
|
||||
- secretCA1
|
||||
- secretCA2
|
||||
optional: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: supersecret
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: HostSNI(`foo.com`)
|
||||
services:
|
||||
- name: whoamitcp
|
||||
port: 8000
|
||||
|
||||
tls:
|
||||
options:
|
||||
name: foo
|
|
@ -0,0 +1,70 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secretCA1
|
||||
namespace: myns
|
||||
|
||||
data:
|
||||
tls.ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secretCA2
|
||||
namespace: myns
|
||||
|
||||
data:
|
||||
tls.ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: myns
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
snistrict: true
|
||||
ciphersuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
clientca:
|
||||
secretnames:
|
||||
- secretCA1
|
||||
- secretCA2
|
||||
optional: true
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: supersecret
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: HostSNI(`foo.com`)
|
||||
services:
|
||||
- name: whoamitcp
|
||||
port: 8000
|
||||
|
||||
tls:
|
||||
options:
|
||||
name: foo
|
||||
namespace: myns
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: HostSNI(`foo.com`)
|
||||
services:
|
||||
- name: whoamitcp
|
||||
port: 8000
|
||||
|
||||
tls:
|
||||
options:
|
||||
name: unknown
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: HostSNI(`foo.com`)
|
||||
services:
|
||||
- name: whoamitcp
|
||||
port: 8000
|
||||
|
||||
tls:
|
||||
options:
|
||||
name: foo
|
||||
namespace: unknown
|
|
@ -0,0 +1,61 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secretCA1
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: badSecret
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.ca:
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
snistrict: true
|
||||
ciphersuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
clientca:
|
||||
secretnames:
|
||||
- secretCA1
|
||||
- secretUnknown
|
||||
- emptySecret
|
||||
optional: true
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
|
||||
tls:
|
||||
options:
|
||||
name: foo
|
60
pkg/provider/kubernetes/crd/fixtures/with_tls_options.yml
Normal file
60
pkg/provider/kubernetes/crd/fixtures/with_tls_options.yml
Normal file
|
@ -0,0 +1,60 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secretCA1
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secretCA2
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
snistrict: true
|
||||
ciphersuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
clientca:
|
||||
secretnames:
|
||||
- secretCA1
|
||||
- secretCA2
|
||||
optional: true
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
|
||||
tls:
|
||||
options:
|
||||
name: foo
|
|
@ -0,0 +1,61 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secretCA1
|
||||
namespace: myns
|
||||
|
||||
data:
|
||||
tls.ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secretCA2
|
||||
namespace: myns
|
||||
|
||||
data:
|
||||
tls.ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: myns
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
snistrict: true
|
||||
ciphersuites:
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
clientca:
|
||||
secretnames:
|
||||
- secretCA1
|
||||
- secretCA2
|
||||
optional: true
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
|
||||
tls:
|
||||
options:
|
||||
name: foo
|
||||
namespace: myns
|
|
@ -0,0 +1,31 @@
|
|||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
|
||||
tls:
|
||||
options:
|
||||
name: unknown
|
|
@ -0,0 +1,32 @@
|
|||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: TLSOption
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
minversion: VersionTLS12
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
|
||||
tls:
|
||||
options:
|
||||
name: foo
|
||||
namespace: unknown
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1alpha1 "github.com/containous/traefik/pkg/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeTLSOptions implements TLSOptionInterface
|
||||
type FakeTLSOptions struct {
|
||||
Fake *FakeTraefikV1alpha1
|
||||
ns string
|
||||
}
|
||||
|
||||
var tlsoptionsResource = schema.GroupVersionResource{Group: "traefik.containo.us", Version: "v1alpha1", Resource: "tlsoptions"}
|
||||
|
||||
var tlsoptionsKind = schema.GroupVersionKind{Group: "traefik.containo.us", Version: "v1alpha1", Kind: "TLSOption"}
|
||||
|
||||
// Get takes name of the tLSOption, and returns the corresponding tLSOption object, and an error if there is any.
|
||||
func (c *FakeTLSOptions) Get(name string, options v1.GetOptions) (result *v1alpha1.TLSOption, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(tlsoptionsResource, c.ns, name), &v1alpha1.TLSOption{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.TLSOption), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of TLSOptions that match those selectors.
|
||||
func (c *FakeTLSOptions) List(opts v1.ListOptions) (result *v1alpha1.TLSOptionList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(tlsoptionsResource, tlsoptionsKind, c.ns, opts), &v1alpha1.TLSOptionList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.TLSOptionList{ListMeta: obj.(*v1alpha1.TLSOptionList).ListMeta}
|
||||
for _, item := range obj.(*v1alpha1.TLSOptionList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested tLSOptions.
|
||||
func (c *FakeTLSOptions) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(tlsoptionsResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a tLSOption and creates it. Returns the server's representation of the tLSOption, and an error, if there is any.
|
||||
func (c *FakeTLSOptions) Create(tLSOption *v1alpha1.TLSOption) (result *v1alpha1.TLSOption, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(tlsoptionsResource, c.ns, tLSOption), &v1alpha1.TLSOption{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.TLSOption), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a tLSOption and updates it. Returns the server's representation of the tLSOption, and an error, if there is any.
|
||||
func (c *FakeTLSOptions) Update(tLSOption *v1alpha1.TLSOption) (result *v1alpha1.TLSOption, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(tlsoptionsResource, c.ns, tLSOption), &v1alpha1.TLSOption{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.TLSOption), err
|
||||
}
|
||||
|
||||
// Delete takes name of the tLSOption and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeTLSOptions) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(tlsoptionsResource, c.ns, name), &v1alpha1.TLSOption{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeTLSOptions) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(tlsoptionsResource, c.ns, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha1.TLSOptionList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched tLSOption.
|
||||
func (c *FakeTLSOptions) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.TLSOption, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(tlsoptionsResource, c.ns, name, data, subresources...), &v1alpha1.TLSOption{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.TLSOption), err
|
||||
}
|
|
@ -48,6 +48,10 @@ func (c *FakeTraefikV1alpha1) Middlewares(namespace string) v1alpha1.MiddlewareI
|
|||
return &FakeMiddlewares{c, namespace}
|
||||
}
|
||||
|
||||
func (c *FakeTraefikV1alpha1) TLSOptions(namespace string) v1alpha1.TLSOptionInterface {
|
||||
return &FakeTLSOptions{c, namespace}
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *FakeTraefikV1alpha1) RESTClient() rest.Interface {
|
||||
|
|
|
@ -31,3 +31,5 @@ type IngressRouteExpansion interface{}
|
|||
type IngressRouteTCPExpansion interface{}
|
||||
|
||||
type MiddlewareExpansion interface{}
|
||||
|
||||
type TLSOptionExpansion interface{}
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
scheme "github.com/containous/traefik/pkg/provider/kubernetes/crd/generated/clientset/versioned/scheme"
|
||||
v1alpha1 "github.com/containous/traefik/pkg/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// TLSOptionsGetter has a method to return a TLSOptionInterface.
|
||||
// A group's client should implement this interface.
|
||||
type TLSOptionsGetter interface {
|
||||
TLSOptions(namespace string) TLSOptionInterface
|
||||
}
|
||||
|
||||
// TLSOptionInterface has methods to work with TLSOption resources.
|
||||
type TLSOptionInterface interface {
|
||||
Create(*v1alpha1.TLSOption) (*v1alpha1.TLSOption, error)
|
||||
Update(*v1alpha1.TLSOption) (*v1alpha1.TLSOption, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1alpha1.TLSOption, error)
|
||||
List(opts v1.ListOptions) (*v1alpha1.TLSOptionList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.TLSOption, err error)
|
||||
TLSOptionExpansion
|
||||
}
|
||||
|
||||
// tLSOptions implements TLSOptionInterface
|
||||
type tLSOptions struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newTLSOptions returns a TLSOptions
|
||||
func newTLSOptions(c *TraefikV1alpha1Client, namespace string) *tLSOptions {
|
||||
return &tLSOptions{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the tLSOption, and returns the corresponding tLSOption object, and an error if there is any.
|
||||
func (c *tLSOptions) Get(name string, options v1.GetOptions) (result *v1alpha1.TLSOption, err error) {
|
||||
result = &v1alpha1.TLSOption{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("tlsoptions").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of TLSOptions that match those selectors.
|
||||
func (c *tLSOptions) List(opts v1.ListOptions) (result *v1alpha1.TLSOptionList, err error) {
|
||||
result = &v1alpha1.TLSOptionList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("tlsoptions").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested tLSOptions.
|
||||
func (c *tLSOptions) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("tlsoptions").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a tLSOption and creates it. Returns the server's representation of the tLSOption, and an error, if there is any.
|
||||
func (c *tLSOptions) Create(tLSOption *v1alpha1.TLSOption) (result *v1alpha1.TLSOption, err error) {
|
||||
result = &v1alpha1.TLSOption{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("tlsoptions").
|
||||
Body(tLSOption).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a tLSOption and updates it. Returns the server's representation of the tLSOption, and an error, if there is any.
|
||||
func (c *tLSOptions) Update(tLSOption *v1alpha1.TLSOption) (result *v1alpha1.TLSOption, err error) {
|
||||
result = &v1alpha1.TLSOption{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("tlsoptions").
|
||||
Name(tLSOption.Name).
|
||||
Body(tLSOption).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the tLSOption and deletes it. Returns an error if one occurs.
|
||||
func (c *tLSOptions) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("tlsoptions").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *tLSOptions) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("tlsoptions").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched tLSOption.
|
||||
func (c *tLSOptions) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.TLSOption, err error) {
|
||||
result = &v1alpha1.TLSOption{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("tlsoptions").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
|
@ -38,6 +38,7 @@ type TraefikV1alpha1Interface interface {
|
|||
IngressRoutesGetter
|
||||
IngressRouteTCPsGetter
|
||||
MiddlewaresGetter
|
||||
TLSOptionsGetter
|
||||
}
|
||||
|
||||
// TraefikV1alpha1Client is used to interact with features provided by the traefik.containo.us group.
|
||||
|
@ -57,6 +58,10 @@ func (c *TraefikV1alpha1Client) Middlewares(namespace string) MiddlewareInterfac
|
|||
return newMiddlewares(c, namespace)
|
||||
}
|
||||
|
||||
func (c *TraefikV1alpha1Client) TLSOptions(namespace string) TLSOptionInterface {
|
||||
return newTLSOptions(c, namespace)
|
||||
}
|
||||
|
||||
// NewForConfig creates a new TraefikV1alpha1Client for the given config.
|
||||
func NewForConfig(c *rest.Config) (*TraefikV1alpha1Client, error) {
|
||||
config := *c
|
||||
|
|
|
@ -67,6 +67,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
|
|||
return &genericInformer{resource: resource.GroupResource(), informer: f.Traefik().V1alpha1().IngressRouteTCPs().Informer()}, nil
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("middlewares"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Traefik().V1alpha1().Middlewares().Informer()}, nil
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("tlsoptions"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Traefik().V1alpha1().TLSOptions().Informer()}, nil
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ type Interface interface {
|
|||
IngressRouteTCPs() IngressRouteTCPInformer
|
||||
// Middlewares returns a MiddlewareInformer.
|
||||
Middlewares() MiddlewareInformer
|
||||
// TLSOptions returns a TLSOptionInformer.
|
||||
TLSOptions() TLSOptionInformer
|
||||
}
|
||||
|
||||
type version struct {
|
||||
|
@ -65,3 +67,8 @@ func (v *version) IngressRouteTCPs() IngressRouteTCPInformer {
|
|||
func (v *version) Middlewares() MiddlewareInformer {
|
||||
return &middlewareInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// TLSOptions returns a TLSOptionInformer.
|
||||
func (v *version) TLSOptions() TLSOptionInformer {
|
||||
return &tLSOptionInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
versioned "github.com/containous/traefik/pkg/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
internalinterfaces "github.com/containous/traefik/pkg/provider/kubernetes/crd/generated/informers/externalversions/internalinterfaces"
|
||||
v1alpha1 "github.com/containous/traefik/pkg/provider/kubernetes/crd/generated/listers/traefik/v1alpha1"
|
||||
traefikv1alpha1 "github.com/containous/traefik/pkg/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// TLSOptionInformer provides access to a shared informer and lister for
|
||||
// TLSOptions.
|
||||
type TLSOptionInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha1.TLSOptionLister
|
||||
}
|
||||
|
||||
type tLSOptionInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewTLSOptionInformer constructs a new informer for TLSOption type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewTLSOptionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredTLSOptionInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredTLSOptionInformer constructs a new informer for TLSOption type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredTLSOptionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.TraefikV1alpha1().TLSOptions(namespace).List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.TraefikV1alpha1().TLSOptions(namespace).Watch(options)
|
||||
},
|
||||
},
|
||||
&traefikv1alpha1.TLSOption{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *tLSOptionInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredTLSOptionInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *tLSOptionInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&traefikv1alpha1.TLSOption{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *tLSOptionInformer) Lister() v1alpha1.TLSOptionLister {
|
||||
return v1alpha1.NewTLSOptionLister(f.Informer().GetIndexer())
|
||||
}
|
|
@ -49,3 +49,11 @@ type MiddlewareListerExpansion interface{}
|
|||
// MiddlewareNamespaceListerExpansion allows custom methods to be added to
|
||||
// MiddlewareNamespaceLister.
|
||||
type MiddlewareNamespaceListerExpansion interface{}
|
||||
|
||||
// TLSOptionListerExpansion allows custom methods to be added to
|
||||
// TLSOptionLister.
|
||||
type TLSOptionListerExpansion interface{}
|
||||
|
||||
// TLSOptionNamespaceListerExpansion allows custom methods to be added to
|
||||
// TLSOptionNamespaceLister.
|
||||
type TLSOptionNamespaceListerExpansion interface{}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1alpha1 "github.com/containous/traefik/pkg/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// TLSOptionLister helps list TLSOptions.
|
||||
type TLSOptionLister interface {
|
||||
// List lists all TLSOptions in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.TLSOption, err error)
|
||||
// TLSOptions returns an object that can list and get TLSOptions.
|
||||
TLSOptions(namespace string) TLSOptionNamespaceLister
|
||||
TLSOptionListerExpansion
|
||||
}
|
||||
|
||||
// tLSOptionLister implements the TLSOptionLister interface.
|
||||
type tLSOptionLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewTLSOptionLister returns a new TLSOptionLister.
|
||||
func NewTLSOptionLister(indexer cache.Indexer) TLSOptionLister {
|
||||
return &tLSOptionLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all TLSOptions in the indexer.
|
||||
func (s *tLSOptionLister) List(selector labels.Selector) (ret []*v1alpha1.TLSOption, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.TLSOption))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// TLSOptions returns an object that can list and get TLSOptions.
|
||||
func (s *tLSOptionLister) TLSOptions(namespace string) TLSOptionNamespaceLister {
|
||||
return tLSOptionNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// TLSOptionNamespaceLister helps list and get TLSOptions.
|
||||
type TLSOptionNamespaceLister interface {
|
||||
// List lists all TLSOptions in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.TLSOption, err error)
|
||||
// Get retrieves the TLSOption from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1alpha1.TLSOption, error)
|
||||
TLSOptionNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// tLSOptionNamespaceLister implements the TLSOptionNamespaceLister
|
||||
// interface.
|
||||
type tLSOptionNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all TLSOptions in the indexer for a given namespace.
|
||||
func (s tLSOptionNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.TLSOption, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.TLSOption))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the TLSOption from the indexer for a given namespace and name.
|
||||
func (s tLSOptionNamespaceLister) Get(name string) (*v1alpha1.TLSOption, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha1.Resource("tlsoption"), name)
|
||||
}
|
||||
return obj.(*v1alpha1.TLSOption), nil
|
||||
}
|
|
@ -118,7 +118,7 @@ func (p *Provider) Provide(configurationChan chan<- config.Message, pool *safe.P
|
|||
case <-stop:
|
||||
return nil
|
||||
case event := <-eventsChan:
|
||||
conf := p.loadConfigurationFromIngresses(ctxLog, k8sClient)
|
||||
conf := p.loadConfigurationFromCRD(ctxLog, k8sClient)
|
||||
|
||||
if reflect.DeepEqual(p.lastConfiguration.Get(), conf) {
|
||||
logger.Debugf("Skipping Kubernetes event kind %T", event)
|
||||
|
@ -293,19 +293,59 @@ func loadServers(client Client, namespace string, svc v1alpha1.Service) ([]confi
|
|||
return servers, nil
|
||||
}
|
||||
|
||||
func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Client) *config.Configuration {
|
||||
conf := &config.Configuration{
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{},
|
||||
Services: map[string]*config.TCPService{},
|
||||
},
|
||||
func buildTLSOptions(ctx context.Context, client Client) map[string]tls.TLS {
|
||||
tlsOptionsCRD := client.GetTLSOptions()
|
||||
var tlsOptions map[string]tls.TLS
|
||||
|
||||
if len(tlsOptionsCRD) == 0 {
|
||||
return tlsOptions
|
||||
}
|
||||
tlsOptions = make(map[string]tls.TLS)
|
||||
|
||||
for _, tlsOption := range tlsOptionsCRD {
|
||||
logger := log.FromContext(log.With(ctx, log.Str("tlsOption", tlsOption.Name), log.Str("namespace", tlsOption.Namespace)))
|
||||
var clientCAs []tls.FileOrContent
|
||||
|
||||
for _, secretName := range tlsOption.Spec.ClientCA.SecretNames {
|
||||
secret, exists, err := client.GetSecret(tlsOption.Namespace, secretName)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to fetch secret %s/%s: %v", tlsOption.Namespace, secretName, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !exists {
|
||||
logger.Warnf("Secret %s/%s does not exist", tlsOption.Namespace, secretName)
|
||||
continue
|
||||
}
|
||||
|
||||
cert, err := getCABlocks(secret, tlsOption.Namespace, secretName)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to extract CA from secret %s/%s: %v", tlsOption.Namespace, secretName, err)
|
||||
continue
|
||||
}
|
||||
|
||||
clientCAs = append(clientCAs, tls.FileOrContent(cert))
|
||||
}
|
||||
|
||||
tlsOptions[makeID(tlsOption.Namespace, tlsOption.Name)] = tls.TLS{
|
||||
MinVersion: tlsOption.Spec.MinVersion,
|
||||
CipherSuites: tlsOption.Spec.CipherSuites,
|
||||
ClientCA: tls.ClientCA{
|
||||
Files: clientCAs,
|
||||
Optional: tlsOption.Spec.ClientCA.Optional,
|
||||
},
|
||||
SniStrict: tlsOption.Spec.SniStrict,
|
||||
}
|
||||
}
|
||||
return tlsOptions
|
||||
}
|
||||
|
||||
func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Client, tlsConfigs map[string]*tls.Configuration) *config.HTTPConfiguration {
|
||||
conf := &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
}
|
||||
tlsConfigs := make(map[string]*tls.Configuration)
|
||||
|
||||
for _, ingressRoute := range client.GetIngressRoutes() {
|
||||
logger := log.FromContext(log.With(ctx, log.Str("ingress", ingressRoute.Name), log.Str("namespace", ingressRoute.Namespace)))
|
||||
|
@ -377,17 +417,33 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
|
|||
|
||||
serviceName := makeID(ingressRoute.Namespace, key)
|
||||
|
||||
conf.HTTP.Routers[serviceName] = &config.Router{
|
||||
conf.Routers[serviceName] = &config.Router{
|
||||
Middlewares: mds,
|
||||
Priority: route.Priority,
|
||||
EntryPoints: ingressRoute.Spec.EntryPoints,
|
||||
Rule: route.Match,
|
||||
Service: serviceName,
|
||||
}
|
||||
|
||||
if ingressRoute.Spec.TLS != nil {
|
||||
conf.HTTP.Routers[serviceName].TLS = &config.RouterTLSConfig{}
|
||||
tlsConf := &config.RouterTLSConfig{}
|
||||
if ingressRoute.Spec.TLS.Options != nil && len(ingressRoute.Spec.TLS.Options.Name) > 0 {
|
||||
tlsOptionsName := ingressRoute.Spec.TLS.Options.Name
|
||||
// Is a Kubernetes CRD reference, (i.e. not a cross-provider default)
|
||||
if !strings.Contains(tlsOptionsName, "@") {
|
||||
ns := ingressRoute.Spec.TLS.Options.Namespace
|
||||
if len(ns) == 0 {
|
||||
ns = ingressRoute.Namespace
|
||||
}
|
||||
tlsOptionsName = makeID(ns, tlsOptionsName)
|
||||
}
|
||||
|
||||
tlsConf.Options = tlsOptionsName
|
||||
}
|
||||
conf.Routers[serviceName].TLS = tlsConf
|
||||
}
|
||||
conf.HTTP.Services[serviceName] = &config.Service{
|
||||
|
||||
conf.Services[serviceName] = &config.Service{
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: allServers,
|
||||
// TODO: support other strategies.
|
||||
|
@ -397,8 +453,13 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
|
|||
}
|
||||
}
|
||||
|
||||
for _, middleware := range client.GetMiddlewares() {
|
||||
conf.HTTP.Middlewares[makeID(middleware.Namespace, middleware.Name)] = &middleware.Spec
|
||||
return conf
|
||||
}
|
||||
|
||||
func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client Client, tlsConfigs map[string]*tls.Configuration) *config.TCPConfiguration {
|
||||
conf := &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{},
|
||||
Services: map[string]*config.TCPService{},
|
||||
}
|
||||
|
||||
for _, ingressRouteTCP := range client.GetIngressRouteTCPs() {
|
||||
|
@ -452,19 +513,34 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
|
|||
}
|
||||
|
||||
serviceName := makeID(ingressRouteTCP.Namespace, key)
|
||||
conf.TCP.Routers[serviceName] = &config.TCPRouter{
|
||||
conf.Routers[serviceName] = &config.TCPRouter{
|
||||
EntryPoints: ingressRouteTCP.Spec.EntryPoints,
|
||||
Rule: route.Match,
|
||||
Service: serviceName,
|
||||
}
|
||||
|
||||
if ingressRouteTCP.Spec.TLS != nil {
|
||||
conf.TCP.Routers[serviceName].TLS = &config.RouterTCPTLSConfig{
|
||||
conf.Routers[serviceName].TLS = &config.RouterTCPTLSConfig{
|
||||
Passthrough: ingressRouteTCP.Spec.TLS.Passthrough,
|
||||
}
|
||||
|
||||
if ingressRouteTCP.Spec.TLS.Options != nil && len(ingressRouteTCP.Spec.TLS.Options.Name) > 0 {
|
||||
tlsOptionsName := ingressRouteTCP.Spec.TLS.Options.Name
|
||||
// Is a Kubernetes CRD reference (i.e. not a cross-provider reference)
|
||||
if !strings.Contains(tlsOptionsName, "@") {
|
||||
ns := ingressRouteTCP.Spec.TLS.Options.Namespace
|
||||
if len(ns) == 0 {
|
||||
ns = ingressRouteTCP.Namespace
|
||||
}
|
||||
tlsOptionsName = makeID(ns, tlsOptionsName)
|
||||
}
|
||||
|
||||
conf.Routers[serviceName].TLS.Options = tlsOptionsName
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
conf.TCP.Services[serviceName] = &config.TCPService{
|
||||
conf.Services[serviceName] = &config.TCPService{
|
||||
LoadBalancer: &config.TCPLoadBalancerService{
|
||||
Servers: allServers,
|
||||
},
|
||||
|
@ -472,7 +548,21 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
|
|||
}
|
||||
}
|
||||
|
||||
conf.TLS = getTLSConfig(tlsConfigs)
|
||||
return conf
|
||||
}
|
||||
|
||||
func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client) *config.Configuration {
|
||||
tlsConfigs := make(map[string]*tls.Configuration)
|
||||
conf := &config.Configuration{
|
||||
HTTP: p.loadIngressRouteConfiguration(ctx, client, tlsConfigs),
|
||||
TCP: p.loadIngressRouteTCPConfiguration(ctx, client, tlsConfigs),
|
||||
TLSOptions: buildTLSOptions(ctx, client),
|
||||
TLS: getTLSConfig(tlsConfigs),
|
||||
}
|
||||
|
||||
for _, middleware := range client.GetMiddlewares() {
|
||||
conf.HTTP.Middlewares[makeID(middleware.Namespace, middleware.Name)] = &middleware.Spec
|
||||
}
|
||||
|
||||
return conf
|
||||
}
|
||||
|
@ -618,3 +708,19 @@ func getCertificateBlocks(secret *corev1.Secret, namespace, secretName string) (
|
|||
|
||||
return cert, key, nil
|
||||
}
|
||||
|
||||
func getCABlocks(secret *corev1.Secret, namespace, secretName string) (string, error) {
|
||||
tlsCrtData, tlsCrtExists := secret.Data["tls.ca"]
|
||||
if !tlsCrtExists {
|
||||
return "", fmt.Errorf("the tls.ca entry is missing from secret %s/%s",
|
||||
namespace, secretName)
|
||||
}
|
||||
|
||||
cert := string(tlsCrtData)
|
||||
if cert == "" {
|
||||
return "", fmt.Errorf("the tls.ca entry in secret %s/%s is empty",
|
||||
namespace, secretName)
|
||||
}
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
|
|
|
@ -297,6 +297,261 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS with tls options",
|
||||
paths: []string{"tcp/services.yml", "tcp/with_tls_options.yml"},
|
||||
expected: &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"default/foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
CipherSuites: []string{
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
},
|
||||
ClientCA: tls.ClientCA{
|
||||
Files: []tls.FileOrContent{
|
||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
SniStrict: true,
|
||||
},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{
|
||||
"default/test-crd-fdd3e9338e47a45efefc": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "default/test-crd-fdd3e9338e47a45efefc",
|
||||
Rule: "HostSNI(`foo.com`)",
|
||||
TLS: &config.RouterTCPTLSConfig{
|
||||
Options: "default/foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*config.TCPService{
|
||||
"default/test-crd-fdd3e9338e47a45efefc": {
|
||||
LoadBalancer: &config.TCPLoadBalancerService{
|
||||
Servers: []config.TCPServer{
|
||||
{
|
||||
Address: "10.10.0.1:8000",
|
||||
Port: "",
|
||||
},
|
||||
{
|
||||
Address: "10.10.0.2:8000",
|
||||
Port: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS with tls options and specific namespace",
|
||||
paths: []string{"tcp/services.yml", "tcp/with_tls_options_and_specific_namespace.yml"},
|
||||
expected: &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"myns/foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
CipherSuites: []string{
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
},
|
||||
ClientCA: tls.ClientCA{
|
||||
Files: []tls.FileOrContent{
|
||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
SniStrict: true,
|
||||
},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{
|
||||
"default/test-crd-fdd3e9338e47a45efefc": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "default/test-crd-fdd3e9338e47a45efefc",
|
||||
Rule: "HostSNI(`foo.com`)",
|
||||
TLS: &config.RouterTCPTLSConfig{
|
||||
Options: "myns/foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*config.TCPService{
|
||||
"default/test-crd-fdd3e9338e47a45efefc": {
|
||||
LoadBalancer: &config.TCPLoadBalancerService{
|
||||
Servers: []config.TCPServer{
|
||||
{
|
||||
Address: "10.10.0.1:8000",
|
||||
Port: "",
|
||||
},
|
||||
{
|
||||
Address: "10.10.0.2:8000",
|
||||
Port: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS with bad tls options",
|
||||
paths: []string{"tcp/services.yml", "tcp/with_bad_tls_options.yml"},
|
||||
expected: &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"default/foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
CipherSuites: []string{
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
},
|
||||
ClientCA: tls.ClientCA{
|
||||
Files: []tls.FileOrContent{
|
||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
SniStrict: true,
|
||||
},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{
|
||||
"default/test-crd-fdd3e9338e47a45efefc": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "default/test-crd-fdd3e9338e47a45efefc",
|
||||
Rule: "HostSNI(`foo.com`)",
|
||||
TLS: &config.RouterTCPTLSConfig{
|
||||
Options: "default/foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*config.TCPService{
|
||||
"default/test-crd-fdd3e9338e47a45efefc": {
|
||||
LoadBalancer: &config.TCPLoadBalancerService{
|
||||
Servers: []config.TCPServer{
|
||||
{
|
||||
Address: "10.10.0.1:8000",
|
||||
Port: "",
|
||||
},
|
||||
{
|
||||
Address: "10.10.0.2:8000",
|
||||
Port: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS with unknown tls options",
|
||||
paths: []string{"tcp/services.yml", "tcp/with_unknown_tls_options.yml"},
|
||||
expected: &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"default/foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{
|
||||
"default/test-crd-fdd3e9338e47a45efefc": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "default/test-crd-fdd3e9338e47a45efefc",
|
||||
Rule: "HostSNI(`foo.com`)",
|
||||
TLS: &config.RouterTCPTLSConfig{
|
||||
Options: "default/unknown",
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*config.TCPService{
|
||||
"default/test-crd-fdd3e9338e47a45efefc": {
|
||||
LoadBalancer: &config.TCPLoadBalancerService{
|
||||
Servers: []config.TCPServer{
|
||||
{
|
||||
Address: "10.10.0.1:8000",
|
||||
Port: "",
|
||||
},
|
||||
{
|
||||
Address: "10.10.0.2:8000",
|
||||
Port: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS with unknown tls options namespace",
|
||||
paths: []string{"tcp/services.yml", "tcp/with_unknown_tls_options_namespace.yml"},
|
||||
expected: &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"default/foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{
|
||||
"default/test-crd-fdd3e9338e47a45efefc": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "default/test-crd-fdd3e9338e47a45efefc",
|
||||
Rule: "HostSNI(`foo.com`)",
|
||||
TLS: &config.RouterTCPTLSConfig{
|
||||
Options: "unknown/foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*config.TCPService{
|
||||
"default/test-crd-fdd3e9338e47a45efefc": {
|
||||
LoadBalancer: &config.TCPLoadBalancerService{
|
||||
Servers: []config.TCPServer{
|
||||
{
|
||||
Address: "10.10.0.1:8000",
|
||||
Port: "",
|
||||
},
|
||||
{
|
||||
Address: "10.10.0.2:8000",
|
||||
Port: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS with ACME",
|
||||
paths: []string{"tcp/services.yml", "tcp/with_tls_acme.yml"},
|
||||
|
@ -338,6 +593,7 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
|||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -346,7 +602,7 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
|||
}
|
||||
|
||||
p := Provider{IngressClass: test.ingressClass}
|
||||
conf := p.loadConfigurationFromIngresses(context.Background(), newClientMock(test.paths...))
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), newClientMock(test.paths...))
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
@ -660,6 +916,261 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS with tls options",
|
||||
paths: []string{"services.yml", "with_tls_options.yml"},
|
||||
expected: &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"default/foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
CipherSuites: []string{
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
},
|
||||
ClientCA: tls.ClientCA{
|
||||
Files: []tls.FileOrContent{
|
||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
SniStrict: true,
|
||||
},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{},
|
||||
Services: map[string]*config.TCPService{},
|
||||
},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test-crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test-crd-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
TLS: &config.RouterTLSConfig{
|
||||
Options: "default/foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test-crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS with tls options and specific namespace",
|
||||
paths: []string{"services.yml", "with_tls_options_and_specific_namespace.yml"},
|
||||
expected: &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"myns/foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
CipherSuites: []string{
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
},
|
||||
ClientCA: tls.ClientCA{
|
||||
Files: []tls.FileOrContent{
|
||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
SniStrict: true,
|
||||
},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{},
|
||||
Services: map[string]*config.TCPService{},
|
||||
},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test-crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test-crd-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
TLS: &config.RouterTLSConfig{
|
||||
Options: "myns/foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test-crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS with bad tls options",
|
||||
paths: []string{"services.yml", "with_bad_tls_options.yml"},
|
||||
expected: &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"default/foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
CipherSuites: []string{
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
},
|
||||
ClientCA: tls.ClientCA{
|
||||
Files: []tls.FileOrContent{
|
||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
SniStrict: true,
|
||||
},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{},
|
||||
Services: map[string]*config.TCPService{},
|
||||
},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test-crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test-crd-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
TLS: &config.RouterTLSConfig{
|
||||
Options: "default/foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test-crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS with unknown tls options",
|
||||
paths: []string{"services.yml", "with_unknown_tls_options.yml"},
|
||||
expected: &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"default/foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{},
|
||||
Services: map[string]*config.TCPService{},
|
||||
},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test-crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test-crd-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
TLS: &config.RouterTLSConfig{
|
||||
Options: "default/unknown",
|
||||
},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test-crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS with unknown tls options namespace",
|
||||
paths: []string{"services.yml", "with_unknown_tls_options_namespace.yml"},
|
||||
expected: &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"default/foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{
|
||||
Routers: map[string]*config.TCPRouter{},
|
||||
Services: map[string]*config.TCPService{},
|
||||
},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test-crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test-crd-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
TLS: &config.RouterTLSConfig{
|
||||
Options: "unknown/foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test-crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS with ACME",
|
||||
paths: []string{"services.yml", "with_tls_acme.yml"},
|
||||
|
@ -740,6 +1251,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -748,7 +1260,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
}
|
||||
|
||||
p := Provider{IngressClass: test.ingressClass}
|
||||
conf := p.loadConfigurationFromIngresses(context.Background(), newClientMock(test.paths...))
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), newClientMock(test.paths...))
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -31,7 +31,14 @@ type TLS struct {
|
|||
// SecretName is the name of the referenced Kubernetes Secret to specify the
|
||||
// certificate details.
|
||||
SecretName string `json:"secretName"`
|
||||
// TODO MinimumProtocolVersion string `json:"minimumProtocolVersion,omitempty"`
|
||||
// Options is a reference to a TLSOption, that specifies the parameters of the TLS connection.
|
||||
Options *TLSOptionRef `json:"options"`
|
||||
}
|
||||
|
||||
// TLSOptionRef is a ref to the TLSOption resources.
|
||||
type TLSOptionRef struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
// Service defines an upstream to proxy traffic.
|
||||
|
|
|
@ -29,6 +29,14 @@ type TLSTCP struct {
|
|||
// certificate details.
|
||||
SecretName string `json:"secretName"`
|
||||
Passthrough bool `json:"passthrough"`
|
||||
// Options is a reference to a TLSOption, that specifies the parameters of the TLS connection.
|
||||
Options *TLSOptionTCPRef `json:"options"`
|
||||
}
|
||||
|
||||
// TLSOptionTCPRef is a ref to the TLSOption resources.
|
||||
type TLSOptionTCPRef struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
// ServiceTCP defines an upstream to proxy traffic.
|
||||
|
|
|
@ -39,6 +39,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
|||
&IngressRouteTCPList{},
|
||||
&Middleware{},
|
||||
&MiddlewareList{},
|
||||
&TLSOption{},
|
||||
&TLSOptionList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
|
|
48
pkg/provider/kubernetes/crd/traefik/v1alpha1/tlsoption.go
Normal file
48
pkg/provider/kubernetes/crd/traefik/v1alpha1/tlsoption.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// TLSOption is a specification for a TLSOption resource.
|
||||
type TLSOption struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata"`
|
||||
|
||||
Spec TLSOptionSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// TLSOptionSpec configures TLS for an entry point
|
||||
type TLSOptionSpec struct {
|
||||
MinVersion string `json:"minversion"`
|
||||
CipherSuites []string `json:"ciphersuites"`
|
||||
ClientCA ClientCA `json:"clientca"`
|
||||
SniStrict bool `json:"snistrict"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// ClientCA defines traefik CA files for an entryPoint
|
||||
// and it indicates if they are mandatory or have just to be analyzed if provided
|
||||
type ClientCA struct {
|
||||
// SecretName is the name of the referenced Kubernetes Secret to specify the
|
||||
// certificate details.
|
||||
SecretNames []string `json:"secretnames"`
|
||||
// Optional indicates if ClientCA are mandatory or have just to be analyzed if provided
|
||||
Optional bool `json:"optional"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// TLSOptionList is a list of TLSOption resources.
|
||||
type TLSOptionList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
|
||||
Items []TLSOption `json:"items"`
|
||||
}
|
|
@ -32,6 +32,27 @@ import (
|
|||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClientCA) DeepCopyInto(out *ClientCA) {
|
||||
*out = *in
|
||||
if in.SecretNames != nil {
|
||||
in, out := &in.SecretNames, &out.SecretNames
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientCA.
|
||||
func (in *ClientCA) DeepCopy() *ClientCA {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClientCA)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HealthCheck) DeepCopyInto(out *HealthCheck) {
|
||||
*out = *in
|
||||
|
@ -133,7 +154,7 @@ func (in *IngressRouteSpec) DeepCopyInto(out *IngressRouteSpec) {
|
|||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLS)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -226,7 +247,7 @@ func (in *IngressRouteTCPSpec) DeepCopyInto(out *IngressRouteTCPSpec) {
|
|||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSTCP)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -406,6 +427,11 @@ func (in *ServiceTCP) DeepCopy() *ServiceTCP {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLS) DeepCopyInto(out *TLS) {
|
||||
*out = *in
|
||||
if in.Options != nil {
|
||||
in, out := &in.Options, &out.Options
|
||||
*out = new(TLSOptionRef)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -419,9 +445,128 @@ func (in *TLS) DeepCopy() *TLS {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSOption) DeepCopyInto(out *TLSOption) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSOption.
|
||||
func (in *TLSOption) DeepCopy() *TLSOption {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TLSOption)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *TLSOption) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSOptionList) DeepCopyInto(out *TLSOptionList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]TLSOption, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSOptionList.
|
||||
func (in *TLSOptionList) DeepCopy() *TLSOptionList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TLSOptionList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *TLSOptionList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSOptionRef) DeepCopyInto(out *TLSOptionRef) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSOptionRef.
|
||||
func (in *TLSOptionRef) DeepCopy() *TLSOptionRef {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TLSOptionRef)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSOptionSpec) DeepCopyInto(out *TLSOptionSpec) {
|
||||
*out = *in
|
||||
if in.CipherSuites != nil {
|
||||
in, out := &in.CipherSuites, &out.CipherSuites
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
in.ClientCA.DeepCopyInto(&out.ClientCA)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSOptionSpec.
|
||||
func (in *TLSOptionSpec) DeepCopy() *TLSOptionSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TLSOptionSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSOptionTCPRef) DeepCopyInto(out *TLSOptionTCPRef) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSOptionTCPRef.
|
||||
func (in *TLSOptionTCPRef) DeepCopy() *TLSOptionTCPRef {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TLSOptionTCPRef)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSTCP) DeepCopyInto(out *TLSTCP) {
|
||||
*out = *in
|
||||
if in.Options != nil {
|
||||
in, out := &in.Options, &out.Options
|
||||
*out = new(TLSOptionTCPRef)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
// MustParseYaml parses a YAML to objects.
|
||||
func MustParseYaml(content []byte) []runtime.Object {
|
||||
acceptedK8sTypes := regexp.MustCompile(`(Deployment|Endpoints|Service|Ingress|IngressRoute|Middleware|Secret)`)
|
||||
acceptedK8sTypes := regexp.MustCompile(`(Deployment|Endpoints|Service|Ingress|IngressRoute|Middleware|Secret|TLSOption)`)
|
||||
|
||||
files := strings.Split(string(content), "---")
|
||||
retVal := make([]runtime.Object, 0, len(files))
|
||||
|
|
|
@ -2,6 +2,7 @@ package server
|
|||
|
||||
import (
|
||||
"github.com/containous/traefik/pkg/config"
|
||||
"github.com/containous/traefik/pkg/log"
|
||||
"github.com/containous/traefik/pkg/server/internal"
|
||||
"github.com/containous/traefik/pkg/tls"
|
||||
)
|
||||
|
@ -21,6 +22,7 @@ func mergeConfiguration(configurations config.Configurations) config.Configurati
|
|||
TLSStores: make(map[string]tls.Store),
|
||||
}
|
||||
|
||||
var defaultTLSOptionProviders []string
|
||||
for provider, configuration := range configurations {
|
||||
if configuration.HTTP != nil {
|
||||
for routerName, router := range configuration.HTTP.Routers {
|
||||
|
@ -48,10 +50,25 @@ func mergeConfiguration(configurations config.Configurations) config.Configurati
|
|||
conf.TLSStores[key] = store
|
||||
}
|
||||
|
||||
for key, config := range configuration.TLSOptions {
|
||||
conf.TLSOptions[key] = config
|
||||
for tlsOptionsName, config := range configuration.TLSOptions {
|
||||
if tlsOptionsName != "default" {
|
||||
tlsOptionsName = internal.MakeQualifiedName(provider, tlsOptionsName)
|
||||
} else {
|
||||
defaultTLSOptionProviders = append(defaultTLSOptionProviders, provider)
|
||||
}
|
||||
|
||||
conf.TLSOptions[tlsOptionsName] = config
|
||||
}
|
||||
}
|
||||
|
||||
if len(defaultTLSOptionProviders) == 0 {
|
||||
conf.TLSOptions["default"] = tls.TLS{}
|
||||
} else if len(defaultTLSOptionProviders) > 1 {
|
||||
log.WithoutContext().Errorf("Default TLS Options defined multiple times in %v", defaultTLSOptionProviders)
|
||||
// We do not set an empty tls.TLS{} as above so that we actually get a "cascading failure" later on,
|
||||
// i.e. routers depending on this missing TLS option will fail to initialize as well.
|
||||
delete(conf.TLSOptions, "default")
|
||||
}
|
||||
|
||||
return conf
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/containous/traefik/pkg/config"
|
||||
"github.com/containous/traefik/pkg/tls"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -108,3 +109,170 @@ func TestAggregator(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAggregator_tlsoptions(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
given config.Configurations
|
||||
expected map[string]tls.TLS
|
||||
}{
|
||||
{
|
||||
desc: "Nil returns an empty configuration",
|
||||
given: nil,
|
||||
expected: map[string]tls.TLS{
|
||||
"default": {},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Returns fully qualified elements from a mono-provider configuration map",
|
||||
given: config.Configurations{
|
||||
"provider-1": &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]tls.TLS{
|
||||
"default": {},
|
||||
"foo@provider-1": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Returns fully qualified elements from a multi-provider configuration map",
|
||||
given: config.Configurations{
|
||||
"provider-1": &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"foo": {
|
||||
MinVersion: "VersionTLS13",
|
||||
},
|
||||
},
|
||||
},
|
||||
"provider-2": &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]tls.TLS{
|
||||
"default": {},
|
||||
"foo@provider-1": {
|
||||
MinVersion: "VersionTLS13",
|
||||
},
|
||||
"foo@provider-2": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Create a valid default tls option when appears only in one provider",
|
||||
given: config.Configurations{
|
||||
"provider-1": &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"foo": {
|
||||
MinVersion: "VersionTLS13",
|
||||
},
|
||||
"default": {
|
||||
MinVersion: "VersionTLS11",
|
||||
},
|
||||
},
|
||||
},
|
||||
"provider-2": &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]tls.TLS{
|
||||
"default": {
|
||||
MinVersion: "VersionTLS11",
|
||||
},
|
||||
"foo@provider-1": {
|
||||
MinVersion: "VersionTLS13",
|
||||
},
|
||||
"foo@provider-2": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "No default tls option if it is defined in multiple providers",
|
||||
given: config.Configurations{
|
||||
"provider-1": &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
"default": {
|
||||
MinVersion: "VersionTLS11",
|
||||
},
|
||||
},
|
||||
},
|
||||
"provider-2": &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"foo": {
|
||||
MinVersion: "VersionTLS13",
|
||||
},
|
||||
"default": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]tls.TLS{
|
||||
"foo@provider-1": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
"foo@provider-2": {
|
||||
MinVersion: "VersionTLS13",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Create a default TLS Options configuration if none was provided",
|
||||
given: config.Configurations{
|
||||
"provider-1": &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
},
|
||||
},
|
||||
"provider-2": &config.Configuration{
|
||||
TLSOptions: map[string]tls.TLS{
|
||||
"foo": {
|
||||
MinVersion: "VersionTLS13",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]tls.TLS{
|
||||
"default": {},
|
||||
"foo@provider-1": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
"foo@provider-2": {
|
||||
MinVersion: "VersionTLS13",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := mergeConfiguration(test.given)
|
||||
assert.Equal(t, test.expected, actual.TLSOptions)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,8 +81,9 @@ func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string) m
|
|||
func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string]*config.TCPRouterInfo, configsHTTP map[string]*config.RouterInfo, handlerHTTP http.Handler, handlerHTTPS http.Handler) (*tcp.Router, error) {
|
||||
router := &tcp.Router{}
|
||||
router.HTTPHandler(handlerHTTP)
|
||||
const defaultTLSConfigName = "default"
|
||||
|
||||
defaultTLSConf, err := m.tlsManager.Get("default", "default")
|
||||
defaultTLSConf, err := m.tlsManager.Get("default", defaultTLSConfigName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -90,7 +91,7 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
|
|||
router.HTTPSHandler(handlerHTTPS, defaultTLSConf)
|
||||
|
||||
for routerHTTPName, routerHTTPConfig := range configsHTTP {
|
||||
if len(routerHTTPConfig.TLS.Options) == 0 || routerHTTPConfig.TLS.Options == "default" {
|
||||
if len(routerHTTPConfig.TLS.Options) == 0 || routerHTTPConfig.TLS.Options == defaultTLSConfigName {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -111,7 +112,12 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
|
|||
|
||||
for _, domain := range domains {
|
||||
if routerHTTPConfig.TLS != nil {
|
||||
tlsConf, err := m.tlsManager.Get("default", routerHTTPConfig.TLS.Options)
|
||||
tlsOptionsName := routerHTTPConfig.TLS.Options
|
||||
if tlsOptionsName != defaultTLSConfigName {
|
||||
tlsOptionsName = internal.GetQualifiedName(ctxRouter, routerHTTPConfig.TLS.Options)
|
||||
}
|
||||
|
||||
tlsConf, err := m.tlsManager.Get("default", tlsOptionsName)
|
||||
if err != nil {
|
||||
routerHTTPConfig.Err = err.Error()
|
||||
logger.Debug(err)
|
||||
|
@ -149,12 +155,17 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
|
|||
if routerConfig.TLS.Passthrough {
|
||||
router.AddRoute(domain, handler)
|
||||
} else {
|
||||
configName := "default"
|
||||
if len(routerConfig.TLS.Options) > 0 {
|
||||
configName = routerConfig.TLS.Options
|
||||
tlsOptionsName := routerConfig.TLS.Options
|
||||
|
||||
if len(tlsOptionsName) == 0 {
|
||||
tlsOptionsName = defaultTLSConfigName
|
||||
}
|
||||
|
||||
tlsConf, err := m.tlsManager.Get("default", configName)
|
||||
if tlsOptionsName != defaultTLSConfigName {
|
||||
tlsOptionsName = internal.GetQualifiedName(ctxRouter, tlsOptionsName)
|
||||
}
|
||||
|
||||
tlsConf, err := m.tlsManager.Get("default", tlsOptionsName)
|
||||
if err != nil {
|
||||
routerConfig.Err = err.Error()
|
||||
logger.Debug(err)
|
||||
|
|
|
@ -204,6 +204,9 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
tlsManager.UpdateConfigs(
|
||||
map[string]tls.Store{},
|
||||
map[string]tls.TLS{
|
||||
"default": {
|
||||
MinVersion: "VersionTLS10",
|
||||
},
|
||||
"foo": {
|
||||
MinVersion: "VersionTLS12",
|
||||
},
|
||||
|
|
|
@ -74,7 +74,7 @@ func (m *Manager) Get(storeName string, configName string) (*tls.Config, error)
|
|||
defer m.lock.RUnlock()
|
||||
|
||||
config, ok := m.configs[configName]
|
||||
if !ok && configName != "default" {
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown TLS options: %s", configName)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ package tls
|
|||
import (
|
||||
"crypto/tls"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
|
||||
|
@ -89,3 +91,67 @@ func TestTLSInvalidStore(t *testing.T) {
|
|||
t.Fatal("got error: default store must have TLS certificates.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestManager_Get(t *testing.T) {
|
||||
dynamicConfigs :=
|
||||
[]*Configuration{
|
||||
{
|
||||
Certificate: &Certificate{
|
||||
CertFile: localhostCert,
|
||||
KeyFile: localhostKey,
|
||||
},
|
||||
},
|
||||
}
|
||||
tlsConfigs := map[string]TLS{
|
||||
"foo": {MinVersion: "VersionTLS12"},
|
||||
"bar": {MinVersion: "VersionTLS11"},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
tlsOptionsName string
|
||||
expectedMinVersion uint16
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
desc: "Get a tls config from a valid name",
|
||||
tlsOptionsName: "foo",
|
||||
expectedMinVersion: uint16(tls.VersionTLS12),
|
||||
},
|
||||
{
|
||||
desc: "Get another tls config from a valid name",
|
||||
tlsOptionsName: "bar",
|
||||
expectedMinVersion: uint16(tls.VersionTLS11),
|
||||
},
|
||||
{
|
||||
desc: "Get an tls config from an invalid name",
|
||||
tlsOptionsName: "unknown",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
desc: "Get an tls config from unexisting 'default' name",
|
||||
tlsOptionsName: "default",
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
tlsManager := NewManager()
|
||||
tlsManager.UpdateConfigs(nil, tlsConfigs, dynamicConfigs)
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
config, err := tlsManager.Get("default", test.tlsOptionsName)
|
||||
if test.expectedError {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, config.MinVersion, test.expectedMinVersion)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,4 +11,4 @@ REPO_ROOT=${HACK_DIR}/..
|
|||
--go-header-file "${HACK_DIR}"/boilerplate.go.tmpl \
|
||||
"$@"
|
||||
|
||||
deepcopy-gen --input-dirs github.com/containous/traefik/pkg/config -O zz_generated.deepcopy --go-header-file "${HACK_DIR}"/boilerplate.go.tmpl
|
||||
deepcopy-gen --input-dirs github.com/containous/traefik/pkg/config -O zz_generated.deepcopy --go-header-file "${HACK_DIR}"/boilerplate.go.tmpl
|
||||
|
|
Loading…
Reference in a new issue