Volume Shield Threat Model & Boundaries¶
This page states precisely what Volume Shield protects, under which configuration, and — equally important — what it does not protect. Claims here are deliberately conservative; treat anything not listed as unprotected.
Protected: the storage-layer adversary¶
Volume Shield's design adversary is anyone who can read (or subpoena) the storage medium underneath your PVCs without going through your running pods:
| Scenario | Outcome with Volume Shield |
|---|---|
| Cloud provider staff or tooling reads the PV's backing disk | Ciphertext only (CTVS/AES-256-GCM); DEK is in EU vault + sidecar memory, never on CSP infrastructure |
| Legal compulsion (CLOUD Act / FISA) directed at the cloud provider for stored volume data | Provider can hand over ciphertext and cannot produce the key — the DEK never touches provider-controlled storage, disk, etcd, or Kubernetes Secrets |
| Volume snapshots, backups, replication streams, decommissioned disks | All derived from the backing store — ciphertext only |
| Storage-layer tampering: chunk swap, reorder, splice, bit-flip, tail truncation | Detected by CTVS v3 chunk AAD (fileID ‖ chunk_index ‖ version ‖ total_chunks); reads fail with EIO instead of returning tampered bytes |
With trusted freshness mode — vault, the default for every volume since the founder's 2026-07-06 decision (roadmap#197; see configuration) — two further storage-layer attacks are closed:
| Scenario | Outcome with freshness = vault |
|---|---|
| Rollback/replay: restoring an older, correctly-encrypted snapshot of a chunk, file, or the whole volume | Detected once the path carries trusted state — immediately for new and already-tracked volumes; after the TOFU window closes (graduation migration) for pre-existing populated volumes upgrading into the default |
| Header-strip plaintext injection: replacing an encrypted file with attacker-chosen plaintext so the legacy-plaintext passthrough serves it | Detected unconditionally, including during any volume's TOFU window — the not-encrypted/bad-header check runs before any freshness state lookup |
TOFU window: the one default-on exception, precisely bounded
Populated volumes with no prior freshness state (the "upgrade cohort" — see upgrade cohorts) get a trust-on-first-use window: the first time each file is verified, its current ciphertext is accepted and baselined (logged at WARN, counted by cloudtaser_vs_freshness_baselined_files_total). Until an operator runs the graduation migration, an attacker holding legitimately-encrypted ciphertext from elsewhere on the same volume can plant it at a path that has not yet been baselined and have it accepted as that path's first version. This does not extend to plaintext or header-stripped substitution (blocked unconditionally, per the table above), to paths already baselined (fully protected from that point on), or to tombstoned/deleted paths (stay tombstoned). Volumes opted out via local mode get none of this protection, indefinitely — that is a standing configuration choice, not a TOFU gap.
NOT protected: read the boundaries carefully¶
Compromised application code in the pod¶
Volume Shield presents a transparent plaintext view to the workload — that is its purpose. Any code running inside the pod (the application itself, a supply-chain-compromised library, an attacker with kubectl exec into the app container) reads plaintext through the mount exactly like the application does. Volume Shield is storage-layer encryption, not in-pod runtime protection. In-pod hardening is provided by the separate eBPF enforcement layer and standard workload security practice.
Snapshot rollback on opted-out (local mode) volumes¶
vault mode is the default since 2026-07-06 (roadmap#197); local is now an explicit, deliberate opt-out (per-PVC annotation or cluster-wide Helm value) rather than the default. On a local-mode volume, an adversary with write access to the backing medium can restore an older ciphertext state — it authenticates perfectly because it was genuine — indefinitely, with no TOFU-style narrowing over time. Whole-volume rollback to a previous snapshot is likewise silent, and so is the plaintext-injection variant described above. local exists for workloads whose I/O pattern is incompatible with per-path freshness state (directory-rename-as-commit, hardlink-based snapshots — see the configuration reference); choosing it is choosing to carry this exposure permanently for that volume, not a transitional state like the TOFU window described above.
mmap residual window in cached mode¶
In the default cached I/O mode, decrypted file pages live in the kernel page cache while in use. That plaintext exists in node RAM (not on the CSP-readable medium) but could be captured by an adversary with live kernel-memory access on the node — e.g. hypervisor memory inspection on non-confidential VMs. strict mode removes page-cache residency at the cost of mmap; hypervisor-level exposure of the sidecar's own working memory is addressed by confidential compute nodes, not by Volume Shield.
Metadata¶
File names, sizes (approximate), directory structure, timestamps, and access patterns are not encrypted. An adversary reading the backing store learns the shape of your data, not its content.
Availability¶
Volume Shield fails closed. An adversary who corrupts ciphertext or (in freshness mode) vault state can deny access to data — reads return EIO by design. Fail-closed is the correct trade for a sovereignty product; plan backups accordingly (and note that backups of the raw store are ciphertext, which is what you want).
Key custody chain¶
EU OpenBao (KV v2: cloudtaser/volumes/<ns>/<pvc-uid>)
│ TLS via port/beacon — outbound-only from EU side
▼
vs-sidecar process memory (CapEff=0, in workload pod)
│ zeroed immediately after AES cipher init
▼
per-chunk AES-256-GCM on the raw PVC (ciphertext at rest)
Never present: cloud provider storage, etcd, Kubernetes Secrets, Helm release state, the broker DaemonSet, node disk, workload container images.
Privilege separation guarantees¶
| Component | Capability set | Key access | Rationale |
|---|---|---|---|
| vs-broker (DaemonSet) | privileged | none | Owns /dev/fuse + mount(2) only; passes fds, never keys |
| vs-sidecar | CapEff=0, non-root, read-only rootfs, seccomp RuntimeDefault | DEK in memory | Kernel doesn't recheck capabilities on an SCM_RIGHTS-received fd |
| fd-pass socket | — | carries fd + non-secret identifiers only | fds tagged for a foreign pod or unknown PVC are closed, never served |
A compromised broker can deny service (it owns mounts) but cannot decrypt. A compromised sidecar exposes only the DEKs of that single pod's PVCs — per-pod, per-PVC key isolation bounds the blast radius.
Claim discipline¶
When describing Volume Shield externally, claim only:
- "Tamper detection (swap/reorder/truncate/bitflip)" — for CTVS v3 files.
- "Rollback/replay and plaintext-injection detection" — by default, for any volume not explicitly opted out via
localmode. Plaintext-injection detection is unconditional. Rollback/replay detection is unconditional for new and already-tracked volumes, and bounded by the TOFU window (see above) for pre-existing populated volumes until an operator runs the graduation migration. Never claim rollback/replay detection forlocal-mode volumes — that opt-out has none, permanently. - "Lifetime nonce accounting" — only with trusted nonce leasing enabled.
- Never claim in-pod runtime protection, metadata confidentiality, or automatic DEK rotation.