Skip to content

CLOUDP-137882: Use different mount path for prometheus TLS secret #1155

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions controllers/mongodb_tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ import (
)

const (
tlsCAMountPath = "/var/lib/tls/ca/"
tlsCACertName = "ca.crt"
tlsOperatorSecretMountPath = "/var/lib/tls/server/" //nolint
tlsSecretCertName = "tls.crt" //nolint
tlsSecretKeyName = "tls.key"
tlsSecretPemName = "tls.pem"
tlsCAMountPath = "/var/lib/tls/ca/"
tlsCACertName = "ca.crt"
tlsOperatorSecretMountPath = "/var/lib/tls/server/" //nolint
tlsPrometheusSecretMountPath = "/var/lib/tls/prometheus/" //nolint
tlsSecretCertName = "tls.crt"
tlsSecretKeyName = "tls.key"
tlsSecretPemName = "tls.pem"
)

// validateTLSConfig will check that the configured ConfigMap and Secret exist and that they have the correct fields.
Expand Down Expand Up @@ -316,8 +317,7 @@ func buildTLSPrometheus(mdb mdbv1.MongoDBCommunity) podtemplatespec.Modification
// The same key-certificate pair is used for all servers
tlsSecretVolume := statefulset.CreateVolumeFromSecret("prom-tls-secret", mdb.PrometheusTLSOperatorSecretNamespacedName().Name)

// TODO: Is it ok to use the same `tlsOperatorSecretMountPath`
tlsSecretVolumeMount := statefulset.CreateVolumeMount(tlsSecretVolume.Name, tlsOperatorSecretMountPath, statefulset.WithReadOnly(true))
tlsSecretVolumeMount := statefulset.CreateVolumeMount(tlsSecretVolume.Name, tlsPrometheusSecretMountPath, statefulset.WithReadOnly(true))

// MongoDB expects both key and certificate to be provided in a single PEM file
// We are using a secret format where they are stored in separate fields, tls.crt and tls.key
Expand Down
87 changes: 81 additions & 6 deletions controllers/mongodb_tls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,17 @@ func TestStatefulSet_IsCorrectlyConfiguredWithTLS(t *testing.T) {
err = mgr.GetClient().Get(context.TODO(), types.NamespacedName{Name: mdb.Name, Namespace: mdb.Namespace}, &sts)
assert.NoError(t, err)

assertStatefulsetVolumesAndVolumeMounts(t, sts, mdb.TLSOperatorCASecretNamespacedName().Name, mdb.TLSOperatorSecretNamespacedName().Name)
assertStatefulsetVolumesAndVolumeMounts(t, sts, mdb.TLSOperatorCASecretNamespacedName().Name, mdb.TLSOperatorSecretNamespacedName().Name, "")
}

func assertStatefulsetVolumesAndVolumeMounts(t *testing.T, sts appsv1.StatefulSet, expectedTLSCASecretName string, expectedTLSOperatorSecretName string) {
assert.Len(t, sts.Spec.Template.Spec.Volumes, 8)
func assertStatefulsetVolumesAndVolumeMounts(t *testing.T, sts appsv1.StatefulSet, expectedTLSCASecretName string, expectedTLSOperatorSecretName string, expectedPromTLSSecretName string) {
prometheusTLSEnabled := expectedPromTLSSecretName != ""

if prometheusTLSEnabled {
assert.Len(t, sts.Spec.Template.Spec.Volumes, 9)
} else {
assert.Len(t, sts.Spec.Template.Spec.Volumes, 8)
}
permission := int32(416)
assert.Contains(t, sts.Spec.Template.Spec.Volumes, corev1.Volume{
Name: "tls-ca",
Expand All @@ -62,6 +68,17 @@ func assertStatefulsetVolumesAndVolumeMounts(t *testing.T, sts appsv1.StatefulSe
},
},
})
if prometheusTLSEnabled {
assert.Contains(t, sts.Spec.Template.Spec.Volumes, corev1.Volume{
Name: "prom-tls-secret",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: expectedPromTLSSecretName,
DefaultMode: &permission,
},
},
})
}

