1
0

TerraformでACM PCAのルート証明書に対してACMからリクエストしてサーバ証明書を発行する処理を自動化する

Posted at

はじめに

以前の記事で、オレオレ証明書のACMへの設定方法を紹介したが、この方法だとルート証明書の認証局がないため、場合によってはHTTPS接続でエラーになってしまう。
AWSでは、AWS Private Certificate Authorityを使うことで、お手軽に認証局の機能をお任せすることができるので、TerraformのIaCで自動化してサクッと構築したうえで、ACMと連動させられるようにしておこう。

AWS Private Certificate Authority

プライベート認証局の作成

まずは、Private Certificate Authorityの作成からだ。
local.acm_pca_common_nameには自分の取得しているドメインを設定しておこう。
permanent_deletion_time_in_daysは削除後にどれだけの期間、取消可能として残しておくかのパラメータだ。今回はお試しで作っているので、最短の7日を設定している。
なお、usage_modeSHORT_LIVED_CERTIFICATE(有効期間の短い証明書)に設定すると、ACMからのリクエストがエラーになるので注意が必要だ。

resource "aws_acmpca_certificate_authority" "example" {
  type       = "ROOT"
  usage_mode = "GENERAL_PURPOSE"

  certificate_authority_configuration {
    key_algorithm     = "RSA_2048"
    signing_algorithm = "SHA512WITHRSA"

    subject {
      common_name = local.acm_pca_common_name
    }
  }

  enabled                         = true
  permanent_deletion_time_in_days = 7
}

CA証明書のインストール

プライベート認証局を作ったら、CA証明書をインストールする。
特に難しいことはないが、validity(CA証明書の有効期間)が、ACMの証明書発行のリクエストの期間よりも短いとエラーになることは留意しておこう。
また、template_arnはTerraformのパラメータ上は必須ではないが、今回のケースでは付与していないとエラーになる。

resource "aws_acmpca_certificate" "example_root" {
  certificate_authority_arn   = aws_acmpca_certificate_authority.example.arn
  certificate_signing_request = aws_acmpca_certificate_authority.example.certificate_signing_request
  signing_algorithm           = "SHA256WITHRSA"

  template_arn = "arn:aws:acm-pca:::template/RootCACertificate/V1"

  validity {
    type  = "YEARS"
    value = 10
  }
}

resource "aws_acmpca_certificate_authority_certificate" "example" {
  certificate_authority_arn = aws_acmpca_certificate_authority.example.arn

  certificate       = aws_acmpca_certificate.example_root.certificate
  certificate_chain = aws_acmpca_certificate.example_root.certificate_chain
}

ルート証明書をファイル出力する場合

ACMで設定するだけの場合は不要だが、ルート証明書を他のサーバに設定する場合はPEM形式のファイルが必要になるので、local_fileで出力しておこう。

resource "local_file" "example_root_cert_pem" {
  filename = "${path.module}/certificate/example_root.pem"
  content  = aws_acmpca_certificate_authority.example.certificate
}

ACM

サーバ証明書のリクエスト

ACMは、ACM PCAに証明書のリクエストを送るだけであれば、以下で良い。とてもお手軽だ。

resource "aws_acm_certificate" "example" {
  domain_name               = local.acm_cert_domain_name
  certificate_authority_arn = aws_acmpca_certificate_authority.example.arn
}

サーバ証明書のエクスポート

証明書のエクスポートはTerraformのAWS Providerでは機能提供されていないため、null_resource改めterraform_dataでAWS CLIを実行する。

resource "terraform_data" "export_cert" {
  provisioner "local-exec" {
    command = <<-EOF
      mkdir -p ./certificate &&
      aws acm export-certificate --certificate-arn ${aws_acm_certificate.example.arn} --passphrase $(echo -n 'example' | openssl base64 -e) > ./certificate/tmp.json
    EOF
  }
}

エクスポートにはパスフレーズが必要だが、パスフレーズはBASE64エンコードされている必要があるので、煩雑だが上記のようにしておく。また、出力はサーバ証明書と秘密鍵と証明書チェーンがまとめて出てくるので、一旦JSONの状態のまま一時ファイルに吐き出す。

サーバ証明書、秘密鍵ファイルの作成

ということで、JSONのエクスポートファイルをjqコマンドで吐き出しておく。
なお、GitLabのように、証明書ファイルのパスフレーズを入力する機能がないサーバで扱う場合は、下記の通りOpenSSLのコマンドでパスフレーズを削除した秘密鍵ファイルを作っておく。パスフレーズの削除が不要な場合は、PrivateKeyの値を直接example.keyに出力しておこう。

