AWSでVPC内のリソースに固定Private IPアドレスのLambdaでアクセスさせる方法
かなり限定的な状況ではありますが、AWSでVPC内のリソース(EC2など)にLambdaからアクセスする際、
そのPrivate IPアドレスを固定する必要があったため、備忘録も兼ねて記事にしておきます。
※ 限定的な状況 : EC2のアプリケーション側で接続元IPアドレスを個別に許可する必要があった。
目次
はじめに
こんにちは。
クラウドソリューショングループのwatanabe.tです。
LambdaのPublic IPアドレスを固定する方法は調べると出てきますが、Private IPアドレスを固定となると意外と出てきません。
ニッチな話ではありますが、知っておくと応用が効くかもしれません。
先に記載しますが、今回の構成は以下のようになります。
前提条件
本手順を進めるにあたり、以下は実施済みの前提となります。
必要に応じて公式ページ等を参考に実施してください。
- AWSアカウントが作成済であること(参考 : AWS アカウント作成の流れ | AWS )
- VPC/サブネットが作成済みであること(参考 : Amazon VPC の使用を開始する | AWS )
- サブネットはLambda用とNAT Gateway用の2つが作成済みであること(記事の中ではそれぞれ subnet-private / subnet-nat を作成済み)
Private NAT Gateway作成
さて、まずはPrivate NAT Gatewayから作成していきましょう。
とはいえ、この部分はPublic NAT Gatewayを作成する場合と大きく変わりません。
NAT Gateways から右上の「Create NAT Gateway」を選択し、 NAT Gateway 作成画面に遷移します。
次に「NAT Gateway用のサブネット」「Connectivity type : Private」を選択し、右下の「Create NAT Gateway」を選択すると、NAT Gatewayの作成が開始されます。
このとき、「Connectivity type : Private」を選択していることによって、 VPC内でのみ有効なPrivate NAT Gatewayが作成されることがポイント です。
Lambda作成
次に、作成したNAT Gatewayを通して通信するLambdaを作成します。
AWSのLambdaにはいくつか用意されたサンプル(Blueprint)があり、その中に単純なhttpリクエストを送信するものがあったため、今回はそれを用います。
LambdaのFunctions から右上の「Create functions」を選択し、Functions作成画面を開きます。
「Use a blueprint」を選択後、「nodejs 12.x」「https-request」のサンプルを選択します。
これはNode.js 12.xで動作する、シンプルなHTTPSリクエストを送信し、そのレスポンスをロギングするだけの関数です。
「関数名」「実行に必要なIAMロール」を入力し、「Create function」を選択します。
※ 今回はLambdaをVPCに所属させる関係上、「ec2:DescribeNetworkInterfaces」「ec2:CreateNetworkInterface」「ec2:DeleteNetworkInterface」の権限が必要です。
次に、Lambdaの「Configuration」タブから「VPC」「Edit」と選択し、LambdaをVPCに所属させるように設定します。
事前に作成しておいたLambda用のVPC/サブネット(NAT Gatewayとは別のサブネット)を選択します。
セキュリティグループに関しては、Lambdaの通信先となるリソース(今回はEC2にApache HTTPを起動)に通信が許可されるようにしておきます。
ルーティング変更
さて、ここまで来たらもう一息です。
Lambdaからの通信がNAT Gatewayを通過するように、Lambda用サブネットのルートテーブルを変更します。
VPCのRoute Tables からLambda用サブネットに設定されているルートテーブルを確認します。
デフォルトの状態だと「10.0.0.0/16」向けの通信が「local」にルーティングされるようになっていますが、これを作成したNAT Gatewayに向けることで、VPC内への通信をNAT Gateway経由にすることができます。
「Edit routes」を選択しルーティング編集画面に遷移します。
「10.0.0.0/16」のTargetが「local」になっているため、これを作成済みのNAT Gateway( nat- で始まるリソースID)に変更して保存します。
これでLambdaはVPC内への通信時にNAT Gatewayを通るようになりました。
動作確認
では最後にLambdaがNAT Gatewayを通して通信できているかの確認をしてみましょう。
あらかじめ通信対象のEC2はVPC内に立てておき、NAT GatewayのIPアドレスからの通信を許可するように設定しておきました。
また、Apache HTTPサーバをインストールし、どこからアクセスがあったかも確認できるようにしておきました。
ここでLambdaのindex.jsを編集し、HTTP通信が行えるようにしておきます。(Apache HTTPサーバ側でSSL証明書を用意するのがめんどくさかったので。。。)
「index.js」の「https」となっている箇所を全て「http」と書き換えて保存・デプロイしておけばOKです。
あとはLambdaのテスト実行で以下のデータを渡して実行すれば、Lambda -> NAT Gateway -> EC2(Apache HTTPサーバ)という通信が行われます。
{
"options": {
"protocol": "http:",
"host": "EC2のPrivate IPアドレス",
"port": 80,
"path": "/",
"method": "GET"
},
"data": ""
}
通信の確認のためApache HTTPサーバの /var/log/httpd/access_log
を見てみると、以下のようにアクセスログが表示されていました。
[root@ip-10-0-0-103 ~]# tail -f /var/log/httpd/access_log
10.0.10.17 - - [12/Sep/2021:07:16:59 +0000] "GET / HTTP/1.1" 200 380 "-" "-"
このアクセスログに表示されている 「10.0.10.17」が作成したPrivate NAT GatewayのPrivate IPアドレスと一致しているため、無事にLambdaからの通信がNAT Gatewayを経由してEC2に到達していることが確認できました。
おわりに
今回は、VPC内のリソースに固定Private IPアドレスのLambdaでアクセスさせる方法を紹介しました。
かなり限定的な状況であるとはいえ、Private NAT Gatewayの挙動を知ることができたのは面白かったです。
特に、AWSのネットワーク周りは目に見えづらく、理解しづらい部分も多い分野です。
少しずつユースケースごとのベストパターンを探っていければと思います。
この記事が誰かの役に立つことを祈って。
ちなみに、VPCエンドポイントを利用している場合はLambda用サブネットのルーティング設定がさらに複雑になるのですが、長くなってしまうのでまた別の機会にでも。