tlsSecretVolumeMount := corev1.VolumeMount{
Name: "tls-secret",
Expand All @@ -73,16 +90,70 @@ func assertStatefulsetVolumesAndVolumeMounts(t *testing.T, sts appsv1.StatefulSe
ReadOnly: true,
MountPath: tlsCAMountPath,
}
tlsPrometheusSecretVolumeMount := corev1.VolumeMount{
Name: "prom-tls-secret",
ReadOnly: true,
MountPath: tlsPrometheusSecretMountPath,
}

assert.Len(t, sts.Spec.Template.Spec.InitContainers, 2)

agentContainer := sts.Spec.Template.Spec.Containers[0]
assert.Contains(t, agentContainer.VolumeMounts, tlsSecretVolumeMount)
assert.Contains(t, agentContainer.VolumeMounts, tlsCAVolumeMount)
if prometheusTLSEnabled {
assert.Contains(t, agentContainer.VolumeMounts, tlsPrometheusSecretVolumeMount)
}

mongodbContainer := sts.Spec.Template.Spec.Containers[1]
assert.Contains(t, mongodbContainer.VolumeMounts, tlsSecretVolumeMount)
assert.Contains(t, mongodbContainer.VolumeMounts, tlsCAVolumeMount)
if prometheusTLSEnabled {
assert.Contains(t, mongodbContainer.VolumeMounts, tlsPrometheusSecretVolumeMount)
}
}

func TestStatefulSet_IsCorrectlyConfiguredWithPrometheusTLS(t *testing.T) {
mdb := newTestReplicaSetWithTLS()
mdb.Spec.Prometheus = &mdbv1.Prometheus{
Username: "username",
PasswordSecretRef: mdbv1.SecretKeyReference{
Name: "prom-password-secret",
},
Port: 4321,
TLSSecretRef: mdbv1.SecretKeyReference{
Name: "prom-secret-cert",
},
}

mgr := kubeClient.NewManager(&mdb)
cli := mdbClient.NewClient(mgr.GetClient())

err := secret.CreateOrUpdate(mgr.Client,
secret.Builder().
SetName("prom-password-secret").
SetNamespace(mdb.Namespace).
SetField("password", "my-password").
Build(),
)
assert.NoError(t, err)
err = createTLSSecret(cli, mdb, "CERT", "KEY", "")
assert.NoError(t, err)
err = createPrometheusTLSSecret(cli, mdb, "CERT", "KEY", "")
assert.NoError(t, err)

err = createTLSConfigMap(cli, mdb)
assert.NoError(t, err)

r := NewReconciler(mgr)
res, err := r.Reconcile(context.TODO(), reconcile.Request{NamespacedName: types.NamespacedName{Namespace: mdb.Namespace, Name: mdb.Name}})
assertReconciliationSuccessful(t, res, err)

sts := appsv1.StatefulSet{}
err = mgr.GetClient().Get(context.TODO(), types.NamespacedName{Name: mdb.Name, Namespace: mdb.Namespace}, &sts)
assert.NoError(t, err)

assertStatefulsetVolumesAndVolumeMounts(t, sts, mdb.TLSOperatorCASecretNamespacedName().Name, mdb.TLSOperatorSecretNamespacedName().Name, mdb.PrometheusTLSOperatorSecretNamespacedName().Name)
}

