Skip to content

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 modevault, 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 local mode. 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 for local-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.