Lambda を VPC に入れたらインターネットに出られないときの確認ポイント ── NAT ゲートウェイとプライベートサブネット

目次

概要

AWS Lambda の関数は、何も設定しなければ Lambda が管理する VPC で動き、そのままインターネットにアクセスできます。ところが、RDS などの VPC 内のリソースにつなぐために関数を自分の VPC に接続した途端、外部の API を呼ぶ処理がタイムアウトするようになることがあります。

VPC に接続した関数は、VPC 内に作られるネットワークインターフェイス(Hyperplane ENI)を通って通信し、そのネットワークインターフェイスに付くのはプライベート IP アドレスだけです。そのため、インターネットゲートウェイへのルートがあるパブリックサブネットに関数を接続しても、インターネットには出られません。EC2 インスタンスの感覚で「パブリックサブネットに置けば出られるはず」と考えると、ここでつまずきます。

この記事では、VPC に接続した Lambda 関数がインターネットに出るための構成(プライベートサブネット + パブリックサブネットの NAT ゲートウェイ)と、出られないときに確認するポイント(サブネットとルートテーブル・セキュリティグループ・ネットワーク ACL)を整理します。AWS のサービスにだけつなげればよい場合に使える VPC エンドポイントにも触れます。実践では、関数をパブリックサブネットに接続してタイムアウトすることを確かめてから、プライベートサブネットと NAT ゲートウェイの構成に付け替えて、外部に出られるようになるまでを体験します。

VPC の Lambda を外へ出すのは、パブリックサブネットではなく NAT ゲートウェイ
VPC の Lambda を外へ出すのは、パブリックサブネットではなく NAT ゲートウェイ
クラウドおさる

猿山の外に出る門の前に立っても、通行手形(パブリック IP)を持っていない猿は通してもらえないのでござる。今日は、手形を持った案内役(NAT ゲートウェイ)に付いて外へ出る道を確かめるでござるよ。

この記事のメリット

  • VPC に接続した Lambda 関数が、パブリックサブネットに置いてもインターネットに出られない理由を説明できるようになる
  • 関数をプライベートサブネットに接続し、0.0.0.0/0 をパブリックサブネットの NAT ゲートウェイへ向ける構成を組めるようになる
  • 関数が外へ出られないときに、サブネットとルートテーブル・セキュリティグループ・ネットワーク ACL の順に確認できるようになる
  • AWS のサービスにだけつなぐなら、NAT ゲートウェイの代わりに VPC エンドポイントを使えることが分かる

執筆者とキャラクター紹介

執筆者:土肥(とひ)

株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。

土肥

クラウドおさる

クラウドおさる

はじめましてでござる。弊猿はクラウドおさる。IT インフラが異常に発達した猿山から、雲に乗って地上の AWS を学びに降りてきたのでござる。

クラウドおさる

基礎編や Cloud Practitioner の記事では、とひさんに素朴な疑問をぶつける役でござるな。Security - Specialty などの記事では、要所でワンポイントや注意点をひとこと添えるでござる。

クラウドおさる

猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。

技術解説

VPC に接続すると、関数の通信はすべて VPC を通る

Lambda 関数は、既定では Lambda が管理する VPC で実行され、インターネットにアクセスできます。関数を自分の VPC に接続すると、関数は指定したサブネットに Lambda が作成するネットワークインターフェイス(Hyperplane ENI)を通って通信するようになり、すべてのアウトバウンドリクエストが自分の VPC を通過します。その結果、関数がアクセスできるのは、その VPC から到達できる範囲だけになります。

VPC に接続するときに指定する主な項目は次のとおりです。

項目内容
VPC関数を接続する VPC
サブネットHyperplane ENI を作るサブネット。冗長性のため、複数の AZ のサブネットを指定することが推奨されている
セキュリティグループHyperplane ENI に付けるセキュリティグループ。外へ出る通信をアウトバウンドルールで許可する
実行ロールの権限ネットワークインターフェイスを作るための ec2:CreateNetworkInterface などが要る。AWS 管理ポリシー AWSLambdaVPCAccessExecutionRole で付けられる

実行ロールのこれらの権限は、関数を呼び出すためではなく、ネットワークインターフェイスを作成するためだけに使われます。

パブリックサブネットに接続しても出られない

EC2 インスタンスは、インターネットゲートウェイへのルートがあるパブリックサブネットに置き、パブリック IP アドレスを付ければインターネットに出られます。Lambda 関数は違います。関数をパブリックサブネットに接続しても、関数に割り当てられるのはプライベート IP アドレスだけで、インターネットアクセスやパブリック IP アドレスは提供されません。インターネットゲートウェイへのルートがあっても、パブリック IP アドレスを持たない送信元からの通信はインターネットに出られないため、外部への接続はタイムアウトします。

