Confidential Compute (TEE) Support

Experimental feature. Confidential Compute (TEE) is experimental and under active development. Its SDL syntax, attestation API, and runtime behavior may change without notice. We encourage you to try it and share feedback, but plan for breaking changes.

This guide shows how to enable Confidential Compute (TEE) support on your Akash provider, allowing tenants to deploy workloads inside hardware-backed Trusted Execution Environments.

Prerequisites: You must have a working Akash provider with Kubernetes already deployed. See Kubernetes Setup and Provider Installation.

Hardware required: Your nodes must have TEE-capable processors, AMD EPYC (Milan or later) for SEV-SNP, or Intel Xeon (Sapphire Rapids or later) for TDX.

Do not enable LUKS (full-disk encryption) on TEE host nodes. SEV-SNP and TDX encrypt guest VM memory at the hardware level, that is the security boundary that matters for tenant workloads. LUKS on the host root filesystem adds boot-time complexity without providing additional protection.


Overview

Confidential Compute on Akash uses Kata Containers to run tenant workloads inside hardware-encrypted virtual machines. The provider automatically:

  1. Schedules TEE workloads onto nodes with the correct runtime class
  2. Injects an attestation sidecar into each confidential workload
  3. Proxies attestation requests from tenants to the sidecar inside the TEE

Supported Configurations

TEE TypeRuntime ClassHardware
AMD SEV-SNPkata-qemu-snpAMD with SEV-SNP enabled in BIOS
AMD SEV-SNP + GPUkata-qemu-nvidia-gpu-snpAbove + NVIDIA CC-capable GPU
Intel TDXkata-qemu-tdxIntel with TDX enabled in BIOS
Intel TDX + GPUkata-qemu-nvidia-gpu-tdxAbove + NVIDIA CC-capable GPU

STEP 1 — Verify Hardware Support

AMD SEV-SNP

Run on each TEE node:

Terminal window
# Check CPU supports SEV-SNP
dmesg | grep -i snp

You should see output indicating SEV-SNP is enabled:

SEV-SNP enabled

Verify the device exists:

Terminal window
ls -la /dev/sev

If SEV-SNP is not showing: Enable it in your BIOS/UEFI under AMD CBS > CPU Configuration > SEV-SNP. Ensure your firmware is up to date.

Intel TDX

Run on each TEE node:

Terminal window
# Check CPU supports TDX
dmesg | grep -i tdx

You should see:

tdx: TDX module initialized
virt/tdx: module initialized

Verify the device exists:

Terminal window
ls -la /dev/tdx_guest # or /dev/tdx-attest on older kernels

If TDX is not showing: Enable it in your BIOS/UEFI under Intel Advanced Menu > TDX. Requires a TDX-capable kernel (Linux 6.2+).


STEP 2 — Install Kata Containers via kata-deploy

Kata Containers provides the confidential VM runtime. Install it using the kata-deploy Helm chart, which configures containerd runtime classes, RuntimeClass resources, and all Kata binaries automatically.

Do not install QEMU, KVM userspace, libvirt, or OVMF packages on the host. Kata ships its own NVIDIA-patched versions of these components. Pre-installing them creates silent conflicts.

Terminal window
helm install kata-deploy \
oci://ghcr.io/kata-containers/kata-deploy-charts/kata-deploy \
--namespace kata-system --create-namespace \
--set nfd.enabled=false \
--wait --timeout 10m \
--version 3.29.0

If running K3s instead of standard Kubernetes, add --set k8sDistribution=k3s. Without this flag, kata-deploy will fail searching for containerd config at the wrong path.

Verify the installation:

Terminal window
# kata-deploy pod should be Running
kubectl get pods -n kata-system
# RuntimeClasses should be created automatically
kubectl get runtimeclass | grep kata-qemu

You should see runtime classes including kata-qemu-snp, kata-qemu-tdx, and their GPU variants (kata-qemu-nvidia-gpu-snp, kata-qemu-nvidia-gpu-tdx).

STEP 3 — Install NVIDIA GPU Operator (GPU providers only)

