Files
git.stella-ops.org/docs/flows/16-offline-sync-flow.md
StellaOps Bot ca578801fd save progress
2026-01-03 00:49:19 +02:00

16 KiB

Offline Sync Flow

Overview

The Offline Sync Flow describes how StellaOps supports air-gapped and disconnected environments through the Offline Kit. This flow covers advisory bundle generation, secure transfer, verification, and import in environments with no external network connectivity.

Business Value: Enable full vulnerability scanning and policy evaluation capabilities in highly secure, air-gapped environments while maintaining audit trails and cryptographic verification.

Actors

Actor Type Role
Online Admin Human Generates and exports offline bundles
Offline Admin Human Imports and verifies bundles
Mirror Service Creates advisory snapshots
EvidenceLocker Service Seals bundles for transfer
AirGap Importer Service Validates and imports bundles
Signer Service Signs bundle manifests

Prerequisites

Online Environment

  • Access to vulnerability feeds (NVD, GHSA, etc.)
  • Signing keys configured
  • Bundle generation scheduled

Offline Environment

  • AirGap services deployed
  • Trust anchors configured (public keys)
  • Secure transfer mechanism available

Bundle Types

Bundle Type Contents Frequency
Advisory Bundle CVE data, CVSS scores, affected versions Daily/Weekly
VEX Bundle VEX statements from trusted issuers Daily
Policy Bundle Policy sets, rules, exceptions On-demand
Trust Bundle Signing keys, certificates, CRLs Monthly
Time Anchor Roughtime proofs, NTP alternatives Daily

Flow Diagram

┌─────────────────────────────────────────────────────────────────────────────────┐
│                            Offline Sync Flow                                     │
└─────────────────────────────────────────────────────────────────────────────────┘

 ONLINE ENVIRONMENT                         OFFLINE ENVIRONMENT
┌────────────────────────────────┐         ┌────────────────────────────────┐
│                                │         │                                │
│ ┌────────┐  ┌────────┐  ┌────┐│         │┌────┐  ┌─────────┐  ┌────────┐│
│ │ Mirror │  │Evidence│  │Sign││         ││Verif│  │ AirGap  │  │Concelier││
│ │        │  │ Locker │  │    ││         ││     │  │Importer │  │        ││
│ └───┬────┘  └───┬────┘  └──┬─┘│         │└──┬──┘  └────┬────┘  └───┬────┘│
│     │           │          │  │         │   │          │           │     │
│     │ Snapshot  │          │  │         │   │          │           │     │
│     │ advisories│          │  │         │   │          │           │     │
│     │───┐       │          │  │         │   │          │           │     │
│     │   │       │          │  │         │   │          │           │     │
│     │<──┘       │          │  │         │   │          │           │     │
│     │           │          │  │         │   │          │           │     │
│     │ Create    │          │  │         │   │          │           │     │
│     │ bundle    │          │  │         │   │          │           │     │
│     │──────────>│          │  │         │   │          │           │     │
│     │           │          │  │         │   │          │           │     │
│     │           │ Seal     │  │         │   │          │           │     │
│     │           │──────────>  │         │   │          │           │     │
│     │           │          │  │         │   │          │           │     │
│     │           │ Signed   │  │         │   │          │           │     │
│     │           │ bundle   │  │         │   │          │           │     │
│     │           │<──────────  │         │   │          │           │     │
│     │           │          │  │         │   │          │           │     │
│     │           │          │  │         │   │          │           │     │
│     │      [Export to       ] │         │   │          │           │     │
│     │      [removable media ] │ =========> [Import from│           │     │
│     │           │          │  │         │   │removable]│           │     │
│     │           │          │  │         │   │          │           │     │
│     │           │          │  │         │   │ Verify   │           │     │
│     │           │          │  │         │   │ signature│           │     │
│     │           │          │  │         │   │───┐      │           │     │
│     │           │          │  │         │   │   │      │           │     │
│     │           │          │  │         │   │<──┘      │           │     │
│     │           │          │  │         │   │          │           │     │
│     │           │          │  │         │   │ Verify   │           │     │
│     │           │          │  │         │   │ Merkle   │           │     │
│     │           │          │  │         │   │───┐      │           │     │
│     │           │          │  │         │   │   │      │           │     │
│     │           │          │  │         │   │<──┘      │           │     │
│     │           │          │  │         │   │          │           │     │
│     │           │          │  │         │   │ Import   │           │     │
│     │           │          │  │         │   │──────────>           │     │
│     │           │          │  │         │   │          │           │     │
│     │           │          │  │         │   │          │ Unpack    │     │
│     │           │          │  │         │   │          │ advisories│     │
│     │           │          │  │         │   │          │───┐       │     │
│     │           │          │  │         │   │          │   │       │     │
│     │           │          │  │         │   │          │<──┘       │     │
│     │           │          │  │         │   │          │           │     │
│     │           │          │  │         │   │          │ Merge to  │     │
│     │           │          │  │         │   │          │ Concelier │     │
│     │           │          │  │         │   │          │──────────>│     │
│     │           │          │  │         │   │          │           │     │
│     │           │          │  │         │   │          │           │     │
└────────────────────────────────┘         └────────────────────────────────┘

