I am hosting a site from an S3 bucket and fronting it with a Cloudfront distribution, but after removing (applying-ing without the resource) the s3_distribution (through terraform) I am now unable to re-apply it from terraform.
I am faced with the error:
Error: error creating CloudFront Distribution: CNAMEAlreadyExists: One or more of the CNAMEs you provided are already associated with a different resource.
status code: 409, request id: 195fbaf4-85bb-49f5-8b0d-23a09da73435
on expo-website.tf line 98, in resource "aws_cloudfront_distribution" "s3_distribution":
98: resource "aws_cloudfront_distribution" "s3_distribution" {
Now it seems this is such a common error that AWS made a lengthy guide on handling it: Resolve the "CNAMEAlreadyExists" error in CloudFront
Unfortunately this doesn’t fit the bill as I have no other cloudfront-distributions, nor alternate AWS accounts.
I was able to get the stack running under a differnt sub-domain by simple removing the entire terraform stack and rebuilding it under a different sub-domain. But downing that, and then retrying the original subdomain throws the exact same error.
My suspicion is that it is to do with the aws_acm_certificate_validation.cert
-resource (specifically validation_record_fqdns
) as the _6fb8a3c2319296bbc4d3301badecb94e.expo
part of (from terraform plan):
# aws_acm_certificate_validation.cert will be destroyed
- resource "aws_acm_certificate_validation" "cert" {
- certificate_arn = "arn:aws:acm:us-east-1:775865272939:certificate/8bd66521-c0bd-4b7c-ad30-e3c50268b268" -> null
- id = "2022-09-14 08:01:11.42 +0000 UTC" -> null
- validation_record_fqdns = [
- "_6fb8a3c2319296bbc4d3301badecb94e.expo.danishgenetics.dk",
] -> null
}
…is reoccurring between the original stack and the later stack using same subdomain, but different when using a different subdomain. I can’t think of any way to actively edit/access this “resource”, neither in route53 or ACM or any other related AWS service I could think of.
Question:
Has anyone faced anything similar? Or is there a resource or flow that I am missing?
Any insight is very appreciated!
Update:
Project is being managed with terraform-0.13.4
for now, however I didn’t find any difference when running with latest version.
Full Terraform code for reference:
resource "aws_route53_record" "caa_record_expo_danishgenetics_dk" {
zone_id = aws_route53_zone.danishgenetics_domain.zone_id
name = "expo.danishgenetics.dk"
type = "CAA"
records = [
"0 issue \"amazon.com\"",
"0 issue \"digicert.com\"",
"0 iodef \"mailto:xxx@danishgenetics.dk\""
]
ttl = 60
}
provider "aws" {
region = "us-east-1"
alias = "aws-us-east-1"
}
variable "expo_site_bucket_name" {
default = "danish-genetics-expo-website"
}
variable "expo_site_domain" {
default = "expo.danishgenetics.dk"
}
resource "aws_s3_bucket" "expo_website_s3_bucket" {
bucket = var.expo_site_bucket_name
acl = "public-read"
policy = <<EOF
{
"Version":"2012-10-17",
"Statement":[{
"Sid":"PublicReadForGetBucketObjects",
"Effect":"Allow",
"Principal": "*",
"Action":["s3:GetObject"],
"Resource":["arn:aws:s3:::${var.expo_site_bucket_name}/*"]
}
]
}
EOF
force_destroy = true
website {
index_document = "index.html"
error_document = "index.html"
}
}
locals {
s3_origin_id = "myS3Origin"
}
// Certificate
resource "aws_acm_certificate" "cert" {
provider = aws.aws-us-east-1
domain_name = var.expo_site_domain
validation_method = "DNS"
tags = {
Environment = "production"
}
lifecycle {
create_before_destroy = true
}
}
// Route 53 Record
resource "aws_route53_record" "expo_danishgenetics_dk" {
for_each = {
for dvo in aws_acm_certificate.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.danishgenetics_domain.id
}
// Certificate Validation
resource "aws_acm_certificate_validation" "cert" {
provider = aws.aws-us-east-1
certificate_arn = aws_acm_certificate.cert.arn
validation_record_fqdns = [for record in aws_route53_record.expo_danishgenetics_dk : record.fqdn]
}
// Cloudfront Distribution
resource "aws_cloudfront_distribution" "s3_distribution" {
provider = aws.aws-us-east-1
origin {
domain_name = aws_s3_bucket.expo_website_s3_bucket.bucket_regional_domain_name
origin_id = local.s3_origin_id
}
enabled = true
is_ipv6_enabled = true
comment = "Some comment"
default_root_object = "index.html"
# If there is a 404, return index.html with a HTTP 200 Response
custom_error_response {
error_caching_min_ttl = 3000
error_code = 404
response_code = 200
response_page_path = "/index.html"
}
aliases = [var.expo_site_domain]
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 = 21600
}
ordered_cache_behavior {
path_pattern = "/*"
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD", "OPTIONS"]
target_origin_id = local.s3_origin_id
forwarded_values {
query_string = false
headers = ["Origin"]
cookies {
forward = "none"
}
}
min_ttl = 0
default_ttl = 21600
max_ttl = 86400
compress = true
viewer_protocol_policy = "redirect-to-https"
}
restrictions {
geo_restriction {
restriction_type = "none"
locations = []
}
}
viewer_certificate {
acm_certificate_arn = aws_acm_certificate.cert.arn
ssl_support_method = "sni-only"
}
}
resource "aws_route53_record" "record_a" {
zone_id = aws_route53_zone.danishgenetics_domain.id
name = var.expo_site_domain
type = "A"
alias {
name = replace(aws_cloudfront_distribution.s3_distribution.domain_name, "/[.]$/", "")
zone_id = aws_cloudfront_distribution.s3_distribution.hosted_zone_id
evaluate_target_health = true
}
}