A lightweight, pluggable CSI (Container Storage Interface) block driver for Confidential Containers Peer Pods. It creates and manages block volumes across multiple cloud providers and integrates with the Cloud API Adaptor (CAA) for volume attachment to PodVMs.
| Provider | Backend | Authentication | Status |
|---|---|---|---|
| AWS | EBS Volumes | IAM role or access key credentials | Supported |
| Azure | Managed Disks | DefaultAzureCredential (Workload Identity, Managed Identity, env vars) | Supported |
| Libvirt | Raw disk files | N/A (local) | Supported (dev/test) |
┌──────────────────────────────────────────────────────┐
│ Kubernetes │
│ PVC ──► StorageClass ──► caa-csi-block-driver │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ │ │ │ │
│ ┌───▼───┐ ┌─────▼─────┐ ┌─────▼────┐ │
│ │ AWS │ │ Libvirt │ │ Azure │ │
│ │(EBS) │ │ (raw disk)│ │(Managed │ │
│ │ │ │ │ │ Disks) │ │
│ └───┬───┘ └─────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └───────┬───────┴──────────────┘ │
│ ▼ │
│ mountInfo.json │
│ │ │
│ ▼ │
│ Cloud API Adaptor (CAA) │
│ │ │
│ ▼ │
│ PodVM │
└──────────────────────────────────────────────────────┘
- A PVC is created referencing a
StorageClassbacked by this driver - The Controller Server calls the appropriate cloud provider to create a block volume
- The Node Server writes
mountInfo.jsonto the Kata Containers shared directory - CAA reads
mountInfo.jsonand attaches the volume to the PodVM - On PVC deletion, the controller deletes the cloud volume
├── cmd/ # Driver entrypoint
├── pkg/
│ ├── driver/ # CSI gRPC servers (controller, node, identity)
│ └── provider/
│ ├── interface.go # BlockVolumeProvider interface
│ ├── factory.go # Provider registry and factory
│ ├── aws/ # AWS EBS provider
│ ├── azure/ # Azure Managed Disks provider
│ └── libvirt/ # Libvirt raw disk provider
├── deploy/ # Kubernetes manifests
├── hack/ # Helper scripts
├── .github/workflows/ # CI pipelines
├── Dockerfile
├── Makefile
└── go.mod
Pre-built images are published to GHCR on every push to main and on version tags:
docker pull ghcr.io/confidential-devhub/caa-csi-block-driver:main# Build the binary
make build
# Build the container image
make image
# Build for a specific platform
make build GOOS=linux GOARCH=amd64- Kubernetes cluster with Kata Containers and CAA deployed
kata-remoteRuntimeClass configured
# Create the AWS credentials secret
kubectl create secret generic caa-csi-aws-creds \
-n caa-csi-block \
--from-literal=AWS_ACCESS_KEY_ID=<your-key> \
--from-literal=AWS_SECRET_ACCESS_KEY=<your-secret>
kubectl apply -f deploy/namespace.yaml
kubectl apply -f deploy/rbac.yaml
kubectl apply -f deploy/csi-driver.yaml
kubectl apply -f deploy/daemonset-aws.yaml
kubectl apply -f deploy/storageclass-aws.yamlAuthentication uses DefaultAzureCredential, which supports Workload Identity,
Managed Identity, and environment variables. No secrets in StorageClass parameters.
kubectl apply -f deploy/namespace.yaml
kubectl apply -f deploy/rbac.yaml
kubectl apply -f deploy/csi-driver.yaml
kubectl apply -f deploy/daemonset-azure.yaml
# Edit storageclass-azure.yaml with your subscription, resource group, and location
kubectl apply -f deploy/storageclass-azure.yamlkubectl apply -f deploy/namespace.yaml
kubectl apply -f deploy/rbac.yaml
kubectl apply -f deploy/csi-driver.yaml
kubectl apply -f deploy/daemonset.yaml
kubectl apply -f deploy/storageclass-libvirt.yamlapiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 1Gi
storageClassName: caa-block-azure # or caa-block-aws, caa-block-libvirt
---
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
runtimeClassName: kata-remote
containers:
- name: app
image: busybox
command: ["sh", "-c", "echo hello > /data/test.txt && sleep 3600"]
volumeMounts:
- name: vol
mountPath: /data
volumes:
- name: vol
persistentVolumeClaim:
claimName: test-pvcImplement the BlockVolumeProvider interface:
type BlockVolumeProvider interface {
CreateVolume(volumeID string, sizeBytes int64) (*VolumeInfo, error)
DeleteVolume(volumeID string) error
GetVolumeInfo(volumeID string) (*VolumeInfo, error)
VolumeExists(volumeID string) (bool, error)
}Then register it in an init() function:
func init() {
provider.RegisterProvider("myprovider", func(params map[string]string) (provider.BlockVolumeProvider, error) {
return NewMyProvider(params)
})
}Import the package in cmd/main.go:
_ "github.com/confidential-devhub/caa-csi-block-driver/pkg/provider/myprovider"# Run CSI conformance tests locally
make test
# Run tests with verbose output
make test-verboseThe driver passes all applicable csi-sanity conformance tests:
- 33 Passed — all tests for implemented CSI RPCs
- 58 Skipped — optional features not in scope (snapshots, expansion, cloning, listing)
Apache License 2.0 — see LICENSE for details.