Step-by-Step

1. Advisory Snapshot (Online)

Mirror service creates point-in-time snapshot:

{
  "snapshot_id": "snap-20241229",
  "created_at": "2024-12-29T00:00:00Z",
  "sources": [
    {"name": "nvd", "last_sync": "2024-12-29T00:00:00Z", "count": 245678},
    {"name": "ghsa", "last_sync": "2024-12-28T23:45:00Z", "count": 45678},
    {"name": "osv", "last_sync": "2024-12-28T23:30:00Z", "count": 89012}
  ],
  "delta_from": "snap-20241228",
  "advisories": {
    "new": 127,
    "updated": 456,
    "unchanged": 245095
  }
}

2. Bundle Generation (Online)

EvidenceLocker creates sealed bundle:

{
  "bundle_id": "offline-adv-20241229",
  "bundle_type": "advisory",
  "created_at": "2024-12-29T01:00:00Z",
  "contents": {
    "advisories": {
      "full_count": 245678,
      "delta_count": 583,
      "format": "ndjson.gz"
    },
    "metadata": {
      "sources": ["nvd", "ghsa", "osv"],
      "schema_version": "1.0.0"
    }
  },
  "integrity": {
    "merkle_root": "sha256:abc123...",
    "file_count": 15,
    "total_size": "125 MB"
  }
}

3. Bundle Signing (Online)

Signer creates detached signature:

{
  "bundle_id": "offline-adv-20241229",
  "signature": {
    "algorithm": "ecdsa-p256",
    "keyid": "sha256:offline-signing-key",
    "sig": "base64:signature...",
    "timestamp": "2024-12-29T01:00:00Z"
  },
  "certificate_chain": [
    "base64:signing-cert...",
    "base64:intermediate-ca...",
    "base64:root-ca..."
  ],
  "timestamping": {
    "tsa_url": "https://timestamp.stellaops.io",
    "timestamp_token": "base64:tst..."
  }
}

4. Export Package

Final export package structure:

offline-kit-20241229/
├── manifest.json           # Bundle manifest
├── manifest.sig            # Detached signature
├── advisories/
│   ├── nvd-full.ndjson.gz
│   ├── nvd-delta.ndjson.gz
│   ├── ghsa-full.ndjson.gz
│   └── osv-full.ndjson.gz
├── vex/
│   └── vex-statements.ndjson.gz
├── policies/
│   └── policy-sets.json
├── trust/
│   ├── root-ca.pem
│   └── signing-keys.json
├── merkle/
│   └── tree.json
├── verify.sh               # Verification script
└── README.md

5. Secure Transfer

Transfer via approved mechanism:

  • USB drive (encrypted)
  • Optical media (write-once)
  • Data diode (one-way network)
  • Secure courier

6. Import Verification (Offline)

AirGap Importer verifies bundle:

# Run verification
stellaops-airgap verify /media/usb/offline-kit-20241229/

# Verification steps:
✓ Manifest signature valid
✓ Certificate chain verified (trust anchor: sha256:root-ca)
✓ Timestamp verified (within 7 day window)
✓ Merkle root matches: sha256:abc123...
✓ All 15 files verified against Merkle tree
✓ No tamper detected

Bundle verified successfully. Ready for import.

7. Time Anchor Verification (Offline)

Verify bundle freshness without network time:

