README
¶
DigitalOcean Firewall Allowlister
A Go service that automatically manages DigitalOcean firewall rules by allowing traffic from supported sources. The service can run as a daemon with scheduled updates or as a one-shot command.
Note: This project is personal project need for my own use case. make this publicly available for anyone who might find it useful. since this is also me for learning and trying out new things. so it might not be the best code, but it works for me. and i'm always open to suggestions and improvements.
Features
- 🔥 Automatic Firewall Management: Updates DigitalOcean firewall rules automatically
- ☁️ Cloudflare Integration: Fetches and allows current Cloudflare IP ranges
- 📊 Netdata Support: Resolves and allows IPs for Netdata monitoring domains
- ⏰ Flexible Scheduling: Runs on configurable cron schedules
- 🔧 Multiple Modes: Daemon mode for continuous operation, one-shot for manual execution
- 🧪 Dry-Run Support: Test changes without modifying actual firewall rules
- 📝 Structured Logging: JSON logging with configurable levels
- ⚙️ Flexible Configuration: YAML files, environment variables, and CLI flags
Installation
Using Pre-built Binaries
Download the latest release from GitHub Releases:
# Linux (x86_64)
curl -L https://github.com/kholisrag/do-firewall-allowlister/releases/latest/download/do-firewall-allowlister_Linux_x86_64.tar.gz | tar xz
# macOS (x86_64)
curl -L https://github.com/kholisrag/do-firewall-allowlister/releases/latest/download/do-firewall-allowlister_Darwin_x86_64.tar.gz | tar xz
# Windows (x86_64)
curl -L https://github.com/kholisrag/do-firewall-allowlister/releases/latest/download/do-firewall-allowlister_Windows_x86_64.zip -o do-firewall-allowlister.zip
Using Docker
Multi-architecture Docker images are available:
# Run directly
docker run --rm ghcr.io/kholisrag/do-firewall-allowlister:latest --help
# With configuration file
docker run --rm -v $(pwd)/config.yaml:/config.yaml ghcr.io/kholisrag/do-firewall-allowlister:latest validate --config /config.yaml
Using Go Install
go install github.com/kholisrag/do-firewall-allowlister/cmd/do-firewall-allowlister@latest
From Source
git clone https://github.com/kholisrag/do-firewall-allowlister.git
cd do-firewall-allowlister
# Using Task (recommended)
task build
# Or using Go directly
go build -o do-firewall-allowlister ./cmd/do-firewall-allowlister
Configuration
The service uses a hierarchical configuration system with the following priority (highest to lowest):
- CLI Flags (highest priority)
- Environment Variables
- YAML Configuration File (lowest priority)
Configuration File
Create a config.yaml file:
logLevel: INFO
cron:
schedule: "0 0 * * *" # Daily at midnight
timezone: "UTC"
digitalocean:
api_key: "your-digitalocean-api-key"
firewall_id: "your-firewall-id"
inbound_rules:
- port: 80
protocol: tcp
- port: 443
protocol: tcp
netdata:
domains:
- "app.netdata.cloud"
- "api.netdata.cloud"
- "mqtt.netdata.cloud"
cloudflare:
ips_url: "https://api.cloudflare.com/client/v4/ips"
Environment Variables
All configuration options can be set via environment variables with the FIREWALL_ALLOWLISTER_ prefix:
export FIREWALL_ALLOWLISTER_LOG_LEVEL=DEBUG
export FIREWALL_ALLOWLISTER_DIGITALOCEAN_API_KEY=your-api-key
export FIREWALL_ALLOWLISTER_DIGITALOCEAN_FIREWALL_ID=your-firewall-id
export FIREWALL_ALLOWLISTER_CRON_SCHEDULE="0 */6 * * *"
CLI Flags
All configuration options can be overridden with global CLI flags that work with any command:
./do-firewall-allowlister daemon \
--config config.yaml \
--log-level DEBUG \
--digitalocean.api-key your-api-key \
--digitalocean.firewall-id your-firewall-id \
--dry-run
Global flags are available for all commands and include:
--config, -c: Path to configuration file--log-level: Logging level--digitalocean.api-key: DigitalOcean API key--digitalocean.firewall-id: DigitalOcean firewall ID--cron.schedule: Cron schedule expression--cron.timezone: Timezone for cron schedule--cloudflare.ips-url: Cloudflare IPs API URL
Usage
Daemon Mode
Run the service continuously with scheduled updates:
# Run with default config.yaml
./do-firewall-allowlister daemon
# Run with custom config and dry-run mode
./do-firewall-allowlister daemon --config /path/to/config.yaml --dry-run
# Run with environment variables
FIREWALL_ALLOWLISTER_DIGITALOCEAN_API_KEY=your-key \
./do-firewall-allowlister daemon --dry-run
One-Shot Mode
Execute firewall updates once and exit:
# Run once with default config
./do-firewall-allowlister oneshot
# Run once with dry-run to see what would be changed
./do-firewall-allowlister oneshot --dry-run
# Run with custom configuration
./do-firewall-allowlister oneshot --config /path/to/config.yaml
Configuration Validation
Validate your configuration and test connectivity:
# Validate configuration file
./do-firewall-allowlister validate --config config.yaml
# Validate with environment variables
FIREWALL_ALLOWLISTER_DIGITALOCEAN_API_KEY=your-key \
./do-firewall-allowlister validate
Status Check
Check the status of external services:
# Get status in JSON format
./do-firewall-allowlister status --config config.yaml
# Get status in table format
./do-firewall-allowlister status --format table
Version Information
Get detailed version and build information:
# Text format
./do-firewall-allowlister version
# JSON format
./do-firewall-allowlister version --output json
How It Works
- IP Collection: The service fetches current Cloudflare IP ranges from their API and resolves IP addresses for configured Netdata domains
- Firewall Update: It updates the specified DigitalOcean firewall with inbound rules allowing traffic from these IPs on configured ports
- Scheduling: In daemon mode, it runs on a configurable cron schedule to keep firewall rules up-to-date
- Safety: Dry-run mode allows you to see what changes would be made without actually modifying firewall rules
Configuration Options
| Option | Environment Variable | CLI Flag | Description |
|---|---|---|---|
| Log Level | FIREWALL_ALLOWLISTER_LOG_LEVEL |
--log-level |
Logging level (DEBUG, INFO, WARN, ERROR, FATAL) |
| Cron Schedule | FIREWALL_ALLOWLISTER_CRON_SCHEDULE |
--cron.schedule |
Cron expression for scheduling |
| Timezone | FIREWALL_ALLOWLISTER_CRON_TIMEZONE |
--cron.timezone |
Timezone for cron schedule |
| DO API Key | FIREWALL_ALLOWLISTER_DIGITALOCEAN_API_KEY |
--digitalocean.api-key |
DigitalOcean API key |
| Firewall ID | FIREWALL_ALLOWLISTER_DIGITALOCEAN_FIREWALL_ID |
--digitalocean.firewall-id |
DigitalOcean firewall ID |
| Cloudflare URL | FIREWALL_ALLOWLISTER_CLOUDFLARE_IPS_URL |
--cloudflare.ips-url |
Cloudflare IPs API endpoint |
Examples
Docker Deployment
The project includes a multi-stage Dockerfile using distroless images for security:
# Build the image
docker build -t do-firewall-allowlister .
# Run with configuration
docker run --rm -v $(pwd)/config.yaml:/config.yaml \
do-firewall-allowlister daemon --config /config.yaml
# Run one-shot with dry-run
docker run --rm -v $(pwd)/config.yaml:/config.yaml \
do-firewall-allowlister oneshot --config /config.yaml --dry-run
Or use the pre-built multi-architecture images:
# Pull and run
docker run --rm -v $(pwd)/config.yaml:/config.yaml \
ghcr.io/kholisrag/do-firewall-allowlister:latest daemon --config /config.yaml
Systemd Service
Create /etc/systemd/system/do-firewall-allowlister.service:
[Unit]
Description=DigitalOcean Firewall Allowlister
After=network.target
[Service]
Type=simple
User=firewall-allowlister
WorkingDirectory=/opt/do-firewall-allowlister
ExecStart=/opt/do-firewall-allowlister/do-firewall-allowlister daemon --config /etc/do-firewall-allowlister/config.yaml
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: do-firewall-allowlister
spec:
replicas: 1
selector:
matchLabels:
app: do-firewall-allowlister
template:
metadata:
labels:
app: do-firewall-allowlister
spec:
containers:
- name: do-firewall-allowlister
image: your-registry/do-firewall-allowlister:latest
command: ["./do-firewall-allowlister", "daemon"]
env:
- name: FIREWALL_ALLOWLISTER_DIGITALOCEAN_API_KEY
valueFrom:
secretKeyRef:
name: do-api-secret
key: api-key
- name: FIREWALL_ALLOWLISTER_DIGITALOCEAN_FIREWALL_ID
value: "your-firewall-id"
- name: FIREWALL_ALLOWLISTER_LOG_LEVEL
value: "INFO"
Development
Prerequisites
- Go 1.21 or later
- Task (recommended) or Make
- GoReleaser (for releases)
- Docker (for container builds)
- DigitalOcean API token with firewall management permissions
Quick Start
# Clone the repository
git clone https://github.com/kholisrag/do-firewall-allowlister.git
cd do-firewall-allowlister
# Install dependencies
task deps
# Run tests
task test:short
# Build for current platform
task build
# See all available tasks
task --list
Available Tasks
# Development
task build # Build binary for current platform
task build:all # Build binaries for all platforms
task test # Run all tests with coverage
task test:short # Run short tests
task test:integration # Run integration tests
task test:coverage # Generate coverage report
# Code Quality
task fmt # Format Go code
task lint # Run linters
task check # Run all checks (format, lint, test)
# Docker
task docker:build # Build Docker image
task docker:run # Run Docker container
task docker:push # Push Docker image
# Release
task release:dry # Dry run release with GoReleaser
task release # Create release with GoReleaser
# Utilities
task clean # Clean build artifacts
task dev # Run in development mode
task validate # Validate configuration
Manual Commands
If you prefer not to use Task:
# Build for current platform
go build -o do-firewall-allowlister ./cmd/do-firewall-allowlister
# Build for multiple platforms
GOOS=linux GOARCH=amd64 go build -o do-firewall-allowlister-linux-amd64 ./cmd/do-firewall-allowlister
GOOS=darwin GOARCH=amd64 go build -o do-firewall-allowlister-darwin-amd64 ./cmd/do-firewall-allowlister
# Run tests
go test -short ./...
go test -race -coverprofile=coverage.out ./...
# Format and lint
go fmt ./...
go vet ./...
golangci-lint run
# Docker build
docker build -t do-firewall-allowlister .
Security Considerations
- API Key Security: Store DigitalOcean API keys securely using environment variables or secret management systems
- Firewall Access: Ensure the API key has minimal required permissions (firewall read/write only)
- Network Security: The service makes outbound HTTPS requests to Cloudflare and DigitalOcean APIs
- Logging: Avoid logging sensitive information; API keys are not logged by default
Troubleshooting
Common Issues
- Invalid API Key: Ensure your DigitalOcean API key has firewall management permissions
- Firewall Not Found: Verify the firewall ID exists and is accessible with your API key
- DNS Resolution Failures: Check network connectivity for Netdata domain resolution
- Cron Schedule Errors: Validate cron expressions using online cron validators
Debug Mode
Enable debug logging to troubleshoot issues:
./do-firewall-allowlister daemon --log-level DEBUG --dry-run
Validation
Always test with dry-run mode first:
./do-firewall-allowlister oneshot --dry-run
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- DigitalOcean for their excellent API
- Cloudflare for providing public IP ranges
- Netdata for their monitoring platform
- The Go community for excellent libraries and tools