Commit Graph

15 Commits

Author SHA1 Message Date
3890dca25d chore(workplan): mark NK-WP-0002 fully complete (all 4 stages done)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 08:07:20 +01:00
e7bafd69fc feat(local-identity): Stage 4 — security hardening (NK-WP-0002-T04)
Permission enforcement on startup: enforce_permissions() checks store dir
(700), user files (600), signing key, TLS key, audit.log, revoked.json.
CLI and run_server() call it before any sensitive operation.

New modules:
  security.py  check_store(), enforce_permissions(), print_security_check()
  audit.py     log_event() — append-only TSV audit log (mode 600)
  revoke.py    revoke(jti), is_revoked(jti) — revocation list (mode 600)

New CLI commands:
  security-check          Print per-check pass/warn/fail report; exit 1 on failure
  revoke-token <jti|jwt>  Add JTI to revocation list; accepts raw JTI or full JWT

Serve integration:
  Audit log written for auth request, token issuance, and userinfo calls
  Revocation checked at /userinfo; revoked tokens return 401

Docs: security model section in LocalIdentity.md — threat model,
assumptions, non-guarantees, SELinux/AppArmor guidance, revocation usage.

138 tests passing (34 new for Stage 4).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 08:06:56 +01:00
ae348d0e54 docs(decisions): record D4 (ESO) and D5 (local-identity in-repo)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 01:06:58 +01:00
ec4626fb84 chore(workplan): mark NK-WP-0002-T03 done, record commit hash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 01:06:01 +01:00
d35823df08 feat(local-identity): Stage 3 — minimal native OIDC provider (NK-WP-0002-T03)
Add local-identity serve command: a minimal Authorization Code flow OIDC
server backed by file-store users.  Implemented natively with no heavy
OIDC library — only stdlib http.server and the cryptography package.

New modules:
  keys.py      RSA-2048 signing key generation + JWKS helpers
  tls.py       Self-signed TLS certificate (localhost/127.0.0.1 SANs)
  jwt_utils.py RS256 JWT creation and verification
  serve.py     OIDCHandler + make_handler() factory + run_server()

Endpoints: /.well-known/openid-configuration, /jwks, /auth, /token,
/userinfo.  Server binds to 127.0.0.1 only; tokens carry iss: local-identity
which production Keycloak rejects by design.

104 tests passing (16 new for Stage 3).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 01:05:50 +01:00
25c92863cf chore(workplan): mark NK-WP-0002-T02 done, record commit hash 2026-03-02 00:24:04 +01:00
dad8365e6a feat(local-identity): Stage 2 — Keycloak export & bootstrap integration (NK-WP-0002-T02)
export.py:
  - split_fullname(): last-token strategy (Bernd Worsch → firstName/lastName)
  - _deterministic_id(): uuid5(DNS, "local-identity.{realm}.{username}") for stable,
    re-import-idempotent Keycloak IDs
  - user_to_keycloak(): full Keycloak Admin REST API user representation;
    production_identity mapping applied to username + realm; isolation attributes
    (local_identity_environment, local_identity_generated) always present;
    validate_keycloak_user() called on every conversion to catch schema drift
  - bulk_export_body(): partial import body (ifResourceExists/realm/users)

cli.py: add `export` subcommand
  - export <username>         single user, prints Keycloak JSON
  - export (no args)          bulk; primary users only; stderr note on skipped test users
  - export --include-test     bulk; all users including generated
  - --realm / --if-resource-exists flags

docs/LocalIdentity.md: add two new sections
  - Keycloak import procedure: export → partialImport API → password reset → retire
  - Isolation guarantee: attribute schema, Keycloak Condition authenticator config,
    production_identity mapping walkthrough

