Skip to content

Instantly share code, notes, and snippets.

@ayltai
Created January 12, 2024 14:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ayltai/895eb7b13a9df5beee36af254c05c0d9 to your computer and use it in GitHub Desktop.
Save ayltai/895eb7b13a9df5beee36af254c05c0d9 to your computer and use it in GitHub Desktop.
terraform {
required_version = ">= 1.6.5"
backend "gcs" {
bucket = "rockstar_project_terraform_states"
prefix = "terraform/state"
}
required_providers {
google = {
source = "hashicorp/google"
version = ">= 5.10"
}
tls = {
source = "hashicorp/tls"
version = ">= 4.0"
}
acme = {
source = "vancluever/acme"
version = ">= 2.19"
}
local = {
source = "hashicorp/local"
version = ">= 2.4"
}
}
}
provider "google" {
region = var.region
zone = var.zone
}
provider "acme" {
server_url = "https://acme-v02.api.letsencrypt.org/directory"
}
locals {
website_buckets = [
for pair in setproduct(var.environments, var.static_website_bucket_names) : {
environment = pair[0]
name = "rockstar_project_${pair[0]}_${pair[1]}"
}
]
}
resource "google_storage_bucket" "rockstar_project_static_websites" {
for_each = {
for bucket in local.website_buckets : bucket.name => bucket
}
project = data.google_project.this.project_id
name = each.value.name
location = var.region_storage
uniform_bucket_level_access = false
force_destroy = true
# Set the default file to retrieve when none is specified, i.e. URLs ending with a slash
# Not-found page redirection is needed if this is a React SPA
website {
main_page_suffix = "index.html"
not_found_page = strcontains(each.value.name, "react") ? "index.html" : "404.html"
}
# Depends on your needs, setting CORS headers could make it easier for development
cors {
origin = [
"*",
]
method = [
"GET",
"HEAD",
"PUT",
"POST",
"DELETE",
"PATCH",
]
response_header = [
"*",
]
max_age_seconds = 300
}
}
# Make the files in the bucket publicly accessible
resource "google_storage_default_object_acl" "rockstart_project_static_websites" {
for_each = {
for bucket in local.website_buckets : bucket.name => bucket
}
bucket = each.value.name
role_entity = [
"READER:allUsers",
]
}
# Define a backend for the load balancer in dev environment
resource "google_compute_backend_bucket" "rockstart_project_static_website_dev" {
name = "static_website_dev"
bucket_name = google_storage_bucket.rockstar_project_static_websites["rockstar_project_static_website_dev"].name
enable_cdn = true
cdn_policy {
default_ttl = 300
client_ttl = 300
max_ttl = 3600
}
# This would make local development easier but not recommended in production
custom_response_headers = [
"Access-Control-Allow-Origin: *",
]
}
# Define a backend for the load balancer in staging environment
resource "google_compute_backend_bucket" "rockstart_project_static_website_staging" {
name = "static_website_staging"
bucket_name = google_storage_bucket.rockstar_project_static_websites["rockstar_project_static_website_staging"].name
enable_cdn = true
cdn_policy {
default_ttl = 300
client_ttl = 300
max_ttl = 3600
}
# This would make local development easier but not recommended in production
custom_response_headers = [
"Access-Control-Allow-Origin: *",
]
}
# Get a public IP address for the load balancer
resource "google_compute_global_address" "loadbalancer" {
name = "loadbalancer"
}
# Tell the load balancer how you'd like the traffic to be redirected to different storage bucket backends
resource "google_compute_url_map" "websites" {
name = "websites"
default_service = google_compute_backend_bucket.rockstart_project_static_website_dev.self_link
host_rule {
hosts = [
"dev.${var.domain}",
]
path_matcher = "rockstart-project-static-website-dev"
}
host_rule {
hosts = [
"staging.${var.domain}",
]
path_matcher = "rockstart-project-static-website-staging"
}
path_matcher {
name = "rockstart-project-static-website-dev"
default_service = google_compute_backend_bucket.rockstart_project_static_website_dev.self_link
}
path_matcher {
name = "rockstart-project-static-website-staging"
default_service = google_compute_backend_bucket.rockstart_project_static_website_staging.self_link
}
}
# Generate a private key of a SSL certificate for signing your HTTPS domain name, not needed for HTTP-only websites
resource "tls_private_key" "website" {
algorithm = "RSA"
}
# Tell our ACME provider to use our private key for certificate generation
resource "acme_registration" "website" {
account_key_pem = tls_private_key.website.private_key_pem
email_address = var.acme_email
}
resource "google_compute_ssl_certificate" "rockstart_project_static_website_dev" {
name = "rockstart-project-static-website-dev"
private_key = acme_certificate.rockstart_project_static_website_dev.private_key_pem
certificate = acme_certificate.rockstart_project_static_website_dev.certificate_pem
}
resource "google_compute_ssl_certificate" "rockstart_project_static_website_staging" {
name = "rockstart-project-static-website-staging"
private_key = acme_certificate.rockstart_project_static_website_staging.private_key_pem
certificate = acme_certificate.rockstart_project_static_website_staging.certificate_pem
}
# Use Google CloudDNS to solve the DNS-01 challenge
resource "acme_certificate" "rockstart-project-static-website-dev" {
account_key_pem = acme_registration.website.account_key_pem
common_name = "dev.${var.domain}"
dns_challenge {
provider = "gcloud"
config = {
GCE_PROJECT = var.project_id
GCE_SERVICE_ACCOUNT_FILE = var.service_account_key_file
}
}
}
# Assign the certificates to the HTTPS proxy of the load balancer, not needed for HTTP-only proxy
resource "google_compute_target_https_proxy" "websites" {
name = "websites"
url_map = google_compute_url_map.websites.self_link
ssl_certificates = [
google_compute_ssl_certificate.rockstart_project_static_website_dev.id,
google_compute_ssl_certificate.rockstart_project_static_website_staging.id,
]
}
# Map the incoming traffic of the load balancer to the HTTPS (or HTTP) proxy
resource "google_compute_global_forwarding_rule" "websites" {
name = "websites"
load_balancing_scheme = "EXTERNAL"
target = google_compute_target_https_proxy.websites.self_link
ip_address = google_compute_global_address.loadbalancer.address
port_range = "443"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment