らくがきちょう

なんとなく ~所属組織/団体とは無関係であり、個人の見解です~

Amazon Linux2 でポート変換する

AWS の EC2 インスタンスは複数の ENI (≒ NIC) を割り当てたり、ひとつの ENI に複数のプライベートアドレスを割り当てることが可能です。 「何個割り当てられるか?」はインスタンスタイプによって異なり、大型のインスタンスである程、最大数も増えます。 t2.nano や t2.micro でも「ふたつまでの ENI」「ひとつの ENI にふたつのプライベートアドレスまで」設定することが可能です。 例えば「ひとつの ENI にふたつのプライベートを割り当て」た状態で firewalld のポート転送機能と組み合わせると、以下のようなトラフィックフローを実現することが可能です。

f:id:sig9:20191023011053p:plain

今回は実際にこの設定を行う手順をメモしておきます。

テスト環境

今回は以下の環境でテストしました。

  • Amazon Linux2
  • t2.nano インスタンス
  • ポート転送させたいアプリケーションは、予めセキュリティグループで許可してある

EC2 インスタンスは上記の条件で作成済みですが、特に何も設定せず、かつ電源オンの状態からスタートします。

Step.1

最初に作成した Amazon Linux2 インスタンスの ENI を選択し、IP アドレスの管理 をクリックします。

f:id:sig9:20191023002604p:plain

Step.2

新しい IP の割り当て をクリックします。

f:id:sig9:20191023002617p:plain

Step.3

すると、新たに IP アドレスの欄が追加されます。 この状態で右下の 更新する をクリックします。

f:id:sig9:20191023002642p:plain

Step.4

これで ENI にプライベートアドレスが追加されました。 キャンセル を押して元の画面に戻ります。

f:id:sig9:20191023002711p:plain

Step.5

ENI に セカンダリプライベート IPv4 IP が追加されているのが分かります。

f:id:sig9:20191023002721p:plain

Step.6

次は EIP の設定画面に移ります。 予め 新しいアドレスの割り当て を実行し、ふたつ EIP を取得しておきます。 取得した EIP のうち、一つ目を選択して アドレスの関連付け をクリックします。

f:id:sig9:20191023002736p:plain

Step.7

EIP とプライベートアドレスの紐づけを行います。 リソースタイプは インスタンスインスタンスには 該当のインスタンス IDプライベート IP には一つ目のプライベートアドレスを選択し、関連付け をクリックします。

f:id:sig9:20191023002746p:plain

Step.8

これで「一つ目の EIP とプライベートアドレス」の関連付けが完了しました。 閉じる をクリックします。

f:id:sig9:20191023002800p:plain

Step.9

続いて、二つ目の EIP もプライベートアドレスとの紐づけを行います。 取得した EIP のうち、二つ目を選択して アドレスの関連付け をクリックします。

f:id:sig9:20191023002812p:plain

Step.10

リソースタイプは インスタンスインスタンスには 該当のインスタンス ID を選択するところまでは先ほどと同じです。 プライベート IP には二つ目のプライベートアドレスを選択し、関連付け をクリックします。

f:id:sig9:20191023002831p:plain

Step.11

これで「二つ目の EIP とプライベートアドレス」の関連付けも完了です。

f:id:sig9:20191023002843p:plain

Step.12

ここからは EC2 インスタンスSSH ログインして作業を行います。 AWS の管理コンソールから「二つ目のプライベートアドレス」を割り当てましたが、インスタンスが起動したままである為、反映されていません。 ip address show を実行すると eth0 にプライベートアドレスが一つしか割り当てられていないことが分かります。

# ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 06:18:aa:8a:ae:6a brd ff:ff:ff:ff:ff:ff
    inet 192.168.224.53/24 brd 192.168.224.255 scope global dynamic eth0
       valid_lft 2331sec preferred_lft 2331sec
    inet6 fe80::418:aaff:fe8a:ae6a/64 scope link
       valid_lft forever preferred_lft forever

ネットワークサービスの再起動だけで上手くいくのかも知れませんが (?)、ここでは念のため OS 毎再起動してしまいます。

# reboot

再起動が完了すると eth0 にプライベートアドレスが増えていることが分かります。

# ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 06:18:aa:8a:ae:6a brd ff:ff:ff:ff:ff:ff
    inet 192.168.224.53/24 brd 192.168.224.255 scope global dynamic eth0
       valid_lft 3114sec preferred_lft 3114sec
    inet 192.168.224.8/24 brd 192.168.224.255 scope global secondary eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::418:aaff:fe8a:ae6a/64 scope link
       valid_lft forever preferred_lft forever

Step.13

Amazon Linux2 の初期状態だとポート転送に利用したい firewalld がインストールされていません。

# systemctl status firewalld
Unit firewalld.service could not be found.
# rpm -qa | grep firewalld
#

標準リポジトリから firewalld をインストールし、デーモンを起動&自動起動するように設定しておきます。

yum -y install firewalld
systemctl enable firewalld
systemctl start firewalld

Step.14

初期状態では当然、ポート転送ルールが存在しません。

# firewall-cmd --list-all --zone=public
public
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: ssh dhcpv6-client
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

ここでは以下のようなポート転送ルールを設定します。

グローバルアドレス (EIP) 着信アドレス 着信ポート 転送先アドレス 転送先ポート
13.xxx.xxx.57 192.168.224.53 TCP/80 10.0.0.1 TCP/80
3.xxx.xxx.110 192.168.224.8 TCP/80 10.0.0.2 TCP/80

これを firewalld の Rich Rule として定義すると以下のようになります。

firewall-cmd --zone=public --add-masquerade
firewall-cmd --add-rich-rule='rule family="ipv4" destination address="192.168.224.53" forward-port to-addr="10.0.0.1" to-port="80" protocol="tcp" port="80"'
firewall-cmd --add-rich-rule='rule family="ipv4" destination address="192.168.224.8" forward-port to-addr="10.0.0.2" to-port="80" protocol="tcp" port="80"'

設定が完了したら改めて firewalld のルールを確認すると Rich Rule が設定されたことが分かります。

# firewall-cmd --list-all --zone=public
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: ssh dhcpv6-client
  ports:
  protocols:
  masquerade: yes
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
        rule family="ipv4" destination address="192.168.224.53" forward-port port="80" protocol="tcp" to-port="80" to-addr="10.0.0.1"
        rule family="ipv4" destination address="192.168.224.8" forward-port port="80" protocol="tcp" to-port="80" to-addr="10.0.0.2"

問題無さそうであれば firewalld のルールを保存します。

firewall-cmd --runtime-to-permanent

これで Amazon Linux2 でポート転送出来るようになっているはずです。