【问题标题】:Terraform AWS certificate hangs on validation, although records are created (manually confirmed)尽管已创建记录(手动确认),但 Terraform AWS 证书仍处于验证状态
【发布时间】:2022-01-21 02:13:05
【问题描述】:

我有以下 terraform,旨在:

  • 创建 S3 存储桶
  • 创建一个 CloudFront 分配,以存储桶为源
  • 创建 Route53 托管区域
  • 创建 ACM 证书
  • 通过 DNS 验证证书
  • 向托管区域添加一些其他 DNS 记录。
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.27"
    }
  }
  required_version = ">= 1.0.4"
}

provider "aws" {
  profile = "default"
  region  = "eu-west-2"
}

provider "aws" {
  alias = "acm"
  region = "us-east-1"
}

resource "aws_cloudfront_origin_access_identity" "frontend_access" {
}

data "aws_iam_policy_document" "s3_policy" {
  statement {
    actions   = ["s3:GetObject"]
    resources = ["${aws_s3_bucket.frontend.arn}/*"]

    principals {
      type        = "AWS"
      identifiers = [aws_cloudfront_origin_access_identity.frontend_access.iam_arn]
    }
  }
}

resource "aws_s3_bucket_policy" "frontend_bucket_policy" {
  bucket = aws_s3_bucket.frontend.id
  policy = data.aws_iam_policy_document.s3_policy.json
}

resource "aws_s3_bucket" "frontend" {
  bucket = "domain-frontend"
  acl    = "private"
}

resource "aws_acm_certificate" "default" {
  provider = aws.acm
  domain_name = "domain.com"
  subject_alternative_names = ["api.domain.com"]
  validation_method = "DNS"
  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_route53_record" "validation" {
  for_each = {
    for dvo in aws_acm_certificate.default.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.main.zone_id
}




resource "aws_acm_certificate_validation" "certValidation" {
  provider = aws.acm
  certificate_arn         = aws_acm_certificate.default.arn
  validation_record_fqdns = [for record in aws_route53_record.validation : record.fqdn]
}


resource "aws_route53_zone" "main" {
  name = "domain.com"
}


resource "aws_route53_record" "frontend_domain" {
  zone_id = aws_route53_zone.main.zone_id
  name = "domain.com"
  type = "A"

  alias {
    name = aws_cloudfront_distribution.s3_distribution.domain_name
    zone_id = aws_cloudfront_distribution.s3_distribution.hosted_zone_id
    evaluate_target_health = false
  }
}



resource "aws_route53_record" "mx_record" {
  zone_id = aws_route53_zone.main.zone_id
  name = "domain.com"
  type = "MX"
  ttl = 300
  records = [
    "1 aspmx.l.google.com.",
    "10 alt3.aspmx.l.google.com.",
    "10 alt4.aspmx.l.google.com.",
    "5 alt1.aspmx.l.google.com.",
    "5 alt2.aspmx.l.google.com."
  ]
}

resource "aws_route53_record" "google_site_verification" {
  zone_id = aws_route53_zone.main.zone_id
  name = "domain.com"
  type = "TXT"
  ttl = 300
  records = ["VALUE"]
}

resource "aws_route53_record" "dkim" {
  zone_id = aws_route53_zone.main.zone_id
  name = "google._domainkey.domain.com"
  type = "TXT"
  ttl = 300
  records = ["VALUE"]
}

resource "aws_cloudfront_distribution" "s3_distribution" {
  origin {
    domain_name = aws_s3_bucket.frontend.bucket_regional_domain_name
    origin_id   = aws_s3_bucket.frontend.id
    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.frontend_access.cloudfront_access_identity_path
    }
  }

  enabled             = true
  is_ipv6_enabled     = true
  default_root_object = "index.html"

  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD", "OPTIONS"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = aws_s3_bucket.frontend.id

    forwarded_values {
      query_string = true
      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "redirect-to-https"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 86400
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
      locations = []
    }
  }

  price_class = "PriceClass_100"

  viewer_certificate {
    acm_certificate_arn = aws_acm_certificate.default.arn
    ssl_support_method = "sni-only"
  }
}

观察到的行为是 terraform 脚本在 aws_acm_certificate_validation.certValidation Still creating... [time elapsed] 上挂起 45 分钟,此时它失败并显示 Error creating CloudFront distribution: InvalidViewerCertificate: The specified SSL certificate doesn't exist, isn't in the us-east-1 region, isn't valid, or doesn't include a valid certificate chain. 我已手动检查托管区域上的记录,并且存在验证 CNAME 记录。

【问题讨论】:

  • 我会尝试分离出这个资源创建。将 ACM 和 Route53 验证放在一个计划/根模块中,其余部分放在另一个中。您可以在第一个根模块中添加 terraform 输出,可以通过创建其余资源的第二个计划/根模块中的 terraform 数据源访问该输出。我现在没有时间确切地展示它的样子,但如果你仍然卡住,lmk & 我可以做到。
  • 我认为记录的创建不正确。尽管存在 CNAME 记录,并且在我看来很好,但即使在 24 小时后,AWS 也没有验证证书。
  • 我尝试了您的示例“domain.com”,但这对我也不起作用,但 domain.com 归其他人所有,这就是验证对我不起作用的原因。您能否确认您尝试验证的域名实际上归您所有,并且您有权访问注册商账户,您可以在其中将名称服务器 (NS) 更新为您的 Route53 AWS 名称服务器?
  • 抱歉,出于隐私原因,我更换了域,它归我所有,通过 AWS Route53 购买,所以是的,我可以更新域的 NS 记录。
  • 不幸的是,我无法使用相同的代码和我拥有的域重现您的错误。只有当我使用在注册商中没有正确名称服务器或我不拥有的域时,我才能重现此错误。所以我现在唯一能说的就是验证 CNAME 验证记录是在正确的托管区域中创建的,并确保您的托管区域是公开的,而不是私有的。

标签: amazon-web-services dns terraform terraform-provider-aws


【解决方案1】:

您的新 ACM 证书无法通过 DNS 正确验证的 1 个原因是您的 domain.com 注册商名称服务器设置。如果注册商(您购买 domain.com 的地方)与 Route53 不同,您必须确保将注册商设置中的名称服务器 (NS) 更新为托管区域中的 Route53 名称服务器,否则 DNS 验证无法正确完成.我已经使用我拥有的域进行了测试,并且上述验证按预期工作。

我尝试重现此错误,但除非我使用不属于我的域,否则我无法重现。

确保您的托管区域是公开的,而不是私有的。 您还可以添加 terraform 输出以帮助进行故障排除。在这种情况下,我添加了;

output "validation" {
  value = [for record in aws_route53_record.validation : record.fqdn]
}

【讨论】:

    猜你喜欢
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 2021-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    相关资源
    最近更新 更多