Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
March 21, 2022 08:38 pm GMT

How to secure your site on AWS with CloudFront and ACM?

In the previous article, we've gone over setting up a static site on S3 and associating it with a custom domain.

Did you notice that the website URL uses HTTP? That's not very secure, and we'd better use HTTPS, which is mainly a layer of encryption added to HTTP. In this post, we will secure the site with an SSL Certificate, which proves ownership of the website and signed by a trusted authority. In addition, we'll build everything with Infrastructure as Code.

Image description

Introduction

We assume in this post that there is a website already deployed and working but not secured with HTTPS (If you don't have this implemented, you can have a look at this article).

Before we dig into the technical details, let's go over a high-level plan of what we need to do to secure our site:

  • Create an SSL certificate to prove the ownership of the site
  • Create a CloudFront distribution that would deliver our content from S3 to the viewers - We don't use S3 directly as S3 static websites don't have support for HTTPS
  • Update the A record (a record that maps domain names to IPs) in Route 53 to point to the CloudFront distribution

Don't worry if you're not familiar with these services, as the following section will include a brief explanation of each one.

Create SSL Certificate

We will create an SSL Certificate using AWS Certificate Manager (ACM). If you look at the ACM in the AWS Console, you could choose between requesting a certificate, importing your own certificate or creating a private certificate authority. We want to request a certificate as we would like it to be a public certificate available on the internet and trusted by applications and browsers by default. Private Certificates are mainly used on private networks.

To do it with Terraform, create an acm.tf file with the following content:

resource "aws_acm_certificate" "cert" {  domain_name       = var.domainName  validation_method = "DNS"  lifecycle {    create_before_destroy = true  }}

It's recommended to specify create_before_destroy = true in a lifecycle block to replace a certificate that is currently in use.

We have two options to validate the certificate: DNS or Email. When we choose DNS, ACM provides you with one or more CNAME records that must be added to your DNS host zone - These records contain a unique key-value pair that proves that you control the domain. That's how we do it in Terraform:

resource "aws_route53_record" "cert-cname" {  for_each = {    for dvo in aws_acm_certificate.example_cert.domain_validation_options : dvo.domain_name => {      name   = dvo.resource_record_name      record = dvo.resource_record_value      type   = dvo.resource_record_type    }  }  allow_overwrite = true  name            = each.value.name  records         = [each.value.record]  ttl             = 60  type            = each.value.type  zone_id         = aws_route53_zone.example_domain.zone_id}resource "aws_acm_certificate_validation" "example-validation" {  certificate_arn         = aws_acm_certificate.example_cert.arn  validation_record_fqdns = [for record in aws_route53_record.cert-cname : record.fqdn]}

It takes a bit of time to get the certificate validated (there is an open issue about this).

Create a CloudFront Distribution

You might be wondering what CloudFront is and why we need it in this case. So here's a quick summary before we continue with our setup:

CloudFront is a content delivery network service offered by AWS. It is beneficial for many purposes, such as distributing your content to edgel locations closer to your users, offering better performance, protecting against Network and Application Layer Attacks, and edge computing.

Why do we need it?

According to the documentation, Amazon S3 website endpoints do not support HTTPS. If you want to use HTTPS, you can use Amazon CloudFront to serve a static website hosted on Amazon S3.

Another thing around using ACM certificate with CloudFront is that the certificate has to be in the US East (N. Virgina) Region (us-east-1). Add the following snippet to the acm.tf file created provider = aws.virgina under aws_acm_certificate and aws_acm_certificate_validation blocks, and add this provider block at the top of the file: provider "aws" { alias = "virgina" region = "us-east-1" }

Let's build it:

A cloud front distribution is where you define how your content will be distributed. So we will start with it:

resource "aws_cloudfront_distribution" "example_distribution" {}

The following configuration exists inside the distribution block:

  • Add the origin to that distribution; that's where CloudFront will be retrieving the content from (S3 bucket in our case):
    origin {      domain_name = aws_s3_bucket.example.bucket_regional_domain_name      origin_id   = local.s3_origin_id    }
  • Mark the distribution as enabled and define the default root object (that's index.html):
  enabled             = true  default_root_object = "index.html"
  • Add your custom domain as an alternate domain in CloudFront
    aliases = [var.domainName]
  • Define the default cache behaviour for this distribution. This defines which HTTP methods CloudFront forwards to the S3 bucket, which responses to cache depending on the request HTTP method, and the forwarded values that specify how CloudFront handles query strings, cookies and headers. :
  default_cache_behavior {      allowed_methods  = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]      cached_methods   = ["GET", "HEAD"]      target_origin_id = local.s3_origin_id      forwarded_values {        query_string = false        cookies {          forward = "none"        }      }      viewer_protocol_policy = "allow-all"      min_ttl                = 0      default_ttl            = 3600      max_ttl                = 86400    }
  • Define any restrictions (none in our case) - this is usually used to restrict/enable content distribution by country:
  restrictions {    geo_restriction {      restriction_type = "none"    }  }
  • Set up the viewer certificate; that's the arn of the certificate we created earlier, and that's how we enable viewers to use HTTPS

    • There are two ways to serve HTTPS requests. The first one is using Server Name Indication (SNI), and the second is to dedicate an IP address in each edge location that would serve our content (the second method is expensive)
  viewer_certificate {    acm_certificate_arn = aws_acm_certificate.cert.arn    ssl_support_method = "sni-only"  }

By this, we have finished the setup for our CloudFront distribution.

Route 53 updates

The only thing left is to have our A record in route 53 points to the CloudFront distribution rather than the S3 bucket directly. That's changing the alias inside of the aws_route53_record:

resource "aws_route53_record" "exampleDomain-a" {  zone_id = aws_route53_zone.exampleDomain.zone_id  name    = var.domainName  type    = "A"  alias {    name                   = aws_cloudfront_distribution.example_distribution.domain_name    zone_id                = aws_cloudfront_distribution.example_distribution.hosted_zone_id    evaluate_target_health = true  }}

Run terraform apply to deploy your change.

I hope this was helpful. I'd be keen to hear your thoughts. Do you have a different method to secure your site?


Original Link: https://dev.to/aws-builders/how-to-secure-your-site-on-aws-with-cloudfront-and-acm-5ako

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To