diff --git a/pkg/handlers/generic/mutation/mirrors/containerd_files.go b/pkg/handlers/generic/mutation/mirrors/containerd_files.go index 9e6aece96..16f3bf1bf 100644 --- a/pkg/handlers/generic/mutation/mirrors/containerd_files.go +++ b/pkg/handlers/generic/mutation/mirrors/containerd_files.go @@ -19,7 +19,7 @@ import ( const ( containerdHostsConfigurationOnRemote = "/etc/containerd/certs.d/_default/hosts.toml" - secretKeyForMirrorCACert = "ca.crt" + secretKeyForCACert = "ca.crt" ) var ( @@ -159,7 +159,7 @@ func generateRegistryCACertFiles( ContentFrom: &cabpkv1.FileSource{ Secret: cabpkv1.SecretFileSource{ Name: config.CASecretName, - Key: secretKeyForMirrorCACert, + Key: secretKeyForCACert, }, }, }) diff --git a/pkg/handlers/generic/mutation/mirrors/inject.go b/pkg/handlers/generic/mutation/mirrors/inject.go index 095246071..8eead175b 100644 --- a/pkg/handlers/generic/mutation/mirrors/inject.go +++ b/pkg/handlers/generic/mutation/mirrors/inject.go @@ -7,6 +7,7 @@ import ( "context" "fmt" + corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -193,9 +194,9 @@ func containerdConfigFromGlobalMirror( ) } - if secret != nil { + if secretHasCACert(secret) { configWithOptionalCACert.CASecretName = secret.Name - configWithOptionalCACert.CACert = string(secret.Data[secretKeyForMirrorCACert]) + configWithOptionalCACert.CACert = string(secret.Data[secretKeyForCACert]) } return configWithOptionalCACert, nil @@ -225,9 +226,9 @@ func containerdConfigFromImageRegistry( ) } - if secret != nil { + if secretHasCACert(secret) { configWithOptionalCACert.CASecretName = secret.Name - configWithOptionalCACert.CACert = string(secret.Data[secretKeyForMirrorCACert]) + configWithOptionalCACert.CACert = string(secret.Data[secretKeyForCACert]) } return configWithOptionalCACert, nil @@ -271,3 +272,12 @@ func needContainerdConfiguration(configs []containerdConfig) bool { return false } + +func secretHasCACert(secret *corev1.Secret) bool { + if secret == nil { + return false + } + + _, ok := secret.Data[secretKeyForCACert] + return ok +} diff --git a/pkg/handlers/generic/mutation/mirrors/inject_test.go b/pkg/handlers/generic/mutation/mirrors/inject_test.go index 44b526fd1..a6243352c 100644 --- a/pkg/handlers/generic/mutation/mirrors/inject_test.go +++ b/pkg/handlers/generic/mutation/mirrors/inject_test.go @@ -22,11 +22,8 @@ import ( ) const ( - validMirrorCASecretName = "myregistry-mirror-cacert" - //nolint:gosec // Does not contain hard coded credentials. - cpRegistryAsMirrorCreds = "kubeadmControlPlaneRegistryAsMirrorCreds" - //nolint:gosec // Does not contain hard coded credentials. - workerRegistryAsMirrorCreds = "kubeadmConfigTemplateRegistryAsMirrorCreds" + validMirrorCASecretName = "myregistry-mirror-cacert" + validMirrorNoCASecretName = "myregistry-mirror-no-cacert" ) func TestMirrorsPatch(t *testing.T) { @@ -50,7 +47,7 @@ var _ = Describe("Generate Global mirror patches", func() { testDefs := []capitest.PatchTestDef{ { - Name: "files added in KubeadmControlPlaneTemplate for registry with mirror without CA Certificate", + Name: "files added in KubeadmControlPlaneTemplate for registry with mirror without CA Certificate secret", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( v1alpha1.ClusterConfigVariableName, @@ -65,7 +62,7 @@ var _ = Describe("Generate Global mirror patches", func() { { Operation: "add", Path: "/spec/template/spec/kubeadmConfigSpec/files", - ValueMatcher: gomega.ContainElements( + ValueMatcher: gomega.HaveExactElements( gomega.HaveKeyWithValue( "path", "/etc/containerd/certs.d/_default/hosts.toml", ), @@ -92,12 +89,12 @@ var _ = Describe("Generate Global mirror patches", func() { v1alpha1.GlobalMirrorVariableName, ), }, - RequestItem: request.NewKubeadmControlPlaneTemplateRequest("", cpRegistryAsMirrorCreds), + RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ { Operation: "add", Path: "/spec/template/spec/kubeadmConfigSpec/files", - ValueMatcher: gomega.ContainElements( + ValueMatcher: gomega.HaveExactElements( gomega.HaveKeyWithValue( "path", "/etc/containerd/certs.d/_default/hosts.toml", ), @@ -112,7 +109,74 @@ var _ = Describe("Generate Global mirror patches", func() { }, }, { - Name: "files added in KubeadmConfigTemplate for registry mirror wihthout CA certificate", + Name: "files added in KubeadmControlPlaneTemplate for registry mirror with secret but missing CA certificate key", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + v1alpha1.ClusterConfigVariableName, + v1alpha1.GlobalImageRegistryMirror{ + URL: "https://registry.example.com", + Credentials: &v1alpha1.RegistryCredentials{ + SecretRef: &v1alpha1.LocalObjectReference{ + Name: validMirrorNoCASecretName, + }, + }, + }, + v1alpha1.GlobalMirrorVariableName, + ), + }, + RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/files", + ValueMatcher: gomega.HaveExactElements( + gomega.HaveKeyWithValue( + "path", "/etc/containerd/certs.d/_default/hosts.toml", + ), + gomega.HaveKeyWithValue( + "path", "/etc/caren/containerd/patches/registry-config.toml", + ), + ), + }, + }, + }, + { + Name: "files added in KubeadmControlPlaneTemplate for image registry with CA Certificate secret", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + v1alpha1.ClusterConfigVariableName, + []v1alpha1.ImageRegistry{{ + URL: "https://registry.example.com", + Credentials: &v1alpha1.RegistryCredentials{ + SecretRef: &v1alpha1.LocalObjectReference{ + Name: validMirrorCASecretName, + }, + }, + }}, + v1alpha1.ImageRegistriesVariableName, + ), + }, + RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/files", + ValueMatcher: gomega.HaveExactElements( + gomega.HaveKeyWithValue( + "path", "/etc/containerd/certs.d/_default/hosts.toml", + ), + gomega.HaveKeyWithValue( + "path", "/etc/certs/registry.example.com.pem", + ), + gomega.HaveKeyWithValue( + "path", "/etc/caren/containerd/patches/registry-config.toml", + ), + ), + }, + }, + }, + { + Name: "files added in KubeadmConfigTemplate for registry mirror without CA certificate secret", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( v1alpha1.ClusterConfigVariableName, @@ -135,7 +199,7 @@ var _ = Describe("Generate Global mirror patches", func() { { Operation: "add", Path: "/spec/template/spec/files", - ValueMatcher: gomega.ContainElements( + ValueMatcher: gomega.HaveExactElements( gomega.HaveKeyWithValue( "path", "/etc/containerd/certs.d/_default/hosts.toml", ), @@ -170,12 +234,95 @@ var _ = Describe("Generate Global mirror patches", func() { }, ), }, - RequestItem: request.NewKubeadmConfigTemplateRequest("", workerRegistryAsMirrorCreds), + RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/files", + ValueMatcher: gomega.HaveExactElements( + gomega.HaveKeyWithValue( + "path", "/etc/containerd/certs.d/_default/hosts.toml", + ), + gomega.HaveKeyWithValue( + "path", "/etc/certs/registry.example.com.pem", + ), + gomega.HaveKeyWithValue( + "path", "/etc/caren/containerd/patches/registry-config.toml", + ), + ), + }, + }, + }, + { + Name: "files added in KubeadmConfigTemplate for registry mirror with secret but missing CA certificate key", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + v1alpha1.ClusterConfigVariableName, + v1alpha1.GlobalImageRegistryMirror{ + URL: "https://registry.example.com", + Credentials: &v1alpha1.RegistryCredentials{ + SecretRef: &v1alpha1.LocalObjectReference{ + Name: validMirrorNoCASecretName, + }, + }, + }, + v1alpha1.GlobalMirrorVariableName, + ), + capitest.VariableWithValue( + "builtin", + map[string]any{ + "machineDeployment": map[string]any{ + "class": names.SimpleNameGenerator.GenerateName("worker-"), + }, + }, + ), + }, + RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ { Operation: "add", Path: "/spec/template/spec/files", - ValueMatcher: gomega.ContainElements( + ValueMatcher: gomega.HaveExactElements( + gomega.HaveKeyWithValue( + "path", "/etc/containerd/certs.d/_default/hosts.toml", + ), + gomega.HaveKeyWithValue( + "path", "/etc/caren/containerd/patches/registry-config.toml", + ), + ), + }, + }, + }, + { + Name: "files added in KubeadmConfigTemplate for image registry with secret for CA certificate", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + v1alpha1.ClusterConfigVariableName, + []v1alpha1.ImageRegistry{{ + URL: "https://registry.example.com", + Credentials: &v1alpha1.RegistryCredentials{ + SecretRef: &v1alpha1.LocalObjectReference{ + Name: validMirrorCASecretName, + }, + }, + }}, + v1alpha1.ImageRegistriesVariableName, + ), + capitest.VariableWithValue( + "builtin", + map[string]any{ + "machineDeployment": map[string]any{ + "class": names.SimpleNameGenerator.GenerateName("worker-"), + }, + }, + ), + }, + RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/files", + ValueMatcher: gomega.HaveExactElements( gomega.HaveKeyWithValue( "path", "/etc/containerd/certs.d/_default/hosts.toml", ), @@ -197,7 +344,11 @@ var _ = Describe("Generate Global mirror patches", func() { gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(client.Create( ctx, - newMirrorSecret(validMirrorCASecretName, request.Namespace), + newMirrorSecretWithCA(validMirrorCASecretName, request.Namespace), + )).To(gomega.BeNil()) + gomega.Expect(client.Create( + ctx, + newMirrorSecretWithoutCA(validMirrorNoCASecretName, request.Namespace), )).To(gomega.BeNil()) }) @@ -207,7 +358,11 @@ var _ = Describe("Generate Global mirror patches", func() { gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(client.Delete( ctx, - newMirrorSecret(validMirrorCASecretName, request.Namespace), + newMirrorSecretWithCA(validMirrorCASecretName, request.Namespace), + )).To(gomega.BeNil()) + gomega.Expect(client.Delete( + ctx, + newMirrorSecretWithoutCA(validMirrorNoCASecretName, request.Namespace), )).To(gomega.BeNil()) }) @@ -220,7 +375,7 @@ var _ = Describe("Generate Global mirror patches", func() { } }) -func newMirrorSecret(name, namespace string) *corev1.Secret { +func newMirrorSecretWithCA(name, namespace string) *corev1.Secret { secretData := map[string][]byte{ "ca.crt": []byte("myCACert"), } @@ -238,6 +393,25 @@ func newMirrorSecret(name, namespace string) *corev1.Secret { } } +func newMirrorSecretWithoutCA(name, namespace string) *corev1.Secret { + secretData := map[string][]byte{ + "username": []byte("user"), + "password": []byte("pass"), + } + return &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Data: secretData, + Type: corev1.SecretTypeOpaque, + } +} + func Test_needContainerdConfiguration(t *testing.T) { t.Parallel() tests := []struct {