tests/test_export.py: 34 new tests (88 total, all passing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 00:23:39 +01:00
666a56f4ed feat(local-identity): add --username and --fullname overrides to init
Resolves the system identity mismatch between the Linux username (worsch)
and the bootstrap identity (tegwick / Bernd Worsch / custom email).

Resolution order for all three fields: flag > config > system derivation.
Config is updated on every init so --force reinits are idempotent without
repeating the flags.

- cli.py: extract _resolve_init_params(); add --username / --fullname args;
  persist all three fields to config.yaml on init
- tests/test_cli.py: 13 new tests covering flag priority, config fallback,
  system derivation, config persistence, idempotent --force reinit

54 tests passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 00:11:04 +01:00
45cba35054 chore(workplan): mark NK-WP-0002-T01 done (Stage 1 complete)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 00:02:40 +01:00
4491beaffe feat(local-identity): implement Stage 1 — core file store (NK-WP-0002-T01)
Deliverables:
- src/local_identity/gecos.py: /etc/passwd GECOS parsing, current_username()
- src/local_identity/user.py: UserRecord dataclass, ProductionIdentity, make_test_user()
  - Pure test-user derivation: <user>N / +testN email alias / source_user tracking
- src/local_identity/store.py: file store CRUD backed by LOCAL_IDENTITY_HOME
  - ~/.local-identity/ mode 700, user files mode 600
  - All path lookups dynamic (env-var override enables clean test isolation)
- src/local_identity/cli.py: init/list/show commands; email from flag > config > prompt
- pyproject.toml + uv.lock: pyyaml dep, local-identity script entry point

Tests (41 passing):
- test_gecos.py: 9 tests — simple/comma/empty/non-ASCII/whitespace GECOS, fallback
- test_user.py: 14 tests — test-user derivation, YAML roundtrip, non-ASCII, idempotency
- test_store.py: 18 tests — dir creation, permissions (700/600), CRUD, list, config,
  idempotency (reinit with --force produces identical users)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 00:01:54 +01:00
6ed0061962 feat(local-identity): add NK-WP-0002 workplan and LocalIdentity.md
Follows resolved decisions D4 and D5 (2026-03-01, Tegwick):

D4 — ESO chosen as secret injection strategy. NK-WP-0001 T01 Phase 0b
updated to specify ESO; T01 done-criteria updated to require a working ESO
test injection.

D5 — Local Identity implemented in-repo (not a separate repo). Four
deliverables:
- docs/LocalIdentity.md: capability overview, design principles, user
  schema, OIDC provider description, risk mitigations, scope boundaries
- workplans/NK-WP-0002-local-identity.md: four-stage implementation plan
  (core file store, bootstrap integration, minimal OIDC, security hardening)
  with State Hub task IDs
- NK-WP-0001 updated: D2/D4/D5 rows resolved, T07 bootstrap section now
  references NK-WP-0002 and documents the export→Keycloak migration path,
  Open Questions condensed to two remaining artefacts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 23:49:06 +01:00
873fbcf052 docs(workplan): add D4/D5 decisions, T02 prerequisite, EP-NK-001 reference
- Extend decisions table with D4 (secret injection, pending) and D5
  (file-based bootstrap user store, pending with SWOT)
- Add explicit prerequisite block to T02: T01 Phase 0a must complete first
- Update T07: reference EP-NK-001 (LDAP/Entra extension point) by ID
- Condense Open Questions into a reference table pointing to State Hub artefacts
- Ecosystem ADR recommendation recorded as [repo:custodian] task in hub

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 23:11:51 +01:00
534906d509 docs(workplan): update NK-WP-0001 with resolved decisions D1/D2/D3
- Add Decisions table summarising D1 (KeePassXC→Vault), D2 (Keycloak-internal
  hybrid + file-based bootstrap), D3 (plain Helm, AI-first philosophy)
- Split T01 into Phase 0a (pre-cluster KeePassXC) and Phase 0b (in-cluster
  Vault transition) per D1
- Update T05 to explicitly reference D3 (plain Helm first)
- Update T06 to state the D2 identity decision rather than re-opening it
- Update T07: remove "decide" language, implement decided approach, add
  D2 bootstrap user management scope note
- Update T08: add Vault unseal key backup to the backup list
- Replace Open Questions with remaining unresolved items (5 items)
- Add DECISIONS.md (decision log auto-generated by State Hub)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 22:51:11 +01:00
004a8d6e6b Add CLAUDE.md, wiki protoplans, and NK-WP-0001 workplan
Initialises the net-kingdom project structure:
- README.md: updated title and description
- CLAUDE.md: project instructions and State Hub integration config
- wiki/: three reference docs (NetKingdom overview, ChatGPT and Grok
  protoplans for the SSO/MFA platform)
- workplans/NK-WP-0001-sso-mfa-platform.md: combined workplan (8 phases,
  8 tasks) synthesised from the two protoplans; registered in the
  Custodian State Hub (workstream 39263c4b)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 17:21:51 +01:00
Coulomb Social
a852627f0c Initial commit 2026-02-28 09:41:41 +00:00