Skip this step if your provider does not offer GPU Confidential Computing.

The NVIDIA GPU Operator handles GPU VFIO binding, CC mode toggling, and device plugin registration. Do not install NVIDIA GPU drivers on the host — the operator manages everything.

Terminal window
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update
helm install gpu-operator nvidia/gpu-operator \
--namespace gpu-operator --create-namespace \
--version v26.3.1 \
--set sandboxWorkloads.enabled=true \
--set sandboxWorkloads.mode=kata \
--set nfd.enabled=true \
--set nfd.nodefeaturerules=true \
--wait --timeout 10m

Label each GPU node for operand activation:

Terminal window
kubectl label node <node-name> nvidia.com/gpu.workload.config=vm-passthrough

Verify the installation:

Terminal window
# All operand pods should be Running
kubectl get pods -n gpu-operator
# GPU should be bound to vfio-pci (not nvidia driver)
lspci -nnk -d 10de: | grep "Kernel driver in use"
# Expected: vfio-pci
# CC mode should be enabled
kubectl get node <node-name> -o json | \
jq '.metadata.labels | with_entries(select(.key | startswith("nvidia.com/cc")))'
# Expected: "nvidia.com/cc.mode.state": "on", "nvidia.com/cc.ready.state": "true"
# Passthrough GPU resource should be advertised
kubectl get node <node-name> -o json | \
jq '.status.allocatable | with_entries(select(.key | startswith("nvidia.com")))'
# Expected: "nvidia.com/pgpu": "1" (or more, depending on GPU count)

The operator deploys several components:

  • nvidia-vfio-manager — binds GPUs to the vfio-pci driver for passthrough
  • nvidia-cc-manager — toggles GPU Confidential Computing mode (default: on)
  • nvidia-kata-sandbox-device-plugin — advertises nvidia.com/pgpu resources
  • nvidia-sandbox-validator — node-level CC readiness validation
  • NFD components — detects CPU TEE capabilities and GPU presence via node labels

STEP 3b — Label Nodes for TEE Platform Detection

The Akash provider detects the TEE platform at startup by scanning Kubernetes node labels. Standard NFD (Node Feature Discovery) labels like feature.node.kubernetes.io/cpu-security.sev.snp.enabled are not sufficient. The provider looks for platform-specific labels in a dedicated namespace.

Apply the appropriate label to every TEE-capable node:

AMD SEV-SNP

Terminal window
kubectl label node <node-name> amd.feature.node.kubernetes.io/snp=true

Intel TDX

Terminal window
kubectl label node <node-name> intel.feature.node.kubernetes.io/tdx=true

Why not use standard NFD labels? The provider needs a single, unambiguous signal per platform. NFD exposes many granular CPU feature labels (SEV, SEV_ES, SEV_SNP, SME, etc.) but none in the format the provider expects. These dedicated labels act as a provider-level opt-in that confirms the node is fully configured for CC workloads, not just that the CPU has the capability.

Verify the labels were applied:

Terminal window
kubectl get nodes --show-labels | grep -E "amd.feature|intel.feature"

STEP 4 — Configure Provider Values

The Akash provider can inject an attestation sidecar into confidential workloads that request it. This sidecar runs inside the TEE and serves hardware-signed attestation reports to tenants. Configure it through the provider Helm values.

Helm values

ValueDescriptionRequired
attestation.enabledEnables the mutating admission webhook that injects the attestation sidecar into confidential workloads.Yes
attestation.sidecarImage.repositoryContainer repository for the attestation sidecar.Yes
attestation.sidecarImage.tagContainer tag. When empty, defaults to the provider chart app version.No
attestation.webhookPortHTTPS port used for Kubernetes admission callbacks. Defaults to 9443.No

Add these values to provider.yaml:

provider.yaml
attestation:
enabled: true
webhookPort: 9443
sidecarImage:
repository: ghcr.io/akash-network/provider-attestation-sidecar
tag: ""

Leave the tag empty to keep the sidecar aligned with the provider chart app version. Only set an explicit tag when you have verified that it is compatible with the provider version.


