Files
key-cape/workplans/KEY-WP-0003-bootstrap-console-oidc-mfa-login.md
tegwick 7e22fcf3c7
Some checks failed
Build and Publish Container Image / build-and-push (push) Has been cancelled
bootrapping support
2026-05-24 17:03:01 +02:00

6.9 KiB

id, type, title, domain, repo, status, owner, topic_slug, created, updated
id type title domain repo status owner topic_slug created updated
KEY-WP-0003 workplan Bootstrap Console OIDC Login and MFA Verification netkingdom key-cape finished codex netkingdom 2026-05-24 2026-05-24

KEY-WP-0003 - Bootstrap Console OIDC Login and MFA Verification

Problem

The NetKingdom security bootstrap console now acts as a local OIDC client callback so the operator can verify the dedicated platform-root login before approving custody mode. The current live KeyCape deployment rejects that flow with:

{
  "error": "invalid_profile_usage",
  "description": "redirect_uri does not match any registered URI",
  "feature": "redirect_uri"
}

That error is correct profile enforcement: KeyCape only accepts exact registered redirect URIs. The live demo-app registration has not yet been updated to allow the local bootstrap console callback:

  • http://127.0.0.1:8876/oidc/callback
  • http://localhost:8876/oidc/callback

After that is fixed, there is a second usability/security gap. KeyCape checks privacyIDEA MFA after the Authelia callback, but the browser flow currently expects an mfa_token query parameter instead of presenting a proper OTP challenge page to the human operator.

Goal

Make the bootstrap console's "Start demo OIDC login" button a real end-to-end verification path for the current lightweight IAM stack:

  1. KeyCape accepts the bootstrap console callback URI by exact registration.
  2. The browser leaves KeyCape for the public Authelia login URL.
  3. After password login, KeyCape presents a minimal MFA challenge when privacyIDEA requires one.
  4. KeyCape issues an OIDC authorization code to the bootstrap console callback.
  5. The console can exchange the code and let the operator mark OIDC login verified without exposing tokens or secrets.

This keeps KeyCape's security posture intact: no wildcard redirect URIs, no dynamic client registration, no token display, and no storage of OTP material.

Design Notes

  • Prefer a dedicated public client named netkingdom-bootstrap-console for long-lived clarity. Reusing demo-app is acceptable for the immediate unblock only if the deployment/runbook clearly labels it as a bootstrap test client.
  • The bootstrap callback is local-only and operator-attended. It must be an exact URI in config, not a wildcard or dynamic registration exception.
  • Browser-facing Authelia redirects must use the public Authelia base URL (https://auth.coulomb.social) so the human login page opens correctly.
  • KeyCape may still need an internal service URL for back-channel token exchange. If so, split the current single Authelia URL into browser-facing authorize URL and internal token URL instead of making the browser use an in-cluster hostname.
  • The MFA prompt should collect only a one-time code, post it back to KeyCape, validate with privacyIDEA, and then continue the normal OIDC code flow.
  • This work unblocks the NetKingdom custody gate in NET-WP-0015-platform-root-custody-and-openbao-identity-bootstrap.

Implementation Notes

2026-05-24: Implemented in source:

  • added netkingdom-bootstrap-console as a public OIDC client in the sample KeyCape config, while keeping the local callback registered on demo-app for compatibility,
  • split Authelia browser redirects from server-side token exchange via browserBaseURL and tokenBaseURL,
  • added a browser MFA challenge page at POST /authorize/callback that validates the one-time code with privacyIDEA before issuing the downstream OIDC authorization code,
  • updated NetKingdom's keycape-config generation template and bootstrap console to use the dedicated client,
  • added regression tests for callback registration, split Authelia URLs, MFA challenge rendering, valid OTP continuation, and invalid OTP failure.

Live use still requires deployment: build/publish the updated KeyCape image, refresh the live keycape-config Secret through the custodian age-key unlock ceremony, and restart the KeyCape deployment.


T01 - Register the bootstrap console callback client

id: KEY-WP-0003-T01
status: done
priority: high

Add a KeyCape client registration for the bootstrap console. Either create a dedicated netkingdom-bootstrap-console public client or update demo-app temporarily with these exact redirect URIs:

  • http://127.0.0.1:8876/oidc/callback
  • http://localhost:8876/oidc/callback

Update the sample config, tests, and deployment/runbook references so the registered client is reproducible and not just a live-cluster patch.

Gate: an authorize request using the local callback no longer returns invalid_profile_usage for redirect_uri.

T02 - Separate browser-facing and internal Authelia URLs if needed

id: KEY-WP-0003-T02
status: done
priority: high

Confirm whether the current authelia.baseURL is safe to use for both browser redirects and server-side token exchange. If not, add explicit configuration for the browser authorize base URL and internal token/userinfo base URL.

Gate: the first browser redirect leaves https://kc.coulomb.social for https://auth.coulomb.social/...; server-side token exchange still works from inside the deployment.

T03 - Add a browser MFA challenge step

id: KEY-WP-0003-T03
status: done
priority: high

When CheckMFARequired returns true after the Authelia callback, render a minimal KeyCape MFA challenge page instead of requiring mfa_token in the callback query string. The page should:

  • show the authenticated username and client display name,
  • collect only the OTP code,
  • preserve the pending OIDC state server-side,
  • validate with privacyIDEA,
  • continue to issue the normal authorization code on success,
  • fail closed with the existing telemetry on invalid MFA.

Gate: a user enrolled in privacyIDEA can complete password + OTP in the browser and is returned to the registered downstream callback.

T04 - Add end-to-end profile tests for the bootstrap login path

id: KEY-WP-0003-T04
status: done
priority: medium

Add tests that cover:

  • local bootstrap callback registration,
  • rejection of unregistered callbacks remains intact,
  • Authelia browser redirect uses the expected public URL,
  • MFA-required login presents a challenge instead of immediate failure,
  • invalid OTP fails closed,
  • valid OTP produces an authorization code bound to the original PKCE session.

Gate: make test passes and the negative redirect URI tests remain green.

T05 - Document the live rollout ceremony

id: KEY-WP-0003-T05
status: done
priority: medium

Document the deployment path for updating live KeyCape config without regenerating unrelated secrets. The runbook must fit the NetKingdom custodian age-key model: decrypt or unlock only during an attended ceremony, apply the updated client registration/config, restart KeyCape, and remove plaintext secret material afterward.

Gate: an operator can update the live keycape-config Secret and verify the bootstrap console OIDC login without printing or committing secrets.