Issue validating AWS ACM certification using Terraform - amazon-web-services

Disclaimer: I am new to both AWS and Terraform.
I am testing something out and when deploying my code, I keep running into the same error after running Terraform Apply
Error describing created certificate: Expected certificate to be issued but was in state PENDING_VALIDATION
I have tried running my code multiple times and it times out at 60 minutes each time. I cannot exceed 60 minutes due to a timeout of my session.
For this, there were two steps:
Create the Hosted Zone in a account 2 (this was done by a colleague and completed successfully)
resource "aws_route53_zone" "<example>" {
name = "<domain name>"
2.Created the A record, ACM cert, validation record, and validation object in account 1
resource "aws_route53_record" "<service>" {
provider = aws.account2
zone_id = data.terraform_remote_state.account2.outputs.route53_<example>_zone_id[0]
name = var.domain_name
type = "A"
alias {
name = aws_alb.<service>.dns_name
zone_id = aws_alb.<service>.zone_id
evaluate_target_health = true
}
}
resource "aws_acm_certificate" "<service>" {
domain_name = var.domain_name
validation_method = "DNS"
lifecycle {
create_before_destroy = true
}
}
resource "aws_route53_record" "<service>_validation" {
provider = aws.account2
for_each = {
for dvo in aws_acm_certificate.<service>.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 = data.terraform_remote_state.account2.outputs.route53_<example>_zone_id[0]
}
resource "aws_acm_certificate_validation" "<service>" {
certificate_arn = aws_acm_certificate.<service>.arn
validation_record_fqdns = [for record in aws_route53_record.<service>_validation : record.fqdn]
timeouts {
create = "60m"
}
}
I have looked at quite a few examples online and cannot figure out yet where I went wrong. This is the final piece of my Terraform Apply.
I have checked the AWS Console on Account2 and I saw that the subdomain hosted zone was created and contained the necessary NS record as described here https://aws.amazon.com/premiumsupport/knowledge-center/create-subdomain-route-53/
When I dig A <domain name>
; <<>> DiG 9.16.1-Ubuntu <<>> A <domain name>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 48891
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;<domain name>. IN A
;; AUTHORITY SECTION:
<parent domain>. 300 IN SOA <xxxxxx>.com. <xxxx>.com. 1 14400 3600 604800 300
;; Query time: 100 msec
;; SERVER: x.x.x.x#53(x.x.x.x)
;; WHEN: Fri Apr 01 20:11:12 PDT 2022
;; MSG SIZE rcvd: 152

Related

Validate the certificates from 2 different accounts in AWS Terraform

I have an individual(dev) account and the certificate is created based on the below module. The validation takes place in the root account (i.e., prod account) so when I go to the route 53 of the root account and add the domain entries (create record) and copy the CVALUE of the domain and paste it over there, then my individual account certificate gets validated and changed from "Pending Validation" to "Issued".
I want the below tf to add the entries (domain name and CVALUE) to the root account so that while terraform apply the certificate gets validated. Right now, I am manually adding the CVALUE entries to the root account for validation.
public_dns.tf
resource "aws_route53_zone" "public" {
name = var.domain
}
resource "aws_acm_certificate" "elb_cert" {
domain_name = var.domain
subject_alternative_names = ["*.${var.domain}"]
validation_method = "DNS"
}
resource "aws_route53_record" "cert_validation" {
for_each = {
for dvo in aws_acm_certificate.elb_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.public.zone_id
}
resource "aws_acm_certificate_validation" "elb_cert" {
count = var.certify_domain ? 1 : 0
certificate_arn = aws_acm_certificate.elb_cert.arn
validation_record_fqdns = [for record in aws_route53_record.cert_validation : record.fqdn]
}
To accomplish what you want, you will need to use multiple aws providers (alias).
One for the root account and one for the dev account, as you will be managing resources in two different accounts.
it will look something like this:
provider "aws" {
alias = "prod"
***
}
provider "aws" {
alias = "dev"
***
}
resource "aws_******"{
provider = aws.prod
***
***
}
resource "aws_******"{
provider = aws.dev
***
***
}
Official documentation
Medium article about it

ACM certificates cross account DNS validation

I have 2 AWS accounts: dev and prod.
In the prod account, I setup a DNS domain (example.com), as well as 2 public Hosted Zone: example.com and prod.example.com. 2 ACM certificates are also issued for these domains internal.prod.example.com and eks.prod.example.com. Those certificates are correctly validated by DNS.
In the dev account, I have created 2 public Hosted Zones: dev.example.com and example.com. I issued 2 ACM certificates for internal.dev.example.com and eks.dev.example.com which, as far as I understand need to be validated with the DNS in the prod account.
These certificated are in pending state.
How can I validate them?
What I did so far:
I added a NS record called dev.example.com in the prod account for the example.com Hosted Zone. The value of the NS record are the ones of the dev.example.com Hosted Zone created in the dev account. This is to delegate the ownership of the R53 Hosted Zone in prod. See here.
In the dev account, the CNAME of the requested domain from ACM have been added in the dev.example.com Hosted Zone for validation.
The following code is how it's been done (and working) on the prod account.
Note - this is a code that I took over, so I'm not aware if any manual steps have been taken.
data "aws_route53_zone" "dns-zone" {
name = "${var.environment}.${var.zone_name}"
}
resource "aws_acm_certificate" "cert" {
domain_name = "*.${var.environment}.${var.zone_name}"
validation_method = "DNS"
subject_alternative_names = list("*.internal.${var.environment}.${var.zone_name}", "*.eks.${var.environment}.${var.zone_name}")
lifecycle {
create_before_destroy = true
prevent_destroy = true
}
}
resource "aws_route53_record" "cert_validation" {
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
zone_id = data.aws_route53_zone.dns-zone.zone_id
}
}
allow_overwrite = true
name = each.value.name
records = [each.value.record]
ttl = 60
type = each.value.type
zone_id = each.value.zone_id
}
resource "aws_acm_certificate_validation" "cert" {
certificate_arn = aws_acm_certificate.cert.arn
validation_record_fqdns = [for record in aws_route53_record.cert_validation : record.fqdn]
}
Ps - Should you need more clarification, please let me know.
dev & prod account you have example.com? Only 1 can be used properly. Wherever the registrar is for example.com ... that registrar can only use the name servers from 1 of those hosted zones.
You mentioned you have 2 ACM certs for internal.dev.example.com & eks.dev.example.com ... those should be validated in the DEV Account if that's where their domains are created.
Also I recommend you just create 1 wild card cert in ACM for *.dev.example.com & validate that 1 in the DEV account. Any subdomains such as eks.dev.example.com will be able to use it.

AWS ACM certificate not validating

Before I begin let me say that I read thoroughly all the stack overflow posts and resources in the appendix, and could not find a solution to my problem.
I am trying to create, validate and connect a subdomain through Route53 and AWS Certificate Manager. The subdomain is challenge.sre.mycompany.com.
The terraform plan looks something like this:
# module.project_challenge.module.challenge-certificate.aws_acm_certificate.cert will be created
+ resource "aws_acm_certificate" "cert" {
+ arn = (known after apply)
+ domain_name = "challenge.sre.mycompany.com"
+ domain_validation_options = [
+ {
+ domain_name = "challenge.sre.mycompany.com"
+ resource_record_name = (known after apply)
+ resource_record_type = (known after apply)
+ resource_record_value = (known after apply)
},
]
+ id = (known after apply)
+ status = (known after apply)
+ subject_alternative_names = (known after apply)
+ tags_all = (known after apply)
+ validation_emails = (known after apply)
+ validation_method = "DNS"
}
# module.project_challenge.module.challenge-certificate.aws_acm_certificate_validation.cert will be created
+ resource "aws_acm_certificate_validation" "cert" {
+ certificate_arn = (known after apply)
+ id = (known after apply)
+ validation_record_fqdns = (known after apply)
}
# module.project_challenge.module.challenge-certificate.aws_route53_record.cert["challenge.sre.mycompany.com"] will be created
+ resource "aws_route53_record" "cert" {
+ allow_overwrite = true
+ fqdn = (known after apply)
+ id = (known after apply)
+ name = (known after apply)
+ records = (known after apply)
+ ttl = 60
+ type = (known after apply)
+ zone_id = (known after apply)
}
# module.project_challenge.module.vpc.aws_route53_zone.public will be created
+ resource "aws_route53_zone" "public" {
+ arn = (known after apply)
+ comment = "Managed by Terraform"
+ force_destroy = false
+ id = (known after apply)
+ name = "sre.mycompany.com"
+ name_servers = (known after apply)
+ tags_all = (known after apply)
+ zone_id = (known after apply)
}
As you can see, it create a public hosted zone, an acm certificate and even the validation record. The problem here is that the certificate is stuck on 'Pending Validation` for about 48 hours.
Some details:
The domain is registered through our production account, where I am working on our development account for this.
Both accounts are in the same AWS organisation (if this matters)
Terraform created a public hosted zone sre.mycompany.com with the following attributes:
sre.mycompany.com NS Records:
ns-001.awsdns-01.com.
ns-002.awsdns-02.net.
ns-003.awsdns-03.co.uk.
ns-004.awsdns-04.org.
sre.mycompany.com SOA Simple Record:
ns-001.awsdns-01.com. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400
CNAME Simple Record
_g938534f3gfe03832h34.challenge.sre.mycompany.com _89432htieh4934hw043f.tkfpekghn.acm-validations.aws.
Obviously the real values are obfuscated*
When I dig sre.mycompany.com or dig challenge.sre.mycompany.com I get:
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 16577
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
When I dig just mycompany.com I get:
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61857
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 5
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;mycompany.com. IN A
;; ANSWER SECTION:
mycompany.com. 300 IN A <some-ip-hidden>
;; AUTHORITY SECTION:
mycompany.com. 169554 IN NS ns-555.awsdns-55.com.
mycompany.com. 169554 IN NS ns-666.awsdns-66.net.
mycompany.com. 169554 IN NS ns-777.awsdns-77.org.
mycompany.com. 169554 IN NS ns-888.awsdns-88.co.uk.
Notice that the nameservers here are different from the ones I see in the console of my terraform created hosted zone (scroll above ns-001.awsdns-01.com. etc)
I cannot seem to fetch the CNAME record from my terminal.
In AWS everything seems to work fine on the other hand. When I go to:
Route 53> Hosted zones > Test Record I do get the value of the CNAME record:
Response returned by Route 53
Response from Route 53 based on the following options.
Hosted zone: sre.mycompany.com
Record name: _g938534f3gfe03832h34.challenge.
Record type: CNAME
DNS response code: No Error
Protocol: UDP
Response returned by Route 53: _89432htieh4934hw043f.tkfpekghn.acm-validations.aws.
At last if I , the response is:
;; Received 888 bytes from <some-ip-hidden>#53(ns-666.awsdns-66.net) in 3 ms
mycompany.com. 169201 IN NS ns-666.awsdns-66.net.
mycompany.com. 169201 IN NS ns-777.awsdns-77.org.
mycompany.com. 169201 IN NS ns-888.awsdns-88.co.uk.
mycompany.com. 169201 IN NS ns-555.awsdns-55.com.
;; BAD (HORIZONTAL) REFERRAL
;; Received 888 bytes from <some-ip-hidden>#53(ns-888.awsdns-88.co.uk) in 4 ms
mycompany.com. 169201 IN NS ns-777.awsdns-77.org.
mycompany.com. 169201 IN NS ns-666.awsdns-66.net.
mycompany.com. 169201 IN NS ns-888.awsdns-88.co.uk.
mycompany.com. 169201 IN NS ns-555.awsdns-55.com.
;; BAD (HORIZONTAL) REFERRAL
;; Received 888 bytes from <some-ip-hidden>#53(ns-555.awsdns-55.com) in 4 ms
mycompany.com. 169201 IN NS ns-666.awsdns-66.net.
mycompany.com. 169201 IN NS ns-777.awsdns-77.org.
mycompany.com. 169201 IN NS ns-555.awsdns-55.com.
mycompany.com. 169201 IN NS ns-888.awsdns-88.co.uk.
;; BAD (HORIZONTAL) REFERRAL
;; Received 888 bytes from <some-ip-hidden>#53(ns-888.awsdns-88.co.uk) in 4 ms
mycompany.com. 169201 IN NS ns-777.awsdns-77.org.
mycompany.com. 169201 IN NS ns-666.awsdns-66.net.
mycompany.com. 169201 IN NS ns-888.awsdns-88.co.uk.
mycompany.com. 169201 IN NS ns-555.awsdns-55.com.
;; BAD (HORIZONTAL) REFERRAL
;; Received 888 bytes from <some-ip-hidden>#53(ns-777.awsdns-77.org) in 5 ms
mycompany.com. 169201 IN NS ns-777.awsdns-77.org.
mycompany.com. 169201 IN NS ns-888.awsdns-88.co.uk.
mycompany.com. 169201 IN NS ns-555.awsdns-55.com.
mycompany.com. 169201 IN NS ns-666.awsdns-66.net.
;; BAD (HORIZONTAL) REFERRAL
Key takeaways:
I cannot get the CNAME with any command from my terminal
The certificate is not validating
Appendix
Certificate in Pending state in AWS Certificate Manager
Certificate with DNS Validation is stuck in Pending Validation
AWS ACM certificate state is pending validation and not changing to issues
My domain is pending validation in AWS Certificate Manager
AWS ACM Stuck in Pending Validation Unless NS Changed in Domain
Resolve ACM certificate still pending
Everything your terraform is creating is fine, however when you create a new zone in AWS you need to add the nameservers on the ROOT DNS Panel (most likely where you bought the domain mycompany.com).
You need to add the NS entry for the subdomain you want to use (the new zone you're creating)
You can reference this article https://webmasters.stackexchange.com/questions/93897/can-i-use-different-nameservers-for-different-subdomains
When you have multiple route53 hosted zones for domain and subdomains you need to link them together.
This can be done by adding the subdomain Nameservers in the domain hosted zone.
You cannot break the domain hosted zone by adding records, you will only break the link with the subdomain hosted zone.
So to clarify with an example, let's say you have a domain route53 hosted zone for
mycomany.gr
Record Name
Type
Value
mycomany.gr
NS
ns-xxxx.org ns-xxx.uk
sre.mycompany.com
NS
ns-yyy.org ns-yyy.uk
The first row is created when you create the route53 hosted zone. After you need to take the nameservers and add them to your domain provider. With this way you link the domain with AWS and it knows its valid.
The second row you will need to add it manually after you have create your subdomain route53 hosted zone (sre.mycompany.com). The nameservers now are the ones that route53 subdomain created for you. With this way you say to route53 this domain (mycompany.com) owns this subdomain (sre.mycompany.com).
All those stuff need to be done before and ACM certificates are created and the reason is that the ACM has a domain validation which tries to create a record to your valid domain or subdomain. If your domain or subdomain isnt linked to a valid domain the acm will throw an error.
Your CNAME in your zone file has a mycompany.com on the end. That's not the normal way to do a CNAME. Should probably be:
CNAME Simple Record
_g938534f3gfe03832h34.challenge.sre _89432htieh4934hw043f.tkfpekghn.acm-validations.aws.
If you add the mycompany.com into the CNAME, then the actual resolve address is _g938534f3gfe03832h34.challenge.sre.mycompany.com.mycompany.com
The only way I have found to get correct validation records into route53 through terraform looks like this:
resource "aws_route53_record" "cert-verify" {
for_each = {
for dvo in aws_acm_certificate.cert_name.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
name = each.value.name
records = [each.value.record]
ttl = 60
type = each.value.type
zone_id = aws_route53_zone.zone.zone_id
}
makes for a messy state file, but it works

trying to create an aws_route53_record to point to a load balancer but keep getting an error using terraform

As the domain already existed I imported the zone into my configuration:
resource "aws_route53_zone" "example_hosted_zone" {
name = "example.club"
}
Route 53 record:
resource "aws_route53_record" "us-battasks" {
zone_id = aws_route53_zone.example_hosted_zone.zone_id
name = "us-battasks"
type = "CNAME"
ttl = "60"
records = [aws_lb.restricted_access_lb.id]
}
resource "aws_route53_record" "us-battasksapi" {
zone_id = aws_route53_zone.example_hosted_zone.zone_id
name = "us-battasksapi"
type = "CNAME"
ttl = "60"
records = [aws_lb.restricted_access_lb.id]
}
The Terraform plan shows it will create the resource but when I apply I get this following error:
Error: [ERR]: Error building changeset: InvalidChangeBatch: [Invalid Resource Record: FATAL problem: DomainLabelTooLong (Domain label is too long) encountered with 'arn:aws:elasticloadbalancing:us-east-1:221124075124:loadbalancer', Unparseable CNAME encountered]
status code: 400, request id: e43e5ced-957f-4bcd-83d2-1e7eaea7665b
Error: [ERR]: Error building changeset: InvalidChangeBatch: [Invalid Resource Record: FATAL problem: DomainLabelTooLong (Domain label is too long) encountered with 'arn:aws:elasticloadbalancing:us-east-1:221124075124:loadbalancer', Unparseable CNAME encountered]
status code: 400, request id: 33d3340e-f2f2-4c95-bc96-a9de1349afc4
Here is the Terraform code for the load balancer if it helps:
resource "aws_lb" "restricted_access_lb" {
name = "restricted-access-lb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.swarm_node_sg.id, aws_security_group.monolaunch_instance_sg.id, aws_security_group.restricted_access_sg.id]
subnets = [aws_subnet.public_subnet_b.id, aws_subnet.public_subnet_a.id]
enable_deletion_protection = true
}
The id of the aws_lb resource is the ARN which is why you see the ARN for the load balancer shown in the error when it's trying to create a Route53 record.
Instead you should be using the dns_name attribute instead which will map to the address of the load balancer.
resource "aws_route53_record" "us-battasksapi" {
zone_id = aws_route53_zone.example_hosted_zone.zone_id
name = "us-battasksapi"
type = "CNAME"
ttl = "60"
records = [aws_lb.restricted_access_lb.dns_name]
}
If, instead, you wanted to use an alias A record to avoid the second DNS lookup (plus issues around apex records in a zone) you would instead use the following:
resource "aws_route53_record" "us-battasksapi" {
zone_id = aws_route53_zone.example_hosted_zone.zone_id
name = "us-battasksapi"
type = "A"
alias {
name = aws_lb.restricted_access_lb.dns_name
zone_id = aws_lb.restricted_access_lb.zone_id
evaluate_target_health = true
}
}
In your aws_route53_record you are using:
records = [aws_lb.restricted_access_lb.id]
This will try making CNAME to ARN of your load balancer. Instead you should be using
records = [aws_lb.restricted_access_lb.dns_name]
Ideally, it also should be A Alias record, not CNAME, as shown in the docs.

error ACM (AWS) and cloudflare for validate a certificate

resource "aws_acm_certificate" "cert" {
domain_name = "atlantis.mydomain"
validation_method = "DNS"
}
data "cloudflare_zones" "this" {
filter {
name = "myzone.com"
status = "active"
paused = false
}
}
resource "cloudflare_record" "cert_validation" {
zone_id = data.cloudflare_zones.this.zones[0].id
name = aws_acm_certificate.cert.domain_validation_options.0.resource_record_name
type = aws_acm_certificate.cert.domain_validation_options.0.resource_record_type
value = aws_acm_certificate.cert.domain_validation_options.0.resource_record_value
ttl = 3600
proxied = false
}
resource "aws_acm_certificate_validation" "cert" {
certificate_arn = aws_acm_certificate.cert.arn
validation_record_fqdns = [cloudflare_record.cert_validation.hostname]
}
1 error occurred:
* missing atlantis.mydomain DNS validation record: _1002e16ebd84cda6c12a865cf899175a.atlantis.mydomain
i don't know how to resolve this error
i have a problem when i want create a certificat ACM and validate with cloudflare in aws and with terraform.
i have an error during the deployment about dns vérification
the record and the certificate have been created , but not validate
my cloudflare module is working well and for months
You need to use the values from the Terraform aws_acm_certificate resource's domain_validation_options values to create validation DNS records in CloudFlare. These will be entirely separate from the DNS record you are creating to point to your load balancer.