Edge Security: HTTPS Load Balancing, Cloud CDN, and Cloud Armor
Scenario
An HTTP load balancer isn't enough for production. You require encrypted HTTPS connections and protection from DDoS attacks or SQL injection. You will orchestrate a Global HTTPS Load Balancer. This involves creating a Google-managed SSL certificate, tying it to a Target HTTPS proxy, caching responses at the edge with Cloud CDN, and explicitly securing the backend with a Cloud Armor Web Application Firewall (WAF) security policy.
- Provision a google_compute_managed_ssl_certificate attached to a dummy domain.
- Provision a google_compute_security_policy (Cloud Armor) that allows all traffic, but drops specific blacklisted IP ranges.
- Create the Load Balancer track (Forwarding Rule -> HTTPS Target Proxy -> URL Map -> Backend Service).
- Attach the SSL certificate to the target proxy.
- Attach the Cloud Armor policy and enable_cdn = true to the backend service.
Additional Context
Google-Managed Certificates: GCP can provision and automatically rotate SSL certs for you. However, the certificate will remain in a "PROVISIONING" status until the DNS A record for your domain dynamically points to the Load Balancer's public IP address so Google can verify you own the domain.
Cloud Armor Attachment: Cloud Armor policies are attached at the `google_compute_backend_service` (or backend bucket) level. This means you can have different security rules for different microservices sitting behind the same unified Router/Load Balancer.
main.tf
provider "google" {
project = var.project_id
}
# 1. Cloud Armor WAF Policy
resource "google_compute_security_policy" "defense_policy" {
name = "defense-waf"
# Rule 1000: Block an evil subnet
rule {
action = "deny(403)"
priority = "1000"
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = ["9.9.9.0/24"]
}
}
description = "Block known bad actors"
}
# Default rule: Allow all other traffic
rule {
action = "allow"
priority = "2147483647"
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = ["*"]
}
}
description = "Default permit"
}
}
# 2. Managed SSL Certificate
resource "google_compute_managed_ssl_certificate" "default" {
name = "mysite-cert"
managed {
domains = ["api.myproductiondomain.com"]
}
}
# 3. Dummy Backend setup (Instance Group or Serverless NEG goes here in reality)
resource "google_compute_health_check" "default" {
name = "https-hc"
http_health_check { port = 80 }
}
resource "google_compute_backend_service" "backend" {
name = "secure-backend"
port_name = "http"
protocol = "HTTP" # Communication from edge to backend is HTTP
load_balancing_scheme = "EXTERNAL"
health_checks = [google_compute_health_check.default.id]
# Enable Cloud CDN caching
enable_cdn = true
# Attach Cloud Armor WAF
security_policy = google_compute_security_policy.defense_policy.id
}
# 4. Routing via URL Map
resource "google_compute_url_map" "default" {
name = "https-url-map"
default_service = google_compute_backend_service.backend.id
}
# 5. HTTPS Proxy (Associating Cert and URL Map)
resource "google_compute_target_https_proxy" "default" {
name = "https-proxy"
url_map = google_compute_url_map.default.id
# Attach the SSL certificate
ssl_certificates = [google_compute_managed_ssl_certificate.default.id]
}
# 6. Global Forwarding Rule (Public IP for port 443)
resource "google_compute_global_forwarding_rule" "default" {
name = "https-global-rule"
target = google_compute_target_https_proxy.default.id
port_range = "443"
load_balancing_scheme = "EXTERNAL"
}Workflow Commands
terraform init
terraform apply -var="project_id=my-gcp-project-123"
# Note: The SSL certificate will only activate if you map "api.myproductiondomain.com"
# to the provisioned public IP address in your DNS registrar.
# Otherwise, it will fail to verify.
terraform destroy -var="project_id=my-gcp-project-123"
