See cloudtaser running.
EU/UK data sovereignty for US cloud workloads. You keep the keys. The provider never sees plaintext — not on request, not under the CLOUD Act, not under court order.
Demo options
Three live terminals stream real output from three real systems: a managed GKE cluster in the US (n2d nodes with AMD SEV, the install target) and two EU-hosted VMs running cloudtaser's P2P beacon relay (FRA) and OpenBao secret store (NL). Click through and you'll see the actual cryptographic work end-to-end — no mocks. When someone is running the demo, you watch their steps in real time. When they finish or step away, it is your turn.
Demo improvements in progress
We are upgrading the live demo environment. Check back shortly, or schedule a guided walkthrough with an engineer.
abc1d234-5678-…
What you just saw: a live K8s cluster with an eBPF-enforced secret store. No secret ever touched etcd, a K8s Secret object, or disk. The cloud provider had no path to plaintext. If that landed, the engineering details are below — or talk to us now.
How this actually works (engineering deep dive)
Three official endpoints
https://demo.cloudtaser.io/api/demo/stream?channel=clusterSSE, cluster output
https://demo.cloudtaser.io/api/demo/stream?channel=beaconSSE, beacon log
https://demo.cloudtaser.io/api/demo/stream?channel=vaultSSE, OpenBao audit
https://demo.cloudtaser.io/api/*orchestrator: state, next, probe
| Role | What runs here | Region & cost |
|---|---|---|
| US GKE Cluster | zonal GKE (free control plane) · 1 × n2d-highcpu-2 · AMD SEV · 30 GB pd-balanced · cloudtaser operator + wrapper + eBPF + demo-app pod · reached from VM2 via kubectl (container.developer IAM) | us-west1-a ~$30–46/mo |
| EU VM2 — Beacon + Orchestrator | cloudtaser-beacon relay · orchestrator Go daemon · SSE stream endpoints for cluster and beacon channels | europe-west3 (Frankfurt) e2-micro ~$9/mo |
| EU VM3 — Secret Store | OpenBao · cloudtaser-cli · SSE stream endpoint for vault channel | europe-west4 (Netherlands) e2-micro ~$9/mo |
|
Total: real GKE + 2 EU VMs, ~$48–64/month. Public DNS via Cloudflare; nothing is directly reachable from the public internet except through the Cloudflare tunnels. Honest disclosure: the GKE cluster and both VMs are on GCP. GCP is US-parented — per our own sovereign-deployment-guide, GCP EU regions do NOT establish sovereignty under CLOUD Act analysis. For production sovereignty the secret store would move to Hetzner / OVH / Scaleway / IONOS / Exoscale / UpCloud. |
||
Production topology — what a customer deployment looks like. OpenBao secret store runs on an EU-owned provider (Hetzner / OVH / Scaleway / IONOS / Exoscale / UpCloud). Workload pods run on the US cloud of your choice (GKE, EKS, AKS) on confidential-compute node SKUs. The cloudtaser bridge sits next to OpenBao; an EU-hosted beacon relay carries outbound-only traffic from the cluster. Result: keys never leave EU jurisdiction, ciphertext sits on US infrastructure, the provider has no path to plaintext. This is the topology our Sovereign Deployment Decision Guide walks through.
What you're watching today — honest deviation. For the live demo all three machines (GKE node + beacon VM + OpenBao VM) run on GCP — europe-west3 / europe-west4 for the EU pieces, us-west1 for the cluster. GCP EU regions are real EU data centres but a US-parented operator, so they do NOT clear the sovereignty guide's first-leg test (the secret store wants an EU-owned provider). Posture-wise the demo proves every cloudtaser claim that doesn't depend on substrate jurisdiction (memfd_secret, eBPF enforcement, beacon framing, P2P transport, register/init flow). For the substrate claim itself, swap GCP-EU for Hetzner / OVH / etc — same chart, same code, same operator. Hetzner migration of the demo's own secret store is on our near-term roadmap.
Every cluster mutation the demo performs is a file at cloudtaser.io/demo-lab/manifests/ — read the YAML, don't trust the narration.
Want a sovereign-topology trial in your environment? Book a 30-min call → — we'll size a Hetzner / OVH / Scaleway pilot against one of your workloads and walk the substrate decisions with your security team.
Demo infrastructure internals (for the curious) — orchestrator state machine, probe whitelist, RBAC, GKE rationale
Watch / run state machine
orchestrator state {
driver_session_id : string | null
driver_claimed_at : timestamp
driver_last_seen : timestamp // updated on each /api/demo/next or /api/demo/probe
demo_step : 0..7
viewers : set<session_id>
}
transitions:
visitor arrives -> registered as viewer; receives current state snapshot
driver_session_id null -> first viewer to POST /api/demo/claim wins (atomic compare-and-swap)
session active -> only host session can POST /next or /probe
driver_last_seen > 5min -> server releases session; broadcasts state change
session hits hard cap -> server releases at 20min regardless of activity
all viewers disconnect -> demo idles; ttyd streams persist (cluster state intact)
next viewer arrives -> same session / viewer logic applies
broadcast via Server-Sent Events on /api/demo/events:
{type:"claim", viewer_id:"..."}
{type:"step", step:N, by:"..."}
{type:"probe", name:"...", exit_code:0|non-zero}
{type:"release", reason:"idle"|"hard_cap"|"explicit"}
{type:"reset", new_state:{...}}
Probe whitelist (curated command palette)
Frontend sends {probe: "ptrace_attach"} as an opaque key. Orchestrator does a dict lookup against a fixed YAML. No user-supplied string ever reaches a shell. Command-injection surface is zero by construction.
probes:
# ── Positive-path probes (1–2): prove the secret landed correctly ───────
app_sees_secret:
label: "Postgres uses POSTGRES_PASSWORD (SELECT-as-ledger works)"
target: pod
cmd: kubectl exec -n {{NAMESPACE}} deploy/postgres -- \
psql -U ledger -d demo -tAc \
"SELECT 'OK_DB:' || count(*) FROM messages"
expected: "exit 0 + 'OK_DB:' in output (authenticated query proves
the secret reached the app via memfd_secret, not K8s Secret)"
no_k8s_secret:
label: "Zero K8s Secrets -- DB_PASSWORD is nowhere in any Secret object"
target: vm2-host
cmd: kubectl get secrets -A ... | grep DB_PASSWORD \
|| echo 'OK: no secret containing DB_PASSWORD'
expected: "exit 0 + 'OK: no secret' sentinel — secret travelled via
memfd_secret memory, not through etcd"
# ── Adversarial probes (3–5): block-is-pass ─────────────────────────────
ptrace_attach:
label: "ATTACK - ptrace attach against the wrapped postgres"
target: node-probe # privileged DaemonSet; hostPID; strace installed
cmd: kubectl exec -n cloudtaser-demo ds/node-probe -- \
sh -c "P=$(pgrep postgres | head -1); \
timeout 2 strace -p $P -e trace=none -c 2>&1; \
echo PID=$P"
expected: "exit 0 + PID=<N> in output (attach succeeds today;
eBPF sys_enter_ptrace tracepoint records PTRACE_DENIED
audit event. Future LSM hook will return EPERM before
attach. Run ebpf_audit probe after to see the event.)"
read_environ:
label: "ATTACK - cat /proc/1/environ inside the postgres pod"
target: pod # kubectl exec into {{NAMESPACE}} deploy/postgres
cmd: kubectl exec -n {{NAMESPACE}} deploy/postgres -- \
sh -c "cat /proc/1/environ 2>&1; echo ---END---"
expected: "non-zero exit + 'Permission denied' (eBPF kprobe_openat
blocks the read; DB_PASSWORD absent from environ anyway —
cloudtaser delivers via memfd_secret, not environ array)"
read_mem:
label: "ATTACK - dd if=/proc/1/mem inside the postgres pod"
target: pod
cmd: kubectl exec -n {{NAMESPACE}} deploy/postgres -- \
sh -c "dd if=/proc/1/mem bs=1 count=1 2>&1"
expected: "non-zero exit + 'Permission denied' - eBPF kprobe on
sys_openat blocks the open before any seekable FD exists"
# ── Informational probes (6–9): surface the protection posture ──────────
show_secretmem:
label: "Secret memory protection active (memfd_secret OR mlock fallback)"
target: pod
strategy: |
Two-stage approach (log greps first, FD inspection fallback):
Stage 1: kubectl logs grep for "memfd_secret":true OR mlock-
fallback line — cheap, kernel-agnostic, covers GKE COS.
Stage 2: iterate /proc/[PID]/fd looking for "secretmem" symlink.
Failure of all paths = genuine protection regression.
expected: "exit 0; wrapper-attested memfd_secret or mlock-fallback
log line, or 'secretmem FD present in /proc/<pid>/fd'"
ebpf_audit:
label: "eBPF audit log (last 10 enforcement events)"
target: vm2-host # kubectl logs from orchestrator host
cmd: kubectl logs -n cloudtaser-system \
-l app=cloudtaser-ebpf --tail=500 2>&1 | \
{ grep -iE 'block|deny|EPERM|enforce|kprobe' || \
echo '(no enforcement events yet - run adversarial probes first)'; } | \
tail -10
expected: "exit 0; grep for block/deny/EPERM/enforce/kprobe events
matching the ptrace_attach and read_mem probes run earlier"
ls_fds:
label: "ls -la /proc/<app-pid>/fd (memfd_secret FDs visible; not readable)"
target: pod
cmd: kubectl exec -n {{NAMESPACE}} deploy/postgres -- \
sh -c "P=$(pgrep postgres | head -1); \
echo PID=$P; ls -la /proc/$P/fd | head -15"
expected: "exit 0; fd table of the wrapped postgres process (not
PID 1). Entries backed by memfd_secret appear as
anon-inode symlinks; reading them is blocked because
the backing pages are not in the kernel direct map"
kubectl_pods:
label: "kubectl get pods -o wide (informational)"
target: vm2-host
cmd: kubectl get pods -n {{NAMESPACE}} -o wide
expected: "exit 0; live pod list for the per-session demo-XXXX-XXXX
namespace; 'postgres' pod must be Running"
# ── Confidential-compute probes (10–14): AMD SEV + protection score ─────
cc_dmesg:
label: "dmesg | grep SEV on the GKE CC node"
target: node-probe # hostPath-mounts / at /host
cmd: kubectl exec -n cloudtaser-demo ds/node-probe -- \
sh -c "chroot /host dmesg 2>&1 | grep -iE 'sev|amd mem' | head -8 \
|| echo '(no AMD encryption signatures in dmesg)'"
expected: "exit 0 + 'SEV' in output (AMD Memory Encryption active)"
cc_cpuinfo:
label: "grep sev/sme in /proc/cpuinfo (CPU memory-encryption features)"
target: node-probe
cmd: kubectl exec -n cloudtaser-demo ds/node-probe -- \
sh -c "FLAGS=\$(grep -oE 'sev[_a-z]*|sme' /host/proc/cpuinfo ...); \
echo CC_FEATURES: \$FLAGS"
expected: "exit 0 + 'CC_FEATURES:' sentinel with sev/sme flag list"
cc_kernel_version:
label: "uname -a + /proc/cmdline on the GKE CC node"
target: node-probe
cmd: kubectl exec -n cloudtaser-demo ds/node-probe -- \
sh -c "cat /host/proc/version; cat /host/proc/cmdline"
expected: "exit 0 + 'Linux' in output (kernel version + boot params)"
cc_node_metadata:
label: "kubectl describe node (confidentialCompute label + machine type)"
target: vm2-host
cmd: kubectl get nodes -o jsonpath='{range .items[0]}{.metadata.labels}...'
expected: "exit 0 + 'gke-' in output (GKE node labels including
cloud.google.com/gke-confidential-nodes)"
cc_protection_summary:
label: "Protection score -- secret delivery, runtime defence, hypervisor isolation, sovereign custody"
target: vm2-host
cmd: | # walks four protection legs; always exits 0
EBPF_OK=... INJ=... MEMFD=... CC=...
echo "CloudTaser protection: ebpf=\$EBPF inject-annotation=\$INJ \
memfd_secret=\$MEMFD confidential-compute=\$CC"
expected: "exit 0 + 'CloudTaser protection:' sentinel with four
GREEN/MISSING/NA legs (eBPF, inject, memfd, CC)"
Security analysis for the probe palette
- Whitelist, not freeform. Frontend sends
{probe: "ptrace_attach"}. Orchestrator looks up by key. User-supplied text never reaches a shell,eval, or command assembly. - Commands target the demo pod only. All
kubectl execcalls are hardcoded to a per-sessiondemo-XXXX-XXXXnamespace targetingdeploy/postgresor the privilegedcloudtaser-demo/node-probeDaemonSet. The orchestrator's K8s service account has RBAC limited tocreateonpods/execin namespacesdemo-appandcloudtaser-demo,getonpods/logincloudtaser-system, andgeton nodes. It cannot reach other namespaces, the host, or outside the cluster. - Demo pod is sacrificial.
postgresruns with no host-network access and mounts only synthetic secrets injected via cloudtaser. No customer material ever touches this stack. - All probes are read-only with bounded output. Each command has a
timeoutwrapper; output ishead'd to ~8 KB. No writes, nocurl, no network egress from the pod. - Rate-limited. 1 probe / 2 seconds per active session; hard cap 30 probes / session; session itself hard-capped at 20 minutes. Abuse doesn't compound; reset returns to baseline.
- Probes can demonstrate bugs, not exploit them. If a probe that should block somehow succeeds, that IS a finding - valuable signal, feeds directly into the pentest engagement. Watcher count sees it in real time.
- Probe output doesn't leak. Output streams into the cluster terminal pane (same place as the per-step command output). All viewers see the same stream. Nothing private is produced because nothing private exists on these VMs.
Why a real GKE cluster (not docker-compose on one box)
- Architectural authenticity. Procurement teams ask "what am I actually seeing here?" A demo on one box invites every conceivable doubt. A real zonal GKE cluster with a confidential-compute node pool + two separate EU VMs + real beacon protocol over the Atlantic = exactly the topology a customer would run in production.
- Confidential-compute target is a real one. The GKE node runs n2d-highcpu-2 with
confidential_nodes.enabled = true. AMD SEV is active;/proc/cpuinfoshowssev;dmesgshows "AMD Memory Encryption Features active". Thecc_*probes in the palette surface this live for all viewers. (SEV, not SEV-SNP: GKE's confidential_nodes API defaults to SEV on n2d; SEV-SNP on GKE requires preview flags not worth the complexity for MVP.) - Honest EU framing. The two EU VMs are in
europe-west3(Frankfurt) andeurope-west4(Netherlands). Real EU data-centre regions. Still GCP - US-parented - which does NOT clear the sovereign deployment decision guide's first-leg test. For real sovereignty: Hetzner / OVH / Scaleway / IONOS / Exoscale / UpCloud. Migration to a real EU-owned provider for the secret store is planned as a follow-up. - Beacon authenticity. GKE node in US, VM3 (secret store) in EU, VM2 (beacon) between them in EU. Bridge<>broker traffic actually crosses the Atlantic. Latency is real, not simulated. TLS terminates at the bridge (VM3) and the broker (GKE-side wrapper), not the relay.
- Cost reality. ~$48-64/month. GKE zonal control plane is free inside GCP's monthly credit; only the 1 CC node + 2 small EU VMs cost anything.
Want even more? Behind this demo: how it actually works ↗
You bring the cluster. We bring the Helm chart. Works on any CNCF-conformant Kubernetes. Honest version: without the three preconditions in the sovereign deployment decision guide, you are running the "better-than-K8s-Secrets" tier, not the "ciphertext-under-CLOUD-Act" tier — and we'd rather you know that before you run helm install.
Prereqs
kubectl1.28+,helm3.12+- Kubernetes 1.28+ (GKE / EKS / AKS / k3s / kubeadm)
- Node kernel Linux 5.14+ with
CONFIG_SECRETMEM=y(COS, Bottlerocket, AL2023, Ubuntu 22.04+ are fine out of the box) - For eBPF synchronous enforcement:
CONFIG_BPF_KPROBE_OVERRIDE=yon nodes - An OpenBao / HashiCorp Vault endpoint reachable from the cluster (see note below on sovereign hosting)
- For the sovereignty claim to hold end-to-end: OpenBao on an EU-owned provider and confidential-compute node SKUs and the kprobe-override kernel. Any two of three gets you the posture improvement but not the headline guarantee — see scope.
TL;DR — install
# Adds the chart repo + installs operator, webhook, eBPF agent, wrapper
$ helm repo add cloudtaser https://charts.cloudtaser.io
$ helm repo update
$ helm install cloudtaser cloudtaser/cloudtaser \
--namespace cloudtaser --create-namespace \
--set secretStore.address=https://openbao.example.eu:8200
TL;DR — annotate a pod
metadata:
annotations:
cloudtaser.io/inject: "true"
cloudtaser.io/secret-paths: "secret/data/db/credentials"
cloudtaser.io/env-map: "password=DB_PASSWORD"
cloudtaser.io/vault-auth-method: "token"
TL;DR — verify
$ kubectl rollout restart deployment my-app
$ kubectl logs -l app=my-app -c cloudtaser-init
# secrets fetched, memfd handoff, eBPF registered
Want to go deeper?
- Full getting-started guide — OpenBao setup, node kernel verification, annotation reference, troubleshooting.
- Sovereign Deployment Decision Guide — preconditions, decision trees, silent-failure anti-patterns. Read this before anything else if the audit story matters.
- Preview status & roadmap — honest picture of where we are (preview, pentest scheduling post-stabilization end-May 2026, SOC 2 Type II Q3 2027).
- Source on GitHub — operator, wrapper, eBPF agent, proxies, CLI. Cosign-signed images, SBOM per release.