STEP 5 — Configure Provider Attributes

Tenants discover TEE-capable providers through the on-chain tee/type attribute. The provider detects the hardware platform from the Kubernetes node labels configured in Step 3b; do not publish a separate tee/platform attribute.

CPU only

attributes:
- key: tee/type
value: cpu

CPU with confidential GPU

attributes:
- key: tee/type
value: cpu-gpu

After updating attributes, restart your provider:

Terminal window
cd /root/provider
helm upgrade akash-provider akash/provider \
-n akash-services \
--version 19.0.2 \
-f provider.yaml \
--set bidpricescript="$(cat price_script.sh | openssl base64 -A)"

STEP 6 — Verify Setup

Test with a Confidential Deployment

Create a test SDL file (test-cc.yaml):

---
version: "2.1"
services:
web:
image: nginx
expose:
- port: 80
as: 80
to:
- global: true
params:
tee:
type: sev-snp
profiles:
compute:
web:
resources:
cpu:
units: 0.5
memory:
size: 256Mi
storage:
size: 128Mi
placement:
akash:
pricing:
web:
denom: uact
amount: 1000
deployment:
web:
akash:
profile: web
count: 1

Deploy and verify:

Terminal window
# Deploy through the selected provider
akt deploy test-cc.yaml \
--from <your-key> \
--bid-select "provider=<provider-address>" \
--yes
# After lease is created, check that the pod has the correct runtime class
kubectl get pods -n <lease-namespace> -o jsonpath='{.items[0].spec.runtimeClassName}'
# Expected: kata-qemu-snp
# Check the attestation sidecar was injected
kubectl get pods -n <lease-namespace> -o jsonpath='{.items[0].spec.containers[*].name}'
# Expected: web akash-attestation-sidecar

Request an Attestation Quote

Terminal window
AKT_FROM=<your-key> akt provider lease-attestation \
<deployment-sequence> \
--provider <provider-address>

A successful response confirms that the provider returned an attestation payload over an authenticated lease connection and that the request nonce is fresh. akt does not currently validate the evidence signature, endorsement chain, or measurement policy, so treat the response as evidence to pass to a TEE verifier rather than proof by itself that the workload is running on genuine TEE hardware.


Troubleshooting

Provider not bidding on CC workloads

The provider won’t bid on TEE deployments if it can’t detect the TEE platform at startup. Check the provider logs for detected TEE platform:

Terminal window
kubectl logs akash-provider-0 -n akash-services | grep -i "tee platform"

If you see no output or TEEPlatformNone, the node labels are missing. Apply them per Step 3b and restart the provider pod.

Pod stuck in Pending

Terminal window
kubectl describe pod <pod-name> -n <lease-namespace>

Common causes:

  • RuntimeClass not found: Verify the RuntimeClass exists with kubectl get runtimeclass
  • No TEE-capable nodes: Ensure nodes with TEE hardware are labeled and schedulable
  • Kata not installed: Check that Kata is properly installed on the target node
  • Insufficient nvidia.com/gpu: The provider set nvidia.com/gpu instead of nvidia.com/pgpu. This means TEE platform detection failed, see the section above

Attestation sidecar not injected

  • Verify the webhook is running: kubectl get mutatingwebhookconfigurations
  • Check provider logs for webhook errors
  • Ensure attestation.enabled: true is present in provider.yaml and was applied with the Helm upgrade

Attestation quote returns error

  • Verify the sidecar container is running: kubectl logs <pod> -c akash-attestation-sidecar -n <namespace>
  • Check that TEE devices are accessible inside the Kata VM
  • For GPU variants, verify NVIDIA drivers are available inside the guest

SEV-SNP device not found

  • Ensure BIOS has SEV-SNP enabled
  • Update to latest firmware/microcode
  • Verify kernel supports SEV-SNP (Linux 5.19+)
  • Check dmesg | grep -i sev for errors

TDX device not found

  • Ensure BIOS has TDX enabled
  • Verify TDX kernel module is loaded: lsmod | grep tdx
  • TDX requires Linux 6.2+ with TDX support compiled in