01Compliance as a release gate, not a scanner
nixfleet-compliance ships 16 typed control modules across 4 frameworks. Each
control follows the enforce + prove pattern: enforce applies
the control (sysctl, firewall rule, SSH policy). prove emits structured JSON
evidence to /var/lib/nixfleet-compliance/evidence.json. A systemd timer runs
the collector hourly for essential entities and daily for important entities.
The compliance layer has no runtime dependency on nixfleet itself. It detects nixfleet
features at evaluation time using options ? checks, so it works with or
without the agent or control plane. Repository:
arcanesys/nixfleet-compliance (MIT).
02The 16 controls
Each typed control declares which article it satisfies per framework. The matrix below is the cross-cutting view; the per-framework detail lives in §03.
| Control | NIS2 Art. 21 | ISO 27001 Annex A | DORA Art. | ANSSI BP-028 |
|---|---|---|---|---|
_access-control | 21(i) | A.8.2, A.8.3 | Art. 9 | preset |
_asset-inventory | 21(i) | A.5.9 | Art. 8 | - |
_audit-logging | 21(f) | A.8.15, A.8.16 | - | R33 |
_authentication | 21(j) | A.8.5 | Art. 9 | preset |
_backup-retention | 21(c) | A.8.13 | Art. 12 | - |
_baseline-hardening | 21(a), 21(g) | A.8.8, A.8.9 | - | R7–R14 |
_change-management | 21(e) | A.8.32 | Art. 8 | - |
_disaster-recovery | 21(c) | A.5.29, A.5.30 | Art. 12 | - |
_encryption-at-rest | 21(h) | A.8.24 | - | preset |
_encryption-in-transit | 21(h) | A.8.20, A.8.24 | - | - |
_incident-response | 21(b) | A.5.24, A.5.26 | Art. 17 | - |
_key-management | 21(h) | A.8.24 | - | - |
_network-segmentation | 21(a) | - | Art. 9 | preset |
_secure-boot | 21(a) | - | - | preset |
_supply-chain | 21(d) | A.5.19, A.5.21 | - | - |
_vulnerability-mgmt | 21(e) | A.8.8 | Art. 8 | - |
03Framework coverage
The same 16 controls satisfy four framework presets through different article-level mappings. Coverage: 10 / 10 NIS2 Article 21 sub-articles, ISO 27001:2022 Annex A across A.5 and A.8, DORA Articles 8 / 9 / 12 / 17, ANSSI BP-028 R7–R14 + R33. Each framework's article-by-article table is its own page:
- NIS2 — Article 21 mapping (10 sub-articles)
- DORA — Chapter III mapping (Articles 8, 9, 12, 17)
- ISO 27001:2022 — Annex A mapping (A.5 + A.8 controls)
- ANSSI BP-028 v2.0 — mapping (R7–R14 + R33, four hardening levels)
- NIS2 entity classification (essential vs. important thresholds across the fleet)
Additional article-level coverage (no full preset yet):
CRA (EU Cyber Resilience Act) Art. 10 on _supply-chain,
_encryption-in-transit, _secure-boot, and Art. 11 on
_vulnerability-mgmt. SecNumCloud on
_key-management, _network-segmentation, _secure-boot.
04Evidence format - JCS-signed JSON
The collector writes three files to /var/lib/nixfleet-compliance/:
evidence.json (the record), evidence.json.sig (a base64 ed25519
signature over the JCS-canonical bytes of the record, RFC 8785), and
evidence.host.pub (the host's SSH ed25519 public key, published alongside).
An auditor with the three files runs nixfleet-compliance-verify to
reproduce the canonicalisation and check the signature: no control plane, no operator
trust, no scanner-vendor trust. Sample record from the _supply-chain
control:
{
"schemaVersion": 1,
"hostname": "water-plant-01",
"collectedAt": "2026-04-05T10:00:00Z",
"controls": [
{
"controlId": "supply-chain",
"passed": true,
"frameworkArticles": {
"nis2": ["21(d)"],
"iso27001": ["A.5.19", "A.5.21"],
"cra": ["Art. 10"]
},
"details": {
"has_configuration_revision": true,
"sbom_generated": true,
"closure_package_count": 847,
"inputs_fresh": true
}
}
]
} Key design decision: frameworkArticles links each control
to the articles it satisfies. details contains the raw probe output, not a
summary - auditors verify each individual assertion. The control-level passed
boolean is derived from details. It is not asserted by configuration.
05Two enforcement modes
- Static gates: the build fails before a non-compliant closure can ship. No runtime detection needed - the closure that ships is provably compliant by construction.
- Runtime probes: gate wave promotion and trigger agent rollback on probe failure. The CP refuses to advance a wave if any compliance probe failed in the prior wave.
06Governance engine
Two global enforcement modes via compliance.governance.enforceMode:
enforce (controls apply NixOS config AND run probes) or
report (controls run probes only, no NixOS config applied) - useful for
onboarding regulated estates where you want the compliance signal before flipping any
switches. Per-control disabling is independent of the mode: set
compliance.controls.<name>.enable = false and document the exception
inline. Framework presets default to enforce with a strictness
knob that drives sensible per-control defaults.
07Compliance-check CLI
compliance-check reads
/var/lib/nixfleet-compliance/evidence.json and prints coloured pass/fail per
control. --live re-runs each probe inline (useful in CI or before an audit).
Output is also available as JSON for scripting.