GCP for DevOps — Cloud Armor

3 minute read

Cloud Armor

Cloud Armor provides DDoS protection and Web Application Firewall (WAF) capabilities for applications behind a Global HTTP(S) Load Balancer. It defends against OWASP Top 10 threats, enables IP-based access control, and provides rate limiting.

How Cloud Armor Works

Cloud Armor:
┌──────────┐    ┌──────────────────┐    ┌──────────────┐
│ Internet   │───▶│ Cloud Armor       │───▶│ Backend       │
│            │    │                    │    │ Service       │
│ Legitimate │    │ ┌──────────────┐  │    │               │
│ traffic    │───▶│ │ Security      │  │───▶│ ✓ Allowed     │
│            │    │ │ Policy        │  │    │               │
│ Attack     │    │ │               │  │    │               │
│ traffic    │──X─│ │ • IP rules    │  │    │               │
│            │    │ │ • WAF rules   │  │    │               │
│ Bot        │    │ │ • Rate limit  │  │    │               │
│ traffic    │──X─│ │ • reCAPTCHA   │  │    │               │
│            │    │ └──────────────┘  │    │               │
└──────────┘    └──────────────────┘    └──────────────┘

Create a Security Policy

# Create a security policy
$ gcloud compute security-policies create my-policy \
    --description="Production WAF policy"

# Attach to a backend service
$ gcloud compute backend-services update my-backend \
    --global \
    --security-policy=my-policy

IP-Based Rules

# Allow only specific IPs
$ gcloud compute security-policies rules create 1000 \
    --security-policy=my-policy \
    --src-ip-ranges="203.0.113.0/24,198.51.100.0/24" \
    --action=allow

# Block a specific IP range
$ gcloud compute security-policies rules create 2000 \
    --security-policy=my-policy \
    --src-ip-ranges="192.0.2.0/24" \
    --action=deny-403

# Block by region (country code)
$ gcloud compute security-policies rules create 3000 \
    --security-policy=my-policy \
    --expression="origin.region_code == 'CN'" \
    --action=deny-403

# Default rule (deny all or allow all)
$ gcloud compute security-policies rules update 2147483647 \
    --security-policy=my-policy \
    --action=allow

WAF Rules (Pre-configured)

# Block SQL injection (OWASP CRS)
$ gcloud compute security-policies rules create 4000 \
    --security-policy=my-policy \
    --expression="evaluatePreconfiguredExpr('sqli-v33-stable')" \
    --action=deny-403

# Block cross-site scripting (XSS)
$ gcloud compute security-policies rules create 4100 \
    --security-policy=my-policy \
    --expression="evaluatePreconfiguredExpr('xss-v33-stable')" \
    --action=deny-403

# Block Remote File Inclusion (RFI)
$ gcloud compute security-policies rules create 4200 \
    --security-policy=my-policy \
    --expression="evaluatePreconfiguredExpr('rfi-v33-stable')" \
    --action=deny-403

# Block Local File Inclusion (LFI)
$ gcloud compute security-policies rules create 4300 \
    --security-policy=my-policy \
    --expression="evaluatePreconfiguredExpr('lfi-v33-stable')" \
    --action=deny-403

Rate Limiting

# Rate limit: max 100 requests per minute per IP
$ gcloud compute security-policies rules create 5000 \
    --security-policy=my-policy \
    --src-ip-ranges="*" \
    --action=rate-based-ban \
    --rate-limit-threshold-count=100 \
    --rate-limit-threshold-interval-sec=60 \
    --ban-duration-sec=300 \
    --conform-action=allow \
    --exceed-action=deny-429 \
    --enforce-on-key=IP

# Rate limit per path (login endpoint)
$ gcloud compute security-policies rules create 5100 \
    --security-policy=my-policy \
    --expression="request.path.matches('/api/login')" \
    --action=rate-based-ban \
    --rate-limit-threshold-count=10 \
    --rate-limit-threshold-interval-sec=60 \
    --ban-duration-sec=600 \
    --conform-action=allow \
    --exceed-action=deny-429 \
    --enforce-on-key=IP

Custom Rules with CEL

# Block requests with suspicious user agents
$ gcloud compute security-policies rules create 6000 \
    --security-policy=my-policy \
    --expression="request.headers['user-agent'].contains('sqlmap') || request.headers['user-agent'].contains('nikto')" \
    --action=deny-403

# Block requests to admin paths from non-internal IPs
$ gcloud compute security-policies rules create 6100 \
    --security-policy=my-policy \
    --expression="request.path.matches('/admin/.*') && !inIpRange(origin.ip, '10.0.0.0/8')" \
    --action=deny-403

List and Manage Policies

# List security policies
$ gcloud compute security-policies list

# Describe a policy
$ gcloud compute security-policies describe my-policy

# List rules in a policy
$ gcloud compute security-policies rules list --security-policy=my-policy

# Delete a rule
$ gcloud compute security-policies rules delete 6000 --security-policy=my-policy

Common Mistakes

Mistake Why It’s Wrong Fix
No WAF rules Vulnerable to OWASP attacks Enable sqli, xss at minimum
Too aggressive rate limiting Blocks legitimate users Start high, tune down
No default deny rule Unknown traffic gets through Set default to deny for sensitive apps
Not testing WAF rules May block legitimate traffic Test in preview mode first
Missing logging Can’t investigate incidents Enable verbose logging

Quick Reference

Command Description
gcloud compute security-policies create Create policy
gcloud compute security-policies rules create Add rule
gcloud compute security-policies rules list List rules
gcloud compute backend-services update --security-policy Attach policy
gcloud compute security-policies rules delete Delete rule

Next → Load Balancing Deep Dive

Updated: