Friday 15 November 2019

How to host secure/non-secure Static Website on S3 using Terraform

Most of us know how AWS is growing and with it's growth, It is making developer's lives easier to develop and deploy live applications. Most of us definitely have a use case where we want to deploy a static website for product marketing or maybe for personal profile showcase or maybe because of client's requirement

AWS S3 provides a feature to host static websites (by static it means content is never dynamic) on S3 buckets and gives you an endpoint through which you can access the website. However, we need to consider the fact that we cannot make the site secure(with ssl, which is certainly a corner case because making a static site secure doesn't make sense to me at least) directly but indirectly it is definitely possible. This is where CloudFront comes into the picture and turns the table around for some developers because configuring the cloud front adds a bit of complexity.

Additionally, What if you have a case where you need to host multiple website. You need to go through the entire process multiple times.

  • Making an S3 bucket
  • Uploading files to the bucket
  • Configuring the static website
  • Configuring cloud front
  • Create a Domain name and map it to the CloudFront domain and create a record set. fuhhh 😓 -->You can skip this step if you don't want your site to be secured on SSL.
If you are going through the same feeling let's automate it with a tool called "Terraform".

main.tf

provider "aws"{
region = "us-east-1"
}
resource "aws_s3_bucket" "website_bucket" {
  bucket = "${var.name_domain}.${var.root_domain}"
  acl    = "private"
  website {
    index_document = "index.html"
    error_document = "error.html"
  }
  tags = {
    Name        = "${var.Customer}"
    Environment = "${var.Environment}"
  }
region = "us-east-1"
}
data "aws_s3_bucket" "get_s3_zone" {
  bucket = "${var.name_domain}.${var.root_domain}"
  depends_on = ["aws_s3_bucket.website_bucket"]
}
data "aws_route53_zone" "getZone" {
  count = "${var.hostedZone == "yes" ? 1 : 0}"
  name         = "${var.root_domain}"
  private_zone = false
}
resource "aws_route53_zone" "website_zone" {
  count = "${var.hostedZone == "yes" ? 0 : 1}"
  name = "${var.root_domain}"
    tags = {
    Name        = "${var.Customer}"
    Environment = "${var.Environment}"
  }
}
data "aws_acm_certificate" "fetch_certificate_arn" {
  domain   = "${var.certificate}"
  statuses = ["ISSUED"]
  most_recent = true
}
resource "aws_cloudfront_distribution" "website_cloudfront" {
  origin {
    domain_name = "${aws_s3_bucket.website_bucket.website_endpoint}"
    origin_id = "${var.Customer}_S3_origin"
    custom_origin_config {
        origin_protocol_policy = "http-only"
        https_port = 443
        http_port = 80
        origin_ssl_protocols = ["TLSv1", "SSLv3"]
        }   
 }
  enabled = true
  aliases = ["${var.name_domain}.${var.root_domain}"]
  price_class = "PriceClass_200"
  retain_on_delete = true
  default_cache_behavior {
    allowed_methods = [ "GET", "HEAD"]
    cached_methods = [ "GET", "HEAD" ]
    target_origin_id = "${var.Customer}_S3_origin"
    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }
    viewer_protocol_policy = "redirect-to-https"
    min_ttl = 0
    default_ttl = 3600
    max_ttl = 86400
  }
  viewer_certificate {
    acm_certificate_arn = "${data.aws_acm_certificate.fetch_certificate_arn.arn}"
    ssl_support_method = "sni-only"
    minimum_protocol_version = "TLSv1.1_2016"
  }
  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }
depends_on = ["aws_s3_bucket.website_bucket"]
}
resource "aws_route53_record" "www"{
 zone_id = "${var.hostedZone == "no" ? join("", aws_route53_zone.website_zone.*.zone_id) : join ("",data.aws_route53_zone.getZone.*.zone_id)}"
  name    = "${var.name_domain}.${var.root_domain}"
  type    = "A"
  alias {
    name                   = "${aws_cloudfront_distribution.website_cloudfront.domain_name}"
    zone_id                = "${aws_cloudfront_distribution.website_cloudfront.hosted_zone_id}"
    evaluate_target_health = "false"
  }
depends_on = [aws_route53_zone.website_zone]
}
output "website_endpoint" {
value = aws_s3_bucket.website_bucket.website_endpoint
}

inputs.tf

variable "hostedZone"{
description = "'yes': if 'PUBLIC' hosted zone for the root domain is present , else 'no' NOTE: Make sure the hosted zone is public and not private. If the hosted zone is present but is private enter 'no'"
}
variable "root_domain"{
description = "Root domain of the website eg. If Website is xyz.example.com, root_domain is example.com"
}
variable "name_domain"{
description = "If Website is xyz.example.com, name_domain is xyz"
}
variable "Customer"{
description = "Name of the customer"
}
variable "Environment"{
description = "Customer's Environment"
}
variable "certificate"{
description = "Enter the certificate to use eg. if you have the root domain as example.com enter '*.example.com' to use wildcard cert else enter whole domain of the website to use a custom cert"
}

terraform.tfvars

Customer = "Quicktrixx"
Environment = "prod"
root_domain  = "" #example: quicktrixx.com or quicktrixx.qa
name_domain = "" #example:example, So if your whole domain is hello.example.com enter 'hello' in the name domain and 'example.com' in root domain


If you are facing any issues let me know in the comments section.

Regards,
Quicktrixx👻

How to install google-chrome in redhat without redhat subscription

Install google-chrome in redhat  Download the .rpm file of chrome https://www.google.com/chrome/thank-you.html?installdataindex=empty&st...