Skip to content

Commit 428edb8

Browse files
authored
cmd/skipper: allow exclusion of insecure cipher suites (#3123)
Golang maintains a list of cipher suites considered insecure, which are still allowed if requested. This flag will allow those cipher suites to be completely excluded. Signed-off-by: Ricardo Herrera <[email protected]>
1 parent 02515fe commit 428edb8

File tree

4 files changed

+62
-0
lines changed

4 files changed

+62
-0
lines changed

config/config.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,9 @@ type Config struct {
219219
// TLS version
220220
TLSMinVersion string `yaml:"tls-min-version"`
221221

222+
// Exclude insecure cipher suites
223+
ExcludeInsecureCipherSuites bool `yaml:"exclude-insecure-cipher-suites"`
224+
222225
// TLS Config
223226
KubernetesEnableTLS bool `yaml:"kubernetes-enable-tls"`
224227

@@ -517,6 +520,9 @@ func NewConfig() *Config {
517520
// TLS version
518521
flag.StringVar(&cfg.TLSMinVersion, "tls-min-version", defaultMinTLSVersion, "minimal TLS Version to be used in server, proxy and client connections")
519522

523+
// Exclude insecure cipher suites
524+
flag.BoolVar(&cfg.ExcludeInsecureCipherSuites, "exclude-insecure-cipher-suites", false, "excludes insecure cipher suites")
525+
520526
// API Monitoring:
521527
flag.BoolVar(&cfg.ApiUsageMonitoringEnable, "enable-api-usage-monitoring", false, "enables the apiUsageMonitoring filter")
522528
flag.StringVar(&cfg.ApiUsageMonitoringRealmKeys, "api-usage-monitoring-realm-keys", "", "name of the property in the JWT payload that contains the authority realm")
@@ -715,6 +721,7 @@ func (c *Config) ToOptions() skipper.Options {
715721
DebugListener: c.DebugListener,
716722
CertPathTLS: c.CertPathTLS,
717723
KeyPathTLS: c.KeyPathTLS,
724+
CipherSuites: c.filterCipherSuites(),
718725
MaxLoopbacks: c.MaxLoopbacks,
719726
DefaultHTTPStatus: c.DefaultHTTPStatus,
720727
ReverseSourcePredicate: c.ReverseSourcePredicate,
@@ -1031,6 +1038,19 @@ func (c *Config) getMinTLSVersion() uint16 {
10311038
return tlsVersionTable[defaultMinTLSVersion]
10321039
}
10331040

1041+
func (c *Config) filterCipherSuites() []uint16 {
1042+
if !c.ExcludeInsecureCipherSuites {
1043+
return nil
1044+
}
1045+
1046+
cipherSuites := make([]uint16, 0)
1047+
for _, suite := range tls.CipherSuites() {
1048+
cipherSuites = append(cipherSuites, suite.ID)
1049+
}
1050+
1051+
return cipherSuites
1052+
}
1053+
10341054
func (c *Config) parseHistogramBuckets() ([]float64, error) {
10351055
if c.HistogramMetricBucketsString == "" {
10361056
return prometheus.DefBuckets, nil

config/config_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"os"
77
"reflect"
8+
"slices"
89
"strings"
910
"testing"
1011
"time"
@@ -174,6 +175,7 @@ func TestToOptions(t *testing.T) {
174175
c.ProxyPreserveHost = true // 4
175176
c.RemoveHopHeaders = true // 16
176177
c.RfcPatchPath = true // 32
178+
c.ExcludeInsecureCipherSuites = true
177179

178180
// config
179181
c.EtcdUrls = "127.0.0.1:5555"
@@ -231,6 +233,15 @@ func TestToOptions(t *testing.T) {
231233
if len(opt.EditRoute) != 1 {
232234
t.Errorf("Failed to get expected edit route: %s", c.EditRoute)
233235
}
236+
if opt.CipherSuites == nil {
237+
t.Errorf("Failed to get the filtered cipher suites")
238+
} else {
239+
for _, i := range tls.InsecureCipherSuites() {
240+
if slices.Contains(opt.CipherSuites, i.ID) {
241+
t.Errorf("Insecure cipher found in list: %s", i.Name)
242+
}
243+
}
244+
}
234245
}
235246

236247
func Test_Validate(t *testing.T) {
@@ -405,6 +416,23 @@ func TestMinTLSVersion(t *testing.T) {
405416
})
406417
}
407418

419+
func TestExcludeInsecureCipherSuites(t *testing.T) {
420+
421+
t.Run("test default", func(t *testing.T) {
422+
cfg := new(Config)
423+
if cfg.filterCipherSuites() != nil {
424+
t.Error("No cipher suites should be filtered by default")
425+
}
426+
})
427+
t.Run("test excluded insecure cipher suites", func(t *testing.T) {
428+
cfg := new(Config)
429+
cfg.ExcludeInsecureCipherSuites = true
430+
if cfg.filterCipherSuites() == nil {
431+
t.Error(`Failed to get list of filtered cipher suites`)
432+
}
433+
})
434+
}
435+
408436
type testFormatter struct {
409437
messages map[string]log.Level
410438
}

skipper.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,9 @@ type Options struct {
614614
// TLSMinVersion to set the minimal TLS version for all TLS configurations
615615
TLSMinVersion uint16
616616

617+
// CipherSuites sets the list of cipher suites to use for TLS 1.2
618+
CipherSuites []uint16
619+
617620
// Flush interval for upgraded Proxy connections
618621
BackendFlushInterval time.Duration
619622

@@ -1176,6 +1179,10 @@ func (o *Options) tlsConfig(cr *certregistry.CertRegistry) (*tls.Config, error)
11761179
MinVersion: o.TLSMinVersion,
11771180
}
11781181

1182+
if o.CipherSuites != nil {
1183+
config.CipherSuites = o.CipherSuites
1184+
}
1185+
11791186
if cr != nil {
11801187
config.GetCertificate = cr.GetCertFromHello
11811188
}

skipper_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,13 @@ func TestOptionsTLSConfig(t *testing.T) {
186186
require.NoError(t, err)
187187
require.Equal(t, uint16(tls.VersionTLS13), c.MinVersion)
188188
require.Equal(t, []tls.Certificate{cert, cert2}, c.Certificates)
189+
190+
// TLS Cipher Suites
191+
o = &Options{CipherSuites: []uint16{1}}
192+
c, err = o.tlsConfig(cr)
193+
require.NoError(t, err)
194+
assert.Equal(t, len(c.CipherSuites), 1)
195+
189196
}
190197

191198
func TestOptionsTLSConfigInvalidPaths(t *testing.T) {

0 commit comments

Comments
 (0)