Deployment

From one container to a hardened cluster.

DFENS is a single static binary in a distroless container that runs as a non-root user. The same image runs under docker run, Docker Compose, or Kubernetes. What changes is how you supply config, state, and network isolation.

The image

Private early access

There is no public image yet. Approved design partners are issued a registry credential and an image reference; request access to be onboarded. The examples below use REGISTRY/ai-firewall:<tag> as a placeholder. Substitute the reference you're given (and, for a private registry, configure the corresponding pull credentials).

What the image provides and expects:

AspectValue
BaseDistroless, runs as nonroot, no shell.
Ports8080 (proxy + inspect), 9090 (metrics).
Config/etc/ai-firewall/config.yaml (a minimal default ships in the image).
Rules/etc/ai-firewall/rules.d/ + registry.yaml, baked in.
StateA writable dir for the audit sequencer, ruleset cache, and disable overlay.
HealthGET /health, always 200. Parse the body.

Single container

The fastest way to see it work is to mount a config, publish the ports, and give it a writable state volume:

docker run
docker run --rm \
  -p 8080:8080 -p 9090:9090 \
  -v "$PWD/config.yaml:/etc/ai-firewall/config.yaml:ro" \
  -v ai-firewall-data:/data \
  REGISTRY/ai-firewall:<tag>

# In another shell — confirm it's up
curl -s localhost:8080/health
{"status":"ok","ready":true,"degraded_rules":[],"disabled_rules":[]}

A minimal config.yaml is on the Configuration page. Set server.state_dir: "/data" so the writable volume is actually used. The default state path is not writable under the read-only root filesystem.

Docker Compose

Compose is the simplest way to run DFENS alongside its optional admin console (a web UI for managing rulesets and reviewing decisions across instances). The repository ships a reference stack under examples/compose-admin/: a firewall instance, the admin service, and profiles for Postgres-backed state and auto-scaling replicas.

docker-compose.yaml (excerpt)
services:
  firewall:
    image: REGISTRY/ai-firewall:<tag>
    ports:
      - "127.0.0.1:8080:8080"     # bind loopback: keep the listener private
    volumes:
      - ./config/firewall.yaml:/etc/ai-firewall/config.yaml:ro
      - firewall-data:/data
    environment:
      AI_FIREWALL_ADMIN_TOKEN: ${AI_FIREWALL_ADMIN_TOKEN:?generate one}
      # Inbound client token (optional). Callers send it as X-AI-Firewall-Key.
      AI_FIREWALL_CLIENT_TOKEN: ${AI_FIREWALL_CLIENT_TOKEN:-}
    restart: unless-stopped

volumes:
  firewall-data:

The loopback bind (127.0.0.1:) keeps the listener private; set AI_FIREWALL_CLIENT_TOKEN to also require a client token on every request (see client authentication). The full rig, including the admin console and its one-time initialisation step, is documented in the example's own README.

Kubernetes

The repository ships a minimal, provider-agnostic manifest set under deploy/k8s/: a ConfigMap, a hardened two-replica Deployment with /health probes, a ClusterIP Service exposing the proxy and metrics ports, a NetworkPolicy, and a Secret template, wired together with Kustomize.

deploy/k8s
# 1. Point the Deployment at the image reference you were issued
sed -i 's|REGISTRY/ai-firewall:v0.6.1|your-registry/ai-firewall:<tag>|' deployment.yaml

# 2. (Optional) create the Secret: vault-mode provider keys, an admin token,
#    and/or the inbound client token (X-AI-Firewall-Key).
kubectl apply -f secret.example.yaml   # after editing in real values

# 3. Apply the whole stack
kubectl apply -k deploy/k8s

# 4. Confirm rollout and readiness
kubectl rollout status deploy/ai-firewall
kubectl port-forward svc/ai-firewall 8080:8080 &
curl -s localhost:8080/health

Two things in these manifests are load-bearing, not cosmetic:

The Deployment ships a hardened pod security context (non-root, all capabilities dropped, no privilege escalation) and probes both liveness and readiness against /health.

Status

These manifests are validated for structure but are a reviewed starting point, not a turnkey production artifact. They carry no Ingress and no cloud-specific annotations by design. Dry-run them against your cluster and fold them into your own Kustomize or Helm setup. The deploy/k8s/README.md documents every file and the customisation points.

Running your own rules

The image bakes in the default rule set. To run your own, load the rule files into a ConfigMap (or bake them into a derived image) and mount them over the rules directory:

custom rules on k8s
kubectl create configmap ai-firewall-rules --from-file=./rules/

Then add a volume and a volumeMount at /etc/ai-firewall/rules.d in the Deployment. A ConfigMap caps at 1 MiB total; for large rule sets use a PVC or a derived image instead.

ML operators (the fat image)

The default image is pure-Go and dependency-free. The ML-backed operators (@detectPromptInjectionML, @classify, @toxicity) live in a separate :fat image that loads ONNX models at startup.

Back to the overview, or revisit Configuration.