Skip to content

Security Best Practices

Thomas Mangin edited this page Nov 15, 2025 · 1 revision

Security Best Practices

Securing your ExaBGP deployment is critical, as BGP is a foundational protocol for network routing. This guide covers security hardening for ExaBGP in production environments.

Table of Contents

Overview

Important: ExaBGP does NOT manipulate the routing table (RIB/FIB) directly, but it does inject routes into BGP. Unauthorized access to ExaBGP can allow attackers to manipulate routing, cause traffic black-holing, or perform man-in-the-middle attacks.

Security Principles

  1. Authentication - Verify BGP peer identity
  2. Authorization - Limit what can be announced
  3. Integrity - Detect message tampering
  4. Confidentiality - Protect sensitive data (optional)
  5. Availability - Prevent DoS attacks
  6. Least Privilege - Run with minimal permissions
  7. Defense in Depth - Multiple security layers

Threat Model

Threats to consider:

  • Unauthorized BGP peering
  • Route hijacking via compromised ExaBGP
  • Denial of service attacks
  • Compromised API processes
  • Information disclosure
  • Man-in-the-middle attacks

Authentication

MD5 Authentication

MD5 authentication (RFC 2385) protects BGP sessions against spoofed packets and unauthorized peers.

Enabling MD5 Authentication

# /etc/exabgp/exabgp.conf

neighbor 192.0.2.1 {
    router-id 192.0.2.10;
    local-address 192.0.2.10;
    local-as 65001;
    peer-as 65001;

    # MD5 authentication
    md5-password "your-strong-password-here";

    family {
        ipv4 unicast;
    }
}

Strong Password Guidelines

# BAD: Weak password
md5-password "password123";

# BAD: Short password
md5-password "abc";

# GOOD: Strong random password
md5-password "K8$mP9#nQ2@vR5!wX7^yZ4&bC1";

# BEST: Use password from secure file
md5-password include "/etc/exabgp/secrets/neighbor-192.0.2.1.pwd";

Storing Passwords Securely

# Create secrets directory
mkdir -p /etc/exabgp/secrets
chmod 700 /etc/exabgp/secrets

# Generate strong password
openssl rand -base64 32 > /etc/exabgp/secrets/neighbor-192.0.2.1.pwd
chmod 600 /etc/exabgp/secrets/neighbor-192.0.2.1.pwd
chown exabgp:exabgp /etc/exabgp/secrets/neighbor-192.0.2.1.pwd

# Password content (example)
cat /etc/exabgp/secrets/neighbor-192.0.2.1.pwd
# K8$mP9#nQ2@vR5!wX7^yZ4&bC1

Configuration with Password File

neighbor 192.0.2.1 {
    router-id 192.0.2.10;
    local-address 192.0.2.10;
    local-as 65001;
    peer-as 65001;

    # Load password from secure file
    md5-password include "/etc/exabgp/secrets/neighbor-192.0.2.1.pwd";

    family {
        ipv4 unicast;
    }
}

Peer Verification

Always verify peer AS numbers and addresses:

neighbor 192.0.2.1 {
    # Verify peer identity
    peer-as 65001;  # Expected AS number

    # Only accept connections from this address
    local-address 192.0.2.10;

    # Prevent address spoofing
    md5-password "strong-password";
}

BGP Security Features

TTL Security (Generalized TTL Security Mechanism - GTSM)

GTSM (RFC 5082) prevents attacks from non-adjacent routers by requiring TTL=255.

neighbor 192.0.2.1 {
    router-id 192.0.2.10;
    local-address 192.0.2.10;
    local-as 65001;
    peer-as 65001;

    # Enable TTL security
    ttl-security 255;

    family {
        ipv4 unicast;
    }
}

How it works:

  • ExaBGP sends packets with TTL=255
  • Expects to receive packets with TTL=255
  • Rejects packets with TTL < 255
  • Effective against remote attackers (packets traversing routers will have TTL < 255)

Maximum Prefix Limits

Protect against route table overflow attacks:

neighbor 192.0.2.1 {
    router-id 192.0.2.10;
    local-address 192.0.2.10;
    local-as 65001;
    peer-as 65001;

    # Limit routes received from peer
    maximum-prefix {
        ipv4 unicast 10000;   # Max 10,000 IPv4 routes
        ipv6 unicast 5000;    # Max 5,000 IPv6 routes
    }

    family {
        ipv4 unicast;
        ipv6 unicast;
    }
}

Note: ExaBGP is primarily used for route announcement, not reception. This feature is most relevant when receive-routes is enabled.

Route Filtering

Filter what routes can be announced:

#!/usr/bin/env python3
# /etc/exabgp/announce-with-validation.py