func TestStatefulSet_IsCorrectlyConfiguredWithTLSAfterChangingExistingVolumes(t *testing.T) {
Expand Down Expand Up @@ -110,7 +181,7 @@ func TestStatefulSet_IsCorrectlyConfiguredWithTLSAfterChangingExistingVolumes(t
err = mgr.GetClient().Get(context.TODO(), types.NamespacedName{Name: mdb.Name, Namespace: mdb.Namespace}, &sts)
assert.NoError(t, err)

assertStatefulsetVolumesAndVolumeMounts(t, sts, tlsCAVolumeSecretName, mdb.TLSOperatorSecretNamespacedName().Name)
assertStatefulsetVolumesAndVolumeMounts(t, sts, tlsCAVolumeSecretName, mdb.TLSOperatorSecretNamespacedName().Name, "")

// updating sts tls-ca volume directly to simulate changing of underlying volume's secret
for i := range sts.Spec.Template.Spec.Volumes {
Expand All @@ -122,15 +193,15 @@ func TestStatefulSet_IsCorrectlyConfiguredWithTLSAfterChangingExistingVolumes(t
err = mgr.GetClient().Update(context.TODO(), &sts)
assert.NoError(t, err)

assertStatefulsetVolumesAndVolumeMounts(t, sts, changedTLSCAVolumeSecretName, mdb.TLSOperatorSecretNamespacedName().Name)
assertStatefulsetVolumesAndVolumeMounts(t, sts, changedTLSCAVolumeSecretName, mdb.TLSOperatorSecretNamespacedName().Name, "")

res, err = r.Reconcile(context.TODO(), reconcile.Request{NamespacedName: types.NamespacedName{Namespace: mdb.Namespace, Name: mdb.Name}})
assertReconciliationSuccessful(t, res, err)

sts = appsv1.StatefulSet{}
err = mgr.GetClient().Get(context.TODO(), types.NamespacedName{Name: mdb.Name, Namespace: mdb.Namespace}, &sts)
assert.NoError(t, err)
assertStatefulsetVolumesAndVolumeMounts(t, sts, tlsCAVolumeSecretName, mdb.TLSOperatorSecretNamespacedName().Name)
assertStatefulsetVolumesAndVolumeMounts(t, sts, tlsCAVolumeSecretName, mdb.TLSOperatorSecretNamespacedName().Name, "")
}

func TestAutomationConfig_IsCorrectlyConfiguredWithTLS(t *testing.T) {
Expand Down Expand Up @@ -422,6 +493,10 @@ func createTLSSecret(c k8sClient.Client, mdb mdbv1.MongoDBCommunity, crt string,
return createTLSSecretWithNamespaceAndName(c, mdb.Namespace, mdb.Spec.Security.TLS.CertificateKeySecret.Name, crt, key, pem)
}

func createPrometheusTLSSecret(c k8sClient.Client, mdb mdbv1.MongoDBCommunity, crt string, key string, pem string) error {
return createTLSSecretWithNamespaceAndName(c, mdb.Namespace, mdb.Spec.Prometheus.TLSSecretRef.Name, crt, key, pem)
}

func createUserPasswordSecret(c k8sClient.Client, mdb mdbv1.MongoDBCommunity, userPasswordSecretName string, password string) error {
sBuilder := secret.Builder().
SetName(userPasswordSecretName).
Expand Down
2 changes: 1 addition & 1 deletion controllers/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func getPrometheusModification(getUpdateCreator secret.GetUpdateCreator, mdb mdb
if err != nil {
return automationconfig.NOOP(), err
}
tlsPEMPath = tlsOperatorSecretMountPath + tlsOperatorSecretFileName(certKey)
tlsPEMPath = tlsPrometheusSecretMountPath + tlsOperatorSecretFileName(certKey)
scheme = "https"
} else {
scheme = "http"
Expand Down
4 changes: 2 additions & 2 deletions release.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"version-upgrade-hook": "1.0.6",
"readiness-probe": "1.0.12",
"mongodb-agent": {
"version": "12.0.10.7591-1",
"tools_version": "100.5.3"
"version": "12.0.14.7630-1",
"tools_version": "100.6.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ func TestFeatureCompatibilityVersion(t *testing.T) {
defer ctx.Teardown()

mdb, user := e2eutil.NewTestMongoDB(ctx, "mdb0", "")
mdb.Spec.Version = "4.0.6"
mdb.Spec.FeatureCompatibilityVersion = "4.0"
mdb.Spec.Version = "4.2.23"
mdb.Spec.FeatureCompatibilityVersion = "4.2"

_, err := setup.GeneratePasswordForUser(ctx, user, "")
if err != nil {
Expand All @@ -45,24 +45,24 @@ func TestFeatureCompatibilityVersion(t *testing.T) {
t.Run("Create MongoDB Resource", mongodbtests.CreateMongoDBResource(&mdb, ctx))
t.Run("Basic tests", mongodbtests.BasicFunctionality(&mdb))
t.Run("Ensure Authentication", tester.EnsureAuthenticationIsConfigured(3))
t.Run("Test FeatureCompatibilityVersion is 4.0", tester.HasFCV("4.0", 3))
t.Run("Test FeatureCompatibilityVersion is 4.2", tester.HasFCV("4.2", 3))

// Upgrade version to 4.2.6 while keeping the FCV set to 4.0
t.Run("MongoDB is reachable while version is upgraded", func(t *testing.T) {
defer tester.StartBackgroundConnectivityTest(t, time.Second*10)()
t.Run("Test Version can be upgraded", mongodbtests.ChangeVersion(&mdb, "4.2.6"))
defer tester.StartBackgroundConnectivityTest(t, time.Second*20)()
t.Run("Test Version can be upgraded", mongodbtests.ChangeVersion(&mdb, "4.4.11"))
t.Run("Stateful Set Reaches Ready State, after Upgrading", mongodbtests.StatefulSetBecomesReady(&mdb, wait.Timeout(20*time.Minute)))
})

t.Run("Test Basic Connectivity after upgrade has completed", tester.ConnectivitySucceeds())
t.Run("Test FeatureCompatibilityVersion, after upgrade, is 4.0", tester.HasFCV("4.0", 3))
t.Run("Test FeatureCompatibilityVersion, after upgrade, is 4.2", tester.HasFCV("4.2", 3))

// Downgrade version back to 4.0.6, checks that the FeatureCompatibilityVersion stayed at 4.0
t.Run("MongoDB is reachable while version is downgraded", func(t *testing.T) {
defer tester.StartBackgroundConnectivityTest(t, time.Second*10)()
t.Run("Test Version can be downgraded", mongodbtests.ChangeVersion(&mdb, "4.0.6"))
t.Run("Test Version can be downgraded", mongodbtests.ChangeVersion(&mdb, "4.2.23"))
t.Run("Stateful Set Reaches Ready State, after Upgrading", mongodbtests.StatefulSetBecomesReady(&mdb, wait.Timeout(20*time.Minute)))
})

t.Run("Test FeatureCompatibilityVersion, after downgrade, is 4.0", tester.HasFCV("4.0", 3))
t.Run("Test FeatureCompatibilityVersion, after downgrade, is 4.2", tester.HasFCV("4.2", 3))
}
37 changes: 21 additions & 16 deletions test/e2e/prometheus/prometheus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ func TestMain(m *testing.M) {
}

func TestPrometheus(t *testing.T) {
ctx, testConfig := setup.SetupWithTLS(t, "")
resourceName := "mdb0"
ctx, testConfig := setup.SetupWithTLS(t, resourceName)
defer ctx.Teardown()

mdb, user := e2eutil.NewTestMongoDB(ctx, "mdb0", testConfig.Namespace)
mdb, user := e2eutil.NewTestMongoDB(ctx, resourceName, testConfig.Namespace)

mdb.Spec.Security.TLS = e2eutil.NewTestTLSConfig(false)
mdb.Spec.Prometheus = e2eutil.NewPrometheusConfig(mdb.Namespace)

_, err := setup.GeneratePasswordForUser(ctx, user, "")
_, err := setup.GeneratePasswordForUser(ctx, user, testConfig.Namespace)
if err != nil {
t.Fatal(err)
}
Expand All @@ -41,21 +44,23 @@ func TestPrometheus(t *testing.T) {

t.Run("Create MongoDB Resource", mongodbtests.CreateMongoDBResource(&mdb, ctx))
t.Run("Basic tests", mongodbtests.BasicFunctionality(&mdb))
t.Run("Keyfile authentication is configured", tester.HasKeyfileAuth(3))
t.Run("Test Basic Connectivity", tester.ConnectivitySucceeds())

t.Run("Test Prometheus endpoint is active", tester.PrometheusEndpointIsReachable("prom-user", "prom-password", false))
t.Run("Ensure Authentication", tester.EnsureAuthenticationIsConfigured(3))
t.Run("AutomationConfig has the correct version", mongodbtests.AutomationConfigVersionHasTheExpectedVersion(&mdb, 1))
mongodbtests.SkipTestIfLocal(t, "Ensure MongoDB with Prometheus configuration", func(t *testing.T) {
t.Run("Resource has TLS Mode", tester.HasTlsMode("requireSSL", 60, WithTls(mdb)))
t.Run("Test Basic Connectivity", tester.ConnectivitySucceeds(WithTls(mdb)))
t.Run("Test Prometheus endpoint is active", tester.PrometheusEndpointIsReachable("prom-user", "prom-password", false))
t.Run("Ensure Authentication", tester.EnsureAuthenticationIsConfigured(3, WithTls(mdb)))
t.Run("AutomationConfig has the correct version", mongodbtests.AutomationConfigVersionHasTheExpectedVersion(&mdb, 1))

t.Run("Enabling HTTPS on the Prometheus endpoint", func(t *testing.T) {
err = e2eutil.UpdateMongoDBResource(&mdb, func(mdb *v1.MongoDBCommunity) {
mdb.Spec.Prometheus.TLSSecretRef.Name = "tls-certificate"
})
assert.NoError(t, err)
t.Run("Enabling HTTPS on the Prometheus endpoint", func(t *testing.T) {
err = e2eutil.UpdateMongoDBResource(&mdb, func(mdb *v1.MongoDBCommunity) {
mdb.Spec.Prometheus.TLSSecretRef.Name = "tls-certificate"
})
assert.NoError(t, err)

t.Run("MongoDB Reaches Running Phase", mongodbtests.MongoDBReachesRunningPhase(&mdb))
t.Run("Test Prometheus HTTPS endpoint is active", tester.PrometheusEndpointIsReachable("prom-user", "prom-password", true))
t.Run("MongoDB Reaches Running Phase", mongodbtests.MongoDBReachesRunningPhase(&mdb))
t.Run("Test Prometheus HTTPS endpoint is active", tester.PrometheusEndpointIsReachable("prom-user", "prom-password", true))
t.Run("AutomationConfig has the correct version", mongodbtests.AutomationConfigVersionHasTheExpectedVersion(&mdb, 2))
})
})
t.Run("AutomationConfig has the correct version", mongodbtests.AutomationConfigVersionHasTheExpectedVersion(&mdb, 2))
}