Files
net-kingdom/tools/security-bootstrap-console/README.md

268 lines
11 KiB
Markdown

# Security Bootstrap Console
Local console and localhost web UI for the NetKingdom guided security bootstrap
experience.
The console prints trust stage, gates, checklists, non-secret templates, and can
write an explicit custody-mode approval record. It does not collect secret
values and refuses live OpenBao initialization.
Run:
```bash
python3 tools/security-bootstrap-console/security_bootstrap_console.py status
```
Print the king credential kit checklist:
```bash
python3 tools/security-bootstrap-console/security_bootstrap_console.py king-kit
```
Validate non-secret kit metadata:
```bash
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
--metadata .local/security-bootstrap.json \
validate-king-kit
```
Approve custody mode from the CLI:
```bash
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
--metadata .local/security-bootstrap.json \
approve-custody-mode \
--mode temporary-single-king \
--mfa-enrolled-confirmed \
--mfa-enrollment-source identity-provider \
--recovery-confirmed \
--custody-packet-prepared
```
The command asks for the phrase `approve custody mode` unless `--yes` is passed.
`two-of-three-planned` can be recorded in metadata but cannot approve live
OpenBao init.
For TOTP, use the QR code or setup key from the identity provider or other
authority that will verify the login. This tool records only the non-secret
enrollment confirmation and source.
Recovery material means the operator can regain control of the platform-root
credential and encrypted bootstrap bundle without this UI storing any values:
the platform-root password-safe entry, MFA recovery or re-enrollment path,
custodian age private-key location, encrypted bootstrap bundle location, and
notification/setup contact are all known.
The custody packet is separate. It is the offline OpenBao ceremony envelope:
selected custody strategy, recovery-material references, init checklist,
unseal-share assignment slots, root-token disposition plan, and signature/date.
Select the custody strategy first, prepare recovery material and the custody
packet for that strategy, then approve the strategy. Only after that approval
should the OpenBao preflight/init sequence begin.
Secret capture is an architecture gate, not a user checkbox. The control
surface must not request or store passwords, OTP seeds, recovery codes, private
keys, OpenBao root tokens, or unseal shares. The UI reports this automatically
from local metadata and plaintext bootstrap-secret presence.
Serve the local approval UI:
```bash
make security-bootstrap-ui
```
Open `http://127.0.0.1:8876`.
The Make target stores non-secret progress in `.local/security-bootstrap.json`.
That directory is intentionally ignored by Git so local setup state survives
UI/server restarts without being committed.
The web UI is structured as:
1. **Roles & Responsibilities** - global bootstrap roles with designated
operator emails.
2. **Subsystems & Scope** - installation and initial access for LLDAP,
privacyIDEA, KeyCape, the custodian age envelope, and Railiance OpenBao.
3. **Integration & Tests** - OIDC and OpenBao preflight checks, with every
operator command shown as a copyable console block.
4. **Usecases & Runbooks** - guided routines for key-material compromise,
trial-output exposure, replacement unseal keys, and OpenBao token
revocation.
5. **Artefacts & Locations** - final non-secret overview of established
artefacts and where to find their custody references.
Role, subsystem, integration, and artefact records use the same fields:
`name`, `description`, `subsystem`, `responsibility`, `location`, and `state`.
States are `nil`, `set`, `err`, and `ok`. Role chips expose the designated
email as hover text.
Responsibility assignments are edited through the **Change responsibilities**
foldout. Editing enables local Save/Cancel actions; Save writes only non-secret
role metadata and Cancel restores the last loaded values. Command cards use
`blocked`, `todo`, `redo`, and `done` to show whether an operator command is
available, needs to be run, should be repeated after a state change, or has
already succeeded.
The **Key material compromised** runbook is also useful for trial ceremonies:
mark the trial output as exposed, stop treating the generated unseal shares or
root token as production material, then either rotate unseal keys after unseal
or reset the trial environment before any live secrets are migrated.
The **OpenBao token revocation** runbook includes a self-revoke action for the
token currently stored in the OpenBao pod token helper and an accessor-based
revocation action for accidentally disclosed tokens. The accessor path prompts
inside the pod for a root/sudo-capable OpenBao token and avoids placing token
values on the local command line.
The UI is a guide and approval surface, not the identity provider. Current
lightweight-mode credential placement is:
- bootstrap bundle encryption: custodian age public key;
- user record: LLDAP (`https://lldap.coulomb.social`);
- MFA enrollment and QR/setup key: privacyIDEA self-service
(`https://pink-account.coulomb.social`);
- privacyIDEA setup/admin repair: `pi-admin` at
`https://pink.coulomb.social`;
- OIDC/IAM Profile token issuer: KeyCape (`https://kc.coulomb.social`);
- secret custody and OpenBao admin policies: OpenBao, after the attended
ceremony.
The UI opens the external authority in a new browser tab and records only
non-secret progress. It does not embed or prefill secret-bearing forms unless a
future audited integration is built for that authority.
The custodian age public key is safe to store here and is used as the recipient
for encrypted bootstrap bundles. The private age key is not stored here. Record
only a non-secret private-key custody reference, such as a password-safe entry
label or offline packet label. See
`docs/security-bootstrap-age-custody.md` for the trust model.
LLDAP has no public registration flow. The first user path is:
1. Log in to `https://lldap.coulomb.social` as `admin`.
2. Retrieve `LLDAP_LDAP_USER_PASS` from the password safe entry
`net-kingdom/LLDAP/admin`.
3. Create the dedicated `platform-root` or `king` account.
4. Add it to `net-kingdom-admins` for the current lightweight path.
5. Store the new account password only in the password safe/offline custody
packet, not in this metadata file.
For OTP enrollment, do not create a separate shadow identity in privacyIDEA if
the LLDAP resolver is working. Use `pi-admin` to verify or repair the
privacyIDEA realm, resolver, and self-enrollment policy. Then use
`platform-root` in the self-service portal to generate the QR code or setup
key and verify the factor. Admin-assisted token assignment is a fallback only;
record it as the MFA enrollment source, but never record the seed, QR code, or
recovery codes in this UI.
If the live privacyIDEA instance has lost the `coulomb` realm, LLDAP resolver,
or self-service policies, open **Usecases & Runbooks** and copy **Repair
privacyIDEA realm and self-service**. The action is attended: it prompts for
the `pi-admin` password and the LLDAP bind/admin password, writes them only to a
private temporary directory, runs
`sso-mfa/k8s/privacyidea/repair-realm-live.sh`, removes the temporary files on
exit, and then runs `sso-mfa/k8s/verify-t06.sh`. The UI does not store either
password, and TOTP enrollment or re-enrollment remains a human step in
`https://pink-account.coulomb.social`.
After doing that, return to the control surface, set account reference
`platform-root@lldap`, check `Account created`, `Admin group assigned`, and
`Password stored`, then save progress.
KeyCape does not have a dashboard at its root URL; `https://kc.coulomb.social`
returning `404` is expected. Use
`https://kc.coulomb.social/.well-known/openid-configuration` for issuer
discovery or a registered OIDC client to test real login. The bootstrap UI acts
as the local `netkingdom-bootstrap-console` callback at
`http://127.0.0.1:8876/oidc/callback`.
Treat that as a login-path check only: it should force LLDAP password auth and
privacyIDEA MFA, then return to the local callback page. The callback exchanges
the code and shows non-secret claims only; it does not store tokens, OTP values,
or passwords. Mark `OIDC login verified` only for the same identity recorded in
the credential section.
If the login-check flow redirects to
`https://kc.coulomb.social/api/oidc/authorization...` and lands on a 404, the
KeyCape service is reachable but its browser-facing Authelia redirect config is
not yet rolled out. Regenerate `keycape-config` with
`sso-mfa/k8s/keycape/create-secrets.sh` and restart the KeyCape deployment
after confirming `authelia.browserBaseURL` is `https://auth.coulomb.social`.
After Authelia password login, KeyCape should show a compact OTP challenge if
privacyIDEA reports that MFA is required. Only then should it issue the final
OIDC authorization code back to the local callback.
Print a blank offline custody packet template:
```bash
python3 tools/security-bootstrap-console/security_bootstrap_console.py custody-packet
```
Show safe OpenBao preflight commands:
```bash
python3 tools/security-bootstrap-console/security_bootstrap_console.py openbao-preflight \
--railiance-path ../railiance-platform
```
Run safe OpenBao preflight targets:
```bash
python3 tools/security-bootstrap-console/security_bootstrap_console.py openbao-preflight \
--railiance-path ../railiance-platform \
--run
```
This still does not run `bao operator init`.
Validate the current NET-WP-0017-T02 OpenBao audit/recovery gates:
```bash
make security-bootstrap-validate-t02
```
The validator checks local non-secret metadata, the next independent quorum
roster, the Audit Core retention/risk decision, and the Railiance restore and
emergency-drill evidence validators. It fails until real evidence files exist,
the signed custody roster exists, and the remaining T02 metadata gates are
recorded.
Create and validate the local two-of-three custody roster:
```bash
make security-bootstrap-custody-roster-template \
> .local/custody-roster.json
# Edit .local/custody-roster.json locally. It may contain real contact data,
# so it is ignored by Git and must not be copied into State Hub or workplans.
make security-bootstrap-sign-custody-roster
make security-bootstrap-validate-custody-roster
```
The roster is tamper-evident through an SSH detached signature with namespace
`netkingdom-custody-roster`. The default signer is
`~/.ssh/id_custodian_agent`; the local allowed-signers file is written to
`.local/custody-roster.allowed_signers`.
OpenBao itself is operated from the Railiance runbook. Public ingress is
disabled, so the live ceremony uses Railiance `make` targets, `kubectl exec`,
or an operator port-forward. The local UI can record non-secret milestones
such as preflight passed, initialized/unsealed, root-token disposition, and
restore drill passed; it must never record root tokens or unseal shares.
Optional non-secret metadata can be supplied:
```bash
python3 tools/security-bootstrap-console/security_bootstrap_console.py metadata-template \
> .local/security-bootstrap.json
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
--metadata .local/security-bootstrap.json \
status
```
Do not put passwords, OTP seeds, OpenBao root tokens, unseal shares, recovery
codes, private keys, or screenshots of secret output into the metadata file.