SECURITY POSTURE
Haven Guard
Haven Guard audits the security-relevant configuration of Keycloak realms and OIDC clients. It is intentionally deterministic: the same realm/client configuration produces the same findings, score, and SHA-256 fingerprint.
Get the highlights.
-
13Deterministic rules, HAVEN001–013, across four severity tiers
-
SHA-256Fingerprint for pinning a baseline and detecting drift
-
3CI exit codes: 0 clean, 1 error, 2 findings over threshold
-
6Built-in Keycloak clients excluded from findings and counts
Haven Guard audits the security-relevant configuration of Keycloak realms and OIDC clients. It is intentionally deterministic: the same realm/client configuration produces the same findings, score and SHA-256 fingerprint.
- Live console API
GET /api/v1/security/posture(plus?realm=,?baseline=sha256:...,?includeMaster=1, and a/sarifvariant) inside the normal Haven console session.masteris excluded from an all-realm scan unlessincludeMaster=1is set. - Offline audit (CLI)
go run ./cmd/haven-audit --input realm.jsonagainst an exported realm JSON document — plain,--format json, or--format sarifoutput, with--fail-onto gate CI on a severity threshold.
Live console API¶
GET /api/v1/security/posture
GET /api/v1/security/posture?realm=my-tenant
GET /api/v1/security/posture?baseline=sha256:...
GET /api/v1/security/posture?includeMaster=1
GET /api/v1/security/posture/sarif
master is excluded from an all-realm scan unless includeMaster=1 is supplied. A specific realm=master request still scans it.
The API requires the normal Haven console session.
Offline audit¶
Export a realm JSON document containing the realm properties and clients array, then run:
go run ./cmd/haven-audit --input realm.json
JSON output:
go run ./cmd/haven-audit --input realm.json --format json --fail-on none
SARIF output:
go run ./cmd/haven-audit \
--input identity/realm.json \
--format sarif \
--fail-on none > haven-guard.sarif
When --input is a repository-relative file path, Haven Guard includes that file as the SARIF result location so GitHub code scanning can display the findings. The live /sarif API remains useful as a portable report but does not invent a repository file location.
CI gate:
go run ./cmd/haven-audit --input realm.json --fail-on high
Exit codes:
- 0: scan succeeded and did not cross the configured threshold
- 1: input/configuration/runtime error
- 2: scan succeeded but findings crossed --fail-on
Rules¶
| ID | Severity | Check |
|---|---|---|
| HAVEN001 | critical | wildcard redirect URI |
| HAVEN002 | high | non-loopback HTTP redirect URI |
| HAVEN003 | high | wildcard web origin |
| HAVEN004 | high | public client + Direct Access Grants |
| HAVEN005 | high | public auth-code client without PKCE S256 |
| HAVEN006 | high | implicit flow enabled |
| HAVEN007 | high | public client + service accounts |
| HAVEN008 | medium | confidential client + Direct Access Grants |
| HAVEN009 | medium | bearer-only client with interactive grants |
| HAVEN010 | medium | standard-flow client without redirect URI |
| HAVEN011 | medium | self-registration without email verification |
| HAVEN012 | medium | brute-force protection disabled |
| HAVEN013 | low | disabled/stale application client retained |
Built-in Keycloak clients (account, account-console, admin-cli, broker, realm-management, security-admin-console) are excluded from client counts and findings.
Fingerprint / drift¶
The fingerprint includes security-relevant realm state plus application-client grant modes, redirect URIs, web origins, PKCE settings and service-account state. Lists are sorted before hashing, so ordering changes do not create false drift.
To pin a baseline:
- Get a clean report.
- Store
fingerprintin Git, a release record, or the Guard UI baseline. - Send it back as
baseline=sha256:.... drifted: truemeans the security-relevant state changed.
A fingerprint tells you that state changed. Findings and the future Realm Time Machine diff tell you what changed.