Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release-4.6] Bug 1918281: *: ensure etcd listens on strong ciphers #526

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 29 additions & 0 deletions pkg/etcdenvvar/etcd_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import (
"github.com/openshift/cluster-etcd-operator/pkg/operator/ceohelpers"
"github.com/openshift/cluster-etcd-operator/pkg/operator/operatorclient"

configv1 "github.com/openshift/api/config/v1"
operatorv1 "github.com/openshift/api/operator/v1"
configv1listers "github.com/openshift/client-go/config/listers/config/v1"
"github.com/openshift/library-go/pkg/crypto"
"go.etcd.io/etcd/pkg/tlsutil"
corev1listers "k8s.io/client-go/listers/core/v1"
"k8s.io/klog/v2"
)

type envVarContext struct {
Expand All @@ -30,6 +34,7 @@ var FixedEtcdEnvVars = map[string]string{
"ETCD_QUOTA_BACKEND_BYTES": "7516192768", // 7 gig
"ETCD_INITIAL_CLUSTER_STATE": "existing",
"ETCD_ENABLE_PPROF": "true",
"ETCD_CIPHER_SUITES": getDefaultCipherSuites(),
}

type envVarFunc func(envVarContext envVarContext) (map[string]string, error)
Expand Down Expand Up @@ -273,3 +278,27 @@ func getUnsupportedArch(envVarContext envVarContext) (map[string]string, error)
"ETCD_UNSUPPORTED_ARCH": arch,
}, nil
}

//TODO replace with TLS security policy observer
func getDefaultCipherSuites() string {
profileSpec := configv1.TLSProfiles[configv1.TLSProfileIntermediateType]
// whitelist ciphers for use with etcd
cipherSuites := whitelistEtcdCipherSuites(crypto.OpenSSLToIANACipherSuites(profileSpec.Ciphers))
return strings.Join(cipherSuites, ",")
}

// whitelistEtcdCipherSuites ensures ciphers are valid for use with etcd.
// TODO move upstream
func whitelistEtcdCipherSuites(cipherSuites []string) []string {
whitelist := []string{}
for _, cipher := range cipherSuites {
_, ok := tlsutil.GetCipherSuite(cipher)
if !ok {
// skip and log unsupported ciphers
klog.Warningf("cipher is not supported for use with etcd: %q", cipher)
continue
}
whitelist = append(whitelist, cipher)
}
return whitelist
}
40 changes: 40 additions & 0 deletions pkg/etcdenvvar/etcd_env_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package etcdenvvar

import (
"reflect"
"testing"

configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/library-go/pkg/crypto"
)

// TestWhitelistEtcdCipherSuites this test is intended to ensure the ciphers we support is explicitly understood overtime.
// As etcd minor versions increment golang versions will as well, so this test will need to be maintained against changes
// to the etcd whitelist[1] and or TLSProfileIntermediateType.
//[1] https://github.com/etcd-io/etcd/blob/release-3.4/pkg/tlsutil/cipher_suites.go
func TestWhitelistEtcdCipherSuites(t *testing.T) {
tests := []struct {
name string
ciphers []string
want []string
}{
{
name: "test TLS v1.2 (current supported runtime)",
ciphers: crypto.OpenSSLToIANACipherSuites(configv1.TLSProfiles[configv1.TLSProfileIntermediateType].Ciphers),
want: []string{
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // https://ciphersuite.info/cs/TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256/
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", // https://ciphersuite.info/cs/TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256/
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", // https://ciphersuite.info/cs/TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384/
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", // https://ciphersuite.info/cs/TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384/
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := whitelistEtcdCipherSuites(test.ciphers)
if !reflect.DeepEqual(test.want, got) {
t.Errorf("want %v got %v", test.want, got)
}
})
}
}