Skip to content

Commit

Permalink
feature: operator's metrics server enforce TLS Security Profile
Browse files Browse the repository at this point in the history
Signed-off-by: Haoyu Sun <[email protected]>
  • Loading branch information
raptorsun committed Oct 18, 2024
1 parent cd24a01 commit b6436fb
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 1 deletion.
31 changes: 30 additions & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,15 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log/zap"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"

configv1 "github.com/openshift/api/config/v1"
monv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"

olsv1alpha1 "github.com/openshift/lightspeed-operator/api/v1alpha1"

"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/openshift/lightspeed-operator/internal/controller"
utiltls "github.com/openshift/lightspeed-operator/internal/tls"
//+kubebuilder:scaffold:imports
)

Expand All @@ -71,6 +73,7 @@ func init() {
utilruntime.Must(consolev1.AddToScheme(scheme))
utilruntime.Must(openshiftv1.AddToScheme(scheme))
utilruntime.Must(monv1.AddToScheme(scheme))
utilruntime.Must(configv1.AddToScheme(scheme))

utilruntime.Must(olsv1alpha1.AddToScheme(scheme))
//+kubebuilder:scaffold:scheme
Expand Down Expand Up @@ -145,14 +148,15 @@ func main() {
setupLog.Info("Images setting loaded", "images", listImages())
setupLog.Info("Starting the operator", "metricsAddr", metricsAddr, "probeAddr", probeAddr, "reconcilerIntervalMinutes", reconcilerIntervalMinutes, "certDir", certDir, "certName", certName, "keyName", keyName)

var tlsSecurityProfileSpec configv1.TLSProfileSpec
if secureMetricsServer {
cfg, err := config.GetConfig()
if err != nil {
setupLog.Error(err, "unable to get Kubernetes config")
os.Exit(1)
}

k8sClient, err := client.New(cfg, client.Options{})
k8sClient, err := client.New(cfg, client.Options{Scheme: scheme})
if err != nil {
setupLog.Error(err, "unable to create Kubernetes client")
os.Exit(1)
Expand All @@ -171,6 +175,25 @@ func main() {
setupLog.Error(err, fmt.Sprintf("the key %s is not found in %s/%s configmap.", controller.ClientCACertKey, controller.ClientCACmNamespace, controller.ClientCACmName))
os.Exit(1)
}

olsconfig := &olsv1alpha1.OLSConfig{}
err = k8sClient.Get(ctx, types.NamespacedName{Name: controller.OLSConfigName}, olsconfig)
if err != nil && client.IgnoreNotFound(err) != nil {
setupLog.Error(err, fmt.Sprintf("failed to get %s OLSConfig.", controller.OLSConfigName))
os.Exit(1)
}
if olsconfig.Spec.OLSConfig.TLSSecurityProfile != nil {
tlsSecurityProfileSpec = utiltls.GetTLSProfileSpec(olsconfig.Spec.OLSConfig.TLSSecurityProfile)
} else {
setupLog.Info("TLS profile is not defined in OLSConfig, fetch from API server")
profileAPIServer, err := utiltls.FetchAPIServerTlsProfile(k8sClient)
if err != nil {
setupLog.Error(err, "unable to get TLS profile from API server")
os.Exit(1)
}
tlsSecurityProfileSpec = utiltls.GetTLSProfileSpec(profileAPIServer)
}

}

metricsTLSSetup := func(tlsConf *tls.Config) {
Expand All @@ -180,6 +203,12 @@ func main() {
tlsConf.ClientCAs = x509.NewCertPool()
tlsConf.ClientCAs.AppendCertsFromPEM([]byte(metricsClientCA))
tlsConf.ClientAuth = tls.RequireAndVerifyClientCert
tlsConf.MinVersion = utiltls.VersionCode(configv1.TLSProtocolVersion(utiltls.MinTLSVersion(tlsSecurityProfileSpec)))
ciphers, unsupportedCiphers := utiltls.CipherCodes(utiltls.TLSCiphers(tlsSecurityProfileSpec))
tlsConf.CipherSuites = ciphers
if len(unsupportedCiphers) > 0 {
setupLog.Info("TLS setup for metrics server contains unsupported ciphers", "unsupportedCiphers", unsupportedCiphers)
}
}

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Expand Down
71 changes: 71 additions & 0 deletions internal/tls/tls_security_profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tls

import (
"context"
"crypto/tls"

configv1 "github.com/openshift/api/config/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -48,6 +49,76 @@ func MinTLSVersion(profile configv1.TLSProfileSpec) string {
return string(profile.MinTLSVersion)
}

// VersionName returns the code for the provided TLS version name
func VersionCode(version configv1.TLSProtocolVersion) uint16 {
switch version {
case configv1.VersionTLS10:
return tls.VersionTLS10
case configv1.VersionTLS11:
return tls.VersionTLS11
case configv1.VersionTLS12:
return tls.VersionTLS12
case configv1.VersionTLS13:
return tls.VersionTLS13
default:
defaultProfile := configv1.TLSProfiles[DefaultTLSProfileType]
return VersionCode(defaultProfile.MinTLSVersion)
}
}

var CiphersToCodes = map[string]uint16{
"TLS_AES_128_GCM_SHA256": tls.TLS_AES_128_GCM_SHA256,
"TLS_AES_256_GCM_SHA384": tls.TLS_AES_256_GCM_SHA384,
"TLS_CHACHA20_POLY1305_SHA256": tls.TLS_CHACHA20_POLY1305_SHA256,
"ECDHE-ECDSA-AES128-GCM-SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
"ECDHE-RSA-AES128-GCM-SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
"ECDHE-ECDSA-AES256-GCM-SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
"ECDHE-RSA-AES256-GCM-SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
"ECDHE-ECDSA-CHACHA20-POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
"ECDHE-RSA-CHACHA20-POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
"ECDHE-ECDSA-AES128-SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
"ECDHE-RSA-AES128-SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
"ECDHE-ECDSA-AES128-SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
"ECDHE-RSA-AES128-SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
"ECDHE-ECDSA-AES256-SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
"ECDHE-RSA-AES256-SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
"ECDHE-ECDSA-AES256-SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
"ECDHE-RSA-AES256-SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
"AES128-GCM-SHA256": tls.TLS_AES_128_GCM_SHA256,
"AES256-GCM-SHA384": tls.TLS_AES_256_GCM_SHA384,
"AES128-SHA256": tls.TLS_AES_128_GCM_SHA256,
// Please refer to https://pkg.go.dev/crypto/tls#pkg-constants for more information.
// These ciphers are not supported by Go's TLS implementation:
// "DHE-RSA-AES128-GCM-SHA256",
// "DHE-RSA-AES256-GCM-SHA384",
// "DHE-RSA-CHACHA20-POLY1305",
// "DHE-RSA-AES128-SHA256",
// "DHE-RSA-AES256-SHA256",
// "AES256-SHA256",
// "AES128-SHA",
// "AES256-SHA",
// "DES-CBC3-SHA".
}

func CipherCode(cipher string) uint16 {
if code, ok := CiphersToCodes[cipher]; ok {
return code
}
return 0
}

func CipherCodes(ciphers []string) (cipherCodes []uint16, unsupportedCiphers []string) {
for _, cipher := range ciphers {
code := CipherCode(cipher)
if code == 0 {
unsupportedCiphers = append(unsupportedCiphers, cipher)
continue
}
cipherCodes = append(cipherCodes, code)
}
return cipherCodes, unsupportedCiphers
}

// GetTLSProfileSpec returns TLSProfileSpec
func GetTLSProfileSpec(profile *configv1.TLSSecurityProfile) configv1.TLSProfileSpec {
defaultProfile := *configv1.TLSProfiles[DefaultTLSProfileType]
Expand Down

0 comments on commit b6436fb

Please sign in to comment.