EC2起動時にRoute53のレコードを更新させる仕組みのメモ

# EC2起動時にRoute53のレコードを更新させたい
ElasticIPを設定しておけばいいと思われるがIPv4アドレスに課金する動きがあったりして、ElasticIPだけでは不安になってくるのでRoute53を毎回更新しておけばいろいろと都合が良さそうなので。
今回はRockyLinux9で設定。

## インスタンスにはあらかじめIAMロールを設定しておく
**route53:ChangeResourceRecordSets** が付与されていれば良いと思われるが適時調整要。

## バッチファイルを作成して配置
:::note warn
SELinuxの関係で/usr/libexecに配置して実行権限を付与。
```chmod +x /usr/libexec/update-route53.sh```
:::

## 作成したバッチファイル
```
#!/bin/bash

set -euo pipefail

#インスタンスメタデータからIPアドレスを取得
ipv4=`/bin/curl -s http://169.254.169.254/latest/meta-data/public-ipv4/`
ipv6=`/bin/curl -s http://169.254.169.254/latest/meta-data/ipv6/`

#ZONEIDはあらかじめ設定
zoneid=

#ホスト名を自動取得できない場合は設定を行う
#hostname=`hostname`
hostname=<ホスト名をFQDNで>

#インストールしたAWS-Cliのフルパスを設定しておく
awscli=/usr/local/bin/aws

# JSON をスクリプト内に直接埋め込み
cat <<EOF > /tmp/ipv4upsert.json
{
  "Comment": "Update A record",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "${hostname}.",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "${ipv4}"
          }
        ]
      }
    }
  ]
}
EOF

cat <<EOF > /tmp/ipv6upsert.json
{
  "Comment": "Update AAAA record",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "${hostname}.",
        "Type": "AAAA",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "${ipv6}"
          }
        ]
      }
    }
  ]
}
EOF

#更新実行
${awscli} route53 change-resource-record-sets --hosted-zone-id ${zoneid} --change-batch file:///tmp/ipv4upsert.json
${awscli} route53 change-resource-record-sets --hosted-zone-id ${zoneid} --change-batch file:///tmp/ipv6upsert.json

while true; do
        ipv4result=$(dig +short @8.8.8.8 "${hostname}" A)
        /bin/logger "Route53:更新 期待値: ${ipv4}, dig結果: ${ipv4result}"
        if [ "$ipv4" = "$ipv4result" ]; then
                logger "Route53:更新 IPv4の更新完了"
                break
        fi
        /bin/logger "Route53:更新 IPv4の更新未完了のため5秒待機します"
        sleep 5
done

while true; do
        ipv6result=$(dig +short @8.8.8.8 "${hostname}" AAAA)
        /bin/logger "Route53:更新 期待値: ${ipv6}, dig結果: ${ipv6result}"
        if [ "$ipv6" = "$ipv6result" ]; then
                /bin/logger "Route53:更新 IPv6の更新完了"
                break
        fi
        /bin/logger "Route53:更新 IPv6の更新未完了のため5秒待機します"
        sleep 5
done

#後始末
rm -f /tmp/ipv4upsert.json
rm -f /tmp/ipv6upsert.json
```

## systemdで使用するユニットファイルを作成する
```vi /etc/systemd/system/route53-update.service```

```
[Unit]
Description=Update Route53 A/AAAA Records with Instance IPs
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/libexec/update-route53.sh
TimeoutStartSec=180

[Install]
WantedBy=multi-user.target
```

## ユニットファイルを取り込んで実行設定
```
systemctl daemon-reexec
systemctl daemon-reload
systemctl enable route53-update.service
```

## バッチファイルの解説
systemdで実行することを意図しているため、ログはsyslogなどに流す。(loggerコマンドを使用）

:::note info
## IPアドレスはインスタンスメタデータから取得できる
```
# IPv4アドレス
/bin/curl -s http://169.254.169.254/latest/meta-data/public-ipv4/
# IPv6アドレス
/bin/curl -s http://169.254.169.254/latest/meta-data/ipv6/
```
:::

:::note info
AWS-Cliは以下のようにインストールする
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html
```
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
```
:::

:::note info
Route53の更新には多少の時間を要するため、更新されたことを確認できるまで次に進ませない。
```
while true; do
        ipv4result=$(dig +short @8.8.8.8 "${hostname}" A)
        /bin/logger "Route53:更新 期待値: ${ipv4}, dig結果: ${ipv4result}"
        if [ "$ipv4" = "$ipv4result" ]; then
                logger "Route53:更新 IPv4の更新完了"
                break
        fi
        /bin/logger "Route53:更新 IPv4の更新未完了のため5秒待機します"
        sleep 5
done

while true; do
        ipv6result=$(dig +short @8.8.8.8 "${hostname}" AAAA)
        /bin/logger "Route53:更新 期待値: ${ipv6}, dig結果: ${ipv6result}"
        if [ "$ipv6" = "$ipv6result" ]; then
                /bin/logger "Route53:更新 IPv6の更新完了"
                break
        fi
        /bin/logger "Route53:更新 IPv6の更新未完了のため5秒待機します"
        sleep 5
done
```