👷‍♀️

AWS CLI によるRoute53 / ACMの基礎基本

2023/09/04に公開

最近はTerraformやCDK/CloudFormationなどを用いたIaCによるインフラ構成管理が主流です。しかし、こうしたツールがサポートしない異常事態やインシデントに適切に対処する上では、AWSのインフラを直接操作できる実務上のノウハウとスキルが必要となります。
このシリーズでは、AWS CLIを用いてAWSの各種リソースを操作するための基礎知識とノウハウをおさらいし、読者の学び直しを支援することを目的としています。

Route53

Route53はAWSにおけるマネージド権威DNS。グローバルサービスとして提供されており、耐障害性に優れたコンテンツサーバー(クラスタ)を手頃な価格で利用できる。(正確には、Route53ファミリにはリゾルバを構築するサービスも含まれるが、本稿では触れない。)
AWSでドメイン名を購入した場合は、基本的にRoute53でゾーンを管理することとなる。ちなみに筆者は、外部のレジストラで取得したドメイン名の適当な階層を、Route53のDNSインスタンスに委任(delegate)して使うことが多い。

ゾーン作成

aws route53 create-hosted-zone \
    --name hole.name.tld \
    --caller-reference somedesc

新規にRoute53の権威DNSにゾーンをホストさせる。自動的にSOAとNSが設定される。

[オプション] ゾーンの委任

ドメインの購入元(レジストラ)がAWSでない場合は、上位の権威サーバーからRoute53にゾーンを委任する必要がある。
コマンド実行後、戻り値としてRoute53のDNSのホスト名一覧が返ってくるため、このホスト名を委任元の権威サーバーやWHOISの name server として設定(申請)する。上位の権威DNSからの委任の手順やWHOISへの情報登録についてはレジストラのドキュメントや書籍を参照してほしい。

https://jprs.co.jp/publish/

もちろん、Route53にゾーンを委任した時点で、そのゾーンの名前の信頼性に関わる全てをAWSに依存することとなる。この判断に迷う場合は、Route53を使うべきではない。
また、ゾーンの委任関係がいったん名前解決の対象になると、少なくともコンテンツサーバーのNSレコードやRoute53のSOAのTTL時間にわたって、1つ以上のクライアントから継続的に参照されることになる。(ただし、クライアント端末の参照先リゾルバや経路上のリゾルバを管理できる特殊なケースを除く)。
委任設定のミスは大きなタイムロスを招くだけでなく、他の機関に迷惑をかけたり、場合によっては一時的とはいえゾーンの管理権限を他人に譲り渡す可能性さえある。当然ながら、最新の注意を払って実施すべき操作であると言える。

ゾーン一覧の表示

aws route53 list-hosted-zones

リージョン内の権威DNSとゾーンを一覧にする。

DNSレコードの設定

aws route53 change-resource-record-set \
    --hosted-zone-id /hostedzone/XXXXXXXXXX \
    --change-batch “BATCH_DESC"

設定済みのゾーンにリソースレコードを設定する。
BATCH_DESCは、RRset を操作するためのJSON。
AWS CLIを通じた操作ではリソースの指定にゾーン名を含む必要があったり、ドメイン名末尾のドット(.)の有無が任意となっているなど、一般のゾーンファイルの記法とは指定方法が異なることに注意が必要だ。

BATCH_DESCのJSONの構造は、manページで次のように示されている。

BATCH_DESC syntax
{
  "Comment": "string",
  "Changes": [
    {
      "Action": "CREATE"|"DELETE"|"UPSERT",
      "ResourceRecordSet": {
        "Name": "string",
        "Type": "SOA"|"A"|"TXT"|"NS"|"CNAME"|"MX"|"NAPTR"|"PTR"|"SRV"|"SPF"|"AAAA"|"CAA"|"DS",
        "SetIdentifier": "string",
        "Weight": long,
        "Region": "us-east-1"|"us-east-2"|"us-west-1"|"us-west-2"|"ca-central-1"|"eu-west-1"|"eu-west-2"|"eu-west-3"|"eu-central-1"|"eu-central-2"|"ap-southeast-1"|"ap-southeast-2"|"ap-southeast-3"|"ap-northeast-1"|"ap-northeast-2"|"ap-northeast-3"|"eu-north-1"|"sa-east-1"|"cn-north-1"|"cn-northwest-1"|"ap-east-1"|"me-south-1"|"me-central-1"|"ap-south-1"|"af-south-1"|"eu-south-1",
        "GeoLocation": {
          "ContinentCode": "string",
          "CountryCode": "string",
          "SubdivisionCode": "string"
        },
        "Failover": "PRIMARY"|"SECONDARY",
        "MultiValueAnswer": true|false,
        "TTL": long,
        "ResourceRecords": [
          {
            "Value": "string"
          }
        ],
        "AliasTarget": {
          "HostedZoneId": "string",
          "DNSName": "string",
          "EvaluateTargetHealth": true|false
        },
        "HealthCheckId": "string",
        "TrafficPolicyInstanceId": "string",
        "CidrRoutingConfig": {
          "CollectionId": "string",
          "LocationName": "string"
        }
      }
    }
  ]
}

