異なるネットワークにEC2インスタンスをリストアするときの注意点を考えてみた

DRなどで地味はまりするポイントを把握しよう。 取り敢えずルーティング情報を更新しよう。 できるなら、EC2Launch v2をインストールしよう。
2021.04.19

こんにちは、のん です。

皆さんはDR構成をしたことありますか? 私はあります。
DRの構成として、普段使うリージョンと別のリージョンを使ってDR環境を用意することがありますが、意外な落とし穴があったりします。
そんな注意点を私の備忘も兼ねてまとめてみます。

他にもこんな注意点があるよ!! という方がいらっしゃれば、私のTwitterにお知らせください。

最初にまとめ

  • Windows Server 2016 以降のWindows Serverはリストア後、ルーティング情報を更新する
  • IPアドレスはOS内で直接指定するのではなく、DHCPで設定する
  • スタティックルートやhostsファイルを確認して、必要があれば更新する
  • 各種ソフトウェアがライセンス切れなど起こさずに正常に動作するか事前に確認する

詳細については、以降に記載していきます。

構成とポイント

今回は以下のような構成で検証をしました。

ポイントとしては以下になります。

  • 複数のリージョンを利用している
  • AWS Managed Microsoft ADでマルチリージョンレプリケーションをしている
  • 各VPCのCIDRが重複していない
  • us-east-1のEC2インスタンスのAMIを作成して、us-east-2にコピーする
  • us-east-2にコピーしたAMIで、EC2インスタンスをリストアする
  • OS内のネットワーク設定で自身のIPアドレスをDHCPではなく、IPアドレスを直接指定する

AWS Managed Microsoft ADのマルチリージョンについての詳細な説明は、以下をご参考ください。

Windows Server 2016 以降のWindows Serverはリストア後ルーティング情報を更新する

しないと困ること

1. 壁紙に正しい情報が表示されない

us-east-2にリストアしたはずが、以下の画像の通り、壁紙に記載されているAZ情報がリストア前のus-east-1a同じになっています。 その他、インスタンスIDや、IPアドレスといった情報もリストア前の情報を表示しています。

もし、壁紙の情報を元に、ログインしているEC2インスタンスが正しいことを確認する。ということをしていると誤った判断をしてしまいます。

2. OSのライセンス認証が切れている

EC2インスタンスリストア後、slmgr /dlvで現在のライセンス情報を確認すると、以下のように通知モードになり、ライセンス認証を促すメッセージが表示されます。

Windows Server 2012 から Windows Server 2019 のOSでは、サーバの動作に関する機能制限はありませんが、ライセンス認証を求めるメッセージが継続的に表示される場合があります。

エラーコードの説明については、以下の通りです。 要するにライセンス認証が正常にされていない状態になっています。

0xC004F00F ソフトウェア ライセンス サーバーで、ハードウェア ID バインドが許容範囲のレベルを超えていることが報告されました。
考えられる原因
ハードウェアが変更されたか、またはシステムでドライバーが更新されました。
解決方法
MAK ライセンス認証を使用している場合は、OOT の猶予期間中にオンラインまたは電話によるライセンス認証を使用してシステムのライセンス認証を再実行します。
KMS ライセンス認証を使用している場合は、Windows を再起動するか、slmgr.vbs /ato を実行します。

0xC004F00F ソフトウェア ライセンス サーバーで、ハードウェア ID バインドが許容範囲のレベルを超えていることが報告されました。

また、slmgrの詳細な説明は以下公式ドキュメントをご確認ください。

ボリューム ライセンス認証情報を取得するための Slmgr.vbs オプション

3. 時刻同期ができていない

ドメインに参加していないEC2インスタンスはデフォルトで、Amazon Time Sync Service を使って時刻同期をします。
しかし、リストア後、w32 /query /statusで時刻同期の状態を確認すると、時刻同期先がLocal CMOS Clockとなっており、時刻同期ができていないことがわかります。

なお、ドメインに参加しているEC2インスタンスについては、DHCPオプションセットのドメインネームサーバーの設定項目で、AWS Managed Microsoft ADのドメインコントローラーのIPアドレスを指定しておくことで、正常に時刻同期ができます。
DHCPオプションセットを介してDNSの設定をEC2インスタンスに渡すことで、ドメインコントローラーの名前解決ができるため、リストア後にドメインに参加し直すことができ、正常にドメインコントローラーと時刻同期をします。

