EC2インスタンスのプライベートIP固定化でつまづいた話と成功した話

# きっかけ
ある学習のために立てた2台のEC2インスタンスを見て
なぜかふと
**「なんとなくこの2台のプライベートIPは並びの数字にしたいなぁ」**
と思い、軽い気持ちでIPアドレスの固定化に足を踏み入れてみたら
これが**想定外に沼**だったのでその顛末について残してみます。

### ■2台のインスタンスとその構成
上述の2台のインスタンスは
**　① Windows Server 2012 R2**
**　② Amazon Linux 2**
で、構成は以下です。
![StaticIP_VPC.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1041476/c88124bc-a716-5e17-919f-a63f1f980ea1.png)
セキュリティグループではRDP(3389)とSSH(22)を自宅回線のグローバルIPのみで許可しています。

今回は、GUI操作もでき、より馴染みのあるWindows Server 2012 R2のほうをAmazon Linux 2のアドレス側に寄せることにしました。
※文章表現の便宜上、以後①をWindows、②をLinuxと表記します。

# IPアドレスの変更を適用したところで、リモートデスクトップが切断
事前にipconfigコマンドの結果から、サブネットマスク、デフォルトゲートウェイ、DNSサーバーなど基本的な情報を控えておきます。
*（↓今回の話に不要な行は割愛しています）*
<pre>
イーサネット アダプター イーサネット:
   物理アドレス. . . . . . . . . . . . .: 06-FE-DC-57-87-30
   DHCP 有効 . . . . . . . . . . . . . .: はい
   自動構成有効. . . . . . . . . . . . .: はい
   IPv4 アドレス . . . . . . . . . . . .: 10.0.0.133(優先) 
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .: 10.0.0.1
   DNS サーバー. . . . . . . . . . . . .: 10.0.0.2
</pre>

このIPアドレスを、Linuxと並びになる10.0.0.51に変更します。
![netconnections_properties.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1041476/2d8ffa43-ab33-c1a0-583b-2fb07618a252.png)
上記のようにIPv4アドレスを10.0.0.51に指定、その他情報にも先程控えたものを正しく入力し[OK]をクリックしたところで
リモートデスクトップ接続が途切れてしまい、その後何度試しても再度接続することはできませんでした。
# なぜリモートデスクトップ接続が途切れてしまったのかを考える。
変えたのはあくまでVPC内のプライベートIPで、RDP接続の際に指定するパブリックIPはいじっていない。
VPC・サブネットのCIDRからも外れていないから、インターネットゲートウェイから受け取ったRDP通信が正しく通ることになっているだろう。
ネットワーク的には問題ない"はず"なのに、なぜ接続ができなくなったのか。考えてみます。

### ■分析①：どの通信が不可なのかを確認
まず、RDP接続だけ問題が起きたのか、あるいはその他の通信も不可になったのかを確認するため
シンプルにLinux側からWindows側にpingを飛ばしてみたところ、やはりレスポンスは返って来ません。
<pre>
[ec2-user@ip-10-0-0-50 ~]$ ping 10.0.0.51
PING 10.0.0.51 (10.0.0.51) 56(84) bytes of data.
From 10.0.0.50 icmp_seq=1 Destination Host Unreachable
From 10.0.0.50 icmp_seq=2 Destination Host Unreachable
From 10.0.0.50 icmp_seq=3 Destination Host Unreachable
</pre>
「やっぱり全通信が死んでるのかぁ」と私は思いました。
*（・・・あとで分かることだが、これは半分正解で半分間違いだった）*

### ■分析②：あたらしいインスタンスを立て、正常な状態を確認
#### pingを打つ
RDPも正常に接続できる状態を作るため、あらためて別のインスタンスでWindows Serverを立ててみました。
（この別のインスタンスのIPアドレスには10.0.0.240が振られています）
そしてLinux側から疎通がとれるか、シンプルにpingを飛ばしてみます。
・・・すると、なぜかここでもpingが通りませんでした。

