diff --git a/api/v1/mdb/mongodb_types.go b/api/v1/mdb/mongodb_types.go index 0f71068b9..cb6ccad46 100644 --- a/api/v1/mdb/mongodb_types.go +++ b/api/v1/mdb/mongodb_types.go @@ -194,7 +194,7 @@ func (m *MongoDB) GetSecretsMountedIntoDBPod() []string { secrets = append(secrets, tls) } } - agentCerts := m.GetSecurity().AgentClientCertificateSecretName(m.Name).Name + agentCerts := m.GetSecurity().AgentClientCertificateSecretName(m.Name) if agentCerts != "" { secrets = append(secrets, agentCerts) } @@ -851,7 +851,7 @@ func (s *Security) ShouldUseX509(currentAgentAuthMode string) bool { // AgentClientCertificateSecretName returns the name of the Secret that holds the agent // client TLS certificates. // If no custom name has been defined, it returns the default one. -func (s Security) AgentClientCertificateSecretName(resourceName string) corev1.SecretKeySelector { +func (s Security) AgentClientCertificateSecretName(resourceName string) string { secretName := util.AgentSecretName if s.CertificatesSecretsPrefix != "" { @@ -861,10 +861,7 @@ func (s Security) AgentClientCertificateSecretName(resourceName string) corev1.S secretName = s.Authentication.Agents.ClientCertificateSecretRefWrap.ClientCertificateSecretRef.Name } - return corev1.SecretKeySelector{ - Key: util.AutomationAgentPemSecretKey, - LocalObjectReference: corev1.LocalObjectReference{Name: secretName}, - } + return secretName } // The customer has set ClientCertificateSecretRef. This signals that client certs are required, diff --git a/api/v1/mdb/mongodb_types_test.go b/api/v1/mdb/mongodb_types_test.go index 491091871..96af62232 100644 --- a/api/v1/mdb/mongodb_types_test.go +++ b/api/v1/mdb/mongodb_types_test.go @@ -382,15 +382,15 @@ func TestAgentClientCertificateSecretName(t *testing.T) { rs := NewReplicaSetBuilder().SetSecurityTLSEnabled().EnableAuth([]AuthMode{util.X509}).Build() // Default is the hardcoded "agent-certs" - assert.Equal(t, util.AgentSecretName, rs.GetSecurity().AgentClientCertificateSecretName(rs.Name).Name) + assert.Equal(t, util.AgentSecretName, rs.GetSecurity().AgentClientCertificateSecretName(rs.Name)) // If the top-level prefix is there, we use it rs.Spec.Security.CertificatesSecretsPrefix = "prefix" - assert.Equal(t, fmt.Sprintf("prefix-%s-%s", rs.Name, util.AgentSecretName), rs.GetSecurity().AgentClientCertificateSecretName(rs.Name).Name) + assert.Equal(t, fmt.Sprintf("prefix-%s-%s", rs.Name, util.AgentSecretName), rs.GetSecurity().AgentClientCertificateSecretName(rs.Name)) // If the name is provided (deprecated) we return it rs.GetSecurity().Authentication.Agents.ClientCertificateSecretRefWrap.ClientCertificateSecretRef.Name = "foo" - assert.Equal(t, "foo", rs.GetSecurity().AgentClientCertificateSecretName(rs.Name).Name) + assert.Equal(t, "foo", rs.GetSecurity().AgentClientCertificateSecretName(rs.Name)) } func TestInternalClusterAuthSecretName(t *testing.T) { diff --git a/controllers/om/automation_config_test.go b/controllers/om/automation_config_test.go index fdc0d8e18..1c10af19d 100644 --- a/controllers/om/automation_config_test.go +++ b/controllers/om/automation_config_test.go @@ -365,7 +365,7 @@ func TestCanResetAgentSSL(t *testing.T) { ac.AgentSSL = &AgentSSL{ ClientCertificateMode: util.OptionalClientCertficates, CAFilePath: util.CAFilePathInContainer, - AutoPEMKeyFilePath: util.AutomationAgentPemFilePath, + AutoPEMKeyFilePath: "/fake/path/to/pem", } if err := ac.Apply(); err != nil { @@ -374,7 +374,7 @@ func TestCanResetAgentSSL(t *testing.T) { tls := cast.ToStringMap(ac.Deployment["tls"]) assert.Equal(t, tls["clientCertificateMode"], util.OptionalClientCertficates) - assert.Equal(t, tls["autoPEMKeyFilePath"], util.AutomationAgentPemFilePath) + assert.Equal(t, tls["autoPEMKeyFilePath"], "/fake/path/to/pem") assert.Equal(t, tls["CAFilePath"], util.CAFilePathInContainer) ac.AgentSSL = &AgentSSL{ diff --git a/controllers/om/backup_agent_config.go b/controllers/om/backup_agent_config.go index 4d324493f..f0187be1a 100644 --- a/controllers/om/backup_agent_config.go +++ b/controllers/om/backup_agent_config.go @@ -49,8 +49,8 @@ func (bac *BackupAgentConfig) UnsetAgentPassword() { bac.BackupAgentTemplate.Password = util.MergoDelete } -func (bac *BackupAgentConfig) EnableX509Authentication(backupAgentSubject string) { - bac.BackupAgentTemplate.SSLPemKeyFile = util.AutomationAgentPemFilePath +func (bac *BackupAgentConfig) EnableX509Authentication(backupAgentSubject, automationAgentPemFilePath string) { + bac.BackupAgentTemplate.SSLPemKeyFile = automationAgentPemFilePath bac.SetAgentUserName(backupAgentSubject) } diff --git a/controllers/om/backup_agent_test.go b/controllers/om/backup_agent_test.go index b9c0997ac..aff7f0584 100644 --- a/controllers/om/backup_agent_test.go +++ b/controllers/om/backup_agent_test.go @@ -32,7 +32,7 @@ func TestFieldsAreUpdatedBackupConfig(t *testing.T) { func TestBackupFieldsAreNotLost(t *testing.T) { config := getTestBackupConfig() - config.EnableX509Authentication("namespace") + config.EnableX509Authentication("namespace", "/fake/path/to/pem") assert.Contains(t, config.BackingMap, "logPath") assert.Contains(t, config.BackingMap, "logRotate") @@ -48,7 +48,7 @@ func TestBackupFieldsAreNotLost(t *testing.T) { func TestNestedFieldsAreNotLost(t *testing.T) { config := getTestBackupConfig() - config.EnableX509Authentication("namespace") + config.EnableX509Authentication("namespace", "/fake/path/to/pem") _ = config.Apply() diff --git a/controllers/om/monitoring_agent_config.go b/controllers/om/monitoring_agent_config.go index 1bf30d42e..af4aafe5f 100644 --- a/controllers/om/monitoring_agent_config.go +++ b/controllers/om/monitoring_agent_config.go @@ -45,9 +45,9 @@ func (m *MonitoringAgentConfig) UnsetAgentPassword() { m.MonitoringAgentTemplate.Password = util.MergoDelete } -func (m *MonitoringAgentConfig) EnableX509Authentication(MonitoringAgentSubject string) { - m.MonitoringAgentTemplate.SSLPemKeyFile = util.AutomationAgentPemFilePath - m.SetAgentUserName(MonitoringAgentSubject) +func (m *MonitoringAgentConfig) EnableX509Authentication(monitoringAgentSubject, automationAgentPemFilePath string) { + m.MonitoringAgentTemplate.SSLPemKeyFile = automationAgentPemFilePath + m.SetAgentUserName(monitoringAgentSubject) } func (m *MonitoringAgentConfig) DisableX509Authentication() { diff --git a/controllers/operator/appdbreplicaset_controller.go b/controllers/operator/appdbreplicaset_controller.go index 071ba8336..0a3d46b77 100644 --- a/controllers/operator/appdbreplicaset_controller.go +++ b/controllers/operator/appdbreplicaset_controller.go @@ -538,7 +538,12 @@ func (r *ReconcileAppDbReplicaSet) ReconcileAppDB(ctx context.Context, opsManage return result.OK() } - podVars, err := r.tryConfigureMonitoringInOpsManager(ctx, opsManager, opsManagerUserPassword, log) + agentCertSecretName := opsManager.Spec.AppDB.GetSecurity().AgentClientCertificateSecretName(opsManager.Name) + agentCertHash := enterprisepem.ReadHashFromSecret(ctx, r.SecretClient, opsManager.Namespace, agentCertSecretName, "", log) + // TODO: Review this. Can this be moved to a function? + autoPEMKeyFilePath := util.PvcMmsHomeMountPath + "/" + util.AgentSecretName + "/" + agentCertHash + + podVars, err := r.tryConfigureMonitoringInOpsManager(ctx, opsManager, opsManagerUserPassword, autoPEMKeyFilePath, log) // it's possible that Ops Manager will not be available when we attempt to configure AppDB monitoring // in Ops Manager. This is not a blocker to continue with the rest of the reconciliation. if err != nil { @@ -1621,7 +1626,7 @@ func (r *ReconcileAppDbReplicaSet) ensureAppDbAgentApiKey(ctx context.Context, o // tryConfigureMonitoringInOpsManager attempts to configure monitoring in Ops Manager. This might not be possible if Ops Manager // has not been created yet, if that is the case, an empty PodVars will be returned. -func (r *ReconcileAppDbReplicaSet) tryConfigureMonitoringInOpsManager(ctx context.Context, opsManager *omv1.MongoDBOpsManager, opsManagerUserPassword string, log *zap.SugaredLogger) (env.PodEnvVars, error) { +func (r *ReconcileAppDbReplicaSet) tryConfigureMonitoringInOpsManager(ctx context.Context, opsManager *omv1.MongoDBOpsManager, opsManagerUserPassword string, autoPEMKeyFilePath string, log *zap.SugaredLogger) (env.PodEnvVars, error) { var operatorVaultSecretPath string if r.VaultClient != nil { operatorVaultSecretPath = r.VaultClient.OperatorSecretPath() @@ -1660,6 +1665,7 @@ func (r *ReconcileAppDbReplicaSet) tryConfigureMonitoringInOpsManager(ctx contex Mechanisms: []string{util.SCRAM}, ClientCertificates: util.OptionalClientCertficates, AutoUser: util.AutomationAgentUserName, + AutoPEMKeyFilePath: autoPEMKeyFilePath, CAFilePath: util.CAFilePathInContainer, } err = authentication.Configure(conn, opts, false, log) diff --git a/controllers/operator/authentication/authentication.go b/controllers/operator/authentication/authentication.go index e9f89a293..c2e36735b 100644 --- a/controllers/operator/authentication/authentication.go +++ b/controllers/operator/authentication/authentication.go @@ -43,6 +43,8 @@ type Options struct { // so it is possible to use other auth mechanisms without needing to provide client certs. ClientCertificates string + AutoPEMKeyFilePath string + CAFilePath string // Use Agent Client Auth @@ -348,7 +350,7 @@ func addOrRemoveAgentClientCertificate(conn om.Connection, opts Options, log *za if opts.AgentsShouldUseClientAuthentication { ac.AgentSSL = &om.AgentSSL{ - AutoPEMKeyFilePath: util.AutomationAgentPemFilePath, + AutoPEMKeyFilePath: opts.AutoPEMKeyFilePath, CAFilePath: opts.CAFilePath, ClientCertificateMode: opts.ClientCertificates, } diff --git a/controllers/operator/authentication/x509.go b/controllers/operator/authentication/x509.go index 2fd4ee4f2..edefc44cd 100644 --- a/controllers/operator/authentication/x509.go +++ b/controllers/operator/authentication/x509.go @@ -29,7 +29,7 @@ func (x *connectionX509) EnableAgentAuthentication(conn om.Connection, opts Opti auth.KeyFile = util.AutomationAgentKeyFilePathInContainer auth.KeyFileWindows = util.AutomationAgentWindowsKeyFilePath ac.AgentSSL = &om.AgentSSL{ - AutoPEMKeyFilePath: util.AutomationAgentPemFilePath, + AutoPEMKeyFilePath: opts.AutoPEMKeyFilePath, CAFilePath: opts.CAFilePath, ClientCertificateMode: opts.ClientCertificates, } @@ -46,7 +46,7 @@ func (x *connectionX509) EnableAgentAuthentication(conn om.Connection, opts Opti log.Info("Configuring backup agent user") err = conn.ReadUpdateBackupAgentConfig(func(config *om.BackupAgentConfig) error { - config.EnableX509Authentication(opts.AutomationSubject) + config.EnableX509Authentication(opts.AutomationSubject, opts.AutoPEMKeyFilePath) config.SetLdapGroupDN(opts.AutoLdapGroupDN) return nil }, log) @@ -56,7 +56,7 @@ func (x *connectionX509) EnableAgentAuthentication(conn om.Connection, opts Opti log.Info("Configuring monitoring agent user") return conn.ReadUpdateMonitoringAgentConfig(func(config *om.MonitoringAgentConfig) error { - config.EnableX509Authentication(opts.AutomationSubject) + config.EnableX509Authentication(opts.AutomationSubject, opts.AutoPEMKeyFilePath) config.SetLdapGroupDN(opts.AutoLdapGroupDN) return nil }, log) diff --git a/controllers/operator/certs/certificates.go b/controllers/operator/certs/certificates.go index 29f0bd6ba..3f3706593 100644 --- a/controllers/operator/certs/certificates.go +++ b/controllers/operator/certs/certificates.go @@ -309,14 +309,16 @@ func ValidateCertificates(ctx context.Context, secretGetter secret.Getter, name, // VerifyAndEnsureClientCertificatesForAgentsAndTLSType ensures that agent certs are present and correct, and returns whether they are of the kubernetes.io/tls type. // If the secret is of type kubernetes.io/tls, it creates a new secret containing the concatenation fo the tls.crt and tls.key fields -func VerifyAndEnsureClientCertificatesForAgentsAndTLSType(ctx context.Context, secretReadClient, secretWriteClient secrets.SecretClient, secret types.NamespacedName) error { +func VerifyAndEnsureClientCertificatesForAgentsAndTLSType(ctx context.Context, secretReadClient, secretWriteClient secrets.SecretClient, secret types.NamespacedName, log *zap.SugaredLogger) error { needToCreatePEM := false var secretData map[string][]byte var s corev1.Secret var err error + var databaseSecretPath string if vault.IsVaultSecretBackend() { needToCreatePEM = true + databaseSecretPath = secretReadClient.VaultClient.DatabaseSecretPath() secretData, err = secretReadClient.VaultClient.ReadSecretBytes(fmt.Sprintf("%s/%s/%s", secretReadClient.VaultClient.DatabaseSecretPath(), secret.Namespace, secret.Name)) if err != nil { return err @@ -338,11 +340,8 @@ func VerifyAndEnsureClientCertificatesForAgentsAndTLSType(ctx context.Context, s return err } - dataMap := map[string]string{ - util.AutomationAgentPemSecretKey: data, - } - - return CreateOrUpdatePEMSecret(ctx, secretWriteClient, secret, dataMap, []metav1.OwnerReference{}, Database) + secretHash := enterprisepem.ReadHashFromSecret(ctx, secretReadClient, secret.Namespace, secret.Name, databaseSecretPath, log) + return CreateOrUpdatePEMSecretWithPreviousCert(ctx, secretWriteClient, secret, secretHash, data, []metav1.OwnerReference{}, Database) } return validatePemSecret(s, util.AutomationAgentPemSecretKey, nil) diff --git a/controllers/operator/common_controller.go b/controllers/operator/common_controller.go index 61fa4ea1b..4e68e7211 100644 --- a/controllers/operator/common_controller.go +++ b/controllers/operator/common_controller.go @@ -30,6 +30,7 @@ import ( "github.com/mongodb/mongodb-kubernetes/controllers/operator/authentication" "github.com/mongodb/mongodb-kubernetes/controllers/operator/certs" "github.com/mongodb/mongodb-kubernetes/controllers/operator/construct" + enterprisepem "github.com/mongodb/mongodb-kubernetes/controllers/operator/pem" "github.com/mongodb/mongodb-kubernetes/controllers/operator/secrets" "github.com/mongodb/mongodb-kubernetes/controllers/operator/watch" "github.com/mongodb/mongodb-kubernetes/controllers/operator/workflow" @@ -231,7 +232,7 @@ func (r *ReconcileCommonController) SetupCommonWatchers(watcherResource WatcherR } else { secretNames = []string{security.MemberCertificateSecretName(resourceNameForSecret)} if security.ShouldUseX509("") { - secretNames = append(secretNames, security.AgentClientCertificateSecretName(resourceNameForSecret).Name) + secretNames = append(secretNames, security.AgentClientCertificateSecretName(resourceNameForSecret)) } } r.resourceWatcher.RegisterWatchedTLSResources(objectToReconcile, security.TLSConfig.CA, secretNames) @@ -504,6 +505,8 @@ func (r *ReconcileCommonController) updateOmAuthentication(ctx context.Context, return workflow.Failed(xerrors.Errorf("error configuring agent subjects: %w", err)), false } authOpts.AgentsShouldUseClientAuthentication = ar.GetSecurity().ShouldUseClientCertificates() + // TODO: Review this. Can this be moved to a function? Multi-cluster key override is annoying - is it still necesssary? + authOpts.AutoPEMKeyFilePath = util.PvcMmsHomeMountPath + "/" + util.AgentSecretName + "/" + agentCertSecretSelector.Key } if ar.GetSecurity().ShouldUseLDAP(ac.Auth.AutoAuthMechanism) { secretRef := ar.GetSecurity().Authentication.Agents.AutomationPasswordSecretRef @@ -595,16 +598,22 @@ func (r *ReconcileCommonController) readAgentSubjectsFromSecret(ctx context.Cont } func (r *ReconcileCommonController) clearProjectAuthenticationSettings(ctx context.Context, conn om.Connection, mdb *mdbv1.MongoDB, processNames []string, log *zap.SugaredLogger) error { - secretKeySelector := mdb.Spec.Security.AgentClientCertificateSecretName(mdb.Name) + agentCertSecretName := mdb.Spec.Security.AgentClientCertificateSecretName(mdb.Name) + agentSecret := &corev1.Secret{} - if err := r.client.Get(ctx, kube.ObjectKey(mdb.Namespace, secretKeySelector.Name), agentSecret); client.IgnoreNotFound(err) != nil { + if err := r.client.Get(ctx, kube.ObjectKey(mdb.Namespace, agentCertSecretName), agentSecret); client.IgnoreNotFound(err) != nil { return nil } if agentSecret.Type == corev1.SecretTypeTLS { - secretKeySelector.Name = fmt.Sprintf("%s%s", secretKeySelector.Name, certs.OperatorGeneratedCertSuffix) + agentCertSecretName = fmt.Sprintf("%s%s", agentCertSecretName, certs.OperatorGeneratedCertSuffix) } + agentCertHash := enterprisepem.ReadHashFromSecret(ctx, r.SecretClient, mdb.Namespace, agentCertSecretName, "", log) + secretKeySelector := corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{Name: agentCertSecretName}, + Key: agentCertHash, + } userOpts, err := r.readAgentSubjectsFromSecret(ctx, mdb.Namespace, secretKeySelector, log) err = client.IgnoreNotFound(err) if err != nil { @@ -631,8 +640,8 @@ func (r *ReconcileCommonController) ensureX509SecretAndCheckTLSType(ctx context. if !security.IsTLSEnabled() { return workflow.Failed(xerrors.Errorf("Authentication mode for project is x509 but this MDB resource is not TLS enabled")) } - agentSecretName := security.AgentClientCertificateSecretName(configurator.GetName()).Name - err := certs.VerifyAndEnsureClientCertificatesForAgentsAndTLSType(ctx, configurator.GetSecretReadClient(), configurator.GetSecretWriteClient(), kube.ObjectKey(configurator.GetNamespace(), agentSecretName)) + agentSecretName := security.AgentClientCertificateSecretName(configurator.GetName()) + err := certs.VerifyAndEnsureClientCertificatesForAgentsAndTLSType(ctx, configurator.GetSecretReadClient(), configurator.GetSecretWriteClient(), kube.ObjectKey(configurator.GetNamespace(), agentSecretName), log) if err != nil { return workflow.Failed(err) } diff --git a/controllers/operator/common_controller_test.go b/controllers/operator/common_controller_test.go index da0928f67..13c9d85d3 100644 --- a/controllers/operator/common_controller_test.go +++ b/controllers/operator/common_controller_test.go @@ -418,7 +418,7 @@ func TestSecretWatcherWithAllResources(t *testing.T) { // TODO: unify the watcher setup with the secret creation/mounting code in database creation memberCert := rs.GetSecurity().MemberCertificateSecretName(rs.Name) internalAuthCert := rs.GetSecurity().InternalClusterAuthSecretName(rs.Name) - agentCert := rs.GetSecurity().AgentClientCertificateSecretName(rs.Name).Name + agentCert := rs.GetSecurity().AgentClientCertificateSecretName(rs.Name) expected := map[watch.Object][]types.NamespacedName{ {ResourceType: watch.ConfigMap, Resource: kube.ObjectKey(mock.TestNamespace, mock.TestProjectConfigMapName)}: {kube.ObjectKey(mock.TestNamespace, rs.Name)}, diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index d2076d7cc..42da4f8c6 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -95,6 +95,7 @@ type DatabaseStatefulSetOptions struct { PodVars *env.PodEnvVars CurrentAgentAuthMode string CertificateHash string + AgentCertificateHash string PrometheusTLSCertHash string InternalClusterHash string ServicePort int32 @@ -376,7 +377,7 @@ func buildVaultDatabaseSecretsToInject(mdb databaseStatefulSetSource, opts Datab secretsToInject := vault.DatabaseSecretsToInject{Config: opts.VaultConfig} if mdb.GetSecurity().ShouldUseX509(opts.CurrentAgentAuthMode) || mdb.GetSecurity().ShouldUseClientCertificates() { - secretName := mdb.GetSecurity().AgentClientCertificateSecretName(mdb.GetName()).Name + secretName := mdb.GetSecurity().AgentClientCertificateSecretName(mdb.GetName()) secretName = fmt.Sprintf("%s%s", secretName, certs.OperatorGeneratedCertSuffix) secretsToInject.AgentCerts = secretName } diff --git a/controllers/operator/database_statefulset_options.go b/controllers/operator/database_statefulset_options.go index d60bb1747..9e829d97e 100644 --- a/controllers/operator/database_statefulset_options.go +++ b/controllers/operator/database_statefulset_options.go @@ -54,6 +54,13 @@ func CertificateHash(hash string) func(options *construct.DatabaseStatefulSetOpt } } +// AgentCertificateHash will assign the given AgentCertificateHash during StatefulSet construction. +func AgentCertificateHash(hash string) func(options *construct.DatabaseStatefulSetOptions) { + return func(options *construct.DatabaseStatefulSetOptions) { + options.AgentCertificateHash = hash + } +} + // InternalClusterHash will assign the given InternalClusterHash during StatefulSet construction. func InternalClusterHash(hash string) func(options *construct.DatabaseStatefulSetOptions) { return func(options *construct.DatabaseStatefulSetOptions) { diff --git a/controllers/operator/mongodbmultireplicaset_controller.go b/controllers/operator/mongodbmultireplicaset_controller.go index 013844268..c547342e6 100644 --- a/controllers/operator/mongodbmultireplicaset_controller.go +++ b/controllers/operator/mongodbmultireplicaset_controller.go @@ -179,6 +179,7 @@ func (r *ReconcileMongoDbMultiReplicaSet) Reconcile(ctx context.Context, request if mrs.Spec.Security.IsTLSEnabled() { certSecretName := mrs.Spec.GetSecurity().MemberCertificateSecretName(mrs.Name) internalClusterCertSecretName := mrs.Spec.GetSecurity().InternalClusterAuthSecretName(mrs.Name) + // TOOD: check if it makes sense to define funcs reading hash in the common controller. tlsCertHash := enterprisepem.ReadHashFromSecret(ctx, r.SecretClient, mrs.Namespace, certSecretName, "", log) internalClusterCertHash := enterprisepem.ReadHashFromSecret(ctx, r.SecretClient, mrs.Namespace, internalClusterCertSecretName, "", log) @@ -493,8 +494,11 @@ func (r *ReconcileMongoDbMultiReplicaSet) reconcileStatefulSets(ctx context.Cont return workflow.Failed(err) } + agentCertSecretName := mrs.GetSecurity().AgentClientCertificateSecretName(mrs.Name) + // get cert hash of tls secret if it exists certHash := enterprisepem.ReadHashFromSecret(ctx, r.SecretClient, mrs.Namespace, mrsConfig.CertSecretName, "", log) + agentCertHash := enterprisepem.ReadHashFromSecret(ctx, r.SecretClient, mrs.Namespace, agentCertSecretName, "", log) internalCertHash := enterprisepem.ReadHashFromSecret(ctx, r.SecretClient, mrs.Namespace, mrsConfig.InternalClusterSecretName, "", log) log.Debugf("Creating StatefulSet %s with %d replicas in cluster: %s", mrs.MultiStatefulsetName(clusterNum), replicasThisReconciliation, item.ClusterName) @@ -524,6 +528,7 @@ func (r *ReconcileMongoDbMultiReplicaSet) reconcileStatefulSets(ctx context.Cont PodEnvVars(newPodVars(conn, projectConfig, mrs.Spec.LogLevel)), CurrentAgentAuthMechanism(currentAgentAuthMode), CertificateHash(certHash), + AgentCertificateHash(agentCertHash), InternalClusterHash(internalCertHash), WithLabels(mrs.GetOwnerLabels()), WithAdditionalMongodConfig(mrs.Spec.GetAdditionalMongodConfig()), @@ -758,7 +763,13 @@ func (r *ReconcileMongoDbMultiReplicaSet) updateOmDeploymentRs(ctx context.Conte caFilePath := fmt.Sprintf("%s/ca-pem", util.TLSCaMountPath) agentCertSecretName := mrs.GetSecurity().AgentClientCertificateSecretName(mrs.GetName()) - status, additionalReconciliationRequired := r.updateOmAuthentication(ctx, conn, rs.GetProcessNames(), &mrs, agentCertSecretName, caFilePath, internalClusterCertPath, isRecovering, log) + // TODO: Move hash reads somewhere up the call stack + agentCertHash := enterprisepem.ReadHashFromSecret(ctx, r.SecretClient, mrs.Namespace, agentCertSecretName, "", log) + agentCertSecretSelector := corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{Name: agentCertSecretName}, + Key: agentCertHash, + } + status, additionalReconciliationRequired := r.updateOmAuthentication(ctx, conn, rs.GetProcessNames(), &mrs, agentCertSecretSelector, caFilePath, internalClusterCertPath, isRecovering, log) if !status.IsOK() && !isRecovering { return xerrors.Errorf("failed to enable Authentication for MongoDB Multi Replicaset") } diff --git a/controllers/operator/mongodbreplicaset_controller.go b/controllers/operator/mongodbreplicaset_controller.go index bf6b2d2b7..02099f061 100644 --- a/controllers/operator/mongodbreplicaset_controller.go +++ b/controllers/operator/mongodbreplicaset_controller.go @@ -200,12 +200,15 @@ func (r *ReconcileMongoDbReplicaSet) Reconcile(ctx context.Context, request reco tlsCertHash := enterprisepem.ReadHashFromSecret(ctx, r.SecretClient, rs.Namespace, rsCertsConfig.CertSecretName, databaseSecretPath, log) internalClusterCertHash := enterprisepem.ReadHashFromSecret(ctx, r.SecretClient, rs.Namespace, rsCertsConfig.InternalClusterSecretName, databaseSecretPath, log) + agentCertSecretName := rs.GetSecurity().AgentClientCertificateSecretName(rs.Name) + agentCertHash := enterprisepem.ReadHashFromSecret(ctx, r.SecretClient, rs.Namespace, agentCertSecretName, databaseSecretPath, log) rsConfig := construct.ReplicaSetOptions( PodEnvVars(newPodVars(conn, projectConfig, rs.Spec.LogLevel)), CurrentAgentAuthMechanism(currentAgentAuthMode), CertificateHash(tlsCertHash), InternalClusterHash(internalClusterCertHash), + AgentCertificateHash(agentCertHash), PrometheusTLSCertHash(prometheusCertHash), WithVaultConfig(vaultConfig), WithLabels(rs.Labels), @@ -233,8 +236,10 @@ func (r *ReconcileMongoDbReplicaSet) Reconcile(ctx context.Context, request reco } } - agentCertSecretSelector := rs.GetSecurity().AgentClientCertificateSecretName(rs.Name) - agentCertSecretSelector.Name += certs.OperatorGeneratedCertSuffix + agentCertSecretSelector := corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{Name: agentCertSecretName + certs.OperatorGeneratedCertSuffix}, + Key: agentCertHash, + } internalClusterCertPath := "" if internalClusterCertHash != "" { @@ -457,6 +462,7 @@ func (r *ReconcileMongoDbReplicaSet) updateOmDeploymentRs(ctx context.Context, c replicaSet := replicaset.BuildFromStatefulSetWithReplicas(r.imageUrls[mcoConstruct.MongodbImageEnv], r.forceEnterprise, set, rs.GetSpec(), updatedMembers, rs.CalculateFeatureCompatibilityVersion(), tlsCertPath) processNames := replicaSet.GetProcessNames() + // TODO: Move hash reads somewhere up the call stack status, additionalReconciliationRequired := r.updateOmAuthentication(ctx, conn, processNames, rs, agentCertSecretSelector, caFilePath, internalClusterCertPath, isRecovering, log) if !status.IsOK() && !isRecovering { return status diff --git a/controllers/operator/mongodbshardedcluster_controller.go b/controllers/operator/mongodbshardedcluster_controller.go index 4b670d6fa..f4f2e407a 100644 --- a/controllers/operator/mongodbshardedcluster_controller.go +++ b/controllers/operator/mongodbshardedcluster_controller.go @@ -1084,7 +1084,12 @@ func (r *ShardedClusterReconcileHelper) doShardedClusterProcessing(ctx context.C return workflowStatus } - agentCertSecretSelector := sc.GetSecurity().AgentClientCertificateSecretName(sc.Name) + agentCertSecretName := sc.GetSecurity().AgentClientCertificateSecretName(sc.Name) + agentCertHash := enterprisepem.ReadHashFromSecret(ctx, r.commonController.SecretClient, sc.Namespace, agentCertSecretName, "", log) + agentCertSecretSelector := corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{Name: agentCertSecretName}, + Key: agentCertHash, + } opts = deploymentOptions{ podEnvVars: podEnvVars, @@ -2280,6 +2285,8 @@ func (r *ShardedClusterReconcileHelper) getConfigServerOptions(ctx context.Conte PodEnvVars(opts.podEnvVars), CurrentAgentAuthMechanism(opts.currentAgentAuthMode), CertificateHash(enterprisepem.ReadHashFromSecret(ctx, r.commonController.SecretClient, sc.Namespace, certSecretName, databaseSecretPath, log)), + // TODO: Check if it is necessary. Can we just use opts? + AgentCertificateHash(enterprisepem.ReadHashFromSecret(ctx, r.commonController.SecretClient, sc.Namespace, opts.agentCertSecretSelector.Name, databaseSecretPath, log)), InternalClusterHash(enterprisepem.ReadHashFromSecret(ctx, r.commonController.SecretClient, sc.Namespace, internalClusterSecretName, databaseSecretPath, log)), PrometheusTLSCertHash(opts.prometheusCertHash), WithVaultConfig(vaultConfig), @@ -2311,6 +2318,8 @@ func (r *ShardedClusterReconcileHelper) getMongosOptions(ctx context.Context, sc PodEnvVars(opts.podEnvVars), CurrentAgentAuthMechanism(opts.currentAgentAuthMode), CertificateHash(enterprisepem.ReadHashFromSecret(ctx, r.commonController.SecretClient, sc.Namespace, certSecretName, vaultConfig.DatabaseSecretPath, log)), + // TODO: Check if it is necessary. Can we just use opts? + AgentCertificateHash(enterprisepem.ReadHashFromSecret(ctx, r.commonController.SecretClient, sc.Namespace, opts.agentCertSecretSelector.Name, vaultConfig.DatabaseSecretPath, log)), InternalClusterHash(enterprisepem.ReadHashFromSecret(ctx, r.commonController.SecretClient, sc.Namespace, internalClusterSecretName, vaultConfig.DatabaseSecretPath, log)), PrometheusTLSCertHash(opts.prometheusCertHash), WithVaultConfig(vaultConfig), @@ -2341,6 +2350,8 @@ func (r *ShardedClusterReconcileHelper) getShardOptions(ctx context.Context, sc PodEnvVars(opts.podEnvVars), CurrentAgentAuthMechanism(opts.currentAgentAuthMode), CertificateHash(enterprisepem.ReadHashFromSecret(ctx, r.commonController.SecretClient, sc.Namespace, certSecretName, databaseSecretPath, log)), + // TODO: Check if it is necessary. Can we just use opts? + AgentCertificateHash(enterprisepem.ReadHashFromSecret(ctx, r.commonController.SecretClient, sc.Namespace, opts.agentCertSecretSelector.Name, databaseSecretPath, log)), InternalClusterHash(enterprisepem.ReadHashFromSecret(ctx, r.commonController.SecretClient, sc.Namespace, internalClusterSecretName, databaseSecretPath, log)), PrometheusTLSCertHash(opts.prometheusCertHash), WithVaultConfig(vaultConfig), diff --git a/controllers/operator/mongodbstandalone_controller.go b/controllers/operator/mongodbstandalone_controller.go index a408d1ddc..f829807d8 100644 --- a/controllers/operator/mongodbstandalone_controller.go +++ b/controllers/operator/mongodbstandalone_controller.go @@ -243,8 +243,11 @@ func (r *ReconcileMongoDbStandalone) Reconcile(ctx context.Context, request reco } } + agentCertSecretName := s.GetSecurity().AgentClientCertificateSecretName(s.Name) + standaloneOpts := construct.StandaloneOptions( CertificateHash(pem.ReadHashFromSecret(ctx, r.SecretClient, s.Namespace, standaloneCertSecretName, databaseSecretPath, log)), + AgentCertificateHash(pem.ReadHashFromSecret(ctx, r.SecretClient, s.Namespace, agentCertSecretName, databaseSecretPath, log)), CurrentAgentAuthMechanism(currentAgentAuthMode), PodEnvVars(podVars), WithVaultConfig(vaultConfig), @@ -319,7 +322,12 @@ func (r *ReconcileMongoDbStandalone) updateOmDeployment(ctx context.Context, con return workflow.Failed(err) } - agentCertSecretSelector := s.GetSecurity().AgentClientCertificateSecretName(s.Name) + agentCertSecretName := s.GetSecurity().AgentClientCertificateSecretName(s.Name) + agentCertHash := pem.ReadHashFromSecret(ctx, r.SecretClient, s.Namespace, agentCertSecretName, "", log) + agentCertSecretSelector := corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{Name: agentCertSecretName}, + Key: agentCertHash, + } // TODO standalone PR status, additionalReconciliationRequired := r.updateOmAuthentication(ctx, conn, []string{set.Name}, s, agentCertSecretSelector, "", "", isRecovering, log) diff --git a/pkg/util/constants.go b/pkg/util/constants.go index 443ae925c..aecef945a 100644 --- a/pkg/util/constants.go +++ b/pkg/util/constants.go @@ -124,7 +124,6 @@ const ( AutomationAgentName = "mms-automation-agent" AutomationAgentPemSecretKey = AutomationAgentName + "-pem" - AutomationAgentPemFilePath = PvcMmsHomeMountPath + "/" + AgentSecretName + "/" + AutomationAgentPemSecretKey // Key used in concatenated pem secrets to denote the hash of the latest certificate LatestHashSecretKey = "latestHash"