What happens
A RestoreJob that restores a MongoDB backup into a second MongoDB application (the to-copy flow documented in examples/backups/mongodb) reports status.phase: Succeeded, but the target cluster is unusable afterwards. Every system user in the target now carries the source cluster's password, so the target's own <release>-percona-server-mongodb-users and internal-<release>-users Secrets no longer authenticate. The psmdb operator itself is affected: its clusterAdmin and clusterMonitor connections start failing at the moment the restore completes and never recover.
Evidence
The e2e case mongodb-2-backup-roundtrip has failed in 20 out of 20 CI runs since it landed, always at the same point: the final step that reads the restored sentinel document back out of the target.
== Step 30 verify: the sentinel round-tripped through S3 into the copy ==
MongoServerError: Authentication failed.
command terminated with exit code 1
The target cluster's mongod log gives a sharp boundary. The Cozystack RestoreJob was created at 15:47:37, the psmdb operator's pbm restore ran from 15:47:44 to 15:47:53, and the PerconaServerMongoDBRestore reached state: ready.
15:47:01 .. 15:47:50 every auth succeeds (clusterAdmin, clusterMonitor, userAdmin, backup)
15:47:44 .. 15:47:53 pbm logical restore replays the source dump into the target
15:47:52 onwards every auth fails, and keeps failing to the end of the log
Each failure carries the same reason:
"msg":"Failed to authenticate","attr":{"user":"clusterAdmin","db":"admin",
"error":"AuthenticationFailed: SCRAM authentication failed, storedKey mismatch"}
storedKey mismatch means the user documents are present but their stored SCRAM credentials no longer match the ones the target's Secret holds. The failing set includes databaseAdmin from a mongosh 2.5.10 client, which is the example harness reading the sentinel back, and clusterAdmin and clusterMonitor from the operator itself.
Both halves before this point are genuinely healthy. The BackupJob completed in 75 seconds with BackupCompleted, the RestoreJob completed in 20 seconds with RestoreCompleted, and the sentinel data did travel through S3 into the target. The only thing that breaks is the ability to talk to the target afterwards.
Mechanism
A psmdb logical restore replays the source dump including the admin database, so the source cluster's admin.system.users documents replace the target's. Percona documents this precondition for restoring into a new environment: the destination must already hold a Secrets object with the same user passwords as the original cluster.
The Cozystack MongoDB chart cannot satisfy that precondition. packages/apps/mongodb/templates/mongodb.yaml hardcodes the users Secret to the release name:
secrets:
users: {{ .Release.Name }}-percona-server-mongodb-users
There is no value that overrides it, and the operator generates a fresh random password set per release. Two MongoDB applications in the same namespace therefore always disagree on system-user credentials, and a to-copy restore between them always ends with the target holding credentials nobody can look up through the target application.
Impact
- A tenant following
examples/backups/mongodb end to end is left with a broken target cluster and a Succeeded RestoreJob telling them it worked.
- The target's
<release>-credentials Secret, which is what the dashboard surfaces as the connection URI, is silently stale.
- The psmdb operator loses its own access to the target, so subsequent reconciliation of that cluster is degraded.
mongodb-2-backup-roundtrip holds the in-tree e2e suite red on every branch that runs it.
Notes on the fix space
I am not proposing a specific fix, but the shape of the problem constrains it. The restore path in internal/backupcontroller/psmdbstrategy_controller.go builds the operator Restore CR from backupSource plus clusterName and does not touch system users, so any fix has to decide deliberately what the target's credentials should be after a cross-cluster restore. Making the target adopt the source's system-user Secret before the restore matches what the operator expects, but it hands one application's credentials to another and that is a security decision rather than a mechanical one. Reporting the RestoreJob as Succeeded while the target is unreachable is worth treating as a separate defect from the credential handling itself.
One thing this is not: the bootstrap gate for the default MongoDB strategy is not involved. cozy-default-mongodb was present and the BackupJob dispatched against it normally in every failing run.
Reproduction
Run examples/backups/mongodb/run-all.sh in a namespace with a provisioned bucket, or run the mongodb chainsaw suite from hack/e2e-chainsaw/mongodb/. It fails on the final verification every time.
What happens
A
RestoreJobthat restores a MongoDB backup into a second MongoDB application (the to-copy flow documented inexamples/backups/mongodb) reportsstatus.phase: Succeeded, but the target cluster is unusable afterwards. Every system user in the target now carries the source cluster's password, so the target's own<release>-percona-server-mongodb-usersandinternal-<release>-usersSecrets no longer authenticate. The psmdb operator itself is affected: itsclusterAdminandclusterMonitorconnections start failing at the moment the restore completes and never recover.Evidence
The e2e case
mongodb-2-backup-roundtriphas failed in 20 out of 20 CI runs since it landed, always at the same point: the final step that reads the restored sentinel document back out of the target.The target cluster's mongod log gives a sharp boundary. The Cozystack
RestoreJobwas created at 15:47:37, the psmdb operator'spbmrestore ran from 15:47:44 to 15:47:53, and thePerconaServerMongoDBRestorereachedstate: ready.Each failure carries the same reason:
storedKey mismatchmeans the user documents are present but their stored SCRAM credentials no longer match the ones the target's Secret holds. The failing set includesdatabaseAdminfrom amongosh 2.5.10client, which is the example harness reading the sentinel back, andclusterAdminandclusterMonitorfrom the operator itself.Both halves before this point are genuinely healthy. The
BackupJobcompleted in 75 seconds withBackupCompleted, theRestoreJobcompleted in 20 seconds withRestoreCompleted, and the sentinel data did travel through S3 into the target. The only thing that breaks is the ability to talk to the target afterwards.Mechanism
A psmdb logical restore replays the source dump including the
admindatabase, so the source cluster'sadmin.system.usersdocuments replace the target's. Percona documents this precondition for restoring into a new environment: the destination must already hold a Secrets object with the same user passwords as the original cluster.The Cozystack MongoDB chart cannot satisfy that precondition.
packages/apps/mongodb/templates/mongodb.yamlhardcodes the users Secret to the release name:There is no value that overrides it, and the operator generates a fresh random password set per release. Two MongoDB applications in the same namespace therefore always disagree on system-user credentials, and a to-copy restore between them always ends with the target holding credentials nobody can look up through the target application.
Impact
examples/backups/mongodbend to end is left with a broken target cluster and aSucceededRestoreJob telling them it worked.<release>-credentialsSecret, which is what the dashboard surfaces as the connection URI, is silently stale.mongodb-2-backup-roundtripholds the in-tree e2e suite red on every branch that runs it.Notes on the fix space
I am not proposing a specific fix, but the shape of the problem constrains it. The restore path in
internal/backupcontroller/psmdbstrategy_controller.gobuilds the operator Restore CR frombackupSourceplusclusterNameand does not touch system users, so any fix has to decide deliberately what the target's credentials should be after a cross-cluster restore. Making the target adopt the source's system-user Secret before the restore matches what the operator expects, but it hands one application's credentials to another and that is a security decision rather than a mechanical one. Reporting the RestoreJob asSucceededwhile the target is unreachable is worth treating as a separate defect from the credential handling itself.One thing this is not: the bootstrap gate for the default MongoDB strategy is not involved.
cozy-default-mongodbwas present and the BackupJob dispatched against it normally in every failing run.Reproduction
Run
examples/backups/mongodb/run-all.shin a namespace with a provisioned bucket, or run themongodbchainsaw suite fromhack/e2e-chainsaw/mongodb/. It fails on the final verification every time.