import sys
import ipaddress

# Whitelist of allowed prefixes
ALLOWED_PREFIXES = [
    ipaddress.ip_network("198.51.100.0/24"),
    ipaddress.ip_network("203.0.113.0/24"),
]

def is_allowed_prefix(prefix_str):
    """Check if prefix is in whitelist"""
    try:
        prefix = ipaddress.ip_network(prefix_str)
        return any(prefix.subnet_of(allowed) for allowed in ALLOWED_PREFIXES)
    except:
        return False

def announce_route(prefix, next_hop):
    """Announce route only if allowed"""
    if is_allowed_prefix(prefix):
        print(f"announce route {prefix} next-hop {next_hop}", flush=True)
        sys.stderr.write(f"Announced allowed prefix: {prefix}\n")
    else:
        sys.stderr.write(f"SECURITY: Blocked unauthorized prefix: {prefix}\n")

# Example usage
announce_route("198.51.100.0/24", "192.0.2.10")  # Allowed
announce_route("10.0.0.0/8", "192.0.2.10")       # Blocked

System Security

Run as Non-Root User

Never run ExaBGP as root. Create a dedicated user with minimal privileges.

Create ExaBGP User

# Create exabgp user and group
sudo groupadd -r exabgp
sudo useradd -r -g exabgp -s /bin/false -c "ExaBGP daemon" exabgp

# Create necessary directories
sudo mkdir -p /etc/exabgp
sudo mkdir -p /var/run/exabgp
sudo mkdir -p /var/log/exabgp

# Set ownership
sudo chown -R exabgp:exabgp /etc/exabgp
sudo chown -R exabgp:exabgp /var/run/exabgp
sudo chown -R exabgp:exabgp /var/log/exabgp

# Set permissions
sudo chmod 750 /etc/exabgp
sudo chmod 750 /var/run/exabgp
sudo chmod 750 /var/log/exabgp

Systemd Service Configuration

# /etc/systemd/system/exabgp.service

[Unit]
Description=ExaBGP
Documentation=https://github.com/Exa-Networks/exabgp/wiki
After=network.target

[Service]
Type=simple

# Security: Run as non-root user
User=exabgp
Group=exabgp

# Security: Restrict capabilities
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN

# Security: Filesystem protections
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/run/exabgp /var/log/exabgp
PrivateTmp=true

# Security: Namespace isolation
PrivateDevices=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true

# Security: System call filtering
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources

# ExaBGP command
ExecStart=/usr/local/bin/exabgp /etc/exabgp/exabgp.conf

# Restart policy
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Verify Non-Root Execution

# Start service
sudo systemctl start exabgp

# Check process user
ps aux | grep exabgp
# Should show 'exabgp' user, NOT 'root'

# Verify with systemd
sudo systemctl status exabgp

File Permissions

Restrict access to configuration files:

# Configuration files: readable only by exabgp user
chmod 640 /etc/exabgp/exabgp.conf
chown exabgp:exabgp /etc/exabgp/exabgp.conf

