Automating GCP Firewall Rules with Terraform: Consistent, Scalable Network Security
Introduction
Firewall rules are your first—and often only—line of defense in a VPC. Manual management invites drift, misconfigurations, and audit headaches. In this post, you’ll learn how to codify, test, and deploy GCP firewall rules reliably using Terraform.
Background & Problem Statement
Every GCP firewall rule consists of:
- Network tags or service accounts
- Direction (
INGRESSorEGRESS) - Priority and name conventions
- Source/destination ranges and protocols
Manual edits often lead to:
- Inconsistent naming
- Overly permissive “catch-all” rules
- Forgotten rules after team handoffs
Why Terraform for Firewall Automation
- Idempotence – Repeat applies with zero surprises
- Version Control & Code Review – Peer-review your security policy
- Drift Detection & Auditing – See exactly what will change with
terraform plan
Getting Started: Provider & Setup
-
Enable the Compute API in your GCP project.
-
Create a service account with
roles/compute.networkAdminand download its JSON key. -
Add this to your Terraform config:
provider "google" { credentials = file(var.credentials_file) project = var.project_id region = var.region } -
Initialize and validate:
terraform init terraform validate
Defining a Simple Firewall Rule
resource "google_compute_firewall" "allow_ssh" {
name = "allow-ssh"
network = var.network
direction = "INGRESS"
priority = 1000
source_ranges = ["203.0.113.0/24"]
allows {
protocol = "tcp"
ports = ["22"]
}
target_tags = ["ssh-able"]
}
Run:
terraform plan
terraform apply
Parameterizing with Variables & Locals
variable "environments" {
type = map(object({
cidr = string
tags = list(string)
}))
default = {
dev = { cidr = "10.0.0.0/24", tags = ["dev"] }
prod = { cidr = "192.168.0.0/24", tags = ["prod"] }
}
}
locals {
firewall_rules = [
for name, env in var.environments : {
name_prefix = "allow-${name}-ssh"
source_ranges = [env.cidr]
target_tags = env.tags
}
]
}
Building a Reusable Module
-
Create
modules/firewall-rule/main.tf:variable "name_prefix" { type = string } variable "network" { type = string } variable "source_ranges" { type = list(string) } variable "allows" { type = list(object({ protocol = string, ports = list(string) })) } variable "target_tags" { type = list(string) } variable "priority" { type = number } resource "google_compute_firewall" "this" { name = var.name_prefix network = var.network direction = "INGRESS" priority = var.priority source_ranges = var.source_ranges dynamic "allows" { for_each = var.allows content { protocol = allows.value.protocol ports = allows.value.ports } } target_tags = var.target_tags } -
Invoke the module in your root config:
module "app_firewall" { source = "./modules/firewall-rule" name_prefix = "allow-app" network = var.network source_ranges = ["0.0.0.0/0"] allows = [{ protocol = "tcp", ports = ["8080", "443"] }] target_tags = ["app-server"] priority = 1000 }
Testing & Validation
- Dry Runs: Gate
terraform planin your CI pipelines. - Security Scans: Integrate tools like
tfsecorcheckov. - Connectivity Tests: Use GCP’s Network Intelligence Center for end-to-end reachability validation (see Connectivity Tests in GCP).
CI/CD Integration
# .github/workflows/terraform.yml
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.0
- run: terraform fmt -check
- run: terraform validate
- run: terraform plan -out=tfplan
- name: Apply in Prod
if: github.ref == 'refs/heads/main'
run: terraform apply -auto-approve tfplan
Best Practices & Tips
- Naming Conventions: Prefix by environment—e.g.,
prod-allow-ssh. - Least Privilege: Default deny, then allow only required traffic.
- Tags vs. Service Accounts: Choose the right selector for your VM groups.
- Audit Logging: Enable VPC Flow Logs for firewall rule hits.
Common Pitfalls & FAQs
| Issue | Fix |
|---|---|
| Overlapping priorities cause conflicts | Allocate distinct ranges: SSH (1000–1999), APP (2000–2999). |
| Forgotten instance tags | Manage tags via Terraform or startup scripts. |
| Default “allow-google” interference | Disable default rules or add higher-priority denies. |
Conclusion
Terraform brings consistency, auditability, and repeatability to firewall management—ensuring your VPC scales securely with your team’s velocity.
Call to Action
- 💬 Drop your Terraform firewall patterns in the comments below!
- 🔗 Check out Connectivity Tests in GCP for full-network validation.
- 📥 Subscribe for monthly GCP IaC deep dives.