Files
net-kingdom/docs/LocalIdentity.md
tegwick 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

156 lines
6.5 KiB
Markdown

# Local Identity
Local Identity is a zero-dependency, file-based user management capability
for net-kingdom bootstrap environments — systems that do not yet have (or do
not need) a running Keycloak instance.
## Why it exists
In net-kingdom, Keycloak is the production identity provider. But Keycloak
requires a running Kubernetes cluster, a database, and a configured realm
before it can authenticate anyone. This creates a bootstrapping paradox:
> You need identity to set up infrastructure, but the infrastructure provides
> identity.
Local Identity breaks this cycle. An operator with only a Linux home directory
can establish their identity, generate deterministic test users, and run
dev/test applications with OIDC authentication — before any service is
deployed.
## Design principles
1. **Zero dependencies** — only the Linux filesystem; no Docker, no K8s, no
running services required.
2. **Derived identity** — the primary user is derived from `$USER`,
`/etc/passwd` (GECOS), and a configured email address. No manual setup
required for the basic case.
3. **Deterministic test users** — two test users are auto-generated from the
primary user at `init` time using `N` and `+testN` suffixes:
| Field | Primary | Test 1 | Test 2 |
|----------|-------------|---------------------|---------------------|
| username | `$USER` | `${USER}1` | `${USER}2` |
| fullname | GECOS field | `<fullname>+test1` | `<fullname>+test2` |
| email | configured | `<user>+test1@…` | `<user>+test2@…` |
Email aliases follow the Gmail `+xxx` convention so test emails route to
the operator's inbox without extra accounts.
4. **Hard isolation** — test users carry `environment: local`; production
connectors reject this flag by default. Test users cannot authenticate in
production without an explicit override.
5. **Minimal OIDC** — a lightweight native OIDC provider backed by the file
store, for apps that require OIDC in dev/test without a running Keycloak.
Tokens carry `iss: local-identity`; production systems are configured to
reject this issuer.
6. **Secure by default**`~/.local-identity/` is created with mode `700`;
individual user files with mode `600`; the tool validates permissions on
every startup and refuses to run if the store is world-readable.
## What it is not
- **Not a production identity provider.** Local Identity is never exposed to
the internet. It has no MFA. It is not hardened for public traffic.
- **Not a replacement for Keycloak.** Once a cluster is operational, Keycloak
is the IdP. Local Identity provides an on-ramp, not an alternative.
- **Not multi-user.** Local Identity is single-operator: one primary user
derived from the Linux session, plus generated test users.
- **Not an LDAP/AD/Entra bridge.** Enterprise federation is handled by
Keycloak. See EP-NK-001 in the State Hub.
- **No MFA.** Second factors are out of scope; this is intentionally minimal.
## User schema
Users are stored as YAML files under `~/.local-identity/users/`:
```yaml
# ~/.local-identity/users/tegwick.yaml
schema_version: "1"
username: tegwick
fullname: "Bernd Worsch"
email: "bernd.worsch@gmail.com"
environment: local # never "production" for local-identity users
generated: false # true for auto-generated test users
production_identity: # optional: maps this user to a production identity
username: tegwick
realm: net-kingdom
```
Test users are generated at `init` time and stored alongside:
```yaml
# ~/.local-identity/users/tegwick1.yaml
schema_version: "1"
username: tegwick1
fullname: "Bernd Worsch+test1"
email: "bernd.worsch+test1@gmail.com"
environment: local
generated: true
source_user: tegwick
production_identity: # optional: can map to a test/staging account
username: tegwick-test1
realm: net-kingdom
```
## Sandbox → production mapping
Each user file can optionally carry a `production_identity` block. When an
entity owned by a local-identity user needs to be transferred to a production
environment (e.g. a resource created during local development), the mapping
provides the correct production user ID.
`local-identity export <user>` produces a Keycloak-compatible user JSON that
respects this mapping. The schema is validated against the Keycloak user
representation to prevent silent drift.
## CLI reference
```
local-identity init # derive primary user, generate test users
local-identity list # list all users in the store
local-identity show <username> # display user file
local-identity export <username> # emit Keycloak-compatible JSON
local-identity security-check # validate filesystem permissions and config
```
## OIDC provider (Stage 3)
When running `local-identity serve`, a minimal OIDC Authorization Code flow
server starts on localhost. It supports:
- `GET /.well-known/openid-configuration` — discovery document
- Authorization endpoint, token endpoint, userinfo endpoint
- JWT tokens with `iss: local-identity` (hard-coded; production systems
reject this issuer by default)
- Auto-generated self-signed TLS certificate
This allows dev/test applications to use standard OIDC libraries against
Local Identity without any Keycloak dependency.
**Security note:** the OIDC server binds to `127.0.0.1` only. Never expose
it on a public interface.
## Risks and mitigations
| Risk | Mitigation |
|------|------------|
| World-readable credential files | `~/.local-identity/` mode `700`; startup check fails loudly |
| Test users leaking into production | `environment: local` flag; production connectors reject by default |
| Local Identity tokens accepted in production | `iss: local-identity`; configure production Keycloak to reject this issuer |
| File schema drifting from Keycloak model | `export` command validates against Keycloak representation; schema is versioned |
| Bootstrap store becoming a long-lived crutch | Explicit scope limit: once Keycloak is operational, migrate and stop using Local Identity |
## Relationship to the SSO platform
Local Identity is a complementary workstream to the SSO & MFA Platform
(NK-WP-0001). The SSO platform provides production-grade identity; Local
Identity provides the bootstrap path that allows the SSO platform itself to
be set up and tested.
When the Keycloak realm (NK-WP-0001 T06) is operational, primary and test
users can be exported from Local Identity into Keycloak using
`local-identity export` and the Keycloak admin API.
Implementation: see [NK-WP-0002](../workplans/NK-WP-0002-local-identity.md).