Terraform & AWS: ACM Certificate Never Validated

Viewed 6314

I am trying to create an ACM certificate to apply to my Amazon ALB using Terraform 0.12.0. I'm able to create my ALB without a certificate with no problem. The entire infrastructure stack is built and deployed as expected. Now, I've added the following code to create the Route 53 validation record, request the certificate, and assign it to a new ALB listener:

resource "aws_route53_zone" "main" {
  name = "${var.zone_name}"
}

resource "aws_route53_record" "validation" {
  name    = "${aws_acm_certificate.main.domain_validation_options.0.resource_record_name}"
  type    = "${aws_acm_certificate.main.domain_validation_options.0.resource_record_type}"
  zone_id = "${aws_route53_zone.main.zone_id}"
  records = ["${aws_acm_certificate.main.domain_validation_options.0.resource_record_value}"]
  ttl     = "60"
}

resource "aws_acm_certificate_validation" "main" {
  certificate_arn = "${aws_acm_certificate.main.arn}"
  validation_record_fqdns = "${aws_route53_record.validation.*.fqdn}"
}

resource "aws_alb_listener" "front_end_tls" {
  load_balancer_arn = "${aws_alb.main.id}"
  port              = "443"
  protocol          = "HTTPS"

  ssl_policy = "ELBSecurityPolicy-2016–08"
  certificate_arn = "${var.certificate_arn}"

  default_action {
    target_group_arn = "${aws_alb_target_group.main.id}"
    type             = "forward"
  }
}

When I run terraform apply, however, it seems to get stuck on the certificate validation. I see messages like this:

module.dns.aws_acm_certificate_validation.main: Still creating... [38m21s elapsed]

I've let the code run for over 45 minutes, until I eventually see an error saying:

Error: Error creating LB Listener: SSLPolicyNotFound: SSL policy 'ELBSecurityPolicy-2016–08' not found
    status code: 400, request id: a5f052c1-86df-11e9-993c-f99526fa9bba

  on alb/main.tf line 25, in resource "aws_alb_listener" "front_end_tls":
  25: resource "aws_alb_listener" "front_end_tls" {



Error: Expected certificate to be issued but was in state PENDING_VALIDATION

  on dns/main.tf line 38, in resource "aws_acm_certificate_validation" "main":
  38: resource "aws_acm_certificate_validation" "main" {

If I login to the console, I see the certificate request still in the Pending Validation state. I also see the Route 53 validation record created as expected.

Why is it that this certificate request is never processed and applied? Am I missing something in my Terraform code?

UPDATE: When I use an existing Route 53 zone (with a different domain name from the one I'm trying above) and reference it as a data resource in my aws_route53_record, it works with no problem. The domain name I'm trying in this test was just purchased via Route 53 today, so I'm wondering if that has something to do with my issue. I'm unable to do an nslookup on any of the records, even though I see them listed in the Route 53 console. Maybe? I'll let it sit for a couple days and see if it's just a timing issue.

3 Answers

I don't have reputation to comment, so writing an answer

OP mentioned in a comment that domain was purchased from route53, in that case a hosted zone should have been created for the domain. OP also mentions that they can see the records from AWS console but can't do nslookup for any of these records.

I think in this case OP might not have purchased a domain and might have created a private hosted zone and is working with that. And off course public ACM certs can't be validated with private hosted zone

AWS Forum: https://forums.aws.amazon.com/thread.jspa?threadID=238468

Before to apply the following code, make sure you've purchased one domain and then, fill domain_name variable, if it should be a wildcard, you can use wildcard_enable = true this way, you can create a wildcard certificate, really useful to reuse the same ACM in different subdomains.

My directory structure

.
|____main.tf
|____variables.tf

main.tf

locals {
  final_domain = "${var.wildcard_enable == true ? "*.${var.domain_name}" : var.domain_name}"
}

resource "aws_acm_certificate" "this" {
  domain_name       = local.final_domain
  validation_method = "DNS"

  tags = {
    "Name"       = "acm-cert-name"
    "costCenter" = "xxxxxxxxx"
    "owner"      = "xxxxxxxxx"
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_route53_record" "this" {
  depends_on = ["aws_acm_certificate.this"]
  zone_id    = "xxxxxxxxxx"
  name       = aws_acm_certificate.this.domain_validation_options.0.resource_record_name
  type       = "CNAME"
  ttl        = "300"
  records    = [aws_acm_certificate.this.domain_validation_options.0.resource_record_value]
}

variables.tf

variable "wildcard_enable" {
  description = "Variable that allow us to choose the possibility of not use wildcard certificate"
  default     = false
}

variable "domain_name" {
  description = "The name of the domain to which apply the cert"
}

First: apply this code as a module or just apply it and wait until AWS validate it.

Finally: use aws_acm_certificate.this.arn to get the ACM arn and it could be used on ALB.

If the ACM certificate wasn't validated yet, you can't use it with ALB because the AWS api doesn't retrieve the ACM ARN.

I hope will be useful to you and other users.

Be sure you put the right name servers in the domain configuration if you purchased outside Route53

Related