セキュリティグループの設定がおかしいのか？
ただ、「pingにはポート番号という概念がない」的なことを昔なんとなく聞いたことがあったので
いつか見たサイトを探して見直してみたところ、
たしかにそう書いてあったのですが 私は重要な概念を抜かしていたことにここで気づきます。
> *実は、pingにはポートという概念がありません。*
> *pingには、icmpというプロトコル名がついているだけで、ポートは無いのです。*

> 引用元「pingのポート番号ってあるの？ファイアウォールで禁止できるのか？」
> https://searchman.info/tips/2000.html

pingはICMP(*Internet Control Message Protocol, インターネット制御通知プロトコル*)という**【プロトコル】**による通信だということ。

そしてAWS公式ドキュメントも念のため確認してみると、以下のような記述を見つけました。
> *インスタンスに ping を実行するには、次のインバウンド ICMP ルールを追加する必要があります。*
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/security-group-rules-reference.html#sg-rules-ping

つまりセキュリティグループにて、**「ICMP」**のインバウンド通信の許可が必要とのこと。
（セキュリティグループが「ホワイトリスト方式」であることを考えると、当然といえば当然である）

プロトコルとポートをごっちゃにしていた雑な自分に軽く落ち込みつつ、
セキュリティグループにVPCのCIDRである10.0.0.0/21からのICMPを通すルールを追加したところで
無事、pingが通るようになりました。
想定外の寄り道でしたが、1個大事な知識の再認識ができたのはよかったです。

#### arpテーブルを確認する
先にWindowsのコマンドプロンプトにて対象NICのMACアドレスを出し、控えておきます。
*※ここでも説明に不要な行は割愛。*
<pre>
イーサネット アダプター イーサネット:
   物理アドレス. . . . . . . . . . . . .: 06-20-BA-DF-20-AA
   DHCP 有効 . . . . . . . . . . . . . .: はい
   自動構成有効. . . . . . . . . . . . .: はい
   IPv4 アドレス . . . . . . . . . . . .: 10.0.0.240(優先) 
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .: 10.0.0.1
   DNS サーバー. . . . . . . . . . . . .: 10.0.0.2
</pre>
つぎにLinux側でarpコマンドを打つと、WindowsのNICのMACアドレスとIPアドレスが現れるので、
正常にarpの紐付けも取れているということが確認できます。
<pre>
[ec2-user@ip-10-0-0-50 ~]$ arp
Address                  HWtype  HWaddress           Flags Mask            Iface
gateway                  ether   06:14:58:45:01:72   C                     eth0
10.0.0.2                 ether   06:14:58:45:01:72   C                     eth0
10.0.0.240               ether   06:20:ba:df:20:aa   C                     eth0
</pre>



### ■分析③：固定IP化によって通信断絶する現象を再現
ここでようやくIP設定を固定アドレスに変え、現象を再現させてみます。
序盤に登場したWindows Serverに当てているものとは別のアドレス(10.0.0.151)を設定。
すると、序盤の展開と同じようにリモートデスクトップ接続が終了し、その後再び接続できることはありませんでした。

LinuxへのSSH接続は生きているので、新しく割り当てたIPアドレス(10.0.0.151)にpingを打ってみます。
結果、Destination Host Unreachableとなり、疎通が取れなくなっていることがわかります。
<pre>
[ec2-user@ip-10-0-0-50 ~]$ ping 10.0.0.151
PING 10.0.0.151 (10.0.0.151) 56(84) bytes of data.
From 10.0.0.50 icmp_seq=1 Destination Host Unreachable
From 10.0.0.50 icmp_seq=2 Destination Host Unreachable
From 10.0.0.50 icmp_seq=3 Destination Host Unreachable
</pre>
ちなみに、変更前のIPアドレス(10.0.0.240)でも同じ結果でした。

次にLinux側でarpを打って確認してみると、Windowsのarp情報が消えていました。
<pre>
[ec2-user@ip-10-0-0-50 ~]$ arp
Address                  HWtype  HWaddress           Flags Mask            Iface
gateway                  ether   06:14:58:45:01:72   C                     eth0
10.0.0.2                 ether   06:14:58:45:01:72   C                     eth0
</pre>

