Skip to content
All projects

PF-02 · GCP · IaC

GCP Terraform GKE platform

A module set that keeps capacity during GKE node pool upgrades with SURGE, and opens only what a VPN needs through a firewall baseline, all as code.

Role
Design and implementation
Period
Personal project · released Nov 2026
Cloud
GCP
Scale
22 modules · 3 examples
Key tech
Terraform · GCP · GKE · Cloud Logging · Cloud Monitoring
GitHub
22
Terraform modules
5
Extra nodes first (max_surge)
0
Nodes down at once (max_unavailable)

At a glance

GKE node pool SURGE upgrademax_surge = 5 max_unavailable = 0New nodesOld nodesOld nodes leave one at a time · 0 unavailableSwapped to 5 new nodes · 0 nodes unavailableSoak 3600s applies only to BLUE_GREEN
The swap finishes. The 3600s soak value is read only under BLUE_GREEN.

Problem

A GKE node upgrade must not reduce serving capacity, and management ports should open only from a VPN.

Approach

The node pool upgrades with SURGE: five new nodes come up first and unavailable stays at zero. The c2sfirewall module opens management ports from the VPN at priority 1000 and denies other tcp and udp outbound at priority 65534.

Result

Old nodes leave only after replacements are ready. Host errors flow from the hostError audit log to a log-based metric, an alert policy, and a Slack channel.

Up close

Firewall evaluated in priority orderTwo rules from the c2sfirewall module, plus the GCP implied rules1000 · INGRESS allowVPN ranges to tcp 22, 3389, 637965534 · EGRESS denytcp and udp 0-65535 outbound denied65535 · GCP implied rulesInbound deny, outbound allowVPNallowServer outbounddenyDeny by default, open only what is needed with an earlier rule
An allow rule ahead of 65534 can still open a specific path.

Node pool SURGE settings

What this code does: Brings new nodes up first so no node is unavailable during an upgrade.

  node_pool = {
    game = {
      autoscaling_enable = true
      min_node_count     = 3
      max_node_count     = 12
      location_policy    = "BALANCED"
      node_count         = null
      pool_version       = "1.31"
      machine_type       = "e2-standard-4"
      tags               = ["gke-node"]

      # Five extra nodes come up first, and no node is taken away until its replacement is ready.
      strategy        = ["SURGE"]
      max_surge       = 5
      max_unavailable = 0

      # Soak time is read only when the strategy is switched to BLUE_GREEN.
      node_pool_soak_duration = "3600s"
    }
  }

A VPN-only firewall baseline

What this code does: Opens management ports only from VPN ranges, at priority 1000.

locals {
  firewall_rules = {
    c2s-inbound-vpn = {
      direction            = "INGRESS"
      action               = "allow"
      ranges               = var.vpn_source_ranges
      sources              = null
      targets              = null
      use_service_accounts = false
      enable_logging       = false
      priority             = "1000"
      rules = [
        {
          protocol = "tcp"
          ports    = var.management_ports
        }
      ]
    }

What I learned

A setting name alone can mislead. The soak time is read only under BLUE_GREEN, so the SURGE example leaves it out.

What I would improve

This repository defines GKE with Terraform and stops there. CI validates the examples but does not apply them.

Open to work · Cloud infrastructure and security