> ## Documentation Index
> Fetch the complete documentation index at: https://docs.quintai.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Kubernetes: restricted setup

> Install the Quint node installer once per cluster, then run agent pods beside Quint in namespaces that enforce the restricted Pod Security level.

> [!NOTE]
>
> Quint on Kubernetes is early access. The Quint container images, the Helm charts and the admission webhook are not available for download. Your Quint contact gives you each of them, with the image digests for your release, so talk to your Quint contact before you plan an install.

At the end of this page your agent runs beside Quint in a namespace that enforces the Kubernetes `restricted` Pod Security level. No container in the agent's pod has added privileges. Instead, the Quint node installer runs once per cluster and sets each governed pod's network rules on the node. You need a cluster that meets the [requirements](https://docs.quintai.dev/install/containers.md#requirements) on a [supported network](https://docs.quintai.dev/install/containers.md#networking-for-the-restricted-setup), the [Quint admission webhook](https://docs.quintai.dev/install/admission-webhook.md), `kubectl` and `helm`. Ask your Quint contact for the `quint-sidecar` and `quint-node-installer` charts and the image digests for your release.

Runs in the restricted setup are recorded as **unverified**. See [Status recorded for runs](https://docs.quintai.dev/install/containers.md#status-recorded-for-runs).

## What the node installer runs

The `quint-node-installer` chart runs two DaemonSets on every node labelled `quintai.dev/node-installer`. `install-cni` chains Quint's network plugin after your cluster's own plugin and keeps it chained. The node agent holds the right to cut off every governed pod on its node. Both need a `privileged` namespace; the agent pods do not.

While a node's chain is not confirmed, `install-cni` taints the node `quintai.dev/netlock-unready:NoSchedule` and sets its label to `quintai.dev/node-installer=false`. It removes the taint and sets the label to `true` once the chain checks out. Governed pods select `quintai.dev/node-installer=true`.

> [!WARNING]
>
> The taint applies to every workload without a toleration, not only governed pods. While a node's chain is not confirmed, nothing new schedules there.

**1. Register the nodes**

Register each node that will run governed pods with the label `quintai.dev/node-installer=false` and the startup taint `quintai.dev/netlock-unready:NoSchedule`, through kubelet `--node-labels` and `--register-with-taints` or your node group's labels and taints. A governed pod on a node without the installer gets no network rules, so its Quint sidecar refuses to start.

**2. Install the node installer**

The `quint-node-installer` chart, its image and the image digest come from your Quint contact. They are not available for download.

Install it in a namespace labelled `pod-security.kubernetes.io/enforce=privileged`. `plugin.resolvers` is required: give the cluster DNS service address (the `kube-dns` ClusterIP). The release name may be at most 32 characters.

```bash theme={"dark"}
kubectl create namespace quint-system
kubectl label namespace quint-system pod-security.kubernetes.io/enforce=privileged
helm install ni ./quint-node-installer -n quint-system \
  --set image.digest=sha256:<quint-node-installer digest> \
  --set "plugin.resolvers={<kube-dns ClusterIP>}" \
  --set "plugin.governedNamespaces={agents}"
```

List every restricted agent namespace in `plugin.governedNamespaces`. Then no pod there starts without Quint, static pods included. If you set `plugin.allowPrivate`, it must match `QUINT_ALLOW_PRIVATE_CIDRS` on the Quint sidecar.

**3. Create and label the agent namespace**

```bash theme={"dark"}
kubectl create namespace agents
kubectl label namespace agents pod-security.kubernetes.io/enforce=restricted \
  quintai.dev/governed=true quintai.dev/netlock=node-installer
kubectl -n agents create secret generic quint-workload-key --from-file=key=./workload.key
```

The key comes from the workload's **Keys** card on the [Workloads](https://docs.quintai.dev/dashboard/workloads.md) page.

**4. Install the agent chart**

Install `quint-sidecar` as in the [standard setup](https://docs.quintai.dev/install/kubernetes-standard.md), with `qhelper.mode=node-installer`. The pod then holds only the Quint sidecar and your agent. The chart, the Quint sidecar image and its digest come from your Quint contact.

```bash theme={"dark"}
helm install my-agent ./quint-sidecar -n agents \
  --set qhelper.mode=node-installer \
  --set agentUID=10002 \
  --set quint.workload=ci-agent \
  --set quint.workloadKeySecret.name=quint-workload-key \
  --set images.sidecar.digest=sha256:<quint-sidecar digest> \
  --set agent.image.repository=registry.example/my-agent --set agent.image.tag=1.0
```

Set `quint.harnessVersions` too, so rules that ask for approval wait for an approver. Quint accepts only the harness versions it knows, so ask your Quint contact which ones before you set it. Without it, every rule that asks for approval denies the action straight away. See the "Declare your agent's harness version" step in the [standard setup](https://docs.quintai.dev/install/kubernetes-standard.md).

## Cilium

Chain Quint inside Cilium's own CNI configuration. Put a list that holds `cilium-cni` followed by exactly the node installer's plugin configuration (the `plugin.json` key of the `<release>-quint-node-installer` ConfigMap) in a ConfigMap, and point Cilium's Helm value `cni.configMap` at it. Keep `cni.exclusive=true`.

Store the list under the key `cni-config`. That is the key Cilium reads unless you changed its Helm value `cni.configMapKey`; under any other key Cilium finds no configuration. The list is a complete CNI configuration list, so it also carries `cniVersion` and `name`, as Cilium's own list does. Create the ConfigMap in Cilium's namespace:

```bash theme={"dark"}
kubectl -n kube-system create configmap quint-cni-config \
  --from-file=cni-config=./cilium-chained.conflist
helm upgrade cilium cilium/cilium -n kube-system --reuse-values \
  --set cni.configMap=quint-cni-config --set cni.exclusive=true
```

With kube-proxy replacement and `socketLB.enabled`, also set `socketLB.hostNamespaceOnly=true`. The Quint sidecar's DNS depends on it.

The node installer then writes no list of its own, and keeps the node closed while Cilium's entry differs from its own configuration. With Cilium's defaults (no `cni.configMap`), Cilium removes the installer's list each time it is written. After three removals in ten minutes the node installer refuses that network plugin: the node stays closed, the installer retries once a minute, and its log names the fix.

## Take a node out

Remove the `quintai.dev/node-installer` label. Setting it to `false` by hand does not work, because `install-cni` sets it back. With the label gone, both DaemonSets and every governed pod leave the node.

## Upgrades

Upgrade the node installer and the `quint-sidecar` images to the same Quint release, together. The new charts, images and digests come from your Quint contact. The Quint sidecar refuses to start unless the node's network rules match the ones its own release builds, so a mixed pair refuses every governed pod.

The node agent is replaced one node at a time. While it is away, governed pods keep their network rules, and Quint denies every tool call and closes its proxy. A pod is cut off for good only if the agent is away for more than 90 seconds, so pre-pull the new image on a slow registry before you upgrade.

## If this fails

| What you see | What it means | What to do |
| - | - | - |
| Governed pods stay Pending | No node has `quintai.dev/node-installer=true` | Check that the node installer runs there and read its `install-cni` logs. |
| The Quint sidecar refuses to start | The pod's node has no Quint network rules for it, or they come from a different Quint release | Keep governed pods on installer nodes, and upgrade both charts together. |
| On Cilium, the node never opens | Quint is not chained through `cni.configMap`, or the entry differs from the node installer's | Follow [Cilium](#cilium). The `install-cni` log names the keys that differ. |
| A pod stays Running but not Ready, then is replaced | The node agent found the pod's network rules missing and marked it | Nothing. Its Job or Deployment creates a new pod. |

## Next

* [The Quint admission webhook](https://docs.quintai.dev/install/admission-webhook.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.