AWS+Rails環境でSSL証明書発行とリスナーへの紐付け

RailsからAWS SDKを使って、ACMで証明書を発行して、ELBのリスナーに証明書を紐付けてHTTPSリクエストを受信可能とした方法を説明します。

概要

弊社Webサービスの一部をお客様管理ドメインで行いたいと要望を受けました。Webサービスを提供するには、SSL証明書を発行して、ロードバランサに設定する必要があります。一般的にこれらの設定は、システム構築時にterraformなどのオーケストレーションで行います。今回はお客様が自分でドメイン設定を行う仕様となったため、これをオンラインで行います。aumoではRailsをAWSで動かしています。RailsからAWS SDKを使って、ACMで証明書を発行して、ELBのリスナーに証明書を紐付けてHTTPSリクエストを受信可能とした方法を説明します。

証明書発行要求

お客様管理ドメイン名を入力していただき、そのドメインの証明書をACMに発行要求します。

      target_domain_name = 'map.mahiguch.com'
      digest = Digest::MD5.new
      digest.update(target_domain_name)
      params = {
        domain_name: target_domain_name, # ドメイン名
        validation_method: 'DNS', # 認証方式。EMAIL, DNSのどちらか
        idempotency_token: digest.hexdigest, # 1時間以内にidempotency_tokenが同じ要求があった場合、1回の要求とみなす。
        options: {
          certificate_transparency_logging_preference: 'ENABLED', # 証明書の透過性ログ。通常はENABLED。
        },
      }
      acm_client = Aws::ACM::Client.new(region: 'ap-northeast-1')
      resp = acm_client.request_certificate(params)
      certificate_arn = resp.certificate_arn

次の画面からこの画面に戻ってくることができる仕様のため、戻るたびに新たな証明書ができることは避けたいと思います。idempotency_tokenにドメイン名を設定することで、これを防ぎます。今回はDNS認証を利用するため、validation_methodにDNSを設定します。これらのパラメータを設定して、request_certificateを呼び出すことで証明書を作成します。レスポンスには、発行した証明書のARNが入っています。

証明書DNS認証

次に証明書のDNS認証を行います。

      acm_client = Aws::ACM::Client.new(region: 'ap-northeast-1')
      resp = acm_client.describe_certificate({certificate_arn: certificate_arn})
      domain_validation = resp.certificate.domain_validation_options[0]
      validation_status =  domain_validation.validation_status # PENDING_VALIDATION, SUCCESS, FAILED のいずれか
      record_name = domain_validation.resource_record&.name || '' # DNS認証で利用するrecord_name。xxxxx.yourdomain.comのようなもの。
      record_type: domain_validation.resource_record&.type || '' # DNS認証で利用するrecord_type。通常はCNAME。
      record_value: domain_validation.resource_record&.value || '' # DNS認証で利用するrecord_value。xxxxx.acm-validations.awsのようなもの

先ほど取得した証明書のARNを使って、describe_certificateで証明書の情報を取得します。レスポンスにDNS認証用のレコードが格納されています。これを画面に表示して、お客様のDNSに設定していただきます。この状態では、validation_statusがPENDING_VALIDATIONとなっています。注意点としては、証明書発行要求してからDNS認証用レコードが生成されるまで数十秒かかることです。生成前の段階では、resource_recordにnilが格納されています。

次の画面では、証明書の状態を確認します。お客様が表示されたDNSレコードを設定し、それをACMが確認したらvalidation_statusがSUCCESSに変わります。

定期的にdescribe_certificateを発行して、validation_statusがSUCCESSになったら次画面へ進むボタンを活性化します。

リスナーへの証明書設定

証明書をELBに紐付けます。

      listener_arn = Settings.official_site.listener_arn  # 対象ELBは決まっているので設定から取得
      elb_client = Aws::ElasticLoadBalancingV2::Client.new(region: 'ap-northeast-1')
      elb_client.add_listener_certificates({
                                             listener_arn: listener_arn,
                                             certificates: [
                                               {
                                                 certificate_arn: certificate_arn, # 証明書発行要求のときに取得したもの
                                               },
                                             ],
                                           })

対象のELB及びリスナーは決まっているので、事前に設定に保存しておきます。add_listener_certificatesを呼び出して、リスナーと証明書を紐付けます。

認証済みの証明書がリスナーに設定されました。同様の要件は存在しそうですが、ネット上で事例は見つけられなかったため、Blogにまとめました。同様の要件に対応されている方、今後同様の要件に対応される可能性のあるRailsやAWSを使ったシステム開発をされている方のお役に立てれば幸いです。

人気記事