-
Notifications
You must be signed in to change notification settings - Fork 459
Security Hardening
Best practices for securing ExaBGP deployments
π Defense in depth - multiple layers of security protect your BGP infrastructure
- Overview
- Threat Model
- BGP Authentication
- Process Isolation
- User Permissions
- Firewall Rules
- Route Filtering
- API Security
- Audit Logging
- Attack Mitigation
- Security Checklist
β ExaBGP 5.0.0 Security Fix: TOCTOU (Time-of-Check-Time-of-Use) vulnerability fixed in configuration parser. Upgrading to 5.0.0 is recommended for security-conscious deployments.
ExaBGP 5.0.0 Security Enhancements:
- β TOCTOU Fix: Fixed race condition in configuration file parsing that could allow unauthorized config modifications
- β Configuration Reload Fix: Improved API process state consistency during reload operations (#1340)
- β Python 3.8+ Only: Removed Python 2 support (Python 2 has known security vulnerabilities and no updates)
Recommendation: Upgrade to ExaBGP 5.0.0 for latest security fixes. See 4.x β 5.0.0 Migration Guide.
ExaBGP security follows these principles:
- Authentication: Verify BGP peer identity
- Authorization: Control what peers can do
- Isolation: Separate privileges and processes
- Monitoring: Detect suspicious activity
- Defense in Depth: Multiple security layers
Where ExaBGP can be attacked:
Component Attack Vectors
-----------------------------------------
BGP sessions Spoofing, MITM, session hijacking
API processes Code injection, privilege escalation
Configuration files Unauthorized modification
Log files Information disclosure
Network interfaces Eavesdropping, packet injection
Process memory Buffer overflows (unlikely in Python)
1. Network Threats
- BGP session hijacking
- TCP connection spoofing
- Man-in-the-middle attacks
- Route injection/hijacking
- Denial of service
2. Local Threats
- Privilege escalation
- Configuration tampering
- API process exploitation
- Log file manipulation
- Resource exhaustion
3. Application Threats
- Malicious API processes
- Code injection
- Dependency vulnerabilities
- Configuration errors
High Risk:
- Unauthenticated BGP sessions
- Running as root
- World-writable configuration files
- No firewall rules
- Unvalidated route announcements
Medium Risk:
- Weak MD5 passwords
- Verbose logging with sensitive data
- Shared user accounts
- No audit trail
Low Risk:
- Outdated ExaBGP version (rare vulnerabilities)
- Default configuration paths
Configure MD5 authentication:
# ExaBGP configuration
neighbor 192.168.1.1 {
router-id 192.168.1.2;
local-address 192.168.1.2;
local-as 65001;
peer-as 65000;
# MD5 password (RFC 2385)
md5-password "SuperSecretPassword123!";
family {
ipv4 unicast;
}
}Corresponding router configuration (Cisco):
router bgp 65000
neighbor 192.168.1.2 remote-as 65001
neighbor 192.168.1.2 password SuperSecretPassword123!
Corresponding router configuration (Juniper):
protocols {
bgp {
group exabgp {
neighbor 192.168.1.2 {
authentication-key "SuperSecretPassword123!";
}
}
}
}
Best practices:
1. Use strong passwords:
# Generate strong password (20 characters)
openssl rand -base64 20
# Example output:
# VXk3dGF3Zm9zNHMxMmRhc2Rhc2Q=2. Store passwords securely:
# Don't commit passwords to Git!
# Use environment variables or secrets management
# .gitignore
*.secret
secrets/
# Store in separate file
cat > /etc/exabgp/secrets/peer-password.txt <<EOF
VXk3dGF3Zm9zNHMxMmRhc2Rhc2Q=
EOF
chmod 600 /etc/exabgp/secrets/peer-password.txt
chown exabgp:exabgp /etc/exabgp/secrets/peer-password.txt3. Reference password from file:
#!/bin/bash
# Generate config with password from secret file
PASSWORD=$(cat /etc/exabgp/secrets/peer-password.txt)
cat > /etc/exabgp/exabgp.conf <<EOF
neighbor 192.168.1.1 {
md5-password "${PASSWORD}";
}
EOFMore secure alternative to MD5 (RFC 5925):
Note: TCP-AO support depends on OS kernel version (Linux 5.12+)
# Check if kernel supports TCP-AO
grep TCP_AO /boot/config-$(uname -r)Configuration (when supported):
neighbor 192.168.1.1 {
# TCP-AO is more secure than MD5
# Check ExaBGP documentation for current support status
tcp-ao {
key-id 1;
recv-id 1;
algorithm hmac-sha-256;
password "StrongPassword123!";
}
}Generalized TTL Security Mechanism (RFC 5082):
Protects against remote attacks by requiring TTL=255 (directly connected peers).
ExaBGP configuration:
neighbor 192.168.1.1 {
router-id 192.168.1.2;
local-as 65001;
peer-as 65000;
# TTL must be 255 (directly connected)
ttl-security 255;
}Router configuration (Cisco):
router bgp 65000
neighbor 192.168.1.2 ttl-security hops 1
Router configuration (Juniper):
protocols {
bgp {
group exabgp {
neighbor 192.168.1.2 {
multihop {
ttl 255;
}
}
}
}
}
Never run ExaBGP as root!
Create dedicated user:
# Create exabgp user (no login shell)
useradd -r -s /bin/false -d /var/lib/exabgp exabgp
# Create directories
mkdir -p /etc/exabgp /var/log/exabgp /var/lib/exabgp
# Set ownership
chown -R exabgp:exabgp /etc/exabgp /var/log/exabgp /var/lib/exabgp
# Set permissions
chmod 750 /etc/exabgp
chmod 750 /var/log/exabgp
chmod 750 /var/lib/exabgpSecure systemd service configuration:
# /etc/systemd/system/exabgp.service
[Unit]
Description=ExaBGP
After=network.target
Documentation=https://github.com/Exa-Networks/exabgp
[Service]
Type=simple
ExecStart=/usr/local/bin/exabgp /etc/exabgp/exabgp.conf
# Run as dedicated user
User=exabgp
Group=exabgp
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/log/exabgp
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
# Restrict capabilities (CAP_NET_BIND_SERVICE not needed if not binding <1024)
CapabilityBoundingSet=
AmbientCapabilities=
# Restrict network access
RestrictAddressFamilies=AF_INET AF_INET6
# Resource limits
LimitNOFILE=4096
LimitNPROC=64
TasksMax=128
# Restart policy
Restart=always
RestartSec=10
# Logging
StandardOutput=append:/var/log/exabgp/exabgp.log
StandardError=append:/var/log/exabgp/exabgp.log
SyslogIdentifier=exabgp
[Install]
WantedBy=multi-user.targetReload and restart:
systemctl daemon-reload
systemctl restart exabgp
systemctl status exabgpCreate AppArmor profile for additional isolation:
# /etc/apparmor.d/usr.local.bin.exabgp
#include <tunables/global>
/usr/local/bin/exabgp {
#include <abstractions/base>
#include <abstractions/python>
#include <abstractions/nameservice>
# ExaBGP binary
/usr/local/bin/exabgp r,
/usr/bin/python3* ix,
# Configuration files
/etc/exabgp/** r,
# API processes
/etc/exabgp/processes/*.py r,
/usr/local/bin/healthcheck.py r,
# Logs
/var/log/exabgp/** w,
# PID file
/var/run/exabgp.pid w,
# Network
network inet stream,
network inet6 stream,
# Deny everything else
deny /** w,
}
Enable AppArmor profile:
# Load profile
apparmor_parser -r /etc/apparmor.d/usr.local.bin.exabgp
# Enable enforcement
aa-enforce /usr/local/bin/exabgp
# Check status
aa-status | grep exabgpSecure file permissions:
# Configuration files (read-only for exabgp user)
chmod 640 /etc/exabgp/exabgp.conf
chown root:exabgp /etc/exabgp/exabgp.conf
# API processes (read-only, executable)
chmod 750 /etc/exabgp/processes/
chmod 750 /etc/exabgp/processes/*.py
chown root:exabgp /etc/exabgp/processes/*.py
# Log directory (writable by exabgp)
chmod 750 /var/log/exabgp
chown exabgp:exabgp /var/log/exabgp
# Secrets (read-only by exabgp only)
chmod 600 /etc/exabgp/secrets/
chown exabgp:exabgp /etc/exabgp/secrets/Verify permissions:
#!/bin/bash
# Check ExaBGP file permissions
echo "=== ExaBGP Security Audit ==="
echo
echo "Configuration files:"
ls -la /etc/exabgp/*.conf
echo
echo "API processes:"
ls -la /etc/exabgp/processes/
echo
echo "Log files:"
ls -la /var/log/exabgp/
echo
echo "Secrets:"
ls -la /etc/exabgp/secrets/
echo
echo "Process user:"
ps aux | grep exabgp | grep -v grepMinimal sudo access for API processes:
# /etc/sudoers.d/exabgp
# Allow exabgp to reload specific services (no password)
exabgp ALL=(ALL) NOPASSWD: /bin/systemctl reload nginx
exabgp ALL=(ALL) NOPASSWD: /bin/systemctl reload haproxy
# Allow IP address management
exabgp ALL=(ALL) NOPASSWD: /sbin/ip addr add *
exabgp ALL=(ALL) NOPASSWD: /sbin/ip addr del *
# Deny everything else (explicit)
exabgp ALL=(ALL) !/bin/bash
exabgp ALL=(ALL) !/bin/sh
exabgp ALL=(ALL) !/usr/bin/suTest sudo permissions:
# As exabgp user
sudo -lRestrict BGP access to known peers:
#!/bin/bash
# ExaBGP firewall rules
# BGP peers (update with your peer IPs)
BGP_PEERS=(
"192.168.1.1"
"192.168.1.2"
"2001:db8::1"
)
# Flush existing BGP rules
iptables -D INPUT -p tcp --dport 179 -j ACCEPT 2>/dev/null
ip6tables -D INPUT -p tcp --dport 179 -j ACCEPT 2>/dev/null
# Allow established connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow BGP from known peers only
for peer in "${BGP_PEERS[@]}"; do
if [[ "$peer" =~ : ]]; then
# IPv6
ip6tables -A INPUT -p tcp -s "$peer" --dport 179 -j ACCEPT
else
# IPv4
iptables -A INPUT -p tcp -s "$peer" --dport 179 -j ACCEPT
fi
done
# Drop all other BGP traffic
iptables -A INPUT -p tcp --dport 179 -j DROP
ip6tables -A INPUT -p tcp --dport 179 -j DROP
# Log dropped BGP packets
iptables -A INPUT -p tcp --dport 179 -j LOG --log-prefix "BGP-DROP: "
ip6tables -A INPUT -p tcp --dport 179 -j LOG --log-prefix "BGP-DROP: "
# Save rules
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6Modern firewall with nftables:
#!/usr/sbin/nft -f
# /etc/nftables.conf
table inet filter {
# Define BGP peers
set bgp_peers_v4 {
type ipv4_addr
elements = { 192.168.1.1, 192.168.1.2 }
}
set bgp_peers_v6 {
type ipv6_addr
elements = { 2001:db8::1, 2001:db8::2 }
}
chain input {
type filter hook input priority 0; policy drop;
# Allow established connections
ct state established,related accept
# Allow loopback
iif lo accept
# Allow BGP from known peers
tcp dport 179 ip saddr @bgp_peers_v4 accept
tcp dport 179 ip6 saddr @bgp_peers_v6 accept
# Log and drop other BGP
tcp dport 179 log prefix "BGP-DROP: " drop
}
}Apply rules:
nft -f /etc/nftables.conf
systemctl enable nftablesProtect against BGP connection floods:
# Iptables rate limiting
iptables -A INPUT -p tcp --dport 179 -m state --state NEW \
-m recent --set --name BGP
iptables -A INPUT -p tcp --dport 179 -m state --state NEW \
-m recent --update --seconds 60 --hitcount 10 --name BGP \
-j DROPNftables rate limiting:
table inet filter {
chain input {
# Limit BGP connections to 10/minute
tcp dport 179 ct state new \
limit rate 10/minute accept
}
}Filter announced routes in API process:
#!/usr/bin/env python3
"""
Secure route announcer with prefix validation
"""
import sys
import ipaddress
# Whitelist of allowed prefixes
ALLOWED_PREFIXES = [
ipaddress.ip_network('100.10.0.0/16'),
ipaddress.ip_network('203.0.113.0/24'),
]
def is_prefix_allowed(prefix_str):
"""Check if prefix is in whitelist"""
try:
prefix = ipaddress.ip_network(prefix_str)
for allowed in ALLOWED_PREFIXES:
if prefix.subnet_of(allowed):
return True
return False
except:
return False
def announce_route(prefix, **attributes):
"""Announce route only if allowed"""
if not is_prefix_allowed(prefix):
sys.stderr.write(f"SECURITY: Blocked announcement of {prefix}\n")
return
# Build announcement
cmd = f"announce route {prefix}"
if 'next_hop' in attributes:
cmd += f" next-hop {attributes['next_hop']}"
sys.stdout.write(cmd + "\n")
sys.stdout.flush()
sys.stderr.write(f"ALLOWED: Announced {prefix}\n")
# Example usage
announce_route('100.10.0.100/32', next_hop='self')
announce_route('1.1.1.1/32', next_hop='self') # Blocked!Validate BGP attributes:
#!/usr/bin/env python3
"""
Validate BGP attributes before announcing
"""
import sys
def validate_announcement(prefix, next_hop, med=None, as_path=None):
"""Validate BGP announcement parameters"""
# Check prefix format
if not is_valid_prefix(prefix):
sys.stderr.write(f"SECURITY: Invalid prefix format: {prefix}\n")
return False
# Check next-hop
if next_hop != 'self' and not is_valid_ip(next_hop):
sys.stderr.write(f"SECURITY: Invalid next-hop: {next_hop}\n")
return False
# Check MED (0-4294967295)
if med is not None:
if not (0 <= med <= 4294967295):
sys.stderr.write(f"SECURITY: Invalid MED: {med}\n")
return False
# Check AS-PATH (no private ASNs if peering with public internet)
if as_path:
if any(64512 <= asn <= 65535 for asn in as_path):
sys.stderr.write(f"SECURITY: Private ASN in AS-PATH\n")
return False
return True
def is_valid_prefix(prefix):
"""Validate prefix format"""
import ipaddress
try:
ipaddress.ip_network(prefix)
return True
except:
return False
def is_valid_ip(ip):
"""Validate IP address"""
import ipaddress
try:
ipaddress.ip_address(ip)
return True
except:
return FalseAlways filter on routers too (defense in depth):
Cisco prefix-list:
! Only accept specific prefixes from ExaBGP
ip prefix-list FROM-EXABGP permit 100.10.0.0/16 le 32
ip prefix-list FROM-EXABGP permit 203.0.113.0/24 le 32
ip prefix-list FROM-EXABGP deny 0.0.0.0/0 le 32
router bgp 65000
neighbor 192.168.1.2 prefix-list FROM-EXABGP in
Juniper prefix-list:
policy-options {
prefix-list from-exabgp {
100.10.0.0/16;
203.0.113.0/24;
}
policy-statement accept-from-exabgp {
term 1 {
from {
prefix-list from-exabgp;
}
then accept;
}
term default {
then reject;
}
}
}
protocols {
bgp {
group exabgp {
import accept-from-exabgp;
}
}
}
Never trust external input:
#!/usr/bin/env python3
"""
Secure API process with input validation
"""
import sys
import re
import ipaddress
def sanitize_input(data):
"""Sanitize external input"""
# Remove dangerous characters
data = re.sub(r'[;&|`$\n]', '', data)
return data
def check_service_health(url):
"""Check service with validated URL"""
import urllib.parse
# Validate URL
parsed = urllib.parse.urlparse(url)
# Only allow http/https
if parsed.scheme not in ['http', 'https']:
sys.stderr.write(f"SECURITY: Invalid URL scheme: {parsed.scheme}\n")
return False
# Only allow localhost
if parsed.hostname not in ['localhost', '127.0.0.1', '::1']:
sys.stderr.write(f"SECURITY: Invalid hostname: {parsed.hostname}\n")
return False
# Now safe to check
import urllib.request
try:
response = urllib.request.urlopen(url, timeout=5)
return response.status == 200
except:
return False
# Safe usage
if check_service_health('http://localhost/health'):
sys.stdout.write("announce route 100.10.0.100/32 next-hop self\n")
sys.stdout.flush()Don't use eval(), exec(), or shell=True:
# β DANGEROUS: Code injection vulnerability
import subprocess
route = input("Enter route: ") # User could enter: "1.1.1.1; rm -rf /"
subprocess.run(f"ip route add {route}", shell=True) # DON'T DO THIS!
# β
SAFE: No shell injection possible
import subprocess
route = input("Enter route: ")
# Validate input first
if is_valid_route(route):
subprocess.run(['ip', 'route', 'add', route], shell=False)Use subprocess timeouts and resource limits:
#!/usr/bin/env python3
"""
Safely execute health checks with resource limits
"""
import subprocess
import resource
def check_service_with_limits():
"""Execute health check with resource limits"""
def set_limits():
# Set resource limits for child process
resource.setrlimit(resource.RLIMIT_CPU, (5, 5)) # 5 sec CPU
resource.setrlimit(resource.RLIMIT_AS, (50*1024*1024, 50*1024*1024)) # 50 MB memory
resource.setrlimit(resource.RLIMIT_NPROC, (0, 0)) # No new processes
try:
result = subprocess.run(
['/usr/local/bin/healthcheck.sh'],
timeout=10, # 10 second timeout
preexec_fn=set_limits, # Apply resource limits
capture_output=True
)
return result.returncode == 0
except subprocess.TimeoutExpired:
sys.stderr.write("SECURITY: Health check timeout\n")
return False
except Exception as e:
sys.stderr.write(f"SECURITY: Health check error: {e}\n")
return FalseLog security-relevant events:
#!/usr/bin/env python3
"""
API process with security audit logging
"""
import sys
import syslog
import datetime
def audit_log(event, level=syslog.LOG_INFO):
"""Write to syslog for audit trail"""
syslog.openlog('exabgp-security', syslog.LOG_PID, syslog.LOG_DAEMON)
syslog.syslog(level, event)
syslog.closelog()
# Also write to stderr for ExaBGP logs
timestamp = datetime.datetime.now().isoformat()
sys.stderr.write(f"[{timestamp}] AUDIT: {event}\n")
# Log security events
audit_log("API process started", syslog.LOG_INFO)
audit_log("Route announced: 100.10.0.100/32", syslog.LOG_INFO)
audit_log("Blocked invalid prefix: 1.1.1.1/32", syslog.LOG_WARNING)
audit_log("Health check failed 3 times", syslog.LOG_ERR)Configure secure log rotation:
# /etc/logrotate.d/exabgp
/var/log/exabgp/*.log {
daily
rotate 90 # Keep 90 days for audit
compress
delaycompress
missingok
notifempty
create 0640 exabgp exabgp
sharedscripts
postrotate
systemctl reload exabgp > /dev/null 2>&1 || true
endscript
}Send logs to SIEM for analysis:
# /etc/rsyslog.d/exabgp.conf
# Send ExaBGP logs to central syslog server
if $programname == 'exabgp' or $programname == 'exabgp-security' then {
action(type="omfwd"
target="siem.example.com"
port="514"
protocol="tcp")
}Prevent session hijacking:
- Use MD5 authentication (minimum)
- Use TTL security (GTSM)
- Filter BGP traffic (firewall)
- Monitor for unexpected sessions
Detection script:
#!/usr/bin/env python3
"""
Detect unexpected BGP sessions
"""
import subprocess
import sys
EXPECTED_PEERS = ['192.168.1.1', '192.168.1.2']
def check_bgp_sessions():
"""Check for unexpected BGP connections"""
result = subprocess.run(
['ss', '-tan', 'sport', '=', ':179', 'or', 'dport', '=', ':179'],
capture_output=True,
text=True
)
for line in result.stdout.split('\n'):
if 'ESTAB' in line:
# Parse connection
parts = line.split()
if len(parts) >= 5:
remote = parts[4].split(':')[0]
if remote not in EXPECTED_PEERS:
# ALERT: Unexpected BGP session!
msg = f"SECURITY ALERT: Unexpected BGP session from {remote}"
sys.stderr.write(msg + "\n")
# Send alert
send_alert(msg)
if __name__ == '__main__':
check_bgp_sessions()Monitor for suspicious route announcements:
#!/usr/bin/env python3
"""
Monitor for route hijacking attempts
"""
import sys
import ipaddress
# Bogon prefixes (should never be announced)
BOGONS = [
ipaddress.ip_network('0.0.0.0/8'),
ipaddress.ip_network('10.0.0.0/8'),
ipaddress.ip_network('127.0.0.0/8'),
ipaddress.ip_network('169.254.0.0/16'),
ipaddress.ip_network('172.16.0.0/12'),
ipaddress.ip_network('192.168.0.0/16'),
ipaddress.ip_network('224.0.0.0/4'),
ipaddress.ip_network('240.0.0.0/4'),
]
def is_bogon(prefix_str):
"""Check if prefix is a bogon"""
try:
prefix = ipaddress.ip_network(prefix_str)
for bogon in BOGONS:
if prefix.subnet_of(bogon):
return True
return False
except:
return False
# Monitor announcements
for line in sys.stdin:
if 'announce route' in line:
# Extract prefix
parts = line.split()
if len(parts) >= 3:
prefix = parts[2]
if is_bogon(prefix):
sys.stderr.write(f"SECURITY ALERT: Bogon announcement blocked: {prefix}\n")
# Don't forward this announcement
continue
# Forward legitimate announcements
sys.stdout.write(line)
sys.stdout.flush()Prevent DoS via resource exhaustion:
#!/usr/bin/env python3
"""
Rate-limit route announcements to prevent DoS
"""
import sys
import time
from collections import deque
class RateLimiter:
def __init__(self, max_rate=100, window=1.0):
"""
max_rate: Maximum announcements per window
window: Time window in seconds
"""
self.max_rate = max_rate
self.window = window
self.events = deque()
def allow(self):
"""Check if action is allowed"""
now = time.time()
# Remove old events
while self.events and now - self.events[0] > self.window:
self.events.popleft()
# Check rate
if len(self.events) < self.max_rate:
self.events.append(now)
return True
else:
return False
limiter = RateLimiter(max_rate=100, window=1.0)
def announce_route(prefix):
"""Rate-limited route announcement"""
if limiter.allow():
sys.stdout.write(f"announce route {prefix} next-hop self\n")
sys.stdout.flush()
else:
sys.stderr.write(f"SECURITY: Rate limit exceeded for {prefix}\n")Before deploying to production:
Authentication & Authorization:
- MD5 or TCP-AO authentication enabled
- Strong passwords (20+ characters)
- Passwords stored securely (not in Git)
- TTL security (GTSM) enabled if applicable
Process Isolation:
- Running as dedicated user (not root)
- Systemd hardening enabled
- AppArmor/SELinux profile configured
- Resource limits set
File Permissions:
- Config files mode 640 or stricter
- API processes owned by root, executable by exabgp
- Log directory writable by exabgp only
- Secrets directory mode 600
Firewall:
- BGP traffic restricted to known peers
- Rate limiting enabled
- Logging enabled for dropped packets
Route Security:
- Prefix filtering in API processes
- Attribute validation enabled
- Router-side filtering configured
- Bogon filtering enabled
Monitoring:
- Audit logging enabled
- Logs rotated with retention
- SIEM integration configured
- Alerts for security events
- Unexpected session detection
API Security:
- Input validation on all external data
- No shell=True in subprocess calls
- No eval()/exec() usage
- Resource limits on API processes
- Rate limiting enabled
Perform regular audits:
#!/bin/bash
# ExaBGP security audit script
echo "=== ExaBGP Security Audit ==="
echo "Date: $(date)"
echo
# Check process user
echo "1. Process User:"
ps aux | grep exabgp | grep -v grep | awk '{print $1}'
if ps aux | grep exabgp | grep -v grep | grep -q root; then
echo " β WARNING: Running as root!"
else
echo " β
OK: Not running as root"
fi
echo
# Check file permissions
echo "2. File Permissions:"
config_perms=$(stat -c %a /etc/exabgp/exabgp.conf 2>/dev/null)
if [ "$config_perms" -le 640 ]; then
echo " β
OK: Config permissions: $config_perms"
else
echo " β WARNING: Config too permissive: $config_perms"
fi
echo
# Check BGP authentication
echo "3. BGP Authentication:"
if grep -q "md5-password" /etc/exabgp/exabgp.conf; then
echo " β
OK: MD5 authentication enabled"
else
echo " β WARNING: No MD5 authentication"
fi
echo
# Check firewall
echo "4. Firewall Rules:"
if iptables -L -n | grep -q "dpt:179"; then
echo " β
OK: BGP firewall rules present"
else
echo " β WARNING: No BGP firewall rules"
fi
echo
# Check for secrets in Git
echo "5. Secrets in Git:"
if git -C /etc/exabgp rev-parse 2>/dev/null; then
if git -C /etc/exabgp grep -q "md5-password"; then
echo " β WARNING: Passwords in Git!"
else
echo " β
OK: No passwords in Git"
fi
fi
echo
echo "=== Audit Complete ==="- Performance Tuning - Optimize ExaBGP
- Monitoring - Monitor security events
- Debugging - Troubleshooting guide
- NIST Cybersecurity Framework
- CIS Benchmarks
- MANRS - Routing security best practices
Need security help? Join our Slack community β
π» Ghost written by Claude (Anthropic AI)
π Home
π Getting Started
π§ API
π‘οΈ Use Cases
π Address Families
βοΈ Configuration
π Operations
π Reference
- Architecture
- BGP State Machine
- Communities (RFC)
- Extended Communities
- BGP Ecosystem
- Capabilities (AFI/SAFI)
- RFC Support
π Migration
π Community
π External
- GitHub Repo β
- Slack β
- Issues β
π» Ghost written by Claude (Anthropic AI)