メインコンテンツへスキップ
kt-tech.blog

【AWS】Lambdaを用いて、Route53にAレコードを登録する

技術6分で読めます

この記事でわかること

  • Lambda から Route 53 に A レコードを登録する実装コード(AWS SDK v3)
  • 必要な IAM 権限と、本番ではどこまで絞れるか
  • API Gateway 経由だと event.body が文字列になって踏む落とし穴
  • 入力を検証せずにレコード名にする危うさ

Route 53 でドメイン(ホストゾーン)を取得済みであること。AWS コンソールに入れて、Lambda 関数と IAM ロールを作成できる権限があれば十分です。

概要

今回は、「Lambda を用いて、Route 53 に A レコードを登録する」というテーマで記事を書いてみました。

ポイント

取得済みのドメインに対して、IP アドレスを元にした A レコードを動的に登録していきます。用途としては IP アドレスを固定にできないときなどです。

(例)127-0-0-1.example.com / 127-0-0-2.example.com

導入手順

Lambda を作成する

あまり経験がない方は Lambda の入門(公式ドキュメント) を参照いただけると良いと思います。

注意
下のコードは require を使った CommonJS 形式なので、ファイル名を index.mjs から index.js に変更してください(コンソールの既定は index.mjs = ESM です)。.mjs のまま行くなら、requireimport { Route53Client, ChangeResourceRecordSetsCommand } from "@aws-sdk/client-route-53"; に、exports.handlerexport const handler に書き換えてください。

Role について

Lambda にアタッチする Role には AmazonRoute53FullAccess のポリシーを付与しておいてください。付与されていないと A レコードを作成する権限がなく、エラーになります。

Tips
AmazonRoute53FullAccess全ホストゾーンを好きにいじれる権限です。手元で試す分には楽ですが、本番では対象のホストゾーンに絞ったインラインポリシーにしてください。必要なのは route53:ChangeResourceRecordSets だけで、Resource を arn:aws:route53:::hostedzone/対象ID に限定できます。

Lambda の処理

JavaScript
const { Route53Client, ChangeResourceRecordSetsCommand } = require("@aws-sdk/client-route-53"); 

exports.handler = async function (event, context) {
    // Route53への接続
    const route53 = new Route53Client();

    // 変更を行うドメイン名とhostedzone IDを入力
    const hostedZoneId = '********';
    const recordName = 'example.com';
    
    // IPアドレスを取得
    const newIpAddress = event.body.address;

    //レコード名を作成('.'->'\u2019へ正規化した上で結合)
    const newRecordName=newIpAddress.replace(/\./g, '-')+'.'+recordName

    // Aレコードの変更リクエストを作成
    const changeBatch = {
        Changes: [
            {
                Action: 'UPSERT',
                ResourceRecordSet: {
                    Name: newRecordName,
                    Type: 'A',
                    TTL: 300,
                    ResourceRecords: [
                        { Value: newIpAddress }
                    ]
                }
            }
        ]
    };
    
    // レコードの変更を実行
    try {
        const command = new ChangeResourceRecordSetsCommand({
            HostedZoneId: hostedZoneId,
            ChangeBatch: changeBatch
        });

        const response = await route53.send(command);

        console.log(response);
        
        return {
            statusCode: 200,
            body: JSON.stringify(response)
        };
    } catch (error) {
        console.error(error);
        
        return {
            statusCode: 500,
            body: JSON.stringify(error.message)
        };
    }
};

test を実行する

送られてきた IP アドレスの .- に変換した文字列をドメインの頭につける形で、A レコードを登録します。次の JSON でテストを行います。

JSON
{
  "body": {
    "address": "127.0.0.1"
  }
}
注意
このコードはテストイベントを前提にしています。コンソールのテストでは event.body がオブジェクトのまま届くので event.body.address で取れますが、API Gateway 経由で呼ぶと event.body は文字列になり、undefined になります。実運用では const { address } = JSON.parse(event.body) のようにパースしてください。
重要
入力をそのままレコード名にしないこと。上のコードは受け取った文字列を検証せずに DNS レコード名にしています。外部から叩けるエンドポイントにするなら、IP アドレスの形式かどうかを先に検査してください(例: /^\d{1,3}(\.\d{1,3}){3}$/ で弾く)。そうしないと意図しないサブドメインを自由に作られます。

実行結果の確認

Route 53 で自分が選択したホストゾーン(example.com)に A レコードが登録されていたら OK です。

参考リンク

おわりに

今回の記事では、Lambda で Route 53 に A レコードを登録してみたい時に、Lambda にどんな処理を書けばいいのか記述をしました。

今回の内容を応用すれば、IPアドレスの変更等を検知した場合や、EC2の起動を検知した場合などに、Aレコードを新しく登録もしくは更新するなどもできると思います。

更新履歴

  1. タイトルと本文の誤記を修正(Lamda→Lambda、exaple.com→example.com)。見出しの番号を削除し、導入手順の下に各ステップを入れ子にする形に修正。コード内の壊れていたコメントを修正。API Gateway 経由だと event.body が文字列になる件、入力を検証せずにレコード名にしている件、最小権限の IAM ポリシー、ESM/CommonJS の違いを補足。引用ブロックを callout に変更し、裸 URL をタイトル付きリンクに変更。
  2. 記事内リンクと OGP Description の修正

この記事のタグ