diff --git a/creds-manifests/vm-secret-locations b/creds-manifests/vm-secret-locations index ced58dc..b35685c 100644 --- a/creds-manifests/vm-secret-locations +++ b/creds-manifests/vm-secret-locations @@ -111,3 +111,12 @@ # --- netbox VM: the founding SEC-009 miss ------------------------------------ netbox vr1-office1 office1-netbox /root/netbox-secrets/* +# The per-DC MAAS REGION controller VMs (D-132 amendment, 2026-07-30). Adding these rows is +# definition-of-done for the new mint site: the region VM mints its own DB password and +# admin password, and an unlisted location is not audited -- which is exactly how SEC-022 +# happened. Reached ONLY through their DC's rack (no L3 route from vcloud or the headend to +# any DC node plane -- SEC-010 + isolated libvirt nets, see D-138). +region vr1-dc0 ssh vr1-dc0-maas:~/.maas-db-pw +region vr1-dc0 ssh vr1-dc0-maas:~/.maas-admin-pw +region vr1-dc1 ssh vr1-dc1-maas:~/.maas-db-pw +region vr1-dc1 ssh vr1-dc1-maas:~/.maas-admin-pw diff --git a/creds-manifests/vr1-dc0.manifest b/creds-manifests/vr1-dc0.manifest index 44a719b..0799144 100644 --- a/creds-manifests/vr1-dc0.manifest +++ b/creds-manifests/vr1-dc0.manifest @@ -56,3 +56,13 @@ octavia-pki-vr1-dc0.tar.gz 600 local # [octavia-reissue-backup] see creds-matrix-notes.md ## n-reissue-backup vr1-dc0-octavia-pki-.tar.gz 600 local + +# [dc0-maas-region] D-132 amendment (2026-07-30): the per-DC MAAS region controller VM at +# utility-band .6 runs its OWN regiond + PostgreSQL, so it mints its own DB password, its +# own admin password and its own API key. These are NOT the Office1 region's credentials +# (`~/vr1-office1-creds/maas-*`) and MUST NOT be conflated with them -- the whole point of +# the per-DC region is that the DC's provider API is independent of Office1. +# Source is the region VM: minted there, working copy pulled into this folder at mint time. +maas-region-db-password 600 PENDING-TIER2 +maas-region-admin-password 600 PENDING-TIER2 +maas-region-api-key.txt 600 local diff --git a/creds-matrix.tsv b/creds-matrix.tsv index 3eecbba..37eb49c 100644 --- a/creds-matrix.tsv +++ b/creds-matrix.tsv @@ -82,6 +82,19 @@ dc0-maas-apikey per-DC vr1-dc0 headend credentials.yaml api service off-manifest-known stage5 runbook:runbooks/dc-dc-phase4-juju-bundle-per-dc.md:141 SEC-018 n-juju-cred-store dc0-juju-maas-user per-DC vr1-dc0 - - api service off-manifest-known stage5 runbook:runbooks/dc-dc-phase4-juju-bundle-per-dc.md:128 SEC-018 n-juju-user-nopassword +# per-DC MAAS REGION (D-132 amendment 2026-07-30). The region VM is its OWN host-role: +# not `headend` (that is the Office1 region) and not `rack` (the controller it is +# deliberately kept separate from, so the region DB does not share fate with the +# hypervisor running every node). Minted at region install; jumphost copy is the +# SEC-009 consolidation target. mint-ref is operator-terminal because no repo script +# mints these yet -- that is real provenance debt, and writing the install into a +# runbook is what clears it. +dc0-region-db per-DC vr1-dc0 region .maas-db-pw none service source-of-record stage5 operator-terminal SEC-027 - +dc0-region-db per-DC vr1-dc0 jumphost maas-region-db-password none service verbatim-copy stage5 operator-terminal SEC-027 - +dc0-region-admin per-DC vr1-dc0 region .maas-admin-pw gui human source-of-record stage5 operator-terminal SEC-027 - +dc0-region-admin per-DC vr1-dc0 jumphost maas-region-admin-password gui human verbatim-copy stage5 operator-terminal SEC-027 - +dc0-region-apikey per-DC vr1-dc0 jumphost maas-region-api-key.txt api service consolidated stage5 operator-terminal SEC-027 - + # ---------------------------------------------------------------- vr1-dc1 dc1-svc-key per-DC vr1-dc1 jumphost vr1-dc1_svc_ed25519 ssh service consolidated stage3 operator-terminal - n-no-mint-command dc1-svc-key per-DC vr1-dc1 jumphost vr1-dc1_svc_ed25519.pub none service consolidated stage3 operator-terminal - n-no-mint-command @@ -97,6 +110,19 @@ dc1-maas-apikey per-DC vr1-dc1 headend credentials.yaml api service off-manifest-known stage5 runbook:runbooks/dc-dc-phase4-juju-bundle-per-dc.md:141 SEC-019 n-juju-cred-store dc1-juju-maas-user per-DC vr1-dc1 - - api service off-manifest-known stage5 runbook:runbooks/dc-dc-phase4-juju-bundle-per-dc.md:128 SEC-019 n-juju-user-nopassword +# per-DC MAAS REGION (D-132 amendment 2026-07-30). The region VM is its OWN host-role: +# not `headend` (that is the Office1 region) and not `rack` (the controller it is +# deliberately kept separate from, so the region DB does not share fate with the +# hypervisor running every node). Minted at region install; jumphost copy is the +# SEC-009 consolidation target. mint-ref is operator-terminal because no repo script +# mints these yet -- that is real provenance debt, and writing the install into a +# runbook is what clears it. +dc1-region-db per-DC vr1-dc1 region .maas-db-pw none service source-of-record stage5 operator-terminal SEC-027 - +dc1-region-db per-DC vr1-dc1 jumphost maas-region-db-password none service verbatim-copy stage5 operator-terminal SEC-027 - +dc1-region-admin per-DC vr1-dc1 region .maas-admin-pw gui human source-of-record stage5 operator-terminal SEC-027 - +dc1-region-admin per-DC vr1-dc1 jumphost maas-region-admin-password gui human verbatim-copy stage5 operator-terminal SEC-027 - +dc1-region-apikey per-DC vr1-dc1 jumphost maas-region-api-key.txt api service consolidated stage5 operator-terminal SEC-027 - + # ---------------------------------------------------------------- outside the SEC-009 *-creds/ convention (research FINDING 2) vault-unseal-shares singleton - jumphost init.txt none service off-manifest-known vr0-phase02 runbook:runbooks/phase-02-vault-bringup.md:71 SEC-023 n-outside-convention vault-root-token singleton - jumphost init.txt none service off-manifest-known vr0-phase02 runbook:runbooks/phase-02-vault-bringup.md:71 SEC-023 n-outside-convention diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index cadec2e..e948166 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -333,6 +333,32 @@ `scripts/dc-dc-whole-host-budget.py` before applying (the D-104 gate passed at RAM 83% for the 10-node shape and this adds a 12th domain per rack); the substrate caller is `for_each`-keyed so it plans `1 add / 0 change / 0 destroy`. + **dc0 REGION IS LIVE 2026-07-30.** `hot-kid` / `tw7ptw` deployed Ubuntu **noble** (matching + voffice1's 24.04.4), then MAAS **3.7.2** + PostgreSQL **16.14** snaps -- byte-identical + versions to the Office1 region, checked rather than assumed. `maas init region+rack` exit 0; + `maas status` shows `regiond`, `rackd`, `apiserver` ACTIVE and **`dhcpd` INACTIVE** (no DHCP + conflict with the Office1 rack still serving that VLAN -- the migration enables it + deliberately, later). **`http://10.12.8.6:5240/MAAS/api/2.0/version/` -> 200**, which is the + address `jujud` could not reach at Office1. Carve verified BOTH legs: `enp1s0` static + `10.12.8.6` + `fd50:840e:74e2:220::6`, `enp2s0` static `10.12.4.6` **gw `10.12.4.1`**. + **THREE NEW CREDENTIALS MINTED, CONSOLIDATED AND REGISTERED (SEC-027, open SEC 22 -> 23).** + DB password, region admin password and admin API key: minted ON the VM, never printed, + consolidated to `~/vr1-dc0-creds/` (0600; sha256 digests compared to prove the copies are + identical; API key format-verified parts=3). **The creds MATRIX now EXPECTS them at BOTH + DCs** (operator-directed): 5 rows per DC, a new `region` host-role token in + `creds-matrix.py`'s enum, 4 rows in `vm-secret-locations` (definition-of-done for a new + mint site -- an unlisted location is not audited, which is how SEC-022 happened), and the + dc0 manifest declares its three. **dc1's three now FAIL S2 by design** -- that is the + forward register making dc1's absence detectable, which is the whole purpose of D-137. + Harness `tests/creds-matrix` 65/65 PASS; `creds-matrix.py` S1 111 rows, all enums valid. + **SSH REACH TO DC NODES, recorded because it is not obvious:** deployed nodes carry the + MAAS-registered `vr1-office1-svc` key, NOT the per-DC rack service key, so each hop needs + its OWN identity -- a bare `ssh -i -J voffice1,` FAILS because `-i` forces one + key on every hop. Durable aliases added to vcloud `~/.ssh/config.d/vr1-sites` + (`vr1-dc0-rack`, `vr1-dc1-rack`, `vr1-dc0-maas`, `vr1-dc0-juju`), each hop keyed correctly; + no credential was copied anywhere. **STILL OWED:** migrate the 9 dc0 nodes into this region + (re-enrol + re-carve + re-tag + images + DHCP + power), then re-point Juju at + `10.12.8.6:5240`; dc1's region VM is authored but NOT applied. **^ THE `1 add` FIGURE IS WRONG, CORRECTED BY MEASUREMENT: it is `2 to add`** -- `modules/node-vm` creates a `libvirt_domain` AND a `libvirt_volume` per node. Carried in from the D-104 amendment's prose, which is wrong at resource level for the same reason. The diff --git a/docs/security-ledger.md b/docs/security-ledger.md index 676ec2d..5e23ffe 100644 --- a/docs/security-ledger.md +++ b/docs/security-ledger.md @@ -77,3 +77,4 @@ The current rule text is in D-137; this paragraph is kept as the record of what existed before it. | SEC-026 | 2026-07-30 | **A MAAS admin-scoped API key becomes RESIDENT on a DC-local host, by D-138.** D-138 (RULED 2026-07-30) moves the cloud-facing client -- the Juju client, and `phase-03`..`phase-06`'s `openstack` CLI work -- INTO each DC, because `voffice1` has no L3 path to any DC node plane and SEC-010/D-052/D-125 deliberately forbid creating one. The client needs its DC's MAAS credential where it runs, so `juju-vr1-dc0`'s key (SEC-018) now lives on the dc0 client host, and `juju-vr1-dc1`'s (SEC-019) will on dc1's. **The exposure is wider than the DC it sits in: the key is MAAS ADMIN-scoped (full machine/power/deploy) and the MAAS region is SHARED by BOTH DCs**, so a host inside dc0 holding it has region-wide MAAS admin, including over dc1's hardware. This is a NEW residency, not a new key -- SEC-018/-019 already carry the keys' own rotation obligations. | 2026-07-30 Stage-5 bootstrap failure + D-138 ruling; capture `docs/audit/stage5-bootstrap-reachability-20260730.txt` | operator | **OPEN.** (1) **ISOLATION IS THE LOAD-BEARING CONTROL:** each DC's client host receives ONLY THAT DC's credential. Never copy the whole Juju client credential store (`~/.local/share/juju/credentials.yaml` on voffice1 holds BOTH `vr1-dc0-cred` and `vr1-dc1-cred`) to a DC host -- that single act would put dc1's credential on dc0's rack and destroy the per-DC isolation SEC-018/-019 exist to create. Verify after any client rebuild that `juju credentials --client` on a DC host lists exactly one. (2) ROTATE at v1 close, or immediately if the DC client host is rebuilt or shared. (3) SCOPE HARDENING CANDIDATE, Roosevelt-relevant: MAAS has no per-DC admin scope, so the blast radius is regional by construction; a narrower grant (or a per-DC MAAS region) is the fix and is deferred, not solved. (4) The residency must be re-asserted at every DC standup as part of D-138's definition-of-done. | +| SEC-027 | 2026-07-30 | **Per-DC MAAS region controller credentials -- a NEW credential class, three secrets per DC.** D-132's amendment (RULED 2026-07-30) gives each DC its own MAAS region controller VM at utility-band `.6`, running its own `regiond` + PostgreSQL. Each region therefore mints and holds: (a) a PostgreSQL role password for the `maas` DB role, (b) a MAAS region `admin` account password (a HUMAN login), and (c) that admin's MAAS API key (3-part, service). dc0's are MINTED and consolidated to `~/vr1-dc0-creds/` (`maas-region-db-password`, `maas-region-admin-password`, `maas-region-api-key.txt`, all 0600, sha256-verified identical to the on-VM source, never printed). dc1's are NOT YET MINTED -- its region VM is authored but not applied. **These are NOT the Office1 region's credentials and must never be conflated with them**: the entire point of the per-DC region is that each DC's provider API is independent of Office1. | 2026-07-30 Stage-5 region build; D-132 amendment + addendum; capture `docs/audit/stage5-bootstrap-reachability-20260730.txt` | operator | **OPEN -- rotation obligation + two structural notes.** (1) ROTATE all three at v1 close, or immediately if the region VM is rebuilt or shared. (2) **RESIDUAL ARGV EXPOSURE, recorded rather than hidden:** `maas init` offers NO stdin or file option for `--database-uri`, so the DB password is briefly visible in that host's own `ps` output at init time and is then written to `/var/snap/maas/current/regiond.conf`. The URI was assembled inside the remote shell from a 0600 file so it never reached the operator terminal or the session transcript, but the argv exposure on the VM itself is unavoidable with this tool. Identical in shape to the existing Office1 region -- not a new exposure class. (3) **PROVENANCE DEBT, deliberate:** all five matrix rows carry `mint-ref=operator-terminal` because NO repo script mints these yet. That is truthful, not an oversight -- writing the region install into a runbook or script is what clears it, and until then these are not reproducible from the repo if the jumphost is rebuilt (research FINDING 1 class). (4) The `region` host-role token was added to `scripts/creds-matrix.py`'s enum for this class; `creds-manifests/vm-secret-locations` gained four rows, which is definition-of-done for a new mint site (an unlisted location is not audited -- how SEC-022 happened). | diff --git a/scripts/creds-matrix.py b/scripts/creds-matrix.py index 2f7a202..ad3d5ef 100644 --- a/scripts/creds-matrix.py +++ b/scripts/creds-matrix.py @@ -42,7 +42,11 @@ NCOL = len(COLUMNS) CARDINALITY = {"singleton", "per-site", "per-DC", "per-node", "per-tenant"} -HOST_ROLE = {"jumphost", "headend", "rack", "edge", "netbox", "cloud", "unit", "client", "-"} +# `region` added 2026-07-30 for the D-132-amendment per-DC MAAS region controller VM +# (one per DC, utility-band .6). It is NOT `headend` -- that role is the Office1 region -- +# and NOT `rack`, which is the DC rack controller the region is deliberately separate from. +HOST_ROLE = {"jumphost", "headend", "rack", "region", "edge", "netbox", "cloud", "unit", + "client", "-"} ACCESS_TYPE = {"gui", "api", "ssh", "cli-profile", "console", "none"} PRINCIPAL = {"human", "service", "-"} CUSTODY = {"consolidated", "source-of-record", "off-manifest-known",