Hierarchical Firewall Policies — Enterprise Security at Scale
Executive Summary
GCP firewall rules có hierarchy tại organization level:
Organization
├── Policy (org-level)
├─── Folder
│ ├── Policy (folder-level)
│ └─── Project
│ ├── Policy (project-level)
│ └─── VPC
│ └── Rules (VPC-level)Các policies kaskade down (inheritance) với override capabilities (exceptions).
Policy Hierarchy Layers
Layer 1: Organization Policy
Organization Policy (top-level)
- Applied to: entire organization
- Scope: all projects, all VPCs
- Priority: highest (evaluated first)
- Enforcement: Allow/Deny
- Exceptions: folder/project-level
Example:
Org policy: DENY all ingress except from corporate networks
Effect: All projects inherit this policy
No project can expose to internet (unless exception)Layer 2: Folder Policy
Folder: Production (contains 50+ projects)
- Policy: Allow ingress from internal networks only
- Exceptions: marketing-website project (allow from internet)
Effect: 49 projects: deny internet ingress (inherit)
1 project: allow internet ingress (exception)Layer 3: Project Policy
Project: prod-app
- Policy: Allow tcp:443 from LB only
- Exceptions: none
Scope: All VPCs in this project affectedLayer 4: VPC Rules
VPC: prod-vpc
- Rule 1: priority 1000, allow tcp:443 from 10.0.0.0/8
- Rule 2: priority 1100, allow tcp:3306 from app-tier
Scope: Only this VPCEvaluation Order: Complete Flow
When packet arrives, firewall decision:
Step 1: Organization Policy
Rule exists? → DENY ingress from internet?
Match? → YES
Evaluate exception → marketing-website project?
Is current project in exception list? → NO
→ ENFORCE DENY
Step 2: Folder Policy
Would apply if org policy didn't already deny
Step 3: Project Policy
Would apply if folder policy didn't already deny
Step 4: VPC Rules
Would apply if project policy allowed
Result: Packet DENIED at organization layer
Never reaches VPC rulesCreating Hierarchical Policies
Organization Policy
bash
gcloud compute firewall-policies create \
--organization=ORGANIZATION_ID \
--name=org-default-deny-ingress
# Add rule:
gcloud compute firewall-policies rules create \
--firewall-policy=org-default-deny-ingress \
--organization=ORGANIZATION_ID \
--priority=100 \
--direction=INGRESS \
--action=deny \
--match="{'srcIpRanges': ['0.0.0.0/0']}"Folder Policy with Exceptions
bash
gcloud compute firewall-policies create \
--parent=folders/FOLDER_ID \
--name=folder-production-policy
# Add allow rule for internal:
gcloud compute firewall-policies rules create \
--firewall-policy=folder-production-policy \
--parent=folders/FOLDER_ID \
--priority=100 \
--direction=INGRESS \
--action=allow \
--match="{'srcIpRanges': ['10.0.0.0/8']}"
# Add exception for specific project:
gcloud compute firewall-policies rules create \
--firewall-policy=folder-production-policy \
--parent=folders/FOLDER_ID \
--priority=200 \
--direction=INGRESS \
--action=allow \
--match="{'srcIpRanges': ['0.0.0.0/0'], 'dest Project': ['projects/marketing-website']}"Project Policy
bash
gcloud compute firewall-policies create \
--project=PROJECT_ID \
--name=project-app-policy
gcloud compute firewall-policies rules create \
--firewall-policy=project-app-policy \
--project=PROJECT_ID \
--priority=100 \
--direction=INGRESS \
--action=allow \
--match="{'srcIpRanges': ['35.191.0.0/16'], 'destPorts': [443]}"Multi-Org Scenarios
Scenario 1: Strict Org, Relaxed Folder
Organization Policy:
Rule 1: DENY all ingress from internet
Folder "Development":
Policy: Override with ALLOW from internet
Project "dev-api" (in Development folder):
No project policy
VPC "dev-api" (in dev-api project):
No VPC rules
Traffic: Internet → dev-api VPC
Evaluation:
Step 1: Org policy says DENY
Is there folder override? → YES (Development folder)
→ Use ALLOW
Step 2: Folder policy applies (ALLOW)
→ Packet allowed ✓Scenario 2: Exception List
Organization Policy:
"Deny ingress from internet EXCEPT these projects: [marketing, api-public]"
Evaluation for each project:
Project "api-public": In exception? YES → Inherit org ALLOW
Project "app-internal": In exception? NO → Inherit org DENY
Project "marketing": In exception? YES → Inherit org ALLOWScenario 3: Multi-org Federation
Organization A (main):
Organization Policy: Base security policy
Organization B (subsidiary acquired):
Organization Policy: Inherited from org-wide settings
Firewall rule evaluation: Respects each org's policies independently
(No cross-org hierarchy)Enforcement: Allow vs Deny
Allow Policy
Organization Policy:
Rule: ALLOW ingress from corporate-network
VPC Rule:
Rule: ALLOW ingress from 0.0.0.0/0
Evaluation: Organization ALLOW + VPC ALLOW = ALLOW ✓
Effect: Packet allowed
Even stricter VPC rule cannot DENY what org allowsDeny Policy
Organization Policy:
Rule: DENY ingress from internet
VPC Rule:
Rule: ALLOW ingress from 0.0.0.0/0
Evaluation: Organization DENY > VPC ALLOW → DENY ✓
Effect: Packet denied (org policy wins)
VPC rule cannot override org denyExceptions: Granular Control
Exception by Project
Organization Policy:
Base rule: DENY all ingress
Exception: except projects in folder "Public APIs"
Result:
Projects in "Public APIs" folder → Can have ingress policies
All other projects → RestrictedException by Service
Organization Policy:
Base rule: DENY port 22 (SSH)
Exception: except Cloud IAP service
Result:
Direct SSH: DENIED
SSH via Cloud IAP: ALLOWED
(IAP traffic counted as from trusted Google service)Exception by Condition
Organization Policy (CEL expression):
DENY ingress EXCEPT WHERE:
- Source IP in corporate-whitelist AND
- Destination port in [443, 8443] AND
- Protocol == TCP
Result: Very fine-grained control per ruleObservability: Auditing Policies
List Policies
bash
# Organization-level:
gcloud compute firewall-policies list \
--organization=ORGANIZATION_ID
# Folder-level:
gcloud compute firewall-policies list \
--parent=folders/FOLDER_ID
# Project-level:
gcloud compute firewall-policies list \
--project=PROJECT_IDDescribe Policy Rules
bash
gcloud compute firewall-policies rules list \
--firewall-policy=org-default-deny \
--organization=ORGANIZATION_ID \
--format=tableAudit Logs
bash
gcloud logging read \
'resource.type="compute#FirewallPolicy" AND
protoPayload.methodName="compute.firewallPolicies.patchRule"' \
--limit=50Policy Conflicts: Resolution Order
When multiple policies apply (org + folder + project):
Precedence (highest to lowest):
1. Organization Policy (explicit DENY always wins)
2. Folder Policy
3. Project Policy
4. VPC Rules (lowest level)
Example conflict:
Org policy: DENY 0.0.0.0/0 (ingress)
Project policy: ALLOW 0.0.0.0/0 (ingress)
Result: ORG POLICY WINS → DENY
(Principle: Most restrictive wins)Common Patterns
Pattern 1: Organization-wide DDoS Protection
Organization Policy:
Rule 1 (priority 100): DENY from known-bad IPs (threat intelligence)
Rule 2 (priority 500): ALLOW from verified CDN providers
Rule 3 (priority 65534): ALLOW all (default)
Effect:
All projects inherit DDoS filtering
CDN traffic always allowed (exception)
Everything else allowed (baseline)Pattern 2: Compliance Data Residency
Organization Policy:
Rule: DENY ingress from outside-compliance-region
Compliance regions defined: us-central1, us-east1 only
Effect:
VMs in us-central1, us-east1: Can receive traffic
VMs in europe-west1: Cannot (policy enforced)Pattern 3: Prod vs Dev Segmentation
Organization:
├── Folder "Production"
│ Policy: DENY all except monitored, audited IPs
└── Folder "Development"
Policy: ALLOW all (permissive for agility)
Result: Strict prod, flexible dev, single enforcement pointBest Practices
✅ Do:
- Define organization-level baseline policies (deny + allow exceptions)
- Use exceptions for specific use cases (avoid complexity)
- Audit policy changes via Cloud Audit Logs
- Test policies in staging first
- Document policy rationale
❌ Don't:
- Create overlapping policies (confusing evaluation order)
- Use overly complex CEL expressions (hard to debug)
- Forget that organization policy is inherited (affects all projects)
- Mix ALLOW and DENY rules without clear precedence
- Disable organization policies without replacement
Troubleshooting
Symptom: VPC Rule Not Applied
bash
Diagnosis:
1. Check organization policy:
gcloud compute firewall-policies list --organization=ORG
2. Check folder policy:
gcloud compute firewall-policies list --parent=folders/FOLDER
3. Check project policy:
gcloud compute firewall-policies list --project=PROJECT
4. List all rules at each level and trace evaluation
5. Check exceptions:
gcloud compute firewall-policies rules describe RULE_ID \
--firewall-policy=POLICY_ID \
--organization=ORG
Result: If org policy DENY, VPC ALLOW rule never evaluatedSymptom: Unexpected Traffic Denial
bash
Diagnosis:
1. Get firewall policy rules in order of priority:
gcloud compute firewall-policies rules list \
--firewall-policy=POLICY_ID \
--sort-by=priority
2. Check CEL expressions for match:
Rule 1: priority 100, DENY from 0.0.0.0/0?
Match incoming traffic? → YES
→ Packet DENIED here
3. Verify no lower-priority exceptions:
gcloud compute firewall-policies rules describe \
--firewall-policy=POLICY_ID \
--priority=200
Result: Find blocking rule, check if exception appliesConclusion
Hierarchical firewall policies provide enterprise-grade security:
- Organization level: Baseline security (DDoS, compliance)
- Folder level: Team/environment policies (prod vs dev)
- Project level: Application-specific rules
- VPC level: Fine-grained traffic control
Key principle: Centralized baseline, decentralized overrides.
For large organizations (10K+ projects), hierarchical policies are essential.