up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
This commit is contained in:
33
docs/airgap/bootstrap.md
Normal file
33
docs/airgap/bootstrap.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Bootstrap Pack (Airgap 56-004)
|
||||
|
||||
Guidance to build and install the bootstrap pack that primes sealed environments.
|
||||
|
||||
## Contents
|
||||
- Core images/charts for platform services (Authority, Excititor, Concelier, Export Center, Scheduler) with digests.
|
||||
- Offline NuGet/npm caches (if permitted) with checksum manifest.
|
||||
- Configuration defaults: sealed-mode toggles, trust roots, time-anchor bundle, network policy presets.
|
||||
- Verification scripts: hash check, DSSE verification (if available), and connectivity probes to local mirrors.
|
||||
|
||||
## Build steps
|
||||
1. Gather image digests and charts from trusted registry/mirror.
|
||||
2. Create `bootstrap-manifest.json` with:
|
||||
- `bundleId`, `createdAt` (UTC), `producer`, `mirrorGeneration`
|
||||
- `files[]` (path, sha256, size, mediaType)
|
||||
- optional `dsseEnvelopeHash`
|
||||
3. Package into tarball with deterministic ordering (POSIX tar, sorted paths, numeric owner 0:0).
|
||||
4. Compute sha256 for tarball; record in manifest.
|
||||
|
||||
## Install steps
|
||||
1. Transfer pack to sealed site (removable media).
|
||||
2. Verify tarball hash and DSSE (if present) using offline trust roots.
|
||||
3. Load images/charts into local registry; preload caches to `local-nugets/` etc.
|
||||
4. Apply network policies (deny-all) and sealed-mode config.
|
||||
5. Register bootstrap manifest and mirrorGeneration with Excititor/Export Center.
|
||||
|
||||
## Determinism & rollback
|
||||
- Keep manifests in ISO-8601 UTC; no host-specific metadata in tar headers.
|
||||
- For rollback, retain previous bootstrap tarball + manifest; restore registry contents and config snapshots.
|
||||
|
||||
## Related
|
||||
- `docs/airgap/mirror-bundles.md` — mirror pack format and validation.
|
||||
- `docs/airgap/sealing-and-egress.md` — egress enforcement used during install.
|
||||
6
docs/airgap/console-airgap-tasks.md
Normal file
6
docs/airgap/console-airgap-tasks.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Console Airgap Implementation Tasks (link to DOCS-AIRGAP-57-002)
|
||||
|
||||
- Implement sealed badge + staleness indicators using `staleness-and-time.md` rules.
|
||||
- Hook import wizard to backend once mirror bundle schema and timeline event API are available.
|
||||
- Ensure admin-only import; read-only view otherwise.
|
||||
- Emit telemetry for imports (success/failure) and denied attempts.
|
||||
19
docs/airgap/degradation-matrix.md
Normal file
19
docs/airgap/degradation-matrix.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Airgap Degradation Matrix (DOCS-AIRGAP-58-001)
|
||||
|
||||
What works and what degrades across modes (sealed → constrained → connected).
|
||||
|
||||
| Capability | Connected | Constrained | Sealed | Notes |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Mirror imports | ✓ | ✓ | ✓ | Sealed requires preloaded media + offline validation. |
|
||||
| Time anchors (external NTP) | ✓ | ✓ (allowlisted) | ✗ | Sealed relies on signed time anchors. |
|
||||
| Transparency log lookups | ✓ | ✓ (if allowlisted) | ✗ | Sealed skips; rely on bundled checkpoints. |
|
||||
| Rekor witness | ✓ | optional | ✗ | Disabled in sealed; log locally. |
|
||||
| SBOM feed refresh | ✓ | limited mirrors | offline only | Use mirror bundles. |
|
||||
| CLI plugin downloads | ✓ | allowlisted | ✗ | Must ship in bootstrap pack. |
|
||||
| Telemetry export | ✓ | optional | optional/log-only | Sealed may use console exporter only. |
|
||||
| Webhook callbacks | ✓ | allowlisted internal only | ✗ | Use internal queue instead. |
|
||||
| OTA updates | ✓ | partial | ✗ | Use mirrorGeneration refresh. |
|
||||
|
||||
## Remediation guidance
|
||||
- If a capability is degraded in sealed mode, provide offline substitute (mirror bundles, time anchors, console exporter).
|
||||
- When moving to constrained/connected, re-enable trust roots and transparency checks gradually; verify hashes first.
|
||||
23
docs/airgap/devportal-offline.md
Normal file
23
docs/airgap/devportal-offline.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# DevPortal Offline (DOCS-AIRGAP-DEVPORT-64-001)
|
||||
|
||||
How to use the developer portal in fully offline/sealed environments.
|
||||
|
||||
## Serving the portal
|
||||
- Host static build from local object store or file server; no CDN.
|
||||
- Set `DEVPORTAL_OFFLINE=true` to disable external analytics/fonts.
|
||||
|
||||
## Auth
|
||||
- Use Authority in offline mode with pre-provisioned tenants; cache JWKS locally.
|
||||
|
||||
## Bundles
|
||||
- Provide mirror/bootstrap bundles via offline download page with hashes and DSSE (if available).
|
||||
- Offer time anchors download; display staleness and mirrorGeneration in UI header.
|
||||
|
||||
## Search/docs
|
||||
- Bundle docs and search index; disable remote doc fetch.
|
||||
|
||||
## Telemetry
|
||||
- Disable remote telemetry; keep console logs only or send to local OTLP endpoint.
|
||||
|
||||
## Verification
|
||||
- On load, run self-check to confirm no external requests; fail with clear banner if any detected.
|
||||
28
docs/airgap/mirror-bundles.md
Normal file
28
docs/airgap/mirror-bundles.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Mirror Bundles (Airgap 56-003)
|
||||
|
||||
Defines the mirror bundle format and validation workflow for sealed deployments.
|
||||
|
||||
## Contents
|
||||
- Images/charts: OCI artifacts exported with digests + SBOMs.
|
||||
- Manifests: `manifest.json` with entries:
|
||||
- `bundleId`, `mirrorGeneration`, `createdAt`, `producer` (export center), `hashes` (sha256 list)
|
||||
- `dsseEnvelopeHash` for signed manifest (if available)
|
||||
- `files[]`: path, sha256, size, mediaType
|
||||
- Transparency: optional TUF metadata (`timestamp.json`, `snapshot.json`) for replay protection.
|
||||
|
||||
## Validation steps
|
||||
1. Verify `manifest.json` sha256 matches provided hash.
|
||||
2. If DSSE present, verify signature against offline trust roots.
|
||||
3. Validate Merkle root (if included) over `files[]` hashes.
|
||||
4. For each OCI artifact, confirm digest matches and SBOM present.
|
||||
5. Record `mirrorGeneration` and manifest hash; store in audit log and timeline event.
|
||||
|
||||
## Workflow
|
||||
- Export Center produces bundle + manifest; Attestor/Excititor importers validate before ingest.
|
||||
- Bundle consumers must refuse imports if any hash/signature fails.
|
||||
- Keep format stable; any schema change bumps `manifestVersion` in `manifest.json`.
|
||||
|
||||
## Determinism
|
||||
- Sort `files[]` by path; compute hashes with UTF-8 canonical paths.
|
||||
- Use ISO-8601 UTC timestamps in manifests.
|
||||
- Do not include host-specific paths or timestamps in tar layers.
|
||||
34
docs/airgap/operations.md
Normal file
34
docs/airgap/operations.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Airgap Operations (DOCS-AIRGAP-57-004)
|
||||
|
||||
Runbooks for imports, failure recovery, and auditing in sealed/constrained modes.
|
||||
|
||||
## Imports
|
||||
1) Verify bundle hash/DSSE (see `mirror-bundles.md`).
|
||||
2) `stella airgap import --bundle ... --generation N --dry-run` (optional).
|
||||
3) Apply network policy: ensure sealed/constrained mode set correctly.
|
||||
4) Import with `stella airgap import ...` and watch logs.
|
||||
5) Confirm timeline event emitted (bundleId, mirrorGeneration, actor).
|
||||
|
||||
## Failure recovery
|
||||
- Hash/signature mismatch: reject bundle; re-request export; log incident.
|
||||
- Partial import: rerun with `--force` after cleaning registry/cache; keep previous generation for rollback.
|
||||
- Staleness breach: if imports unavailable, raise amber alert; if >72h, go red and halt new ingest until refreshed.
|
||||
- Time anchor expired: apply new anchor from trusted media before continuing operations.
|
||||
|
||||
## Auditing
|
||||
- Record every import in audit log: `{tenant, mirrorGeneration, manifestHash, actor, sealed}`.
|
||||
- Preserve manifests and hashes for at least two generations.
|
||||
- Periodically (daily) run `stella airgap list --format json` and archive output.
|
||||
- Ensure logs are immutable (append-only) in sealed environments.
|
||||
|
||||
## Observability
|
||||
- Monitor counters for denied egress, import success/failure, and staleness alerts.
|
||||
- Expose `/obs/airgap/status` (if available) to scrape bundle freshness.
|
||||
|
||||
## Checklist (per import)
|
||||
- [ ] Hash/DSSE verified
|
||||
- [ ] Sealed/constrained mode configured
|
||||
- [ ] Registry/cache reachable
|
||||
- [ ] Import succeeded
|
||||
- [ ] Timeline/audit recorded
|
||||
- [ ] Staleness dashboard updated
|
||||
32
docs/airgap/overview.md
Normal file
32
docs/airgap/overview.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Airgap Overview
|
||||
|
||||
This page orients teams before diving into per-component runbooks. It summarises modes, lifecycle, and governance responsibilities for sealed deployments.
|
||||
|
||||
## Modes
|
||||
- **Sealed**: deny-all egress; only preloaded bundles (mirror + bootstrap) allowed. Requires exported time anchors and offline trust roots.
|
||||
- **Constrained**: limited egress to allowlisted registries and NTP; mirror bundles still preferred.
|
||||
- **Connected**: full egress for staging; must remain policy-compatible with sealed mode.
|
||||
|
||||
## Lifecycle
|
||||
1. **Prepare bundles**: export mirror + bootstrap packs (images/charts, SBOMs, DSSE metadata) signed and hashed.
|
||||
2. **Stage & verify**: load bundles into the offline store, verify hashes/DSSE, record mirrorGeneration.
|
||||
3. **Activate**: flip sealed toggle; enforce deny-all egress and policy banners; register bundles with Excititor/Export Center.
|
||||
4. **Operate**: run periodic staleness checks, apply time anchors, and audit imports via timeline events.
|
||||
5. **Refresh/rollback**: import next mirrorGeneration or roll back using previous manifest + hashes.
|
||||
|
||||
## Responsibilities
|
||||
- **AirGap Controller Guild**: owns network posture (deny-all, allowlists), sealed-mode policy banners, and change control.
|
||||
- **Export Center / Evidence Locker Guilds**: produce and verify bundle manifests, DSSE envelopes, and Merkle roots.
|
||||
- **Module owners** (Excititor, Concelier, etc.): honor sealed-mode toggles, emit staleness headers, and refuse unsigned/unknown bundles.
|
||||
- **Ops/Signals Guild**: maintain time anchors and observability sinks compatible with sealed deployments.
|
||||
|
||||
## Rule banner (sealed mode)
|
||||
Display a top-of-console banner when `sealed=true`:
|
||||
- "Sealed mode: no external egress. Only registered bundles permitted. Imports logged; violations trigger audit."
|
||||
- Include current `mirrorGeneration`, bundle manifest hash, and time-anchor status.
|
||||
|
||||
## Related docs
|
||||
- `docs/airgap/airgap-mode.md` — deeper policy shapes per mode.
|
||||
- `docs/airgap/bundle-repositories.md` — mirror/bootstrap bundle structure.
|
||||
- `docs/airgap/staleness-and-time.md` — time anchors and staleness checks.
|
||||
- `docs/airgap/controller-scaffold.md` / `importer-scaffold.md` — implementation scaffolds.
|
||||
@@ -1,90 +1,27 @@
|
||||
# Portable Evidence Bundles (Sealed/Air-Gapped)
|
||||
# Portable Evidence Bundles (DOCS-AIRGAP-58-004)
|
||||
|
||||
> Sprint 160 · Task EVID-OBS-60-001
|
||||
> Audience: Evidence Locker operators, Air-Gap controllers, incident responders
|
||||
Guidance for exporting/importing portable evidence bundles across enclaves.
|
||||
|
||||
Portable bundles let operators hand off sealed evidence across enclaves without exposing tenant identifiers or internal storage coordinates. The Evidence Locker produces a deterministic archive (`portable-bundle-v1.tgz`) that carries the manifest + signature alongside redacted metadata, checksum manifest, and an offline verification script.
|
||||
## Bundle contents
|
||||
- Evidence payloads (VEX observations/linksets) as NDJSON.
|
||||
- Timeline events and attestation DSSE envelopes.
|
||||
- Manifest with `bundleId`, `source`, `tenant`, `createdAt`, `files[]`, `dsseEnvelopeHash` (optional).
|
||||
|
||||
## 1. When to use the portable flow
|
||||
## Export
|
||||
- Produce from Evidence Locker/Excititor with deterministic ordering and SHA-256 hashes.
|
||||
- Include Merkle root over evidence files; store in manifest.
|
||||
- Sign manifest (DSSE) when trust roots available.
|
||||
|
||||
- **Sealed mode exports.** Regulatory or incident response teams that cannot access the primary enclave directly.
|
||||
- **Chain-of-custody transfers.** Moving evidence into offline review systems while keeping the DSSE provenance intact.
|
||||
- **Break-glass rehearsals.** Validating incident response playbooks without exposing internal bundle metadata.
|
||||
## Import
|
||||
- Verify manifest hash, Merkle root, and DSSE signature offline.
|
||||
- Enforce tenant scoping; refuse cross-tenant bundles.
|
||||
- Emit timeline event upon successful import.
|
||||
|
||||
Avoid portable bundles for regular intra-enclave automation; the full `bundle.tgz` already carries richer metadata for automated tooling.
|
||||
## Constraints
|
||||
- No external lookups; verification uses bundled roots.
|
||||
- Max size per bundle configurable; default 500 MB.
|
||||
- Keep file paths UTF-8 and slash-separated; avoid host-specific metadata.
|
||||
|
||||
## 2. Generating the bundle
|
||||
|
||||
1. Seal the evidence bundle as usual (`POST /evidence/snapshot` or via CLI).
|
||||
2. Request the portable artefact using the new endpoint:
|
||||
|
||||
```
|
||||
GET /evidence/{bundleId}/portable
|
||||
Scope: evidence:read
|
||||
```
|
||||
|
||||
Response headers mirror the standard download (`application/gzip`, `Content-Disposition: attachment; filename="portable-evidence-bundle-{bundleId}.tgz"`).
|
||||
|
||||
The Evidence Locker caches the portable archive using write-once semantics. Subsequent requests reuse the existing object and the audit log records whether the file was newly created or served from cache.
|
||||
|
||||
## 3. Archive layout
|
||||
|
||||
```
|
||||
portable-bundle-v1.tgz
|
||||
├── manifest.json # Canonical bundle manifest (identical to sealed bundle)
|
||||
├── signature.json # DSSE signature + optional RFC3161 timestamp (base64 token)
|
||||
├── bundle.json # Redacted metadata (bundleId, kind, rootHash, timestamps, incidentMetadata)
|
||||
├── checksums.txt # Merkle root + per-entry SHA-256 digests
|
||||
├── instructions-portable.txt # Human-readable guidance for sealed transfers
|
||||
└── verify-offline.sh # POSIX shell helper (extract + checksum verify + reminder to run DSSE verification)
|
||||
```
|
||||
|
||||
Redaction rules:
|
||||
|
||||
- No tenant identifiers, storage keys, descriptions, or free-form metadata.
|
||||
- Incident metadata is retained *only* under the `incidentMetadata` object (`incident.mode`, `incident.changedAt`, etc.).
|
||||
- `portableGeneratedAt` records when the archive was produced so downstream systems can reason about freshness.
|
||||
|
||||
## 4. Offline verification workflow
|
||||
|
||||
1. Copy `portable-bundle-v1.tgz` into the sealed environment (USB, sneaker-net, etc.).
|
||||
2. Run the included helper from a POSIX shell:
|
||||
|
||||
```sh
|
||||
chmod +x verify-offline.sh
|
||||
./verify-offline.sh portable-bundle-v1.tgz
|
||||
```
|
||||
|
||||
The script:
|
||||
- extracts the archive into a temporary directory,
|
||||
- validates `checksums.txt` using `sha256sum` (or `shasum -a 256`), and
|
||||
- prints the Merkle root hash from `bundle.json`.
|
||||
|
||||
3. Complete provenance verification:
|
||||
- Preferred: `stella evidence verify --bundle portable-bundle-v1.tgz`
|
||||
- Alternative: supply `manifest.json` and `signature.json` to the evidence verifier library.
|
||||
|
||||
4. Record the verification output (root hash, timestamp) with the receiving enclave’s evidence locker or incident ticket.
|
||||
|
||||
> **Note:** The DSSE payload is unchanged from the sealed bundle, so existing verification tooling does not need special handling for portable archives.
|
||||
|
||||
## 5. Importing into the receiving enclave
|
||||
|
||||
1. Upload the archive to the target Evidence Locker or attach it to the incident record.
|
||||
2. Store the checksum report generated by `verify-offline.sh` alongside the archive.
|
||||
3. If downstream automation needs enriched metadata, attach a private note referencing the original bundle’s tenant context—the portable archive intentionally omits it.
|
||||
|
||||
## 6. Troubleshooting
|
||||
|
||||
| Symptom | Likely cause | Remediation |
|
||||
|--------|--------------|-------------|
|
||||
| `verify-offline.sh` reports checksum failures | Transfer corruption | Re-transfer artefact; run `sha256sum portable-bundle-v1.tgz` on both sides and compare. |
|
||||
| `stella evidence verify` cannot reach TSA | Sealed environment lacks TSA connectivity | Verification still succeeds using DSSE signature; capture the missing TSA warning in the import log. |
|
||||
| `/portable` endpoint returns 400 | Bundle not yet sealed or signature missing | Wait for sealing to complete; ensure DSSE signing is enabled. |
|
||||
| `/portable` returns 404 | Bundle not found or tenant mismatch | Confirm DPoP scope and tenant claim; refresh bundle status via `GET /evidence/{id}`. |
|
||||
|
||||
## 7. Change management
|
||||
|
||||
- Portable bundle versioning is encoded in the filename (`portable-bundle-v1.tgz`). When content or script behaviour changes, bump the version and announce in release notes.
|
||||
- Any updates to `verify-offline.sh` must remain POSIX-sh compatible and avoid external dependencies beyond `tar`, `sha256sum`/`shasum`, and standard coreutils.
|
||||
- Remember to update this guide and the bundle packaging dossier (`docs/modules/evidence-locker/bundle-packaging.md`) when fields or workflows change.
|
||||
## Determinism
|
||||
- Sort files lexicographically; use ISO-8601 UTC timestamps.
|
||||
- Avoid re-compressing files; if tar is used, set deterministic headers (uid/gid=0, mtime=0).
|
||||
|
||||
30
docs/airgap/sealing-and-egress.md
Normal file
30
docs/airgap/sealing-and-egress.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Sealing and Egress (Airgap 56-002)
|
||||
|
||||
Guidance for enforcing deny-all egress and validating sealed-mode posture.
|
||||
|
||||
## Network policies
|
||||
- Kubernetes: apply namespace-scoped `NetworkPolicy` with default deny; allow only:
|
||||
- DNS to internal resolver
|
||||
- Object storage/mirror endpoints on allowlist
|
||||
- OTLP/observability endpoints if permitted for sealed monitoring
|
||||
- Docker Compose: use firewall rules or `extra_hosts` to block outbound except mirrors; ship `iptables` template in ops bundle.
|
||||
|
||||
## EgressPolicy facade
|
||||
- Services MUST read `Excititor:Network:EgressPolicy` (or module equivalent) to decide runtime behavior:
|
||||
- `sealed` → deny outbound HTTP/S except allowlist; fail fast on unexpected hosts.
|
||||
- `constrained` → allow allowlist + time/NTP if required.
|
||||
- Log policy decisions and surface `X-Sealed-Mode: true|false` on HTTP responses for diagnostics.
|
||||
|
||||
## Verification checklist
|
||||
1. Confirm policy manifests applied (kubectl/compose diff) and pods restarted.
|
||||
2. Run connectivity probe from each pod:
|
||||
- Allowed endpoints respond (200/OK or 403 expected).
|
||||
- Disallowed domains return immediate failure.
|
||||
3. Attempt bundle import; verify timeline event emitted with `sealed=true`.
|
||||
4. Check observability: counters for denied egress should increment (export or console log).
|
||||
5. Record mirrorGeneration + manifest hash in audit log.
|
||||
|
||||
## Determinism & offline posture
|
||||
- No external CRLs/OCSP in sealed mode; rely on bundled trust roots.
|
||||
- Keep allowlist minimal and declared in config; no implicit fallbacks.
|
||||
- All timestamps UTC; avoid calling external time APIs.
|
||||
Reference in New Issue
Block a user