CloudNativePG Cluster CR (net-kingdom-pg, PostgreSQL 16) with two application databases: keycloak_db (owner: keycloak) and privacyidea_db (owner: privacyidea). Passwords managed continuously via managed.roles. WAL archiving section stubbed and commented; activate when object storage is available. ScheduledBackup CR included (daily 02:00 UTC, 7d retention). Also: sync workplan status for T01 (Phase 0a done), T02 (manifests done), T03 (manifests done, restore drill pending); close NK-WP-0002. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8.4 KiB
id, type, title, domain, status, owner, topic_slug, state_hub_workstream_id, created, updated
| id | type | title | domain | status | owner | topic_slug | state_hub_workstream_id | created | updated |
|---|---|---|---|---|---|---|---|---|---|
| NK-WP-0002 | workplan | Local Identity — Bootstrap User Store & Minimal OIDC | netkingdom | completed | worsch | netkingdom | 7c9021b1-319c-4b4a-a8be-0642239a1893 | 2026-03-01 | 2026-03-05 |
Local Identity — Bootstrap User Store & Minimal OIDC
Summary
Implement a zero-dependency, file-based user management capability for net-kingdom environments that do not yet have (or do not need) a running Keycloak instance. Local Identity derives the primary user from the Linux identity, auto-generates test users, provides a sandbox→production mapping mechanism, and (in Stage 3) a minimal native OIDC provider for dev/test use.
See docs/LocalIdentity.md for the full capability description, design principles, user schema, and risk mitigations.
Context
Resolved from Decision D5 (2026-03-01, Tegwick). The decision chose to implement Local Identity in-repo (not as a separate repository) in staged workplan form, with a clear scope boundary and explicit out-of-scope limitations. The minimal OIDC provider is to be implemented natively to avoid heavy dependencies, keeping the bootstrap footprint minimal.
Relationship to NK-WP-0001
Local Identity is complementary to the SSO & MFA Platform (NK-WP-0001). It is not a blocking dependency: the SSO platform core deployment (T01–T08) does not require Local Identity to be complete. However:
- NK-WP-0001 T07 (user management) references Local Identity for the pre-Keycloak bootstrap use case.
- Stage 2 of this workplan produces Keycloak-compatible user exports, which feed the NK-WP-0001 T06 realm configuration.
- Once NK-WP-0001 is fully operational, Local Identity is no longer needed for new instances and should be explicitly migrated away from.
Architecture
~/.local-identity/
├── config.yaml # operator email, optional overrides
└── users/
├── <user>.yaml # primary user (derived from Linux identity)
├── <user>1.yaml # test user 1 (generated)
└── <user>2.yaml # test user 2 (generated)
local-identity CLI
├── init # derive + generate users
├── list / show # read operations
├── export # Keycloak-compatible JSON
├── security-check # permissions validation
└── serve # Stage 3: minimal OIDC server (localhost only)
Secret injection: Local Identity does not use Vault or K8s Secrets — it operates entirely at the filesystem level, pre-cluster. This is by design.
Tasks
T01 — Stage 1: Core file store
id: NK-WP-0002-T01
state_hub_task_id: 656652dd-05af-4fa4-95b2-17ce029ac7bd
status: done
priority: high
commit: 4491bea
Define YAML user schema (schema_version, username, fullname, email,
environment, generated, source_user, production_identity).
Implement:
local-identity init— read$USER,/etc/passwdGECOS, prompt for email if not in config; write primary user file; auto-generate two test users withN/+testNsuffixeslocal-identity list— tabular output of all users in the storelocal-identity show <user>— pretty-print user YAML
File store:
- Create
~/.local-identity/with mode700 - Create user files with mode
600 - Refuse to overwrite existing store without
--force
Unit tests:
- GECOS name parsing edge cases (missing fields, non-ASCII)
- Test user derivation: username suffix, email
+testNinsertion - Idempotency:
inittwice with--forceproduces identical output
Done when: init/list/show work; files created with correct permissions; unit tests passing.
T02 — Stage 2: Bootstrap integration
id: NK-WP-0002-T02
state_hub_task_id: 5ea6e68d-7ebe-4ea7-b92e-61aac17ff04c
status: done
priority: high
commit: dad8365
Extend user schema with optional production_identity block (username,
realm). Test users carry environment: local and generated: true.
Implement:
local-identity export <user>— emit Keycloak-compatible user JSON (Keycloak Admin REST API representation); applyproduction_identitymapping if present- Schema validation: run against Keycloak user JSON schema on export; fail with a clear diff if schema has drifted
Bootstrap tooling integration:
local-identity export --allproduces a bulk import file compatible with Keycloak's partial import endpoint- Document the import procedure in
docs/LocalIdentity.md
Isolation guarantee:
- Production connectors (Keycloak, future services) must reject users with
environment: local— document the configuration required on the Keycloak side (e.g. custom attribute check in authentication flow)
Done when: export produces valid Keycloak JSON; schema validation catches drift; bulk import procedure documented and tested against a local Keycloak dev instance.
T03 — Stage 3: Minimal native OIDC provider
id: NK-WP-0002-T03
state_hub_task_id: eb09d287-8e08-4c88-8bd1-6f0501ef5fc8
status: done
priority: medium
commit: d35823d
Implement local-identity serve — a minimal OIDC Authorization Code flow
server, implemented natively (no heavy OIDC library dependencies). Target:
a single binary or script that can be invoked without installing an
application framework.
Endpoints required:
GET /.well-known/openid-configuration— OIDC discovery documentGET /auth— authorization endpoint (redirects withcode)POST /token— token endpoint (exchangescodefor JWT)GET /userinfo— userinfo endpoint
Token requirements:
- JWT signed with a local key (generated on first
serveinvocation; stored in~/.local-identity/keys/) - Claims:
sub,iss: local-identity,aud,exp,iat,email,name,preferred_username iss: local-identityis intentionally non-routable; configure production Keycloak to reject tokens with this issuer
TLS:
- Auto-generate a self-signed certificate on first run; store in
~/.local-identity/tls/ - Bind to
127.0.0.1only; document that external binding is explicitly unsupported
Scope:
- Supports
openid,profile,emailscopes - No refresh tokens (stateless; re-auth required after expiry)
- No client secret validation (dev-mode only; all registered clients are trusted)
Done when: a standard OIDC client library can authenticate against
local-identity serve; discovery, auth, token, and userinfo endpoints
pass an OIDC conformance smoke test; server refuses to bind to 0.0.0.0.
T04 — Stage 4: Security hardening
id: NK-WP-0002-T04
state_hub_task_id: 936de7fa-dfb4-48a2-804f-6b9bd7271a05
status: done
priority: medium
commit: e7bafd6
Permission enforcement:
- On every startup, validate
~/.local-identity/mode700and all user files mode600; fail loudly (exit 1 + clear error) if violated local-identity security-checkcommand: explicit security audit with per-check output (pass / warn / fail)
Audit log:
- Append-only log at
~/.local-identity/audit.log; mode600 - Log entries: timestamp, command, username, outcome
- For
serve: log every authentication event (auth request, token issued, userinfo call)
Token hardening (for Stage 3 OIDC server):
- Configurable token TTL (default: 1 hour)
- Token revocation list stored in
~/.local-identity/revoked.json local-identity revoke-token <jti>command
Documentation:
- Optional SELinux/AppArmor label guidance added to
docs/LocalIdentity.md - Security model section: threat model, assumptions, explicit non-guarantees
Done when: security-check passes cleanly on a correct install; audit log records all auth events; startup fails on incorrect permissions; token expiry and revocation functional.
Deliverables Checklist
~/.local-identity/store initialised from Linux identity; test users generatedlocal-identity list / show / exportworking; Keycloak export validated- Minimal OIDC server passes conformance smoke test; binds localhost only
- Filesystem permissions enforced on startup;
security-checkpasses - Audit log recording all auth events
docs/LocalIdentity.mdcomplete with import procedure and security model- NK-WP-0001 T07 migration procedure documented (Local Identity → Keycloak)
Open Questions
None at this stage. All decisions resolved. Stage 3 language selection (implementation language for the OIDC server) is a task-level detail to be determined in T03.