Skip to main content

Running the Agent in Docker & Kubernetes

The EntryGuard Agent is available as a multi-arch Docker image (amd64 + arm64), suitable for Docker Compose, Kubernetes, and any container runtime.

docker pull ghcr.io/entropy8-io/eg-agent:latest
Image tags
  • ghcr.io/entropy8-io/eg-agent:latest — latest release
  • ghcr.io/entropy8-io/eg-agent:0.6.2 — pinned version (recommended for production)

The image is Alpine-based with bash included for script execution.

Prerequisites

Before deploying, you'll need:

  1. An API key with the agent:connect scope (create in Settings → API Keys)
  2. A script directory with apply/ and revoke/ subdirectories (see Script Directories)
  3. A config file (config.yml) — see Configuration Reference

Docker Compose

1. Create the directory structure

eg-agent/
├── docker-compose.yml
├── config.yml
└── scripts/
└── my-resource/
├── apply/
│ └── 01-ufw.sh
└── revoke/
└── 01-ufw.sh

2. Write the config file

config.yml
server:
url: "https://app.entryguard.io/api/v1"
api_key: "eg_your_api_key_here"

agent:
name: "docker-agent"

execution:
timeout: 30s
shell: "/bin/bash"

3. Write your scripts

scripts/my-resource/apply/01-ufw.sh
#!/bin/bash
set -euo pipefail
CIDR="$1"
echo "Applied $CIDR"
# Your apply logic here
scripts/my-resource/revoke/01-ufw.sh
#!/bin/bash
set -euo pipefail
CIDR="$1"
echo "Revoked $CIDR"
# Your revoke logic here

Make the scripts executable:

