diff --git a/charts/osm/README.md b/charts/osm/README.md index 03d48524e5..058120bb75 100644 --- a/charts/osm/README.md +++ b/charts/osm/README.md @@ -178,6 +178,9 @@ The following table lists the configurable parameters of the osm chart and their | osm.vault.port | int | `8200` | port to use to connect to Vault | | osm.vault.protocol | string | `"http"` | protocol to use to connect to Vault | | osm.vault.role | string | `"openservicemesh"` | Vault role to be used by Open Service Mesh | +| osm.vault.secret | object | `{"key":"token","name":"osm-vault-token"}` | The Kubernetes secret storing the Vault token used in OSM | +| osm.vault.secret.key | string | `"token"` | The Kubernetes secret key with the value bring the Vault token | +| osm.vault.secret.name | string | `"osm-vault-token"` | The Kubernetes secret name storing the Vault token used in OSM | | osm.vault.token | string | `""` | token that should be used to connect to Vault | | osm.webhookConfigNamePrefix | string | `"osm-webhook"` | Prefix used in name of the webhook configuration resources | | smi.validateTrafficTarget | bool | `true` | Enables validation of SMI Traffic Target | diff --git a/charts/osm/templates/cleanup-hook.yaml b/charts/osm/templates/cleanup-hook.yaml index 0760004f20..ea491ed9ae 100644 --- a/charts/osm/templates/cleanup-hook.yaml +++ b/charts/osm/templates/cleanup-hook.yaml @@ -84,6 +84,7 @@ spec: kubectl replace -f /osm-crds; kubectl delete --ignore-not-found meshconfig -n '{{ include "osm.namespace" . }}' osm-mesh-config; kubectl delete --ignore-not-found secret -n '{{ include "osm.namespace" . }}' {{ .Values.osm.caBundleSecretName }}; + kubectl delete --ignore-not-found meshrootcertificate -n '{{ include "osm.namespace" . }}' osm-mesh-root-certificate; kubectl delete mutatingwebhookconfiguration -l app.kubernetes.io/name=openservicemesh.io,app.kubernetes.io/instance={{ .Values.osm.meshName }},app.kubernetes.io/version={{ .Chart.AppVersion }},app=osm-injector --ignore-not-found; kubectl delete validatingwebhookconfiguration -l app.kubernetes.io/name=openservicemesh.io,app.kubernetes.io/instance={{ .Values.osm.meshName }},app.kubernetes.io/version={{ .Chart.AppVersion }},app=osm-controller --ignore-not-found; nodeSelector: diff --git a/charts/osm/templates/preset-mesh-root-certificate.yaml b/charts/osm/templates/preset-mesh-root-certificate.yaml new file mode 100644 index 0000000000..00a1e412d9 --- /dev/null +++ b/charts/osm/templates/preset-mesh-root-certificate.yaml @@ -0,0 +1,43 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: preset-mesh-root-certificate + namespace: {{ include "osm.namespace" . }} +data: + preset-mesh-root-certificate.json: | + { + "provider": { + {{- if eq (.Values.osm.certificateProvider.kind | lower) "tresor"}} + "tresor": { + "ca": { + "secretRef": { + "name": {{.Values.osm.caBundleSecretName | mustToJson}}, + "namespace": "{{include "osm.namespace" .}}" + } + } + } + {{- end}} + {{- if eq (.Values.osm.certificateProvider.kind | lower) "cert-manager"}} + "certManager": { + "issuerName": {{.Values.osm.certmanager.issuerName | mustToJson}}, + "issuerKind": {{.Values.osm.certmanager.issuerKind | mustToJson}}, + "issuerGroup": {{.Values.osm.certmanager.issuerGroup | mustToJson}} + } + {{- end}} + {{- if eq (.Values.osm.certificateProvider.kind | lower) "vault"}} + "vault": { + "token": { + "secretKeyRef": { + "name": {{.Values.osm.vault.secret.name | mustToJson}}, + "key": {{.Values.osm.vault.secret.key | mustToJson}}, + "namespace": "{{include "osm.namespace" .}}" + } + }, + "host": {{.Values.osm.vault.host | mustToJson}}, + "role": {{.Values.osm.vault.role | mustToJson}}, + "protocol": {{.Values.osm.vault.protocol | mustToJson}}, + "port": {{.Values.osm.vault.port | mustToJson}} + } + {{- end}} + } + } diff --git a/charts/osm/values.schema.json b/charts/osm/values.schema.json index 336a5ac10d..f8604a170b 100644 --- a/charts/osm/values.schema.json +++ b/charts/osm/values.schema.json @@ -1292,6 +1292,26 @@ "title": "Hashicorp Vault's role schema", "description": "Role to use with Vault", "type": "string" + }, + "secret": { + "$id": "#/properties/osm/properties/vault/properties/secret", + "type": "object", + "title": "Vault token secret schema", + "description": "Vault token secret reference parameters", + "properties": { + "name": { + "$id": "#/properties/osm/properties/vault/properties/secret/properties/name", + "title": "Vault token secret name schema", + "description": "Name of the Kubernetes Secret to store the vault token", + "type": "string" + }, + "key": { + "$id": "#/properties/osm/properties/vault/properties/secret/properties/key", + "title": "Vault token secret key schema", + "description": "Name of the Kubernetes Secret key with the value of the vault token", + "type": "string" + } + } } }, "examples": [ diff --git a/charts/osm/values.yaml b/charts/osm/values.yaml index bf6ce7d22d..61057a5405 100644 --- a/charts/osm/values.yaml +++ b/charts/osm/values.yaml @@ -129,6 +129,12 @@ osm: token: "" # -- Vault role to be used by Open Service Mesh role: openservicemesh + # -- The Kubernetes secret storing the Vault token used in OSM + secret: + # -- The Kubernetes secret name storing the Vault token used in OSM + name: osm-vault-token + # -- The Kubernetes secret key with the value bring the Vault token + key: token # # -- cert-manager.io configuration diff --git a/cmd/cli/uninstall_mesh.go b/cmd/cli/uninstall_mesh.go index ff4d358eb9..17b4506649 100644 --- a/cmd/cli/uninstall_mesh.go +++ b/cmd/cli/uninstall_mesh.go @@ -251,6 +251,7 @@ func (d *uninstallMeshCmd) uninstallCustomResourceDefinitions() error { "egresses.policy.openservicemesh.io", "ingressbackends.policy.openservicemesh.io", "meshconfigs.config.openservicemesh.io", + "meshRootCertificate.config.openservicemesh.io", "upstreamtrafficsettings.policy.openservicemesh.io", "retries.policy.openservicemesh.io", "multiclusterservices.config.openservicemesh.io", diff --git a/cmd/osm-bootstrap/crds/config_mesh_root_certificate.yaml b/cmd/osm-bootstrap/crds/config_mesh_root_certificate.yaml index f94344e0ab..ba5366b6d2 100644 --- a/cmd/osm-bootstrap/crds/config_mesh_root_certificate.yaml +++ b/cmd/osm-bootstrap/crds/config_mesh_root_certificate.yaml @@ -60,14 +60,10 @@ spec: description: Cert-manager provider configuration type: object required: - - secretName - issuerName - issuerKind - issuerGroup properties: - secretName: - description: The name of the kubernetes secret containing the root certificate - type: string issuerName: description: The name of the Issuer or ClusterIssuer resource type: string diff --git a/cmd/osm-bootstrap/osm-bootstrap.go b/cmd/osm-bootstrap/osm-bootstrap.go index 7eca301ebe..0649c21eb1 100644 --- a/cmd/osm-bootstrap/osm-bootstrap.go +++ b/cmd/osm-bootstrap/osm-bootstrap.go @@ -44,9 +44,12 @@ import ( ) const ( - meshConfigName = "osm-mesh-config" - presetMeshConfigName = "preset-mesh-config" - presetMeshConfigJSONKey = "preset-mesh-config.json" + meshConfigName = "osm-mesh-config" + presetMeshConfigName = "preset-mesh-config" + presetMeshConfigJSONKey = "preset-mesh-config.json" + meshRootCertificateName = "osm-mesh-root-certificate" + presetMeshRootCertificateName = "preset-mesh-root-certificate" + presetMeshRootCertificateJSONKey = "preset-mesh-root-certificate.json" ) var ( @@ -76,9 +79,9 @@ var ( ) type bootstrap struct { - kubeClient kubernetes.Interface - meshConfigClient configClientset.Interface - namespace string + kubeClient kubernetes.Interface + configClient configClientset.Interface + namespace string } func init() { @@ -156,9 +159,9 @@ func main() { } bootstrap := bootstrap{ - kubeClient: kubeClient, - meshConfigClient: configClient, - namespace: osmNamespace, + kubeClient: kubeClient, + configClient: configClient, + namespace: osmNamespace, } err = bootstrap.ensureMeshConfig() @@ -167,6 +170,12 @@ func main() { return } + err = bootstrap.ensureMeshRootCertificate() + if err != nil { + log.Fatal().Err(err).Msgf("Error setting up default MeshRootCertificate %s from ConfigMap %s", meshRootCertificateName, presetMeshRootCertificateName) + return + } + err = bootstrap.initiatilizeKubernetesEventsRecorder() if err != nil { log.Fatal().Err(err).Msg("Error initializing Kubernetes events recorder") @@ -253,7 +262,7 @@ func (b *bootstrap) createDefaultMeshConfig() error { if err != nil { return err } - if _, err := b.meshConfigClient.ConfigV1alpha2().MeshConfigs(b.namespace).Create(context.TODO(), defaultMeshConfig, metav1.CreateOptions{}); err == nil { + if _, err := b.configClient.ConfigV1alpha2().MeshConfigs(b.namespace).Create(context.TODO(), defaultMeshConfig, metav1.CreateOptions{}); err == nil { log.Info().Msgf("MeshConfig (%s) created in namespace %s", meshConfigName, b.namespace) return nil } @@ -267,7 +276,7 @@ func (b *bootstrap) createDefaultMeshConfig() error { } func (b *bootstrap) ensureMeshConfig() error { - config, err := b.meshConfigClient.ConfigV1alpha2().MeshConfigs(b.namespace).Get(context.TODO(), meshConfigName, metav1.GetOptions{}) + config, err := b.configClient.ConfigV1alpha2().MeshConfigs(b.namespace).Get(context.TODO(), meshConfigName, metav1.GetOptions{}) if apierrors.IsNotFound(err) { // create a default mesh config since it was not found return b.createDefaultMeshConfig() @@ -281,7 +290,7 @@ func (b *bootstrap) ensureMeshConfig() error { if err := util.CreateApplyAnnotation(config, unstructured.UnstructuredJSONScheme); err != nil { return err } - if _, err := b.meshConfigClient.ConfigV1alpha2().MeshConfigs(b.namespace).Update(context.TODO(), config, metav1.UpdateOptions{}); err != nil { + if _, err := b.configClient.ConfigV1alpha2().MeshConfigs(b.namespace).Update(context.TODO(), config, metav1.UpdateOptions{}); err != nil { return err } } @@ -355,3 +364,68 @@ func buildDefaultMeshConfig(presetMeshConfigMap *corev1.ConfigMap) (*configv1alp return config, util.CreateApplyAnnotation(config, unstructured.UnstructuredJSONScheme) } + +func (b *bootstrap) ensureMeshRootCertificate() error { + meshRootCertificateList, err := b.configClient.ConfigV1alpha2().MeshRootCertificates(b.namespace).List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return err + } + + if len(meshRootCertificateList.Items) != 0 { + return nil + } + + // create a MeshRootCertificate since none were found + return b.createMeshRootCertificate() +} + +func (b *bootstrap) createMeshRootCertificate() error { + // find preset config map to build the MeshRootCertificate from + presetMeshRootCertificate, err := b.kubeClient.CoreV1().ConfigMaps(b.namespace).Get(context.TODO(), presetMeshRootCertificateName, metav1.GetOptions{}) + if err != nil { + return err + } + + // Create a MeshRootCertificate + defaultMeshRootCertificate, err := buildMeshRootCertificate(presetMeshRootCertificate) + if err != nil { + return err + } + _, err = b.configClient.ConfigV1alpha2().MeshRootCertificates(b.namespace).Create(context.TODO(), defaultMeshRootCertificate, metav1.CreateOptions{}) + if apierrors.IsAlreadyExists(err) { + log.Info().Msgf("MeshRootCertificate already exists in %s. Skip creating.", b.namespace) + return nil + } + if err != nil { + return err + } + + log.Info().Msgf("Successfully created MeshRootCertificate %s in %s.", meshRootCertificateName, b.namespace) + return nil +} + +func buildMeshRootCertificate(presetMeshRootCertificateConfigMap *corev1.ConfigMap) (*configv1alpha2.MeshRootCertificate, error) { + presetMeshRootCertificate := presetMeshRootCertificateConfigMap.Data[presetMeshRootCertificateJSONKey] + presetMeshRootCertificateSpec := configv1alpha2.MeshRootCertificateSpec{} + err := json.Unmarshal([]byte(presetMeshRootCertificate), &presetMeshRootCertificateSpec) + if err != nil { + return nil, fmt.Errorf("error converting preset-mesh-root-certificate json string to MeshRootCertificate object: %w", err) + } + + mrc := &configv1alpha2.MeshRootCertificate{ + TypeMeta: metav1.TypeMeta{ + Kind: "MeshRootCertificate", + APIVersion: "config.openservicemesh.io/configv1alpha2", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: meshRootCertificateName, + }, + Spec: presetMeshRootCertificateSpec, + Status: configv1alpha2.MeshRootCertificateStatus{ + State: constants.MRCStateComplete, + RotationStage: constants.MRCStageIssuing, + }, + } + + return mrc, util.CreateApplyAnnotation(mrc, unstructured.UnstructuredJSONScheme) +} diff --git a/cmd/osm-bootstrap/osm-bootstrap_test.go b/cmd/osm-bootstrap/osm-bootstrap_test.go index 6667fe02dd..32e3eec19e 100644 --- a/cmd/osm-bootstrap/osm-bootstrap_test.go +++ b/cmd/osm-bootstrap/osm-bootstrap_test.go @@ -13,6 +13,7 @@ import ( fakeKube "k8s.io/client-go/kubernetes/fake" configv1alpha2 "github.com/openservicemesh/osm/pkg/apis/config/v1alpha2" + "github.com/openservicemesh/osm/pkg/constants" configClientset "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned" fakeConfig "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned/fake" ) @@ -89,6 +90,43 @@ var testPresetMeshConfigMap *corev1.ConfigMap = &corev1.ConfigMap{ }, } +var testMeshRootCertificate *configv1alpha2.MeshRootCertificate = &configv1alpha2.MeshRootCertificate{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: meshRootCertificateName, + }, + Spec: configv1alpha2.MeshRootCertificateSpec{}, + Status: configv1alpha2.MeshRootCertificateStatus{ + State: constants.MRCStateComplete, + RotationStage: constants.MRCStageIssuing, + }, +} + +var testPresetMeshRootCertificate *corev1.ConfigMap = &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: presetMeshRootCertificateName, + Namespace: testNamespace, + }, + Data: map[string]string{ + presetMeshRootCertificateJSONKey: `{ +"provider": { + "tresor": { + "ca": { + "secretRef": { + "name": "osm-ca-bundle", + "namespace": "test-namespace" + } + } + } + } +}`, + }, +} + func TestBuildDefaultMeshConfig(t *testing.T) { assert := tassert.New(t) @@ -109,6 +147,19 @@ func TestBuildDefaultMeshConfig(t *testing.T) { assert.False(meshConfig.Spec.FeatureFlags.EnableRetryPolicy) } +func TestBuildMeshRootCertificate(t *testing.T) { + assert := tassert.New(t) + + meshRootCertificate, err := buildMeshRootCertificate(testPresetMeshRootCertificate) + assert.Contains(meshRootCertificate.Annotations, "kubectl.kubernetes.io/last-applied-configuration") + assert.NoError(err) + assert.Equal(meshRootCertificate.Name, meshRootCertificateName) + assert.Equal(meshRootCertificate.Spec.Provider.Tresor.CA.SecretRef.Name, "osm-ca-bundle") + assert.Equal(meshRootCertificate.Spec.Provider.Tresor.CA.SecretRef.Namespace, testNamespace) + assert.Nil(meshRootCertificate.Spec.Provider.Vault) + assert.Nil(meshRootCertificate.Spec.Provider.CertManager) +} + func TestValidateCLIParams(t *testing.T) { assert := tassert.New(t) @@ -156,7 +207,7 @@ func TestCreateDefaultMeshConfig(t *testing.T) { name string namespace string kubeClient kubernetes.Interface - meshConfigClient configClientset.Interface + configClient configClientset.Interface expectDefaultMeshConfig bool expectErr bool }{ @@ -164,7 +215,7 @@ func TestCreateDefaultMeshConfig(t *testing.T) { name: "successfully create default meshconfig from preset configmap", namespace: testNamespace, kubeClient: fakeKube.NewSimpleClientset([]runtime.Object{testPresetMeshConfigMap}...), - meshConfigClient: fakeConfig.NewSimpleClientset(), + configClient: fakeConfig.NewSimpleClientset(), expectDefaultMeshConfig: true, expectErr: false, }, @@ -172,7 +223,7 @@ func TestCreateDefaultMeshConfig(t *testing.T) { name: "preset configmap does not exist", namespace: testNamespace, kubeClient: fakeKube.NewSimpleClientset(), - meshConfigClient: fakeConfig.NewSimpleClientset(), + configClient: fakeConfig.NewSimpleClientset(), expectDefaultMeshConfig: false, expectErr: true, }, @@ -180,7 +231,7 @@ func TestCreateDefaultMeshConfig(t *testing.T) { name: "default MeshConfig already exists", namespace: testNamespace, kubeClient: fakeKube.NewSimpleClientset([]runtime.Object{testPresetMeshConfigMap}...), - meshConfigClient: fakeConfig.NewSimpleClientset([]runtime.Object{testMeshConfig}...), + configClient: fakeConfig.NewSimpleClientset([]runtime.Object{testMeshConfig}...), expectDefaultMeshConfig: true, expectErr: false, }, @@ -190,67 +241,55 @@ func TestCreateDefaultMeshConfig(t *testing.T) { t.Run(tc.name, func(t *testing.T) { assert := tassert.New(t) b := bootstrap{ - kubeClient: tc.kubeClient, - meshConfigClient: tc.meshConfigClient, - namespace: tc.namespace, + kubeClient: tc.kubeClient, + configClient: tc.configClient, + namespace: tc.namespace, } err := b.createDefaultMeshConfig() - if tc.expectErr { - assert.NotNil(err) - } else { - assert.Nil(err) - } + assert.Equal(tc.expectErr, err != nil) - _, err = b.meshConfigClient.ConfigV1alpha2().MeshConfigs(b.namespace).Get(context.TODO(), meshConfigName, metav1.GetOptions{}) - if tc.expectDefaultMeshConfig { - if err == nil { - assert.Nil(err) - } - } else { - if err == nil { - assert.NotNil(err) - } - } + _, err = b.configClient.ConfigV1alpha2().MeshConfigs(b.namespace).Get(context.TODO(), meshConfigName, metav1.GetOptions{}) + assert.Equal(tc.expectDefaultMeshConfig, err == nil) }) } } func TestEnsureMeshConfig(t *testing.T) { tests := []struct { - name string - namespace string - kubeClient kubernetes.Interface - meshConfigClient configClientset.Interface - expectErr bool + name string + namespace string + kubeClient kubernetes.Interface + configClient configClientset.Interface + expectErr bool }{ { - name: "MeshConfig found with no last-applied annotation", - namespace: testNamespace, - kubeClient: fakeKube.NewSimpleClientset(), - meshConfigClient: fakeConfig.NewSimpleClientset([]runtime.Object{testMeshConfig}...), - expectErr: false, + name: "MeshConfig found with no last-applied annotation", + namespace: testNamespace, + kubeClient: fakeKube.NewSimpleClientset(), + configClient: fakeConfig.NewSimpleClientset([]runtime.Object{testMeshConfig}...), + expectErr: false, }, { - name: "MeshConfig found with last-applied annotation", - namespace: testNamespace, - kubeClient: fakeKube.NewSimpleClientset(), - meshConfigClient: fakeConfig.NewSimpleClientset([]runtime.Object{testMeshConfigWithLastAppliedAnnotation}...), - expectErr: false, + name: "MeshConfig found with last-applied annotation", + namespace: testNamespace, + kubeClient: fakeKube.NewSimpleClientset(), + configClient: fakeConfig.NewSimpleClientset([]runtime.Object{testMeshConfigWithLastAppliedAnnotation}...), + expectErr: false, }, { - name: "MeshConfig not found but successfully created", - namespace: testNamespace, - kubeClient: fakeKube.NewSimpleClientset([]runtime.Object{testPresetMeshConfigMap}...), - meshConfigClient: fakeConfig.NewSimpleClientset(), - expectErr: false, + name: "MeshConfig not found but successfully created", + namespace: testNamespace, + kubeClient: fakeKube.NewSimpleClientset([]runtime.Object{testPresetMeshConfigMap}...), + configClient: fakeConfig.NewSimpleClientset(), + expectErr: false, }, { - name: "MeshConfig not found and error creating it", - namespace: testNamespace, - kubeClient: fakeKube.NewSimpleClientset(), - meshConfigClient: fakeConfig.NewSimpleClientset(), - expectErr: true, + name: "MeshConfig not found and error creating it", + namespace: testNamespace, + kubeClient: fakeKube.NewSimpleClientset(), + configClient: fakeConfig.NewSimpleClientset(), + expectErr: true, }, } @@ -258,17 +297,15 @@ func TestEnsureMeshConfig(t *testing.T) { t.Run(tc.name, func(t *testing.T) { assert := tassert.New(t) b := bootstrap{ - kubeClient: tc.kubeClient, - meshConfigClient: tc.meshConfigClient, - namespace: tc.namespace, + kubeClient: tc.kubeClient, + configClient: tc.configClient, + namespace: tc.namespace, } err := b.ensureMeshConfig() - if tc.expectErr { - assert.NotNil(err) - } else { - assert.Nil(err) - config, err := b.meshConfigClient.ConfigV1alpha2().MeshConfigs(b.namespace).Get(context.TODO(), meshConfigName, metav1.GetOptions{}) + assert.Equal(tc.expectErr, err != nil) + if !tc.expectErr { + config, err := b.configClient.ConfigV1alpha2().MeshConfigs(b.namespace).Get(context.TODO(), meshConfigName, metav1.GetOptions{}) assert.Nil(err) assert.Contains(config.Annotations, "kubectl.kubernetes.io/last-applied-configuration") } @@ -276,6 +313,108 @@ func TestEnsureMeshConfig(t *testing.T) { } } +func TestCreateMeshRootCertificate(t *testing.T) { + tests := []struct { + name string + namespace string + kubeClient kubernetes.Interface + configClient configClientset.Interface + expectDefaultMeshRootCertificate bool + expectErr bool + }{ + { + name: "successfully create default MeshRootCertificate from preset configmap", + namespace: testNamespace, + kubeClient: fakeKube.NewSimpleClientset([]runtime.Object{testPresetMeshRootCertificate}...), + configClient: fakeConfig.NewSimpleClientset(), + expectDefaultMeshRootCertificate: true, + expectErr: false, + }, + { + name: "preset configmap does not exist", + namespace: testNamespace, + kubeClient: fakeKube.NewSimpleClientset(), + configClient: fakeConfig.NewSimpleClientset(), + expectDefaultMeshRootCertificate: false, + expectErr: true, + }, + { + name: "MeshRootCertificate already exists", + namespace: testNamespace, + kubeClient: fakeKube.NewSimpleClientset([]runtime.Object{testPresetMeshRootCertificate}...), + configClient: fakeConfig.NewSimpleClientset([]runtime.Object{testMeshRootCertificate}...), + expectDefaultMeshRootCertificate: true, + expectErr: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + assert := tassert.New(t) + b := bootstrap{ + kubeClient: tc.kubeClient, + configClient: tc.configClient, + namespace: tc.namespace, + } + + err := b.createMeshRootCertificate() + assert.Equal(tc.expectErr, err != nil) + + _, err = b.configClient.ConfigV1alpha2().MeshRootCertificates(b.namespace).Get(context.TODO(), meshRootCertificateName, metav1.GetOptions{}) + assert.Equal(tc.expectDefaultMeshRootCertificate, err == nil) + }) + } +} + +func TestEnsureMeshRootCertificate(t *testing.T) { + tests := []struct { + name string + namespace string + kubeClient kubernetes.Interface + configClient configClientset.Interface + expectErr bool + }{ + { + name: "MeshRootCertificate found", + namespace: testNamespace, + kubeClient: fakeKube.NewSimpleClientset(), + configClient: fakeConfig.NewSimpleClientset([]runtime.Object{testMeshRootCertificate}...), + expectErr: false, + }, + { + name: "MeshRootCertificate not found but successfully created", + namespace: testNamespace, + kubeClient: fakeKube.NewSimpleClientset([]runtime.Object{testPresetMeshRootCertificate}...), + configClient: fakeConfig.NewSimpleClientset(), + expectErr: false, + }, + { + name: "MeshRootCertificate not found and error creating it", + namespace: testNamespace, + kubeClient: fakeKube.NewSimpleClientset(), + configClient: fakeConfig.NewSimpleClientset(), + expectErr: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + assert := tassert.New(t) + b := bootstrap{ + kubeClient: tc.kubeClient, + configClient: tc.configClient, + namespace: tc.namespace, + } + + err := b.ensureMeshRootCertificate() + assert.Equal(tc.expectErr, err != nil) + + _, err = b.configClient.ConfigV1alpha2().MeshRootCertificates(b.namespace).Get(context.TODO(), meshRootCertificateName, metav1.GetOptions{}) + assert.Equal(tc.expectErr, err != nil) + }) + } +} + func TestGetBootstrapPod(t *testing.T) { assert := tassert.New(t) testPodName := "test-pod-name" @@ -332,11 +471,7 @@ func TestGetBootstrapPod(t *testing.T) { assert.Nil(err) _, err = b.getBootstrapPod() - if tc.expectErr { - assert.NotNil(err) - } else { - assert.Nil(err) - } + assert.Equal(tc.expectErr, err != nil) }) } } diff --git a/pkg/apis/config/v1alpha2/meshrootcertificate.go b/pkg/apis/config/v1alpha2/meshrootcertificate.go index 93a4be49a6..a0f06ae7cb 100644 --- a/pkg/apis/config/v1alpha2/meshrootcertificate.go +++ b/pkg/apis/config/v1alpha2/meshrootcertificate.go @@ -49,9 +49,6 @@ type ProviderSpec struct { // CertManagerProviderSpec defines the configuration of the cert-manager provider type CertManagerProviderSpec struct { - // SecretName specifies the name of the k8s secret containing the root certificate - SecretName string `json:"secretName"` - // IssuerName specifies the name of the Issuer resource IssuerName string `json:"issuerName"` diff --git a/pkg/certificate/providers/config.go b/pkg/certificate/providers/config.go index 4be4f2dfd2..a4e3eb8417 100644 --- a/pkg/certificate/providers/config.go +++ b/pkg/certificate/providers/config.go @@ -57,8 +57,8 @@ func NewCertificateManager(kubeClient kubernetes.Interface, kubeConfig *rest.Con }, // TODO(#4502): Detect if an actual MRC exists, and set the status accordingly. Status: v1alpha2.MeshRootCertificateStatus{ - State: constants.MRCStateValidating, - RotationStage: constants.MRCStageComplete, + State: constants.MRCStateComplete, + RotationStage: constants.MRCStageIssuing, }, }, } diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index df9a9728a3..961d9c20b0 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -166,8 +166,14 @@ const ( // MRCVersionAnnotation is the annotation used for the version of the MeshRootCertificate MRCVersionAnnotation = "openservicemesh.io/mrc-version" - MRCStateValidating = "validating" - MRCStageComplete = "complete" + // MRCStageValidating is the validating status option for the rotation stage of the MeshRootCertificate + MRCStageValidating = "validating" + + // MRCStageIssuing is the issuing status option for the rotation stage of the MeshRootCertificate + MRCStageIssuing = "issuing" + + // MRCStateComplete is the complete status option for the state of the MeshRootCertificate + MRCStateComplete = "complete" ) // Labels used by the control plane diff --git a/tests/framework/common.go b/tests/framework/common.go index 390a8049bb..3b767390fe 100644 --- a/tests/framework/common.go +++ b/tests/framework/common.go @@ -354,10 +354,13 @@ func (td *OsmTestData) GetOSMInstallOpts(options ...InstallOsmOpt) InstallOSMOpt DeployFluentbit: false, EnableReconciler: false, - VaultHost: "vault." + td.OsmNamespace + ".svc.cluster.local", - VaultProtocol: "http", - VaultRole: "openservicemesh", - VaultToken: "token", + VaultHost: "vault." + td.OsmNamespace + ".svc.cluster.local", + VaultProtocol: "http", + VaultPort: 8200, + VaultRole: "openservicemesh", + VaultToken: "token", + VaultTokenSecretName: "osm-vault-token", + VaultTokenSecretKey: "token-key", CertmanagerIssuerGroup: "cert-manager.io", CertmanagerIssuerKind: "Issuer", @@ -519,7 +522,9 @@ func (td *OsmTestData) InstallOSM(instOpts InstallOSMOpts) error { fmt.Sprintf("osm.vault.host=%s", instOpts.VaultHost), fmt.Sprintf("osm.vault.role=%s", instOpts.VaultRole), fmt.Sprintf("osm.vault.protocol=%s", instOpts.VaultProtocol), - fmt.Sprintf("osm.vault.token=%s", instOpts.VaultToken)) + fmt.Sprintf("osm.vault.token=%s", instOpts.VaultToken), + fmt.Sprintf("osm.vault.port=%d", instOpts.VaultPort), + ) // Wait for the vault pod if err := td.WaitForPodsRunningReady(instOpts.ControlPlaneNS, 60*time.Second, 1, nil); err != nil { return errors.Wrap(err, "failed waiting for vault pod to become ready") diff --git a/tests/framework/types.go b/tests/framework/types.go index a4ae502513..146b23b872 100644 --- a/tests/framework/types.go +++ b/tests/framework/types.go @@ -106,10 +106,13 @@ type InstallOSMOpts struct { DeployFluentbit bool EnableReconciler bool - VaultHost string - VaultProtocol string - VaultToken string - VaultRole string + VaultHost string + VaultProtocol string + VaultPort int + VaultToken string + VaultRole string + VaultTokenSecretName string + VaultTokenSecretKey string CertmanagerIssuerGroup string CertmanagerIssuerKind string