Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error creating cloudfront distribution with terraform. InvalidViewerCertificate

I'm trying to deploy a ReactJS project statically to s3 using Terraform

My s3 bucket terraform config to create the bucket with the policy:

resource "aws_s3_bucket" "site" {
  bucket = var.domain
  acl = "public-read"

  policy = <<EOF
{
  "Version":"2012-10-17",
  "Statement":[{
        "Sid":"PublicReadForGetBucketObjects",
        "Effect":"Allow",
          "Principal": "*",
      "Action":["s3:GetObject"],
      "Resource":["arn:aws:s3:::${var.domain}/*"]
    }
  ]
}
  EOF

  website {
      index_document = "index.html"
      error_document = "404.html"
  }
}

route53 config with the necessary dns:

resource "aws_route53_zone" "main" {
  name = var.domain
}

resource "aws_route53_record" "root_domain" {
  zone_id = aws_route53_zone.main.zone_id
  name = var.domain
  type = "A"

  alias {
    name = aws_cloudfront_distribution.cdn.domain_name
    zone_id = aws_cloudfront_distribution.cdn.hosted_zone_id
    evaluate_target_health = false
  }
}

cloudfront config:

resource "aws_cloudfront_distribution" "cdn" {
  origin {
    origin_id   = var.domain
    domain_name = aws_s3_bucket.site.bucket_regional_domain_name

    custom_origin_config {
      http_port = 80
      https_port = 443
      origin_protocol_policy = "match-viewer"
      origin_ssl_protocols = ["TLSv1", "TLSv1.1", "TLSv1.2"]
    }
  }

  aliases = [var.domain]

  enabled             = true
  wait_for_deployment = false
  default_root_object = "index.html"

  custom_error_response {
      error_caching_min_ttl = 0
      error_code = 404
      response_code = 200
      response_page_path = "/index.html"
  }

  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD", "OPTIONS"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = var.domain

    forwarded_values {
      query_string = true
      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "allow-all"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 86400
  }

  price_class = "PriceClass_100"

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

Even though I'm trying to use cloudfront default certificate i keep getting the following error after running terraform apply:

Error: error creating CloudFront Distribution: InvalidViewerCertificate: To add an alternate domain name (CNAME) to a CloudFront distribution, you must attach a trusted certificate that validates your authorization to use the domain name.

like image 691
AM DEV Avatar asked Jan 28 '20 14:01

AM DEV


People also ask

How would you create a CloudFront distribution using terraform?

Launch EC2 instance. In this EC2 instance use the key and security group which we have created in step 1. Developer have uploded the code into github repo also the repo has some images. Create S3 bucket, and copy/deploy the images from github repo into the s3 bucket and change the permission to public readable.

How do I enable CloudFront cache?

If you want OPTIONS responses to be cached, do the following: Choose the options for default cache behavior settings that enable caching for OPTIONS responses. Configure CloudFront to forward the following headers: Origin , Access-Control-Request-Headers , and Access-Control-Request-Method .


4 Answers

Finally fixed it, if you want to use the default certificate you cannot add alternate domain names to the CloudFront distribution, you will need to generate an SSL certificate using Amazon certificate manager. In other words, to make this work you need to comment out aliases = [var.domain] in the CloudFront config part

like image 81
AM DEV Avatar answered Oct 21 '22 09:10

AM DEV


This problem is of course not related to Terraform.

As mentoied in How do I resolve the "InvalidViewerCertificate" error exception while creating or updating a CloudFront distribution:

This error message:

To add an alternate domain name (CNAME) to a CloudFront distribution, you must attach a trusted certificate that validates your authorization to use the domain name.

Indicates that the alternate domain names (CNAMEs) on the distribution aren't covered by the Subject Alternative Name (SAN) of the certificate that you provided.
You can request a public certificate with ACM, or you can contact your certificate authority (CA) for an updated certificate that covers the alternate domain names on the distribution.

(*) Regarding the provided answer above - Notice that you are not forced to use Amazon certificate manager - you can use external provider (for example the free LetsEncrypt) as long as you follow the mentioned rules.

like image 2
RtmY Avatar answered Oct 21 '22 08:10

RtmY


Terraform version of the @RtmY reply could look something like this. In order to get a certificate and validate it you have to do it in us-east-1 region, therefore we need to introduce it in your settings:

provider "aws" {
  version = "~> 2.46.0"
}

provider "aws" {
  version = "~> 2.46.0"
  region = "us-east-1"
  alias = "us-east-1"
}

Then we have to create a certificate:

resource "aws_acm_certificate" "cert" {
  provider = aws.us-east-1
  domain_name       = local.bucket_name
  validation_method = "DNS"

  lifecycle {
    create_before_destroy = true
  }
}

To validate a certificate we have to create a DNS entry using Route53:

resource "aws_route53_record" "cert_validation" {
  name = "${aws_acm_certificate.cert.domain_validation_options.0.resource_record_name}"
  type = "${aws_acm_certificate.cert.domain_validation_options.0.resource_record_type}"
  zone_id = var.zone-id-of-your-route-53
  records = ["${aws_acm_certificate.cert.domain_validation_options.0.resource_record_value}"]
  ttl = 60
} 

Last step, we have to validate newly created certificate, again in us-east-1 region:

resource "aws_acm_certificate_validation" "cert" {
  provider = aws.us-east-1
  certificate_arn         = aws_acm_certificate.cert.arn
  validation_record_fqdns = ["${aws_route53_record.cert_validation.fqdn}"]
}

Now, in our aws_cloudfront_distribution we keep aliases where they are, and have to add another configuration for the viewer certificate:

viewer_certificate {
    acm_certificate_arn = aws_acm_certificate_validation.cert.certificate_arn
    ssl_support_method = "sni-only"
}

I assume, such validation works for one alias only and not for many. In case of many aliases, the example from the docs might suit better: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation

The solution was borrowed from here:

Terraform AWS ACM certificates in us-east-1 for resources in eu-west-1

like image 1
klimksh Avatar answered Oct 21 '22 09:10

klimksh


I had this issue too, found that I had accidentally created the cert through the ACM in the wrong region. The certificate must be in the same region as the distribution

like image 1
willcwf Avatar answered Oct 21 '22 07:10

willcwf