VPC に接続した関数をインターネットに出すには、NAT を経由させます。

  1. 関数はプライベートサブネットに接続する
  2. NAT ゲートウェイは、インターネットゲートウェイへのルートがあるパブリックサブネットに作る(Elastic IP 付き)
  3. プライベートサブネットのルートテーブルで、0.0.0.0/0 のターゲットを NAT ゲートウェイにする

NAT ゲートウェイはパブリックサブネットに置かれますが、NAT ゲートウェイへのルートを書くのはプライベートサブネットのルートテーブルです。関数からの通信は NAT ゲートウェイの Elastic IP を送信元にしてインターネットに出ていきます。

関数を接続するサブネットサブネットの 0.0.0.0/0 のターゲットインターネットに出られるか
パブリックサブネットインターネットゲートウェイ出られない(関数にパブリック IP アドレスが無い)
プライベートサブネットなし(local だけ)出られない
プライベートサブネットパブリックサブネットの NAT ゲートウェイ出られる(送信元は NAT ゲートウェイの Elastic IP)
関数の ENI にはパブリック IP が付かない。外へ出るには NAT ゲートウェイで変換する
関数の ENI にはパブリック IP が付かない。外へ出るには NAT ゲートウェイで変換する
クラウドおさる

「外に出したいからパブリックサブネットに置く」は EC2 の考え方でござる。Lambda はパブリックサブネットに置いても手形をもらえないので、ここを取り違えると、いつまでもタイムアウトを眺めることになるのでござるぞ。

出られないときの確認ポイント

VPC に接続した関数が外部への接続でタイムアウトするときは、次の 3 つを確認します。

確認する場所見るところ
サブネットとルートテーブル関数に指定したすべてのサブネットがプライベートサブネットで、0.0.0.0/0 が NAT ゲートウェイを向いているか。NAT ゲートウェイを削除したままルートを残すと、ルートの状態が Blackhole になる
セキュリティグループ関数のセキュリティグループのアウトバウンドルールが、宛先のポート(HTTPS なら 443)への通信を許可しているか
ネットワーク ACL既定のネットワーク ACL はすべて許可する。ルールを変えている場合は、関数のサブネットで、宛先へのアウトバウンドと戻りの通信(エフェメラルポート 1024〜65535 へのインバウンド)を許可しているか。NAT ゲートウェイを置いたパブリックサブネットの ACL でも、関数のプライベート IP アドレスとの往復の通信を許可しているか

関数がリクエストを送るとき、どのサブネットのネットワークインターフェイスを使うかは指定したサブネットの中から選ばれます。パブリックサブネットとプライベートサブネットを混ぜて指定していると、成功したりタイムアウトしたりを繰り返すことがあります。タイムアウトが断続的に起きるときは、指定したすべてのサブネットがプライベートサブネットで、NAT ゲートウェイへのデフォルトルートを持っているかを確認します。

確認を自動で行いたい場合は、Systems Manager のオートメーションランブック AWSSupport-TroubleshootLambdaInternetAccess を使う方法もあります。

AWS のサービスにだけつなぐなら VPC エンドポイント

関数がつなぎたい先が外部の API ではなく、S3 や DynamoDB、Secrets Manager などの AWS のサービスだけなら、NAT ゲートウェイを使わずに VPC エンドポイントで接続できます。VPC エンドポイントを使うと、インターネットへの経路が無いプライベートサブネットからでも、対応する AWS のサービスに接続できます。

方法つなげる先料金
NAT ゲートウェイインターネット上の任意の宛先(外部 API・AWS のサービスとも)NAT ゲートウェイが使用可能な時間と、処理したデータ量に応じて課金
ゲートウェイエンドポイントS3 と DynamoDB追加料金なし
インターフェイスエンドポイント対応する AWS のサービス(S3・DynamoDB を含む)料金がかかる

外部の API を呼ぶ必要があるなら NAT ゲートウェイ、AWS のサービスだけなら VPC エンドポイント、と目的で選び分けます。なお、NAT ゲートウェイは 1 つの AZ にだけ置くと、その AZ の障害で他の AZ の関数も外へ出られなくなります。AZ ごとに置く方法やリージョン NAT ゲートウェイについては、NAT ゲートウェイの AZ 障害対策 ── プライベートサブネットから外に出られなくなるのを防ぐ で扱っています。

