Infrastructure as Code: Provisioning Secure C Clusters on Google Cloud Using Terraform
Terraform Provider Configuration for Google Cloud
To provision resources on Google Cloud Platform (GCP) using Terraform, we first need to configure the Google Cloud provider. This involves specifying your GCP project ID, the region and zone for resource deployment, and authentication credentials. For production environments, it’s highly recommended to use a service account with least-privilege permissions.
Create a file named main.tf and define the provider block as follows. Ensure you replace your-gcp-project-id with your actual GCP project ID.
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 4.0"
}
}
}
provider "google" {
project = "your-gcp-project-id"
region = "us-central1"
zone = "us-central1-a"
}
Authentication can be handled in several ways. The most common and secure method for CI/CD pipelines or automated deployments is by setting the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your service account key JSON file. Alternatively, Terraform can infer credentials from the environment if you’re running it on a GCE instance with an attached service account, or if you’ve authenticated using gcloud auth application-default login.
Provisioning a GKE Cluster with Enhanced Security
We’ll define a Google Kubernetes Engine (GKE) cluster using the google_container_cluster resource. For security, we’ll focus on enabling network policies, private clusters, and workload identity.
Network Policies: Enforcing network policies is crucial for microsegmentation within your cluster, limiting pod-to-pod communication. This requires enabling the Calico network plugin.
Private Clusters: Private clusters restrict access to the Kubernetes API server and nodes from the public internet, significantly reducing the attack surface. Nodes will only have private IP addresses.
Workload Identity: This is the recommended way to grant GKE workloads access to Google Cloud services. It allows Kubernetes service accounts to impersonate Google service accounts, avoiding the need to manage long-lived Kubernetes secrets for cloud credentials.
resource "google_container_cluster" "secure_gke_cluster" {
name = "secure-c-cluster"
location = "us-central1-a"
# Enable network policy enforcement
network_policy {
enabled = true
provider = "CALICO" # Or "VPC_NATIVE" if using GKE's native network policy
}
# Configure for private cluster
private_cluster_config {
enable_private_nodes = true
enable_private_endpoint = false # Set to true for fully private API server
master_ipv4_cidr_block = "172.16.0.0/28" # A dedicated /28 for the control plane
# Optionally, if enable_private_endpoint is true:
# master_global_access_config {
# enabled = false
# }
}
# Enable Workload Identity
workload_identity_config {
workload_pool = "${var.project_id}.svc.id.goog"
}
# Node pool configuration
node_pool {
name = "default-node-pool"
initial_node_count = 1
node_locations = ["us-central1-a"]
autoscaling {
min_node_count = 1
max_node_count = 5
}
# Security enhancements for nodes
management {
auto_repair = true
auto_upgrade = true
}
# Shielded GKE Nodes for enhanced security
shielded_instance_config {
enable_secure_boot = true
enable_integrity_monitoring = true
}
# Ephemeral OS disks for better security and performance
local_ssd_count = 0 # Use ephemeral OS disks by default
disk_type = "pd-standard" # Or "pd-ssd" for performance
disk_size_gb = 100
}
# Enable VPC-native networking for better IP management and network policies
ip_allocation_policy {
cluster_ipv4_cidr_block = "/17" # /17 for pods, adjust as needed
services_ipv4_cidr_block = "/20" # /20 for services
}
# Enable Shielded GKE Nodes for the control plane
enable_shielded_nodes = true
# Enable Binary Authorization for secure container deployments
binary_authorization {
evaluation_mode = "POLICY_ENFORCE"
}
# Enable Node Auto-Provisioning for dynamic node scaling
autoscaling {
location_policy = "BALANCED"
}
# Enable Node Auto-Upgrades
release_channel {
channel = "REGULAR" # Or "STABLE", "RAPID"
}
# Enable Logging and Monitoring
logging_service = "logging.googleapis.com/kubernetes"
monitoring_service = "monitoring.googleapis.com/kubernetes"
# Specify the Kubernetes version
min_master_version = "1.25" # Ensure this is a supported and stable version
# Define network and subnetwork
network = "default" # Or your custom VPC network
subnetwork = "default" # Or your custom subnetwork
# Enable Confidential Computing for sensitive workloads (optional, incurs higher costs)
# confidential_nodes {
# enabled = true
# }
# Enable Node Pool auto-repair and auto-upgrade
node_pool {
name = "default-node-pool"
initial_node_count = 1
autoscaling {
min_node_count = 1
max_node_count = 5
}
management {
auto_repair = true
auto_upgrade = true
}
# ... other node pool configurations
}
}
variable "project_id" {
description = "The GCP project ID."
type = string
default = "your-gcp-project-id" # Replace with your actual project ID
}
# Output the cluster name and endpoint for easy access
output "cluster_name" {
description = "The name of the GKE cluster."
value = google_container_cluster.secure_gke_cluster.name
}
output "cluster_endpoint" {
description = "The public endpoint of the GKE cluster."
value = google_container_cluster.secure_gke_cluster.endpoint
}
output "cluster_ca_certificate" {
description = "The cluster's CA certificate."
value = google_container_cluster.secure_gke_cluster.master_auth.0.cluster_ca_certificate
}
Service Account and IAM Configuration
For Workload Identity to function correctly, we need to create a Google service account and grant it specific IAM roles. This service account will be impersonated by the Kubernetes service account running your application pods.
First, define the Google service account in Terraform:
resource "google_service_account" "gke_workload_sa" {
account_id = "gke-workload-sa"
display_name = "GKE Workload Service Account"
project = var.project_id
}
resource "google_project_iam_member" "gke_workload_sa_binding" {
project = var.project_id
role = "roles/storage.objectViewer" # Example role, replace with necessary roles
member = "serviceAccount:${google_service_account.gke_workload_sa.email}"
}
# Grant the GKE service agent the ability to impersonate the Google service account
resource "google_service_account_iam_member" "gke_service_agent_impersonation" {
service_account_id = google_service_account.gke_workload_sa.name
role = "roles/iam.workloadIdentityUser"
member = "serviceAccount:${var.project_id}.svc.id.goog[${var.project_id}/default]" # Adjust namespace if needed
}
Next, create a Kubernetes service account and annotate it to link it with the Google service account. This is typically done in a separate Kubernetes manifest file or using a Kubernetes provider for Terraform.
Here’s an example of how you might define the Kubernetes service account and its annotation using a kubernetes provider (assuming you have configured it):
provider "kubernetes" {
host = google_container_cluster.secure_gke_cluster.endpoint
cluster_ca_certificate = base64decode(google_container_cluster.secure_gke_cluster.master_auth.0.cluster_ca_certificate)
token = data.google_client_config.current.access_token
}
data "google_client_config" "current" {}
resource "kubernetes_service_account" "app_sa" {
metadata {
name = "app-service-account"
namespace = "default" # Or your application's namespace
annotations = {
"iam.gke.io/gcp-service-account" = google_service_account.gke_workload_sa.email
}
}
}
Applying the Terraform Configuration
Once your Terraform files (main.tf, variables.tf if you create one, etc.) are in place, you can provision the infrastructure. Ensure your GCP credentials are set up correctly (e.g., via GOOGLE_APPLICATION_CREDENTIALS environment variable).
- Initialize Terraform:
terraform init
- Review the execution plan:
terraform plan
- Apply the configuration to create the GKE cluster and associated resources:
terraform apply
After the apply is complete, you can configure kubectl to connect to your new cluster using the output values from Terraform:
gcloud container clusters get-credentials secure-c-cluster --zone us-central1-a --project your-gcp-project-id
This setup provides a robust foundation for a secure GKE cluster, leveraging Infrastructure as Code for repeatability and consistency. Remember to tailor IAM roles and network policies to your specific application requirements.