Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger

.nornir/auth-design.md

Auth, RBAC & audit — design

Class: design · Function: auth (gates serve's write path). The whole-system view is design.md; the model rationale + proposals are in auth-rbac-design.md (reasoning). This file states the wired posture.

The write gate (reads are not gated)

A write goes: agent → authenticate → authorize (RBAC) → route → cap → backend.put(). authorize_write was added only to the write path, so a read never runs auth.

Authenticate — server/lib/src/auth.rs

validate_request() accepts either:

An empty method list = open access; a configured-but-invalid credential = 401.

Authorize — RBAC (Role = Reader | Writer | Admin)

Both write paths run the role check: gRPC put_artifact → authorize_write (grpc.rs) and the HTTP/OCI gateway → authorize_http_write (exposed/http.rs).

auth: Some((
    methods: [ Oidc(( issuer_url: "https://idp/realm" )), Mtls(( ca_cert: "..." )) ],
    roles: { "alice@corp": Admin, "CN=build-bot": Writer },
    default_role: Some(Reader),
))

Caps, audit & hardening

Known gaps (flagged in code)

Per-method mTLS ca_cert verification is flagged open — trust is currently delegated to the TLS client_ca; the per-method chain check needs cert plumbing. Reads are not yet gated. Offline OIDC (JWT-signature verify against an offline JWKS, no /userinfo) is the airgap auth path and is now WIRED (auth.rs::validate_oidc_bearer → verify_jwt_offline against a cached / pre-provisioned JWKS; see auth-rbac-design.md §W1-airgap). Production air-gapped CA issuance/rotation does not exist (only the mannequin test PKI).