Overview
Securing your SSV Node is critical to protect your validator operations and prevent slashing. This guide covers security best practices, key management, and hardening procedures.
Operator Key Security
Key Generation
SSV Node operators must generate and protect their operator private keys. These keys are used to sign messages within the SSV network.
Never share your operator private key. If compromised, an attacker could impersonate your operator and potentially participate in malicious activities.
Encrypted Keystore (Recommended)
For production environments, always use encrypted keystore format:
Generate encrypted keystore
# Create a strong password file
echo "your-strong-password-here" > password.txt
chmod 600 password.txt
# Generate encrypted operator keys
docker run --rm -it \
-v $( pwd ) :/keys \
ssvlabs/ssv-node:latest \
/go/bin/ssvnode generate-operator-keys \
--password-file=/keys/password.txt
This generates an encrypted encrypted_private_key.json file.
Secure the keystore files
# Set restrictive permissions
chmod 600 encrypted_private_key.json
chmod 600 password.txt
# Store in a secure directory
sudo mkdir -p /etc/ssv/secrets
sudo mv encrypted_private_key.json /etc/ssv/secrets/
sudo mv password.txt /etc/ssv/secrets/
sudo chown root:root /etc/ssv/secrets/ *
Configure SSV Node
Update your config.yaml: KeyStore :
PrivateKeyFile : /etc/ssv/secrets/encrypted_private_key.json
PasswordFile : /etc/ssv/secrets/password.txt
Mount secrets in Docker
services :
ssv-node :
volumes :
- /etc/ssv/secrets:/etc/ssv/secrets:ro
The :ro flag mounts the directory as read-only for additional security.
Converting Existing Keys
If you have an existing raw operator key, convert it to encrypted format:
docker run --rm -it \
-v $( pwd ) :/keys \
ssvlabs/ssv-node:latest \
/go/bin/ssvnode generate-operator-keys \
--password-file=/keys/password.txt \
--operator-key-file=/keys/existing_key.txt
After conversion, securely delete the raw key file: shred -vfz -n 10 existing_key.txt
Key Backup Strategy
Create encrypted backup
# Create encrypted archive
tar -czf - /etc/ssv/secrets | \
gpg --symmetric --cipher-algo AES256 \
-o ssv-keys-backup- $( date +%Y%m%d ) .tar.gz.gpg
Store in multiple locations
Secure offline storage (hardware encrypted USB)
Password manager vault
Secure cloud storage (encrypted)
Physical safe or safety deposit box
Document recovery procedure
Create a recovery document with:
Backup locations
Decryption instructions
Configuration file locations
Emergency contacts
Never store backup passwords in the same location as the encrypted backups.
Slashing Protection
Understanding Slashing Risks
Ethereum validators can be slashed for:
Double Attestation : Signing two different attestations for the same slot
Surround Voting : Signing attestations that surround or are surrounded by previous attestations
Double Proposal : Proposing two different blocks for the same slot
SSV Node implements built-in slashing protection mechanisms to prevent these scenarios.
Built-in Protections
SSV Node includes automatic slashing protection:
// From source: attestations.md:15
// Slashing protection mechanism kicks in to ensure
// Operator never signs two contradicting attestations
The node maintains a slashing protection database that tracks:
All signed attestations (slot, source epoch, target epoch)
All signed proposals (slot, block root)
Additional Protection Measures
Never run duplicate validators
Critical : Never run the same validator keys on multiple nodes or clusters simultaneously. This will result in slashing.
Proper migration procedure
When migrating validators:
Stop the old node completely
Wait for at least 2 epochs (13 minutes)
Verify the old node is not attesting
Start the new node
Monitor for successful attestations
Database backup caution
Be extremely careful when restoring from database backups. Restoring an old database state and signing attestations can lead to slashing.
Best practice: Let the node sync from network events rather than restoring old database backups.
Monitor for anomalies
Set up alerts for:
Sudden increase in missed attestations
Duplicate validator indices in logs
Slashing warnings from beacon node
Network Security
Firewall Configuration
Implement defense-in-depth with multiple firewall layers:
UFW (Ubuntu Firewall)
# Default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# SSH access (change port if using non-standard)
sudo ufw allow 22/tcp
# P2P ports
sudo ufw allow 12001/udp comment 'SSV P2P Discovery'
sudo ufw allow 13001/tcp comment 'SSV P2P Communication'
# Enable firewall
sudo ufw enable
# Verify rules
sudo ufw status verbose
Do not open ports 15000 or 16000 to the internet. These should only be accessible from your monitoring infrastructure.
iptables (Advanced)
Advanced iptables Configuration
# Flush existing rules (careful in production!)
sudo iptables -F
# Default policies
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
# Allow loopback
sudo iptables -A INPUT -i lo -j ACCEPT
# Allow established connections
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow SSH from specific IP (replace with your IP)
sudo iptables -A INPUT -p tcp --dport 22 -s YOUR_ADMIN_IP -j ACCEPT
# Allow P2P ports
sudo iptables -A INPUT -p udp --dport 12001 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 13001 -j ACCEPT
# Allow metrics from monitoring server only
sudo iptables -A INPUT -p tcp --dport 15000 -s YOUR_MONITORING_IP -j ACCEPT
# Rate limiting to prevent DDoS
sudo iptables -A INPUT -p tcp --dport 13001 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT
# Log dropped packets
sudo iptables -A INPUT -j LOG --log-prefix "iptables-dropped: "
# Save rules
sudo netfilter-persistent save
Cloud Provider Security Groups
For AWS, GCP, Azure deployments:
# Example AWS Security Group rules
Ingress Rules :
- Protocol : TCP
Port : 13001
Source : 0.0.0.0/0
Description : SSV P2P TCP
- Protocol : UDP
Port : 12001
Source : 0.0.0.0/0
Description : SSV P2P UDP Discovery
- Protocol : TCP
Port : 22
Source : YOUR_ADMIN_IP/32
Description : SSH Admin Access
- Protocol : TCP
Port : 15000
Source : YOUR_VPC_CIDR
Description : Metrics (internal only)
Egress Rules :
- Protocol : All
Port : All
Destination : 0.0.0.0/0
DDoS Protection
Rate limiting
Configure connection limits in iptables: sudo iptables -A INPUT -p tcp --syn --dport 13001 \
-m connlimit --connlimit-above 50 -j REJECT
Fail2ban for SSH
sudo apt-get install fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Cloud-level protection
Enable DDoS protection services:
AWS Shield
Google Cloud Armor
Azure DDoS Protection
System Hardening
Operating System Security
Keep system updated
# Enable automatic security updates
sudo apt-get install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# Manually update
sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get dist-upgrade -y
Disable unnecessary services
# List running services
systemctl list-unit-files --state=enabled
# Disable unnecessary services
sudo systemctl disable bluetooth.service
sudo systemctl disable cups.service
Configure SSH securely
Edit /etc/ssh/sshd_config: # Disable root login
PermitRootLogin no
# Use SSH keys only
PasswordAuthentication no
PubkeyAuthentication yes
# Limit users
AllowUsers your-user
# Change default port (optional but recommended)
Port 2222
Restart SSH: sudo systemctl restart sshd
Enable AppArmor/SELinux
# Check AppArmor status
sudo aa-status
# Ensure it's enabled
sudo systemctl enable apparmor
sudo systemctl start apparmor
Docker Security
Run as non-root user
The SSV Node Docker image runs processes as non-root by default. Verify: docker inspect ssvlabs/ssv-node:latest | grep User
Use read-only filesystem where possible
services :
ssv-node :
read_only : true
tmpfs :
- /tmp
- /var/run
volumes :
- ./data:/data # Only this needs write access
Drop unnecessary capabilities
services :
ssv-node :
cap_drop :
- ALL
cap_add :
- NET_BIND_SERVICE # Only if binding to ports < 1024
Enable Docker security scanning
# Scan image for vulnerabilities
docker scan ssvlabs/ssv-node:latest
File System Security
# Set secure permissions on configuration
chmod 600 config.yaml
chown root:root config.yaml
# Secure data directory
chmod 700 ./data
chown -R 1000:1000 ./data
# Secure docker-compose file
chmod 600 docker-compose.yaml
Monitoring and Intrusion Detection
Log Monitoring
Set up centralized logging and monitoring:
Forward logs to SIEM
services :
ssv-node :
logging :
driver : syslog
options :
syslog-address : "tcp://your-siem:514"
tag : "ssv-node"
Monitor for suspicious activity
Alert on:
Failed authentication attempts
Unexpected configuration changes
Abnormal P2P connection patterns
Unusual resource usage
Unexpected restarts
Enable audit logging
# Install auditd
sudo apt-get install auditd
# Monitor config file changes
sudo auditctl -w /path/to/config.yaml -p wa -k ssv-config-change
# Monitor secrets directory
sudo auditctl -w /etc/ssv/secrets -p ra -k ssv-secrets-access
Intrusion Detection
AIDE File Integrity Monitoring
# Install AIDE
sudo apt-get install aide
# Initialize database
sudo aideinit
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
# Run checks daily
sudo aide --check
# Add to crontab
echo "0 2 * * * /usr/bin/aide --check" | sudo crontab -
Secrets Management
Environment Variables
For sensitive configuration, use environment variables instead of config files:
services :
ssv-node :
environment :
# Don't use this for production - use secrets management
OPERATOR_PRIVATE_KEY : ${OPERATOR_PRIVATE_KEY}
env_file :
- .env.secret
Secure the env file:
chmod 600 .env.secret
echo ".env.secret" >> .gitignore
Docker Secrets (Swarm)
For Docker Swarm deployments:
secrets :
operator_key :
external : true
key_password :
external : true
services :
ssv-node :
secrets :
- operator_key
- key_password
HashiCorp Vault Integration
Vault Integration Example
# Store secret in Vault
vault kv put secret/ssv/operator-key \
private_key=@encrypted_private_key.json \
password=@password.txt
# Retrieve in startup script
vault kv get -field=private_key secret/ssv/operator-key > /tmp/key.json
vault kv get -field=password secret/ssv/operator-key > /tmp/password.txt
# Start node with retrieved secrets
docker-compose up -d
# Clean up
shred -vfz -n 10 /tmp/key.json /tmp/password.txt
Incident Response
Security Incident Playbook
Detection
Identify the security incident through:
Monitoring alerts
Log analysis
Anomaly detection
External notification
Containment
# Immediately stop the node if compromised
docker-compose down
# Isolate the server
sudo iptables -P INPUT DROP
sudo iptables -P OUTPUT DROP
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT
Investigation
Preserve logs and system state
Analyze attack vectors
Determine scope of compromise
Check if operator keys were accessed
Recovery
If operator keys are compromised:
Generate new operator keys
Update operator registration on SSV network
Rebuild server from clean image
Implement additional security controls
Monitor for follow-up attacks
Post-Incident
Document the incident
Update security procedures
Conduct post-mortem
Implement preventive measures
Maintain a list of emergency contacts:
Security team members
Infrastructure team
SSV Network support: Discord
Beacon chain monitoring services
Security Checklist
Pre-Deployment
Deployment
Ongoing
Additional Resources
Next Steps