Unnecessary destruction when attributes depend on another resource that is destroyed

It seems that if a resource would be created if an attribute changes, and that attribute is unknown during the plan phase, because an upstream dependency is recreated, then the resource is destroyed first, then recreated, even if the actual value of the attribute is unchanged.

For example, if I have an aws_acm_certificate, and aws_route53_records, that depend on that. Then if I recreate the certificate, the records are destroyed and recreated, even though the validation records for dns valication didn’t actually change at.

Am I doing something wrong? Is there some way to get around this behaviour?

Hi @tmccombs!

Terraform depends on the providers to indicate in their plan results what attribute values they are expecting as the result of an action. It sounds like in the situation you’re describing, the provider is indicating that it can’t predict the value until the apply step.

Looking at the ACM API, it seems that indeed those validation values are decided by the remote server as part of RequestCertificate (which is what the provider calls to “create” an aws_acm_certificate) and so unless the provider were to try to replicate the same logic that ACM runs server-side during RequestCertificate it would not be possible for the AWS provider to reliably predict the values in domain_validation_options at plan time, and so Terraform must conservatively assume that the new value will be different in order to produce a thorough plan.

It sounds like in practice the validation options are somehow deterministic from just the certificate inputs and so recreating a certificate with the same settings produces the same values for domain_validation_options. Since that doesn’t seem to be contractual in the AWS API it’s not safe for the AWS provider itself to assume that, but if you know it to be true then this is one of the exceptional situations where it can be reasonable to use the -target option when creating your plan:

terraform plan -target=aws_acm_certificate.example

By excluding the other objects from the plan you avoid Terraform having to make a plan for aws_route53_records based on incomplete information. Once that targeted plan is applied, you can then make a normal plan (with no targeting constraints) to complete the operation, and Terraform will be able to see that the domain_validation_options values are known from the previous operation and thus avoid changing your downstream aws_route53_record.

Alternatively, if you don’t intend to make changes to the aws_acm_certificate resource that would affect the validation records, you could ask Terraform to ignore changes to the records argument on that resource:

resource "aws_route53_record" "example" {
  # (the settings to create the validation record)

  lifecycle {
    # Don't recreate validation record when the
    # ACM certificate is recreated.
    ignore_changes = records
  }
}

That would avoid the need to use -target, at the expense of preventing the validation record from updating even if it should be changed by a certificate replacement.

By excluding the other objects from the plan you avoid Terraform having to make a plan for aws_route53_records based on incomplete information.

Unfortunately this doesn’t work for me. The problem is that in order to maintain continuity, if the certificate changes, I want to create the new one before deleting the old one. Currently, this means terraform will try to create the new validation records before the old ones are deleted, which fails since they already exist. The processing order I would like is:

  1. Create new certificate
  2. Add/remove dns records as needed (remove and recreate isn’t the end of the world, but I’d like to avoid if possible… but the delete does need to come before the create)
  3. Update load balancers that use the certificate
  4. remove old certificate

I haven’t found a good workflow to accomplisth this workflow without either interrupting the service or requiring many manual steps.