NLB経由でPrivate subnetにあるEC2へアクセスする

# はじめに
AWSのNLBでPrivate subnetにあるEC2へアクセスする方法を書いた記事です。
Web3層アーキテクチャをEC2単体で全部賄っているけど、EC2自体はPublic subnetではなくPrivate subnetに置いておきたいなといった場合に便利です。
ところで、なぜALBではなくNLBを採用するのか？というと、今回は以下の条件があったからです。
- 複数AZで冗長化する予定がない。
- 多量のデータをやり取りする可能性がある。
- 相互 TLS 認証（サーバー認証＋クライアント認証）を使いたい。ALBは今のところ相互 TLS 認証がサポートされていません。


公式資料はここら辺を参考にしました。
Network Load Balancer の作成
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/network/create-network-load-balancer.html
プライベート IP アドレスを持つバックエンドインスタンスを ELB のインターネット向けロードバランサーにアタッチするにはどうすればよいですか?
https://aws.amazon.com/jp/premiumsupport/knowledge-center/public-load-balancer-private-ec2/
Application Load Balancer 用の HTTPS リスナーを作成する←相互 TLS 認証はALBじゃないよという記載
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/create-https-listener.html

# NLB→Public subnet→Private subnetでアクセスする
公式資料にも記載されていますが、NLBからはPublic subnetを経由してPrivate subnetへアクセスします。ただし、ただ経由すればいいという訳ではなくPublic subnetとPrivate subnetは同一のAvailability Zoneに配置する必要があります。
なお、相対TLS認証の終端はEC2に載っているWebサーバーとなります。NLBは暗号化された通信をそのまま転送します。WAFは暗号化された通信を評価できまないため、今回のケースではAWS WAFを利用できません。

システム構成図はこちら。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/00d42f3b-d7f6-6e79-a689-2866b81d9368.png" width="300">

# EC2のセキュリティグループ設定
~~Privet subnetにおいたEC2のセキュリティグループにPublicsubentのIPv4 CIDR（VPC CIDR）からの接続を許可しておきます。
嘘です。NLBはクライアントのIPでEC2へ到達するため、EC2のセキュリティグループは対象のポートをソース0.0.0.0/0で開けます。
解放するポートは、EC2で提供するサービスのプロトコルとNLBの設定によって変わります。今回、HTTPSでの接続はNLBのPreserve client IP addressesをoffにして、セキュリティグループはPublicsubentのIPv4 CIDR（VPC CIDR）からの接続を許可しました。また、FTPSはPreserve client IP addressesをonにして、ソース0.0.0.0/0で開けました。~~
解放するポートは、EC2で提供するサービスのプロトコルとNLBの設定によって変わります。
今回は、HTTPSとFTPSでの接続があります。HTTPS接続についてはNLBのプライベート IPv4 アドレスのみの許可としました。FTPSも同様の設定にしたかったのですが、FTPサーバー側の問題で上手くいかなかったので0.0.0.0/0を許可しました。
なお、クライアントの固定IPが分かっている場合は、NLBのPreserve client IP addressesをONにすればクライアントの固定IPのみを許可することもできます。Preserve client IP addresses→ONにすると、EC2からはクライアントの固定IPが接続してきたように見えて、Preserve client IP addresses→OFFにすると、EC2からはNLBが接続してきたように見えるというわけです。

# ターゲットグループとリスナーの関係
リスナーはポートごとに作成します。ターゲットはリスナーと同一のポートで作成します。例えば、80番ポートと443番ポートのリスナーを設定している場合は、80番ポートと443番ポートのターゲットをそれぞれ作成して、それぞれのリスナーに紐づけます。80番ポートと443番ポートを単一のターゲットで作成してリスナー80番ポートに紐づけたりすると、ターゲットの80番ポートに転送されることもあれば443番ポートに転送されることもあるというふるまいをしてしまいます。
なお、複数台のEC2をNLBに紐づける場合はターゲットとして複数のEC2インスタンスの同一ポートを登録し、いずれかのEC2へ転送されるように設定します。

# ターゲットグループの作成
NLBを作成する際にターゲットグループの設定が必要になるので、NLBより先にターゲットグループを作成しておきます。
EC2サービスにあるターゲットグループを選択して「Create target group」をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/94f02210-a13b-4861-ef5c-dfe54a16d6ce.png" width="700">
Specify group detailsの画面が表示されたら、今回は以下で設定します。
target typeは、Instancesを選択。
Targetgroup nameには、適切なターゲットグループの名前を入力。
ProtocolはTCPでPortは443を設定。これで暗号化通信をパススルーするわけですね。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/426f1b31-9f38-2863-bb6c-eac5ac49b6ca.png" width="600">
Health checksのHealth checks protocolはTCPだったのでそのまま何もせず、「Next」をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/9e0ae24e-b9e6-4896-666e-c16c8150b09d.png" width="600">
ターゲットとするPrivate subnetにあるインスタンスにチェックをつけます。
Ports for the selected instancesに443を入力して、「Include as pending below」をクリックします。
Targetsに反映した内容を確認して、「Create target group」をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/416802d3-d545-e2be-bc63-2044936d2741.png" width="800">
Target groupsに表示されたら成功です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/2cea25bd-acf6-ca6e-9494-1ca8bb770451.png" width="800">

# NLBの作成
EC2サービスにあるロードバランサーを選択して「ロードバランサーの作成」をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/e787c9aa-b781-81bb-b432-a6abdf7b503f.png" width="300">
Network Load BalancerのCreateをクリック。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/96673955-306e-bae5-7b9b-c709d22992b7.png" width="500">
Basic configurationを今回は以下で設定します。
Load balancer nameに適切なNLBの名前を入力します。
インターネットに向けるのでInternet-facingです。
IP address typeはIP4なのでそのまま変更しません。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/1571aba3-6df9-22d8-d813-caf939f39131.png" width="400">
同じページにあるNetwork mappinngを設定します。
Mappingsで使用するAZにチェックを付けてPublic subnetを選択します。
よく見ると「選択したsubnetはInternetGatewayに繋がってないとダメだからな！」って注意喚起してくれてますね。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/ec039420-e773-99a0-ce9a-70768d5a148d.png" width="700">

同じページにあるListeners and routingを設定します。
Protocol はTCPを選択、Portには443を入力。
Default actionは作成したターゲットグループを選択します。
ここまで設定したらページの一番下にある「Create load balancer」をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/4e306ad8-9030-170d-959b-05c8cfcb79db.png" width="500">
View load balancerをクリックして…
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/07cd7502-6ae0-de7e-b5ad-5af6eaf34977.png" width="600">
無事出来上がっていることを確認します。初めは状態がプロビジョニングなのでActiveになるのを待ちましょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/26db5971-e525-0e9f-81b4-9a34ff90ebf6.png" width="700">
続いてHealth statusがhealtyyになっていることを確認します。
無事、Httpsで接続できたら完成です。

# おわりに
しっかし、NLBは簡単に作れるものの奥が深く、調べれば調べるほど分からないことが出てきますね…。