# How enforcement works

Learn where Zero-Code makes each decision on a node, how an AI agent is held in a boundary, and how monitor mode, enforce mode and the brake fit.

Zero-Code makes its decisions on the node, in the Linux kernel, with small programs loaded by eBPF. A decision made there cannot be skipped by a workload that ignores a library or connects to an IP address directly.

The programs are loaded by the _node agent_, the Zero-Code component that runs on every node. This page explains what is decided, where, and what controls whether a decision is applied. To install the node agent, see [Install Zero-Code on a cluster](/zero-code/install).

## Where each decision is made

Zero-Code makes three kinds of decision, each at the point where it cannot be avoided.

| Decision                                     | Made by                                 | A denial is                       |
| -------------------------------------------- | --------------------------------------- | --------------------------------- |
| May this workload open this connection?      | The kernel, as the connection is opened | The connection fails with `EPERM` |
| May this request reach this route?           | The node's proxy, on the request        | `403`                             |
| May this process do this to another process? | The kernel's security hooks             | The call fails                    |

## Rules on where a workload connects

For each workload you list where it may connect: the destinations, and the ports on them. The console drafts the list from the connections it saw the workload make, under **What it may reach** in the workload's Protect step. Each destination is marked **allowed** or **would be refused**.

When the workload is in enforce mode, every other destination is denied. Outbound access is closed by default.

## The boundary around an AI agent

A workload classified as **AI agent** runs as a registered AI agent, chosen in **Runs as**. It is held more tightly than an ordinary service. An AI agent runs code that a model wrote, so the boundary assumes the code may try anything.

| The AI agent tries to                                 | Result                                                                         |
| ----------------------------------------------------- | ------------------------------------------------------------------------------ |
| Connect somewhere it was not granted                  | Denied                                                                         |
| Reach the cloud metadata address, `169.254.169.254`   | Denied. No grant opens it.                                                     |
| Open a raw socket, to craft its own packets           | Denied                                                                         |
| Inspect or control a process outside its own workload | Denied                                                                         |
| Load its own program into the kernel                  | Denied                                                                         |
| Connect to a local socket it was not given            | Denied                                                                         |
| Call a tool                                           | Allowed through the [MCP gateway](/agents/mcp-gateway), which checks the grant |

The metadata address is where a cloud hands out the node's own credentials. An AI agent that reaches it has the node's access, which is why no grant opens it.

Each denial is recorded with the AI agent, what it tried and when.

## Monitor mode and enforce mode

A rule is in one of two modes. In _monitor mode_, a rule denies nothing and records what it would have denied. In _enforce mode_, the rule is applied. Everything starts in monitor mode.

The mode is set at two levels.

| Level       | Set by                                 | Meaning                                                                  |
| ----------- | -------------------------------------- | ------------------------------------------------------------------------ |
| The cluster | `mode` in the install                  | `observe`: the nodes are in monitor mode. `enforce`: the nodes may deny. |
| A workload  | **Turn on protection…** in the console | Monitor mode until you turn protection on, then enforce mode             |

The console shows the cluster's mode as **Node mode** in the cluster list. A workload whose saved rules are in monitor mode carries the badge **monitor**.

**Turn on protection…** is available once a workload has been watched for 24 hours, classified, and given its rules. Until then the console shows **Watched for under 24 hours**, and a saved draft records what it would deny in the meantime.

A protected workload's rules apply on the nodes running it whatever the node mode.

## The brake

The cluster owner holds a switch that AuthFI cannot override. It is a field on the install's `AgentRuntime` resource.

```yaml
spec:
  enforcementInhibit: true
```

With the brake on, the nodes stop denying. Everything is still monitored and recorded, so you can see what is happening while it is on. Take the brake off, and the rules in force resume.

The brake is set in the cluster, by whoever administers the cluster. Clearing it is done in the cluster too: the AuthFI console and control plane have no control over it.

## How rules reach a node

Rules reach a node within 30 seconds of a change: turning protection on, or saving new rules for a protected workload. A revocation reaches the node the same way, and is then checked on every request.

A node keeps deciding when something around it is unavailable.

| Situation                                     | What the node does                                                    |
| --------------------------------------------- | --------------------------------------------------------------------- |
| Your project cannot be reached                | Keeps enforcing the last rules it received                            |
| The node agent restarts, or is upgraded       | Rules in force stay in force. The programs stay loaded in the kernel. |
| A node agent has started and has no rules yet | Answers `503` with `Retry-After`                                      |
| A workload is not yet known                   | Left alone                                                            |

A node agent with no rules answers `503` so that no request is decided by a guess.

## Connections that are already open

A connection already open when a workload is switched to enforce mode is left alone until it closes. Rules apply to connections opened afterwards.

To have a workload's existing connections checked at once, restart the workload.

## What is recorded

Every denial, in the kernel or at the proxy, is an entry in the [audit record](/security/audit) with the layer that denied it.

**Security > Signals** counts denials by cause and by the gate that denied, so you can see which rules are doing the denying. Choose **Last 24 hours**, **Last 7 days** or **Last 30 days**. The table has the columns **Cause**, **Refused at** and **Refusals**.

## Next steps

<Cards>
  <Card href="/zero-code/install" title="Install Zero-Code on a cluster">
    Connect a cluster with the command the console gives you.
  </Card>
  <Card href="/zero-code/protect-ui" title="Protect a web app">
    Put sign-in in front of a service people open in a browser.
  </Card>
  <Card href="/zero-code/protect-api" title="Protect an API">
    Require an access token, and write a rule for each route.
  </Card>
  <Card href="/agents/revocation" title="Stop an agent">
    Revoke an AI agent, and have the nodes deny its remaining tokens.
  </Card>
</Cards>
