Skip to main content

Configuration and Deployment

Introduction

This document covers environment variables, Docker deployment, Ansible integration, CI/CD pipeline, and troubleshooting for the sensor agent.


Environment Variables

VariableRequiredDefaultDescription
SENSOR_IDYesUUID of the sensor, assigned by the backend when the sensor is created
BACKEND_URLYesBackend API base URL (e.g., http://10.10.10.70:5009)
INSTALL_TOKENFirst run onlyOne-time enrollment token generated by the frontend
SENSOR_TOKENAfter enrollmentDurable token received from enrollment, persisted to config file
HEARTBEAT_INTERVALNo30Heartbeat interval in seconds
SENSOR_PORTNo22SSH port on the sensor host (reported to backend for Ansible access)
CONFIG_FILENo/etc/ravenxcope/sensor-agent.envPath where the sensor token is persisted
HOST_OS_RELEASE_FILENo/host-os-releaseBind-mounted host /etc/os-release for OS detection
HOST_HOSTNAME_FILENo/host-hostnameBind-mounted host /etc/hostname for hostname detection

Docker Deployment

Build Image

docker build -t sensor-agent:latest .

The Dockerfile uses a multi-stage build:

  1. Builder stage (golang:1.22-alpine):

    • Downloads Go module dependencies
    • Builds a static binary with CGO_ENABLED=0
  2. Runtime stage (alpine:latest):

    • Copies the static binary
    • Adds ca-certificates for 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:

FlagPurpose
--network hostRequired for accurate host network interface detection
-v /etc/os-release:/host-os-release:roHost OS detection instead of container OS
-v /etc/hostname:/host-hostname:roHost hostname instead of container hostname
-v /etc/ravenxcope:/etc/ravenxcopePersistent storage for sensor token
--restart unless-stoppedAuto-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:

  1. Connects to the sensor host via SSH.
  2. Creates the .env.sensor-agent file with proper configuration.
  3. Pulls and starts the Docker container.
  4. 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:

StageBranchImage Tag
build-devdeveloplatest-dev, <commit-sha>
buildmainlatest, <commit-sha>

Both stages:

  1. Login to GitLab Container Registry.
  2. Build multi-platform image (linux/amd64) using docker buildx.
  3. Push with both latest* and commit SHA tags.

Running Tests

cd ravenxcope-sensor-agent
go test -v ./...

Current test coverage:

TestVerifies
TestPersistSensorTokenCreatesMissingConfigFileToken persistence creates parent directories and writes correctly
TestPersistSensorTokenUpdatesExistingConfigFileToken replacement and INSTALL_TOKEN commenting work on existing config
TestOsInfoFromFilesPrefersHostMetadataHost OS release file is preferred over container OS release
TestHostnameFromFilesPrefersHostMetadataHost 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

  1. Check backend connectivity:
    curl -v http://<BACKEND_URL>/api/sensors/<SENSOR_ID>/agent/heartbeat
  2. Check the sensor token is valid — it may have been revoked on the backend.
  3. 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.