4. インスタンスメタデータが取得できないため、IAMロールを使った認証情報の受け渡しができない

リストア後、以下のようにインスタンスメタデータを取得しようとしても、エラーが発生します。

> Invoke-RestMethod http://169.254.169.254/latest/meta-data/instance-type

また、インスタンスメタデータにアクセスできないため、SSMのセッションマネージャーを使って接続することも出来ません。SSMセッションマネージャーで接続しようとすると以下のようなエラーを出力します。

> aws ssm start-session --target i-xxxxxxx--document-name AWS-StartPortForwardingSession --parameters portNumber=3389,localPortNumber=13389

An error occurred (TargetNotConnected) when calling the StartSession operation: i-xxxxxxx is not connected.

この理由は、SSMを使用するEC2インスタンスはIAMロールを使って、認証をしているためです。
以下公式ドキュメントの通り、IAMロールはインスタンスメタデータを介して、セキュリティ認証情報の渡します。

インスタンスのアプリケーションは、インスタンスメタデータアイテム iam/security-credentials/role-name のロールから提供されたセキュリティ認証情報を取得します。アプリケーションには、ロールに関連付けられたセキュリティ認証情報によって、ロールに対して定義したアクションおよびリソースのアクセス許可が付与されます。これらのセキュリティ認証情報は一時的なものであり、私たちが自動的に循環させます。新しい認証情報は、古い認証情報が失効する少なくとも 5 分前から有効になるようにします。

Amazon EC2 の IAM ロール- インスタンスメタデータからのセキュリティ認証情報の取得

そのため、インスタンスメタデータにアクセスできない場合、IAMロールでEC2インスタンスに認証情報を渡すことができないため、EC2インスタンスからSSMやS3、CloudWatchなどのAWSのリソースにアクセスすることができなくなります。

原因

以下ブログにも記載ありますが、ルーティング情報が古い状態になっているのが原因です。

EC2インスタンスでは169.254.169.123や、169.254.169.250などのリンクローカルアドレスに対するスタティックルートが追加されています。 これは、Windows Server 2016以降のWindows OSのAMIにデフォルトでインストールされている、EC2Launchがインスタンスの作成時に追加したルートになります。 リストア後にroute printコマンドでルート情報を確認すると、そのルート情報が確認できます。

EC2Launchによるルートの追加は、通常、インスタンスの作成時にしか行われません。そのため今回の場合は、最初にインスタンスを作成した、us-east-1の時のルーティング情報が残ったままになっています。

しないと困ることにリストアップした事象は全て、この追加されたルーティング情報を使用してデータを取得します。 追加されたルーティング情報は以下のように使用されます。

  • AmazonProvidedDNS: 169.254.169.253
  • インスタンスメタデータ: 169.254.169.254
  • KMS(AWS KMSではなくWindowsのKey Management Service): 169.254.169.250 / 169.254.169.251
  • Amazon Time Sync Service: 169.254.169.123

なお、上述のブログにも記載されていますが、本事象はWindows Server 2016にEC2Launch v1がインストールされているためです。 EC2Launch v1がインストールされていないEC2インスタンスでは発生しません。 そのため、以下の状態のEC2インスタンスはルーティング情報の更新は不要です。

  • EC2Configがインストールされている(一般的にはWindows Server 2012 R2以前)
  • EC2Launch v2がインストールされている

EC2Launch v2についての詳細は以下ブログをご覧ください。

また、Amazon Linux2でも確認してみましたが、Windowsのようなリンクローカルアドレスへのスタティックルートは追加されていませんでした。

解決策

古いルーティング情報が残っていることが原因なので、ルーティング情報を更新します。 更新する際は、Powershellを管理者権限で起動して、以下のコマンドを実行します。

// EC2Launchのモジュールをインポート
> Import-Module C:\ProgramData\Amazon\EC2-Windows\Launch\Module\Ec2Launch.psd1

// ルーティング情報の更新
> Add-Routes

