Add tls option for Elliptic Curve Preferences

This commit is contained in:
Kelvin Sarink 2019-11-03 15:54:04 +01:00 committed by Traefiker Bot
parent c5ec12cd56
commit 5a3e325742
10 changed files with 104 additions and 15 deletions

View file

@ -274,6 +274,46 @@ spec:
With TLS 1.3, the cipher suites are not configurable (all supported cipher suites are safe in this case). With TLS 1.3, the cipher suites are not configurable (all supported cipher suites are safe in this case).
<https://golang.org/doc/go1.12#tls_1_3> <https://golang.org/doc/go1.12#tls_1_3>
### Curve Preferences
This option allows to set the preferred elliptic curves in a specific order.
The names of the curves defined by [`crypto`](https://godoc.org/crypto/tls#CurveID) (e.g. `CurveP521`) and the [RFC defined names](https://tools.ietf.org/html/rfc8446#section-4.2.7) (e. g. `secp521r1`) can be used.
See [CurveID](https://godoc.org/crypto/tls#CurveID) for more information.
```toml tab="File (TOML)"
# Dynamic configuration
[tls.options]
[tls.options.default]
curvePreferences = ["CurveP521", "CurveP384"]
```
```yaml tab="File (YAML)"
# Dynamic configuration
tls:
options:
default:
curvePreferences:
- CurveP521
- CurveP384
```
```yaml tab="Kubernetes"
apiVersion: traefik.containo.us/v1alpha1
kind: TLSOption
metadata:
name: default
namespace: default
spec:
curvePreferences:
- CurveP521
- CurveP384
```
### Strict SNI Checking ### Strict SNI Checking
With strict SNI checking, Traefik won't allow connections from clients connections With strict SNI checking, Traefik won't allow connections from clients connections

View file

@ -321,6 +321,7 @@
maxVersion = "foobar" maxVersion = "foobar"
cipherSuites = ["foobar", "foobar"] cipherSuites = ["foobar", "foobar"]
sniStrict = true sniStrict = true
curvePreferences = ["foobar", "foobar"]
[tls.options.Options0.clientAuth] [tls.options.Options0.clientAuth]
caFiles = ["foobar", "foobar"] caFiles = ["foobar", "foobar"]
clientAuthType = "foobar" clientAuthType = "foobar"
@ -329,6 +330,7 @@
maxVersion = "foobar" maxVersion = "foobar"
cipherSuites = ["foobar", "foobar"] cipherSuites = ["foobar", "foobar"]
sniStrict = true sniStrict = true
curvePreferences = ["foobar", "foobar"]
[tls.options.Options1.clientAuth] [tls.options.Options1.clientAuth]
caFiles = ["foobar", "foobar"] caFiles = ["foobar", "foobar"]
clientAuthType = "foobar" clientAuthType = "foobar"

View file

@ -353,6 +353,9 @@ tls:
cipherSuites: cipherSuites:
- foobar - foobar
- foobar - foobar
curvePreferences:
- foobar
- foobar
clientAuth: clientAuth:
caFiles: caFiles:
- foobar - foobar
@ -365,6 +368,9 @@ tls:
cipherSuites: cipherSuites:
- foobar - foobar
- foobar - foobar
curvePreferences:
- foobar
- foobar
clientAuth: clientAuth:
caFiles: caFiles:
- foobar - foobar

View file

@ -481,9 +481,10 @@ 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,
MaxVersion: tlsOption.Spec.MaxVersion, MaxVersion: tlsOption.Spec.MaxVersion,
CipherSuites: tlsOption.Spec.CipherSuites, CipherSuites: tlsOption.Spec.CipherSuites,
CurvePreferences: tlsOption.Spec.CurvePreferences,
ClientAuth: tls.ClientAuth{ ClientAuth: tls.ClientAuth{
CAFiles: clientCAs, CAFiles: clientCAs,
ClientAuthType: tlsOption.Spec.ClientAuth.ClientAuthType, ClientAuthType: tlsOption.Spec.ClientAuth.ClientAuthType,

View file

@ -19,11 +19,12 @@ 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,omitempty"` MinVersion string `json:"minVersion,omitempty"`
MaxVersion string `json:"maxVersion,omitempty"` MaxVersion string `json:"maxVersion,omitempty"`
CipherSuites []string `json:"cipherSuites,omitempty"` CipherSuites []string `json:"cipherSuites,omitempty"`
ClientAuth ClientAuth `json:"clientAuth,omitempty"` CurvePreferences []string `json:"curvePreferences,omitempty"`
SniStrict bool `json:"sniStrict,omitempty"` ClientAuth ClientAuth `json:"clientAuth,omitempty"`
SniStrict bool `json:"sniStrict,omitempty"`
} }
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true

View file

@ -803,6 +803,11 @@ func (in *TLSOptionSpec) DeepCopyInto(out *TLSOptionSpec) {
*out = make([]string, len(*in)) *out = make([]string, len(*in))
copy(*out, *in) copy(*out, *in)
} }
if in.CurvePreferences != nil {
in, out := &in.CurvePreferences, &out.CurvePreferences
*out = make([]string, len(*in))
copy(*out, *in)
}
in.ClientAuth.DeepCopyInto(&out.ClientAuth) in.ClientAuth.DeepCopyInto(&out.ClientAuth)
return return
} }

