#!/bin/bash # DigitalOcean Cloud Firewall provisioning script # Generated by provisioning {{ provisioning_version }} at {{ now }} # Reference: DigitalOcean API v2 Firewalls - https://docs.digitalocean.com/reference/api/api-reference/#firewalls set -e {% if debug and debug == "yes" %}set -x{% endif %} # Validate required environment if [ -z "$DIGITALOCEAN_TOKEN" ]; then echo "ERROR: DIGITALOCEAN_TOKEN environment variable not set" exit 1 fi # Firewall configuration FIREWALL_NAME="{{ firewall.name }}" FIREWALL_DESCRIPTION="{{ firewall.description | default('Cloud Firewall') }}" # Validate required fields if [ -z "$FIREWALL_NAME" ]; then echo "ERROR: Firewall name is required" exit 1 fi # Create firewall echo "Creating firewall: $FIREWALL_NAME..." # Build inbound rules JSON cat > /tmp/inbound_rules.json << 'INBOUND_EOF' [ {% for rule in firewall.inbound_rules %} { "protocol": "{{ rule.protocol | default('tcp') }}", "ports": "{{ rule.ports | default('all') }}", {% if rule.sources %} "sources": { {% if rule.sources.droplet_ids %} "droplet_ids": [{{ rule.sources.droplet_ids | join(', ') }}], {% endif %} {% if rule.sources.addresses %} "addresses": [{{ rule.sources.addresses | map('tojson') | join(', ') }}] {% endif %} } {% endif %} }{{ "," if not loop.last else "" }} {% endfor %} ] INBOUND_EOF # Build outbound rules JSON cat > /tmp/outbound_rules.json << 'OUTBOUND_EOF' [ {% for rule in firewall.outbound_rules %} { "protocol": "{{ rule.protocol | default('tcp') }}", "ports": "{{ rule.ports | default('all') }}", {% if rule.destinations %} "destinations": { {% if rule.destinations.droplet_ids %} "droplet_ids": [{{ rule.destinations.droplet_ids | join(', ') }}], {% endif %} {% if rule.destinations.addresses %} "addresses": [{{ rule.destinations.addresses | map('tojson') | join(', ') }}] {% endif %} } {% endif %} }{{ "," if not loop.last else "" }} {% endfor %} ] OUTBOUND_EOF # Create firewall using doctl doctl compute firewall create \ --inbound-rules "$(cat /tmp/inbound_rules.json)" \ --outbound-rules "$(cat /tmp/outbound_rules.json)" \ --format ID \ --no-header \ "$FIREWALL_NAME" # Get the firewall ID FIREWALL_ID=$(doctl compute firewall list --format Name,ID --no-header | grep "^${FIREWALL_NAME} " | awk '{print $NF}') if [ -z "$FIREWALL_ID" ]; then echo "ERROR: Failed to create firewall $FIREWALL_NAME" rm -f /tmp/inbound_rules.json /tmp/outbound_rules.json exit 1 fi echo "✓ Firewall $FIREWALL_NAME created successfully" echo " ID: $FIREWALL_ID" echo " Inbound rules: {{ firewall.inbound_rules | length }}" echo " Outbound rules: {{ firewall.outbound_rules | length }}" {% if firewall.apply_to_droplets %} # Apply firewall to droplets echo "Applying firewall to droplets..." {% for droplet_name in firewall.apply_to_droplets %} DROPLET_ID=$(doctl compute droplet list --format Name,ID --no-header | grep "^{{ droplet_name }} " | awk '{print $NF}') if [ -n "$DROPLET_ID" ]; then doctl compute firewall add-droplets \ "$FIREWALL_ID" \ "$DROPLET_ID" echo " ✓ Applied to droplet: {{ droplet_name }} (ID: $DROPLET_ID)" else echo " ⚠ Droplet '{{ droplet_name }}' not found - skipping" fi {% endfor %} {% endif %} {% if firewall.apply_to_tags %} # Apply firewall to tagged resources echo "Applying firewall to tagged resources..." {% for tag in firewall.apply_to_tags %} doctl compute firewall add-tags \ "$FIREWALL_ID" \ "{{ tag }}" echo " ✓ Applied to tag: {{ tag }}" {% endfor %} {% endif %} {% if firewall.tags %} # Apply tags to firewall itself {% for tag in firewall.tags %} doctl compute firewall tag "$FIREWALL_ID" --tag-name "{{ tag }}" {% endfor %} echo "✓ Firewall tags applied: {{ firewall.tags | join(', ') }}" {% endif %} # Clean up temporary files rm -f /tmp/inbound_rules.json /tmp/outbound_rules.json # Output firewall details echo "" echo "Firewall configuration:" doctl compute firewall get "$FIREWALL_ID" --format ID,Name,InboundRulesCount,OutboundRulesCount,Status --no-header exit 0