再度、ルーティング情報を確認してみると、ルーティング情報が更新されていることが確認できます。

壁紙の更新

ルーティング情報を更新した後、Powershellを管理者権限で起動して、以下のコマンドを実行します。

// ルーティング情報を更新したプロンプト上で実行する場合は、Import-Moduleは不要
> Import-Module C:\ProgramData\Amazon\EC2-Windows\Launch\Module\Ec2Launch.psd1

// 壁紙の更新
> Set-Wallpaper

壁紙を確認してみると、以下の通りインスタンスIDやAZ情報が更新されていることが確認できます。

OSのライセンス認証

ルーティング情報を更新した後、コマンドプロンプトを管理者権限で起動して、以下のコマンドを実行します。

// ライセンス認証
> slmgr /ato

// ライセンス認証されたことを確認
> slmgr /dlv

時刻同期

ルーティング情報を更新した後、コマンドプロンプトを管理者権限で起動して、以下のコマンドを実行します。 以下の例では、Amazon Time Sync Serviceと時刻同期できていることが確認できます。

// 時刻同期を実行
> w32tm /resync /rediscover

// 時刻同期の状態を確認
> w32tm /query /status

メタデータの取得確認

ルーティング情報を更新した後はインスタンスメタデータも以下の通り、取得できます。

IPアドレスはOS内で直接指定するのではなく、DHCPで設定する

しないと困ること

リストア後にEC2インスタンスに接続できません。

Windowsの場合は、以下の通りRDP接続ができませんでした。

また、インスタンスのステータスチェックにも失敗します。

Linuxの場合は、SSHで接続ができます。しかし、systemctl restart networkを実行した後、再度SSHで接続をしようとすると接続に失敗します。

原因

OSとEC2インスタンスが認識しているIPアドレスが異なるためです。 OS内ではネットワークアダプターにus-east-1のCIDRのIPアドレスを割り当てていますが、AWS側からはus-east-2のCIDRのIPアドレスを割り当てています。 そのため、接続に不整合が発生し、インスタンスに接続できなくなっています。

Linuxについては、以下のようにネットワークサービスの再起動をしてから、IPアドレスが変わったところを見ると、 EC2インスタンス作成時の最初の起動はOS内の設定を無視して、DHCPでIPを取得するようです。

