Configuration and Deployment
Introduction
This document covers environment variables, Docker deployment, Ansible integration, CI/CD pipeline, and troubleshooting for the sensor agent.
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
SENSOR_ID | Yes | — | UUID of the sensor, assigned by the backend when the sensor is created |
BACKEND_URL | Yes | — | Backend API base URL (e.g., http://10.10.10.70:5009) |
INSTALL_TOKEN | First run only | — | One-time enrollment token generated by the frontend |
SENSOR_TOKEN | After enrollment | — | Durable token received from enrollment, persisted to config file |
HEARTBEAT_INTERVAL | No | 30 | Heartbeat interval in seconds |
SENSOR_PORT | No | 22 | SSH port on the sensor host (reported to backend for Ansible access) |
CONFIG_FILE | No | /etc/ravenxcope/sensor-agent.env | Path where the sensor token is persisted |
HOST_OS_RELEASE_FILE | No | /host-os-release | Bind-mounted host /etc/os-release for OS detection |
HOST_HOSTNAME_FILE | No | /host-hostname | Bind-mounted host /etc/hostname for hostname detection |
Docker Deployment
Build Image
docker build -t sensor-agent:latest .
The Dockerfile uses a multi-stage build:
-
Builder stage (
golang:1.22-alpine):- Downloads Go module dependencies
- Builds a static binary with
CGO_ENABLED=0
-
Runtime stage (
alpine:latest):- Copies the static binary
- Adds
ca-certificatesfor HTTPS support - Runs as root (required for network interface enumeration)
Run with Docker
docker run -d \
--name sensor-agent \
--restart unless-stopped \
--network host \
-v /etc/os-release:/host-os-release:ro \
-v /etc/hostname:/host-hostname:ro \
-v /etc/ravenxcope:/etc/ravenxcope \
-e SENSOR_ID=your-sensor-uuid \
-e BACKEND_URL=http://10.10.10.70:5009 \
-e INSTALL_TOKEN=one-time-token \
-e HEARTBEAT_INTERVAL=30 \
--deploy-resources-limits-cpus=0.5 \
--deploy-resources-limits-memory=256M \
sensor-agent:latest
Key Docker flags:
| Flag | Purpose |
|---|---|
--network host | Required for accurate host network interface detection |
-v /etc/os-release:/host-os-release:ro | Host OS detection instead of container OS |
-v /etc/hostname:/host-hostname:ro | Host hostname instead of container hostname |
-v /etc/ravenxcope:/etc/ravenxcope | Persistent storage for sensor token |
--restart unless-stopped | Auto-restart after host reboot |
Docker Compose
The agent is part of the sensor stack in docker-compose.yml:
sensor-agent:
image: exdec/sensor-agent:latest
restart: unless-stopped
network_mode: host
volumes:
- /etc/os-release:/host-os-release:ro
- /etc/hostname:/host-hostname:ro
- /etc/ravenxcope:/etc/ravenxcope
env_file:
- .env.sensor-agent
deploy:
resources:
limits:
cpus: "0.5"
memory: 256M
Ansible Integration
The sensor agent is automatically deployed via Ansible when a sensor is activated from the frontend. The Ansible playbook:
- Connects to the sensor host via SSH.
- Creates the
.env.sensor-agentfile with proper configuration. - Pulls and starts the Docker container.
- Verifies the agent is running.
Example Ansible task:
- name: Create sensor agent env file
copy:
dest: /opt/sensor/.env.sensor-agent
content: |
SENSOR_ID={{ sensor_uuid }}
BACKEND_URL={{ backend_url }}
INSTALL_TOKEN={{ install_token }}
HEARTBEAT_INTERVAL=30
After the agent enrolls, the INSTALL_TOKEN is consumed and SENSOR_TOKEN is persisted. Subsequent container restarts do not require the install token.
CI/CD Pipeline
The GitLab CI pipeline has two stages:
| Stage | Branch | Image Tag |
|---|---|---|
build-dev | develop | latest-dev, <commit-sha> |
build | main | latest, <commit-sha> |
Both stages:
- Login to GitLab Container Registry.
- Build multi-platform image (
linux/amd64) usingdocker buildx. - Push with both
latest*and commit SHA tags.
Running Tests
cd ravenxcope-sensor-agent
go test -v ./...
Current test coverage:
| Test | Verifies |
|---|---|
TestPersistSensorTokenCreatesMissingConfigFile | Token persistence creates parent directories and writes correctly |
TestPersistSensorTokenUpdatesExistingConfigFile | Token replacement and INSTALL_TOKEN commenting work on existing config |
TestOsInfoFromFilesPrefersHostMetadata | Host OS release file is preferred over container OS release |
TestHostnameFromFilesPrefersHostMetadata | Host hostname file is preferred over container hostname |
Building from Source
# Install Go 1.22+
go mod download
go build -o sensor-agent .
# Run locally
export SENSOR_ID=test-sensor-uuid
export BACKEND_URL=http://localhost:5009
export INSTALL_TOKEN=test-install-token
export HEARTBEAT_INTERVAL=5
./sensor-agent
Troubleshooting
Agent exits with "SENSOR_ID is required"
The SENSOR_ID environment variable is missing. This is the UUID assigned by the backend when the sensor is created in the frontend.
Agent exits with "INSTALL_TOKEN is required for first enrollment"
On first startup, the agent needs an install token to enroll. This token is generated from the sensor detail page in the frontend ("Generate Install Command").
Agent logs "heartbeat failed" repeatedly
- Check backend connectivity:
curl -v http://<BACKEND_URL>/api/sensors/<SENSOR_ID>/agent/heartbeat
- Check the sensor token is valid — it may have been revoked on the backend.
- Check network connectivity from the sensor host to the defense center.
Agent reports wrong hostname or OS
The agent reads host metadata from bind-mounted files. Verify the volumes are mounted:
docker inspect sensor-agent | grep -A5 Mounts
Expected mounts:
/etc/os-release→/host-os-release(read-only)/etc/hostname→/host-hostname(read-only)
Agent shows only container interfaces
The agent must run with --network host to see host network interfaces. Verify:
docker inspect sensor-agent --format '{{.HostConfig.NetworkMode}}'
# Expected: host
Sensor token not persisted after restart
Check the /etc/ravenxcope volume mount:
cat /etc/ravenxcope/sensor-agent.env
The file should contain SENSOR_TOKEN=... after successful enrollment. If it does not exist, the volume may not be mounted, and the agent will re-enroll on every restart.