Expand Client Auth Type configuration
This commit is contained in:
parent
7a4b4c941c
commit
2c7cfd1c68
31 changed files with 304 additions and 151 deletions
|
@ -139,35 +139,39 @@ tls:
|
||||||
minVersion: VersionTLS13
|
minVersion: VersionTLS13
|
||||||
```
|
```
|
||||||
|
|
||||||
### Mutual Authentication
|
### Client Authentication (mTLS)
|
||||||
|
|
||||||
Traefik supports both optional and strict (which is the default) mutual authentication, though the `ClientCA.files` section.
|
Traefik supports mutual authentication, through the `ClientAuth` section.
|
||||||
If present, connections from clients without a certificate will be rejected.
|
|
||||||
|
|
||||||
For clients with a certificate, the `optional` option governs the behaviour as follows:
|
For authentication policies that require verification of the client certificate, the certificate authority for the certificate should be set in `ClientAuth.caFiles`.
|
||||||
|
|
||||||
- When `optional = false`, Traefik accepts connections only from clients presenting a certificate signed by a CA listed in `ClientCA.files`.
|
The `ClientAuth.clientAuthType` option governs the behaviour as follows:
|
||||||
- When `optional = true`, Traefik authorizes connections from clients presenting a certificate signed by an unknown CA.
|
|
||||||
|
- `NoClientCert`: disregards any client certificate.
|
||||||
|
- `RequestClientCert`: asks for a certificate but proceeds anyway if none is provided.
|
||||||
|
- `RequireAnyClientCert`: requires a certificate but does not verify if it is signed by a CA listed in `ClientAuth.caFiles`.
|
||||||
|
- `VerifyClientCertIfGiven`: if a certificate is provided, verifies if it is signed by a CA listed in `ClientAuth.caFiles`. Otherwise proceeds without any certificate.
|
||||||
|
- `RequireAndVerifyClientCert`: requires a certificate, which must be signed by a CA listed in `ClientAuth.caFiles`.
|
||||||
|
|
||||||
```toml tab="TOML"
|
```toml tab="TOML"
|
||||||
[tls.options]
|
[tls.options]
|
||||||
[tls.options.default]
|
[tls.options.default]
|
||||||
[tls.options.default.clientCA]
|
[tls.options.default.clientAuth]
|
||||||
# in PEM format. each file can contain multiple CAs.
|
# in PEM format. each file can contain multiple CAs.
|
||||||
files = ["tests/clientca1.crt", "tests/clientca2.crt"]
|
caFiles = ["tests/clientca1.crt", "tests/clientca2.crt"]
|
||||||
optional = false
|
clientAuthType = "RequireAndVerifyClientCert"
|
||||||
```
|
```
|
||||||
|
|
||||||
```yaml tab="YAML"
|
```yaml tab="YAML"
|
||||||
tls:
|
tls:
|
||||||
options:
|
options:
|
||||||
default:
|
default:
|
||||||
clientCA:
|
clientAuth:
|
||||||
# in PEM format. each file can contain multiple CAs.
|
# in PEM format. each file can contain multiple CAs.
|
||||||
files:
|
caFiles:
|
||||||
- tests/clientca1.crt
|
- tests/clientca1.crt
|
||||||
- tests/clientca2.crt
|
- tests/clientca2.crt
|
||||||
optional: false
|
clientAuthType: RequireAndVerifyClientCert
|
||||||
```
|
```
|
||||||
|
|
||||||
### Cipher Suites
|
### Cipher Suites
|
||||||
|
|
|
@ -296,7 +296,7 @@ metadata:
|
||||||
namespace: default
|
namespace: default
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
minversion: VersionTLS12
|
minVersion: VersionTLS12
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
|
|
@ -275,16 +275,16 @@
|
||||||
minVersion = "foobar"
|
minVersion = "foobar"
|
||||||
cipherSuites = ["foobar", "foobar"]
|
cipherSuites = ["foobar", "foobar"]
|
||||||
sniStrict = true
|
sniStrict = true
|
||||||
[tls.options.Options0.clientCA]
|
[tls.options.Options0.clientAuth]
|
||||||
files = ["foobar", "foobar"]
|
caFiles = ["foobar", "foobar"]
|
||||||
optional = true
|
clientAuthType = "VerifyClientCertIfGiven"
|
||||||
[tls.options.Options1]
|
[tls.options.Options1]
|
||||||
minVersion = "foobar"
|
minVersion = "foobar"
|
||||||
cipherSuites = ["foobar", "foobar"]
|
cipherSuites = ["foobar", "foobar"]
|
||||||
sniStrict = true
|
sniStrict = true
|
||||||
[tls.options.Options1.clientCA]
|
[tls.options.Options1.clientAuth]
|
||||||
files = ["foobar", "foobar"]
|
caFiles = ["foobar", "foobar"]
|
||||||
optional = true
|
clientAuthType = "VerifyClientCertIfGiven"
|
||||||
[tls.stores]
|
[tls.stores]
|
||||||
[tls.stores.Store0]
|
[tls.stores.Store0]
|
||||||
[tls.stores.Store0.defaultCertificate]
|
[tls.stores.Store0.defaultCertificate]
|
||||||
|
|
|
@ -303,22 +303,22 @@ tls:
|
||||||
cipherSuites:
|
cipherSuites:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
clientCA:
|
clientAuth:
|
||||||
files:
|
caFiles:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
optional: true
|
clientAuthType: VerifyClientCertIfGiven
|
||||||
sniStrict: true
|
sniStrict: true
|
||||||
Options1:
|
Options1:
|
||||||
minVersion: foobar
|
minVersion: foobar
|
||||||
cipherSuites:
|
cipherSuites:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
clientCA:
|
clientAuth:
|
||||||
files:
|
caFiles:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
optional: true
|
clientAuthType: VerifyClientCertIfGiven
|
||||||
sniStrict: true
|
sniStrict: true
|
||||||
stores:
|
stores:
|
||||||
Store0:
|
Store0:
|
||||||
|
|
|
@ -47,6 +47,6 @@
|
||||||
keyFile = "fixtures/https/snitest.org.key"
|
keyFile = "fixtures/https/snitest.org.key"
|
||||||
|
|
||||||
[tls.options]
|
[tls.options]
|
||||||
[tls.options.default.ClientCA]
|
[tls.options.default.clientAuth]
|
||||||
files = ["fixtures/https/clientca/ca1.crt"]
|
caFiles = ["fixtures/https/clientca/ca1.crt"]
|
||||||
optional = true
|
clientAuthType = "VerifyClientCertIfGiven"
|
||||||
|
|
|
@ -47,5 +47,5 @@
|
||||||
keyFile = "fixtures/https/snitest.org.key"
|
keyFile = "fixtures/https/snitest.org.key"
|
||||||
|
|
||||||
[tls.options]
|
[tls.options]
|
||||||
[tls.options.default.clientCA]
|
[tls.options.default.clientAuth]
|
||||||
files = ["fixtures/https/clientca/ca1and2.crt"]
|
caFiles = ["fixtures/https/clientca/ca1and2.crt"]
|
|
@ -46,6 +46,6 @@
|
||||||
keyFile = "fixtures/https/snitest.org.key"
|
keyFile = "fixtures/https/snitest.org.key"
|
||||||
|
|
||||||
[tls.options]
|
[tls.options]
|
||||||
[tls.options.default.clientCA]
|
[tls.options.default.clientAuth]
|
||||||
files = ["fixtures/https/clientca/ca1.crt", "fixtures/https/clientca/ca2.crt"]
|
caFiles = ["fixtures/https/clientca/ca1.crt", "fixtures/https/clientca/ca2.crt"]
|
||||||
optional = false
|
clientAuthType = "RequireAndVerifyClientCert"
|
||||||
|
|
|
@ -69,13 +69,13 @@
|
||||||
[tls.options]
|
[tls.options]
|
||||||
|
|
||||||
[tls.options.foo]
|
[tls.options.foo]
|
||||||
minversion = "VersionTLS11"
|
minVersion = "VersionTLS11"
|
||||||
|
|
||||||
[tls.options.baz]
|
[tls.options.baz]
|
||||||
minversion = "VersionTLS11"
|
minVersion = "VersionTLS11"
|
||||||
|
|
||||||
[tls.options.bar]
|
[tls.options.bar]
|
||||||
minversion = "VersionTLS12"
|
minVersion = "VersionTLS12"
|
||||||
|
|
||||||
[tls.options.default]
|
[tls.options.default]
|
||||||
minversion = "VersionTLS12"
|
minVersion = "VersionTLS12"
|
||||||
|
|
|
@ -5,8 +5,8 @@ metadata:
|
||||||
namespace: default
|
namespace: default
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
minversion: VersionTLS12
|
minVersion: VersionTLS12
|
||||||
snistrict: true
|
sniStrict: true
|
||||||
ciphersuites:
|
cipherSuites:
|
||||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
[tls.options]
|
[tls.options]
|
||||||
|
|
||||||
[tls.options.foo]
|
[tls.options.foo]
|
||||||
minversion = "VersionTLS11"
|
minVersion = "VersionTLS11"
|
||||||
|
|
||||||
[tls.options.bar]
|
[tls.options.bar]
|
||||||
minversion = "VersionTLS12"
|
minVersion = "VersionTLS12"
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
## dynamic configuration ##
|
## dynamic configuration ##
|
||||||
|
|
||||||
[tls.options]
|
[tls.options]
|
||||||
[tls.options.default.clientCA]
|
[tls.options.default.clientAuth]
|
||||||
files = [ """{{ .RootCertContent }}""" ]
|
caFiles = [ """{{ .RootCertContent }}""" ]
|
||||||
optional = false
|
clientAuthType = "RequireAndVerifyClientCert"
|
||||||
|
|
||||||
[tls.stores]
|
[tls.stores]
|
||||||
[tls.stores.default.defaultCertificate]
|
[tls.stores.default.defaultCertificate]
|
||||||
|
|
|
@ -460,16 +460,16 @@
|
||||||
minVersion = "foobar"
|
minVersion = "foobar"
|
||||||
cipherSuites = ["foobar", "foobar"]
|
cipherSuites = ["foobar", "foobar"]
|
||||||
sniStrict = true
|
sniStrict = true
|
||||||
[tls.options.TLS0.clientCA]
|
[tls.options.TLS0.clientAuth]
|
||||||
files = ["foobar", "foobar"]
|
caFiles = ["foobar", "foobar"]
|
||||||
optional = true
|
clientAuthType = "VerifyClientCertIfGiven"
|
||||||
[tls.options.TLS1]
|
[tls.options.TLS1]
|
||||||
minVersion = "foobar"
|
minVersion = "foobar"
|
||||||
cipherSuites = ["foobar", "foobar"]
|
cipherSuites = ["foobar", "foobar"]
|
||||||
sniStrict = true
|
sniStrict = true
|
||||||
[tls.options.TLS1.clientCA]
|
[tls.options.TLS1.clientAuth]
|
||||||
files = ["foobar", "foobar"]
|
caFiles = ["foobar", "foobar"]
|
||||||
optional = true
|
clientAuthType = "VerifyClientCertIfGiven"
|
||||||
[tls.stores]
|
[tls.stores]
|
||||||
[tls.stores.Store0]
|
[tls.stores.Store0]
|
||||||
[tls.stores.Store0.defaultCertificate]
|
[tls.stores.Store0.defaultCertificate]
|
||||||
|
|
|
@ -222,7 +222,7 @@ func (p *passTLSClientCert) modifyRequestHeaders(logger logrus.FieldLogger, r *h
|
||||||
if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
|
if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
|
||||||
r.Header.Set(xForwardedTLSClientCert, getXForwardedTLSClientCert(logger, r.TLS.PeerCertificates))
|
r.Header.Set(xForwardedTLSClientCert, getXForwardedTLSClientCert(logger, r.TLS.PeerCertificates))
|
||||||
} else {
|
} else {
|
||||||
logger.Warn("Try to extract certificate on a request without TLS")
|
logger.Warn("Tried to extract a certificate on a request without mutual TLS")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ func (p *passTLSClientCert) modifyRequestHeaders(logger logrus.FieldLogger, r *h
|
||||||
headerContent := p.getXForwardedTLSClientCertInfo(r.TLS.PeerCertificates)
|
headerContent := p.getXForwardedTLSClientCertInfo(r.TLS.PeerCertificates)
|
||||||
r.Header.Set(xForwardedTLSClientCertInfo, url.QueryEscape(headerContent))
|
r.Header.Set(xForwardedTLSClientCertInfo, url.QueryEscape(headerContent))
|
||||||
} else {
|
} else {
|
||||||
logger.Warn("Try to extract certificate on a request without TLS")
|
logger.Warn("Tried to extract a certificate on a request without mutual TLS")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,17 +25,17 @@ metadata:
|
||||||
namespace: default
|
namespace: default
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
minversion: VersionTLS12
|
minVersion: VersionTLS12
|
||||||
snistrict: true
|
sniStrict: true
|
||||||
ciphersuites:
|
cipherSuites:
|
||||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||||
clientca:
|
clientAuth:
|
||||||
secretnames:
|
secretNames:
|
||||||
- secretCA1
|
- secretCA1
|
||||||
- secretUnknown
|
- secretUnknown
|
||||||
- emptySecret
|
- emptySecret
|
||||||
optional: true
|
clientAuthType: VerifyClientCertIfGiven
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
|
|
|
@ -25,16 +25,16 @@ metadata:
|
||||||
namespace: default
|
namespace: default
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
minversion: VersionTLS12
|
minVersion: VersionTLS12
|
||||||
snistrict: true
|
sniStrict: true
|
||||||
ciphersuites:
|
cipherSuites:
|
||||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||||
clientca:
|
clientAuth:
|
||||||
secretnames:
|
secretNames:
|
||||||
- secretCA1
|
- secretCA1
|
||||||
- secretCA2
|
- secretCA2
|
||||||
optional: true
|
clientAuthType: VerifyClientCertIfGiven
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
|
|
|
@ -25,16 +25,16 @@ metadata:
|
||||||
namespace: myns
|
namespace: myns
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
minversion: VersionTLS12
|
minVersion: VersionTLS12
|
||||||
snistrict: true
|
sniStrict: true
|
||||||
ciphersuites:
|
cipherSuites:
|
||||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||||
clientca:
|
clientAuth:
|
||||||
secretnames:
|
secretNames:
|
||||||
- secretCA1
|
- secretCA1
|
||||||
- secretCA2
|
- secretCA2
|
||||||
optional: true
|
clientAuthType: VerifyClientCertIfGiven
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
|
|
|
@ -6,7 +6,7 @@ metadata:
|
||||||
namespace: default
|
namespace: default
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
minversion: VersionTLS12
|
minVersion: VersionTLS12
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
|
|
@ -6,7 +6,7 @@ metadata:
|
||||||
namespace: default
|
namespace: default
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
minversion: VersionTLS12
|
minVersion: VersionTLS12
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
|
|
@ -25,17 +25,17 @@ metadata:
|
||||||
namespace: default
|
namespace: default
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
minversion: VersionTLS12
|
minVersion: VersionTLS12
|
||||||
snistrict: true
|
sniStrict: true
|
||||||
ciphersuites:
|
cipherSuites:
|
||||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||||
clientca:
|
clientAuth:
|
||||||
secretnames:
|
secretNames:
|
||||||
- secretCA1
|
- secretCA1
|
||||||
- secretUnknown
|
- secretUnknown
|
||||||
- emptySecret
|
- emptySecret
|
||||||
optional: true
|
clientAuthType: VerifyClientCertIfGiven
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
|
|
@ -25,16 +25,16 @@ metadata:
|
||||||
namespace: default
|
namespace: default
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
minversion: VersionTLS12
|
minVersion: VersionTLS12
|
||||||
snistrict: true
|
sniStrict: true
|
||||||
ciphersuites:
|
cipherSuites:
|
||||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||||
clientca:
|
clientAuth:
|
||||||
secretnames:
|
secretNames:
|
||||||
- secretCA1
|
- secretCA1
|
||||||
- secretCA2
|
- secretCA2
|
||||||
optional: true
|
clientAuthType: VerifyClientCertIfGiven
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
|
|
@ -25,16 +25,16 @@ metadata:
|
||||||
namespace: myns
|
namespace: myns
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
minversion: VersionTLS12
|
minVersion: VersionTLS12
|
||||||
snistrict: true
|
sniStrict: true
|
||||||
ciphersuites:
|
cipherSuites:
|
||||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||||
clientca:
|
clientAuth:
|
||||||
secretnames:
|
secretNames:
|
||||||
- secretCA1
|
- secretCA1
|
||||||
- secretCA2
|
- secretCA2
|
||||||
optional: true
|
clientAuthType: VerifyClientCertIfGiven
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
|
|
@ -5,7 +5,7 @@ metadata:
|
||||||
namespace: default
|
namespace: default
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
minversion: VersionTLS12
|
minVersion: VersionTLS12
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
|
|
@ -5,7 +5,7 @@ metadata:
|
||||||
namespace: default
|
namespace: default
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
minversion: VersionTLS12
|
minVersion: VersionTLS12
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
|
|
@ -313,7 +313,7 @@ func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options
|
||||||
logger := log.FromContext(log.With(ctx, log.Str("tlsOption", tlsOption.Name), log.Str("namespace", tlsOption.Namespace)))
|
logger := log.FromContext(log.With(ctx, log.Str("tlsOption", tlsOption.Name), log.Str("namespace", tlsOption.Namespace)))
|
||||||
var clientCAs []tls.FileOrContent
|
var clientCAs []tls.FileOrContent
|
||||||
|
|
||||||
for _, secretName := range tlsOption.Spec.ClientCA.SecretNames {
|
for _, secretName := range tlsOption.Spec.ClientAuth.SecretNames {
|
||||||
secret, exists, err := client.GetSecret(tlsOption.Namespace, secretName)
|
secret, exists, err := client.GetSecret(tlsOption.Namespace, secretName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("Failed to fetch secret %s/%s: %v", tlsOption.Namespace, secretName, err)
|
logger.Errorf("Failed to fetch secret %s/%s: %v", tlsOption.Namespace, secretName, err)
|
||||||
|
@ -337,9 +337,9 @@ func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options
|
||||||
tlsOptions[makeID(tlsOption.Namespace, tlsOption.Name)] = tls.Options{
|
tlsOptions[makeID(tlsOption.Namespace, tlsOption.Name)] = tls.Options{
|
||||||
MinVersion: tlsOption.Spec.MinVersion,
|
MinVersion: tlsOption.Spec.MinVersion,
|
||||||
CipherSuites: tlsOption.Spec.CipherSuites,
|
CipherSuites: tlsOption.Spec.CipherSuites,
|
||||||
ClientCA: tls.ClientCA{
|
ClientAuth: tls.ClientAuth{
|
||||||
Files: clientCAs,
|
CAFiles: clientCAs,
|
||||||
Optional: tlsOption.Spec.ClientCA.Optional,
|
ClientAuthType: tlsOption.Spec.ClientAuth.ClientAuthType,
|
||||||
},
|
},
|
||||||
SniStrict: tlsOption.Spec.SniStrict,
|
SniStrict: tlsOption.Spec.SniStrict,
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,12 +319,12 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientCA: tls.ClientCA{
|
ClientAuth: tls.ClientAuth{
|
||||||
Files: []tls.FileOrContent{
|
CAFiles: []tls.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
Optional: true,
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
SniStrict: true,
|
SniStrict: true,
|
||||||
},
|
},
|
||||||
|
@ -377,12 +377,12 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientCA: tls.ClientCA{
|
ClientAuth: tls.ClientAuth{
|
||||||
Files: []tls.FileOrContent{
|
CAFiles: []tls.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
Optional: true,
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
SniStrict: true,
|
SniStrict: true,
|
||||||
},
|
},
|
||||||
|
@ -435,11 +435,11 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientCA: tls.ClientCA{
|
ClientAuth: tls.ClientAuth{
|
||||||
Files: []tls.FileOrContent{
|
CAFiles: []tls.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
Optional: true,
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
SniStrict: true,
|
SniStrict: true,
|
||||||
},
|
},
|
||||||
|
@ -1009,12 +1009,12 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientCA: tls.ClientCA{
|
ClientAuth: tls.ClientAuth{
|
||||||
Files: []tls.FileOrContent{
|
CAFiles: []tls.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
Optional: true,
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
SniStrict: true,
|
SniStrict: true,
|
||||||
},
|
},
|
||||||
|
@ -1067,12 +1067,12 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientCA: tls.ClientCA{
|
ClientAuth: tls.ClientAuth{
|
||||||
Files: []tls.FileOrContent{
|
CAFiles: []tls.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
Optional: true,
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
SniStrict: true,
|
SniStrict: true,
|
||||||
},
|
},
|
||||||
|
@ -1125,11 +1125,11 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
},
|
},
|
||||||
ClientCA: tls.ClientCA{
|
ClientAuth: tls.ClientAuth{
|
||||||
Files: []tls.FileOrContent{
|
CAFiles: []tls.FileOrContent{
|
||||||
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||||
},
|
},
|
||||||
Optional: true,
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
},
|
},
|
||||||
SniStrict: true,
|
SniStrict: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,22 +19,22 @@ type TLSOption struct {
|
||||||
|
|
||||||
// TLSOptionSpec configures TLS for an entry point
|
// TLSOptionSpec configures TLS for an entry point
|
||||||
type TLSOptionSpec struct {
|
type TLSOptionSpec struct {
|
||||||
MinVersion string `json:"minversion"`
|
MinVersion string `json:"minVersion,omitempty"`
|
||||||
CipherSuites []string `json:"ciphersuites"`
|
CipherSuites []string `json:"cipherSuites,omitempty"`
|
||||||
ClientCA ClientCA `json:"clientca"`
|
ClientAuth ClientAuth `json:"clientAuth,omitempty"`
|
||||||
SniStrict bool `json:"snistrict"`
|
SniStrict bool `json:"sniStrict,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
// ClientCA defines traefik CA files for an entryPoint
|
// ClientAuth defines the parameters of the client authentication part of the TLS connection, if any.
|
||||||
// and it indicates if they are mandatory or have just to be analyzed if provided
|
type ClientAuth struct {
|
||||||
type ClientCA struct {
|
|
||||||
// SecretName is the name of the referenced Kubernetes Secret to specify the
|
// SecretName is the name of the referenced Kubernetes Secret to specify the
|
||||||
// certificate details.
|
// certificate details.
|
||||||
SecretNames []string `json:"secretnames"`
|
SecretNames []string `json:"secretNames"`
|
||||||
// Optional indicates if ClientCA are mandatory or have just to be analyzed if provided
|
// ClientAuthType defines the client authentication type to apply.
|
||||||
Optional bool `json:"optional"`
|
// The available values are: "NoClientCert", "RequestClientCert", "VerifyClientCertIfGiven" and "RequireAndVerifyClientCert".
|
||||||
|
ClientAuthType string `json:"clientAuthType"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
|
@ -33,7 +33,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ClientCA) DeepCopyInto(out *ClientCA) {
|
func (in *ClientAuth) DeepCopyInto(out *ClientAuth) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.SecretNames != nil {
|
if in.SecretNames != nil {
|
||||||
in, out := &in.SecretNames, &out.SecretNames
|
in, out := &in.SecretNames, &out.SecretNames
|
||||||
|
@ -43,12 +43,12 @@ func (in *ClientCA) DeepCopyInto(out *ClientCA) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientCA.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientAuth.
|
||||||
func (in *ClientCA) DeepCopy() *ClientCA {
|
func (in *ClientAuth) DeepCopy() *ClientAuth {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(ClientCA)
|
out := new(ClientAuth)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
@ -529,7 +529,7 @@ func (in *TLSOptionSpec) DeepCopyInto(out *TLSOptionSpec) {
|
||||||
*out = make([]string, len(*in))
|
*out = make([]string, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
in.ClientCA.DeepCopyInto(&out.ClientCA)
|
in.ClientAuth.DeepCopyInto(&out.ClientAuth)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,21 +4,22 @@ const certificateHeader = "-----BEGIN CERTIFICATE-----\n"
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
// ClientCA defines traefik CA files for a entryPoint
|
// ClientAuth defines the parameters of the client authentication part of the TLS connection, if any.
|
||||||
// and it indicates if they are mandatory or have just to be analyzed if provided.
|
type ClientAuth struct {
|
||||||
type ClientCA struct {
|
CAFiles []FileOrContent `json:"caFiles,omitempty" toml:"caFiles,omitempty" yaml:"caFiles,omitempty"`
|
||||||
Files []FileOrContent `json:"files,omitempty" toml:"files,omitempty" yaml:"files,omitempty"`
|
// ClientAuthType defines the client authentication type to apply.
|
||||||
Optional bool `json:"optional,omitempty" toml:"optional,omitempty" yaml:"optional,omitempty"`
|
// The available values are: "NoClientCert", "RequestClientCert", "VerifyClientCertIfGiven" and "RequireAndVerifyClientCert".
|
||||||
|
ClientAuthType string `json:"clientAuthType,omitempty" toml:"clientAuthType,omitempty" yaml:"clientAuthType,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
// Options configures TLS for an entry point
|
// Options configures TLS for an entry point
|
||||||
type Options struct {
|
type Options struct {
|
||||||
MinVersion string `json:"minVersion,omitempty" toml:"minVersion,omitempty" yaml:"minVersion,omitempty" export:"true"`
|
MinVersion string `json:"minVersion,omitempty" toml:"minVersion,omitempty" yaml:"minVersion,omitempty" export:"true"`
|
||||||
CipherSuites []string `json:"cipherSuites,omitempty" toml:"cipherSuites,omitempty" yaml:"cipherSuites,omitempty"`
|
CipherSuites []string `json:"cipherSuites,omitempty" toml:"cipherSuites,omitempty" yaml:"cipherSuites,omitempty"`
|
||||||
ClientCA ClientCA `json:"clientCA,omitempty" toml:"clientCA,omitempty" yaml:"clientCA,omitempty"`
|
ClientAuth ClientAuth `json:"clientAuth,omitempty" toml:"clientAuth,omitempty" yaml:"clientAuth,omitempty"`
|
||||||
SniStrict bool `json:"sniStrict,omitempty" toml:"sniStrict,omitempty" yaml:"sniStrict,omitempty" export:"true"`
|
SniStrict bool `json:"sniStrict,omitempty" toml:"sniStrict,omitempty" yaml:"sniStrict,omitempty" export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
|
@ -3,6 +3,7 @@ package tls
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -159,23 +160,45 @@ func buildTLSConfig(tlsOption Options) (*tls.Config, error) {
|
||||||
// ensure http2 enabled
|
// ensure http2 enabled
|
||||||
conf.NextProtos = []string{"h2", "http/1.1", tlsalpn01.ACMETLS1Protocol}
|
conf.NextProtos = []string{"h2", "http/1.1", tlsalpn01.ACMETLS1Protocol}
|
||||||
|
|
||||||
if len(tlsOption.ClientCA.Files) > 0 {
|
if len(tlsOption.ClientAuth.CAFiles) > 0 {
|
||||||
pool := x509.NewCertPool()
|
pool := x509.NewCertPool()
|
||||||
for _, caFile := range tlsOption.ClientCA.Files {
|
for _, caFile := range tlsOption.ClientAuth.CAFiles {
|
||||||
data, err := caFile.Read()
|
data, err := caFile.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ok := pool.AppendCertsFromPEM(data)
|
ok := pool.AppendCertsFromPEM(data)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid certificate(s) in %s", caFile)
|
if caFile.IsPath() {
|
||||||
|
return nil, fmt.Errorf("invalid certificate(s) in %s", caFile)
|
||||||
|
}
|
||||||
|
return nil, errors.New("invalid certificate(s) content")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conf.ClientCAs = pool
|
conf.ClientCAs = pool
|
||||||
if tlsOption.ClientCA.Optional {
|
conf.ClientAuth = tls.RequireAndVerifyClientCert
|
||||||
|
}
|
||||||
|
|
||||||
|
clientAuthType := tlsOption.ClientAuth.ClientAuthType
|
||||||
|
if len(clientAuthType) > 0 {
|
||||||
|
if conf.ClientCAs == nil && (clientAuthType == "VerifyClientCertIfGiven" ||
|
||||||
|
clientAuthType == "RequireAndVerifyClientCert") {
|
||||||
|
return nil, fmt.Errorf("invalid clientAuthType: %s, CAFiles is required", clientAuthType)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch clientAuthType {
|
||||||
|
case "NoClientCert":
|
||||||
|
conf.ClientAuth = tls.NoClientCert
|
||||||
|
case "RequestClientCert":
|
||||||
|
conf.ClientAuth = tls.RequestClientCert
|
||||||
|
case "RequireAnyClientCert":
|
||||||
|
conf.ClientAuth = tls.RequireAnyClientCert
|
||||||
|
case "VerifyClientCertIfGiven":
|
||||||
conf.ClientAuth = tls.VerifyClientCertIfGiven
|
conf.ClientAuth = tls.VerifyClientCertIfGiven
|
||||||
} else {
|
case "RequireAndVerifyClientCert":
|
||||||
conf.ClientAuth = tls.RequireAndVerifyClientCert
|
conf.ClientAuth = tls.RequireAndVerifyClientCert
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown client auth type %q", clientAuthType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,12 @@ package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
|
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
|
||||||
|
@ -146,3 +149,125 @@ func TestManager_Get(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClientAuth(t *testing.T) {
|
||||||
|
tlsConfigs := map[string]Options{
|
||||||
|
"eca": {ClientAuth: ClientAuth{}},
|
||||||
|
"ecat": {ClientAuth: ClientAuth{ClientAuthType: ""}},
|
||||||
|
"ncc": {ClientAuth: ClientAuth{ClientAuthType: "NoClientCert"}},
|
||||||
|
"rcc": {ClientAuth: ClientAuth{ClientAuthType: "RequestClientCert"}},
|
||||||
|
"racc": {ClientAuth: ClientAuth{ClientAuthType: "RequireAnyClientCert"}},
|
||||||
|
"vccig": {
|
||||||
|
ClientAuth: ClientAuth{
|
||||||
|
CAFiles: []FileOrContent{localhostCert},
|
||||||
|
ClientAuthType: "VerifyClientCertIfGiven",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"vccigwca": {
|
||||||
|
ClientAuth: ClientAuth{ClientAuthType: "VerifyClientCertIfGiven"},
|
||||||
|
},
|
||||||
|
"ravcc": {ClientAuth: ClientAuth{ClientAuthType: "RequireAndVerifyClientCert"}},
|
||||||
|
"ravccwca": {
|
||||||
|
ClientAuth: ClientAuth{
|
||||||
|
CAFiles: []FileOrContent{localhostCert},
|
||||||
|
ClientAuthType: "RequireAndVerifyClientCert",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"ravccwbca": {
|
||||||
|
ClientAuth: ClientAuth{
|
||||||
|
CAFiles: []FileOrContent{"Bad content"},
|
||||||
|
ClientAuthType: "RequireAndVerifyClientCert",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"ucat": {ClientAuth: ClientAuth{ClientAuthType: "Unknown"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
block, _ := pem.Decode([]byte(localhostCert))
|
||||||
|
cert, err := x509.ParseCertificate(block.Bytes)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
tlsOptionsName string
|
||||||
|
expectedClientAuth tls.ClientAuthType
|
||||||
|
expectedRawSubject []byte
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Empty ClientAuth option should get a tls.NoClientCert (default value)",
|
||||||
|
tlsOptionsName: "eca",
|
||||||
|
expectedClientAuth: tls.NoClientCert,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Empty ClientAuthType option should get a tls.NoClientCert (default value)",
|
||||||
|
tlsOptionsName: "ecat",
|
||||||
|
expectedClientAuth: tls.NoClientCert,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "NoClientCert option should get a tls.NoClientCert as ClientAuthType",
|
||||||
|
tlsOptionsName: "ncc",
|
||||||
|
expectedClientAuth: tls.NoClientCert,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "RequestClientCert option should get a tls.RequestClientCert as ClientAuthType",
|
||||||
|
tlsOptionsName: "rcc",
|
||||||
|
expectedClientAuth: tls.RequestClientCert,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "RequireAnyClientCert option should get a tls.RequireAnyClientCert as ClientAuthType",
|
||||||
|
tlsOptionsName: "racc",
|
||||||
|
expectedClientAuth: tls.RequireAnyClientCert,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "VerifyClientCertIfGiven option should get a tls.VerifyClientCertIfGiven as ClientAuthType",
|
||||||
|
tlsOptionsName: "vccig",
|
||||||
|
expectedClientAuth: tls.VerifyClientCertIfGiven,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "VerifyClientCertIfGiven option without CAFiles yields a default ClientAuthType (NoClientCert)",
|
||||||
|
tlsOptionsName: "vccigwca",
|
||||||
|
expectedClientAuth: tls.NoClientCert,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "RequireAndVerifyClientCert option without CAFiles yields a default ClientAuthType (NoClientCert)",
|
||||||
|
tlsOptionsName: "ravcc",
|
||||||
|
expectedClientAuth: tls.NoClientCert,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "RequireAndVerifyClientCert option should get a tls.RequireAndVerifyClientCert as ClientAuthType with CA files",
|
||||||
|
tlsOptionsName: "ravccwca",
|
||||||
|
expectedClientAuth: tls.RequireAndVerifyClientCert,
|
||||||
|
expectedRawSubject: cert.RawSubject,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Unknown option yields a default ClientAuthType (NoClientCert)",
|
||||||
|
tlsOptionsName: "ucat",
|
||||||
|
expectedClientAuth: tls.NoClientCert,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Bad CA certificate content yields a default ClientAuthType (NoClientCert)",
|
||||||
|
tlsOptionsName: "ravccwbca",
|
||||||
|
expectedClientAuth: tls.NoClientCert,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsManager := NewManager()
|
||||||
|
tlsManager.UpdateConfigs(nil, tlsConfigs, nil)
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
config, err := tlsManager.Get("default", test.tlsOptionsName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
if test.expectedRawSubject != nil {
|
||||||
|
subjects := config.ClientCAs.Subjects()
|
||||||
|
assert.Len(t, subjects, 1)
|
||||||
|
assert.Equal(t, subjects[0], test.expectedRawSubject)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, config.ClientAuth, test.expectedClientAuth)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -51,22 +51,22 @@ func (in *CertAndStores) DeepCopy() *CertAndStores {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ClientCA) DeepCopyInto(out *ClientCA) {
|
func (in *ClientAuth) DeepCopyInto(out *ClientAuth) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.Files != nil {
|
if in.CAFiles != nil {
|
||||||
in, out := &in.Files, &out.Files
|
in, out := &in.CAFiles, &out.CAFiles
|
||||||
*out = make([]FileOrContent, len(*in))
|
*out = make([]FileOrContent, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientCA.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientAuth.
|
||||||
func (in *ClientCA) DeepCopy() *ClientCA {
|
func (in *ClientAuth) DeepCopy() *ClientAuth {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(ClientCA)
|
out := new(ClientAuth)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ func (in *Options) DeepCopyInto(out *Options) {
|
||||||
*out = make([]string, len(*in))
|
*out = make([]string, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
in.ClientCA.DeepCopyInto(&out.ClientCA)
|
in.ClientAuth.DeepCopyInto(&out.ClientAuth)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue