349 lines
10 KiB
Markdown
349 lines
10 KiB
Markdown
# component_architecture_airgap.md - **Stella Ops AirGap** (2025Q4)
|
|
|
|
> Air-gapped deployment controller, importer, and time anchor services.
|
|
|
|
> **Scope.** Implementation-ready architecture for **AirGap**: the controller, importer, and time anchor subsystems enabling StellaOps operation in disconnected/air-gapped environments with sealed-mode state management.
|
|
|
|
---
|
|
|
|
## 0) Mission & boundaries
|
|
|
|
**Mission.** Enable **fully offline, air-gapped operation** of StellaOps with sealed-mode state management, bundle-based updates, and cryptographic time anchors for staleness detection.
|
|
|
|
**Boundaries.**
|
|
|
|
* AirGap **does not** connect to external networks in sealed mode.
|
|
* AirGap **does not** generate vulnerability data. It imports pre-packaged bundles.
|
|
* Bundle verification is **mandatory**. Unsigned or tampered bundles are rejected.
|
|
* Time anchors are **cryptographically verified** using Roughtime or RFC3161.
|
|
|
|
---
|
|
|
|
## 1) Solution & project layout
|
|
|
|
```
|
|
src/AirGap/
|
|
├─ StellaOps.AirGap.Controller/ # Seal/unseal state machine, status APIs
|
|
│ ├─ Services/
|
|
│ │ ├─ ISealingController.cs # Sealing state interface
|
|
│ │ ├─ SealingController.cs # State machine implementation
|
|
│ │ └─ StatusService.cs # Health and status endpoints
|
|
│ └─ Models/
|
|
│ ├─ SealState.cs # sealed | unsealed | transitioning
|
|
│ └─ SealTransition.cs # Transition metadata
|
|
│
|
|
├─ StellaOps.AirGap.Importer/ # Bundle verification and import
|
|
│ ├─ Services/
|
|
│ │ ├─ IBundleVerifier.cs # DSSE/TUF verification
|
|
│ │ ├─ BundleVerifier.cs # Verification implementation
|
|
│ │ ├─ ICatalogImporter.cs # Catalog update interface
|
|
│ │ └─ CatalogImporter.cs # Import orchestration
|
|
│ └─ Models/
|
|
│ ├─ ImportBundle.cs # Bundle metadata
|
|
│ └─ ImportResult.cs # Import outcome
|
|
│
|
|
├─ StellaOps.AirGap.Time/ # Time anchor verification
|
|
│ ├─ Services/
|
|
│ │ ├─ ITimeAnchorService.cs # Time anchor interface
|
|
│ │ ├─ RoughtimeAnchor.cs # Roughtime implementation
|
|
│ │ └─ Rfc3161Anchor.cs # RFC3161 timestamp
|
|
│ └─ Models/
|
|
│ ├─ TimeAnchor.cs # Anchor record
|
|
│ └─ StalenessResult.cs # Staleness calculation
|
|
│
|
|
├─ StellaOps.AirGap.Policy/ # Air-gap specific policy rules
|
|
│ ├─ StellaOps.AirGap.Policy/
|
|
│ ├─ StellaOps.AirGap.Policy.Analyzers/
|
|
│ └─ StellaOps.AirGap.Policy.Tests/
|
|
│
|
|
├─ __Libraries/
|
|
│ ├─ StellaOps.AirGap.Bundle/ # Bundle format and parsing
|
|
│ └─ StellaOps.AirGap.Persistence/ # State persistence
|
|
│
|
|
├─ __Tests/ # Test projects
|
|
│
|
|
├─ scripts/ # Operational scripts
|
|
│
|
|
└─ AGENTS.md # Guild charter
|
|
```
|
|
|
|
---
|
|
|
|
## 2) External dependencies
|
|
|
|
* **PostgreSQL** - State persistence, import history
|
|
* **Authority** - Scope enforcement (`airgap:seal`, `airgap:status:read`)
|
|
* **Cryptography** - Bundle signature verification
|
|
* **Object storage** - Bundle staging and quarantine
|
|
|
|
---
|
|
|
|
## 3) Contracts & data model
|
|
|
|
### 3.1 Seal State
|
|
|
|
```csharp
|
|
public enum SealState
|
|
{
|
|
Unsealed, // Normal operation, network allowed
|
|
Transitioning, // Sealing or unsealing in progress
|
|
Sealed // Air-gapped, no network egress
|
|
}
|
|
|
|
public sealed record SealStatus
|
|
{
|
|
public required SealState State { get; init; }
|
|
public required DateTimeOffset LastTransition { get; init; }
|
|
public required string TransitionedBy { get; init; }
|
|
public DateTimeOffset? SealedSince { get; init; }
|
|
public TimeAnchor? LastTimeAnchor { get; init; }
|
|
}
|
|
```
|
|
|
|
### 3.2 Import Bundle
|
|
|
|
```json
|
|
{
|
|
"bundleId": "airgap-2025-01-15-abc123",
|
|
"bundleType": "advisory-update",
|
|
"version": "2025.01.15.001",
|
|
"createdAt": "2025-01-15T10:30:00Z",
|
|
"contents": [
|
|
{
|
|
"type": "concelier-snapshot",
|
|
"digest": "sha256:abc123...",
|
|
"path": "data/concelier-2025-01-15.tar.zst"
|
|
},
|
|
{
|
|
"type": "trivy-db",
|
|
"digest": "sha256:def456...",
|
|
"path": "data/trivy-db-2025-01-15.tar.gz"
|
|
}
|
|
],
|
|
"signature": {
|
|
"keyId": "sha256:sigkey...",
|
|
"algorithm": "ecdsa-p256",
|
|
"value": "base64..."
|
|
},
|
|
"timeAnchor": {
|
|
"source": "roughtime",
|
|
"timestamp": "2025-01-15T10:25:00Z",
|
|
"proof": "base64..."
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3.3 Time Anchor
|
|
|
|
```csharp
|
|
public sealed record TimeAnchor
|
|
{
|
|
public required string Source { get; init; } // roughtime, rfc3161
|
|
public required DateTimeOffset Timestamp { get; init; }
|
|
public required byte[] Proof { get; init; } // Cryptographic proof
|
|
public required string[] Servers { get; init; } // Servers used
|
|
public required bool Verified { get; init; }
|
|
}
|
|
|
|
public sealed record StalenessResult
|
|
{
|
|
public required TimeSpan Age { get; init; }
|
|
public required bool IsStale { get; init; }
|
|
public required TimeSpan StalenessThreshold { get; init; }
|
|
public string? Warning { get; init; }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4) REST API (Controller + Importer)
|
|
|
|
All under `/api/v1/airgap`. Auth: **OpTok** with airgap scopes.
|
|
|
|
### Controller APIs
|
|
|
|
```
|
|
GET /status → { state, lastTransition, timeAnchor }
|
|
POST /seal → { transitionId, status: "transitioning" }
|
|
POST /unseal → { transitionId, status: "transitioning" }
|
|
GET /transitions/{id} → { transition details }
|
|
```
|
|
|
|
### Importer APIs
|
|
|
|
```
|
|
POST /bundles/upload multipart → { bundleId, status: "pending" }
|
|
POST /bundles/{id}/verify → { valid: bool, details }
|
|
POST /bundles/{id}/import → { importId, status: "importing" }
|
|
GET /bundles/{id}/status → { status, progress, errors }
|
|
GET /bundles → { bundles: BundleSummary[] }
|
|
```
|
|
|
|
### Time APIs
|
|
|
|
```
|
|
GET /time/anchor → { anchor: TimeAnchor, staleness }
|
|
POST /time/anchor { source, proof } → { anchor, verified }
|
|
GET /time/staleness → { staleness: StalenessResult }
|
|
```
|
|
|
|
---
|
|
|
|
## 5) Configuration (YAML)
|
|
|
|
```yaml
|
|
AirGap:
|
|
Controller:
|
|
InitialState: "unsealed"
|
|
TransitionTimeoutSeconds: 300
|
|
RequireApproval: true
|
|
|
|
Importer:
|
|
StagingPath: "/data/airgap/staging"
|
|
QuarantinePath: "/data/airgap/quarantine"
|
|
MaxBundleSizeMb: 10240
|
|
TrustRoots:
|
|
- "sha256:abc123..." # StellaOps signing key
|
|
AllowedBundleTypes:
|
|
- "advisory-update"
|
|
- "trivy-db"
|
|
- "policy-pack"
|
|
|
|
Time:
|
|
StalenessThresholdHours: 168 # 7 days
|
|
RoughtimeServers:
|
|
- "roughtime.cloudflare.com"
|
|
- "roughtime.google.com"
|
|
Rfc3161Servers:
|
|
- "http://timestamp.digicert.com"
|
|
RequireMultipleServers: true
|
|
MinServerQuorum: 2
|
|
|
|
Quarantine:
|
|
TtlDays: 30
|
|
MaxQuotaMb: 51200
|
|
|
|
Postgres:
|
|
ConnectionString: "Host=postgres;Database=airgap;..."
|
|
```
|
|
|
|
---
|
|
|
|
## 6) Sealing State Machine
|
|
|
|
```
|
|
┌──────────────┐
|
|
│ Unsealed │
|
|
└──────┬───────┘
|
|
│ seal()
|
|
▼
|
|
┌──────────────┐
|
|
│ Transitioning│
|
|
└──────┬───────┘
|
|
│ complete
|
|
▼
|
|
┌──────────────┐
|
|
│ Sealed │
|
|
└──────┬───────┘
|
|
│ unseal()
|
|
▼
|
|
┌──────────────┐
|
|
│ Transitioning│
|
|
└──────┬───────┘
|
|
│ complete
|
|
▼
|
|
┌──────────────┐
|
|
│ Unsealed │
|
|
└──────────────┘
|
|
```
|
|
|
|
### Transition Actions
|
|
|
|
**Seal transition:**
|
|
1. Verify pending work is complete
|
|
2. Capture final time anchor
|
|
3. Disable network egress
|
|
4. Update state to Sealed
|
|
|
|
**Unseal transition:**
|
|
1. Verify network connectivity
|
|
2. Refresh time anchor
|
|
3. Enable network egress
|
|
4. Update state to Unsealed
|
|
|
|
---
|
|
|
|
## 7) Bundle Import Flow
|
|
|
|
```
|
|
1. Upload bundle to staging
|
|
└─ Validate manifest structure
|
|
|
|
2. Verify bundle
|
|
├─ Check signature against trust roots
|
|
├─ Verify content digests
|
|
└─ Validate time anchor
|
|
|
|
3. Import bundle
|
|
├─ Extract contents
|
|
├─ Update target catalogs (Concelier, Trivy, etc.)
|
|
└─ Record import in history
|
|
|
|
4. Cleanup or quarantine
|
|
├─ Success: Remove from staging
|
|
└─ Failure: Move to quarantine with TTL
|
|
```
|
|
|
|
---
|
|
|
|
## 8) Security & compliance
|
|
|
|
* **Signature verification**: All bundles must be signed
|
|
* **Trust roots**: Configurable trust root keys
|
|
* **Quarantine**: Failed imports isolated with TTL
|
|
* **Audit trail**: All imports and state changes logged
|
|
* **Scope enforcement**: Authority scopes for all operations
|
|
* **Rollback prevention**: Version monotonicity enforced
|
|
|
|
---
|
|
|
|
## 9) Performance targets
|
|
|
|
* **Seal/unseal transition**: < 30s
|
|
* **Bundle verification**: < 10s for 1GB bundle
|
|
* **Bundle import**: < 60s for typical advisory update
|
|
* **Time anchor verification**: < 5s
|
|
|
|
---
|
|
|
|
## 10) Observability
|
|
|
|
**Metrics:**
|
|
* `airgap.state{state=sealed|unsealed|transitioning}`
|
|
* `airgap.bundles.imported_total{type,result}`
|
|
* `airgap.bundles.quarantined_total{reason}`
|
|
* `airgap.time.staleness_seconds`
|
|
* `airgap.time.anchor_age_seconds`
|
|
|
|
**Tracing:** Spans for transitions, imports, verifications.
|
|
|
|
---
|
|
|
|
## 11) Testing matrix
|
|
|
|
* **Seal/unseal tests**: State machine transitions
|
|
* **Bundle tests**: Verification and import flows
|
|
* **Quarantine tests**: Failed import handling
|
|
* **Time tests**: Staleness calculations, anchor verification
|
|
* **Integration tests**: Full offline workflow simulation
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
* Evidence reconciliation: `./evidence-reconciliation.md`
|
|
* Exporter coordination: `./exporter-cli-coordination.md`
|
|
* Mirror DSSE plan: `./mirror-dsse-plan.md`
|
|
* Offline Kit: `../../24_OFFLINE_KIT.md`
|
|
* Time anchor schema: `../../airgap/time-anchor-schema.md`
|