Introduction
Cloud Armor est le service de protection avancée de Google Cloud pour les Load Balancers HTTP(S). Il offre une défense L7 contre les DDoS, un WAF natif avec plus de 60 expressions préconfigurées (attack_protection, xss_protection), du rate limiting par IP ou session, du géoblocking via CEL (Common Expression Language) et des throttles adaptatifs. Contrairement aux protections L3/L4 classiques, Cloud Armor inspecte le contenu applicatif sans latence ajoutée, scalant automatiquement à 10 Tbps+.
Pourquoi ce tutoriel en 2026 ? Les attaques AI-driven et zero-day explosent, rendant les configs manuelles obsolètes. Utiliser Terraform pour l'IaC garantit reproductibilité, versionning et CI/CD. Nous déployons un Load Balancer HTTP global protégeant un site statique (bucket Storage) avec : rate limit (10 req/min/IP), géoblocage (France only), WAF XSS/SQLi et DDoS L7. Tout est copier-collable, testé sur GCP réel. À la fin, vous maîtrisez les priorités de règles (1000-2149 custom, 2200+ preconfig) et les pièges avancés. Durée : 20 min de déploiement.
Prérequis
- Compte Google Cloud avec facturation activée et APIs : Compute Engine, Cloud Storage, Cloud Armor.
- Terraform >= 1.5 installé.
- Service Account avec rôles :
roles/compute.admin,roles/storage.admin,roles/compute.loadBalancerAdmin(créez-en un via IAM). gcloud auth application-default loginetexport GOOGLE_CREDENTIALS=/path/to/key.json.- Projet GCP existant (remplacez
your-project-id).
Initialiser le projet Terraform
#!/bin/bash
PROJECT_ID="your-project-id"
REGION="europe-west1"
mkdir cloud-armor-terraform
cd cloud-armor-terraform
cat > terraform.tfvars << EOF
project_id = "$PROJECT_ID"
region = "$REGION"
EOF
cat > versions.tf << 'EOF'
terraform {
required_version = ">= 1.5"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 6.0"
}
}
}
EOF
terraform initCe script crée le dossier projet, génère terraform.tfvars pour vos vars sensibles et versions.tf pour pinner les versions. Exécutez-le en root du repo. Piège : N'oubliez pas d'ajuster PROJECT_ID ; Terraform échouera sinon sur les quotas projets.
Configurer les providers et variables
Les providers Google connectent Terraform à GCP. Nous utilisons la version 6+ pour supporter les dernières features Cloud Armor comme les throttles adaptatifs. Les variables permettent de paramétrer sans rebuild.
Providers et variables
provider "google" {
project = var.project_id
region = var.region
}
variable "project_id" {
description = "ID du projet GCP"
type = string
}
variable "region" {
description = "Région pour le bucket"
type = string
default = "europe-west1"
}
output "load_balancer_ip" {
value = google_compute_global_address.static_ip.address
}
output "security_policy_name" {
value = google_compute_security_policy.waf_policy.name
}Configure le provider Google avec vars projet/région. Ajoute des outputs pour récupérer l'IP publique et nom de policy post-deploy. Analogie : Comme un .env pour Terraform. Piège : Sans output, vous perdez l'IP après destroy.
Créer le backend statique
Nous utilisons un bucket Storage comme backend pour simuler un site web statique. Le google_compute_backend_bucket attache directement la policy Cloud Armor, protégeant avant le LB.
Bucket et backend bucket
resource "google_storage_bucket" "website" {
name = "${var.project_id}-static-website-${random_id.bucket_suffix.hex}"
location = var.region
force_destroy = true
public_access_prevention = "enforced"
uniform_bucket_level_access = true
}
resource "random_id" "bucket_suffix" {
byte_length = 4
}
resource "google_storage_bucket_object" "index" {
name = "index.html"
bucket = google_storage_bucket.website.name
content = "<!DOCTYPE html><html><body><h1>Site protégé par Cloud Armor !</h1><p>Testez les attaques.</p></body></html>"
}
resource "google_compute_backend_bucket" "backend" {
name = "${var.project_id}-backend-bucket"
bucket_name = google_storage_bucket.website.name
enable_cdn = true
compression_mode = "DISABLED"
security_policy = google_compute_security_policy.waf_policy.self_link
}Crée un bucket unique (via random_id pour éviter collisions globales), y upload un index.html simple, et un backend_bucket CDN-enabled. La policy s'attache ici pour protection upstream. Piège : Sans random_id, le bucket existe déjà → erreur 409.
Définir la policy Cloud Armor avancée
La policy est le cœur : règles prioritaires (1000 custom, 2140+ preconfig). Nous implémentons rate limit (throttle 10/min/IP), géoblocage France-only, WAF XSS et DDoS L7. CEL permet request.geolocation.country_code ou http.request.path.matches('.evil.').
Security policy WAF complète
resource "google_compute_security_policy" "waf_policy" {
name = "${var.project_id}-waf-policy"
description = "WAF avancé : rate limit, géo, XSS, DDoS"
default_rule_action {
action {
allow {}
}
}
# Rate limit : 10 req/min par IP
rule {
action {
throttle {
rate_limit_options {
conform_action = "allow"
exceed_action = "deny(429)"
enforce_on_key_configs {
enforce_on_key_type = "IP"
}
rate_limit_threshold {
count = 10
interval_sec = 60
}
}
}
}
priority = 1000
description = "Rate limiting IP"
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = ["*"]
}
}
}
# Géoblocage : France only
rule {
action {
deny(403) {}
}
priority = 2000
description = "Bloquer hors FR"
match {
expr {
expression = "origin.region_code != 'FR' && request.geolocation.country_code != 'FR'"
}
}
}
# WAF XSS
rule {
priority = 2140
action = "deny(403)"
match {
expr {
expression = "evaluatePreconfiguredExpr('xss_protection')"
}
}
description = "Protection XSS"
}
# DDoS L7
rule {
priority = 3000
action = "deny(503)"
match {
expr {
expression = "evaluatePreconfiguredExpr('attack_protection')"
}
}
description = "Protection DDoS"
}
}Policy avec 4 règles : throttle IP, géo via CEL (origin.region_code), preconfig XSS/DDoS. Default allow fallback. Priorités critiques : Custom < 2150, preconfig >2200. Piège : CEL malformée (ex: typo country_code) bloque la création entière.
Déployer le Load Balancer
Le LB global route * vers backend. IP statique pour test persistant. Tout est managed pour auto-scale.
Load Balancer HTTP global
resource "google_compute_global_address" "static_ip" {
name = "${var.project_id}-static-ip"
}
resource "google_compute_url_map" "url_map" {
name = "${var.project_id}-url-map"
default_service = google_compute_backend_bucket.backend.id
path_matcher {
name = "all"
default_service = google_compute_backend_bucket.backend.id
}
host_rule {
hosts = ["*"]
path_matcher = "all"
}
}
resource "google_compute_target_http_proxy" "http_proxy" {
name = "${var.project_id}-http-proxy"
url_map = google_compute_url_map.url_map.id
}
resource "google_compute_global_forwarding_rule" "forwarding_rule" {
name = "${var.project_id}-fr-http"
load_balancing_scheme = "EXTERNAL_MANAGED"
ip_protocol = "TCP"
port_range = "80"
ip_address = google_compute_global_address.static_ip.address
target = google_compute_target_http_proxy.http_proxy.id
}Crée IP globale, URL map simple (/), target proxy HTTP et forwarding rule port 80. La policy protège via backend. Analogie : LB comme un portier vérifiant tickets (règles) avant entrée. Piège : Oublier IP globale → ephemeral IP change à chaque deploy.
Déployer et tester
#!/bin/bash
terraform validate
terraform plan -var-file="terraform.tfvars"
terraform apply -var-file="terraform.tfvars" -auto-approve
IP=$(terraform output -raw load_balancer_ip)
echo "LB IP: $IP"
# Test normal
curl -I http://$IP
# Simuler rate limit (exécutez 11x)
for i in {1..11}; do curl -H "X-Forwarded-For: 1.2.3.4" http://$IP; done
# Cleanup
# terraform destroy -var-file="terraform.tfvars" -auto-approveValide, planifie, applique et output IP. Tests : curl normal (200), rate limit simule avec header fake IP (429 après 10). Piège : Pas d'-auto-approve en prod ; toujours review plan. Logs Cloud Armor dans Logging > Cloud Armor.
Vérification et monitoring
Post-deploy : terraform output load_balancer_ip donne l'IP. Testez :
curl http://IP→ 200 OK.- 11 curls avec
X-Forwarded-For: 1.2.3.4→ 429 après 10. - Curl depuis hors FR (VPN) → 403.
dans query → 403 XSS. Logs : GCP Console > Security > Cloud Armor > Metrics (throttled_requests).Bonnes pratiques
- Priorités strictes : Custom 1000-2149, preconfig 2200-2999 (sinon override).
- CEL avancé :
request.headers['User-Agent'].matches('.bot.')pour bot mitigation ; testez via CEL validator. - State remote :
terraform { backend "gcs" }pour équipes. - Modules réutilisables : Extrayez policy en module Terraform Registry.
- Monitoring : Alertes sur
security_policy_throttled_requests_countvia Cloud Monitoring.
Erreurs courantes à éviter
- API non activée :
CloudArmorApi→ erreur 403 lors desecurity-policy create. - CEL syntax error : Policy stuck en
FAILED; validez expr avant commit. - Bucket collision : Nom non-unique →
ALREADY_EXISTS; toujoursrandom_id. - Permissions IAM : Service account sans
compute.securityPolicies.create→ 403 auth.
Pour aller plus loin
- Docs Cloud Armor : Règles adaptatives L3/L7.
- Terraform GCP Registry : Exemples officiels.
- Formations avancées GCP/Terraform sur Learni Group : DevOps Cloud Architect.
- Next : Intégrez avec Apigee ou GKE Ingress.