chmod +x scripts/my-resource/apply/*.sh scripts/my-resource/revoke/*.sh

4. Create docker-compose.yml

docker-compose.yml
services:
eg-agent:
image: ghcr.io/entropy8-io/eg-agent:latest
container_name: eg-agent
restart: unless-stopped
volumes:
- ./config.yml:/etc/eg-agent/config.yml:ro
- ./scripts:/etc/eg-agent/scripts:ro

5. Start the agent

docker compose up -d

Check logs:

docker compose logs -f eg-agent

You should see:

eg-agent  | 2026/04/02 10:00:00 eg-agent 0.6.2 starting (name=docker-agent)
eg-agent | 2026/04/02 10:00:00 registered as docker-agent (id=..., status=ONLINE)
eg-agent | 2026/04/02 10:00:00 [poller] polling enabled (script directories configured per resource)

6. Configure the resource in EntryGuard

In the dashboard, create a resource with:

  • Provider: AGENT
  • Type: Script
  • Script Directory: /etc/eg-agent/scripts/my-resource (the path inside the container)

With tunnel mode

To enable tunnel mode alongside script execution, add the tunnel config:

config.yml
server:
url: "https://app.entryguard.io/api/v1"
api_key: "eg_your_api_key_here"

agent:
name: "docker-agent"

execution:
timeout: 30s
shell: "/bin/bash"

tunnel:
enabled: true
edge_url: "wss://edge.entryguard.io"

With host network access

If your scripts need to manage the host's firewall (iptables, ufw), the container needs host network access and elevated privileges:

docker-compose.yml
services:
eg-agent:
image: ghcr.io/entropy8-io/eg-agent:latest
container_name: eg-agent
restart: unless-stopped
network_mode: host
privileged: true
volumes:
- ./config.yml:/etc/eg-agent/config.yml:ro
- ./scripts:/etc/eg-agent/scripts:ro
warning

privileged: true and network_mode: host grant the container full access to the host. Only use this when the scripts need to modify host-level networking (iptables, ufw, nftables). For scripts that call APIs or modify files, the default container networking is sufficient.


Kubernetes

1. Create the Secret for config

kubectl create secret generic eg-agent-config \
--from-file=config.yml=config.yml

Or with a manifest:

secret.yml
apiVersion: v1
kind: Secret
metadata:
name: eg-agent-config
type: Opaque
stringData:
config.yml: |
server:
url: "https://app.entryguard.io/api/v1"
api_key: "eg_your_api_key_here"
agent:
name: "k8s-agent"
execution:
timeout: 30s
shell: "/bin/bash"
kubectl apply -f secret.yml

2. Create the ConfigMap for scripts

scripts-configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: eg-agent-scripts
data:
01-apply.sh: |
#!/bin/bash
set -euo pipefail
CIDR="$1"
echo "Applied $CIDR"
# Your apply logic here

01-revoke.sh: |
#!/bin/bash
set -euo pipefail
CIDR="$1"
echo "Revoked $CIDR"
# Your revoke logic here
kubectl apply -f scripts-configmap.yml

3. Deploy the agent

deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: eg-agent
labels:
app: eg-agent
spec:
replicas: 1
selector:
matchLabels:
app: eg-agent
template:
metadata:
labels:
app: eg-agent
spec:
containers:
- name: eg-agent
image: ghcr.io/entropy8-io/eg-agent:0.6.2
resources:
requests:
cpu: 50m
memory: 32Mi
limits:
cpu: 200m
memory: 64Mi
volumeMounts:
- name: config
mountPath: /etc/eg-agent/config.yml
subPath: config.yml
readOnly: true
- name: apply-scripts
mountPath: /etc/eg-agent/scripts/my-resource/apply
readOnly: true
- name: revoke-scripts
mountPath: /etc/eg-agent/scripts/my-resource/revoke
readOnly: true
volumes:
- name: config
secret:
secretName: eg-agent-config
- name: apply-scripts
configMap:
name: eg-agent-scripts
defaultMode: 0755
items:
- key: 01-apply.sh
path: 01-apply.sh
- name: revoke-scripts
configMap:
name: eg-agent-scripts
defaultMode: 0755
items:
- key: 01-revoke.sh
path: 01-revoke.sh
kubectl apply -f deployment.yml

4. Verify

kubectl logs -f deployment/eg-agent

5. Configure the resource in EntryGuard

Set the Script Directory to /etc/eg-agent/scripts/my-resource (the path inside the container).

Using Helm values for multiple resources

For multiple resources with different scripts, create separate ConfigMaps and mount them to different paths:

volumeMounts:
- name: config
mountPath: /etc/eg-agent/config.yml
subPath: config.yml
readOnly: true
- name: webserver-apply
mountPath: /etc/eg-agent/scripts/webserver/apply
readOnly: true
- name: webserver-revoke
mountPath: /etc/eg-agent/scripts/webserver/revoke
readOnly: true
- name: database-apply
mountPath: /etc/eg-agent/scripts/database/apply
readOnly: true
- name: database-revoke
mountPath: /etc/eg-agent/scripts/database/revoke
readOnly: true

Then configure two resources in EntryGuard:

  • webserver: Script Directory = /etc/eg-agent/scripts/webserver
  • database: Script Directory = /etc/eg-agent/scripts/database
Do not use DaemonSets

Running the agent as a DaemonSet (one pod per node) is not supported. Each agent instance registers with the same name and they will overwrite each other's registration, causing heartbeat conflicts and missed commands. Always use a single-replica Deployment.

If you need to manage node-level firewall rules, install the agent binary directly on each node instead of using containers — see Installation & Setup.


Troubleshooting

Container exits immediately

Check logs:

docker compose logs eg-agent
# or
kubectl logs deployment/eg-agent

Common causes:

  • Config file not mounted — verify the volume mount path
  • Invalid API key — check server.api_key in config.yml
  • Missing agent nameagent.name is required

Scripts not executing

  • Verify the Script Directory is set on the resource in the EntryGuard dashboard
  • The path must match the mount path inside the container (e.g., /etc/eg-agent/scripts/my-resource)
  • Ensure scripts are executable (chmod +x or defaultMode: 0755 in ConfigMap)
  • Scripts must follow the NN- naming convention (e.g., 01-apply.sh)

Permission denied on scripts

In Kubernetes, set defaultMode: 0755 on the ConfigMap volume. In Docker Compose, ensure the host files are executable before mounting.