【小ネタ】TerraformでACM証明書作成してALBに関連付ける

TerraformでACM証明書作成とALBへの関連づけを楽して対応したい
2021.03.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは!コンサル部のinomaso(@inomasosan)です。

最近はAWSでWebサイトを構築する際、SSLサーバ証明書をACMの無料証明書(DV証明書)にて対応することが多かったです。
そこでサクッと構築できるように、Terraformでコード化を検証してみました。

この記事で学べること

  • ACM証明書やALBの作成方法
  • Terraformでのコードの書き方

環境

今回実行した環境は以下の通りです。

  • macOS Catalina 10.15.7
  • Terraform 0.14.8
  • AWSプロバイダー 3.34.0

前提

Route53でドメイン登録等を実施し、ホストゾーン作成まで完了していること。

コード

1. ACM関連

ACMで無料証明書を作成し、Route53にACMのドメイン検証用レコードを追加します。
Route53のホストゾーンIDは手動入力しているので、ご自分の環境で試される際は、AWSマネージメントコンソール等からご確認願います。

resource "aws_acm_certificate" "cert" {
  # ワイルドカード証明書で同じドメイン内の複数のサイトを保護
  domain_name               = "*.inomaso.classmethod.info"
  # ネイキッドドメインや apex ドメイン(ドメイン名そのもの)を保護
  subject_alternative_names = ["inomaso.classmethod.info"]
  # ACMドメイン検証方法にDNS検証を指定
  validation_method         = "DNS"

  lifecycle {
    create_before_destroy = true
  }

  tags = {
    Name = "inomaso-dev-acm"
  }
}

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
    }
  }

  allow_overwrite = true
  name = each.value.name
  records = [each.value.record]
  type = each.value.type
  ttl = "300"

  # レコードを追加するドメインのホストゾーンIDを指定
  zone_id = "Z123456789ABCDEFG"
}

2. ALB関連

ALBを作成し、ACM証明書をHTTPSリスナーに関連付けます。

resource "aws_lb" "alb" {
  name               = "inomaso-dev-alb"
  load_balancer_type = "application"
  internal           = false
  idle_timeout               = 60
  security_groups = [
    aws_security_group.alb.id
  ]
  subnets = [
    aws_subnet.sub_front_1a.id,
    aws_subnet.sub_front_1c.id
  ]
}

resource "aws_alb_listener" "alb_https" {
  load_balancer_arn = aws_lb.alb.arn
  port              = "443"
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  # ACM証明書をHTTPSリスナーに関連づけ
  certificate_arn   = aws_acm_certificate.cert.arn

  default_action {
    target_group_arn = aws_lb_target_group.ec2_http.arn
    type             = "forward"
  }
}

resource "aws_lb_target_group" "ec2_http" {
  name     = "inomaso-dev-alb-tg"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.vpc.id

  health_check {
    interval            = 10
    path                = "/"
    port                = "traffic-port"
    protocol            = "HTTP"
    timeout             = 5
    healthy_threshold   = 2
    unhealthy_threshold = 2
  }
}

resource "aws_lb_target_group_attachment" "ec2" {
  target_group_arn = aws_lb_target_group.ec2_http.arn
  target_id        = aws_instance.ec2.id
  port             = 80
}

ハマったこと

Route53にACMのドメイン検証用レコード追加は、最初以下のようなコードにしていましたが
This value does not have any indices.というエラーが発生しました。

resource "aws_route53_record" "acm" {
  zone_id = "Z123456789ABCDEFG"
  name = aws_acm_certificate.acm.domain_validation_options[0].resource_record_name
  type = aws_acm_certificate.acm.domain_validation_options[0].resource_record_type
  records = [aws_acm_certificate.acm.domain_validation_options[0].resource_record_value]
  ttl = "300"
}

調べてみたところ、AWS Provider 3.0.0 以降から仕様変更されており、listタイプではダメなことがわかりました。

下記ブログにある通り、今回はsetタイプにコードを修正しております。

set は list とは異なり順序付けされません。よって、以前のようなカウントインデックスは割り当てられず Error: Invalid index となるわけです。

結果確認

まずはACMから確認していきます。

証明書の状況は発行済で、ドメイン検証状態も成功しております。
また更新資格も使用可能のため、証明書の自動更新にも対応済です。

次にALBを確認していきます。

HTTPSリスナールールにSSL証明書が関連付けられていますね。

まとめ

ACM証明書作成からALBへの関連づけまでをコードで対応できるようになったので、構築時には楽できるようになりました。

ちょっとずつ、AWSマネージメントコンソールのポチポチから卒業していきたいと思います。

この記事が、どなたかのお役に立てば幸いです。それでは!