From e6a50f430d205b357825278a9d778d6434ea8c3a Mon Sep 17 00:00:00 2001 From: Cavaughn Browne Date: Tue, 21 Mar 2023 20:53:02 -0500 Subject: [PATCH] add validation that checks if the OS is valid for the provided registry mirror configuration --- .../anywhere.eks.amazonaws.com_clusters.yaml | 3 +- config/manifest/eksa-components.yaml | 3 +- pkg/api/v1alpha1/cluster.go | 9 -- pkg/api/v1alpha1/cluster_test.go | 16 ---- pkg/api/v1alpha1/cluster_types.go | 1 - pkg/registrymirror/registrymirror.go | 1 - pkg/validations/cluster.go | 22 +++++ pkg/validations/cluster_test.go | 93 +++++++++++++++++++ .../createvalidations/preflightvalidations.go | 7 ++ .../preflightvalidations.go | 7 ++ 10 files changed, 131 insertions(+), 31 deletions(-) diff --git a/config/crd/bases/anywhere.eks.amazonaws.com_clusters.yaml b/config/crd/bases/anywhere.eks.amazonaws.com_clusters.yaml index 9a9f2ca106e6..018a1d526c51 100644 --- a/config/crd/bases/anywhere.eks.amazonaws.com_clusters.yaml +++ b/config/crd/bases/anywhere.eks.amazonaws.com_clusters.yaml @@ -346,8 +346,7 @@ spec: insecureSkipVerify: description: InsecureSkipVerify skips the registry certificate verification. Only use this solution for isolated testing or - in a tightly controlled, air-gapped environment. Currently only - supported for snow provider + in a tightly controlled, air-gapped environment. type: boolean ociNamespaces: description: OCINamespaces defines the mapping from an upstream diff --git a/config/manifest/eksa-components.yaml b/config/manifest/eksa-components.yaml index dbfefee2e04c..22d7b4528c1f 100644 --- a/config/manifest/eksa-components.yaml +++ b/config/manifest/eksa-components.yaml @@ -3917,8 +3917,7 @@ spec: insecureSkipVerify: description: InsecureSkipVerify skips the registry certificate verification. Only use this solution for isolated testing or - in a tightly controlled, air-gapped environment. Currently only - supported for snow provider + in a tightly controlled, air-gapped environment. type: boolean ociNamespaces: description: OCINamespaces defines the mapping from an upstream diff --git a/pkg/api/v1alpha1/cluster.go b/pkg/api/v1alpha1/cluster.go index 0533e997299f..3f38aa5ec626 100644 --- a/pkg/api/v1alpha1/cluster.go +++ b/pkg/api/v1alpha1/cluster.go @@ -723,15 +723,6 @@ func validateMirrorConfig(clusterConfig *Cluster) error { return fmt.Errorf("registry mirror port %s is invalid, please provide a valid port", clusterConfig.Spec.RegistryMirrorConfiguration.Port) } - if clusterConfig.Spec.RegistryMirrorConfiguration.InsecureSkipVerify { - switch clusterConfig.Spec.DatacenterRef.Kind { - case DockerDatacenterKind, NutanixDatacenterKind, VSphereDatacenterKind, TinkerbellDatacenterKind, CloudStackDatacenterKind, SnowDatacenterKind: - break - default: - return fmt.Errorf("insecureSkipVerify is only supported for docker, nutanix, snow, tinkerbell, cloudstack and vsphere providers") - } - } - mirrorCount := 0 ociNamespaces := clusterConfig.Spec.RegistryMirrorConfiguration.OCINamespaces for _, ociNamespace := range ociNamespaces { diff --git a/pkg/api/v1alpha1/cluster_test.go b/pkg/api/v1alpha1/cluster_test.go index 511e8753b02b..b15d07394787 100644 --- a/pkg/api/v1alpha1/cluster_test.go +++ b/pkg/api/v1alpha1/cluster_test.go @@ -2571,22 +2571,6 @@ func TestValidateMirrorConfig(t *testing.T) { }, }, }, - { - name: "insecureSkipVerify on an unsupported provider", - wantErr: "insecureSkipVerify is only supported for docker, nutanix, snow, tinkerbell, cloudstack and vsphere providers", - cluster: &Cluster{ - Spec: ClusterSpec{ - RegistryMirrorConfiguration: &RegistryMirrorConfiguration{ - Endpoint: "1.2.3.4", - Port: "443", - InsecureSkipVerify: true, - }, - DatacenterRef: Ref{ - Kind: "nonsnow", - }, - }, - }, - }, { name: "insecureSkipVerify on snow provider", wantErr: "", diff --git a/pkg/api/v1alpha1/cluster_types.go b/pkg/api/v1alpha1/cluster_types.go index 6004a915b606..23366c464ab6 100644 --- a/pkg/api/v1alpha1/cluster_types.go +++ b/pkg/api/v1alpha1/cluster_types.go @@ -174,7 +174,6 @@ type RegistryMirrorConfiguration struct { // InsecureSkipVerify skips the registry certificate verification. // Only use this solution for isolated testing or in a tightly controlled, air-gapped environment. - // Currently only supported for snow provider InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"` } diff --git a/pkg/registrymirror/registrymirror.go b/pkg/registrymirror/registrymirror.go index 1726de7b971b..3fc7bb9e8aad 100644 --- a/pkg/registrymirror/registrymirror.go +++ b/pkg/registrymirror/registrymirror.go @@ -23,7 +23,6 @@ type RegistryMirror struct { CACertContent string // InsecureSkipVerify skips the registry certificate verification. // Only use this solution for isolated testing or in a tightly controlled, air-gapped environment. - // Currently only supported for snow provider InsecureSkipVerify bool } diff --git a/pkg/validations/cluster.go b/pkg/validations/cluster.go index 7c40317fe0d6..2e7b83716726 100644 --- a/pkg/validations/cluster.go +++ b/pkg/validations/cluster.go @@ -2,6 +2,7 @@ package validations import ( "context" + "errors" "fmt" "github.com/aws/eks-anywhere/pkg/api/v1alpha1" @@ -9,9 +10,30 @@ import ( "github.com/aws/eks-anywhere/pkg/config" "github.com/aws/eks-anywhere/pkg/features" "github.com/aws/eks-anywhere/pkg/logger" + "github.com/aws/eks-anywhere/pkg/providers" "github.com/aws/eks-anywhere/pkg/types" ) +// ValidateOSForRegistryMirror checks if the OS is valid for the provided registry mirror configuration. +func ValidateOSForRegistryMirror(clusterSpec *cluster.Spec, provider providers.Provider) error { + cluster := clusterSpec.Cluster + if cluster.Spec.RegistryMirrorConfiguration == nil { + return nil + } + + machineConfigs := provider.MachineConfigs(clusterSpec) + if !cluster.Spec.RegistryMirrorConfiguration.InsecureSkipVerify || machineConfigs == nil { + return nil + } + + for _, mc := range machineConfigs { + if mc.OSFamily() == v1alpha1.Bottlerocket { + return errors.New("InsecureSkipVerify is not supported for bottlerocket") + } + } + return nil +} + func ValidateCertForRegistryMirror(clusterSpec *cluster.Spec, tlsValidator TlsValidator) error { cluster := clusterSpec.Cluster if cluster.Spec.RegistryMirrorConfiguration == nil { diff --git a/pkg/validations/cluster_test.go b/pkg/validations/cluster_test.go index d912facede82..a10c9f61789b 100644 --- a/pkg/validations/cluster_test.go +++ b/pkg/validations/cluster_test.go @@ -15,6 +15,8 @@ import ( "github.com/aws/eks-anywhere/pkg/cluster" "github.com/aws/eks-anywhere/pkg/constants" "github.com/aws/eks-anywhere/pkg/features" + "github.com/aws/eks-anywhere/pkg/providers" + providermocks "github.com/aws/eks-anywhere/pkg/providers/mocks" "github.com/aws/eks-anywhere/pkg/types" "github.com/aws/eks-anywhere/pkg/validations" "github.com/aws/eks-anywhere/pkg/validations/mocks" @@ -25,6 +27,7 @@ type clusterTest struct { *WithT tlsValidator *mocks.MockTlsValidator kubectl *mocks.MockKubectlClient + provider *providermocks.MockProvider clusterSpec *cluster.Spec certContent string host, port string @@ -33,9 +36,11 @@ type clusterTest struct { type clusterTestOpt func(t *testing.T, ct *clusterTest) func newTest(t *testing.T, opts ...clusterTestOpt) *clusterTest { + ctrl := gomock.NewController(t) cTest := &clusterTest{ WithT: NewWithT(t), clusterSpec: test.NewClusterSpec(), + provider: providermocks.NewMockProvider(ctrl), } for _, opt := range opts { opt(t, cTest) @@ -153,6 +158,94 @@ func TestValidateAuthenticationForRegistryMirrorAuthValid(t *testing.T) { tt.Expect(validations.ValidateAuthenticationForRegistryMirror(tt.clusterSpec)).To(Succeed()) } +func TestValidateOSForRegistryMirrorNoRegistryMirror(t *testing.T) { + tt := newTest(t, withTLS()) + tt.clusterSpec.Cluster.Spec.RegistryMirrorConfiguration = nil + tt.Expect(validations.ValidateOSForRegistryMirror(tt.clusterSpec, tt.provider)).To(Succeed()) +} + +func TestValidateOSForRegistryMirrorInsecureSkipVerifyDisabled(t *testing.T) { + tt := newTest(t, withTLS()) + tt.clusterSpec.Cluster.Spec.RegistryMirrorConfiguration.InsecureSkipVerify = false + tt.provider.EXPECT().MachineConfigs(tt.clusterSpec).Return([]providers.MachineConfig{}) + tt.Expect(validations.ValidateOSForRegistryMirror(tt.clusterSpec, tt.provider)).To(Succeed()) +} + +func TestValidateOSForRegistryMirrorInsecureSkipVerifyEnabled(t *testing.T) { + tests := []struct { + name string + mirrorConfig *anywherev1.RegistryMirrorConfiguration + machineConfigs func() []providers.MachineConfig + wantErr string + }{ + { + name: "insecureSkipVerify no machine configs", + machineConfigs: func() []providers.MachineConfig { + return nil + }, + wantErr: "", + }, + { + name: "insecureSkipVerify on provider with ubuntu", + machineConfigs: func() []providers.MachineConfig { + configs := make([]providers.MachineConfig, 0, 1) + configs = append(configs, &anywherev1.VSphereMachineConfig{ + Spec: anywherev1.VSphereMachineConfigSpec{ + OSFamily: anywherev1.Ubuntu, + }, + }) + return configs + }, + wantErr: "", + }, + { + name: "insecureSkipVerify on provider with bottlerocket", + machineConfigs: func() []providers.MachineConfig { + configs := make([]providers.MachineConfig, 0, 1) + configs = append(configs, &anywherev1.SnowMachineConfig{ + Spec: anywherev1.SnowMachineConfigSpec{ + OSFamily: anywherev1.Bottlerocket, + }, + }) + return configs + }, + wantErr: "InsecureSkipVerify is not supported for bottlerocket", + }, + { + name: "insecureSkipVerify on provider with redhat", + machineConfigs: func() []providers.MachineConfig { + configs := make([]providers.MachineConfig, 0, 1) + configs = append(configs, &anywherev1.VSphereMachineConfig{ + Spec: anywherev1.VSphereMachineConfigSpec{ + OSFamily: anywherev1.RedHat, + }, + }) + return configs + }, + wantErr: "", + }, + } + + validationTest := newTest(t, func(t *testing.T, ct *clusterTest) { + ct.clusterSpec = test.NewClusterSpec(func(s *cluster.Spec) { + s.Cluster.Spec.RegistryMirrorConfiguration = &anywherev1.RegistryMirrorConfiguration{ + InsecureSkipVerify: true, + } + }) + }) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + validationTest.provider.EXPECT().MachineConfigs(validationTest.clusterSpec).Return(test.machineConfigs()) + err := validations.ValidateOSForRegistryMirror(validationTest.clusterSpec, validationTest.provider) + if test.wantErr != "" { + validationTest.Expect(err).To(MatchError(test.wantErr)) + } else { + validationTest.Expect(err).To(BeNil()) + } + }) + } +} + func TestValidateManagementClusterNameValid(t *testing.T) { mgmtName := "test" tt := newTest(t, withKubectl()) diff --git a/pkg/validations/createvalidations/preflightvalidations.go b/pkg/validations/createvalidations/preflightvalidations.go index b54c35eb16c9..d83190ae8be1 100644 --- a/pkg/validations/createvalidations/preflightvalidations.go +++ b/pkg/validations/createvalidations/preflightvalidations.go @@ -21,6 +21,13 @@ func (v *CreateValidations) PreflightValidations(ctx context.Context) []validati } createValidations := []validations.Validation{ + func() *validations.ValidationResult { + return &validations.ValidationResult{ + Name: "validate OS is compatible with registry mirror configuration", + Remediation: "please use a valid OS for your registry mirror configuration", + Err: validations.ValidateOSForRegistryMirror(v.Opts.Spec, v.Opts.Provider), + } + }, func() *validations.ValidationResult { return &validations.ValidationResult{ Name: "validate certificate for registry mirror", diff --git a/pkg/validations/upgradevalidations/preflightvalidations.go b/pkg/validations/upgradevalidations/preflightvalidations.go index 639701479b2b..d123cf479b3b 100644 --- a/pkg/validations/upgradevalidations/preflightvalidations.go +++ b/pkg/validations/upgradevalidations/preflightvalidations.go @@ -22,6 +22,13 @@ func (u *UpgradeValidations) PreflightValidations(ctx context.Context) []validat KubeconfigFile: u.Opts.ManagementCluster.KubeconfigFile, } upgradeValidations := []validations.Validation{ + func() *validations.ValidationResult { + return &validations.ValidationResult{ + Name: "validate OS is compatible with registry mirror configuration", + Remediation: "please use a valid OS for your registry mirror configuration", + Err: validations.ValidateOSForRegistryMirror(u.Opts.Spec, u.Opts.Provider), + } + }, func() *validations.ValidationResult { return &validations.ValidationResult{ Name: "validate certificate for registry mirror",