Skip to content

feat: compartmentalized need-to-know configs — PCR policy matrix per mission compartment (ALPHA/BRAVO/CHARLIE) #37

Description

@nielsweistra

Problem

All mission machines currently receive configs encrypted with the same PCR policy. A captured node at any sensitivity level can attempt to decrypt configs intended for higher-classification nodes — there is no cryptographic separation between compartments.

Solution — Compartmentalized Need-to-Know Configs

Each machine is assigned a compartment level. Config delivery gates on matching the compartment's PCR policy — a BRAVO node cannot decrypt an ALPHA config even with a valid EK.

Compartment Model

# models/compartment.py
class CompartmentLevel(str, Enum):
    ALPHA   = "ALPHA"    # highest — PCR[0,1,2,3,7] required
    BRAVO   = "BRAVO"    # standard mission — PCR[0,7]
    CHARLIE = "CHARLIE"  # logistics/support — PCR[7] only

class MissionCompartment(Base):
    id: uuid
    mission_id: uuid
    level: CompartmentLevel
    pcr_policy_mask: list[int]      # PCR indices required
    hmac_policy: str                # policy digest (hex)
    description: str | None
# models/machine.py
class MachineRow(Base):
    ...
    compartment_id: uuid | None  # FK → MissionCompartment

Config Delivery Gate

# handlers/config_delivery.py
async def encrypt_config_for_machine(machine: MachineRow, config: dict) -> bytes:
    compartment = await get_compartment(machine.compartment_id)
    pcr_policy = build_pcr_policy(compartment.pcr_policy_mask)
    # AES-256-GCM key wrapped with TPM2 PolicyPCR (existing mechanism)
    # Gate: TPM will only unseal if ALL required PCRs match
    return encrypt_with_pcr_policy(config, pcr_policy, machine.ek_pub)

Assignment

POST /api/v1/machines/{id}/compartment
{ "compartment_id": "uuid" }

Requires itl-cell-admin role.

MITRE ATT&CK

  • T1078 — Valid Accounts (mitigated: captured node cannot escalate compartment)
  • T1552 — Unsecured Credentials (mitigated: cross-compartment key access blocked)

Files

  • New: models/compartment.py
  • New: handlers/compartment_policy.py
  • New: routers/compartment.py — CRUD for MissionCompartment
  • Extend: handlers/config_delivery.py — PCR policy per compartment
  • Extend: models/machine.py — add compartment_id FK
  • Alembic migration: add_mission_compartment_table

Acceptance Criteria

  • ALPHA config fails to decrypt on BRAVO hardware (wrong PCR policy → TPM rejects)
  • Machine without compartment gets default CHARLIE policy
  • Compartment assignment requires admin role
  • PCR policy digest stored and auditable
  • Test: ALPHA config + BRAVO PCR state → decryption fails; ALPHA config + ALPHA PCR state → succeeds
  • GET /api/v1/missions/{id}/compartments lists all compartments for a mission

Metadata

Metadata

Assignees

No one assigned

    Labels

    effort:13Effort score 13 (Fibonacci)impact:5Impact score 5 (Fibonacci)military-gradesecuritySecurity vulnerability or hardeningtype:storyUser story -- a piece of deliverable value

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions