DKIMの公開鍵がRoute 53に長すぎると言われたときの対処法


KaiMailでドメインのDKIMを設定していたときのことだ。ダッシュボードからDKIM公開鍵をコピーし、AWS Route 53のコンソールにTXTレコードとして貼り付け、保存をクリックしたたら、赤い大きなエラーバナーが表示されてしまった。

AWS DNS Error: Value Too Long

AWS DNS Error: Value Too Long

CharacterStringTooLong (Value is too long)

エラーメッセージにはDKIMの値がそのまま表示されていて、まるで嘲笑されているようだった。Route 53は保存も拒否。親切な提案も「もしかして...」というプロンプトもない。ただの拒否である。

同じ経験をしたことがあるなら、あなただけではない。これはDKIMに関するDNSの最もよくある落とし穴の1つで、原因さえわかれば修正は簡単だ。

なぜこうなるのか

Route 53が意地悪しているわけではない。DNS TXTレコードの仕様自体の制限である。

1つのTXTレコード文字列の最大長は255文字だ(RFC 7208による)。この制限は数十年前には合理的だったが、現代のDKIM公開鍵(特に現在標準となっている2048ビットRSA鍵)は簡単にこれを超えてしまう。典型的な2048ビットDKIM鍵のTXT値は約400〜500文字になる。鍵自体に問題はない。DNSが1つの塊では運べないだけだ。

Route 53はこの255文字制限を厳密に適用するため、DKIM値を貼り付けた瞬間にCharacterStringTooLongが発生する。

修正方法: ダブルクォートで分割する

DNS仕様はこの問題を想定していた。1つのTXTレコードに複数の文字列を含めることができ、受信側のDNSリゾルバが自動的に結合して1つの値に戻してくれる。長い値を255文字以下のチャンクに分割し、それぞれをダブルクォートで囲み、スペースで区切るだけでいい。

実際にはこうなる。DKIMの値が以下のようだとする:

"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr09HrXma8mAdtjJg5KbAI8SNr9KMxrYYFF3T+GV19adopztPvSJvcRwwejcKwf3WUc1Fk4g+6e0prUePDtEJtG5OF6e03/7OWecfzhwup3FJ3s25+qHJ22+FMcv3OZOuxJp5uEWzAgQnQOKHRkDqwtmiaTOzxKY177Ui5+1CKQEyg2S+2K/Ao1906Ow018CjL+4KDU7IFiEaM3yq9yQl9iIZ3Ix1ZNygHP0Q5qJxj3wVyrb9lfzkpAVPDQQFWLRRDmAx02IA4TF2A9tCc8KTqlkEa1Ne/YQZZiRlzEq88VaS3R6eThSFU+j+sykblcc45ick08MXbgfS16IsrgC+9wIDAQAB"

255文字を大幅に超えている。これを複数のクォート文字列に分割する:

"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr09HrXma" "8mAdtjJg5KbAI8SNr9KMxrYYFF3T+GV19adopztPvSJvcRwwejcKwf3WUc1Fk4" "g+6e0prUePDtEJtG5OF6e03/7OWecfzhwup3FJ3s25+qHJ22+FMcv3OZOuxJp5" "uEWzAgQnQOKHRkDqwtmiaTOzxKY177Ui5+1CKQEyg2S+2K/Ao1906Ow018CjL+4KDU7IFiEaM3yq9yQl9iIZ3I" "x1ZNygHP0Q5qJxj3wVyrb9lfzkpAVPDQQFWLRRDmAx02IA4TF2A9tCc8KTqlkEa1Ne" "/YQZZiRlzEq88VaS3R6eThSFU+j+sykblcc45ick08MXbgfS16IsrgC+9wIDAQAB"

各チャンクが255文字以下で、それぞれダブルクォートで囲まれ、スペースで区切られている。これだけだ。Route 53のTXTレコード値フィールドに貼り付ければ、問題なく保存される。

スペースで区切る、改行ではないことが重要

Route 53コンソールでよくある間違いがある。複数のクォート文字列に分割したとき、同一行でスペースで区切る必要がある。改行ではない。

各クォートチャンクを別々の行に配置すると、Route 53はそれぞれを1つのレコードの一部ではなく、別々のTXTレコードとして解釈してしまう。複数の文字列セグメントを持つ1つのDKIMレコードではなく、4つか5つの独立したTXTレコードになってしまい、どれも完全な鍵を含んでいないためDKIM検証が失敗する。

Classmethod開発者ブログの詳細な解説がこの落とし穴を具体的に説明しているので、技術的な詳細を知りたい方は参照してほしい。

Route 53コンソールでの手順

  1. ホストゾーンに移動し、レコードを作成をクリックする。
  2. レコードタイプをTXTに設定する。
  3. レコード名に、メールサービスが提供するDKIMセレクタ(例: kaimail._domainkey)を入力する。
  4. 値フィールドに、複数のクォート文字列に分割したDKIM値を1行で、スペース区切りで貼り付ける。
  5. レコードを作成をクリックする。

AWS CLIを使う場合は:

aws route53 change-resource-record-sets --hosted-zone-id YOUR_ZONE_ID --change-batch '{
  "Changes": [{
    "Action": "UPSERT",
    "ResourceRecordSet": {
      "Name": "kaimail._domainkey.yourdomain.com",
      "Type": "TXT",
      "TTL": 3600,
      "ResourceRecords": [{
        "Value": "\"v=DKIM1; k=rsa; p=FIRST_CHUNK\" \"SECOND_CHUNK\" \"THIRD_CHUNK\""
      }]
    }
  }]
}'

正しく設定できたか確認する方法

レコードを保存したら、DNSリゾルバが完全な結合済み値を返すか確認する:

dig TXT kaimail._domainkey.yourdomain.com +short

完全なDKIM値が返されるはずだ。複数のクォートセグメントとして表示されることもあるが、それは正常である。受信メールサーバーは署名検証時に自動的に結合する。

MXToolboxなどのオンラインツールでDKIMレコードを確認することもできる。kaimail._domainkey:yourdomain.comと入力すれば、鍵が正しく公開されているか表示される。

Route 53固有の問題ではない

補足しておくと、これはAWSの問題ではない。255文字制限はすべてのDNSプロバイダーに適用される。一部のプロバイダー(Cloudflareなど)は裏側で自動的に分割を処理してくれるため、これまで遭遇しなかったかもしれない。Route 53はそうした処理をしない。分割は自分で行う必要がある。より透明ではあるが、より厳格でもある。

Andrew RayのRoute 53でカスタムドメインを設定するブログ記事は、私がこの問題を明確に説明しているものとして最初に見つけた記事の1つだ。AWSのナレッジベース記事も解決方法を説明している。

クイックリファレンス

項目 詳細
エラー CharacterStringTooLong (Value is too long)
原因 1つのTXT文字列が255文字を超えている
修正 複数のクォート文字列に分割(各255文字以下)
区切り クォートチャンク間はスペース(改行ではない)
確認 dig TXT selector._domainkey.yourdomain.com +short

KaiMailのDKIMを設定する場合は、ダッシュボードに完全な公開鍵が表示される。上記のように分割してからRoute 53に貼り付ければ完了だ。