Install on k3s, kind and RKE2
Install MAQPNA on a kind cluster for development, on k3s for edge and lab sites, and on SUSE RKE2 for self-managed production, with gVisor, Kata and network policy set up for each.
This page covers clusters you run yourself:
- kind for development on a laptop. tier-0 only.
- k3s for edge sites, labs and single-node installations.
- RKE2 (SUSE Rancher) for self-managed production clusters, with the
values-rke2.yamlprofile.
None of them ships a sandbox runtime, so you install gVisor (tier-0) and, where the hosts have /dev/kvm, Kata
(tier-1) yourself. If you only want to try MAQPNA without Kubernetes, use local MAQPNA instead
(maqpna dev up).
flowchart LR
subgraph Node["Each sandbox node"]
CD["containerd<br/>+ runsc handler"] --> S0["tier-0 sandbox<br/>RuntimeClass gvisor"]
KD["kata-deploy<br/>(needs /dev/kvm)"] --> S1["tier-1 sandbox<br/>kata-qemu"]
end
subgraph CP["maqpna-system"]
OP[operator]
GW[gateway]
ID[identity broker]
end
S0 -->|"NetworkPolicy: DNS + gateway only"| GW
S1 --> GW
OP -->|"creates Sandbox"| AS["agent-sandbox<br/>controller"]
| Cluster | tier-0 (gVisor) | tier-1 (microVM) | NetworkPolicy | Profile |
|---|---|---|---|---|
| kind | runsc copied into each node |
no (no /dev/kvm in kind nodes) |
kindnet does not enforce it; install Calico or Cilium to test policies | --profile dev |
| k3s | runsc through the k3s containerd template |
kata-deploy on hosts with /dev/kvm |
kube-router, built into k3s | --profile dev, or prod for a lab |
| RKE2 | runsc through the RKE2 containerd template |
kata-deploy on hosts with /dev/kvm |
Canal (default) or Cilium | --profile prod -f values-rke2.yaml |
Before you begin#
kubectl,helm3.14 or later, and for kind: Docker andkind.- The
maqpnaCLI and itsmaqpna-installplugin, version 2.1.0:curl -fsSL https://maqpna.com/install.sh | sh. REGISTRYset to the release registry listed on maqpna.com/download.
V=2.1.0
export REGISTRY=<release-registry-from-maqpna.com/download>
kind (development)#
Step 1: Create the cluster#
# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: maqpna
networking:
disableDefaultCNI: false # true, then install Calico or Cilium, to test NetworkPolicy
podSubnet: 10.244.0.0/16
nodes:
- role: control-plane
extraPortMappings:
- {containerPort: 30080, hostPort: 8080, protocol: TCP} # optional gateway NodePort
- role: worker
kind create cluster --config kind-config.yaml
Step 2: Install gVisor in every node#
kind nodes are containers, so you copy runsc, its shim and the gvisor-bin/ directory into each node and register
the runsc handler with containerd. hack/kind-gvisor.sh in the MAQPNA source does exactly that, with sha512
verification:
KIND_CLUSTER=maqpna GVISOR_RELEASE=latest hack/kind-gvisor.sh
Smoke-test the runtime once the chart has created the gvisor RuntimeClass (step 4):
kubectl run gv --rm -it --restart=Never --image=busybox \
--overrides='{"spec":{"runtimeClassName":"gvisor"}}' -- dmesg | head -3
Step 3: Install the agent-sandbox controller and the dev key#
kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v1.0.6/sandbox-with-extensions.yaml
# The dev profile turns on the SAMPLE attestation verifier (DEV ONLY), which needs a public key
openssl genpkey -algorithm ed25519 -out dev-attest.key
openssl pkey -in dev-attest.key -pubout -out dev-attest.pub
kubectl create namespace maqpna-system
kubectl -n maqpna-system create secret generic maqpna-attest-dev --from-file=pub.pem=dev-attest.pub
Step 4: Install#
maqpna preflight --profile dev --version "$V" --chart "oci://$REGISTRY/charts/maqpna"
maqpna install --profile dev --version "$V" --chart "oci://$REGISTRY/charts/maqpna" --wait
The dev profile (values-dev.yaml) enables only the gVisor RuntimeClass, uses a generated identity key that changes
on every restart, puts sovereignty in audit mode, runs one replica of everything and deploys the echo test MCP
server.
Step 5: Verify#
kubectl -n maqpna-system get pods
helm test maqpna -n maqpna-system
kubectl -n maqpna-system port-forward svc/maqpna-gateway 8080:8080 &
export MAQPNA_ADMIN_TOKEN=$(kubectl -n maqpna-system get secret maqpna-tokens -o jsonpath='{.data.admin-token}' | base64 -d)
maqpna doctor -n maqpna-system --gateway http://127.0.0.1:8080
doctor reports the production checks the dev profile fails by design (admin-auth-mode, identity-key-mode,
attest-verifier and others). Accept them for a dev cluster with --accept ID,...; never in production.
k3s (edge and lab)#
Step 1: Install k3s and gVisor#
k3s embeds containerd. Install gVisor on each node that runs sandboxes and register it through the k3s containerd
template (k3s v1.31 and later read config-v3.toml.tmpl; older releases read config.toml.tmpl):
curl -sfL https://get.k3s.io | sh -
ARCH=$(uname -m); URL=https://storage.googleapis.com/gvisor/releases/release/latest/${ARCH}
curl -fsSLO "${URL}/gvisor.tar.bz2" -O "${URL}/gvisor.tar.bz2.sha512"
sha512sum -c gvisor.tar.bz2.sha512 && tar -xjf gvisor.tar.bz2
sudo install -m 0755 runsc containerd-shim-runsc-v1 /usr/local/bin/
sudo cp -r gvisor-bin /usr/local/bin/
sudo mkdir -p /var/lib/rancher/k3s/agent/etc/containerd
cat <<'EOF' | sudo tee /var/lib/rancher/k3s/agent/etc/containerd/config-v3.toml.tmpl
{{ template "base" . }}
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runsc]
runtime_type = "io.containerd.runsc.v1"
EOF
sudo systemctl restart k3s
k3s's built-in NetworkPolicy controller (kube-router) enforces MAQPNA's default-deny policies. Hosts with /dev/kvm
can also run Kata through kata-deploy (with k3s as the runtime flavour) for tier-1.
Step 2: Install#
Follow kind steps 3 to 5 for a dev or lab install. For a lab with real identity and audit settings, use
--profile prod and the production install steps. On a single node, set
gateway.replicas: 1 if you keep the file state backend: the chart refuses more than one replica with file.
Air-gapped edge sites#
Build the offline bundle on a connected host, carry it across, import the images with k3s ctr images import and
install the chart from the bundle. The full flow is in Air-gapped install.
RKE2 (self-managed production)#
values-rke2.yaml maps the tiers like this:
| Tier | RuntimeClass | Set up |
|---|---|---|
| tier-0 | gvisor (created by the chart, pinned to maqpna.com/pool=gvisor) |
install runsc on the sandbox nodes and add it to RKE2's containerd template, as for k3s, under /var/lib/rancher/rke2/agent/etc/containerd/ |
| tier-1 | kata-qemu (created by kata-deploy) |
kata-deploy on nodes with /dev/kvm |
| tier-2 | opt-in | Kata CoCo on AMD SEV-SNP or Intel TDX hosts: set runtimeClasses.kataQemuSnp.enabled: true and add the tier once the hardware and Trustee are in place |
Step 1: Prepare the nodes#
- Install
runscon each sandbox node as in k3s step 1, writing the template under/var/lib/rancher/rke2/agent/etc/containerd/, then restartrke2-agent(orrke2-server). - Label the nodes:
kubectl label node <node> maqpna.com/pool=gvisor. - Install a storage provisioner. RKE2 installs no StorageClass; use Longhorn, local-path-provisioner or your CSI
driver and make it the default, or set
gateway.auditStorage.storageClassName. - Install the agent-sandbox controller (kind step 3, first command).
Step 2: Install#
helm pull "oci://$REGISTRY/charts/maqpna" --version "$V" --untar
maqpna values validate --chart ./maqpna --profile production \
-f maqpna/values-production.yaml -f maqpna/values-rke2.yaml -f my-values.yaml
maqpna preflight --chart ./maqpna --profile prod -f maqpna/values-rke2.yaml -f my-values.yaml --strict
maqpna install --chart ./maqpna --profile prod -f maqpna/values-rke2.yaml -f my-values.yaml \
--license maqpna-license.jws --wait --timeout 15m
Create the Secrets and my-values.yaml as in Production install with Helm.
Canal (rke2-canal) and Cilium (rke2-cilium) both pass preflight's CNI check. With cni: cilium in
/etc/rancher/rke2/config.yaml you can also set networkPolicy.fqdnEgress.enabled: true (provider cilium).
Expose the gateway#
ingress-nginx in RKE2 reached end of life in March 2026, and the chart creates no Ingress. Expose the gateway with a Gateway API route or a load balancer you own, and admit it with a NetworkPolicy (Ingress and TLS).
FIPS#
RKE2 can run FIPS 140-3 validated Kubernetes components, but MAQPNA's images are not FIPS builds and contain no validated cryptographic module; neither are gVisor and Kata. In a FIPS cluster, record MAQPNA as a non-FIPS workload.
Verify#
Run step 12 of Install on EKS: helm test, maqpna doctor --strict through
the admin port, and the runtime-class check of a sandbox pod.
Troubleshooting#
| Symptom | Cause | Fix |
|---|---|---|
Sandbox pod ContainerCreating, event no runtime for "runsc" is configured |
The handler is not in containerd's config on that node | Check the template path for your k3s or RKE2 version and restart the service. |
runsc fails to start, missing gvisor_sentry |
gvisor-bin/ is not next to runsc |
Copy the archive's gvisor-bin/ directory into /usr/local/bin/. |
Preflight fails on attest-dev-key-secret |
The dev profile's sample verifier key is missing | Create the maqpna-attest-dev Secret (kind step 3). |
tier-1 sessions stay Pending on kind |
kind nodes have no /dev/kvm, so no Kata runtime |
Use tier-0 on kind; test tier-1 on k3s or RKE2 hosts with /dev/kvm. |
| Agents on kind reach the internet | kindnet does not enforce NetworkPolicy | Recreate the cluster with disableDefaultCNI: true and install Calico or Cilium. |
| Tokens stop verifying after a broker restart | The dev profile generates a new identity key on every restart | Expected in dev; use identity.key.mode: helm or existingSecret for anything that lasts. |
RKE2: gateway PVC Pending |
No StorageClass | Install a provisioner (RKE2 step 1). |