View file

@ -60,6 +60,20 @@ var (
"TLS_CHACHA20_POLY1305_SHA256": tls.TLS_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256": tls.TLS_CHACHA20_POLY1305_SHA256,
"TLS_FALLBACK_SCSV": tls.TLS_FALLBACK_SCSV, "TLS_FALLBACK_SCSV": tls.TLS_FALLBACK_SCSV,
} }
// CurveIDs is a Map of TLS elliptic curves from crypto/tls
// Available CurveIDs defined at https://godoc.org/crypto/tls#CurveID,
// also allowing rfc names defined at https://tools.ietf.org/html/rfc8446#section-4.2.7
CurveIDs = map[string]tls.CurveID{
`secp256r1`: tls.CurveP256,
`CurveP256`: tls.CurveP256,
`secp384r1`: tls.CurveP384,
`CurveP384`: tls.CurveP384,
`secp521r1`: tls.CurveP521,
`CurveP521`: tls.CurveP521,
`x25519`: tls.X25519,
`X25519`: tls.X25519,
}
) )
// Certificate holds a SSL cert/key pair // Certificate holds a SSL cert/key pair

View file

@ -16,11 +16,12 @@ type ClientAuth struct {
// 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"`
MaxVersion string `json:"maxVersion,omitempty" toml:"maxVersion,omitempty" yaml:"maxVersion,omitempty" export:"true"` MaxVersion string `json:"maxVersion,omitempty" toml:"maxVersion,omitempty" yaml:"maxVersion,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"`
ClientAuth ClientAuth `json:"clientAuth,omitempty" toml:"clientAuth,omitempty" yaml:"clientAuth,omitempty"` CurvePreferences []string `json:"curvePreferences,omitempty" toml:"curvePreferences,omitempty" yaml:"curvePreferences,omitempty"`
SniStrict bool `json:"sniStrict,omitempty" toml:"sniStrict,omitempty" yaml:"sniStrict,omitempty" export:"true"` ClientAuth ClientAuth `json:"clientAuth,omitempty" toml:"clientAuth,omitempty" yaml:"clientAuth,omitempty"`
SniStrict bool `json:"sniStrict,omitempty" toml:"sniStrict,omitempty" yaml:"sniStrict,omitempty" export:"true"`
} }
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true

View file

@ -211,7 +211,7 @@ func buildTLSConfig(tlsOption Options) (*tls.Config, error) {
} }
} }
// Set the minimum TLS version if set in the config TOML // Set the minimum TLS version if set in the config
if minConst, exists := MinVersion[tlsOption.MinVersion]; exists { if minConst, exists := MinVersion[tlsOption.MinVersion]; exists {
conf.PreferServerCipherSuites = true conf.PreferServerCipherSuites = true
conf.MinVersion = minConst conf.MinVersion = minConst
@ -223,7 +223,7 @@ func buildTLSConfig(tlsOption Options) (*tls.Config, error) {
conf.MaxVersion = maxConst conf.MaxVersion = maxConst
} }
// Set the list of CipherSuites if set in the config TOML // Set the list of CipherSuites if set in the config
if tlsOption.CipherSuites != nil { if tlsOption.CipherSuites != nil {
// if our list of CipherSuites is defined in the entryPoint config, we can re-initialize the suites list as empty // if our list of CipherSuites is defined in the entryPoint config, we can re-initialize the suites list as empty
conf.CipherSuites = make([]uint16, 0) conf.CipherSuites = make([]uint16, 0)
@ -237,6 +237,20 @@ func buildTLSConfig(tlsOption Options) (*tls.Config, error) {
} }
} }
// Set the list of CurvePreferences/CurveIDs if set in the config
if tlsOption.CurvePreferences != nil {
conf.CurvePreferences = make([]tls.CurveID, 0)
// if our list of CurvePreferences/CurveIDs is defined in the config, we can re-initialize the list as empty
for _, curve := range tlsOption.CurvePreferences {
if curveID, exists := CurveIDs[curve]; exists {
conf.CurvePreferences = append(conf.CurvePreferences, curveID)
} else {
// CurveID listed in the toml does not exist in our listed
return nil, fmt.Errorf("invalid CurveID in curvePreferences: %s", curve)
}
}
}
return conf, nil return conf, nil
} }

View file

@ -79,6 +79,11 @@ func (in *Options) DeepCopyInto(out *Options) {
*out = make([]string, len(*in)) *out = make([]string, len(*in))
copy(*out, *in) copy(*out, *in)
} }
if in.CurvePreferences != nil {
in, out := &in.CurvePreferences, &out.CurvePreferences
*out = make([]string, len(*in))
copy(*out, *in)
}
in.ClientAuth.DeepCopyInto(&out.ClientAuth) in.ClientAuth.DeepCopyInto(&out.ClientAuth)
return return
} }