Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Re-importing certificate to ACM causes replace not update. #29634

Closed
NoahCallaway opened this issue Feb 24, 2023 · 6 comments · Fixed by #29763
Closed

[Bug]: Re-importing certificate to ACM causes replace not update. #29634

NoahCallaway opened this issue Feb 24, 2023 · 6 comments · Fixed by #29763
Labels
bug Addresses a defect in current functionality. service/acm Issues and PRs that pertain to the acm service.
Milestone

Comments

@NoahCallaway
Copy link

NoahCallaway commented Feb 24, 2023

Terraform Core Version

1.3.7

AWS Provider Version

4.55.0

Affected Resource(s)

aws_acm_certificate

Expected Behavior

Terraform should update the certificate in place with a new private key and certificate body, maintaining the existing ARN.

Much like this CLI command

aws acm import-certificate --certificate fileb://cert.pem --certificate-chain fileb://cert-chain.pem --private-key fileb://private-key.pem --certificate-arn <Existing-ARN>

Actual Behavior

Terraform deletes the old certificate and creates a new one with the new private key and certificate body.

Relevant Error/Panic Output Snippet

No response

Terraform Configuration Files

The private key and certificate in the example below change when the certificate nears expiry.

resource "aws_acm_certificate" "cert" {
  private_key       = vault_pki_secret_backend_cert.cert.private_key
  certificate_body  = vault_pki_secret_backend_cert.cert.certificate
  certificate_chain = vault_pki_secret_backend_cert.cert.ca_chain

  tags = var.tags
}

Steps to Reproduce

  • Create a certificate with the above configuration
  • With a new certificate body (either from vault or from file) run terraform apply

Debug Output

-/+ destroy and then create replacement
+/- create replacement and then destroy

Terraform will perform the following actions:

  # module.vault_cert.aws_acm_certificate.cert must be replaced
-/+ resource "aws_acm_certificate" "cert" {
      ~ arn                       = "arn:aws:acm:<region>:<account-number>:certificate/<guid>" -> (known after apply)

Panic Output

No response

Important Factoids

No.

References

The providers update function looks to be here:

func resourceCertificateUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {

Terraform seems to be forcing recreate rather than the update in this function?

Would you like to implement a fix?

None

@NoahCallaway NoahCallaway added bug Addresses a defect in current functionality. needs-triage Waiting for first response or review from a maintainer. labels Feb 24, 2023
@github-actions
Copy link

Community Note

Voting for Prioritization

  • Please vote on this issue by adding a 👍 reaction to the original post to help the community and maintainers prioritize this request.
  • Please see our prioritization guide for information on how we prioritize.
  • Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request.

Volunteering to Work on This Issue

  • If you are interested in working on this issue, please leave a comment.
  • If this would be your first contribution, please review the contribution guide.

@github-actions github-actions bot added the service/acm Issues and PRs that pertain to the acm service. label Feb 24, 2023
@mattburgess
Copy link
Collaborator

Hi @NoahCallaway! Are you able to post a bit more output from Terraform please? As you're on very recent versions of both Terraform and the provider, Terraform should tell you which of the attributes caused it to think that the resource needed replacing.

From a quick test here, using hashicorp/tls to provide the relevant key material, I think it might be the transparency logging option that's causing the problem:

ca.tf:

resource "tls_private_key" "cert" {
  algorithm = "RSA"
}

resource "tls_cert_request" "cert" {
  private_key_pem = tls_private_key.cert.private_key_pem

  subject {
    common_name  = "cert.example.com"
    organization = "ACME Examples, Inc"
  }
}

resource "tls_locally_signed_cert" "cert" {
  cert_request_pem   = tls_cert_request.cert.cert_request_pem
  ca_private_key_pem = tls_private_key.ca.private_key_pem
  ca_cert_pem        = tls_self_signed_cert.ca.cert_pem

  validity_period_hours = 12

  allowed_uses = [
    "key_encipherment",
    "digital_signature",
    "server_auth",
  ]
}

resource "aws_acm_certificate" "cert" {
  private_key      = tls_private_key.cert.private_key_pem
  certificate_body = tls_locally_signed_cert.cert.cert_pem

  options {
    certificate_transparency_logging_preference = "DISABLED"
  }
}

cert.tf:

resource "tls_private_key" "cert" {
  algorithm = "RSA"
}

resource "tls_cert_request" "cert" {
  private_key_pem = tls_private_key.cert.private_key_pem

  subject {
    common_name  = "cert.example.com"
    organization = "ACME Examples, Inc"
  }
}

resource "tls_locally_signed_cert" "cert" {
  cert_request_pem   = tls_cert_request.cert.cert_request_pem
  ca_private_key_pem = tls_private_key.ca.private_key_pem
  ca_cert_pem        = tls_self_signed_cert.ca.cert_pem

  validity_period_hours = 12

  allowed_uses = [
    "key_encipherment",
    "digital_signature",
    "server_auth",
  ]
}

resource "aws_acm_certificate" "cert" {
  private_key      = tls_private_key.cert.private_key_pem
  certificate_body = tls_locally_signed_cert.cert.cert_pem
}
  1. Create all resources:
$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  + create

Terraform will perform the following actions:

  # aws_acm_certificate.cert will be created
  + resource "aws_acm_certificate" "cert" {
      + arn                       = (known after apply)
      + certificate_body          = (known after apply)
      + domain_name               = (known after apply)
      + domain_validation_options = (known after apply)
      + id                        = (known after apply)
      + key_algorithm             = (known after apply)
      + not_after                 = (known after apply)
      + not_before                = (known after apply)
      + pending_renewal           = (known after apply)
      + private_key               = (sensitive value)
      + renewal_eligibility       = (known after apply)
      + renewal_summary           = (known after apply)
      + status                    = (known after apply)
      + subject_alternative_names = (known after apply)
      + tags_all                  = (known after apply)
      + type                      = (known after apply)
      + validation_emails         = (known after apply)
      + validation_method         = (known after apply)
    }

  # tls_cert_request.cert will be created
  + resource "tls_cert_request" "cert" {
      + cert_request_pem = (known after apply)
      + id               = (known after apply)
      + key_algorithm    = (known after apply)
      + private_key_pem  = (sensitive value)

      + subject {
          + common_name  = "cert.example.com"
          + organization = "ACME Examples, Inc"
        }
    }

  # tls_locally_signed_cert.cert will be created
  + resource "tls_locally_signed_cert" "cert" {
      + allowed_uses          = [
          + "key_encipherment",
          + "digital_signature",
          + "server_auth",
        ]
      + ca_cert_pem           = (known after apply)
      + ca_key_algorithm      = (known after apply)
      + ca_private_key_pem    = (sensitive value)
      + cert_pem              = (known after apply)
      + cert_request_pem      = (known after apply)
      + early_renewal_hours   = 0
      + id                    = (known after apply)
      + is_ca_certificate     = false
      + ready_for_renewal     = false
      + set_subject_key_id    = false
      + validity_end_time     = (known after apply)
      + validity_period_hours = 12
      + validity_start_time   = (known after apply)
    }

  # tls_private_key.ca will be created
  + resource "tls_private_key" "ca" {
      + algorithm                     = "RSA"
      + ecdsa_curve                   = "P224"
      + id                            = (known after apply)
      + private_key_openssh           = (sensitive value)
      + private_key_pem               = (sensitive value)
      + private_key_pem_pkcs8         = (sensitive value)
      + public_key_fingerprint_md5    = (known after apply)
      + public_key_fingerprint_sha256 = (known after apply)
      + public_key_openssh            = (known after apply)
      + public_key_pem                = (known after apply)
      + rsa_bits                      = 2048
    }

  # tls_private_key.cert will be created
  + resource "tls_private_key" "cert" {
      + algorithm                     = "RSA"
      + ecdsa_curve                   = "P224"
      + id                            = (known after apply)
      + private_key_openssh           = (sensitive value)
      + private_key_pem               = (sensitive value)
      + private_key_pem_pkcs8         = (sensitive value)
      + public_key_fingerprint_md5    = (known after apply)
      + public_key_fingerprint_sha256 = (known after apply)
      + public_key_openssh            = (known after apply)
      + public_key_pem                = (known after apply)
      + rsa_bits                      = 2048
    }

  # tls_self_signed_cert.ca will be created
  + resource "tls_self_signed_cert" "ca" {
      + allowed_uses          = [
          + "key_encipherment",
          + "digital_signature",
          + "server_auth",
          + "cert_signing",
        ]
      + cert_pem              = (known after apply)
      + early_renewal_hours   = 0
      + id                    = (known after apply)
      + is_ca_certificate     = true
      + key_algorithm         = (known after apply)
      + private_key_pem       = (sensitive value)
      + ready_for_renewal     = false
      + set_authority_key_id  = false
      + set_subject_key_id    = false
      + validity_end_time     = (known after apply)
      + validity_period_hours = 12
      + validity_start_time   = (known after apply)

      + subject {
          + common_name  = "example.com"
          + organization = "ACME Examples, Inc"
        }
    }

Plan: 6 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

tls_private_key.cert: Creating...
tls_private_key.ca: Creating...
tls_private_key.ca: Creation complete after 0s [id=80a77f9ccc78431954a0821224d60acc8504fcd8]
tls_self_signed_cert.ca: Creating...
tls_self_signed_cert.ca: Creation complete after 0s [id=55727894767933383695186811739252795667]
tls_private_key.cert: Creation complete after 0s [id=ecbac0d9f5b3c9ef697892b5a4476dd469843d7a]
tls_cert_request.cert: Creating...
tls_cert_request.cert: Creation complete after 0s [id=0264fc230ccc350f80723a1fa1dd5d53b3a7fffe]
tls_locally_signed_cert.cert: Creating...
tls_locally_signed_cert.cert: Creation complete after 0s [id=242375531891319981900019092251257633177]
aws_acm_certificate.cert: Creating...
aws_acm_certificate.cert: Creation complete after 0s [id=arn:aws:acm:eu-west-2:320797911953:certificate/b385c2fd-a847-4780-87e7-9347b17ee52d]

Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
  1. Simulate a cert renewal:
$ terraform taint tls_private_key.cert
Resource instance tls_private_key.cert has been marked as tainted.
  1. Reproduce the issue; note what's logging the # forces replacement on aws_acm_certificate.cert:
$ terraform plan
tls_private_key.cert: Refreshing state... [id=ecbac0d9f5b3c9ef697892b5a4476dd469843d7a]
tls_private_key.ca: Refreshing state... [id=80a77f9ccc78431954a0821224d60acc8504fcd8]
tls_cert_request.cert: Refreshing state... [id=0264fc230ccc350f80723a1fa1dd5d53b3a7fffe]
tls_self_signed_cert.ca: Refreshing state... [id=55727894767933383695186811739252795667]
tls_locally_signed_cert.cert: Refreshing state... [id=242375531891319981900019092251257633177]
aws_acm_certificate.cert: Refreshing state... [id=arn:aws:acm:eu-west-2:320797911953:certificate/b385c2fd-a847-4780-87e7-9347b17ee52d]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # aws_acm_certificate.cert must be replaced
-/+ resource "aws_acm_certificate" "cert" {
      ~ arn                       = "arn:aws:acm:eu-west-2:320797911953:certificate/b385c2fd-a847-4780-87e7-9347b17ee52d" -> (known after apply)
      - certificate_authority_arn = "" -> null
      ~ certificate_body          = <<-EOT
            -----BEGIN CERTIFICATE-----
            MIIDTDCCAjSgAwIBAgIRALZX1Ffb//T7jr7w45PceZkwDQYJKoZIhvcNAQELBQAw
            MzEbMBkGA1UEChMSQUNNRSBFeGFtcGxlcywgSW5jMRQwEgYDVQQDEwtleGFtcGxl
            LmNvbTAeFw0yMzAyMjgyMDE3MzlaFw0yMzAzMDEwODE3MzlaMDgxGzAZBgNVBAoT
            EkFDTUUgRXhhbXBsZXMsIEluYzEZMBcGA1UEAxMQY2VydC5leGFtcGxlLmNvbTCC
            ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRdV2iW2Sj0pMtUqbWObWOC
            /pzogRcWdcBE9L9qwjHqSeK7QeqzAx5WOgIVVHcAVTil78rgUDgLPrK7Xx2nrKEB
            iqJr+gf1NZoHTupUJNLVmGm6Od+u7o0li85GgswCCussh3hVOQ6XyoVPxHmMsOa0
            vp9q9KsTy19erHSveQD+/xNkJ0QVaKRU0JcKuKOE2NnxLW6xW5zF62XUjLvpfRLQ
            CNVR6dDNOBXyyZ7sUJlRRNvROulhHVbijoALLJFWEexiLY2Eyxrnx4eOR2DgNU2x
            SN0maoCbkDTbm6SZDPteX0YJV7fDefjtI+nqSRdWFCdCx1HNaMOr9c5hQLTaNlsC
            AwEAAaNWMFQwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwG
            A1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUKM7BnjfT2fvKfKc8qfJ/YJZMW3cwDQYJ
            KoZIhvcNAQELBQADggEBALJ0z2SGnDJMsFdOWgUcVHaBUz+jS37uHJCrWB1hCDTl
            zqHf0OU4nz09xizohSic2KrcaIyLR6NCb8IuUeuRgBfb7tNXtBuRK6Gu5gL+hWzz
            zBSOrlQC45OHDkLa7W5zDIpuX7qJa57ob2e98H9uuPsA3RbCQeSic36WmBlDCSNo
            ycSMP5tcYVWhzMFMTFVVAxGrjBCg0XOm0nnP0iiNT7MZgqS9aTqt9CHtBDfoADRD
            WmyJnRUuk1W8+26VyTDMkKOiWdtPKKR3QgXa7MICoJB7j+elMR+QeRinJd+DIOer
            6cHZjFe33kKa7MALqUThzeUn/Tn3MkzF0/QXe4yl56g=
            -----END CERTIFICATE-----
        EOT -> (known after apply)
      ~ domain_name               = "cert.example.com" -> (known after apply)
      ~ domain_validation_options = [] -> (known after apply)
      - early_renewal_duration    = "" -> null
      ~ id                        = "arn:aws:acm:eu-west-2:320797911953:certificate/b385c2fd-a847-4780-87e7-9347b17ee52d" -> (known after apply)
      ~ key_algorithm             = "RSA_2048" -> (known after apply)
      ~ not_after                 = "2023-03-01T08:17:39Z" -> (known after apply)
      ~ not_before                = "2023-02-28T20:17:39Z" -> (known after apply)
      ~ pending_renewal           = false -> (known after apply)
      ~ private_key               = (sensitive value)
      ~ renewal_eligibility       = "INELIGIBLE" -> (known after apply)
      ~ renewal_summary           = [] -> (known after apply)
      ~ status                    = "ISSUED" -> (known after apply)
      ~ subject_alternative_names = [
          - "cert.example.com",
        ] -> (known after apply)
      - tags                      = {} -> null
      ~ tags_all                  = {} -> (known after apply)
      ~ type                      = "IMPORTED" -> (known after apply)
      ~ validation_emails         = [] -> (known after apply)
      ~ validation_method         = "NONE" -> (known after apply)

      - options {
          - certificate_transparency_logging_preference = "DISABLED" -> null # forces replacement
        }
    }

  # tls_cert_request.cert must be replaced
-/+ resource "tls_cert_request" "cert" {
      ~ cert_request_pem = <<-EOT
            -----BEGIN CERTIFICATE REQUEST-----
            MIICfTCCAWUCAQAwODEbMBkGA1UEChMSQUNNRSBFeGFtcGxlcywgSW5jMRkwFwYD
            VQQDExBjZXJ0LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
            CgKCAQEAxF1XaJbZKPSky1SptY5tY4L+nOiBFxZ1wET0v2rCMepJ4rtB6rMDHlY6
            AhVUdwBVOKXvyuBQOAs+srtfHaesoQGKomv6B/U1mgdO6lQk0tWYabo5367ujSWL
            zkaCzAIK6yyHeFU5DpfKhU/EeYyw5rS+n2r0qxPLX16sdK95AP7/E2QnRBVopFTQ
            lwq4o4TY2fEtbrFbnMXrZdSMu+l9EtAI1VHp0M04FfLJnuxQmVFE29E66WEdVuKO
            gAsskVYR7GItjYTLGufHh45HYOA1TbFI3SZqgJuQNNubpJkM+15fRglXt8N5+O0j
            6epJF1YUJ0LHUc1ow6v1zmFAtNo2WwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEB
            ALEoMx8BSizfmIWK+XZJflFs2OiVVl47xAfqnvLmrrjhdNmbaOzRPNnK/GY/How2
            uGr9vI7nK23xTd4zO1JAui7fQIaEcMZpkGwzCWLYtoiAGFrycgEeUqVtlArSOfk5
            dtoSvkWbQ95Yf7so/vNLZbtCnIiKjCbDuQYJIrT8UgXJtr1Lv8pp/PFifmjXBrNL
            igikzDNYh+z34IvcR4D1l9S/cuw8ZOX24EudgMzmZm5lHfozGQCSm8IHPlBtzjHm
            V+lNaxGcs8MCi7UuMUM8OBY6YTWRnZOGLRUBcflcR10V5AcMQ1FJc8I8UGOQt6ES
            4Qtcm4jGpXoTwhb5RA10XT4=
            -----END CERTIFICATE REQUEST-----
        EOT -> (known after apply)
      ~ id               = "0264fc230ccc350f80723a1fa1dd5d53b3a7fffe" -> (known after apply)
      ~ key_algorithm    = "RSA" -> (known after apply)
      ~ private_key_pem  = (sensitive value) # forces replacement

        # (1 unchanged block hidden)
    }

  # tls_locally_signed_cert.cert must be replaced
-/+ resource "tls_locally_signed_cert" "cert" {
      ~ ca_key_algorithm      = "RSA" -> (known after apply)
      ~ cert_pem              = <<-EOT
            -----BEGIN CERTIFICATE-----
            MIIDTDCCAjSgAwIBAgIRALZX1Ffb//T7jr7w45PceZkwDQYJKoZIhvcNAQELBQAw
            MzEbMBkGA1UEChMSQUNNRSBFeGFtcGxlcywgSW5jMRQwEgYDVQQDEwtleGFtcGxl
            LmNvbTAeFw0yMzAyMjgyMDE3MzlaFw0yMzAzMDEwODE3MzlaMDgxGzAZBgNVBAoT
            EkFDTUUgRXhhbXBsZXMsIEluYzEZMBcGA1UEAxMQY2VydC5leGFtcGxlLmNvbTCC
            ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRdV2iW2Sj0pMtUqbWObWOC
            /pzogRcWdcBE9L9qwjHqSeK7QeqzAx5WOgIVVHcAVTil78rgUDgLPrK7Xx2nrKEB
            iqJr+gf1NZoHTupUJNLVmGm6Od+u7o0li85GgswCCussh3hVOQ6XyoVPxHmMsOa0
            vp9q9KsTy19erHSveQD+/xNkJ0QVaKRU0JcKuKOE2NnxLW6xW5zF62XUjLvpfRLQ
            CNVR6dDNOBXyyZ7sUJlRRNvROulhHVbijoALLJFWEexiLY2Eyxrnx4eOR2DgNU2x
            SN0maoCbkDTbm6SZDPteX0YJV7fDefjtI+nqSRdWFCdCx1HNaMOr9c5hQLTaNlsC
            AwEAAaNWMFQwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwG
            A1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUKM7BnjfT2fvKfKc8qfJ/YJZMW3cwDQYJ
            KoZIhvcNAQELBQADggEBALJ0z2SGnDJMsFdOWgUcVHaBUz+jS37uHJCrWB1hCDTl
            zqHf0OU4nz09xizohSic2KrcaIyLR6NCb8IuUeuRgBfb7tNXtBuRK6Gu5gL+hWzz
            zBSOrlQC45OHDkLa7W5zDIpuX7qJa57ob2e98H9uuPsA3RbCQeSic36WmBlDCSNo
            ycSMP5tcYVWhzMFMTFVVAxGrjBCg0XOm0nnP0iiNT7MZgqS9aTqt9CHtBDfoADRD
            WmyJnRUuk1W8+26VyTDMkKOiWdtPKKR3QgXa7MICoJB7j+elMR+QeRinJd+DIOer
            6cHZjFe33kKa7MALqUThzeUn/Tn3MkzF0/QXe4yl56g=
            -----END CERTIFICATE-----
        EOT -> (known after apply)
      ~ cert_request_pem      = <<-EOT
            -----BEGIN CERTIFICATE REQUEST-----
            MIICfTCCAWUCAQAwODEbMBkGA1UEChMSQUNNRSBFeGFtcGxlcywgSW5jMRkwFwYD
            VQQDExBjZXJ0LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
            CgKCAQEAxF1XaJbZKPSky1SptY5tY4L+nOiBFxZ1wET0v2rCMepJ4rtB6rMDHlY6
            AhVUdwBVOKXvyuBQOAs+srtfHaesoQGKomv6B/U1mgdO6lQk0tWYabo5367ujSWL
            zkaCzAIK6yyHeFU5DpfKhU/EeYyw5rS+n2r0qxPLX16sdK95AP7/E2QnRBVopFTQ
            lwq4o4TY2fEtbrFbnMXrZdSMu+l9EtAI1VHp0M04FfLJnuxQmVFE29E66WEdVuKO
            gAsskVYR7GItjYTLGufHh45HYOA1TbFI3SZqgJuQNNubpJkM+15fRglXt8N5+O0j
            6epJF1YUJ0LHUc1ow6v1zmFAtNo2WwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEB
            ALEoMx8BSizfmIWK+XZJflFs2OiVVl47xAfqnvLmrrjhdNmbaOzRPNnK/GY/How2
            uGr9vI7nK23xTd4zO1JAui7fQIaEcMZpkGwzCWLYtoiAGFrycgEeUqVtlArSOfk5
            dtoSvkWbQ95Yf7so/vNLZbtCnIiKjCbDuQYJIrT8UgXJtr1Lv8pp/PFifmjXBrNL
            igikzDNYh+z34IvcR4D1l9S/cuw8ZOX24EudgMzmZm5lHfozGQCSm8IHPlBtzjHm
            V+lNaxGcs8MCi7UuMUM8OBY6YTWRnZOGLRUBcflcR10V5AcMQ1FJc8I8UGOQt6ES
            4Qtcm4jGpXoTwhb5RA10XT4=
            -----END CERTIFICATE REQUEST-----
        EOT -> (known after apply) # forces replacement
      ~ id                    = "242375531891319981900019092251257633177" -> (known after apply)
      ~ validity_end_time     = "2023-03-01T08:17:39.462762461Z" -> (known after apply)
      ~ validity_start_time   = "2023-02-28T20:17:39.462762461Z" -> (known after apply)
        # (8 unchanged attributes hidden)
    }

  # tls_private_key.cert is tainted, so must be replaced
-/+ resource "tls_private_key" "cert" {
      ~ id                            = "ecbac0d9f5b3c9ef697892b5a4476dd469843d7a" -> (known after apply)
      ~ private_key_openssh           = (sensitive value)
      ~ private_key_pem               = (sensitive value)
      ~ private_key_pem_pkcs8         = (sensitive value)
      ~ public_key_fingerprint_md5    = "86:c5:ff:28:2e:ec:df:cf:91:6d:4f:a5:74:48:61:1e" -> (known after apply)
      ~ public_key_fingerprint_sha256 = "SHA256:ySMUc6mRrB5MWZ4Mf2FYQLQ41MmjDiuGu1mTQkQmZVg" -> (known after apply)
      ~ public_key_openssh            = <<-EOT
            ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEXVdoltko9KTLVKm1jm1jgv6c6IEXFnXARPS/asIx6kniu0HqswMeVjoCFVR3AFU4pe/K4FA4Cz6yu18dp6yhAYqia/oH9TWaB07qVCTS1Zhpujnfru6NJYvORoLMAgrrLId4VTkOl8qFT8R5jLDmtL6favSrE8tfXqx0r3kA/v8TZCdEFWikVNCXCrijhNjZ8S1usVucxetl1Iy76X0S0AjVUenQzTgV8sme7FCZUUTb0TrpYR1W4o6ACyyRVhHsYi2NhMsa58eHjkdg4DVNsUjdJmqAm5A025ukmQz7Xl9GCVe3w3n47SPp6kkXVhQnQsdRzWjDq/XOYUC02jZb
        EOT -> (known after apply)
      ~ public_key_pem                = <<-EOT
            -----BEGIN PUBLIC KEY-----
            MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxF1XaJbZKPSky1SptY5t
            Y4L+nOiBFxZ1wET0v2rCMepJ4rtB6rMDHlY6AhVUdwBVOKXvyuBQOAs+srtfHaes
            oQGKomv6B/U1mgdO6lQk0tWYabo5367ujSWLzkaCzAIK6yyHeFU5DpfKhU/EeYyw
            5rS+n2r0qxPLX16sdK95AP7/E2QnRBVopFTQlwq4o4TY2fEtbrFbnMXrZdSMu+l9
            EtAI1VHp0M04FfLJnuxQmVFE29E66WEdVuKOgAsskVYR7GItjYTLGufHh45HYOA1
            TbFI3SZqgJuQNNubpJkM+15fRglXt8N5+O0j6epJF1YUJ0LHUc1ow6v1zmFAtNo2
            WwIDAQAB
            -----END PUBLIC KEY-----
        EOT -> (known after apply)
        # (3 unchanged attributes hidden)
    }

Plan: 4 to add, 0 to change, 4 to destroy.
  1. If I now update my reproducer to have the relevant options block, i.e.:

cert.tf:

resource "aws_acm_certificate" "cert" {
  private_key      = tls_private_key.cert.private_key_pem
  certificate_body = tls_locally_signed_cert.cert.cert_pem

  options {
    certificate_transparency_logging_preference = "DISABLED"
  }
}

The plan now shows the certificate ACM cert will be re-imported under the existing ARN:

$ terraform plan
tls_private_key.ca: Refreshing state... [id=80a77f9ccc78431954a0821224d60acc8504fcd8]
tls_private_key.cert: Refreshing state... [id=ecbac0d9f5b3c9ef697892b5a4476dd469843d7a]
tls_cert_request.cert: Refreshing state... [id=0264fc230ccc350f80723a1fa1dd5d53b3a7fffe]
tls_self_signed_cert.ca: Refreshing state... [id=55727894767933383695186811739252795667]
tls_locally_signed_cert.cert: Refreshing state... [id=242375531891319981900019092251257633177]
aws_acm_certificate.cert: Refreshing state... [id=arn:aws:acm:eu-west-2:320797911953:certificate/b385c2fd-a847-4780-87e7-9347b17ee52d]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  ~ update in-place
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # aws_acm_certificate.cert will be updated in-place
  ~ resource "aws_acm_certificate" "cert" {
      ~ certificate_body          = <<-EOT
            -----BEGIN CERTIFICATE-----
            MIIDTDCCAjSgAwIBAgIRALZX1Ffb//T7jr7w45PceZkwDQYJKoZIhvcNAQELBQAw
            MzEbMBkGA1UEChMSQUNNRSBFeGFtcGxlcywgSW5jMRQwEgYDVQQDEwtleGFtcGxl
            LmNvbTAeFw0yMzAyMjgyMDE3MzlaFw0yMzAzMDEwODE3MzlaMDgxGzAZBgNVBAoT
            EkFDTUUgRXhhbXBsZXMsIEluYzEZMBcGA1UEAxMQY2VydC5leGFtcGxlLmNvbTCC
            ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRdV2iW2Sj0pMtUqbWObWOC
            /pzogRcWdcBE9L9qwjHqSeK7QeqzAx5WOgIVVHcAVTil78rgUDgLPrK7Xx2nrKEB
            iqJr+gf1NZoHTupUJNLVmGm6Od+u7o0li85GgswCCussh3hVOQ6XyoVPxHmMsOa0
            vp9q9KsTy19erHSveQD+/xNkJ0QVaKRU0JcKuKOE2NnxLW6xW5zF62XUjLvpfRLQ
            CNVR6dDNOBXyyZ7sUJlRRNvROulhHVbijoALLJFWEexiLY2Eyxrnx4eOR2DgNU2x
            SN0maoCbkDTbm6SZDPteX0YJV7fDefjtI+nqSRdWFCdCx1HNaMOr9c5hQLTaNlsC
            AwEAAaNWMFQwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwG
            A1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUKM7BnjfT2fvKfKc8qfJ/YJZMW3cwDQYJ
            KoZIhvcNAQELBQADggEBALJ0z2SGnDJMsFdOWgUcVHaBUz+jS37uHJCrWB1hCDTl
            zqHf0OU4nz09xizohSic2KrcaIyLR6NCb8IuUeuRgBfb7tNXtBuRK6Gu5gL+hWzz
            zBSOrlQC45OHDkLa7W5zDIpuX7qJa57ob2e98H9uuPsA3RbCQeSic36WmBlDCSNo
            ycSMP5tcYVWhzMFMTFVVAxGrjBCg0XOm0nnP0iiNT7MZgqS9aTqt9CHtBDfoADRD
            WmyJnRUuk1W8+26VyTDMkKOiWdtPKKR3QgXa7MICoJB7j+elMR+QeRinJd+DIOer
            6cHZjFe33kKa7MALqUThzeUn/Tn3MkzF0/QXe4yl56g=
            -----END CERTIFICATE-----
        EOT -> (known after apply)
        id                        = "arn:aws:acm:eu-west-2:320797911953:certificate/b385c2fd-a847-4780-87e7-9347b17ee52d"
      ~ private_key               = (sensitive value)
        tags                      = {}
        # (17 unchanged attributes hidden)

        # (1 unchanged block hidden)
    }

  # tls_cert_request.cert must be replaced
-/+ resource "tls_cert_request" "cert" {
      ~ cert_request_pem = <<-EOT
            -----BEGIN CERTIFICATE REQUEST-----
            MIICfTCCAWUCAQAwODEbMBkGA1UEChMSQUNNRSBFeGFtcGxlcywgSW5jMRkwFwYD
            VQQDExBjZXJ0LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
            CgKCAQEAxF1XaJbZKPSky1SptY5tY4L+nOiBFxZ1wET0v2rCMepJ4rtB6rMDHlY6
            AhVUdwBVOKXvyuBQOAs+srtfHaesoQGKomv6B/U1mgdO6lQk0tWYabo5367ujSWL
            zkaCzAIK6yyHeFU5DpfKhU/EeYyw5rS+n2r0qxPLX16sdK95AP7/E2QnRBVopFTQ
            lwq4o4TY2fEtbrFbnMXrZdSMu+l9EtAI1VHp0M04FfLJnuxQmVFE29E66WEdVuKO
            gAsskVYR7GItjYTLGufHh45HYOA1TbFI3SZqgJuQNNubpJkM+15fRglXt8N5+O0j
            6epJF1YUJ0LHUc1ow6v1zmFAtNo2WwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEB
            ALEoMx8BSizfmIWK+XZJflFs2OiVVl47xAfqnvLmrrjhdNmbaOzRPNnK/GY/How2
            uGr9vI7nK23xTd4zO1JAui7fQIaEcMZpkGwzCWLYtoiAGFrycgEeUqVtlArSOfk5
            dtoSvkWbQ95Yf7so/vNLZbtCnIiKjCbDuQYJIrT8UgXJtr1Lv8pp/PFifmjXBrNL
            igikzDNYh+z34IvcR4D1l9S/cuw8ZOX24EudgMzmZm5lHfozGQCSm8IHPlBtzjHm
            V+lNaxGcs8MCi7UuMUM8OBY6YTWRnZOGLRUBcflcR10V5AcMQ1FJc8I8UGOQt6ES
            4Qtcm4jGpXoTwhb5RA10XT4=
            -----END CERTIFICATE REQUEST-----
        EOT -> (known after apply)
      ~ id               = "0264fc230ccc350f80723a1fa1dd5d53b3a7fffe" -> (known after apply)
      ~ key_algorithm    = "RSA" -> (known after apply)
      ~ private_key_pem  = (sensitive value) # forces replacement

        # (1 unchanged block hidden)
    }

  # tls_locally_signed_cert.cert must be replaced
-/+ resource "tls_locally_signed_cert" "cert" {
      ~ ca_key_algorithm      = "RSA" -> (known after apply)
      ~ cert_pem              = <<-EOT
            -----BEGIN CERTIFICATE-----
            MIIDTDCCAjSgAwIBAgIRALZX1Ffb//T7jr7w45PceZkwDQYJKoZIhvcNAQELBQAw
            MzEbMBkGA1UEChMSQUNNRSBFeGFtcGxlcywgSW5jMRQwEgYDVQQDEwtleGFtcGxl
            LmNvbTAeFw0yMzAyMjgyMDE3MzlaFw0yMzAzMDEwODE3MzlaMDgxGzAZBgNVBAoT
            EkFDTUUgRXhhbXBsZXMsIEluYzEZMBcGA1UEAxMQY2VydC5leGFtcGxlLmNvbTCC
            ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRdV2iW2Sj0pMtUqbWObWOC
            /pzogRcWdcBE9L9qwjHqSeK7QeqzAx5WOgIVVHcAVTil78rgUDgLPrK7Xx2nrKEB
            iqJr+gf1NZoHTupUJNLVmGm6Od+u7o0li85GgswCCussh3hVOQ6XyoVPxHmMsOa0
            vp9q9KsTy19erHSveQD+/xNkJ0QVaKRU0JcKuKOE2NnxLW6xW5zF62XUjLvpfRLQ
            CNVR6dDNOBXyyZ7sUJlRRNvROulhHVbijoALLJFWEexiLY2Eyxrnx4eOR2DgNU2x
            SN0maoCbkDTbm6SZDPteX0YJV7fDefjtI+nqSRdWFCdCx1HNaMOr9c5hQLTaNlsC
            AwEAAaNWMFQwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwG
            A1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUKM7BnjfT2fvKfKc8qfJ/YJZMW3cwDQYJ
            KoZIhvcNAQELBQADggEBALJ0z2SGnDJMsFdOWgUcVHaBUz+jS37uHJCrWB1hCDTl
            zqHf0OU4nz09xizohSic2KrcaIyLR6NCb8IuUeuRgBfb7tNXtBuRK6Gu5gL+hWzz
            zBSOrlQC45OHDkLa7W5zDIpuX7qJa57ob2e98H9uuPsA3RbCQeSic36WmBlDCSNo
            ycSMP5tcYVWhzMFMTFVVAxGrjBCg0XOm0nnP0iiNT7MZgqS9aTqt9CHtBDfoADRD
            WmyJnRUuk1W8+26VyTDMkKOiWdtPKKR3QgXa7MICoJB7j+elMR+QeRinJd+DIOer
            6cHZjFe33kKa7MALqUThzeUn/Tn3MkzF0/QXe4yl56g=
            -----END CERTIFICATE-----
        EOT -> (known after apply)
      ~ cert_request_pem      = <<-EOT
            -----BEGIN CERTIFICATE REQUEST-----
            MIICfTCCAWUCAQAwODEbMBkGA1UEChMSQUNNRSBFeGFtcGxlcywgSW5jMRkwFwYD
            VQQDExBjZXJ0LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
            CgKCAQEAxF1XaJbZKPSky1SptY5tY4L+nOiBFxZ1wET0v2rCMepJ4rtB6rMDHlY6
            AhVUdwBVOKXvyuBQOAs+srtfHaesoQGKomv6B/U1mgdO6lQk0tWYabo5367ujSWL
            zkaCzAIK6yyHeFU5DpfKhU/EeYyw5rS+n2r0qxPLX16sdK95AP7/E2QnRBVopFTQ
            lwq4o4TY2fEtbrFbnMXrZdSMu+l9EtAI1VHp0M04FfLJnuxQmVFE29E66WEdVuKO
            gAsskVYR7GItjYTLGufHh45HYOA1TbFI3SZqgJuQNNubpJkM+15fRglXt8N5+O0j
            6epJF1YUJ0LHUc1ow6v1zmFAtNo2WwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEB
            ALEoMx8BSizfmIWK+XZJflFs2OiVVl47xAfqnvLmrrjhdNmbaOzRPNnK/GY/How2
            uGr9vI7nK23xTd4zO1JAui7fQIaEcMZpkGwzCWLYtoiAGFrycgEeUqVtlArSOfk5
            dtoSvkWbQ95Yf7so/vNLZbtCnIiKjCbDuQYJIrT8UgXJtr1Lv8pp/PFifmjXBrNL
            igikzDNYh+z34IvcR4D1l9S/cuw8ZOX24EudgMzmZm5lHfozGQCSm8IHPlBtzjHm
            V+lNaxGcs8MCi7UuMUM8OBY6YTWRnZOGLRUBcflcR10V5AcMQ1FJc8I8UGOQt6ES
            4Qtcm4jGpXoTwhb5RA10XT4=
            -----END CERTIFICATE REQUEST-----
        EOT -> (known after apply) # forces replacement
      ~ id                    = "242375531891319981900019092251257633177" -> (known after apply)
      ~ validity_end_time     = "2023-03-01T08:17:39.462762461Z" -> (known after apply)
      ~ validity_start_time   = "2023-02-28T20:17:39.462762461Z" -> (known after apply)
        # (8 unchanged attributes hidden)
    }

  # tls_private_key.cert is tainted, so must be replaced
-/+ resource "tls_private_key" "cert" {
      ~ id                            = "ecbac0d9f5b3c9ef697892b5a4476dd469843d7a" -> (known after apply)
      ~ private_key_openssh           = (sensitive value)
      ~ private_key_pem               = (sensitive value)
      ~ private_key_pem_pkcs8         = (sensitive value)
      ~ public_key_fingerprint_md5    = "86:c5:ff:28:2e:ec:df:cf:91:6d:4f:a5:74:48:61:1e" -> (known after apply)
      ~ public_key_fingerprint_sha256 = "SHA256:ySMUc6mRrB5MWZ4Mf2FYQLQ41MmjDiuGu1mTQkQmZVg" -> (known after apply)
      ~ public_key_openssh            = <<-EOT
            ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEXVdoltko9KTLVKm1jm1jgv6c6IEXFnXARPS/asIx6kniu0HqswMeVjoCFVR3AFU4pe/K4FA4Cz6yu18dp6yhAYqia/oH9TWaB07qVCTS1Zhpujnfru6NJYvORoLMAgrrLId4VTkOl8qFT8R5jLDmtL6favSrE8tfXqx0r3kA/v8TZCdEFWikVNCXCrijhNjZ8S1usVucxetl1Iy76X0S0AjVUenQzTgV8sme7FCZUUTb0TrpYR1W4o6ACyyRVhHsYi2NhMsa58eHjkdg4DVNsUjdJmqAm5A025ukmQz7Xl9GCVe3w3n47SPp6kkXVhQnQsdRzWjDq/XOYUC02jZb
        EOT -> (known after apply)
      ~ public_key_pem                = <<-EOT
            -----BEGIN PUBLIC KEY-----
            MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxF1XaJbZKPSky1SptY5t
            Y4L+nOiBFxZ1wET0v2rCMepJ4rtB6rMDHlY6AhVUdwBVOKXvyuBQOAs+srtfHaes
            oQGKomv6B/U1mgdO6lQk0tWYabo5367ujSWLzkaCzAIK6yyHeFU5DpfKhU/EeYyw
            5rS+n2r0qxPLX16sdK95AP7/E2QnRBVopFTQlwq4o4TY2fEtbrFbnMXrZdSMu+l9
            EtAI1VHp0M04FfLJnuxQmVFE29E66WEdVuKOgAsskVYR7GItjYTLGufHh45HYOA1
            TbFI3SZqgJuQNNubpJkM+15fRglXt8N5+O0j6epJF1YUJ0LHUc1ow6v1zmFAtNo2
            WwIDAQAB
            -----END PUBLIC KEY-----
        EOT -> (known after apply)
        # (3 unchanged attributes hidden)
    }

Plan: 3 to add, 1 to change, 3 to destroy.

@NoahCallaway
Copy link
Author

NoahCallaway commented Mar 1, 2023

Hi @mattburgess, thanks for looking into this.

Yes, apologies I've been slightly stingy with my plan output as didn't want to share anything I shouldn't.
You've recreated my issue exactly.

With my existing configuration, I'm also seeing the certificate transparency logging option as the reason for replacement - I should have spotted this earlier apologies.

Section from the plan on aws_acm_certificate.cert resource shown below.

  # module.vault_cert.aws_acm_certificate.cert must be replaced
-/+ resource "aws_acm_certificate" "cert" {
      ~ arn                       = "arn:aws:acm:eu-west-2:<account-number>:certificate/<guid>" -> (known after apply)
      - certificate_authority_arn = "" -> null
      ~ certificate_body          = <<-EOT

    .............

      ~ type                      = "IMPORTED" -> (known after apply)
      ~ validation_emails         = [] -> (known after apply)
      ~ validation_method         = "NONE" -> (known after apply)
        # (1 unchanged attribute hidden)

      - options {
          - certificate_transparency_logging_preference = "DISABLED" -> null # forces replacement
        }
    }

Adding the options as you did in cert.tf looks like it fixed my issue when I run the plan as below.

  # module.vault_cert.aws_acm_certificate.cert will be updated in-place
  ~ resource "aws_acm_certificate" "cert" {
      ~ certificate_body          = <<-EOT

However, once the apply is run I get a conflict error:

╷
│ Error: Conflicting configuration arguments
│ 
│   with module.vault_cert.aws_acm_certificate.cert,
│   on vault_pki_cert_to_acm/main.tf line 24, in resource "aws_acm_certificate" "cert":
│   24:     certificate_transparency_logging_preference = "DISABLED"
│ 
│ "options.0.certificate_transparency_logging_preference": conflicts with certificate_body

Thanks again for your help.

@NoahCallaway
Copy link
Author

NoahCallaway commented Mar 1, 2023

It looks like I might be able to workaround this issue by adding the lifecycle block to ignore changes to the options.

The following allows me to re-import the certificate successfully without changing the ARN.

resource "aws_acm_certificate" "cert" {
  private_key       = vault_pki_secret_backend_cert.cert.private_key
  certificate_body  = vault_pki_secret_backend_cert.cert.certificate
  certificate_chain = vault_pki_secret_backend_cert.cert.ca_chain

  lifecycle {
    ignore_changes = [
      options,
    ]
  }
  tags = var.tags
}

@justinretzolk justinretzolk removed the needs-triage Waiting for first response or review from a maintainer. label Mar 6, 2023
@github-actions github-actions bot added this to the v4.58.0 milestone Mar 8, 2023
@github-actions
Copy link

This functionality has been released in v4.58.0 of the Terraform AWS Provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading.

For further feature requests or bug reports with this functionality, please create a new GitHub issue following the template. Thank you!

@github-actions
Copy link

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Addresses a defect in current functionality. service/acm Issues and PRs that pertain to the acm service.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants