Description

This rule verifies that inbound access control on DigitalOcean is enforced by meaningful ingress filtering rather than left effectively open. DigitalOcean has no separate 'security group' construct; Cloud Firewalls are the equivalent, and this rule maps the security-group requirement onto them honestly.

An important difference from some other platforms: DigitalOcean Cloud Firewalls are deny-by-default. A firewall with no inbound rules blocks all inbound traffic, so an empty rule set is restrictive, not permissive. The real DigitalOcean risks the rule targets are therefore (a) Droplets with no firewall attached at all, which have no cloud-firewall filtering, and (b) a firewall whose inbound rules effectively disable filtering by allowing all ports from All IPv4/IPv6 (for example protocol covering all traffic, ports 'all'/0, source 0.0.0.0/0 and ::/0).

The rule flags firewalls whose inbound rules amount to no filtering, and Droplets that are not covered by any firewall. Remediation attaches a firewall with least-privilege inbound rules to every Droplet and tightens any wide-open inbound rule to the specific ports and sources actually required.

  • Droplets not attached to any Cloud Firewall (no cloud-firewall ingress filtering)

  • Firewalls whose inbound rules allow all ports (ports '0' or 'all') from 0.0.0.0/0 and/or ::/0, negating filtering

  • Firewalls attached to resources but with inbound rules broader than the workload requires

Rationale

Access control only protects a workload when a firewall is actually attached to it and its rules are scoped to what the service needs. A Droplet with no firewall relies entirely on host-level controls, and a firewall that admits every port from every address provides the appearance of protection with none of the substance.

Requiring every Droplet to be covered by a firewall whose inbound rules are limited to necessary ports and trusted sources closes the gap between intended and actual network posture, and makes the enforced policy auditable in one place.

  • Unattached Droplets have no cloud-firewall filtering at all

  • All-ports/all-sources inbound rules defeat the purpose of a firewall

  • Explicit, scoped ingress makes the enforced policy reviewable

Impact

Pros:

  • Guarantees every Droplet has an enforced, least-privilege ingress policy

  • Removes wide-open rules that mask real exposure

  • Makes network posture consistent and auditable across the fleet

Cons:

  • Requires cataloguing each Droplet's legitimate inbound ports and sources

  • Attaching firewalls and tightening rules can briefly disrupt traffic if a needed port is missed

  • Ongoing maintenance as workloads and source networks change

Default Value

New Droplets are not attached to any Cloud Firewall unless you create and apply one; Cloud Firewalls deny all inbound traffic that no rule permits, so an unprotected Droplet has no cloud-firewall filtering while an empty firewall blocks everything.

Pre-Requisite

  • Control Panel access with permission to view Droplets and firewalls

  • A DigitalOcean API token or doctl authenticated for API/CLI checks

  • An inventory of each Droplet's required inbound ports and trusted source ranges

Remediation

Test Plan

Using the DigitalOcean Control Panel:

  1. Sign in to cloud.digitalocean.com and go to Networking, then Firewalls.

  2. Review each firewall's Rules tab: confirm the inbound rules are scoped to specific ports and sources, and flag any rule that allows all ports from All IPv4/All IPv6.

  3. Go to the Droplets list; for each Droplet open it and check the Networking section (or the firewall's Droplets tab) to confirm at least one firewall is applied.

  4. Cross-check that every Droplet appears under some firewall's applied resources.

  5. Pass: Every Droplet is covered by at least one firewall, and no firewall's inbound rules allow all ports from an unrestricted source.

  6. Fail: One or more Droplets have no firewall applied, or a firewall's inbound rules allow all ports from All IPv4/All IPv6.

Using doctl or the API:

List firewalls (with their droplet_ids and rules) and all Droplets, then compare coverage and inspect for all-open inbound rules.

doctl compute firewall list --format ID,Name,DropletIDs,InboundRules
doctl compute droplet list --format ID,Name
# Firewalls whose inbound rules are effectively unfiltered (all ports from an unrestricted source):
curl -s -X GET -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" "https://api.digitalocean.com/v2/firewalls" | jq '.firewalls[] | {id, name, droplet_ids, wide_open: [.inbound_rules[] | select((.ports=="0" or .ports=="all") and (.sources.addresses // [] | any(.=="0.0.0.0/0" or .=="::/0")))]}'
# Droplet IDs covered by any firewall vs. all Droplet IDs (compare the two lists for gaps):
curl -s -X GET -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" "https://api.digitalocean.com/v2/firewalls" | jq '[.firewalls[].droplet_ids[]] | unique'
curl -s -X GET -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" "https://api.digitalocean.com/v2/droplets" | jq '[.droplets[].id] | unique'

Pass: the two Droplet-ID lists match (every Droplet is covered by a firewall) and no firewall reports a non-empty wide_open array. Fail: some Droplet IDs are absent from firewall coverage, or a firewall has an all-ports rule from 0.0.0.0/0 or ::/0.

Implementation Steps

Using the DigitalOcean Control Panel:

  1. For any Droplet with no firewall: go to Networking, then Firewalls, and either open an existing firewall or Create a firewall with least-privilege inbound rules.

  2. On the firewall, use Apply to Droplets (or the Droplets tab) to attach the uncovered Droplet by name or tag.

  3. For any firewall with an all-ports rule from All IPv4/All IPv6: on the Rules tab, add scoped inbound rules for the specific ports and sources the workload needs, verify connectivity, then delete the wide-open rule via its … (More) menu.

  4. Repeat until every Droplet is covered and no firewall admits all ports from an unrestricted source.

Using doctl or the API:

Attach firewalls to uncovered Droplets and replace all-open inbound rules with scoped ones.

doctl compute firewall add-droplets <firewall-id> --droplet-ids <droplet-id>
doctl compute firewall add-rules <firewall-id> --inbound-rules "protocol:tcp,ports:443,address:0.0.0.0/0"
doctl compute firewall remove-rules <firewall-id> --inbound-rules "protocol:tcp,ports:0,address:0.0.0.0/0"
# API equivalents:
curl -s -X POST -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" -H "Content-Type: application/json" -d '{"droplet_ids":[<droplet-id>]}' "https://api.digitalocean.com/v2/firewalls/<firewall-id>/droplets"
curl -s -X DELETE -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" -H "Content-Type: application/json" -d '{"inbound_rules":[{"protocol":"tcp","ports":"0","sources":{"addresses":["0.0.0.0/0","::/0"]}}]}' "https://api.digitalocean.com/v2/firewalls/<firewall-id>/rules"

Backout Plan:

  1. If a newly attached firewall or tightened rule blocks required traffic, add the missing scoped inbound rule (doctl compute firewall add-rules ... or POST /rules), or detach the firewall with doctl compute firewall remove-droplets <firewall-id> --droplet-ids <droplet-id> to restore prior connectivity while you refine the rules.

  2. Re-apply the least-privilege configuration once the correct ports and sources are confirmed.

References:

  1. DigitalOcean Cloud Firewalls overview

  2. How to Configure Firewall Rules

  3. How to View All Firewall Rules Applied to a Droplet

  4. Firewalls API reference

  5. doctl compute firewall reference