petitviolet blog

    Terraform to provision GCP CDN for GCS backend

    2023-02-20

    TerraformGCP

    Google Cloud offers CDN(content delivery/distributed network) that can be backed by Cloud Storage, a.k.a GCS. Terraform supports provisioning CDN in GCP as always.

    As well as the previous post, in Terraform, variables should be declared in variables.tf but use locals here instead for simplicity a.

    locals {
        gcp_project    = "awesome-project"
        region         = "asia-northeast1"
        user_emails    = ["hoge@example.com"]
        base_domain    = "example.com"
    
        cdn_bucket_name = "hogehoge"
        cdn_bucket_cors_origins = [
            "http://localhost:3000",
        ]
    }
    

    Use google_storage_bucket resource to create a GCS bucket.

    resource "google_storage_bucket" "cdn_bucket" {
      name          = local.cdn_bucket_name
      project       = local.gcp_project
      location      = local.region
    
      uniform_bucket_level_access = false
    
    
      cors {
        origin          = local.cdn_bucket_cors_origins
        method          = ["GET", "HEAD", "POST"]
        response_header = ["*"]
        max_age_seconds = 3600
      }
    }
    

    From the viewpoint of security, as using IAM in GCP is basically recommended, giving uniform_bucket_level_access = true would be a good practice. See the document for details.

    Then, for being able to use the created bucket as a backend of CDN, use google_compute_backend_bucket with enable_cdn = true.

    resource "google_compute_backend_bucket" "app_cdn" {
      name        = "app-cdn-backend"
      description = "backend for app-cdn bucket"
      bucket_name = local.cdn_bucket_name
      enable_cdn  = true
    }
    

    As the last step, provisioning a load balancer to point to the backend. Picking up google_compute_url_map resource to provision load balancer for the google_compute_backend_bucket backend.

    resource "google_compute_url_map" "api_url_map" {
      name            = "api-urlmap"
      default_service = xxx // whatever you want
    
      host_rule {
        hosts        = ["cdn.${local.base_domain}"]
        path_matcher = "cdn"
      }
    
      path_matcher {
        name            = "cdn"
        default_service = google_compute_backend_bucket.app_cdn.id
      }
    }
    

    It seems that having one load balancer in one google project that being backed by multiple services like GAE, Run, etc. is a good practice for the sake of maintainability and cost. There should be more resources including google_compute_target_https_proxy, google_compute_managed_ssl_certificate, and others to provision the load balancer completely, but let me skip them since it's not the main topic of this post.