(Opcjonalna) Google LB + Cloud CDN + Cloud Armor¶
Warstwa edukacyjna do nauki Google Global Load Balancer, Cloud CDN i Cloud Armor — bez zastępowania głównej architektury Cloudflare. Tworzy niezależny endpoint app-lb.kamilos.xyz.
Po co ta warstwa?¶
Cloudflare Free ($0/mies) jest lepszym wyborem ekonomicznym dla frontendu (ADR-005). Ale Google LB to wiedza wymagana na certyfikatach GCP i na rozmowach o architekturze. Ta warstwa pozwala wdrożyć i przebadać Google LB bez ryzyka dla produkcji — i usunąć ją jedną komendą.
app.kamilos.xyz ← prod (Cloudflare CDN → GCS) — zawsze działa
app-lb.kamilos.xyz ← edukacja (Google LB → GCS) — opcjonalny, $23-28/mies
Architektura warstwy¶
Browser
│ HTTPS (DNS A → 34.50.151.193)
▼
Cloud Armor Edge (geoblocking, IP filtering)
│
▼
Google Global HTTPS Load Balancer
│ EXTERNAL_MANAGED
▼
Cloud CDN (USE_ORIGIN_HEADERS)
│
▼
GCS bucket: app-lb.kamilos.xyz
(te same pliki co app.kamilos.xyz)
HTTP→HTTPS redirect jako osobna reguła (url_map + http_proxy + forwarding_rule).
Terraform — zasoby w kolejności zależności¶
# tf/frontend-lb/main.tf
# 1. Statyczny globalny IP
resource "google_compute_global_address" "frontend_lb" {
name = "frontend-lb-ip"
project = var.project_id
}
# 2. Cloud Armor Edge policy
resource "google_compute_security_policy" "frontend_lb" {
name = "frontend-lb-armor"
project = var.project_id
type = "CLOUD_ARMOR_EDGE" # (1)
rule {
action = "allow"
priority = 1000
match {
versioned_expr = "SRC_IPS_V1"
config { src_ip_ranges = ["*"] }
}
}
rule {
action = "deny(403)"
priority = 2147483647
match {
versioned_expr = "SRC_IPS_V1"
config { src_ip_ranges = ["*"] }
}
}
}
# 3. GCS bucket jako origin
resource "google_storage_bucket" "frontend_lb" {
name = "app-lb.kamilos.xyz"
location = "EU"
website {
main_page_suffix = "index.html"
not_found_page = "index.html"
}
}
resource "google_storage_bucket_iam_member" "public_read" {
bucket = google_storage_bucket.frontend_lb.name
role = "roles/storage.objectViewer"
member = "allUsers"
}
# 4. Backend bucket (łączy GCS + CDN + Cloud Armor)
resource "google_compute_backend_bucket" "frontend_lb" {
name = "frontend-lb-backend"
bucket_name = google_storage_bucket.frontend_lb.name
enable_cdn = true
cdn_policy {
cache_mode = "USE_ORIGIN_HEADERS" # (2)
}
edge_security_policy = google_compute_security_policy.frontend_lb.self_link
}
# 5. URL map (routing → backend bucket)
resource "google_compute_url_map" "frontend_lb" {
name = "frontend-lb-url-map"
default_service = google_compute_backend_bucket.frontend_lb.self_link
}
# 6. Managed SSL certificate
resource "google_compute_managed_ssl_certificate" "frontend_lb" {
name = "frontend-lb-ssl"
managed { domains = ["app-lb.kamilos.xyz"] } # (3)
}
# 7. HTTPS proxy
resource "google_compute_target_https_proxy" "frontend_lb" {
name = "frontend-lb-https-proxy"
url_map = google_compute_url_map.frontend_lb.self_link
ssl_certificates = [google_compute_managed_ssl_certificate.frontend_lb.self_link]
}
# 8. Global forwarding rule (public IP:443 → HTTPS proxy)
resource "google_compute_global_forwarding_rule" "frontend_lb_https" {
name = "frontend-lb-https"
target = google_compute_target_https_proxy.frontend_lb.self_link
port_range = "443"
ip_address = google_compute_global_address.frontend_lb.address
}
# 9. HTTP→HTTPS redirect (osobny url_map)
resource "google_compute_url_map" "http_redirect" {
name = "frontend-lb-http-redirect"
default_url_redirect {
https_redirect = true
redirect_response_code = "MOVED_PERMANENTLY_DEFAULT"
strip_query = false
}
}
# + google_compute_target_http_proxy + google_compute_global_forwarding_rule (port 80)
CLOUD_ARMOR_EDGE— jedyny typ obsługiwany przezbackend_bucket. Obsługuje geoblocking i IP filtering. Nie obsługuje rate limiting, WAF (XSS/SQLi), reCAPTCHA — te funkcje wymagająCLOUD_ARMOR+backend_service.USE_ORIGIN_HEADERS— CDN respektujeCache-Controlz GCS.index.html: no-cache,app.js: max-age=3600.- Google automatycznie provisionuje certyfikat TLS po DNS propagacji (10-30 min).
Konfiguracja DNS¶
Grey cloud w Cloudflare — obowiązkowo
app-lb.kamilos.xyz musi wskazywać bezpośrednio na IP LB (DNS A record, proxy OFF).
Z Cloudflare proxy (orange cloud): dwa SSL handshaki, Google managed cert nigdy nie zostanie wydany.
Po dodaniu A rekordu poczekaj na SSL certificate provisioning:
gcloud compute ssl-certificates describe frontend-lb-ssl \
--project=gcp-prototype-1-20260224 \
--format="value(managed.status,managed.domainStatus)"
# PROVISIONING → ACTIVE (~10-30 min po propagacji DNS)
Deploy i zarządzanie¶
Wdrożenie¶
# Przez GitHub Actions
gh workflow run deploy.yml \
-f action=apply \
-f layer=frontend-lb \
--repo benhornbeam/gcp-prototype-1-20260224
# Po apply: dodaj DNS A record, poczekaj na SSL
# Deploy plików frontendu (oddzielnie)
gcloud storage cp frontend/index.html gs://app-lb.kamilos.xyz/ \
--cache-control="no-cache, no-store, must-revalidate"
gcloud storage cp frontend/app.js gs://app-lb.kamilos.xyz/ \
--cache-control="public, max-age=3600"
Auto-deploy przez CI/CD¶
deploy-frontend.yml ma kroki dla obu bucketów. LB bucket z continue-on-error: true:
- name: Deploy to prod — LB bucket (opcjonalny)
if: github.ref_name == 'master'
continue-on-error: true # nie fail jeśli warstwa nie istnieje
run: |
gcloud storage cp frontend/index.html gs://app-lb.kamilos.xyz/ \
--cache-control="no-cache, no-store, must-revalidate"
gcloud storage cp frontend/app.js gs://app-lb.kamilos.xyz/ \
--cache-control="public, max-age=3600"
Usunięcie¶
gh workflow run deploy.yml \
-f action=apply \
-f layer=frontend-lb \
--repo benhornbeam/gcp-prototype-1-20260224
# lub lokalnie:
cd tf/frontend-lb && terraform destroy -var project_id=gcp-prototype-1-20260224
Po destroy: usuń A record z Cloudflare DNS.
Checkov — świadome wyjątki¶
# .checkov.yaml
- id: "CKV2_GCP_12"
comment: "LB access logs — pominięte dla prototypu; koszt vs wartość"
- id: "CKV_GCP_78"
comment: "Cloud Armor Edge nie obsługuje WAF — tylko CLOUD_ARMOR_EDGE dostępny dla backend_bucket"
Cloud Armor Edge vs Standard¶
| Cloud Armor Edge | Cloud Armor Standard | |
|---|---|---|
| Typ policy | CLOUD_ARMOR_EDGE |
CLOUD_ARMOR |
| Dołączany do | backend_bucket |
backend_service |
| Geoblocking | ✅ | ✅ |
| IP filtering | ✅ | ✅ |
| Rate limiting | ❌ | ✅ |
| WAF (XSS, SQLi) | ❌ | ✅ |
| reCAPTCHA | ❌ | ✅ |
| Koszt | Brak dodatkowego kosztu | $5/mies minimum |
| Użycie | Statyczny hosting (GCS) | Cloud Run, GCE, GKE |
Wniosek: jeśli chcesz chronić backend API (Cloud Run) przez Google LB — użyj backend_service + CLOUD_ARMOR Standard. Edge nie da WAF ani rate limiting.
Koszt warstwy¶
| Komponent | Koszt/mies |
|---|---|
| Global Forwarding Rules (2×) | ~$18 |
| Cloud CDN (minimal traffic) | ~$2 |
| Cloud Armor Edge | $0 (wbudowany w LB) |
| GCS bucket | ~$0.05 |
| Łącznie | ~$20-28/mies |
Pokrywane przez $300 GCP Free Trial (90 dni). Po terraform destroy — zero kosztów.
Pułapki¶
Grey cloud — inaczej SSL nie zadziała
Google managed certificate wymaga bezpośredniego połączenia do LB IP. Cloudflare proxy przerywa ten handshake.
Cloud Armor Edge nie zastąpi WAF
CLOUD_ARMOR_EDGE na backend_bucket to tylko geoblocking/IP. Dla pełnego WAF (XSS, SQLi) — backend_service + Cloud Run za LB + CLOUD_ARMOR Standard.