18 KiB
Binary Delta Attestation Flow
Overview
The Binary Delta Attestation Flow describes how StellaOps tracks and attests changes at the binary level between image versions. This flow detects modified, added, or removed binaries and generates attestations about what changed, enabling precise supply chain verification.
Business Value: Detect unauthorized modifications, track binary provenance, and ensure only expected changes are deployed between versions.
Actors
| Actor | Type | Role |
|---|---|---|
| CI Pipeline | System | Triggers delta analysis |
| BinaryIndex | Service | Extracts binary fingerprints |
| Scanner | Service | Coordinates analysis |
| Attestor | Service | Generates delta attestations |
| Signer | Service | Signs attestations |
| Symbols | Service | Resolves debug symbols |
Prerequisites
- Previous image version scanned and indexed
- Binary analysis enabled for image
- Build provenance available (optional)
Binary Fingerprinting
StellaOps extracts multiple identifiers from binaries:
| Identifier | Source | Stability |
|---|---|---|
| SHA-256 | File content | Exact match |
| Build ID | ELF .note.gnu.build-id |
Build-specific |
| PE Checksum | PE header | Load-time |
| Code Hash | .text section only |
Ignores data |
| Symbol Hash | Exported symbols | API stability |
| Debug ID | DWARF/PDB reference | Debug matching |
Flow Diagram
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Binary Delta Attestation Flow │
└─────────────────────────────────────────────────────────────────────────────────┘
┌───────────┐ ┌─────────┐ ┌─────────────┐ ┌─────────┐ ┌─────────┐ ┌────────┐
│ CI │ │ Scanner │ │ BinaryIndex │ │ Symbols │ │ Attestor│ │ Signer │
└─────┬─────┘ └────┬────┘ └──────┬──────┘ └────┬────┘ └────┬────┘ └───┬────┘
│ │ │ │ │ │
│ Scan v1.2.4 │ │ │ │ │
│ --baseline │ │ │ │ │
│ v1.2.3 │ │ │ │ │
│────────────>│ │ │ │ │
│ │ │ │ │ │
│ │ Load v1.2.3 │ │ │ │
│ │ index │ │ │ │
│ │─────────────>│ │ │ │
│ │ │ │ │ │
│ │ Baseline │ │ │ │
│ │ binaries │ │ │ │
│ │<─────────────│ │ │ │
│ │ │ │ │ │
│ │ Index v1.2.4 │ │ │ │
│ │─────────────>│ │ │ │
│ │ │ │ │ │
│ │ │ Extract │ │ │
│ │ │ binaries │ │ │
│ │ │───┐ │ │ │
│ │ │ │ │ │ │
│ │ │<──┘ │ │ │
│ │ │ │ │ │
│ │ │ Compute │ │ │
│ │ │ fingerprints │ │ │
│ │ │───┐ │ │ │
│ │ │ │ │ │ │
│ │ │<──┘ │ │ │
│ │ │ │ │ │
│ │ Current │ │ │ │
│ │ binaries │ │ │ │
│ │<─────────────│ │ │ │
│ │ │ │ │ │
│ │ Compute │ │ │ │
│ │ delta │ │ │ │
│ │───┐ │ │ │ │
│ │ │ │ │ │ │
│ │<──┘ │ │ │ │
│ │ │ │ │ │
│ │ Resolve │ │ │ │
│ │ symbols │ │ │ │
│ │──────────────────────────────> │ │
│ │ │ │ │ │
│ │ │ │ Map to │ │
│ │ │ │ source │ │
│ │ │ │───┐ │ │
│ │ │ │ │ │ │
│ │ │ │<──┘ │ │
│ │ │ │ │ │
│ │ Symbol │ │ │ │
│ │ mappings │ │ │ │
│ │<────────────────────────────── │ │
│ │ │ │ │ │
│ │ Generate │ │ │ │
│ │ attestation │ │ │ │
│ │─────────────────────────────────────────>│ │
│ │ │ │ │ │
│ │ │ │ │ Create │
│ │ │ │ │ statement │
│ │ │ │ │───┐ │
│ │ │ │ │ │ │
│ │ │ │ │<──┘ │
│ │ │ │ │ │
│ │ │ │ │ Sign │
│ │ │ │ │──────────>│
│ │ │ │ │ │
│ │ │ │ │ DSSE │
│ │ │ │ │<──────────│
│ │ │ │ │ │
│ │ Attestation │ │ │ │
│ │<─────────────────────────────────────────│ │
│ │ │ │ │ │
│ Delta │ │ │ │ │
│ report │ │ │ │ │
│<────────────│ │ │ │ │
│ │ │ │ │ │
Step-by-Step
1. Delta Scan Request
CI pipeline requests delta analysis:
stellaops scan myapp:v1.2.4 \
--baseline myapp:v1.2.3 \
--binary-delta \
--attestation
API equivalent:
POST /api/v1/scans HTTP/1.1
Content-Type: application/json
{
"image": "docker.io/myorg/myapp:v1.2.4",
"options": {
"binary_delta": {
"enabled": true,
"baseline": "docker.io/myorg/myapp:v1.2.3"
},
"attestation": true
}
}
2. Baseline Index Retrieval
Scanner retrieves existing binary index for baseline:
{
"image": "docker.io/myorg/myapp:v1.2.3",
"digest": "sha256:baseline123...",
"indexed_at": "2024-12-28T10:00:00Z",
"binaries": [
{
"path": "/app/myapp",
"type": "elf-x86_64",
"sha256": "abc123...",
"build_id": "7f3a9b2c1234567890abcdef",
"code_hash": "def456...",
"symbols": {
"exported": 234,
"hash": "ghi789..."
},
"size": 15234567
},
{
"path": "/app/lib/libcore.so",
"type": "elf-x86_64-shared",
"sha256": "jkl012...",
"build_id": "abcdef1234567890",
"size": 2345678
}
]
}
3. Current Image Indexing
BinaryIndex extracts and fingerprints current image binaries:
{
"image": "docker.io/myorg/myapp:v1.2.4",
"digest": "sha256:current456...",
"indexed_at": "2024-12-29T10:00:00Z",
"binaries": [
{
"path": "/app/myapp",
"type": "elf-x86_64",
"sha256": "xyz789...", // Changed
"build_id": "9f5b7d4e2345678901bcdefg", // New build
"code_hash": "uvw012...", // Code changed
"symbols": {
"exported": 238, // 4 new symbols
"hash": "rst345..." // Symbol hash changed
},
"size": 15456789 // Size increased
},
{
"path": "/app/lib/libcore.so",
"type": "elf-x86_64-shared",
"sha256": "jkl012...", // Unchanged
"build_id": "abcdef1234567890",
"size": 2345678
},
{
"path": "/app/lib/libnew.so", // New binary
"type": "elf-x86_64-shared",
"sha256": "new123...",
"build_id": "newbuild123456",
"size": 567890
}
]
}
4. Delta Computation
Scanner computes binary delta:
{
"delta": {
"baseline": {
"image": "docker.io/myorg/myapp:v1.2.3",
"digest": "sha256:baseline123..."
},
"current": {
"image": "docker.io/myorg/myapp:v1.2.4",
"digest": "sha256:current456..."
},
"summary": {
"total_binaries_baseline": 2,
"total_binaries_current": 3,
"modified": 1,
"added": 1,
"removed": 0,
"unchanged": 1
},
"changes": [
{
"type": "modified",
"path": "/app/myapp",
"baseline": {
"sha256": "abc123...",
"build_id": "7f3a9b2c1234567890abcdef",
"size": 15234567
},
"current": {
"sha256": "xyz789...",
"build_id": "9f5b7d4e2345678901bcdefg",
"size": 15456789
},
"analysis": {
"code_changed": true,
"symbols_added": ["new_feature_init", "new_feature_process", "new_feature_cleanup", "handle_error_v2"],
"symbols_removed": [],
"size_delta": "+222222 bytes"
}
},
{
"type": "added",
"path": "/app/lib/libnew.so",
"current": {
"sha256": "new123...",
"build_id": "newbuild123456",
"size": 567890
}
}
],
"unchanged": [
{
"path": "/app/lib/libcore.so",
"sha256": "jkl012..."
}
]
}
}
5. Symbol Resolution
Symbols service maps build IDs to source:
{
"symbol_resolution": {
"/app/myapp": {
"build_id": "9f5b7d4e2345678901bcdefg",
"debug_info_available": true,
"source_mapping": {
"repository": "github.com/myorg/myapp",
"commit": "abc123def456",
"build_time": "2024-12-29T08:00:00Z",
"compiler": "gcc 13.2.0",
"flags": "-O2 -fstack-protector-strong"
},
"new_symbols": [
{
"name": "new_feature_init",
"source": "src/features/new_feature.c:45",
"size": 256
},
{
"name": "new_feature_process",
"source": "src/features/new_feature.c:89",
"size": 1024
}
]
}
}
}
6. Delta Attestation Generation
Attestor creates in-toto statement for the delta:
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{
"name": "docker.io/myorg/myapp",
"digest": {"sha256": "current456..."}
}
],
"predicateType": "https://stellaops.io/attestation/binary-delta/v1",
"predicate": {
"baseline": {
"name": "docker.io/myorg/myapp",
"digest": {"sha256": "baseline123..."}
},
"delta_summary": {
"modified": 1,
"added": 1,
"removed": 0,
"unchanged": 1
},
"binary_changes": [
{
"path": "/app/myapp",
"change_type": "modified",
"baseline_hash": "sha256:abc123...",
"current_hash": "sha256:xyz789...",
"provenance": {
"commit": "abc123def456",
"build_id": "9f5b7d4e2345678901bcdefg"
}
},
{
"path": "/app/lib/libnew.so",
"change_type": "added",
"current_hash": "sha256:new123...",
"provenance": {
"commit": "abc123def456",
"build_id": "newbuild123456"
}
}
],
"verification": {
"all_changes_have_provenance": true,
"all_binaries_signed": true,
"no_unexpected_modifications": true
},
"timestamp": "2024-12-29T10:30:00Z"
}
}
7. DSSE Signing
Signer wraps statement in DSSE envelope:
{
"payloadType": "application/vnd.in-toto+json",
"payload": "base64:statement-json...",
"signatures": [
{
"keyid": "sha256:binary-attestation-key",
"sig": "base64:signature...",
"cert": "base64:x509-certificate..."
}
]
}
Verification Policies
Strict Mode
binary_delta_policy:
mode: strict
rules:
- all_changes_must_have_provenance: true
- allow_added_binaries: true
- allow_removed_binaries: false
- require_signed_builds: true
- max_modified_binaries: 10
Permissive Mode
binary_delta_policy:
mode: permissive
rules:
- allow_unsigned_binaries: true
- warn_on_missing_provenance: true
- block_known_malware_hashes: true
Data Contracts
Binary Delta Request Schema
interface BinaryDeltaRequest {
image: string;
options: {
binary_delta: {
enabled: boolean;
baseline: string; // Image reference or digest
include_symbols?: boolean;
include_provenance?: boolean;
};
attestation?: boolean;
};
}
Binary Delta Response Schema
interface BinaryDeltaResponse {
scan_id: string;
baseline: ImageReference;
current: ImageReference;
summary: {
total_binaries_baseline: number;
total_binaries_current: number;
modified: number;
added: number;
removed: number;
unchanged: number;
};
changes: BinaryChange[];
unchanged: BinaryReference[];
attestation?: {
digest: string;
rekor_log_index?: number;
};
policy_verdict?: {
verdict: 'PASS' | 'WARN' | 'FAIL';
violations?: string[];
};
}
Error Handling
| Error | Recovery |
|---|---|
| Baseline not found | Return error, suggest scanning baseline first |
| Build ID not found | Continue without provenance, reduce confidence |
| Symbol resolution failed | Continue with hash-only comparison |
| Signing failure | Return delta without attestation |
Observability
Metrics
| Metric | Type | Labels |
|---|---|---|
binary_delta_scans_total |
Counter | result |
binary_delta_changes_total |
Counter | type (modified/added/removed) |
binary_delta_duration_seconds |
Histogram | - |
binary_index_size_bytes |
Histogram | - |
Key Log Events
| Event | Level | Fields |
|---|---|---|
binary.delta.started |
INFO | baseline, current |
binary.delta.computed |
INFO | modified, added, removed |
binary.provenance.missing |
WARN | path, build_id |
binary.delta.attested |
INFO | digest, rekor_index |
Related Flows
- SBOM Generation Flow - Component-level tracking
- CI/CD Gate Flow - Pipeline integration
- Evidence Bundle Export Flow - Attestation packaging