Skip to content

Volume Shield Configuration Reference

All Volume Shield behavior is controlled by PVC annotations (per-volume) and Helm values (cluster-wide). Component version strings below refer to wrapper v0.2.207 / chart 1.0.359.

PVC annotations

Annotation Values Default Description
cloudtaser.io/encrypt-pvc "true" — Enables Volume Shield for this PVC. Read at pod admission time.
cloudtaser.io/pvc-chunk-size-kb integer KiB 64 Encryption chunk size. Larger chunks reduce per-chunk overhead but increase the minimum read-modify-write granularity. Choose once, before first write.
cloudtaser.io/vs-io-mode cached | strict cached Per-PVC I/O mode, see below. Invalid values fail closed to cached.
cloudtaser.io/vs-freshness vault | secretstore inherit cluster default (vault, since the 2026-07-06 default flip) Per-PVC trusted-freshness selection. vault is the default at both cluster and PVC level — see upgrade cohorts and the TOFU window for what that means for pre-existing volumes. Trusted freshness is mandatory: the wrapper refuses local, disabled and off at mount setup, so there is no per-PVC opt-out. See unsupported workloads. Invalid values fail closed to vault.
cloudtaser.io/pvc-transit-key key name — Reserved for Vault Transit envelope encryption (not yet active).

I/O modes: cached vs strict

cached (default) strict
Kernel page cache Active (write-through) Bypassed (FOPEN_DIRECT_IO per file)
mmap(MAP_SHARED) Works Fails with ENODEV
Plaintext residency Decrypted pages may reside in the kernel page cache while the file is in use No plaintext page-cache residency beyond the active I/O
Suitable for SQLite/WAL, Postgres, Cassandra, LMDB — anything that mmaps or relies on page-cache performance Workloads that never mmap, under regulatory policy requiring zero page-cache plaintext

Do not set strict for mmap-dependent workloads

strict intentionally breaks mmap(MAP_SHARED). Databases that memory-map their files (most of them) will fail to start. The default is cached for this reason; measure before switching.

The annotation is per-PVC, so a pod can mix modes — e.g. strict for a compliance-scoped volume and cached for a WAL volume in the same pod.

Helm values

volumeShield:
  enabled: false            # master switch
  nonceBudget:
    mode: ""                # "" (process-local) | "vault" | "secretstore"
    leaseSize: 1048576      # GCM seal invocations reserved per lease
    leaseTimeout: "10s"
  freshness:
    mode: "vault"           # "vault" (default) | "secretstore" (alias). "local" is refused by the wrapper
    timeout: "10s"
  broker:
    mode: "fdpass"          # "fdpass" (default) | "serve" (legacy)
    daemonset:
      enabled: false        # per-node DaemonSet (recommended)
    image:
      repository: europe-west4-docker.pkg.dev/skipopsmain/cloudtaser/cloudtaser-wrapper
      tag: ""               # REQUIRED — wrapper release tag
    healthPort: 8081        # HTTPS kubelet probes
    vaultAddr: ""           # REQUIRED with daemonset.enabled=true
    vaultRole: "cloudtaser-vs-broker"
    vaultCACert: ""
    audienceScopedToken:
      enabled: false
      audience: "cloudtaser-vs-broker"
      expirationSeconds: 3600
  sidecar:
    image:
      repository: europe-west4-docker.pkg.dev/skipopsmain/cloudtaser/cloudtaser-wrapper
      tag: ""               # REQUIRED — wrapper release tag
    healthPort: 8082        # must differ from broker.healthPort

Nonce budget (volumeShield.nonceBudget)

AES-GCM with random nonces is bounded by NIST SP 800-38D to 2³² seal operations per key. Volume Shield always enforces this bound in-process and fails closed at exhaustion (warns at 2³¹).

  • mode: "" (default) — the counter is process-local. A remount resets it while the DEK is unchanged, so the cumulative cross-session count is not bounded.
  • mode: "vault" — the sidecar reserves high-water leases in OpenBao KV v2 (cloudtaser/data/volumeshield-state/<namespace>/<pvc-uid>). Remounts continue from the trusted high-water mark; crashes can waste leased invocations but never reuse them. A DEK change starts a fresh epoch.

leaseSize trades vault round-trips against waste on crash: each lease is one vault CAS write per leaseSize encrypted chunks.

No automatic DEK rotation yet

Trusted leasing accounts for nonce use; it does not rotate the DEK before exhaustion. Rotation currently requires re-encrypting the volume under a new DEK.

Trusted freshness (volumeShield.freshness)

Default flipped 2026-07-06

vault mode is now the default, cluster-wide and per-PVC. Previously the default was disabled (chunk-level integrity only, no rollback/replay detection). The safe rollout path for that flip — volume-scoped baseline gating — is what the upgrade cohorts below describe.

  • mode: "vault" (default) — every decrypt verifies the exact ciphertext bytes against per-file digests in OpenBao (.../files/<sha256(relpath)>); every successful mutation commits a new digest; unlink/rename tombstone old paths. Missing state, tombstones, digest mismatch, DEK-epoch mismatch, and unauthenticated plaintext all fail closed — subject to the TOFU window described below for volumes upgrading into the default.
  • mode: "secretstore" — the secretstore-branded alias of vault.
  • mode: "local" — refused. Current wrapper releases reject local, disabled, off and similar values when the mount is set up, because trusted freshness is mandatory. Do not set it cluster-wide or per PVC: the volume will fail to mount rather than run without rollback detection.

