Skip to content

Operate GCP VM Firewall Rules (HyOps)

  • Purpose: Manage named GCP ingress firewall rules scoped to VM network tags, independently of shared VPC infrastructure. Owner: Platform engineering

  • Trigger: New VM deployment needs port access (RDP, VNC, app ports, standalone IAP SSH), or rule cleanup after VM teardown

  • Impact: Creates or removes google_compute_firewall resources on the target VPC
  • Severity: P3 Pre-reqs: GCP init complete for the environment, target VPC exists, platform/gcp/platform-vm state exists if tagging VMs.

  • Rollback strategy: Run hyops destroy with the same module ref and inputs file.


Context

Module: platform/gcp/vm-firewall-rules Driver: iac/terragrunt Pack: gcp/platform/10-platform/10-vm-firewall-rules@v1.0

This module manages firewall rules that are scoped to specific VMs via network tags. It does not touch the VPC, subnets, or any shared network infrastructure. It is the correct tool when:

  • You need a port opened for a specific VM type (e.g., RDP on allow-rdp tag)
  • You are using the default VPC or a VPC not managed by org/gcp/wan-hub-network
  • You need the IAP SSH rule on a standalone VPC (rather than depending on wan-hub-network)

For VMs already on a VPC managed by org/gcp/wan-hub-network, the IAP SSH rule already exists and this module is not needed for port 22.


Inputs reference

Input Type Default Notes
name_prefix string "" Used in firewall rule name: {prefix}-{context_id}-{name_suffix}
context_id string "" Scoping identifier
project_id string "" Optional override; defaults to env credentials project
network string "default" VPC network name
rules list [] List of rule objects (see below)

Each rule in rules:

Field Required Default Notes
name_suffix yes : Appended to prefix to form the GCP rule name
description no ""
direction no INGRESS INGRESS or EGRESS
priority no 1000
source_ranges no [] CIDR ranges (INGRESS); becomes destination_ranges for EGRESS
target_tags no [] Network tags the rule applies to
allow yes : List of {protocol, ports[]}

Common patterns

RDP access for a Windows VM

name_prefix: platform
context_id: desktop
network: default
rules:
  - name_suffix: allow-rdp
    description: "RDP access for Windows desktop VM"
    direction: INGRESS
    priority: 1000
    source_ranges:
      - "<YOUR_IP>/32"
    target_tags:
      - allow-rdp
    allow:
      - protocol: tcp
        ports: ["3389"]

The corresponding VM must carry the allow-rdp tag in its platform/gcp/platform-vm inputs.

IAP SSH on default VPC (standalone: no wan-hub-network)

name_prefix: platform
context_id: labs
network: default
rules:
  - name_suffix: allow-iap-ssh
    description: "IAP SSH access for platform VMs"
    direction: INGRESS
    priority: 1000
    source_ranges:
      - "35.235.240.0/20"
    target_tags:
      - allow-iap-ssh
    allow:
      - protocol: tcp
        ports: ["22"]

Multiple rules in one module state

name_prefix: platform
context_id: desktop
network: default
rules:
  - name_suffix: allow-rdp
    source_ranges: ["<YOUR_IP>/32"]
    target_tags: [allow-rdp]
    allow:
      - protocol: tcp
        ports: ["3389"]
  - name_suffix: allow-iap-ssh
    source_ranges: ["35.235.240.0/20"]
    target_tags: [allow-iap-ssh]
    allow:
      - protocol: tcp
        ports: ["22"]

Steps

  1. Prepare inputs file

    cp "$HYOPS_CORE_ROOT/modules/platform/gcp/vm-firewall-rules/examples/inputs.min.yml" \
       ~/my-firewall-rules.yml
    # edit to set name_prefix, context_id, network, and rules
    
  2. Preflight

    hyops preflight --env dev \
      --module platform/gcp/vm-firewall-rules \
      --inputs ~/my-firewall-rules.yml
    
  3. Apply

    hyops apply --env dev \
      --module platform/gcp/vm-firewall-rules \
      --inputs ~/my-firewall-rules.yml
    
  4. Verify

    hyops state show --env dev --module platform/gcp/vm-firewall-rules
    

Expected: status: ok, outputs.rule_names map populated.

Cross-check in GCP:

    gcloud compute firewall-rules list \
      --project <PROJECT_ID> \
      --filter="targetTags~allow-rdp OR targetTags~allow-iap-ssh" \
      --format="table(name,network,direction,sourceRanges,targetTags,allowed)"
  1. Destroy (when VMs are torn down)
    hyops destroy --env dev \
      --module platform/gcp/vm-firewall-rules \
      --inputs ~/my-firewall-rules.yml
    

Verification

Primary state:

~/.hybridops/envs/<env>/state/modules/platform__gcp__vm-firewall-rules/latest.json

Run-record files:

~/.hybridops/envs/<env>/logs/module/platform__gcp__vm-firewall-rules/<run_id>/
├── terragrunt_apply.stdout.txt
├── terragrunt_destroy.stdout.txt
└── driver_result.json

Updating source ranges

To restrict or expand which IPs can reach the VM, edit the source_ranges in your inputs file and re-apply. Terraform will update the rule in place:

hyops apply --env dev \
  --module platform/gcp/vm-firewall-rules \
  --inputs ~/my-firewall-rules.yml

Troubleshooting

already exists error during apply

Cause: a firewall rule with the same computed name exists outside Terraform state (created manually or by another module).

Fix:

  • Rename the name_suffix in your inputs, or
  • Import the existing rule into Terraform state (advanced: requires direct terraform import via the pack directory)

Rule exists but VM is still unreachable

Check (in order):

  1. VM has the matching network tag:

    gcloud compute instances describe <VM_NAME> \
      --project <PROJECT_ID> --zone <ZONE> \
      --format="get(tags.items)"
    
  2. Rule targets the correct network (not a different VPC)

  3. Source IP matches source_ranges (check your current public IP)
  4. The destination port is actually listening on the VM

source_ranges must not be empty for INGRESS

Cause: source_ranges left as [] in the inputs for an INGRESS rule.

Fix: provide at least one CIDR range. For IAP SSH use 35.235.240.0/20. For RDP use your operator IP.


References