新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

実践

VPC に接続していない Lambda 関数 lambda-nat-fn を、まずパブリックサブネットに接続して、外部(https://checkip.amazonaws.com)への接続がタイムアウトすることを確かめます。続けて NAT ゲートウェイを作り、関数の接続先をプライベートサブネットに付け替えて、外部に出られるようになることと、送信元が NAT ゲートウェイの Elastic IP になることを確認します。

前提条件

  • リージョン: ap-northeast-1(東京)
  • Lambda・VPC・EC2 の操作権限を持つ IAM ユーザーまたはロールでコンソールにログイン済みであること

以下のリソースが作成済みであることを前提とします。

まだ用意していない場合は、「作り方の参考」の記事の手順で作れます。リソース名は、この記事の名前に読み替えてください。

リソース種別リソース名内容作り方の参考
VPClambda-nat-vpcCIDR 10.0.0.0/16Amazon VPC で仮想ネットワークを構築しサブネットを設定する ※AZ を 2 つにする
パブリックサブネットlambda-nat-public-1a / lambda-nat-public-1c10.0.1.0/24(1a)/ 10.0.2.0/24(1c)。ルートテーブル lambda-nat-public-rt で 0.0.0.0/0 → インターネットゲートウェイ lambda-nat-igw同上
プライベートサブネットlambda-nat-private-1a / lambda-nat-private-1c10.0.11.0/24(1a)/ 10.0.12.0/24(1c)同上
ルートテーブルlambda-nat-private-rt2 つのプライベートサブネットに関連付け。local のルートだけVPC のルートテーブルでトラフィックの流れを制御する
セキュリティグループlambda-nat-fn-sgインバウンドルールなし。アウトバウンドはすべて許可セキュリティグループとネットワーク ACL でアクセスを制御する
IAM ロールlambda-nat-fn-roleAWSLambdaBasicExecutionRole と AWSLambdaVPCAccessExecutionRole をアタッチAWS Lambda で関数を作成しイベント駆動で実行する
Lambda 関数lambda-nat-fnPython 3.13。タイムアウト 10 秒。実行ロールは lambda-nat-fn-role。VPC には接続していない同上

lambda-nat-fn のコードは次のとおりです。https://checkip.amazonaws.com に接続し、返ってきた送信元 IP アドレスを返します。接続できない場合は、関数のタイムアウト(10 秒)まで待って失敗します。

import urllib.request


def lambda_handler(event, context):
    # 接続先が返す「自分の送信元 IP アドレス」で、どこから外へ出たかを確かめる
    with urllib.request.urlopen("https://checkip.amazonaws.com") as res:
        return {"status": res.status, "ip": res.read().decode().strip()}

このハンズオンで作成・変更するリソースは以下のとおりです。

リソース種別リソース名用途
NAT ゲートウェイ(ゾーン)lambda-nat-natgwlambda-nat-public-1a に置く出口
Elastic IP(NAT ゲートウェイの作成画面で割り当て)NAT ゲートウェイの送信元 IP アドレス
ルートlambda-nat-private-rt の 0.0.0.0/0ターゲットを lambda-nat-natgw にする
Lambda 関数の VPC 設定lambda-nat-fnパブリックサブネット → プライベートサブネットに付け替える

NAT ゲートウェイは、作成している間ずっと時間単位で課金され、処理したデータ量にも課金されます。Elastic IP も課金対象です。検証が終わったら必ず削除し、Elastic IP を解放してください。

手順 1: VPC に接続していない状態で外へ出られることを確かめる

AWS マネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。上部の検索バーに Lambda と入力し、「Lambda」を選択します。

「関数」の一覧から lambda-nat-fn を選択し、「テスト」タブを開きます。イベント名に check-ip と入力し、イベント JSON は {} のままにして「テスト」をクリックします。

画面上部に「実行中の関数: 成功」と表示されるので、「詳細」を開き、「Response」に "status": 200 と、AWS のパブリック IP アドレスが ip として返ってくることを確認します。VPC に接続していない関数は、Lambda が管理する VPC からそのままインターネットに出られます。

VPC 未接続の lambda-nat-fn のテスト結果(成功し、status 200 と ip が返っている)
VPC 未接続の lambda-nat-fn のテスト結果(成功し、status 200 と ip が返っている)

手順 2: 関数をパブリックサブネットに接続する

lambda-nat-fn の「設定」タブを開き、左側の「VPC」を選択して「編集」をクリックします。以下を設定します。

  • VPC: lambda-nat-vpc
  • サブネット: lambda-nat-public-1a と lambda-nat-public-1c
  • セキュリティグループ: lambda-nat-fn-sg

その他の項目はデフォルトのままにして、「保存」をクリックします。

VPC の編集画面(VPC が lambda-nat-vpc、サブネットにパブリックサブネット 2 つを選択した状態)
VPC の編集画面(VPC が lambda-nat-vpc、サブネットにパブリックサブネット 2 つを選択した状態)

関数の更新が終わるまで待ちます。Hyperplane ENI の作成に数分かかることがあります。

手順 3: パブリックサブネットではタイムアウトすることを確かめる

「テスト」タブで、手順 1 と同じイベント check-ip のまま「テスト」をクリックします。

10 秒待ったあと「実行中の関数: 失敗」と表示されるので、「詳細」を開き、「Response」の errorType が Sandbox.Timedout、errorMessage に Task timed out after 10.00 seconds が含まれることを確認します。インターネットゲートウェイへのルートがあるサブネットに接続したのに、外部に接続できていません。

パブリックサブネットに接続した lambda-nat-fn のテスト結果(タイムアウトで失敗している)
パブリックサブネットに接続した lambda-nat-fn のテスト結果(タイムアウトで失敗している)

理由を確かめるため、Lambda が作ったネットワークインターフェイスを見ます。上部の検索バーに EC2 と入力し、「EC2」を選択します。左側ナビゲーションの「ネットワーク & セキュリティ」→「ネットワークインターフェイス」を選択し、検索欄でセキュリティグループ lambda-nat-fn-sg の ID を指定して絞り込みます。

パブリックサブネットに作られたネットワークインターフェイスに、プライベート IPv4 アドレスはあっても、パブリック IPv4 アドレスが付いていないことを確認します。

ネットワークインターフェイスの一覧(Lambda のネットワークインターフェイスにパブリック IPv4 アドレスが無い)
ネットワークインターフェイスの一覧(Lambda のネットワークインターフェイスにパブリック IPv4 アドレスが無い)

手順 4: パブリックサブネットに NAT ゲートウェイを作る

上部の検索バーに VPC と入力し、「VPC」を選択します。左側ナビゲーションの「NAT ゲートウェイ」を選択し、「NAT ゲートウェイを作成」をクリックします。以下を設定します。

  • 名前: lambda-nat-natgw
  • アベイラビリティーモード: ゾーナル(初期表示が「リージョナル – 新規」の場合は切り替えます。ゾーナルにすると、サブネット・接続タイプ・Elastic IP の欄が表示されます)
  • サブネット: lambda-nat-public-1a
  • 接続タイプ: パブリック
  • Elastic IP 割り当て ID: 「Elastic IP を割り当て」をクリックして新しく割り当てる

その他の項目はデフォルトのままにして、「NAT ゲートウェイを作成」をクリックします。

NAT ゲートウェイの作成画面(アベイラビリティーモードがゾーナル、サブネットが lambda-nat-public-1a)
NAT ゲートウェイの作成画面(アベイラビリティーモードがゾーナル、サブネットが lambda-nat-public-1a)

状態が Available(利用可能)になるまで数分待ちます。詳細画面に表示される lambda-nat-natgw のプライマリパブリック IPv4 アドレスを控えておきます。

手順 5: プライベートサブネットのルートを NAT ゲートウェイに向ける

左側ナビゲーションの「ルートテーブル」から lambda-nat-private-rt を選択し、「ルート」タブの「ルートを編集」をクリックします。「ルートを追加」をクリックし、以下を設定します。

  • 送信先: 0.0.0.0/0
  • ターゲット: 「NAT ゲートウェイ」を選び、その下の入力欄で lambda-nat-natgw の NAT ゲートウェイ ID を選択

「変更を保存」をクリックします。

lambda-nat-private-rt のルート(0.0.0.0/0 のターゲットが lambda-nat-natgw で、状態がアクティブ)
lambda-nat-private-rt のルート(0.0.0.0/0 のターゲットが lambda-nat-natgw で、状態がアクティブ)

手順 6: 関数の接続先をプライベートサブネットに付け替える

Lambda コンソールに戻り、lambda-nat-fn の「設定」タブ →「VPC」→「編集」をクリックします。サブネットから lambda-nat-public-1a と lambda-nat-public-1c を外し、lambda-nat-private-1a と lambda-nat-private-1c を選択します。VPC とセキュリティグループはそのままにして、「保存」をクリックします。

パブリックサブネットを 1 つでも残すと、そのサブネットが使われたときだけタイムアウトします。すべてのサブネットをプライベートサブネットにすることに注意が必要です。

関数の更新が終わったら、「VPC」の欄にプライベートサブネット 2 つだけが表示されていることを確認します。

lambda-nat-fn の VPC 設定(サブネットが lambda-nat-private-1a と lambda-nat-private-1c だけになっている)
lambda-nat-fn の VPC 設定(サブネットが lambda-nat-private-1a と lambda-nat-private-1c だけになっている)

手順 7: 外へ出られるようになったことを確かめる

「テスト」タブで、同じイベント check-ip のまま「テスト」をクリックします。

実行結果が成功になり、レスポンスに "status": 200 が返ることを確認します。ip の値が、手順 4 で控えた lambda-nat-natgw のパブリック IPv4 アドレスと同じであることも確認します。関数の通信が、プライベートサブネットのルートに従って NAT ゲートウェイを通り、その Elastic IP を送信元にしてインターネットに出ていることが分かります。

プライベートサブネットに接続した lambda-nat-fn のテスト結果(成功し、ip が NAT ゲートウェイの IP アドレスになっている)
プライベートサブネットに接続した lambda-nat-fn のテスト結果(成功し、ip が NAT ゲートウェイの IP アドレスになっている)
クラウドおさる

関数のコードは一行も変えていないのに、置き場所を内側の谷(プライベートサブネット)に移して、道案内(ルート)を案内役(NAT ゲートウェイ)に向けただけで外に出られたでござる。返ってきた IP が案内役の手形と同じなのが、何よりの証拠でござるな。

クラウドおさる

「VPC の Lambda から外部 API を呼びたい」と言われたら、プライベートサブネットと NAT ゲートウェイの組み合わせでござる。「パブリックサブネットに置けば出られる」という EC2 流の考え方と取り違えないことと、AWS のサービスだけなら VPC エンドポイントで足りることを押さえておくでござるよ。

まとめ

やりたいこと構成
VPC 内のリソースにも、インターネット上の API にもつなぎたい関数をプライベートサブネットに接続し、0.0.0.0/0 をパブリックサブネットの NAT ゲートウェイに向ける
VPC 内のリソースと AWS のサービスにだけつなぎたい関数をプライベートサブネットに接続し、VPC エンドポイント(S3・DynamoDB はゲートウェイエンドポイントも使える)を作る
VPC 内のリソースにつなぐ必要がない関数を VPC に接続しない(Lambda が管理する VPC からインターネットに出られる)
  • VPC に接続した関数の通信は、すべて自分の VPC を通る。関数のネットワークインターフェイスにはプライベート IP アドレスしか付かない
  • 関数をパブリックサブネットに接続しても、インターネットアクセスやパブリック IP アドレスは提供されない。外部への接続はタイムアウトする
  • NAT ゲートウェイはパブリックサブネットに置き、ルートはプライベートサブネットのルートテーブルに書く。外部から見える送信元は NAT ゲートウェイの Elastic IP になる
  • 出られないときは、サブネットとルートテーブル・セキュリティグループのアウトバウンドルール・ネットワーク ACL(関数のサブネットと NAT ゲートウェイのサブネットの両方。エフェメラルポートへの戻りも)を確認する。タイムアウトが断続的なら、パブリックサブネットが混ざっていないかを疑う
  • NAT ゲートウェイを 1 つの AZ にだけ置くと、その AZ の障害で外へ出られなくなる。可用性を上げるなら AZ ごとに置く

参照先

キャリア相談
クラウドおさる

独学の先に、AWS の仕事がある ── ジュニアおさるのキャリア相談

CLF には受かったけれど、次に何をすればいいのか分からない。独学で AWS を学ぶジュニアおさるの相談に、株式会社ジェニュイン代表の土肥が答えています。

  • ✓資格はゴールか、CLF の次に何から手を付けるか
  • ✓EC2 の次に作ってみる構成と、IaC・コスト管理
  • ✓実務経験ゼロでも、面接で話せる「これまで」の作り方
新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

株式会社ジェニュイン(https://genuine-pt.jp)の代表取締役.

2018年〜インフラエンジニアとしてキャリアをスタートし、オンプレミスのネットワーク・サーバ環境で3年半、クラウド環境で4年半の8年間エンジニアとして従事。
2021年に佐藤氏の創業した株式会社Luxyを引き継ぎ、代表に就任。
その後アガルートグループ内の株式会社ジェニュインと合併。
合併後同社代表に就任。

目次