new two advisories and sprints work on them
This commit is contained in:
@@ -1,309 +0,0 @@
|
||||
Here’s a short, implementation‑ready plan to turn your SBOMs into enforceable, cryptographic gates in Stella Ops—sequence, gate checks, and a compact threat model you can wire into a sprint.
|
||||
|
||||
---
|
||||
|
||||
# Minimal sequence (do now)
|
||||
|
||||
1. **CI build → Scanner/Sbomer**
|
||||
Compute `sha256` of each artifact and emit CycloneDX 1.6 SBOM with `components[].hashes[]`. ([CycloneDX][1])
|
||||
2. **Authority (DSSE sign)**
|
||||
Canonicalize SBOM JSON; wrap as DSSE `payloadType` for attestations and sign (HSM/KMS key). ([in-toto][2])
|
||||
3. **Router (Rekor v2)**
|
||||
Upload DSSE / in‑toto Statement to Rekor v2; persist returned `uuid`, `logIndex`, `integratedTime`. ([Sigstore Blog][3])
|
||||
4. **Vexer/Excititor (VEX)**
|
||||
Emit OpenVEX/CSAF (or in‑toto predicate) referencing CycloneDX `serialNumber`/`bom-ref` and the Rekor `uuid`. ([in-toto][2])
|
||||
5. **CI gate (OPA/Rego)**
|
||||
Verify (a) DSSE signature chain, (b) `payloadType` matches expected, (c) Rekor inclusion (via `logIndex`/UUID), (d) allowed `predicateType`, (e) component hash equals subject digest. ([Witness][4])
|
||||
|
||||
---
|
||||
|
||||
# Paste‑in Rego (gate)
|
||||
|
||||
```rego
|
||||
package stella.gate
|
||||
|
||||
deny[msg] {
|
||||
input.attestation.payloadType != "application/vnd.cyclonedx+json"
|
||||
msg = "unexpected payloadType"
|
||||
}
|
||||
|
||||
deny[msg] {
|
||||
not input.rekor.logIndex
|
||||
msg = "missing rekor logIndex"
|
||||
}
|
||||
|
||||
/* extend:
|
||||
- verify DSSE signature against Authority key
|
||||
- verify Rekor inclusion proof/integratedTime
|
||||
- ensure predicateType ∈ {
|
||||
"https://cyclonedx.org/schema/bom-1.6",
|
||||
"https://openvex.org/v1"
|
||||
}
|
||||
- ensure subject digest == components[].hashes[].content
|
||||
*/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Compact threat model (top 3 + mitigations)
|
||||
|
||||
* **Tampering at rest** → Anchor in Rekor v2; verify inclusion + `integratedTime`; require DSSE signature with Authority HSM key. ([Sigstore Blog][3])
|
||||
* **Time‑shift / backdating** → Reject if `integratedTime` < pipeline build time − skew; optional RFC‑3161 timestamping on uploads. (Policy check in Scheduler.) ([Sigstore Blog][3])
|
||||
* **Provenance spoofing** → Enforce valid `predicateType` (in‑toto/OpenVEX), and map `signatures[].keyid` to trusted Authority keys (Fulcio/HSM). ([in-toto][2])
|
||||
|
||||
---
|
||||
|
||||
# Where this lands in Stella
|
||||
|
||||
* **Scanner**: compute subject digests; emit artifact metadata.
|
||||
* **Sbomer**: produce CycloneDX 1.6 with hashes, CBOM/attestations support ready. ([CycloneDX][1])
|
||||
* **Authority**: create DSSE envelope + sign; maintain key roster & rotation. ([Gradle Documentation][5])
|
||||
* **Router**: call Rekor v2; persist `uuid`/`logIndex`/`integratedTime` and expose `verifyRekor(uuid)`. ([Sigstore Blog][3])
|
||||
* **Vexer/Excititor**: emit OpenVEX / in‑toto predicates linking `bom-ref` and Rekor `uuid`. ([in-toto][2])
|
||||
|
||||
---
|
||||
|
||||
# Final sprint checklist
|
||||
|
||||
* Enable DSSE wrapping + Authority signing in one CI pipeline; push to Rekor v2; store `logIndex`. ([Sigstore Blog][3])
|
||||
* Add OPA policy to verify `payloadType`, Rekor presence, and digest match; fail CI on violation. ([Witness][4])
|
||||
* Add Scheduler job to periodically re‑verify Rekor roots and enforce time‑skew rules. ([Sigstore Blog][3])
|
||||
|
||||
**Why now:** CycloneDX 1.6 added attestations/CBOM, making SBOMs first‑class, signed evidence; Rekor v2 lowers cost and simplifies ops—ideal for anchoring these facts and gating releases. ([CycloneDX][1])
|
||||
|
||||
If you want, I can drop this into `docs/policies/OPA/stella.gate.rego` and a sample CI job for your GitLab pipeline next.
|
||||
|
||||
[1]: https://cyclonedx.org/news/cyclonedx-v1.6-released/?utm_source=chatgpt.com "CycloneDX v1.6 Released, Advances Software Supply ..."
|
||||
[2]: https://in-toto.io/docs/specs/?utm_source=chatgpt.com "Specifications"
|
||||
[3]: https://blog.sigstore.dev/rekor-v2-ga/?utm_source=chatgpt.com "Rekor v2 GA - Cheaper to run, simpler to maintain"
|
||||
[4]: https://witness.dev/docs/docs/concepts/policy/?utm_source=chatgpt.com "Policies"
|
||||
[5]: https://docs.gradle.com/develocity/dpg/current/?utm_source=chatgpt.com "Develocity Provenance Governor"
|
||||
|
||||
|
||||
|
||||
---
|
||||
Here’s a compact, engineer‑first guide to emitting a CycloneDX SBOM, wrapping it in a DSSE/in‑toto attestation, and anchoring it in Rekor v2—so you can copy/paste shapes straight into your Sbomer → Authority → Router flow.
|
||||
|
||||
---
|
||||
|
||||
# Why this matters (quick background)
|
||||
|
||||
* **CycloneDX**: the SBOM format you’ll emit.
|
||||
* **DSSE**: minimal, unambiguous envelope for signing arbitrary payloads (your SBOM).
|
||||
* **in‑toto Statement**: standard wrapper with `subject` + `predicate` so policy engines can reason about artifacts.
|
||||
* **Rekor (v2)**: transparency log anchor (UUID, index, integrated time) to verify later at gates.
|
||||
|
||||
---
|
||||
|
||||
# Minimal CycloneDX 1.6 SBOM (emit from `Sbomer`)
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"serialNumber": "urn:uuid:11111111-2222-3333-4444-555555555555",
|
||||
"metadata": {
|
||||
"component": {
|
||||
"bom-ref": "stella-app",
|
||||
"type": "application",
|
||||
"name": "stella-app",
|
||||
"version": "1.2.3"
|
||||
}
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"bom-ref": "lib-a",
|
||||
"type": "library",
|
||||
"name": "lib-a",
|
||||
"version": "0.1.0",
|
||||
"hashes": [
|
||||
{ "alg": "SHA-256", "content": "<hex-hash>" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Must‑emit fields (Sbomer):** `specVersion`, `serialNumber`, `components[].bom-ref`, `components[].hashes[].(alg,content)`.
|
||||
|
||||
---
|
||||
|
||||
# Wrap SBOM with DSSE (signed by `Authority`)
|
||||
|
||||
```json
|
||||
{
|
||||
"payloadType": "application/vnd.cyclonedx+json",
|
||||
"payload": "<base64(cyclonedx-bom.json)>",
|
||||
"signatures": [
|
||||
{ "keyid": "cosign:sha256:abcd...", "sig": "<base64-signature>" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Must‑emit (Authority):** `payloadType`, `payload` (base64), `signatures[].keyid`, `signatures[].sig`.
|
||||
|
||||
---
|
||||
|
||||
# Optional: in‑toto Statement (produced by `Excititor/Vexer`)
|
||||
|
||||
```json
|
||||
{
|
||||
"_type": "https://in-toto.io/Statement/v0.1",
|
||||
"subject": [
|
||||
{ "name": "stella-app", "digest": { "sha256": "<artifact-sha256>" } }
|
||||
],
|
||||
"predicateType": "https://cyclonedx.org/schema/bom-1.6",
|
||||
"predicate": {
|
||||
"bomRef": "stella-app",
|
||||
"uri": "oci://registry.example.com/stella-app@sha256:<digest>#sbom"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Must‑emit (Excititor/Vexer):** `predicateType` and a `predicate` your policy engine can dereference (embed SBOM or provide a pointer).
|
||||
|
||||
---
|
||||
|
||||
# Rekor v2 anchor (persist in `Router`, verify at gates)
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "c3f2e4a8-...",
|
||||
"logIndex": 123456,
|
||||
"integratedTime": "2026-01-15T12:34:56Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Must‑store (Router):** `uuid`, `logIndex`, `integratedTime`.
|
||||
|
||||
---
|
||||
|
||||
# End‑to‑end checks (put these in your CI gate)
|
||||
|
||||
* **SBOM shape**: JSON Schema validate CycloneDX; ensure `serialNumber` + per‑component hashes exist.
|
||||
* **DSSE**: verify signature over `payload` and `payloadType`; match `keyid` to trusted keys/profile.
|
||||
* **in‑toto**: confirm `subject.digest` equals the release OCI digest; `predicateType` matches CycloneDX 1.6/1.7.
|
||||
* **Rekor v2**: look up `uuid` → confirm `logIndex` & `integratedTime` and verify inclusion proof.
|
||||
|
||||
---
|
||||
|
||||
# Stella Ops module contract (TL;DR)
|
||||
|
||||
* **Sbomer** → emits CycloneDX 1.6/1.7 with `bom-ref` + hashes.
|
||||
* **Authority** → DSSE sign (`payloadType=application/vnd.cyclonedx+json`).
|
||||
* **Excititor/Vexer** → optional in‑toto Statement with CycloneDX predicate or pointer.
|
||||
* **Router** → store Rekor v2 tuple; expose verify endpoint for gates.
|
||||
|
||||
If you want, I can turn this into ready‑to‑run .NET 10 DTOs + validation (FluentValidation) and a tiny verifier CLI that checks all four layers in one go.
|
||||
Here’s a compact, auditor‑friendly way to sign **binary diffs** so they fit cleanly into today’s supply‑chain tooling (DSSE, in‑toto, Sigstore/Rekor) without inventing a new envelope.
|
||||
|
||||
---
|
||||
|
||||
# DSSE “delta‑sig” predicate for signed binary diffs (what & why)
|
||||
|
||||
* **Goal:** prove *exactly what changed* in a compiled artifact (per‑function patching, hotfixes/backports) and who signed it—using the standard **DSSE** (Dead Simple Signing Envelope) + **in‑toto predicate typing** so verifiers and transparency logs work out‑of‑the‑box.
|
||||
* **Why not just hash the whole file?** Full‑file hashes miss *where* and *how* a patch changed code. A delta predicate captures function‑level changes with canonical digests, so auditors can verify the patch is minimal and intentional, and policy can gate on “only approved backports applied.”
|
||||
|
||||
---
|
||||
|
||||
# Envelope strategy
|
||||
|
||||
* Keep the **DSSE envelope** as usual (`payloadType`, `payload`, `signatures`).
|
||||
* The DSSE `payload` is a **canonical JSON** object typed as an in‑toto predicate.
|
||||
* Predicate type (minimal): `stellaops/delta-sig/v1`.
|
||||
|
||||
This keeps interoperability with:
|
||||
|
||||
* **Sigstore/Rekor** (log DSSE envelopes),
|
||||
* **in‑toto** (predicate typing & subject semantics),
|
||||
* existing verification flows (cosign/sigstore‑python/in‑toto‑verify).
|
||||
|
||||
---
|
||||
|
||||
# Minimal predicate schema
|
||||
|
||||
```json
|
||||
{
|
||||
"predicateType": "stellaops/delta-sig/v1",
|
||||
"subject": [
|
||||
{
|
||||
"uri": "oci://registry.example.com/app@sha256:…",
|
||||
"digest": { "algo": "sha256", "hex": "<artifact_sha256>" },
|
||||
"filename": "bin/app",
|
||||
"arch": "linux-amd64"
|
||||
}
|
||||
],
|
||||
"delta": [
|
||||
{
|
||||
"function_id": "foo::bar(int,char)",
|
||||
"addr": 140737488355328,
|
||||
"old_hash": "<sha256_of_old_bytes>",
|
||||
"new_hash": "<sha256_of_new_bytes>",
|
||||
"hash_algo": "sha256",
|
||||
"diff_len": 112,
|
||||
"patch_offset": 4096,
|
||||
"compressed_diff_b64": "<optional_zstd_or_gzip_b64>"
|
||||
}
|
||||
],
|
||||
"tooling": {
|
||||
"lifter": "ghidra",
|
||||
"lifter_version": "11.1",
|
||||
"canonical_ir": "llvm-ir-15"
|
||||
},
|
||||
"canonicalization": {
|
||||
"json_canonicalization_version": "RFC8785"
|
||||
},
|
||||
"signer": {
|
||||
"keyid": "SHA256:…",
|
||||
"signer_name": "Release Engineering"
|
||||
},
|
||||
"signed_digest": {
|
||||
"algo": "sha256",
|
||||
"hex": "<sha256_of_canonical_payload_bytes>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Notes**
|
||||
|
||||
* Use **SHA‑256** for `subject.digest`, `old_hash`, `new_hash`, and `signed_digest` to maximize compatibility with Rekor/Sigstore. (If you control both ends, **BLAKE2b‑256** is a fine faster alternative.)
|
||||
* `function_id` should be a **stable signature** (normalized symbol or demangled prototype); fall back to address + size if needed.
|
||||
* `compressed_diff_b64` is optional but handy for reproducible patch replay.
|
||||
|
||||
---
|
||||
|
||||
# Signing & verification (practical)
|
||||
|
||||
1. **Produce canonical payload**
|
||||
|
||||
* Serialize JSON with **RFC 8785** canonicalization (no insignificant whitespace, deterministic key order).
|
||||
2. **Wrap in DSSE**
|
||||
|
||||
* `payloadType`: `application/vnd.in-toto+json` (common) or a dedicated type string if you prefer.
|
||||
* `payload`: base64 of canonical JSON bytes.
|
||||
3. **Sign**
|
||||
|
||||
* Use **cosign** or **sigstore‑python** to sign DSSE; store in **Rekor** (transparency).
|
||||
4. **Verify**
|
||||
|
||||
* Check DSSE signature → decode predicate → verify each `old_hash`/`new_hash` against the target bytes → optionally replay `compressed_diff_b64` and re‑hash to confirm `new_hash`.
|
||||
|
||||
Policy examples you can enforce:
|
||||
|
||||
* Only allow releases whose delta predicate touches **≤ N functions** and **no control‑flow edges** outside whitelisted modules.
|
||||
* Require `tooling.lifter` in an approved set and `signed_digest.algo == "sha256"`.
|
||||
|
||||
---
|
||||
|
||||
# Why this fits your stack (Stella Ops, CI/CD, auditors)
|
||||
|
||||
* **Auditable:** function‑level intent captured, reproducible verification, deterministic hashing.
|
||||
* **Composable:** works with existing DSSE/in‑toto pipelines; attach to OCI artifacts or release manifests.
|
||||
* **Gate‑able:** let release policy check the delta surface and signer identity before promotion.
|
||||
* **Future‑proof:** can add PQC keys later without changing the predicate.
|
||||
|
||||
If you want, I can generate:
|
||||
|
||||
* A JSON Schema (`$id`, types, enums, bounds) for `stellaops/delta-sig/v1`.
|
||||
* A tiny reference **signer** (CLI) that emits canonical JSON + DSSE, and a **verifier** that checks function‑level diffs against a binary.
|
||||
Reference in New Issue
Block a user