GCP for DevOps — Firewall Rules
Firewall Rules
GCP firewall rules control inbound (ingress) and outbound (egress) network traffic to and from VM instances. They are stateful, priority-based, and can be applied using network tags or service accounts.
How Firewall Rules Work
Internet
│
┌───────▼───────┐
│ GCP Firewall │
│ │
│ Rule 1: ALLOW │ ◄── Priority 1000
│ tcp:80,443 │ (lower = higher priority)
│ tag:web │
│ │
│ Rule 2: DENY │ ◄── Priority 65534
│ all traffic │ (implied deny-all ingress)
│ │
└───────┬───────┘
│
┌───────▼───────┐
│ VM Instance │
│ tag: web │
└───────────────┘
Default Firewall Rules
Every VPC network starts with two implied rules:
| Rule | Direction | Priority | Action | Description |
|---|---|---|---|---|
| Implied allow egress | Egress | 65535 | Allow | All outbound traffic allowed |
| Implied deny ingress | Ingress | 65535 | Deny | All inbound traffic denied |
Plus default VPC adds:
| Rule | Ports | Source | Priority |
|---|---|---|---|
default-allow-internal |
All | 10.128.0.0/9 |
65534 |
default-allow-ssh |
TCP 22 | 0.0.0.0/0 |
65534 |
default-allow-rdp |
TCP 3389 | 0.0.0.0/0 |
65534 |
default-allow-icmp |
ICMP | 0.0.0.0/0 |
65534 |
⚠️ DevOps Best Practice: Delete the default
allow-sshandallow-rdprules. Use IAP for SSH/RDP access instead of exposing ports to the internet.
Creating Firewall Rules
# Allow HTTP and HTTPS from the internet to VMs with tag "web"
$ gcloud compute firewall-rules create allow-http-https \
--network=default \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:80,tcp:443 \
--source-ranges=0.0.0.0/0 \
--target-tags=web \
--priority=1000 \
--description="Allow HTTP/HTTPS to web servers"
Creating firewall...done.
NAME NETWORK DIRECTION PRIORITY ALLOW DENY DISABLED
allow-http-https default INGRESS 1000 tcp:80,tcp:443 False
# Allow SSH only from IAP's IP range
$ gcloud compute firewall-rules create allow-ssh-iap \
--network=default \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:22 \
--source-ranges=35.235.240.0/20 \
--target-tags=allow-ssh \
--priority=1000 \
--description="Allow SSH from IAP only"
# Allow internal communication between app servers
$ gcloud compute firewall-rules create allow-internal-app \
--network=default \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:8080,tcp:8443 \
--source-tags=app \
--target-tags=app \
--priority=1000
Using Service Accounts Instead of Tags
Service account-based rules are more secure because tags can be set by anyone with compute.instances.setTags permission.
# Allow traffic to VMs running with a specific service account
$ gcloud compute firewall-rules create allow-app-to-db \
--network=default \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:5432 \
--source-service-accounts=app-sa@my-project.iam.gserviceaccount.com \
--target-service-accounts=db-sa@my-project.iam.gserviceaccount.com \
--priority=1000 \
--description="Allow app tier to connect to database on port 5432"
Deny Rules
# Deny all egress to a specific IP range
$ gcloud compute firewall-rules create deny-egress-malicious \
--network=default \
--direction=EGRESS \
--action=DENY \
--rules=all \
--destination-ranges=198.51.100.0/24 \
--priority=900
# Deny SSH from the internet (override default rule)
$ gcloud compute firewall-rules create deny-ssh-internet \
--network=default \
--direction=INGRESS \
--action=DENY \
--rules=tcp:22 \
--source-ranges=0.0.0.0/0 \
--priority=900
Priority System
Lower numbers = higher priority. Range: 0–65535.
Priority 0 ←── Highest (evaluated first)
Priority 100
Priority 1000 ←── Typical custom rules
Priority 65534 ←── Default rules
Priority 65535 ←── Implied rules (cannot be deleted)
# List firewall rules sorted by priority
$ gcloud compute firewall-rules list \
--format="table(name,direction,priority,allowed[].map().firewall_rule().list():label=ALLOWED,sourceRanges.list():label=SRC_RANGES,targetTags.list():label=TARGET_TAGS)" \
--sort-by=priority
NAME DIRECTION PRIORITY ALLOWED SRC_RANGES TARGET_TAGS
deny-ssh-internet INGRESS 900 deny:tcp:22 0.0.0.0/0
allow-http-https INGRESS 1000 tcp:80,tcp:443 0.0.0.0/0 web
allow-ssh-iap INGRESS 1000 tcp:22 35.235.240.0/20 allow-ssh
default-allow-internal INGRESS 65534 all 10.128.0.0/9
Firewall Rule Logging
Enable logging to track which rules are being hit.
# Enable logging on a firewall rule
$ gcloud compute firewall-rules update allow-http-https \
--enable-logging
# View firewall logs
$ gcloud logging read 'resource.type="gce_subnetwork" AND jsonPayload.disposition="ALLOWED"' \
--project=my-project --limit=5
Common Mistakes
| Mistake | Why It’s Wrong | Fix |
|---|---|---|
Allowing SSH from 0.0.0.0/0 |
Exposes all VMs to brute-force | Use IAP (35.235.240.0/20) |
| Not setting priorities | Rules may conflict unexpectedly | Always set explicit priorities |
| Using only tags (not SA) | Tags can be manipulated | Use service account-based rules |
| No egress rules | VMs can reach anything | Add deny-egress for sensitive networks |
| Not enabling logging | Can’t troubleshoot connectivity | Enable logging on important rules |
Quick Reference
| Command | Description |
|---|---|
gcloud compute firewall-rules create NAME --rules=PROTO:PORT |
Create a rule |
gcloud compute firewall-rules list |
List all rules |
gcloud compute firewall-rules describe NAME |
Show rule details |
gcloud compute firewall-rules update NAME |
Update a rule |
gcloud compute firewall-rules delete NAME |
Delete a rule |
--source-ranges=CIDR |
Filter by source IP |
--target-tags=TAG |
Apply to VMs with tag |
--source-service-accounts=SA |
Filter by source SA |
Next → Startup Scripts