docs(#771): bind tier importer to verified target
This commit is contained in:
@@ -17,9 +17,10 @@ The PostgreSQL destination schema is prepared separately before data migration:
|
||||
|
||||
1. The dedicated DDL runner executes `mosaic-db-migrator --run` using its migration-only
|
||||
identity.
|
||||
2. The same runner succeeds at `mosaic-db-migrator --verify` against the exact destination.
|
||||
3. Only then may `mosaic storage migrate-tier` connect as dedicated non-DDL
|
||||
`mosaic_data_importer` to copy data.
|
||||
2. The same runner succeeds at `mosaic-db-migrator --verify` against the exact destination and,
|
||||
only then, emits a signed target-bound attestation.
|
||||
3. Only then may `mosaic storage migrate-tier` verify that attestation and connect as dedicated
|
||||
non-DDL `mosaic_data_importer` to copy data.
|
||||
|
||||
The data migration never executes DDL or changes PostgreSQL roles, memberships, schemas,
|
||||
extensions, extension members, system catalogs, or the Drizzle ledger. Its only target writes are
|
||||
@@ -32,13 +33,17 @@ PostgreSQL is always pre-migrated and runner-verified, including when the source
|
||||
|
||||
- Federated stack is running and healthy (see [Federated Tier Setup](../federation/SETUP.md)).
|
||||
- An approved source backup exists and the target is identified in the KBN-101 change record.
|
||||
- The target passed the runner `--run` and `--verify` sequence above.
|
||||
- The operator has an approved, dedicated importer credential file at
|
||||
`/run/secrets/mosaic_migrate_target_url`; the **path reference** is non-secret, but its
|
||||
contents are never printed, copied, committed, or placed on argv.
|
||||
- KBN-101-02 validates that file before any target connection: it must be a regular,
|
||||
non-symlink file, owned by the expected importer UID:GID, mode `0600`, readable only by
|
||||
that importer process, and its value must be redacted from all output.
|
||||
- The target passed the runner `--run` and `--verify` sequence above; `--verify` is the only
|
||||
trusted attestation producer after verified TLS, identity, manifest, and schema checks.
|
||||
- The operator has an approved, dedicated high-entropy importer credential file at
|
||||
`/run/secrets/mosaic_migrate_target_url` and its paired non-secret attestation artifact at
|
||||
`/run/mosaic-attestations/migrate-target.v1.json`. Neither file contents are printed, copied,
|
||||
committed, or placed on argv.
|
||||
- KBN-101-02 validates both references before any target connection: each is a regular,
|
||||
non-symlink file with the exact required owner/mode. The importer gets only pinned public
|
||||
verification key(s) and the attestation; the runner-only Ed25519 private key never reaches
|
||||
importer/runtime. The URL file is opened, digested, parsed, and connected from the same
|
||||
in-memory bytes with no reread.
|
||||
|
||||
### Source modes
|
||||
|
||||
@@ -57,13 +62,15 @@ mosaic-db-migrator --run
|
||||
mosaic-db-migrator --verify
|
||||
mosaic storage migrate-tier --to federated \
|
||||
--target-url-file /run/secrets/mosaic_migrate_target_url \
|
||||
--target-attestation-file /run/mosaic-attestations/migrate-target.v1.json \
|
||||
--dry-run
|
||||
```
|
||||
|
||||
The frozen KBN-101-02 option is exactly
|
||||
`--target-url-file /run/secrets/mosaic_migrate_target_url`. It is a file reference, not a
|
||||
URL option. The runner and importer use distinct connections: the runner has migration
|
||||
DDL authority; the importer has only approved data-copy DML authority.
|
||||
The frozen KBN-101-02 options are exactly
|
||||
`--target-url-file /run/secrets/mosaic_migrate_target_url` and
|
||||
`--target-attestation-file /run/mosaic-attestations/migrate-target.v1.json`. They are
|
||||
non-secret file references, not URL options. The runner and importer use distinct connections:
|
||||
the runner has migration DDL authority; the importer has only approved data-copy DML authority.
|
||||
|
||||
Expected dry-run output is sanitized and contains no connection string, username, host,
|
||||
database name, SQL, or credential value:
|
||||
@@ -95,6 +102,7 @@ After a reviewed dry-run, repeat the same verified route with `--yes`:
|
||||
mosaic-db-migrator --verify
|
||||
mosaic storage migrate-tier --to federated \
|
||||
--target-url-file /run/secrets/mosaic_migrate_target_url \
|
||||
--target-attestation-file /run/mosaic-attestations/migrate-target.v1.json \
|
||||
--yes
|
||||
```
|
||||
|
||||
@@ -103,8 +111,12 @@ verification, target-file validation, role checks, redaction, or the no-DDL boun
|
||||
|
||||
The command will:
|
||||
|
||||
1. Verify the runner-prepared target schema before opening the importer target connection.
|
||||
2. Validate the credential-file reference and use the dedicated importer identity.
|
||||
1. Before target connection, validate both files, JCS/Ed25519 signature and pinned key ID,
|
||||
expiry, nonce replay, secret version/digest, canonical TLS host/port/database, CA/SPKI,
|
||||
expected importer role, and manifest/schema bindings.
|
||||
2. Connect only from the once-opened in-memory URL bytes, then before transaction/DML compare
|
||||
PostgreSQL system identifier, database OID, `current_user`, CA/SPKI, and manifest/schema
|
||||
fingerprints to the attestation; mismatch closes with zero DML/DDL.
|
||||
3. Copy data in dependency order without DDL.
|
||||
4. Report sanitized row counts and warnings.
|
||||
|
||||
@@ -116,14 +128,26 @@ DDL attempt:
|
||||
- Raw `--target-url` or any URL/credential value on argv.
|
||||
- `DATABASE_URL` as a target or source fallback.
|
||||
- A runtime owner, migrator, schema owner, or extension owner used as the data importer.
|
||||
- Missing, non-regular, symlinked, wrong-owner, or wrong-mode target credential file.
|
||||
- Missing, non-regular, symlinked, wrong-owner, wrong-mode, substituted, or changed-after-check
|
||||
credential file.
|
||||
- Missing, stale, replayed, tampered, wrong-key, revoked-key, expired, malformed, or wrong-binding
|
||||
attestation file.
|
||||
- Wrong host, database, CA/SPKI, PostgreSQL system identifier, database OID, importer role,
|
||||
manifest, schema, or credential secret-version/digest.
|
||||
- Any mode other than the runner-prepared/verified PostgreSQL destination route.
|
||||
- Any direct DDL attempt by the migration command or its target connection.
|
||||
|
||||
KBN-101-02 SHALL add `packages/storage/src/migrate-tier.spec.ts::secureTargetRoute` and
|
||||
its integration counterpart. They prove no target connection is opened on each interface
|
||||
rejection. The finite operator-document scanner rejects an unowned route or a guide that
|
||||
reintroduces a credential-bearing command.
|
||||
The signed attestation has canonical UTF-8/JCS bytes and detached Ed25519 signature. Its
|
||||
credential-free v1 payload binds format/version/key ID; issued/expiry/nonce; exact credential
|
||||
secret version and SHA-256; canonical TLS host/port/database; CA/SPKI; PostgreSQL system
|
||||
identifier/database OID; importer role; manifest/schema; and producer invocation/build/image/
|
||||
correlation. Artifacts are atomically written/renamed `0444`; the replay cache survives until
|
||||
expiry; public-key overlap/revocation and credential rotation force a fresh runner verification.
|
||||
|
||||
KBN-101-02 SHALL add `packages/storage/src/migrate-tier.spec.ts::secureTargetRouteAndAttestation`
|
||||
and its integration counterpart. They prove zero target connection for pre-connect failures and
|
||||
zero DML/DDL for post-connect identity mismatch. The finite operator-document scanner rejects an
|
||||
unowned route or a guide that reintroduces a credential-bearing command.
|
||||
|
||||
## What gets migrated
|
||||
|
||||
|
||||
Reference in New Issue
Block a user