Skip to main content
Datadog Agent with Tero Edge
Deploy Tero Edge alongside your Datadog Agent to apply policies to logs, metrics, and traces before they leave your cluster.

How it works

Edge runs as a DaemonSet on each node. The Datadog Agent sends logs through Edge instead of directly to Datadog. Edge applies policies and forwards to Datadog. Edge only proxies telemetry (logs, metrics, traces). Other agent traffic (security monitoring, remote config, fleet management) goes directly to Datadog.

Prerequisites

  • Datadog Agent running on Kubernetes (via Helm or Datadog Operator)
  • kubectl access to your cluster
  • Tero account

Connect

1

Create an Edge API key

Open your terminal and run:
tero
Navigate to EdgeAPI KeysCreate. Name your key (e.g., “Production cluster”). Copy the key when shown—it’s only displayed once.
2

Create the namespace and secret

Create the namespace and store your API key as a Kubernetes secret:
kubectl create namespace tero-system

kubectl create secret generic tero-edge \
  --namespace tero-system \
  --from-literal=api-key=YOUR_API_KEY
3

Create the Edge ConfigMap

Create a ConfigMap with your Edge configuration. Select your Datadog region:
tero-edge-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: tero-edge-config
  namespace: tero-system
data:
  config.json: |
    {
      "listen_address": "0.0.0.0",
      "listen_port": 8080,
      "upstream_url": "https://agent-http-intake.logs.datadoghq.com",
      "metrics_url": "https://api.datadoghq.com",
      "workspace_id": "90A6EFC2-27B8-41BC-9343-43BFB1DF0732",
      "log_level": "info",
      "max_body_size": 1048576,
      "policy_providers": [
        {
          "id": "tero",
          "type": "http",
          "url": "https://sync.usetero.com/v1/policy/sync",
          "headers": [
            { "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" }
          ]
        }
      ]
    }
If you prefer to manage policies locally instead of syncing from Tero, use a file provider. Add policies.json to your ConfigMap:
tero-edge-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: tero-edge-config
  namespace: tero-system
data:
  config.json: |
    {
      "listen_address": "0.0.0.0",
      "listen_port": 8080,
      "upstream_url": "https://agent-http-intake.logs.datadoghq.com",
      "metrics_url": "https://api.datadoghq.com",
      "workspace_id": "90A6EFC2-27B8-41BC-9343-43BFB1DF0732",
      "log_level": "info",
      "max_body_size": 1048576,
      "policy_providers": [
        {
          "id": "file",
          "type": "file",
          "path": "/etc/tero/policies.json"
        }
      ]
    }
  policies.json: |
    {
      "policies": [
        {
          "id": "drop-debug-logs",
          "name": "drop-debug-logs",
          "enabled": true,
          "log": {
            "match": [{ "log_field": "severity_text", "regex": "DEBUG" }],
            "keep": "none"
          }
        }
      ]
    }
Update upstream_url and metrics_url for your Datadog region.
kubectl apply -f tero-edge-config.yaml
4

Deploy the Edge DaemonSet

Deploy Edge to run on each node:
tero-edge-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: tero-edge
  namespace: tero-system
  labels:
    app: tero-edge
spec:
  selector:
    matchLabels:
      app: tero-edge
  template:
    metadata:
      labels:
        app: tero-edge
    spec:
      containers:
        - name: tero-edge
          image: ghcr.io/usetero/edge:latest
          args:
            - /etc/tero/config.json
          env:
            - name: TERO_API_KEY
              valueFrom:
                secretKeyRef:
                  name: tero-edge
                  key: api-key
          ports:
            - containerPort: 8080
              hostPort: 8080
              protocol: TCP
          resources:
            requests:
              cpu: 50m
              memory: 32Mi
            limits:
              cpu: 200m
              memory: 64Mi
          volumeMounts:
            - name: tero-edge-config
              mountPath: /etc/tero
              readOnly: true
          livenessProbe:
            httpGet:
              path: /_health
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /_health
              port: 8080
            initialDelaySeconds: 2
            periodSeconds: 5
      volumes:
        - name: tero-edge-config
          configMap:
            name: tero-edge-config
      tolerations:
        - operator: Exists
kubectl apply -f tero-edge-daemonset.yaml
5

Configure the Datadog Agent

Point the Datadog Agent’s log output to Edge running on the same node.
Add to your DatadogAgent CR:
spec:
  features:
    logCollection:
      enabled: true
  override:
    nodeAgent:
      env:
        - name: HOST_IP
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        - name: DD_LOGS_CONFIG_LOGS_DD_URL
          value: "http://$(HOST_IP):8080"
      tolerations:
        - operator: Exists
The HOST_IP variable ensures the agent sends to the Edge instance on the same node via the hostPort.
6

Verify

Check that Edge pods are running:
kubectl get pods -n tero-system -l app=tero-edge
Check Edge logs for incoming traffic:
kubectl logs -n tero-system -l app=tero-edge --tail=50

Policy providers

Edge supports multiple policy sources. Configure them in the policy_providers array in your ConfigMap.

File provider

Load policies from a local file. Good for static policies bundled in the ConfigMap.
{
  "id": "file",
  "type": "file",
  "path": "/etc/tero/policies.json"
}

HTTP provider

Fetch policies from a remote endpoint. Good for dynamic policies managed via the Tero API.
{
  "id": "tero",
  "type": "http",
  "url": "https://sync.usetero.com/v1/policy/sync",
  "headers": [{ "name": "Authorization", "value": "Bearer ${TERO_API_KEY}" }]
}
The ${TERO_API_KEY} variable is injected from the Kubernetes secret via the DaemonSet environment configuration.

Example policies

Add policies to the policies.json section of your ConfigMap:
{
  "policies": [
    {
      "id": "drop-debug-logs",
      "name": "drop-debug-logs",
      "enabled": true,
      "log": {
        "match": [{ "log_field": "severity_text", "regex": "DEBUG" }],
        "keep": "none"
      }
    },
    {
      "id": "drop-nginx-source",
      "name": "drop-nginx-source",
      "enabled": true,
      "log": {
        "match": [{ "log_attribute": "ddsource", "regex": "nginx" }],
        "keep": "none"
      }
    },
    {
      "id": "keep-errors",
      "name": "keep-errors",
      "enabled": true,
      "log": {
        "match": [
          { "log_field": "severity_text", "regex": "error" },
          { "log_field": "severity_text", "regex": "critical" }
        ],
        "keep": "all"
      }
    }
  ]
}
See Policy Reference for all filtering options.

Troubleshooting

Agent can’t reach Edge Verify Edge is listening on the hostPort:
kubectl get pods -n tero-system -l app=tero-edge -o wide
Ensure both the agent and Edge have matching tolerations so they run on the same nodes. Policies not applying Check Edge loaded policies successfully:
kubectl logs -n tero-system -l app=tero-edge | grep -i policy
Traffic not reaching Datadog Verify upstream_url matches your Datadog region. Check Edge logs for upstream connection errors.