Files
stack/docs/guides/migrate-tier.md
2026-07-15 05:28:08 -05:00

8.0 KiB

Migrating to the Federated Tier

KBN-101-07 ownership: This active documentation is a non-operative KBN-101 contract until KBN-101-02/-03/-05/-06 land and KBN-101-08 activates an exact reviewed release. The commands below describe the produced interface only. Do not run them on the current branch or replace them with direct PostgreSQL, raw SQL, legacy storage migration, or credential-on-argv procedures.

Required activation sequence

The deployment control plane executes, in order: external privileged bootstrap; verified TLS and roles; mosaic-db-migrator --run; mosaic-db-migrator --verify; then Gateway readiness. The runner is the only attestation producer after its verified TLS, identity, manifest, and schema checks. A data importer is never a schema bootstrap, extension installer, repair command, or DDL consumer.

Target material contract

KBN-101-05 obtains the target URL from Vault KV-v2 secret-{env}/mosaic-stack/database/importer, key url, and reads its authenticated version from the same successful response data.metadata.version. A hash or DSN byte sequence is not a provider version. The renderer treats URL bytes and provider version as one generation, writes a temporary generation directory with fsync plus atomic rename, and creates separate immutable consumer mounts. Swarm uses distinct versioned secret/config references. A deployment cannot mix generations.

Consumer Permitted material
Migrator-attestation producer (10003:10003) Its own migration URL/CA; read-only /run/secrets/mosaic-migrate-target-url and /run/secrets/mosaic-migrate-target-version, each 0400, solely to bind; producer-only attestation output at /run/mosaic-attestations-producer/migrate-target.v1.json; root-wrapper-only signing key. It never connects with, uses, exports, logs, or forwards the importer URL/version.
Privileged deployment handoff controller After runner success and before importer creation, it receives only root-owned non-secret expected provider-version/URL-SHA-256/generation descriptor and pinned public verifier key—not URL bytes or private key. It safe-opens/verifies descriptor and producer artifact, copies exact bytes to a new importer-only mount with fsync/atomic rename, sets 10002:10002 0400, seals it read-only, and refuses importer start on any partial/wrong-generation/wrong-owner/mode result.
Importer (10002:10002) Its own immutable 0400 copies at the same URL/version paths; CA at exact DATABASE_TLS_CA_CERT_PATH=/run/secrets/mosaic-db-ca.crt; pinned Ed25519 public key; read-only /run/mosaic-attestations/migrate-target.v1.json supplied only by the sealed handoff.
Gateway/runtime/unrelated container No importer URL/version, importer artifact, attestation private key, or unrelated CA mount.

The migrator and importer safe-open URL, provider-version, attestation, and public-key files only with O_RDONLY|O_CLOEXEC|O_NOFOLLOW; they validate from the opened fd that the file is regular, has its expected owner/mode and link count one. The migrator digests only that URL fd for binding, then zeroizes/closes it. The importer reads URL bytes once into protected memory, validates the signed binding and exact CA before connecting from those same bytes, then zeroizes/closes every fd. It neither logs nor exposes a URL/version/attestation/key oracle.

Produced command interface

After activation and only after approved target preparation, the future interface is:

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 provider-version file is fixed deployment material, not argv. This connecting dry-run consumes its nonce; before an actual copy, obtain fresh mosaic-db-migrator --verify and a new sealed handoff. The runner uses its migration identity; the importer connects only as non-DDL mosaic_data_importer and only after all pre-connect validation. After verified TLS and before DML it compares PostgreSQL system ID, database OID, current_user, CA/SPKI, and manifest/schema fingerprints to the artifact.

Required refusals and evidence

KBN-101-02/-03/-05/-06 must prove, with stable sanitized errors, that no target connection occurs for missing/unsafe URL/version/attestation/public-key files; symlink, hardlink, owner, mode, or TOCTOU violations; mixed URL/version generations; missing/wrong CA mount; stale/replayed/tampered or revoked-key artifacts; provider rotation/revocation; wrong TLS/server/database/role/manifest binding; raw --target-url; DATABASE_URL fallback; runtime/owner identity; consumer leakage; or any DDL attempt. Post-connect identity mismatch closes with zero DML/DDL. Tests also prove no forwarding, child environment, logging, or error oracle leaks URL/version/key/artifact contents.

The attestation is credential-free JCS with detached Ed25519 signature and binds issued/expiry, nonce, authenticated provider version, exact URL-fd SHA-256, TLS host/port/database, CA/SPKI, PostgreSQL system ID/database OID, importer role, manifest/schema, and producer identity. Provider version rotation invalidates an old artifact and requires a fresh rendered generation plus runner verification.

Actual copy after dry-run

After reviewed dry-run, obtain the required fresh verification/attestation generation, then use:

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

The dry-run artifact is terminally replayed and must be rejected; --yes bypasses no file, generation, signature, TLS, identity, or DDL control.

Data boundary and recovery

The importer has only an allowlisted mutable-table DML registry. It has no grant for immutable KBN relations, schemas, roles, memberships, extensions, catalogs, or the Drizzle ledger. Source PGlite uses its explicit local directory and does not make a PostgreSQL URL fallback valid.

A failed or ambiguous migration is a control-plane incident: preserve sanitized evidence, retain the approved backup/rollback state, and retry only after independent review. Never inspect, unlock, repair, or initialize the target with ad hoc SQL or copied credentials.