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

6.5 KiB

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/:

# ~/.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:

# ~/.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.