# Secrets: readable only by exabgp user
chmod 600 /etc/exabgp/secrets/*
chown exabgp:exabgp /etc/exabgp/secrets/*

# Scripts: executable by exabgp user
chmod 750 /etc/exabgp/*.py
chown exabgp:exabgp /etc/exabgp/*.py

# Logs: writable by exabgp user
chmod 750 /var/log/exabgp
chown exabgp:exabgp /var/log/exabgp

Disable Unnecessary Features

Only enable what you need:

neighbor 192.0.2.1 {
    router-id 192.0.2.10;
    local-address 192.0.2.10;
    local-as 65001;
    peer-as 65001;

    # Only enable required address families
    family {
        ipv4 unicast;  # Enable only what's needed
        # ipv6 unicast;  # Disabled if not needed
        # ipv4 flow;     # Disabled if not needed
    }

    # Disable unnecessary capabilities
    capability {
        add-path disable;           # Disable if not needed
        graceful-restart disable;   # Disable if not needed
    }
}

Network Security

Firewall Rules

Restrict BGP access to authorized peers only.

iptables Rules

#!/bin/bash
# /etc/exabgp/firewall-rules.sh

# BGP peers
PEER1="192.0.2.1"
PEER2="192.0.2.2"
LOCAL_IP="192.0.2.10"

# Default: DROP all BGP traffic
iptables -A INPUT -p tcp --dport 179 -j DROP
iptables -A OUTPUT -p tcp --sport 179 -j DROP

# Allow BGP from authorized peers only
iptables -I INPUT -s $PEER1 -d $LOCAL_IP -p tcp --dport 179 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -I INPUT -s $PEER2 -d $LOCAL_IP -p tcp --dport 179 -m state --state NEW,ESTABLISHED -j ACCEPT

# Allow BGP to authorized peers only
iptables -I OUTPUT -s $LOCAL_IP -d $PEER1 -p tcp --sport 179 -m state --state ESTABLISHED -j ACCEPT
iptables -I OUTPUT -s $LOCAL_IP -d $PEER2 -p tcp --sport 179 -m state --state ESTABLISHED -j ACCEPT

# Log dropped BGP attempts
iptables -A INPUT -p tcp --dport 179 -j LOG --log-prefix "DROPPED BGP: "

nftables Rules

#!/usr/sbin/nft -f
# /etc/exabgp/nftables.conf

table inet filter {
    set bgp_peers {
        type ipv4_addr
        elements = { 192.0.2.1, 192.0.2.2 }
    }

    chain input {
        type filter hook input priority 0; policy drop;

        # Allow established connections
        ct state established,related accept

        # Allow BGP from authorized peers only
        tcp dport 179 ip saddr @bgp_peers accept

        # Log and drop unauthorized BGP
        tcp dport 179 log prefix "DROPPED BGP: " drop
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

Source Address Validation

Bind to specific local addresses:

neighbor 192.0.2.1 {
    # Bind to specific local IP
    local-address 192.0.2.10;

    # This prevents accepting connections on other interfaces
    router-id 192.0.2.10;
    local-as 65001;
    peer-as 65001;
}

Dedicated Management Network

Use separate network for BGP management:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Production Network  β”‚
β”‚  (Data traffic)      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Management Network  β”‚  <- ExaBGP listens here
β”‚  (BGP peering)       β”‚
β”‚  192.0.2.0/24        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Configuration:

# Listen only on management interface
neighbor 192.0.2.1 {
    local-address 192.0.2.10;  # Management network
    # ...
}

API Security

Restrict API Process Execution

Only run trusted API processes:

process healthcheck {
    # Use absolute paths
    run /usr/local/bin/exabgp-healthcheck;

    # NOT: run /tmp/untrusted-script.py
}

Validate API Input

Sanitize input in API processes:

#!/usr/bin/env python3
# /etc/exabgp/secure-announce.py

import sys
import re
import ipaddress

def validate_route(prefix, next_hop):
    """Validate route before announcing"""

    # Validate prefix format
    try:
        network = ipaddress.ip_network(prefix)
    except ValueError:
        sys.stderr.write(f"SECURITY: Invalid prefix format: {prefix}\n")
        return False

    # Validate next-hop format
    try:
        next_hop_ip = ipaddress.ip_address(next_hop)
    except ValueError:
        sys.stderr.write(f"SECURITY: Invalid next-hop format: {next_hop}\n")
        return False

    # Check prefix is not too specific
    if network.prefixlen > 24:
        sys.stderr.write(f"SECURITY: Prefix too specific: {prefix}\n")
        return False

    # Check prefix is not default route
    if network.prefixlen == 0:
        sys.stderr.write(f"SECURITY: Cannot announce default route\n")
        return False

    return True

def announce_route(prefix, next_hop):
    if validate_route(prefix, next_hop):
        print(f"announce route {prefix} next-hop {next_hop}", flush=True)
    else:
        sys.stderr.write(f"SECURITY: Blocked invalid route: {prefix} -> {next_hop}\n")

# Example
announce_route("198.51.100.0/24", "192.0.2.10")  # Valid
announce_route("0.0.0.0/0", "192.0.2.10")        # Blocked (default route)
announce_route("198.51.100.0/32", "192.0.2.10")  # Blocked (too specific)

Prevent Command Injection

Never use shell commands with unsanitized input:

# BAD: Command injection vulnerability
route = user_input  # e.g., "198.51.100.0/24; rm -rf /"
os.system(f"echo 'announce route {route} next-hop self'")

# GOOD: Use safe API
print(f"announce route {validated_route} next-hop self", flush=True)

API Process Isolation

Run API processes with minimal privileges:

# Systemd service for API process
[Service]
User=exabgp-api
Group=exabgp-api
CapabilityBoundingSet=
PrivateDevices=true
ProtectKernelTunables=true
NoNewPrivileges=true

Monitoring and Logging

Enable Comprehensive Logging

# /etc/exabgp/exabgp.conf

# Logging configuration
log {
    all = true;
    destination = /var/log/exabgp/exabgp.log;
    level = INFO;
}

neighbor 192.0.2.1 {
    # ... neighbor config ...
}

Log Security Events

Monitor logs for security events:

# Monitor for authentication failures
tail -f /var/log/exabgp/exabgp.log | grep -i "authentication\|failed\|denied"

# Monitor for unexpected disconnections
tail -f /var/log/exabgp/exabgp.log | grep -i "down\|closed\|reset"

# Monitor for route changes
tail -f /var/log/exabgp/exabgp.log | grep -i "announce\|withdraw"

Centralized Logging

Send logs to SIEM or centralized logging:

# rsyslog configuration
# /etc/rsyslog.d/exabgp.conf

$ModLoad imfile
$InputFileName /var/log/exabgp/exabgp.log
$InputFileTag exabgp:
$InputFileStateFile exabgp-state
$InputFileSeverity info
$InputFileFacility local0
$InputRunFileMonitor

local0.* @@siem.example.com:514

Alerting

Set up alerts for security events:

#!/usr/bin/env python3
# /etc/exabgp/security-monitor.py

import sys
import re
import smtplib

def send_alert(message):
    """Send security alert email"""
    # Configure email settings
    smtp_server = "smtp.example.com"
    from_addr = "[email protected]"
    to_addr = "[email protected]"

    msg = f"Subject: ExaBGP Security Alert\n\n{message}"

    server = smtplib.SMTP(smtp_server)
    server.sendmail(from_addr, to_addr, msg)
    server.quit()

# Monitor ExaBGP logs
log_file = "/var/log/exabgp/exabgp.log"

with open(log_file, 'r') as f:
    for line in f:
        # Alert on authentication failures
        if re.search(r'authentication.*fail', line, re.IGNORECASE):
            send_alert(f"Authentication failure: {line}")

        # Alert on unexpected peer disconnections
        if re.search(r'peer.*down', line, re.IGNORECASE):
            send_alert(f"Peer disconnection: {line}")

Defense in Depth

Implement multiple layers of security:

Layer 1: Network Security

  • Firewall rules restricting BGP access
  • Network segmentation (management network)
  • DDoS protection

Layer 2: BGP Protocol Security

  • MD5 authentication
  • TTL security
  • Prefix limits

Layer 3: System Security

  • Non-root execution
  • File permissions
  • Systemd hardening

Layer 4: Application Security

  • Input validation
  • Route filtering
  • API security

Layer 5: Monitoring & Response

  • Comprehensive logging
  • Security alerting
  • Incident response procedures

Complete Secure Configuration Example

# /etc/exabgp/exabgp.conf - Hardened Configuration

# Logging
log {
    all = true;
    destination = /var/log/exabgp/exabgp.log;
    level = INFO;
}

# Secure API process
process healthcheck {
    run /usr/local/bin/exabgp-healthcheck;
    encoder text;
}

# Secure neighbor configuration
neighbor 192.0.2.1 {
    router-id 192.0.2.10;

    # Bind to specific local address
    local-address 192.0.2.10;

    # AS verification
    local-as 65001;
    peer-as 65001;

    # MD5 authentication
    md5-password include "/etc/exabgp/secrets/neighbor-192.0.2.1.pwd";

    # TTL security
    ttl-security 255;

    # Only enable required address families
    family {
        ipv4 unicast;
    }

    # Disable unnecessary capabilities
    capability {
        add-path disable;
    }

    # API process
    api {
        processes [ healthcheck ];
    }
}

Security Checklist

Use this checklist for production deployments:

Authentication & Authorization

  • MD5 authentication enabled on all peers
  • Strong passwords (32+ characters, random)
  • Passwords stored in separate files with 600 permissions
  • Peer AS numbers verified
  • Local/peer addresses explicitly configured

BGP Protocol Security

  • TTL security enabled (where supported)
  • Maximum prefix limits configured
  • Only required address families enabled
  • Unnecessary capabilities disabled
  • Route filtering implemented in API processes

System Security

  • ExaBGP runs as non-root user (exabgp)
  • Configuration files have 640 permissions
  • Secret files have 600 permissions
  • Scripts have 750 permissions
  • Systemd hardening enabled (ProtectSystem, PrivateTmp, etc.)

Network Security

  • Firewall rules restrict BGP to authorized peers
  • Local address binding configured
  • Management network separated from production
  • DDoS protection in place

API Security

  • Only trusted API processes configured
  • Absolute paths used for process execution
  • Input validation in API processes
  • No shell command injection vulnerabilities
  • API processes run with minimal privileges

Monitoring & Logging

  • Comprehensive logging enabled
  • Logs sent to centralized logging system
  • Security alerts configured
  • Log rotation configured
  • Regular log reviews scheduled

Operational Security

  • Configuration changes version controlled
  • Access to ExaBGP host restricted
  • Incident response procedures documented
  • Regular security audits scheduled
  • Security patches applied promptly

See Also


πŸ‘» Ghost written by Claude (Anthropic AI)

Clone this wiki locally