generated from coulomb/repo-seed
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>
This commit is contained in:
155
docs/LocalIdentity.md
Normal file
155
docs/LocalIdentity.md
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
# 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).
|
||||||
@@ -45,10 +45,10 @@ Two are pending and require further investigation (see Open Questions).
|
|||||||
| ID | Decision | Status | Outcome / Notes |
|
| ID | Decision | Status | Outcome / Notes |
|
||||||
|----|----------|--------|-----------------|
|
|----|----------|--------|-----------------|
|
||||||
| D1 | Vault backend | **Resolved** | KeePassXC pre-cluster → HashiCorp Vault in-cluster. |
|
| D1 | Vault backend | **Resolved** | KeePassXC pre-cluster → HashiCorp Vault in-cluster. |
|
||||||
| D2 | Identity source of truth | **Resolved** | Hybrid: Keycloak-internal + LDAP/Entra for enterprise tier. File-based bootstrap user store deferred pending D5. |
|
| D2 | Identity source of truth | **Resolved** | Hybrid: Keycloak-internal + LDAP/Entra for enterprise tier. File-based bootstrap user store → Local Identity (NK-WP-0002). |
|
||||||
| D3 | GitOps tooling | **Resolved** | Plain Helm first, upgrade to Flux when warranted. AI-first philosophy (TDD, API-first, MCP, CLI; UI separate repos) — ecosystem ADR requested from custodian. |
|
| D3 | GitOps tooling | **Resolved** | Plain Helm first, upgrade to Flux when warranted. AI-first philosophy (TDD, API-first, MCP, CLI; UI separate repos) — ecosystem ADR requested from custodian. |
|
||||||
| D4 | Secret injection: ESO vs Vault Agent Injector | **Pending** | Gates T01 Phase 0b. Tegwick to investigate. |
|
| D4 | Secret injection: ESO vs Vault Agent Injector | **Resolved** | **ESO.** GitOps-aligned; standard K8s Secrets consumable by plain Helm. Monitor dynamic-secret gaps; revisit if needed. |
|
||||||
| D5 | File-based bootstrap user store: separate repo vs defer vs existing tool | **Pending** | Full SWOT in State Hub. Preliminary recommendation: evaluate Keycloak Docker Compose first. |
|
| D5 | File-based bootstrap user store | **Resolved** | **Implement in-repo as `local-identity`.** Staged workplan: NK-WP-0002. See `docs/LocalIdentity.md`. |
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
@@ -118,15 +118,16 @@ manifests). Store offsite.
|
|||||||
**Phase 0b — HashiCorp Vault in-cluster (after T02, once K3s is running):**
|
**Phase 0b — HashiCorp Vault in-cluster (after T02, once K3s is running):**
|
||||||
|
|
||||||
Deploy HashiCorp Vault in the cluster (Helm chart). Migrate secrets from
|
Deploy HashiCorp Vault in the cluster (Helm chart). Migrate secrets from
|
||||||
KeePassXC into Vault. Enable K8s encryption-at-rest. Choose and implement
|
KeePassXC into Vault. Enable K8s encryption-at-rest. Deploy External Secrets
|
||||||
secret injection strategy: External Secrets Operator + Vault backend, or
|
Operator (ESO) — **decided D4**: ESO reconciles Vault secrets into standard
|
||||||
Vault Agent Injector (ESO preferred for GitOps alignment). KeePassXC
|
K8s Secrets, compatible with plain Helm charts without Vault-specific
|
||||||
remains the source of truth for dev/test/sandbox systems that do not connect
|
annotations. KeePassXC remains the source of truth for dev/test/sandbox
|
||||||
to the cluster Vault.
|
systems that do not connect to the cluster Vault.
|
||||||
|
|
||||||
**Done when:** KeePassXC created and all secrets generated (0a). Vault
|
**Done when:** KeePassXC created and all secrets generated (0a). Vault
|
||||||
deployed in-cluster, secrets migrated, injection strategy operational (0b).
|
deployed in-cluster, secrets migrated, ESO operational and injecting secrets
|
||||||
Encrypted ops bundle exported and stored offsite.
|
into at least one test workload (0b). Encrypted ops bundle exported and
|
||||||
|
stored offsite.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -326,14 +327,13 @@ Configure auditing and log shipping: privacyIDEA audit logs + Keycloak
|
|||||||
events → centralized logging (ELK/Loki or equivalent). Token lifecycle
|
events → centralized logging (ELK/Loki or equivalent). Token lifecycle
|
||||||
policies: enrollment, revocation, re-enrollment on device loss.
|
policies: enrollment, revocation, re-enrollment on device loss.
|
||||||
|
|
||||||
**Bootstrap user management (D2 extension — scope TBD):**
|
**Bootstrap user management (D2 + D5 — Local Identity):**
|
||||||
D2 also specifies a file-based lightweight user store for pre-Keycloak
|
The pre-Keycloak user store is implemented as the `local-identity` capability.
|
||||||
systems (dev/test/sandbox that do not connect to the cluster). Users stored
|
See [NK-WP-0002](NK-WP-0002-local-identity.md) and
|
||||||
as files in a secure subdirectory of the Linux home directory; auto-generates
|
[docs/LocalIdentity.md](../docs/LocalIdentity.md). NK-WP-0002 Stage 2
|
||||||
two test users with `N` / `+testN` username and email suffixes. Test users
|
produces Keycloak-compatible user exports (`local-identity export --all`)
|
||||||
must not spill over into other systems; a mapping mechanism from sandbox
|
that feed the realm bulk-import during T06. Once T06 is operational,
|
||||||
identities to production should be provided. This scope is not yet captured
|
Local Identity should be explicitly migrated away from for that instance.
|
||||||
in a task — see Open Questions.
|
|
||||||
|
|
||||||
**Done when:** policies documented and applied, self-service portal live,
|
**Done when:** policies documented and applied, self-service portal live,
|
||||||
audit logs flowing, Keycloak resolver configured.
|
audit logs flowing, Keycloak resolver configured.
|
||||||
@@ -402,9 +402,10 @@ documented and tested, HSTS and NetworkPolicies verified.
|
|||||||
See `DECISIONS.md` for the three resolved decisions (D1–D3).
|
See `DECISIONS.md` for the three resolved decisions (D1–D3).
|
||||||
Two pending decisions have been raised; see State Hub for full detail.
|
Two pending decisions have been raised; see State Hub for full detail.
|
||||||
|
|
||||||
| # | Item | State Hub artefact | Status |
|
All five decisions are now resolved. See `DECISIONS.md` for D1–D3 rationale;
|
||||||
|---|------|--------------------|--------|
|
State Hub decisions `aca69951` (D4) and `d74e2b11` (D5) for the full records.
|
||||||
| D4 | Secret injection: ESO vs Vault Agent Injector | Decision `aca69951` | Pending — Tegwick to investigate |
|
|
||||||
| D5 | File-based bootstrap user store | Decision `d74e2b11` (full SWOT) | Pending — evaluate Keycloak Docker Compose first |
|
| Artefact | Item | Status |
|
||||||
| — | AI-first ecosystem ADR | Task `007415ef` → [repo:custodian] | Recommended; custodian to create |
|
|----------|------|--------|
|
||||||
| EP-NK-001 | LDAP/AD/Entra federation | Extension point `513a7644` | Open; enterprise tier |
|
| Task `007415ef` → [repo:custodian] | Create ecosystem ADR for AI-first principles (D3) | Open; custodian to action |
|
||||||
|
| EP-NK-001 (`513a7644`) | LDAP/AD/Entra federation | Open; enterprise tier |
|
||||||
|
|||||||
236
workplans/NK-WP-0002-local-identity.md
Normal file
236
workplans/NK-WP-0002-local-identity.md
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
---
|
||||||
|
id: NK-WP-0002
|
||||||
|
type: workplan
|
||||||
|
title: "Local Identity — Bootstrap User Store & Minimal OIDC"
|
||||||
|
domain: netkingdom
|
||||||
|
status: active
|
||||||
|
owner: worsch
|
||||||
|
topic_slug: netkingdom
|
||||||
|
state_hub_workstream_id: 7c9021b1-319c-4b4a-a8be-0642239a1893
|
||||||
|
created: "2026-03-01"
|
||||||
|
updated: "2026-03-01"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 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 (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
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: NK-WP-0002-T01
|
||||||
|
state_hub_task_id: 656652dd-05af-4fa4-95b2-17ce029ac7bd
|
||||||
|
status: todo
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
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: todo
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
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: todo
|
||||||
|
priority: medium
|
||||||
|
```
|
||||||
|
|
||||||
|
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: todo
|
||||||
|
priority: medium
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
- [ ] `~/.local-identity/` store initialised from Linux identity; test users generated
|
||||||
|
- [ ] `local-identity list / show / export` working; Keycloak export validated
|
||||||
|
- [ ] Minimal OIDC server passes conformance smoke test; binds localhost only
|
||||||
|
- [ ] Filesystem permissions enforced on startup; `security-check` passes
|
||||||
|
- [ ] Audit log recording all auth events
|
||||||
|
- [ ] `docs/LocalIdentity.md` complete 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.
|
||||||
Reference in New Issue
Block a user