Files
net-kingdom/workplans/NK-WP-0002-local-identity.md
tegwick 8929bf65bc feat(sso-mfa): T03 PostgreSQL manifests (NK-WP-0001-T03)
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>
2026-03-05 09:22:13 +01:00

241 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: NK-WP-0002
type: workplan
title: "Local Identity — Bootstrap User Store & Minimal OIDC"
domain: netkingdom
status: completed
owner: worsch
topic_slug: netkingdom
state_hub_workstream_id: 7c9021b1-319c-4b4a-a8be-0642239a1893
created: "2026-03-01"
updated: "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](../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 (T01T08) 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
```task
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/passwd` GECOS, prompt for
email if not in config; write primary user file; auto-generate two test
users with `N` / `+testN` suffixes
- `local-identity list` — tabular output of all users in the store
- `local-identity show <user>` — pretty-print user YAML
File store:
- Create `~/.local-identity/` with mode `700`
- 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 `+testN` insertion
- Idempotency: `init` twice with `--force` produces identical output
**Done when:** init/list/show work; files created with correct permissions;
unit tests passing.
---
### T02 — Stage 2: Bootstrap integration
```task
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); apply `production_identity`
mapping 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 --all` produces 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
```task
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 document
- `GET /auth` — authorization endpoint (redirects with `code`)
- `POST /token` — token endpoint (exchanges `code` for JWT)
- `GET /userinfo` — userinfo endpoint
Token requirements:
- JWT signed with a local key (generated on first `serve` invocation;
stored in `~/.local-identity/keys/`)
- Claims: `sub`, `iss: local-identity`, `aud`, `exp`, `iat`, `email`,
`name`, `preferred_username`
- `iss: local-identity` is 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.1` only; document that external binding is explicitly
unsupported
Scope:
- Supports `openid`, `profile`, `email` scopes
- 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
```task
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/` mode `700` and all user
files mode `600`; fail loudly (exit 1 + clear error) if violated
- `local-identity security-check` command: explicit security audit with
per-check output (pass / warn / fail)
Audit log:
- Append-only log at `~/.local-identity/audit.log`; mode `600`
- 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
- [x] `~/.local-identity/` store initialised from Linux identity; test users generated
- [x] `local-identity list / show / export` working; Keycloak export validated
- [x] Minimal OIDC server passes conformance smoke test; binds localhost only
- [x] Filesystem permissions enforced on startup; `security-check` passes
- [x] Audit log recording all auth events
- [x] `docs/LocalIdentity.md` complete with import procedure and security model
- [x] 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.