hashicorp / terraform-provider-aws

The AWS Provider enables Terraform to manage AWS resources.
https://registry.terraform.io/providers/hashicorp/aws
Mozilla Public License 2.0
9.74k stars 9.09k forks source link

aws_acm_certificate/aws_acm_certificate_validation deleted and recreated every terraform plan/apply #21770

Open jordanbcooper opened 2 years ago

jordanbcooper commented 2 years ago

Community Note

Terraform CLI and Terraform AWS Provider Version

Affected Resource(s)

Terraform Configuration Files

Please include all Terraform configurations required to reproduce the bug. Bug reports without a functional reproduction may be closed without investigation.

main.tf where apply is made

module "frontend-users" {
  source      = "../frontend-public"
  domain_name = "site-assets.domain.com"
  region      = "us-west-2"
  endpoint = "site-assets.domain.com"
  bucket_name =  "site-assets.domain.com"
  origin_path = "/"
  root_object = "index.html"
  zoneid     = "xxxxxxxxxxx"
}

module "assets" {
  source      = "../frontend-public"
  domain_name = "assets.domain.com"
  region      = "us-west-2"
  endpoint = "assets.domain.com"
  bucket_name =  "assets.domain.com"
  origin_path = "/"
  root_object = ""
  zoneid     = "xxxxxxxxxx"
}

../frontend-public/main.tf

resource "aws_cloudfront_distribution" "cf" {
  enabled             = true
  aliases             = [var.endpoint]
  default_root_object = var.root_object
  provider                = aws.us-east-1
  origin {
    domain_name = data.aws_s3_bucket.selected.bucket_regional_domain_name
    origin_id   = data.aws_s3_bucket.selected.bucket_regional_domain_name

    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.oai.cloudfront_access_identity_path
    }
  }

  default_cache_behavior {
    allowed_methods        = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"]
    cached_methods         = ["GET", "HEAD", "OPTIONS"]
    compress               =  true
    target_origin_id       = data.aws_s3_bucket.selected.bucket_regional_domain_name
    viewer_protocol_policy = "redirect-to-https"

    forwarded_values {
      headers = [
        "Origin",
        "Access-Control-Request-Headers",
        "Access-Control-Request-Method",
        "Access-Control-Allow-Origin"
      ]
      query_string = false

      cookies {
        forward = "all"
      }

    }

  }
  price_class = "PriceClass_200"

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    acm_certificate_arn      = aws_acm_certificate.cert.arn
    ssl_support_method       = "sni-only"
    minimum_protocol_version = "TLSv1.2_2018"
  }
}

resource "aws_cloudfront_origin_access_identity" "oai" {
  comment = "OAI for ${var.endpoint}"
}

resource "aws_s3_bucket_policy" "s3policy" {
  bucket = data.aws_s3_bucket.selected.id
  policy = data.aws_iam_policy_document.s3policy.json
}

resource "aws_acm_certificate" "cert" {
  provider                  = aws.us-east-1
  domain_name               = var.domain_name
  subject_alternative_names = ["${var.domain_name}"]
  validation_method         = "DNS"
  lifecycle {
    create_before_destroy = true
  }
}

terraform {
  required_providers {
    cloudflare = {
      source = "cloudflare/cloudflare"
      version = "~> 3.0"
    }
  }
}

provider "cloudflare" {

}

resource "cloudflare_record" "certvalidation" {
  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
  value           = each.value.record
  ttl             = 60
  type            = each.value.type
  zone_id         = var.zoneid

}

resource "aws_acm_certificate_validation" "certvalidation" {
  provider                = aws.us-east-1
  certificate_arn         = aws_acm_certificate.cert.arn
  validation_record_fqdns = [for record in cloudflare_record.certvalidation: record.hostname ]
}

resource "cloudflare_record" "websiteurl" {
  name    = var.endpoint
  zone_id = var.zoneid
  type    = "CNAME"
  value   =  aws_cloudfront_distribution.cf.domain_name
  proxied = var.proxied
}

../frontend-public/data.tf

data "aws_iam_policy_document" "s3policy" {
  statement {
    actions = ["s3:GetObject"]

    resources = [
      data.aws_s3_bucket.selected.arn,
      "${data.aws_s3_bucket.selected.arn}/*"
    ]

    principals {
      type        = "AWS"
      identifiers = [aws_cloudfront_origin_access_identity.oai.iam_arn]
    }
  }
}

data "aws_s3_bucket" "selected" {
  bucket = var.bucket_name
}

data "cloudflare_zones" "domain" {
  filter {
    name = var.domain_name
  }
}

../frontend-public/variables.tf

variable "bucket_name" {
  description = "S3 bucket name"
  type        = string
}

variable "region" {
  description = "AWS region"
  type        = string
}

variable "domain_name" {
  description = "Domain name"
  type        = string
}

variable "origin_path" {
  description = "Origin path"
  type        = string
}

variable "endpoint" {
  description = "Endpoint url"
  type        = string
}

variable "zoneid" {
  description = "Zone id"
  type        = string
}

variable "root_object" {
  description = "Default root object"
  type        = string

}

variable "proxied" {
  description = "cloudflare proxied"
  default = false

}

Debug Output

https://gist.github.com/jordanbcooper/1c7fbee057d50d49086e10eaf16e1d4d

Panic Output

Expected Behavior

I use this as a module (I believe I have provided relevant tf files), and these certificates should only be created once.

Actual Behavior

Subsequent terraform plan/apply will delete and recreate the certs and cert validations. Can provide additional TF files if needed to reproduce.

Steps to Reproduce

Unsure how to describe reproduction, it just happens every time I run terraform. These are not imported resources.

  1. terraform apply

Important Factoids

References

justinretzolk commented 2 years ago

Hey @jordanbcooper šŸ‘‹ Thanks for taking the time to open up this fresh issue so we can take a look at this. So that we have all of the necessary information in order to look into this, can you update the issue description to include the (redacted as necessary) debug log as well?

jordanbcooper commented 2 years ago

Sorry about that @justinretzolk , debug added.

jordanbcooper commented 2 years ago

Was digging around a bit, is this why a new cert is created every time?

https://github.com/hashicorp/terraform-provider-aws/blob/a15140e1184d201c9cf4cfe46f154a48c4a08958/aws/resource_aws_acm_certificate_validation.go#L16-L40

jordanbcooper commented 2 years ago

Hey folks! Any chance I can get this looked at? Happy to provide more information as needed.

justinretzolk commented 2 years ago

Hey @jordanbcooper šŸ‘‹ I didn't want to leave you hanging, especially since I'd replied to you while triaging. We use šŸ‘ reactions to help with prioritization, so I can't promise a date, but we'll definitely be looking into this as soon as time allows.

bashoKa commented 2 years ago

Seeing the same behaviour and looking at https://github.com/terraform-aws-modules/terraform-aws-acm/issues/90 I guess there are more being affected. Looking forward for a fix. Will try to build a workaround.

github-actions[bot] commented 5 months ago

Marking this issue as stale due to inactivity. This helps our maintainers find and focus on the active issues. If this issue receives no comments in the next 30 days it will automatically be closed. Maintainers can also remove the stale label.

If this issue was automatically closed and you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thank you!

tculp commented 5 months ago

Unstale