> ifconfig -a
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9001
        inet 10.1.0.122  netmask 255.255.255.0  broadcast 10.1.0.255
        inet6 fe80::e0:d0ff:febf:3f6c  prefixlen 64  scopeid 0x20<link>
        ether 02:e0:d0:bf:3f:6c  txqueuelen 1000  (Ethernet)
        RX packets 39709  bytes 56376560 (53.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 5878  bytes 355231 (346.9 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
> systemctl restart network
[  159.198180] ena 0000:00:05.0 eth0: Local page cache is disabled for less than 16 channels
[  159.202983] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
[  159.900814] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
> ifconfig -a
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9001
        inet 10.0.0.16  netmask 255.255.255.0  broadcast 10.0.0.255
        inet6 fe80::e0:d0ff:febf:3f6c  prefixlen 64  scopeid 0x20<link>
        ether 02:e0:d0:bf:3f:6c  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 21  bytes 1662 (1.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

試しにリストア完了後、再起動をすると上述と同様に、IPアドレスが10.0.0.16となりました。 そのため、2回目以降の起動はOS内のネットワークの設定が読み込まれているようです。

解決策

以下のいずれかの方法でDHCPに変更します。

1. シリアルコンソール接続をして、ネットワークの設定を変更する

シリアルコンソールが使えるEC2インスタンス、Windowsの場合は加えてEMSがインストールされていると、シリアルコンソールを使うとリカバリが早いです。

シリアルコンソールログインで接続した後は、cmdもしくはbashでネットワークの設定を修正します。

EMSについての説明および、シリアルコンソールの接続方法は以下の記事をご覧ください。

Windowsの場合は、シリアルコンソールで以下コマンドを実行します。

// ネットワークの構成確認
> netsh interface ip show config

// DHCPに変更
> netsh interface ip set address "<ネットワークアダプター名>" dhcp

// DHCPに変更されているか確認
> netsh interface ip show config

Amazon Linux2の場合は、シリアルコンソールで以下コマンドを実行します。

// ネットワークの設定ファイルを修正し、DHCPに変更する。
> cat << EOT > /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
TYPE=Ethernet
USERCTL=yes
PEERDNS=yes
DHCPV6C=yes
DHCPV6C_OPTIONS=-nw
PERSISTENT_DHCLIENT=yes
RES_OPTIONS="timeout:2 attempts:5"
DHCP_ARP_CHECK=no
EOT

// ネットワークサービスの再起動
> systemctl restart network

// ネットワーク情報の確認
> ifconfig -a

2. トラブルシュート用にENIをアタッチして、割り振られたIPアドレス経由でネットワークの設定を変更する

以下の場合のようにシリアルコンソールが使用できない場合は、トラブルシュート用にENIを作成して、そのENI経由で設定変更を行います。

  • Nitroシステムのインスタンスタイプではない
  • シリアルコンソール接続がIAMポリシーで許可されていない
  • rootのパスワードを設定していない(Linuxの場合)
  • EMSをインストールしていない(Windowsの場合)

手順は以下の通りです。

  1. トラブルシュート用にENIを作成する

  2. トラブルシュート用のENIをリストアしたEC2インスタンスにアタッチする

  3. トラブルシュート用の作成したENIに割り当てられているIPアドレスを使用して、EC2インスタンスに接続する

  4. 問題のネットワーク設定を修正する
  5. トラブルシュート用のENIをデタッチし、削除する
  6. 本来のENIに割り当てられているIPアドレスを使用して、EC2インスタンスに接続できることを確認する

3. インスタンスタイプを変更する

インスタンスタイプを変更すると、ネットワークアダプタが変更されることがあります。その際、ネットワークアダプタの設定がリセットされ、DHCPに設定されます。

これを実行すると、DNSの設定についてもリセットされます。
そのため、AmazonProvidedDNS以外のDNSサーバを指定する場合は、必ずDHCPオプションセットで指定するようにしてください。

しかし、インスタンスタイプ(特にインスタンスのファミリー)を変更する場合はネットワーク以外の変更も大きくあるため、実行は慎重に行う必要があります。

関連ブログは以下をご確認ください。

スタティックルートやhostsファイルを確認して、必要があれば更新する

しないと困ること

異なるネットワークにリストアした影響で、通信ができなくなる可能性があります。

解決策

スタティックルートおよび、hostsファイルを更新します。 事前にリストア時の手順にどのEC2インスタンスのスタティックルート、hostsファイルを更新しなければならないのかを整理しておくと、漏れなく対応できるかと思います。

各種ソフトウェアがライセンス切れなど起こさずに正常に動作するか事前に確認する

しないと困ること

インストールされているソフトウェアが正しく動作しない可能性があります。

ソフトウェアの中にはMACアドレスを使って、ライセンス認証をしているものがあります。
異なるネットワークにリストアすると、同じENIを使うことはできないので、必然的にMACアドレスも違う物が割り振られることになります。

その結果、ミドルウェアがライセンス切れになり、DRでいざリストアという時に動作しない可能性があります。

解決策

該当EC2インスタンスをDR対象に含める際に、インストールされているソフトウェアがMACアドレスが変わっても問題ないか確認する必要があります。 もし、MACアドレスでライセンス認証をしている場合でも、新しいMACアドレスで再度認証をすれば良いパターンもありますので、開発元に確認をすると良いかと思います。

何事も事前にしっかりテストをしよう

何も準備をせずに、いきなり実行しても思わぬトラップがあったりするものです。何事も事前の準備が必要だなと改めて感じました。

DR全体の注意点について補足すると、以下のようなものもあるかなと思います。

  • DR発生時にはDNSのレコード情報を書き換える
  • DR発生時に直ぐにDR環境にアクセスしてもらえるように、DNSキャッシュのTTLを短くする
  • RPOを満たすことができるように定期的にバックアップを取得、転送する

また、今回記載した内容はDR時に限らず、検証環境VPCのEC2インスタンスのAMIを取得して、本番環境のVPCで展開するといった時にも関係あります。

みなさんが私と同様のつまずきをしたときの助けになれば嬉しいです。