BATCH_DESC の例
{
  "Comment": "testing",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "ch1b4k8n.okai.example.org.",
        "Type": "CNAME",
        "SetIdentifier": "string",
        "Region": "ap-northeast-1",
        "TTL": 360,
        "ResourceRecords": [
          {
            "Value": "usagi.rieto.tanihara.example.org."
          }
        ]
      }
    }
  ]
}

BATCH_DESCの必須フィールド

Chages内の3つのフィールドは必須。

field name description
Action 変更モードを指定
ResourceRecordSet.(Name|Type|TTL) リソースの名前、レコードタイプ、TTL
ResourceRecordSet.ResourceRecords[] 1つ以上のレコードの値。ラウンドロビン構成など同一名への複数値の設定も可能。

RRset変更モード

リソースレコードの変更モードは3種類ある。

mode description
CREATE 新規にレコードを作成する。同一の名前について同一種別のレコードがある場合には失敗する。
DELETE 設定済みのレコードを削除する。レコードが存在しない場合には失敗する。
UPSERT レコードが存在すれば更新し、レコードが存在しなければ作成する。値エラー以外では失敗しない。

なお、DELETE命令は、BATCH_DESCに指定するリソースレコードの内容が、登録済みのレコードと完全一致していないと、リクエストが失敗する。

Amazon Certificate Manager (ACM)

Amazon Certificate Manager (ACM)はAWSサービスのためのマネージドPKIで、Amazonの管理・運用するPKIを利用してAPI経由でX.509証明書を発行することができる。(グローバルサービスとして提供されている)。
ちなみに、鍵ペアの管理には内部的にKMSを使っているらしいけれど、ここでは触れない。

ACMが発行する証明書には以下2種類のタイプがある。

種別 説明
公開証明書 Amazon Root CA をトラストチェーンの基点とするX.509証明書を発行。CRLsはオンラインで公開され、OCSPで検証可能。
プライベート証明書 プライベートCAによる証明書を発行。証明書およびCRLsはいずれも公開されない。プライベート証明書を発行するためのCAの作成には別サービス(AWS Private CA)の契約が必要。内部独自ドメインむけのサーバー証明書やスタッフ個人の証明書発行に使うことができる

本稿では、公開X.509証明書を発行する際のACMの主要な操作を概観する。

証明書発行要求

ACMは認証局(CA)と鍵発行元の役割を兼ねており、発行した証明書・鍵のペアは、対応するAWSのサービス(ELB, Cloudfront, APIGateway, etc.)で利用できる。具体的には、それぞれのACM証明書をサポートするサービスの新規インスタンス作成時に、証明書ARNを指定すると(その他オプションが必要になる場合もあるが)簡単にTLS終端サービスを実現できる。

一般的な商用証明書の発行手続きのように、openssl等で秘密鍵&CSRを作成・提出する必要はない。ただし、AWS外部で発行した証明書と鍵のセットをAWSで用いる時には、ACM経由でインポートすることも可能だ。
なお、証明書の発行を完了するためには、指定されたDNSリソースレコードを対象ドメインに設定するか、対象ドメインでメールを受信するといった検証を通過する必要がある。具体的な対応手順については次項以降で解説する。

ACMを通じた証明書発行要求の手順は次の通り。

# オリジン名および検証方法を指定して証明書発行を要求
aws acm request-certificate \
    --domain-name your.example.org \
    --validation-method DNS

証明書一覧の表示

# 証明書一覧を表示
aws acm list-certificates

証明書のARN一覧が得られる。

証明書詳細の表示

# ARNを指定して証明書の詳細情報を表示
aws acm describe-certificate --certificate-arn arn:aws:acm:xxxxxxxxxxxxxxxxxxxxxx
[output example] `aws describe-certificate`
{
    "Certificate": {
        "CertificateArn": "arn:aws:acm:ap-northeast-1:xxxxxxxxxxxxx:certificate/934d66c8-650f-4650-a7f0-1ae606fad0fc",
        "DomainName": "t4d0k0r0.okai.example.org",
        "SubjectAlternativeNames": [
            "t4d0k0r0.okai.example.org"
        ],
        "DomainValidationOptions": [
            {
                "DomainName": "t4d0k0r0.okai.example.org",
                "ValidationDomain": "t4d0k0r0.okai.exmaple.org",
                "ValidationStatus": "PENDING_VALIDATION",
                "ResourceRecord": {
                    "Name": "_6e003ed6d60f528c02a9fd472a6d8af9.t4d0k0r0.okai.example.org.",
                    "Type": "CNAME",
                    "Value": "_216b7ca2bc741ea1de89cdf8164ab74e.xmjnffzjyj.acm-validations.aws."
                },
                "ValidationMethod": "DNS"
            }
        ],
        "Subject": "CN=t4d0k0r0.okai.example.org",
        "Issuer": "Amazon",
        "CreatedAt": "2022-12-02T06:44:01.754000+09:00",
        "Status": "PENDING_VALIDATION",
        "KeyAlgorithm": "RSA-2048",
        "SignatureAlgorithm": "SHA256WITHRSA",
        "InUseBy": [],
        "Type": "AMAZON_ISSUED",
        "KeyUsages": [],
        "ExtendedKeyUsages": [],
        "RenewalEligibility": "INELIGIBLE",
        "Options": {
            "CertificateTransparencyLoggingPreference": "ENABLED"
        }
    }
}

検証待ちの証明書は、StatusがPENDING_VALIDATIONとなっていることに注意しよう。
ACMによる検証が終了して証明書の発行が完了すると、StatusフィールドがISSUEDとなる。
手動で証明書発行要求を行った場合は、aws acm list-certificatesaws acm describe-certificateで適宜進捗状況を確認しておくと良い。

証明書発行のためのドメイン名所有権の証明

先に述べた通り、ACMはX.509準拠のCSRファイルの提出を必要としない一方、証明書発行対象のドメイン名の管理権限ないしは所有権を検証する。証明書発行を完了するためには、対象のゾーンを用いて、以下いずれかの作業が必要となる。

  1. 権威サーバーのリソースレコードとして、Route 53 が指定する値を追加する
  2. オリジンドメインのメールアドレスを用いて、Route53からのメールを受信する

DNS検証の場合には、上記DomainValidationOptions配列内のリソースレコード(CNAME)を対象ドメインからacm-validation.awsのサブドメインに向ければ良い。

aws route53 change-resource-record-sets --hosted-zone-id /hostedzone/Z0181958226N1UUPOQCN9 --change-batch '{
  "Comment": "testing",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
      "Name":"_6e003ed6d60f528c0239fd472a6d8af9.t4d0k0r0.okai.example.org.",
        "Type": "CNAME",
        "SetIdentifier": "string",
        "Region": "ap-northeast-1",
        "TTL": 360,
        "ResourceRecords": [
          {
            "Value": "_116b7ca2b9741ea1de89cdf5164ab74e.xmjnffzjyj.acm-validations.aws."
          }
        ]
      }
    }
  ]
}'

証明書の取得

#ARNを指定して証明書を取得する
aws acm get-certificate --certificate-arn arn:aws:acm:xxxxxxxxxxxxxxxxxxxxxxx

プレーンテキストでX.509証明書が取得できる。サーバー証明書だけでなく、複数の中間証明書を含む証明書チェーンが出力されるため、全て確保する。

繰り返しになるが、ACMは公開CAの証明書に対応する秘密鍵のエクスポートができない仕様であるため、ドメイン名に対して発行した証明書の秘密鍵に相当するデータを抽出することはできない。当然、AWS外のシステムで利用する公開証明書をACMで管理することはできない。あくまでもACMは、AWSにおけるTLS対応サービス(RDS, AuroraDB, Elastic Load Balancer, EKS, CloudFront, etc.)のインスタンスのための証明書を管理するためのものだ。
ちなみに、ACMでプライベートCAを構築している場合は、aws acm export-certificateコマンドを用いて秘密鍵とプライベート証明書をセットで出力できるそうだ。

証明書の削除(失効)

ACMで証明書を失効(revoke)すると、同時に証明書のデータが取得できなくなるため、何らかの理由で事後的に証明書が必要になる場合は事前にバックアップを取っておいた方が良い。

ただし、個人的には、revoke済みの証明書を保管しておくメリットは(監査目的を除けば)ないと思う。

# ACM証明書を削除する
aws acm delete-certificate --certificate-arn arn:aws:acm:xxxxxxxxxxxxxxxxxxxx

Ref

Route53

https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/Welcome.html

ACM

https://docs.aws.amazon.com/acm/latest/userguide/acm-overview.html

[屋根裏小人メモ] 不正確な点、間違いなどあればご一報ください。修正します。

Discussion