{
  "time_verification": {
    "bundle_timestamp": "2024-12-29T01:00:00Z",
    "tsa_timestamp": "2024-12-29T01:00:05Z",
    "local_time_anchor": "2024-12-29T10:00:00Z",
    "max_age_policy": "7d",
    "age": "9h",
    "status": "FRESH"
  }
}

8. Advisory Import (Offline)

AirGap Importer loads advisories into Concelier:

{
  "import_id": "import-20241229-001",
  "bundle_id": "offline-adv-20241229",
  "started_at": "2024-12-29T10:30:00Z",
  "completed_at": "2024-12-29T10:35:00Z",
  "results": {
    "advisories_imported": 583,
    "advisories_updated": 456,
    "advisories_new": 127,
    "conflicts_resolved": 0,
    "errors": 0
  },
  "state": {
    "previous_snapshot": "snap-20241228",
    "current_snapshot": "snap-20241229"
  }
}

Bundle Freshness Policies

Strict (High Security)

freshness_policy:
  mode: strict
  max_age:
    advisory: 24h
    vex: 24h
    policy: 7d
    trust: 30d
  require_tsa: true
  reject_stale: true

Standard

freshness_policy:
  mode: standard
  max_age:
    advisory: 7d
    vex: 7d
    policy: 30d
    trust: 90d
  require_tsa: false
  warn_stale: true

Permissive (Disconnected Operations)

freshness_policy:
  mode: permissive
  max_age:
    advisory: 30d
    vex: 30d
    policy: 90d
    trust: 365d
  require_tsa: false
  warn_stale: true
  allow_manual_override: true

Data Contracts

Bundle Manifest Schema

interface OfflineBundle {
  bundle_id: string;
  bundle_type: 'advisory' | 'vex' | 'policy' | 'trust' | 'time_anchor';
  version: string;
  created_at: string;
  created_by: string;
  contents: {
    files: Array<{
      path: string;
      size: number;
      sha256: string;
    }>;
    metadata: Record<string, unknown>;
  };
  integrity: {
    merkle_root: string;
    algorithm: 'sha256';
    tree_path: string;
  };
  signature: {
    keyid: string;
    algorithm: string;
    sig: string;
  };
  freshness: {
    timestamp: string;
    tsa_timestamp?: string;
    valid_until?: string;
  };
}

Import Result Schema

interface ImportResult {
  import_id: string;
  bundle_id: string;
  status: 'success' | 'partial' | 'failed';
  started_at: string;
  completed_at: string;
  results: {
    records_imported: number;
    records_updated: number;
    records_new: number;
    conflicts: number;
    errors: number;
  };
  verification: {
    signature_valid: boolean;
    merkle_verified: boolean;
    freshness_check: 'FRESH' | 'STALE' | 'EXPIRED';
  };
  audit_log_entry: string;
}

Scheduling Strategies

Daily Sync

offline_sync:
  advisory_bundle:
    schedule: "0 1 * * *"  # Daily at 1 AM
    type: delta
    retention: 7
  vex_bundle:
    schedule: "0 2 * * *"  # Daily at 2 AM
    type: delta
    retention: 7

Weekly Full + Daily Delta

offline_sync:
  advisory_bundle:
    full:
      schedule: "0 0 * * SUN"  # Weekly full on Sunday
      retention: 4
    delta:
      schedule: "0 1 * * MON-SAT"  # Daily delta Mon-Sat
      retention: 7

Error Handling

Error Recovery
Signature invalid Reject bundle, alert admin
Merkle verification failed Reject bundle, request retransfer
Bundle too old Warn user, require override
Import conflict Log conflict, apply latest
Disk space insufficient Cleanup old imports, retry

Observability

Metrics (Online)

Metric Type Labels
offline_bundle_created_total Counter type
offline_bundle_size_bytes Histogram type
offline_bundle_advisory_count Gauge bundle_id

Metrics (Offline)

Metric Type Labels
offline_import_total Counter status, type
offline_bundle_age_hours Gauge bundle_id
offline_advisory_freshness_hours Gauge -

Key Log Events

Event Level Fields
offline.bundle.created INFO bundle_id, type, size
offline.bundle.verified INFO bundle_id, verifier
offline.import.started INFO import_id, bundle_id
offline.import.complete INFO import_id, records
offline.freshness.warning WARN bundle_id, age