MAQPNADocs

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.yaml profile.

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, helm 3.14 or later, and for kind: Docker and kind.
  • The maqpna CLI and its maqpna-install plugin, version 2.1.0: curl -fsSL https://maqpna.com/install.sh | sh.
  • REGISTRY set 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#

  1. Install runsc on each sandbox node as in k3s step 1, writing the template under /var/lib/rancher/rke2/agent/etc/containerd/, then restart rke2-agent (or rke2-server).
  2. Label the nodes: kubectl label node <node> maqpna.com/pool=gvisor.
  3. 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.
  4. 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).

Next steps#