# 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](#overview) - [Authentication](#authentication) - [BGP Security Features](#bgp-security-features) - [System Security](#system-security) - [Network Security](#network-security) - [API Security](#api-security) - [Monitoring and Logging](#monitoring-and-logging) - [Defense in Depth](#defense-in-depth) - [Security Checklist](#security-checklist) - [See Also](#see-also) ## 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 ```ini # /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 ```ini # 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 ```bash # 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 ```ini 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: ```ini 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. ```ini 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 incoming-ttl 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: ```ini 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: ```python #!/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 ```bash # 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 ```ini # /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 ```bash # 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: ```bash # 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: ```ini 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 ```bash #!/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 ```bash #!/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: ```ini 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: ```ini # 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: ```ini 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: ```python #!/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: ```python # 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: ```ini # 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 ```ini # /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: ```bash # 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: ```bash # 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: ```python #!/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 = "exabgp@example.com" to_addr = "security@example.com" 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 ```ini # /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 incoming-ttl 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 - [Configuration Syntax](../Configuration/Configuration-Syntax) - ExaBGP configuration reference - [Debugging](Debugging) - Troubleshooting and diagnostics - [Monitoring](Monitoring) - Production monitoring - [Security Hardening](Security-Hardening) - System hardening guide - [BGP Security](https://www.rfc-editor.org/rfc/rfc7454.html) - RFC 7454: BGP Operations and Security ---