9.5 KiB
9.5 KiB
Offline and Air-Gap Technical Reference
Source Advisories:
- 01-Dec-2025 - DSSE‑Signed Offline Scanner Updates
- 07-Dec-2025 - Reliable Air‑Gap Verification Workflows
Last Updated: 2025-12-14
1. OFFLINE UPDATE BUNDLE STRUCTURE
1.1 Directory Layout
/bundle-2025-12-14/
manifest.json # version, created_at, entries[], sha256s
payload.tar.zst # actual DB/indices/feeds
payload.tar.zst.sha256
statement.dsse.json # DSSE-wrapped statement over payload hash
rekor-receipt.json # Rekor v2 inclusion/verification material
1.2 Manifest Schema
manifest.json:
{
"version": "string",
"created_at": "UTC ISO-8601",
"entries": [{"name": "string", "sha256": "string", "size": int}],
"payload_sha256": "string"
}
1.3 DSSE Predicate Schema
statement.dsse.json payload:
{
"payloadType": "application/vnd.in-toto+json",
"payload": {
"subject": {
"name": "stella-ops-offline-kit-<DATE>.tgz",
"digest": {"sha256": "string"}
},
"predicateType": "https://stella-ops.org/attestations/offline-update/1",
"predicate": {
"offline_manifest_sha256": "string",
"feeds": [{"name": "string", "snapshot_date": "UTC ISO-8601", "archive_digest": "string"}],
"builder": "string",
"created_at": "UTC ISO-8601",
"oukit_channel": "edge|stable|fips-profile"
}
}
}
1.4 Rekor Receipt Schema
rekor-receipt.json:
{
"uuid": "string",
"logIndex": int,
"rootHash": "string",
"hashes": ["string"],
"checkpoint": "string"
}
2. VERIFICATION SEQUENCE
2.1 Offline Kit Import Steps
1. Validate Cosign signature of tarball
2. Validate offline-manifest.json with JWS signature
3. Verify file digests for all entries (including /attestations/*)
4. Verify DSSE:
- Call StellaOps.Attestor.Verify with:
- offline-update.dsse.json
- offline-update.rekor.json
- local Rekor log snapshot/segment
- Ensure payload digest matches kit tarball + manifest digests
5. Only after all checks pass:
- Swap Scanner's feed pointer to new snapshot
- Emit audit event (kit filename, tarball digest, DSSE digest, Rekor UUID + log index)
2.2 Activation Acceptance Rules
- Trust root: pinned publisher public keys (out-of-band rotation)
- Monotonicity: only activate if
manifest.version > current.version - Atomic switch: unpack → validate → symlink flip (
db/staging/→db/active/) - Quarantine on failure: move to
updates/quarantine/with reason code
3. OFFLINE DIRECTORY LAYOUT
/evidence/
keys/
roots/ # root/intermediate certs, PGP pubkeys
identities/ # per-vendor public keys
tlog-root/ # hashed/pinned tlog root(s)
policy/
verify-policy.yaml
lattice-rules.yaml
sboms/ # *.cdx.json, *.spdx.json
attestations/ # *.intoto.jsonl.dsig (DSSE)
tlog/
checkpoint.sig # signed tree head
entries/ # *.jsonl (Merkle leaves) + proofs
tools/
cosign-<ver> (sha256)
oras-<ver> (sha256)
jq-<ver> (sha256)
scanner-<ver> (sha256)
4. OFFLINE VERIFICATION POLICY SCHEMA
keys:
- ./evidence/keys/identities/vendor_A.pub
- ./evidence/keys/identities/your_authority.pub
tlog:
mode: "offline"
checkpoint: "./evidence/tlog/checkpoint.sig"
entry_pack: "./evidence/tlog/entries"
attestations:
required:
- type: slsa-provenance
- type: cyclonedx-sbom
optional:
- type: vex
constraints:
subjects:
alg: "sha256"
certs:
allowed_issuers:
- "https://fulcio.offline"
allow_expired_if_timepinned: true
5. DETERMINISTIC EVIDENCE RECONCILIATION ALGORITHM
1. Index artifacts by immutable digest
2. For each artifact digest:
- Collect SBOM nodes from canonical SBOM files
- Collect attestations (provenance, VEX, SLSA, signatures)
- Validate each attestation (sig + tlog inclusion proof)
3. Normalize all docs (stable sort, strip non-essential timestamps, lowercase URIs)
4. Apply lattice rules (precedence: vendor > maintainer > 3rd-party)
5. Emit `evidence-graph.json` (stable node/edge order) + `evidence-graph.sha256` + DSSE signature
6. OFFLINE FLOW OPERATIONAL STEPS
1. Import bundle (mount WORM media read-only)
2. Verify tools (hash + signature) before execution
3. Verify tlog checkpoint
4. Verify each inclusion proof
5. Verify attestations (keyring + policy)
6. Ingest SBOMs (canonicalize + hash)
7. Reconcile (apply lattice rules → evidence graph)
8. Record run: write `run.manifest` with input/policy/tool/output hashes; DSSE-sign with Authority key
7. SCANNER CONFIG SURFACE
7.1 Offline Kit Configuration
scanner:
offlineKit:
requireDsse: true # fail import if DSSE/Rekor verification fails
rekorOfflineMode: true # use local snapshots only
attestationVerifier: https://attestor.internal
trustAnchors:
- anchorId: "UUID"
purlPattern: "pkg:npm/*"
allowedKeyids: ["key1", "key2"]
7.2 DSSE/Rekor Failure Handling
DSSE/Rekor fail, Cosign + manifest OK:
- Keep old feeds active
- Mark import as failed; surface ProblemDetails error via API/UI
- Log structured fields:
rekorUuid,attestationDigest,offlineKitHash,failureReason
Config flag to soften during rollout:
- When
requireDsse=false: treat DSSE/Rekor failure as warning; allow import with alerts
8. SBOM INGESTION DETERMINISTIC FLOW
# 1. Normalize SBOMs to canonical form
jq -S . sboms/app.cdx.json > sboms/_canon/app.cdx.json
# 2. Validate schemas (vendored validators)
# 3. Hash-pin canonical files and record in manifest.lock
sha256sum sboms/_canon/*.json > manifest.lock
# 4. Import to DB with idempotent keys: (artifactDigest, sbomHash)
9. OFFLINE REKOR MIRROR VERIFICATION
9.1 File-Ledger Pattern
- Keep
tlog/checkpoint.sig(signed tree head) +tlog/entries/*.jsonl(leaves + proofs)
9.2 Verification Steps
1. Recompute Merkle root from entries
2. Check matches `checkpoint.sig` (after verifying signature with tlog root key)
3. For each attestation:
- Verify UUID/digest appears in entry pack
- Verify inclusion proof resolves
10. METRICS & OBSERVABILITY
10.1 Offline Kit Metrics (Prometheus)
offlinekit_import_total{status="success|failed_dsse|failed_rekor|failed_cosign"}
offlinekit_attestation_verify_latency_seconds (histogram)
attestor_rekor_success_total
attestor_rekor_retry_total
rekor_inclusion_latency
10.2 Structured Logging Fields
rekorUuid
attestationDigest
offlineKitHash
failureReason
kitFilename
tarballDigest
dsseStatementDigest
rekorLogIndex
11. ERROR HANDLING
11.1 Import Failure Modes
| Failure Type | Action | Audit Event |
|---|---|---|
| Cosign signature invalid | Reject, quarantine | IMPORT_FAILED_COSIGN |
| Manifest signature invalid | Reject, quarantine | IMPORT_FAILED_MANIFEST |
| DSSE verification failed | Reject (if requireDsse=true) | IMPORT_FAILED_DSSE |
| Rekor inclusion failed | Reject (if requireDsse=true) | IMPORT_FAILED_REKOR |
| Digest mismatch | Reject, quarantine | IMPORT_FAILED_DIGEST |
| Version not monotonic | Reject | IMPORT_FAILED_VERSION |
11.2 Quarantine Structure
/updates/quarantine/<timestamp>-<reason>/
bundle.tar.zst
manifest.json
verification.log
failure-reason.txt
12. CLI COMMANDS
12.1 Offline Kit Import
stellaops offline import \
--bundle ./bundle-2025-12-14.tar.zst \
--verify-dsse \
--verify-rekor \
--trust-root /evidence/keys/roots/stella-root.pub
12.2 Offline Kit Status
stellaops offline status
# Output:
# Active kit: bundle-2025-12-14
# Kit digest: sha256:abc123...
# Activated at: 2025-12-14T10:00:00Z
# DSSE verified: true
# Rekor verified: true
12.3 Offline Verification
stellaops verify offline \
--evidence-dir /evidence \
--artifact sha256:def456... \
--policy verify-policy.yaml
13. AUDIT TRAIL
13.1 Audit Event Schema
{
"eventId": "uuid",
"eventType": "OFFLINE_KIT_IMPORTED",
"timestamp": "2025-12-14T10:00:00Z",
"actor": "system",
"details": {
"kitFilename": "bundle-2025-12-14.tar.zst",
"tarballDigest": "sha256:...",
"dsseStatementDigest": "sha256:...",
"rekorUuid": "...",
"rekorLogIndex": 12345,
"previousKitVersion": "bundle-2025-12-07",
"newKitVersion": "bundle-2025-12-14"
},
"result": "success"
}
13.2 Audit Log Storage
CREATE TABLE offline_kit_audit (
event_id UUID PRIMARY KEY,
event_type TEXT NOT NULL,
timestamp TIMESTAMPTZ NOT NULL,
actor TEXT NOT NULL,
details JSONB NOT NULL,
result TEXT NOT NULL
);
CREATE INDEX idx_offline_kit_audit_ts ON offline_kit_audit(timestamp DESC);
CREATE INDEX idx_offline_kit_audit_type ON offline_kit_audit(event_type);
14. SECURITY CONSIDERATIONS
14.1 Key Management
- Trust roots: pinned via out-of-band distribution
- Key rotation: maintain version history in trust store
- Revocation: maintain revoked_keys list in trust anchors
14.2 Integrity Guarantees
- All bundles content-addressed
- Manifest integrity via signature
- DSSE envelope integrity via signature
- Rekor inclusion proof integrity via Merkle tree
14.3 Air-Gap Boundaries
Allowed:
- Local file system reads (read-only mount)
- Local tool execution (verified binaries)
- Local database writes (staged)
Forbidden:
- Network egress
- DNS lookups
- NTP synchronization (use frozen clock)
- External API calls
Document Version: 1.0 Target Platform: .NET 10, PostgreSQL ≥16, Angular v17