Infrastructure as Code: Provisioning Secure WooCommerce Clusters on Google Cloud Using Terraform
Terraform Project Structure and Provider Configuration
We’ll start by establishing a robust Terraform project structure and configuring the Google Cloud provider. This ensures a clean, maintainable, and secure infrastructure deployment. Our project will be organized into modules for better reusability and logical separation of concerns.
Create a root directory for your Terraform project, e.g., gcp-woocommerce-iac. Inside this, create a main.tf file for the main configuration and a providers.tf file for provider definitions.
providers.tf
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 4.0"
}
}
}
provider "google" {
project = var.gcp_project_id
region = var.gcp_region
zone = var.gcp_zone
}
variable "gcp_project_id" {
description = "The GCP project ID to deploy resources into."
type = string
}
variable "gcp_region" {
description = "The GCP region for resource deployment."
type = string
default = "us-central1"
}
variable "gcp_zone" {
description = "The GCP zone for resource deployment."
type = string
default = "us-central1-a"
}
This configuration declares the Google Cloud provider and specifies the project, region, and zone. We’re using variables for these to allow for easy customization. The required_providers block ensures that the correct version of the Google provider is downloaded.
Networking: VPC, Subnets, and Firewall Rules
Securely isolating your WooCommerce cluster within a Virtual Private Cloud (VPC) is paramount. We’ll define a custom VPC, private subnets for our application and database tiers, and strict firewall rules to control ingress and egress traffic.
Create a network.tf file in your root directory.
network.tf
resource "google_compute_network" "vpc_network" {
name = "woocommerce-vpc"
auto_create_subnetworks = false
routing_mode = "REGIONAL"
}
resource "google_compute_subnetwork" "app_subnet" {
name = "woocommerce-app-subnet"
ip_cidr_range = "10.10.1.0/24"
region = var.gcp_region
network = google_compute_network.vpc_network.id
private_ip_google_access = true # Allows instances to reach Google APIs without external IPs
}
resource "google_compute_subnetwork" "db_subnet" {
name = "woocommerce-db-subnet"
ip_cidr_range = "10.10.2.0/24"
region = var.gcp_region
network = google_compute_network.vpc_network.id
private_ip_google_access = true
}
# Allow SSH from specific IP ranges (e.g., your office or bastion host)
resource "google_compute_firewall" "allow_ssh" {
name = "allow-ssh"
network = google_compute_network.vpc_network.name
allow {
protocol = "tcp"
ports = ["22"]
}
source_ranges = ["YOUR_SECURE_IP_RANGE"] # e.g., "203.0.113.0/24" or "192.168.1.0/24"
target_tags = ["ssh-enabled"]
}
# Allow HTTP/HTTPS from the internet for the web tier
resource "google_compute_firewall" "allow_http_https" {
name = "allow-http-https"
network = google_compute_network.vpc_network.name
allow {
protocol = "tcp"
ports = ["80", "443"]
}
source_ranges = ["0.0.0.0/0"]
target_tags = ["web-server"]
}
# Allow internal communication between app and db subnets (e.g., MySQL port)
resource "google_compute_firewall" "allow_db_access" {
name = "allow-db-access"
network = google_compute_network.vpc_network.name
allow {
protocol = "tcp"
ports = ["3306"] # MySQL default port
}
source_ranges = [google_compute_subnetwork.app_subnet.ip_cidr_range]
destination_ranges = [google_compute_subnetwork.db_subnet.ip_cidr_range]
target_tags = ["database-server"]
}
# Deny all other ingress by default (implicit deny, but good practice to be explicit if needed)
# For simplicity, we rely on GCP's default deny-all for unconfigured rules.
Replace YOUR_SECURE_IP_RANGE with the actual IP address range from which you’ll manage your instances. Using private_ip_google_access = true on subnets is crucial for security, as it allows instances to communicate with Google Cloud services without needing public IP addresses.
Database Tier: Cloud SQL for MySQL
For the database, we’ll provision a highly available Cloud SQL instance for MySQL. This managed service offloads operational burdens like patching, backups, and replication.
Create a database.tf file.
database.tf
resource "google_sql_database_instance" "woocommerce_db" {
name = "woocommerce-db-instance"
project = var.gcp_project_id
region = var.gcp_region
database_version = "MYSQL_8_0"
settings {
tier = "db-custom-2-7680" # Example: 2 vCPUs, 7.5 GB RAM. Adjust as needed.
ip_configuration {
ipv4_enabled = false # Disable public IP for enhanced security
private_network = google_compute_network.vpc_network.id
}
backup_configuration {
enabled = true
binary_log_enabled = true # Required for point-in-time recovery
}
location_preference {
zone = var.gcp_zone
}
availability_type = "REGIONAL" # For high availability
disk_autoresize = true
disk_size = 100 # GB
disk_type = "PD_SSD"
}
# Set a strong root password. Consider using secrets management for production.
root_password = var.db_root_password
}
resource "google_sql_database" "woocommerce_db_name" {
name = "woocommerce_db"
instance = google_sql_database_instance.woocommerce_db.name
project = var.gcp_project_id
}
resource "google_sql_user" "woocommerce_user" {
name = "woocommerce_user"
instance = google_sql_database_instance.woocommerce_db.name
host = "%" # Allow connections from any host within the VPC
password = var.db_user_password
project = var.gcp_project_id
}
variable "db_root_password" {
description = "Root password for the Cloud SQL instance."
type = string
sensitive = true
}
variable "db_user_password" {
description = "Password for the WooCommerce database user."
type = string
sensitive = true
}
We’re configuring the instance with a regional availability type for HA, disabling public IP, and enabling automated backups. The private_network setting ensures the instance is only accessible from within our VPC. Sensitive variables like passwords should ideally be managed via a secrets manager (e.g., Google Secret Manager) in production environments, not directly in Terraform variables.
Application Tier: Compute Engine Instances and Load Balancing
The application tier will consist of Compute Engine instances running a web server (e.g., Nginx) and PHP-FPM, serving the WooCommerce application. A Google Cloud Load Balancer will distribute traffic across these instances.
Create an app.tf file.
app.tf
# Instance Template for Web Servers
resource "google_compute_instance_template" "woocommerce_web_template" {
name_prefix = "woocommerce-web-"
project = var.gcp_project_id
machine_type = "e2-medium" # Adjust based on expected load
tags = ["web-server", "ssh-enabled"]
disk {
source_image = "debian-cloud/debian-11" # Or your preferred OS image
auto_delete = true
boot = true
}
network_interface {
subnetwork = google_compute_subnetwork.app_subnet.id
# No access_config block here to ensure instances don't get public IPs directly
}
metadata = {
# User data for initial setup (install Nginx, PHP, etc.)
# This is a simplified example; consider using a configuration management tool
# like Ansible or a startup script for more complex setups.
startup-script = <<-EOF
#!/bin/bash
apt-get update
apt-get install -y nginx php php-fpm php-mysql
systemctl start nginx
systemctl enable nginx
systemctl start php7.4-fpm # Adjust PHP version as needed
systemctl enable php7.4-fpm
# Further configuration to serve WooCommerce files and connect to DB
# would go here. This typically involves downloading WP/WooCommerce,
# configuring Nginx vhost, and setting up PHP-FPM.
# Example: Download WooCommerce from a private repository or S3.
# Example: Configure Nginx to proxy_pass to php-fpm.
# Example: Update wp-config.php with DB credentials.
EOF
}
scheduling {
automatic_restart = true
on_host_maintenance = "MIGRATE"
}
lifecycle {
create_before_destroy = true
}
}
# Managed Instance Group for Auto-scaling
resource "google_compute_instance_group_manager" "woocommerce_web_igm" {
name = "woocommerce-web-igm"
project = var.gcp_project_id
zone = var.gcp_zone
base_instance_name = "web"
version {
instance_template = google_compute_instance_template.woocommerce_web_template.id
name = "v1"
}
target_size = 2 # Initial number of instances
auto_healing_policies {
initial_delay_sec = 300
health_check = google_compute_health_check.app_health_check.id
}
update_policy {
type = "PROACTIVE"
minimal_action = "REPLACE"
}
}
# Autoscaling configuration
resource "google_compute_autoscaler" "woocommerce_autoscaler" {
name = "woocommerce-autoscaler"
project = var.gcp_project_id
zone = var.gcp_zone
target = google_compute_instance_group_manager.woocommerce_web_igm.id
autoscaling_policy {
max_replicas = 10
min_replicas = 2
cooldown_period = 60
cpu_utilization {
target = 0.6 # Scale up when CPU utilization reaches 60%
}
# Add other metrics like load balancing serving capacity if needed
}
}
# Health Check for the Load Balancer and IGM
resource "google_compute_health_check" "app_health_check" {
name = "app-health-check"
project = var.gcp_project_id
check_interval_sec = 5
timeout_sec = 5
healthy_threshold = 2
unhealthy_threshold = 2
http_health_check {
port = 80
request_path = "/" # WooCommerce should respond to root path with 200 OK
}
}
# Global External HTTP(S) Load Balancer
resource "google_compute_global_forwarding_rule" "http_forwarding_rule" {
name = "http-forwarding-rule"
project = var.gcp_project_id
ip_protocol = "TCP"
port_range = "80"
target = google_compute_target_http_proxy.http_proxy.id
ip_address = "0.0.0.0" # Any IP
}
resource "google_compute_target_http_proxy" "http_proxy" {
name = "http-proxy"
project = var.gcp_project_id
url_map = google_compute_url_map.url_map.id
}
resource "google_compute_url_map" "url_map" {
name = "woocommerce-url-map"
project = var.gcp_project_id
default_service = google_compute_backend_service.app_backend_service.id
}
resource "google_compute_backend_service" "app_backend_service" {
name = "woocommerce-app-backend"
project = var.gcp_project_id
protocol = "HTTP"
port_name = "http"
timeout_sec = 10
enable_cdn = false
load_balancing_scheme = "EXTERNAL"
backend {
group = google_compute_instance_group_manager.woocommerce_web_igm.instance_group
}
health_checks = [google_compute_health_check.app_health_check.id]
}
# Optional: HTTPS setup with Google-managed SSL certificates
# resource "google_compute_managed_ssl_certificate" "default" {
# name = "woocommerce-ssl-cert"
# project = var.gcp_project_id
# managed {
# domains = ["your-domain.com"] # Replace with your domain
# }
# }
# resource "google_compute_target_https_proxy" "https_proxy" {
# name = "https-proxy"
# project = var.gcp_project_id
# url_map = google_compute_url_map.url_map.id
# ssl_certificates = [google_compute_managed_ssl_certificate.default.id]
# }
# resource "google_compute_global_forwarding_rule" "https_forwarding_rule" {
# name = "https-forwarding-rule"
# project = var.gcp_project_id
# ip_protocol = "TCP"
# port_range = "443"
# target = google_compute_target_https_proxy.https_proxy.id
# ip_address = "0.0.0.0" # Any IP
# }
The google_compute_instance_template defines the configuration for our web servers. The startup-script is a basic example; for production, you'd want a more robust deployment mechanism. The google_compute_instance_group_manager and google_compute_autoscaler handle scaling and self-healing. The load balancer components (forwarding rule, target proxy, URL map, backend service) direct traffic to the instance group. Note the absence of access_config in the instance template's network interface, ensuring instances are not directly exposed to the internet.
Security Hardening and Best Practices
Beyond network segmentation and private IPs, several other security measures are critical for a production WooCommerce deployment.
Service Accounts and IAM
Each Compute Engine instance should run with a dedicated service account that has the *least privilege* necessary. For example, if your application needs to write logs to Cloud Logging, grant it the roles/logging.logWriter role. Avoid using the default Compute Engine service account with broad permissions.
# Example: Create a custom service account for the app tier
resource "google_service_account" "woocommerce_app_sa" {
account_id = "woocommerce-app-sa"
display_name = "WooCommerce Application Service Account"
project = var.gcp_project_id
}
# Grant necessary permissions (e.g., Cloud Logging)
resource "google_project_iam_member" "app_sa_logging" {
project = var.gcp_project_id
role = "roles/logging.logWriter"
member = "serviceAccount:${google_service_account.woocommerce_app_sa.email}"
}
# Update instance template to use this service account
resource "google_compute_instance_template" "woocommerce_web_template" {
# ... other configurations ...
service_account {
email = google_service_account.woocommerce_app_sa.email
scopes = ["cloud-platform"] # Adjust scopes as needed
}
# ... rest of the configuration ...
}
Secrets Management
Database credentials, API keys, and other secrets should never be hardcoded in Terraform or instance startup scripts. Use Google Secret Manager. Your application instances would then fetch these secrets at runtime.
Regular Patching and Updates
While Cloud SQL is managed, your Compute Engine instances require patching. Implement a strategy for updating your OS and application dependencies. This could involve creating new instance templates with updated images and performing rolling updates via the instance group manager.
Web Application Firewall (WAF)
For enhanced protection against common web exploits (SQL injection, XSS), consider deploying a WAF. Google Cloud Armor is a managed WAF service that can be integrated with your load balancer.
Deployment Workflow
With the Terraform configuration in place, the deployment process is straightforward:
- Initialize Terraform: Run
terraform initin your project root. - Review the plan: Execute
terraform plan -var="gcp_project_id=your-project-id" -var="db_root_password=your-root-password" -var="db_user_password=your-user-password". Carefully inspect the resources Terraform will create. - Apply the configuration: Run
terraform apply -var="gcp_project_id=your-project-id" -var="db_root_password=your-root-password" -var="db_user_password=your-user-password". Confirm withyeswhen prompted.
For production, use a CI/CD pipeline (e.g., GitLab CI, GitHub Actions, Cloud Build) to automate these steps, manage variables securely, and enforce review processes.