Upgrade cohorts and the TOFU window

The moment freshness.mode resolves to vault for a volume — by default, or by explicit configuration — that volume falls into exactly one of three cohorts:

Cohort Condition Behavior
Already tracked Volume already has freshness state in vault (was already running freshness.mode: vault) Strict immediately. Fail-closed on missing state, unchanged from before the default flip — zero behavior change for existing vault-mode users.
New Volume is empty at first mount Strict from birth. Every file gets trusted state the moment it's written; nothing is ever "old" without state.
Upgrade cohort Volume is populated but has no freshness state (e.g. a volume written before trusted freshness was the default) Trust-on-first-use (TOFU) window. Files bearing a valid CTVS header are baselined into vault on first verify, each baseline logged at WARN and counted by cloudtaser_vs_freshness_baselined_files_total{pvc_uid,namespace}. The window closes only when an operator runs the graduation migration.

TOFU window security meaning — precise boundary

During the TOFU window, and only for the upgrade cohort:

  • Not yet protected: replay of authentic, same-volume ciphertext at a path that has never been baselined — an attacker holding legitimately-encrypted bytes from elsewhere on the same volume can plant them at an unbaselined path and have them accepted as that path's first version.
  • Unchanged, still protected: plaintext or header-stripped injection stays blocked — the not-encrypted/bad-header check runs before any freshness state lookup, so it is never gated by baseline status. Tombstoned (deleted) paths stay tombstoned. Any path already baselined — including everything baselined earlier in the same window — gets full rollback/replay detection from that point forward.

This is why the default-on rollout is TOFU-then-graduate rather than either an indefinite reduced-security default or a hard break on upgrade.

Run the migration entrypoint (see graduating from the TOFU window) to close the window on a volume: it walks every file, baselines anything not yet tracked, and flips the volume to strict once the walk completes with zero errors.

Unsupported workloads

Trusted freshness cannot be switched off, and two common I/O patterns are incompatible with it. These workloads are not supported on Volume Shield volumes for now:

  • Directory-rename-as-commit workloads — ClickHouse part commits, Prometheus TSDB compaction, VictoriaMetrics, and other time-series or columnar stores that commit by renaming a directory — receive EXDEV on subtree renames.
  • Hardlink-based snapshot workloads — e.g. Cassandra nodetool snapshot — receive EOPNOTSUPP on hard-link creation.

Do not place TSDB, ClickHouse or hardlink-snapshot data on a Volume Shield PVC. Keep it on a volume that Volume Shield does not manage. See the troubleshooting symptom table for both errors.

Operational notes for vault mode:

  • Directory renames return EXDEV (moving a subtree would need a multi-file trusted-state transaction). EXDEV makes mv, Python shutil.move, Java NIO Files.move (without ATOMIC_MOVE), and Kafka's move-with-fallback degrade to copy+delete automatically, with every copied file tracked by freshness. Workloads that REQUIRE atomic directory renames or hard links are unsupported (see above). File renames work natively.
  • Each verified read/committed write adds a vault round-trip — budget for the latency on hot paths.

Broker mode (volumeShield.broker.mode)

  • fdpass (default) — privilege-separated: broker mounts, unprivileged sidecar serves and holds the DEK. Use this.
  • serve — legacy: the broker both mounts and serves FUSE, holding DEKs in the per-node privileged process. Retained for backward compatibility only.

Environment variables (advanced)

These are set by the operator/chart; listed for debugging and non-Helm installs.

Variable Component Purpose
CLOUDTASER_VOLUME_SHIELD_ENABLED wrapper Master gate, set to true by webhook
CLOUDTASER_VOLUME_SHIELD_MOUNTS wrapper, sidecar JSON mount descriptor list (all encrypted PVCs of the pod, including per-mount io_mode)
CLOUDTASER_VS_BROKER_SOCK wrapper Broker Unix socket (hostPath)
CLOUDTASER_VS_BROKER_MODE wrapper fdpass when a sidecar is injected
CLOUDTASER_VS_SIDECAR_SOCK sidecar, broker fd-pass Unix socket
CLOUDTASER_VS_STRICT_MODE sidecar Process-wide strict-mode fallback; per-mount io_mode takes precedence
CLOUDTASER_VS_NONCE_BUDGET / CLOUDTASER_VS_NONCE_LEASE_SIZE / CLOUDTASER_VS_NONCE_LEASE_TIMEOUT sidecar Trusted nonce leasing
CLOUDTASER_VS_FRESHNESS / CLOUDTASER_VS_FRESHNESS_TIMEOUT sidecar Trusted freshness

Choosing a production posture

Posture Settings Protects against
Baseline volumeShield.enabled=true (freshness defaults to vault) CSP reading disks/snapshots/backups; in-flight tamper (swap/reorder/bitflip/truncate); rollback/replay and header-strip plaintext injection — immediately for new/already-tracked volumes, after the TOFU window + graduation migration for pre-existing populated volumes (see upgrade cohorts)
Recommended + nonceBudget.mode: vault + cross-remount nonce exhaustion accounting
Maximum + vs-io-mode: strict on compliance-scoped PVCs + plaintext page-cache residency (at the cost of mmap)