つまりリモートデスクトップ接続だけができないとかではなく、ネットワーク上からこのWindowsは消失してしまったのです。

なぜ？？

# 原因は「EC2インスタンスそのものとゲストOS内のIPアドレス設定の乖離」
インスタンスが何らかの原因で停止してしまっていないかを確認するために
EC2ダッシュボードをチェックしてみたところ、あることに気づきます。

**「EC2のサービス上では、プライベートIPアドレスが変わっていない。」**
![スクリーンショット 2021-01-31 23.36.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1041476/254ec2c4-95e5-ab66-c107-6c7d40f696b2.png)


ここで試しにインスタンスの再起動を掛けてみましたが、やはりアドレスは変わりません。
どうやら**「EC2インスタンスそのもののIPアドレス」と、「ゲストOS内の固定IPアドレス」が一致していない**と、
その仮想マシンに対する通信はできなくなってしまうようです。

# アタッチ済みのネットワークインターフェースのIPアドレスを変えようとしてみる
### ■結論：できなかった。
EC2作成時に、ネットワークインターフェース(=ENI)が1つアタッチされている。
そのENIのプライベートIPを変更してみようとEC2ダッシュボードの**[インスタンスの状態]-[ネットワークの設定]-[IPアドレスの管理]**と順番に辿り
プライベートIPアドレスを変更しようと試みてみましたが、その操作はできませんでした。
![スクリーンショット 2021-01-31 23.44.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1041476/8574cf2e-49b9-a06b-5002-4bb85c222379.png)
![スクリーンショット 2021-02-01 0.06.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1041476/b99aafc7-9381-40e3-c81f-604ce2aac6d2.png)

つまり、デフォルトで作成されたENIのプライベートIPアドレスを変更することは不可ということ。


# 指定したアドレスのみを持つインスタンスを建てる方法には基本Elastic IPが要る
自分でプライベートIPを規定して単独のENIを作成し
EC2インスタンスを新規で立てる際にそのENIをアタッチする方法を試してみたところ、
思い通りのプライベートIPアドレスを持ち、インターネット経由で接続可能なインスタンスを立てることに成功しました。

ただしこの場合同時に、Elastic IPにて パブリックIPアドレスもあらかじめ取得しておかないといけないため
インスタンス料金とは別に料金が発生してしまうのですが、
あえてこれをやろうとする場面があるのかというのはいまのところ思いつかないです。

もしくは自動でアタッチされるプライマリネットワークインターフェースのもの以外に
別のプライベートIPアドレス（*セカンダリプライベート IPv4 アドレス*）を先に指定しておくという方法もあるようです。
（当然、インターフェース数が2個になります）
>参考：プライベート IPv4 アドレスと内部 DNS ホスト名
>https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/using-instance-addressing.html#concepts-private-addresses


この方法だとElasticIPに課金することもありません。
ただ、大した目的がない場合にこの方法を使うことは みやみにサブネット内のIPアドレスを消費することにもなるし
何より管理の煩雑さが増加するため ほとんどその有用性を活かすことにならないでしょう。

（ほかにも AMIイメージから同じタイプのインスタンスを立てまくって
使いたいIPアドレスが当てられたインスタンスのみ生かし それ以外は全削除、
...みたいな半ば無理矢理な方法も思いついたが、これも敢えてそんな手間をかけるメリットがあるようには思えない）

# さいごに所感
今回ただの好奇心と遊び心(?)で設定を変更するところから始まったものの、意外にも深堀りできる要素だったのはある意味楽しみも感じました。
今後pingだけのためのセキュリティグループ設定を使うかどうかは別にして、
AWSにおけるセキュリティ設定の壁にぶつかり自分で解決できたことは、今後のためにも良い体験となりました。

初学者の私は「クラウドはオンプレに比べて柔軟で便利なもの」と
根拠もなく思ってた所があるので、パブリッククラウドにはパブリッククラウドで制限があるのだと学べた点が
特に自分の財産となっていく気がします。