Skip to content

Commit

Permalink
Add Setting: SSL Parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
John Liu authored and johnliu55tw committed Dec 7, 2021
1 parent 140adb5 commit ee09e0c
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 0 deletions.
1 change: 1 addition & 0 deletions pkg/controller/master/setting/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func Register(ctx context.Context, management *config.Management, options config
"vip-pools": controller.syncVipPoolsConfig,
"auto-disk-provision-paths": controller.syncNDMAutoProvisionPaths,
"ssl-certificates": controller.syncSSLCertificate,
"ssl-parameters": controller.syncSSLParameters,
}

settings.OnChange(ctx, controllerName, controller.settingOnChanged)
Expand Down
64 changes: 64 additions & 0 deletions pkg/controller/master/setting/ssl_parameters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package setting

import (
"encoding/json"

"github.com/rancher/wrangler/pkg/data"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"

harvesterv1 "github.com/harvester/harvester/pkg/apis/harvesterhci.io/v1beta1"
"github.com/harvester/harvester/pkg/settings"
"github.com/harvester/harvester/pkg/util"
)

func (h *Handler) syncSSLParameters(setting *harvesterv1.Setting) error {
sslParameter := &settings.SSLParameter{}
value := setting.Value
if value == "" {
value = setting.Default
}
if err := json.Unmarshal([]byte(value), sslParameter); err != nil {
return err
}

return h.updateSSLParameters(sslParameter)
}

