mikelindner.com

powering the Internet since 1995

| Photography | Belair Moonshine | LinkedIn |

Terraform Website in a Box (of code)

January 21st, 2022

Here’s a simple example of how to create a rock solid site in Terraform, this uses Terraform Cloud, which HashiCorp recommends. I tend to agree, although vendor lock-in and HCL is something that should consider.

It’s basically an s3 bucket behind all the stuff needed for a CloudFront CDN. It’s not hard to swap out the static s3 site for something more substantial, using this code as a starting point. Remove all my junk, I like to amuse myself with ascii graphics and stuff in code. Keeps it real.

#####
##### Make a website as simply as possible.
#####

terraform {
  cloud {
    organization = "FremantleTechnology"
    workspaces {
      name = "mykl-rocks"
    }
  }
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region = "ap-southeast-2"
}

locals {
  common_tags = {
    OwnedBy     = "[email protected]"
    Name        = "hosting bucket"
    Environment = "dev"
  }
}

#####
##### Set Up Hosting Bucket
#####

resource "aws_s3_bucket" "hosting_bucket" {
  tags   = local.common_tags
  bucket = "mykl.rocks"
}

resource "aws_s3_bucket_acl" "hosting_bucket_acl" {
  bucket = aws_s3_bucket.hosting_bucket.id
  acl    = "public-read"
}

resource "aws_s3_bucket_versioning" "hosting_bucket_versioning" {
  bucket = aws_s3_bucket.hosting_bucket.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_website_configuration" "hosting_bucket_website_conf" {
  bucket = aws_s3_bucket.hosting_bucket.id
  index_document {
    suffix = "index.html"
  }
  error_document {
    key = "error.html"
  }
}

#####
##### Add Objects (stuff to be hosted) to Hosting Bucket
#####

resource "aws_s3_object" "index_page" {
  tags         = local.common_tags
  bucket       = aws_s3_bucket.hosting_bucket.id
  key          = "/index.html"
  source       = "site_files/index.html"
  acl          = "public-read"
  content_type = "text/html"
}

resource "aws_s3_object" "error_page" {
  tags         = local.common_tags
  bucket       = aws_s3_bucket.hosting_bucket.id
  key          = "/error.html"
  source       = "site_files/error.html"
  acl          = "public-read"
  content_type = "text/html"
}

resource "aws_s3_object" "site_logo_image" {
  tags   = local.common_tags
  bucket = aws_s3_bucket.hosting_bucket.id
  key    = "/rock.png"
  source = "site_files/rock.png"
  acl    = "public-read"
}

#####
##### Set Up CLoudFront
##### mykl.rocks.s3.amazonaws.com

module "cdn" {
  source                        = "terraform-aws-modules/cloudfront/aws"
  tags                          = local.common_tags
  aliases                       = ["mykl.rocks"]
  comment                       = "mykl.rocks"
  default_root_object           = "index.html"
  enabled                       = true
  is_ipv6_enabled               = true
  price_class                   = "PriceClass_All"
  retain_on_delete              = false
  wait_for_deployment           = false
  create_origin_access_identity = true

  origin_access_identities = {
    s3_bucket_one = "mykl.rocks oai"
  }

  origin = {

    s3_one = {
      domain_name = "mykl.rocks.s3.amazonaws.com"
      s3_origin_config = {
        origin_access_identity = "s3_bucket_one"
      }
    }
  }

  default_cache_behavior = {
    target_origin_id       = "s3_one"
    viewer_protocol_policy = "redirect-to-https"
    allowed_methods        = ["GET", "HEAD", "OPTIONS"]
    cached_methods         = ["GET", "HEAD"]
    compress               = true
    query_string           = true
  }

  viewer_certificate = {
    acm_certificate_arn = "arn:aws:acm:us-east-1:721648336598:certificate/22fb2915-0681-43c7-88f1-c0f5a8987e2f"
    ssl_support_method  = "sni-only"
  }

  #logging_config = {
  #   bucket = aws_s3_bucket.hosting_bucket.id
  # }
}