resource "terraform_data" "parse_json_cert" {
  depends_on = [terraform_data.export_cert]

  provisioner "local-exec" {
    command = <<-EOF
      jq -r '.Certificate' ./certificate/tmp.json > ./certificate/example.pem &&
      jq -r '.PrivateKey' ./certificate/tmp.json > ./certificate/example_pass.key &&
      openssl rsa -in ./certificate/example_pass.key -out ./certificate/example.key
    EOF
  }
}

確認

サーバ証明書が発行されたら、以下のように中身を確認してみる。
ちゃんと証明書からルート証明書をたどれることが分かる。
これで、プライベート認証局で証明をしてくれるサーバ証明書の発行ができるようになった!

$ openssl x509 -text -noout -in ./certificate/example.pem 
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            6d:dc:6a:89:d8:dc:28:26:47:0a:ee:2f:52:34:bd:0f
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = ★ルート証明書のCommon Name
        Validity
            Not Before: Feb 18 06:14:05 2024 GMT
            Not After : Mar 19 07:14:04 2025 GMT
        Subject: CN = ★サーバ証明書のCommon Name
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:c1:5d:9e:ac:17:f3:b4:15:30:42:dc:9f:e5:c2:
                    ae:51:16:df:67:d5:3c:78:c2:52:27:b2:98:95:e5:
                    68:66:29:df:49:3a:52:7a:d4:50:6b:91:30:40:1d:
                    71:4b:c6:1b:13:79:df:93:36:3f:fd:2c:fe:b4:a3:
                    9f:23:70:89:1a:bd:c2:39:44:cc:9e:67:90:7a:6f:
                    b2:82:ce:b3:91:d6:5a:c9:7b:2e:21:4c:73:f2:16:
                    46:45:c3:2c:16:98:15:ac:84:e1:c3:ad:83:e5:7b:
                    e7:90:18:b0:56:47:aa:0b:e1:ba:95:cb:a8:46:5d:
                    8a:b7:15:2d:27:bd:2d:78:ba:79:b6:0e:22:91:13:
                    44:83:51:51:b0:ae:bf:43:3e:e2:db:de:c7:89:c0:
                    a6:04:76:93:90:cc:9e:30:72:52:60:70:83:f2:58:
                    37:08:9c:8d:62:c2:56:6a:06:15:13:86:e1:2a:0a:
                    a4:57:c3:47:f8:2e:a2:55:a2:21:f3:c2:6b:73:d5:
                    15:93:e9:75:bc:47:c5:82:35:88:51:49:7a:e6:f9:
                    85:2c:9e:e4:92:55:cd:23:4b:3e:14:9e:ae:4c:b6:
                    3f:cd:53:11:49:a6:db:bc:0b:00:d8:06:f9:8e:2a:
                    d8:79:e7:9a:e4:c5:77:35:75:b2:c0:fb:ee:2d:93:
                    4a:0f
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DNS:★ドメイン名
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Authority Key Identifier: 
                keyid:53:A0:C6:14:D1:1C:C1:3F:0C:50:9E:B2:22:B0:A0:DF:6E:E3:22:CD

            X509v3 Subject Key Identifier: 
                B2:65:1F:22:A1:6D:3D:CB:04:00:F9:2C:33:A5:ED:3E:F3:29:6B:4A
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
    Signature Algorithm: sha256WithRSAEncryption
         4d:d5:82:03:9f:d5:b0:8c:29:53:90:a5:68:0a:48:53:36:9e:
         db:95:40:ff:4f:04:4e:af:58:b3:ca:e7:96:5d:c5:f3:19:a0:
         00:12:d5:95:5b:90:17:ff:33:d4:6a:ed:40:f5:41:56:59:40:
         c2:84:21:90:a1:36:c9:77:fc:a8:c4:34:66:95:8c:88:ca:8a:
         03:c8:e6:b3:96:1c:da:e0:17:b0:46:dc:01:ec:24:3a:34:13:
         28:ff:47:e5:9f:ff:4a:8d:02:57:95:01:90:f4:9a:17:98:53:
         6e:76:98:0b:2b:6b:5d:54:51:89:c8:26:aa:b7:af:e6:60:9d:
         83:2c:49:24:d8:65:74:be:2b:ad:0f:b9:cf:91:d5:31:ad:06:
         df:77:ef:bf:d5:98:d5:56:38:85:cc:05:70:93:52:9c:e1:17:
         ea:6c:18:ea:25:e4:d0:ef:40:8b:3b:fd:01:33:bb:08:d0:c4:
         54:d7:da:bd:b8:52:ca:e2:c0:11:89:64:ac:6e:25:d3:b4:9a:
         b9:46:d5:12:3a:0e:02:36:be:9a:5c:d5:e1:d7:ec:d6:54:8d:
         4d:da:c5:93:65:d6:ae:50:eb:87:f6:62:8a:18:eb:1c:ab:27:
         e8:57:83:91:f3:77:af:8c:26:4a:b8:7f:fe:fb:3e:ce:cf:ab:
         9e:43:b1:b6
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0