func (h *Handler) updateSSLParameters(sslParameter *settings.SSLParameter) error {
logrus.Infof("Update SSL Parameters: Ciphers: %s, Protocols: %s", sslParameter.Ciphers, sslParameter.Protocols)

helmChartConfig, err := h.helmChartConfigCache.Get(util.KubeSystemNamespace, util.Rke2IngressNginxAppName)
if err != nil {
return err
}
toUpdateHelmChartConfig := helmChartConfig.DeepCopy()

var values = make(map[string]interface{})
if err := yaml.Unmarshal([]byte(helmChartConfig.Spec.ValuesContent), &values); err != nil {
return err
}

if sslParameter.Ciphers == "" {
data.RemoveValue(values, "controller", "config", "ssl-ciphers")
} else {
data.PutValue(values, sslParameter.Ciphers, "controller", "config", "ssl-ciphers")
}
if sslParameter.Protocols == "" {
data.RemoveValue(values, "controller", "config", "ssl-protocols")
} else {
data.PutValue(values, sslParameter.Protocols, "controller", "config", "ssl-protocols")
}

newValuesContent, err := yaml.Marshal(values)
if err != nil {
return err
}

toUpdateHelmChartConfig.Spec.ValuesContent = string(newValuesContent)
if _, err := h.helmChartConfigs.Update(toUpdateHelmChartConfig); err != nil {
return err
}

return nil
}
7 changes: 7 additions & 0 deletions pkg/settings/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var (
UpgradeCheckerURL = NewSetting("upgrade-checker-url", "https://harvester-upgrade-responder.rancher.io/v1/checkupgrade")
LogLevel = NewSetting("log-level", "info") // options are info, debug and trace
SSLCertificates = NewSetting(SSLCertificatesSettingName, "{}")
SSLParameters = NewSetting(SSLParametersName, "{}")
SupportBundleImage = NewSetting("support-bundle-image", "rancher/support-bundle-kit:v0.0.4")
SupportBundleImagePullPolicy = NewSetting("support-bundle-image-pull-policy", "IfNotPresent")
SupportBundleTimeout = NewSetting(SupportBundleTimeoutSettingName, "10") // Unit is minute. 0 means disable timeout.
Expand All @@ -49,6 +50,7 @@ const (
HttpProxySettingName = "http-proxy"
OvercommitConfigSettingName = "overcommit-config"
SSLCertificatesSettingName = "ssl-certificates"
SSLParametersName = "ssl-parameters"
VipPoolsConfigSettingName = "vip-pools"
DefaultDashboardUIURL = "https://releases.rancher.com/harvester-ui/dashboard/latest/index.html"
)
Expand Down Expand Up @@ -225,3 +227,8 @@ type SSLCertificate struct {
PublicCertificate string `json:"publicCertificate"`
PrivateKey string `json:"privateKey"`
}

type SSLParameter struct {
Protocols string `json:"protocols"`
Ciphers string `json:"ciphers"`
}
52 changes: 52 additions & 0 deletions pkg/webhook/resources/setting/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import (
"net/url"
"os"
"strconv"
"strings"

"github.com/longhorn/backupstore"
_ "github.com/longhorn/backupstore/nfs"
_ "github.com/longhorn/backupstore/s3"
"github.com/rancher/wrangler/pkg/slice"
"golang.org/x/net/http/httpproxy"
admissionregv1 "k8s.io/api/admissionregistration/v1"
"k8s.io/apimachinery/pkg/runtime"
Expand All @@ -30,6 +32,11 @@ import (

var certs = getSystemCerts()

// See supported TLS protocols of ingress-nginx and Nginx.
// - https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#ssl-protocols
// - http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_protocols
var supportedSSLProtocols = []string{"SSLv2", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"}

type validateSettingFunc func(setting *v1beta1.Setting) error

var validateSettingFuncs = map[string]validateSettingFunc{
Expand All @@ -39,6 +46,7 @@ var validateSettingFuncs = map[string]validateSettingFunc{
settings.OvercommitConfigSettingName: validateOvercommitConfig,
settings.VipPoolsConfigSettingName: validateVipPoolsConfig,
settings.SSLCertificatesSettingName: validateSSLCertificates,
settings.SSLParametersName: validateSSLParameters,
}

func NewValidator(settingCache ctlv1beta1.SettingCache) types.Validator {
Expand Down Expand Up @@ -276,6 +284,50 @@ func validateSSLCertificates(setting *v1beta1.Setting) error {
return nil
}

func validateSSLParameters(setting *v1beta1.Setting) error {
if setting.Value == "" {
return nil
}

sslParameter := &settings.SSLParameter{}
if err := json.Unmarshal([]byte(setting.Value), sslParameter); err != nil {
return werror.NewInvalidError(err.Error(), "value")
}

if sslParameter.Protocols == "" && sslParameter.Ciphers == "" {
return nil
}

if err := validateSSLProtocols(sslParameter); err != nil {
return werror.NewInvalidError(err.Error(), "protocols")
}

// TODO: Validate ciphers
// Currently, there's no easy way to actually tell what Ciphers are supported by rke2-ingress-nginx,
// we need to tell users where to look for ciphers in docs.
return nil
}

func validateSSLProtocols(param *settings.SSLParameter) error {
if param.Protocols == "" {
return nil
}

for _, given := range strings.Split(param.Protocols, " ") {
// Deal with multiple spaces between words e.g. "TLSv1.1 TLSv1.2"
// ingress-nginx supports this so we also support it
if len(given) == 0 {
continue
}

if !slice.ContainsString(supportedSSLProtocols, given) {
return fmt.Errorf("unsupported SSL protocol: %s", given)
}
}

return nil
}

func getSystemCerts() *x509.CertPool {
certs, _ := x509.SystemCertPool()
if certs == nil {
Expand Down
50 changes: 50 additions & 0 deletions pkg/webhook/resources/setting/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,53 @@ func Test_validateSupportBundleTimeout(t *testing.T) {
})
}
}

func Test_validateSSLProtocols(t *testing.T) {
tests := []struct {
name string
args *settings.SSLParameter
expectedErr bool
}{
{
name: "Supported protocol 'TLSv1.2'",
args: &settings.SSLParameter{Protocols: "TLSv1.2"},
expectedErr: false,
},
{
name: "Unsupported protocol 'MyTLSv99.9'",
args: &settings.SSLParameter{Protocols: "MyTLSv99.9"},
expectedErr: true,
},
{
name: "A list of supported protocols separated by whitespace",
args: &settings.SSLParameter{Protocols: "TLSv1.1 TLSv1.2"},
expectedErr: false,
},
{
name: "A list of supported protocols separated by multiple whitespace",
args: &settings.SSLParameter{Protocols: " TLSv1.1 TLSv1.2 "},
expectedErr: false,
},
{
name: "One unsupported protocol in a list",
args: &settings.SSLParameter{Protocols: "TLSv1.2 TLSv1.1 MyTLSv99.9"},
expectedErr: true,
},
{
name: "Protocols separate by characters other than whitespace is invalid",
args: &settings.SSLParameter{Protocols: "TLSv1.1,TLSv1.2,TLSv1.3"},
expectedErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validateSSLProtocols(tt.args)
if tt.expectedErr {
assert.Error(t, err)
} else {
assert.Nil(t, err)
}
})
}
}

0 comments on commit ee09e0c

Please sign in to comment.