この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
Lambda関数はVPCの中にも、外にも配置することができますが、 インターネットへの通信を行いたい時はVPC外に配置するのが一般的です。 しかし何らかの事情でパブリックサブネットにLambda関数を配置して、 VPC内部と外部両方との通信を行いたい場合があるかもしれません。 (本当にあるのかはわかりません。。 私は検証目的のアーキテクチャを作っている中で、 VPCエンドポイントを作るのが嫌だったからIGW経由でラクしようと思っただけです)
しかしパブリックサブネット内部に配置されたLambda関数は、 そのままではインターネットへは通信ができませんでした。 その理由を調べてわかったことを書いていこうと思います。
なお、NAT GWを設置することでもインターネットへの接続(アウトバウンドのみ)はもちろん可能ですが、 今回はIGWで接続することだけを想定しています。
やってみる
通信できないことの確認
IGWへ通信可能なサブネットにVPC Lambdaを作成して、 インターネットアクセスができるかを確かめてみます。
IGWがVPCにアタッチされ、ルートテーブルも正常に設定されています。 (VPCにIGWがアタッチされている様子はスクリーンショットを撮り忘れました)
VPC内にLambda関数を作ります。 VPC、サブネット、セキュリティグループを設定します。
これで、IGWに行くことができるサブネットにLambda関数が配置できました。
このLambbda関数からインターネットへ接続する必要があるプログラムを実行してみます。 プログラムは以下のように、Googleのトップページを取得するものを準備しました。
import urllib.request
def lambda_handler(event, context):
url = 'https://www.google.co.jp'
req = urllib.request.Request(url)
with urllib.request.urlopen(req) as res:
text = res.read()
print(text)
実行してみるとインターネットへのアクセスができずにタイムアウトしてしまいました。 タイムアウトは15秒としてあります。
ここで私はしばらく原因がわからずにあれやこれや調べていたのですが、 原因は、Lambda関数にアタッチされたENIがパブリックIPを持っていないからでした。 Lambda関数をVPCに立てる場合パブリックIPは割り当たりませんし、 明示的に割り当てるような設定項目もありません。
実際ENIを見ると、パブリックIPが設定されていません。
IGWは静的NATとしての処理しかしません。 よって、VPC内部のプライベートIPと交換すべきパブリックIPがなければ、 通信はインターネットに出ていくことはできません。 ということで、今回のケースではパブリックIPを与えることができればインターネットに通信できそうです。
ENIにパブリックIPを付与する
ではENIにパブリックIPを付与してみます。 ENIに対して「アドレスの関連付け」を選択します。
指定する際には、対象となるプライベートIPも指定する必要があります。 パブリックIPはIGWでプライベートIPと交換されるので、 ペアとなるプライベートIPを指定するということなんですね。
パブリックIPがセットされました。
再度インターネットへの接続を確認
これで同じLambda関数を実行してみます。
ちゃんと通信できました! htmlのテキストが並んでいるだけですが、 インターネットにアクセスできなければ取得できない情報が含まれています。
おまけ
上記のテスト結果から、ENIについているパブリックIPとは、 IGWで交換するアドレスのことだということがわかりました。 今回、それを裏付ける挙動が他にも見られたのでご紹介します。
再度パブリックIPの関連付けを解除してみます。
次にIGWをVPCからデタッチしてみます。
そして再度ENIにパブリックIPの付与を試みて見ます。
この場合だとパブリックIPの関連付けは拒否されました。
vpc-xxxxxxxx is not attached to any internet gateway
という文言が表示されており、IGWがアタッチされていないとパブリックIPの関連付け自体が拒否されることがわかります。
ENIがIGWとは無関係にパブリックIPを持つのであれば、 所属するVPCにIGWがアタッチされているかどうかは無関係であるはずですが、 実際VPCからIGWをデタッチした状態ではENIへのパブリックIPの関連付けはできないようです。
(ただしEC2インスタンスを立てる際には、VPCにIGWがアタッチされているかに関係なく、 パブリックIPをもったENIがアタッチされたインスタンスを立てることが可能なようです。 ここの事情についてはよくわかっていませんが、 IGWに通信できる状況でなければいくらパブリックIPだけがあってもインターネットへは通信できませんので、 IGWへの通信とパブリックIPは必ずセットで必要と考えれば良さそうです。)
まとめ
VPC内のLambdaからIGW経由でインターネットに出たい場合は、 アタッチされるENIにパブリックIPを関連付けてあげれば大丈夫なことがわかりました。 またそれによって、IGWが静的NATとしてはたらいていることがよくわかりました。
はじめにも書きましたが、インターネットに出たいLambda関数はVPCの外に置くのが普通だと思いますので、 今回の例はあくまでもVPC内Lambdaを立てた時の挙動を理解するという以上の価値はないかなぁと思います。
今回はVPC Lambdaが、どうやってVPC内にLambda関数が配置されたように振る舞うのかという部分はすっ飛ばして、 Lambda関数が直接VPC内に存在するような記述としてしまったのですが、 この辺をもっと深く理解するためには、Lambda 用 VPC ネットワーキングの辺りをもっと理解する必要がありそうです。