ACM certificates cross account DNS validation - amazon-web-services

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.

Related

AWS ACM certificate created with terraform can't be validated, domain doesn't have valid NS (?)

I have a domain generated and managed with AWS Route53. This domain has been manually created but the rest of the infrastructure is created using terraform in different regions to avoid the initial FARGATE CPU limit.
The infrastructure is updated using a GitHub action.
I am trying to create dev environment in eu-north-1 but terraform apply failes after 1H+ of **maws_acm_certifi***e_validation.default: Still creating... [***h***5m0s elapsed] with this error:
**m│ **m**mError: **mwaiting for ACM Certifi***e (arn:aws:acm:***:***:certifi***e***7a0***bccb-0c***7-***776-ab9***-***e670b6a38f***) to be issued: timeout while waiting for state to become 'ISSUED' (last state: 'PENDING_VALIDATION', timeout: ***h***5m0s)
**m│
**m│ with aws_acm_certifi***e_validation.default,
**m│ on aws-acm.tf line ***, in resource "aws_acm_certifi***e_validation" "default":
**m│ ***: resource "aws_acm_certifi***e_validation" "default" **m{
**m│
**m╵
**m╷
**m│ **m**mError: **mcreating ELBv*** Listener (arn:aws:elasticloadbalancing:***:***:loadbalancer***app***-legacy-dev-alb***7***e5baa5dab6d3e6): UnsupportedCertifi***e: The certifi***e 'arn:aws:acm:***:***:certifi***e***7a0***bccb-0c***7-***776-ab9***-***e670b6a38f***' must have a fully-qualified domain name, a supported signature, and a supported key size.
**m│ status code: ***00, request id: 3***f5a0e9-c***ac-***fd3-aed0-60ba39***0590***
**m│
**m│ with aws_lb_listener.https_listener,
**m│ on aws-alb.tf line 70, in resource "aws_lb_listener" "https_listener":
**m│ 70: resource "aws_lb_listener" "https_listener" **m{
I think the second error is just related to the first one because the certificate isn't correctly in issued status. It's a little bit hard to read but the error says waiting for ACM Certificate to be issued: timeout while waiting for state to become 'ISSUED' (last state: 'PENDING_VALIDATION', timeout: ...).
This is part of terraform code related to the certificate:
resource "aws_acm_certificate" "default" {
domain_name = var.root_domain_name
subject_alternative_names = ["*.${var.root_domain_name}"]
validation_method = "DNS"
lifecycle {
create_before_destroy = true
}
}
resource "aws_acm_certificate_validation" "default" {
certificate_arn = aws_acm_certificate.default.arn
validation_record_fqdns = local.validation_record_fqdns
}
resource "aws_route53_record" "default" {
name = "${local.resource_prefix}.${var.root_domain_name}"
type = "CNAME"
zone_id = var.route53_record_zone_id
records = [aws_lb.main.dns_name]
ttl = 60
depends_on = [aws_lb.main]
}
resource "aws_route53_record" "acm_validation" {
name = tolist(aws_acm_certificate.default.domain_validation_options)[0].resource_record_name
type = "CNAME"
zone_id = var.route53_record_zone_id
records = [tolist(aws_acm_certificate.default.domain_validation_options)[0].resource_record_value]
ttl = 300
depends_on = [aws_acm_certificate.default]
}
I tried to add the CNAME record manually and via AWS interface via "Create records in Route 53" button too but the certificate is still in pending.
This is the record entry in Route 53:
Is there a way to trigger again this verification and fix the problem?
UPDATE:
Tried like in the terraform docs but same result.
I am starting to think there's a DNS problem with my domain. The domain should have been registered directly in AWS (I didn't do it) and when I use tools like this (or this) online nslookup and input the domain I am working with I can't get the NS, instead I get them for another domain that my company owns.
Is there something wrong with the domain instead?
Domain info:
Requests for ACM certificates time out if they are not validated within 72 hours. To correct this condition, open the console, find the record for the certificate, click the checkbox for it, choose Actions, and choose Delete. Then choose Actions and Request a certificate to begin again. For more information, see DNS validation or Email validation. We recommend that you use DNS validation if possible.
Please check this link from the AWS Knowledge center
If the hosted zone is destroyed and re-provisioned, new name server records are associated with the new hosted zone. However, the domain name might still have the previous name server records associated with it.
If AWS Route 53 is used as the domain name registrar, head to Route 53 > Registered domains > ${your-domain-name} > Add or edit name servers and add the newly associated name server records from the hosted zone to the registered domain.

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.

terraform route53 simplest example to create a dns record in hosted zone pointing to public IP of ec2 instance

I am trying to create a simplest example where in I can
create a DNS A record pointing to the public IP of an EC2 instance created in default VPC.
I have the following code for the same
hostedzone.tf
resource "aws_route53_zone" "devopslink-public-zone" {
name = var.domain_mydevops_link
comment = "${var.domain_mydevops_link} public zone"
provider = aws
}
instance.tf
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
tags = {
Name = "HelloWorld"
}
}
route53-record.tf
resource "aws_route53_record" "server1-record" {
zone_id = aws_route53_zone.devopslink-public-zone.zone_id
name = "server1.devops.link"
type = "A"
ttl = "300"
records = [aws_instance.web.public_ip]
}
Terraform apply successfully give me this
Outputs:
devopslink-name-servers = [
"ns-1363.awsdns-42.org",
"ns-1707.awsdns-21.co.uk",
"ns-466.awsdns-58.com",
"ns-941.awsdns-53.net",
]
devopslink-public-zone-id = Z06137733F7SHPRF6K9Q3
And I can see the route53 record getting created in AWS console with the public IP of the instance on route53 console
server1.devops.link A Simple - 35.174.12.184
However when i do nslookup online or by using my PC its not resolving
✗ nslookup server1.devops.link
Server: 127.0.0.53
Address: 127.0.0.53#53
** server can't find server1.devops.link: NXDOMAIN
What am i doing wrong here? I do not own the domain devops.link. My assumption is that it should be taken care by the terraform code above.
A public hosted zone is one part of the solution for hosting your DNS configuration, it will hold your DNS records. From what I can see your public hosted zone and record are correct.
The second part involves you not being able to resolve the record, as you do not own the domain there is no mapping to the public hosted zone which prevents anyone resolving the domain to your DNS records.
You need to own the domain to have it resolve to the nameserver, once you own this you would set its name servers values equal to the name server records in the public hosted zone.
As of now no official support for the Route 53 Domains service exists in Terraform, this s the service to purchase and configure the domain.
Basically for this task we need the following
A domain like mydomain.link which you own. When we say own, it means the domain is registered with the domain registrar. When you do so you can either choose their (domain registrar's) default name servers or your custom name servers created in AWS (or any other cloud provider) in a hosted zone.
an EC2 instance with public IP in default VPC
A hosted zone
route53 dns record resolving to the public IP of our instance
With all the resources given in the question, we have created an EC2 instance, a hosted zone and a route53 record.
So now we need to add the fqdn's of the nameservers generated by the terraform code in our domain-registrar's settings so that it uses our nameservers to resolve the record sets.
Link to Example - task link

Issues creating terraform resources with dependencies to resources not yet created

I can't come up with a proper title as my issue is rather complicated (at least for me).
I need to create an infrastructure in AWS
CloudFront
ElasticBeanstalk (backend)
S3 (frontend)
Route53 (dns)
CertificateManager (ssl)
...
Now I can create my hosted zone without an issue, but when I'm trying to create the cloudfront, the first thing terraform tries to do is create and validate a certificate.
As I'm not aware on how my cloudfront url will be yet, I can't create an A record pointing to it. The certificate points to that record though (it's a subdomain of my hosted zone) and therefore the certificate validation times out and terraform ends the apply.
As domain and certificate came later in the development it didn't come up yet as the cloudfront distribution has been there already, but while migrating to a environment I'm hitting a wall.
I can't force terraform to create the record first via a null_resource or a depends_on entry because that will form a loop.
Any ideas?
Update:
I'm using an alias in CloudFront, and I'm hosting my domain in Route53.
My issue though is that for the route53 record (not the validation but the certificate itself) I'm using a cloudfront reference:
resource "aws_route53_record" "frontend_record" {
name = ...
zone_id = ...
type = "A"
alias {
name = local.cloudfront_domain_name <-- this here
...
}
}
And I can't get this because the CloudFront distribution isn't created yet.
If you are using the default CloudFront URL for the CloudFront distribution that you are creating and do not define any aliases then you will want to specify the following in your configuration:
viewer_certificate {
cloudfront_default_certificate = true
}
If you have aliases defined in your CloudFront configuration like this:
aliases = ["mysite.example.com", "yoursite.example.com"]
Then that is the domain you use to create your certificates. In which case you not only want to create your certificate but validate it as well before CloudFront can use it:
resource "aws_acm_certificate" "cert" {
domain_name = "example.com"
validation_method = "DNS"
}
data "aws_route53_zone" "zone" {
name = "example.com."
private_zone = false
}
resource "aws_route53_record" "cert_validation" {
name = "${aws_acm_certificate.cert.domain_validation_options.0.resource_record_name}"
type = "${aws_acm_certificate.cert.domain_validation_options.0.resource_record_type}"
zone_id = "${data.aws_route53_zone.zone.zone_id}"
records = ["${aws_acm_certificate.cert.domain_validation_options.0.resource_record_value}"]
ttl = 60
}
resource "aws_acm_certificate_validation" "cert" {
certificate_arn = "${aws_acm_certificate.cert.arn}"
validation_record_fqdns = ["${aws_route53_record.cert_validation.fqdn}"]
}
The above assumes your domain is hosted in Route53. If your domain is not hosted in Route53 then you will likely need to create the certificate and validate it before using it in your CloudFront terraform configuration. You can validate certificates via DNS or email.

Dynamic Route 53 records for ACM certificate validation

I have a Route 53 zone (example.org) with a few record sets (example.org, sub1.example.org). I also have an ACM certificate with DNS validation for the domains described by the record sets.
All of this is described in Terraform.
Currently for the validation to work I have to list all of the domain names in the certificate (domain_name, subject_alternative_names), the certificate validation (validation_record_fqdns), and the Route 53 records (aws_route53_record resources).
Is there a better, more dynamic way of doing this so if I want to add a new subdomain I only have to do so in one place?
I read about the for and for_each features in recent versions of Terraform but so far it's not trivial for me to use that in this case.
resource "aws_acm_certificate" "example" {
domain_name = "example.org"
subject_alternative_names = ["sub1.example.org"]
validation_method = "DNS"
}
resource "aws_acm_certificate_validation" "example" {
certificate_arn = "${aws_acm_certificate.example.arn}"
validation_record_fqdns = ["${aws_route53_record.example-validation.fqdn}", "${aws_route53_record.example-validation-sub1.fqdn}"]
}
resource "aws_route53_record" "example-validation" {
zone_id = "${data.aws_route53_zone.example.id}"
name = "${aws_acm_certificate.example.domain_validation_options.0.resource_record_name}"
type = "${aws_acm_certificate.example.domain_validation_options.0.resource_record_type}"
ttl = 60
records = ["${aws_acm_certificate.example.domain_validation_options.0.resource_record_value}"]
}
resource "aws_route53_record" "example-validation-sub1" {
zone_id = "${data.aws_route53_zone.example.id}"
name = "${aws_acm_certificate.example.domain_validation_options.1.resource_record_name}"
type = "${aws_acm_certificate.example.domain_validation_options.1.resource_record_type}"
ttl = 60
records = ["${aws_acm_certificate.example.domain_validation_options.1.resource_record_value}"]
}