Skip to content

bug(backups): MongoDB to-copy restore leaves the target cluster unauthenticatable while RestoreJob reports Succeeded #3832

Description

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/databaseIssues or PRs related to managed databases (postgres, mariadb, redis, etcd, kafka, clickhouse)kind/bugCategorizes issue or PR as related to a bugpriority/important-soonMust be staffed and worked on either currently, or very soon, ideally in time for the next releasetriage/acceptedIndicates an issue is ready to be actively worked on

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions