概要
AWS Lambda の関数は、何も設定しなければ Lambda が管理する VPC で動き、そのままインターネットにアクセスできます。ところが、RDS などの VPC 内のリソースにつなぐために関数を自分の VPC に接続した途端、外部の API を呼ぶ処理がタイムアウトするようになることがあります。
VPC に接続した関数は、VPC 内に作られるネットワークインターフェイス(Hyperplane ENI)を通って通信し、そのネットワークインターフェイスに付くのはプライベート IP アドレスだけです。そのため、インターネットゲートウェイへのルートがあるパブリックサブネットに関数を接続しても、インターネットには出られません。EC2 インスタンスの感覚で「パブリックサブネットに置けば出られるはず」と考えると、ここでつまずきます。
この記事では、VPC に接続した Lambda 関数がインターネットに出るための構成(プライベートサブネット + パブリックサブネットの NAT ゲートウェイ)と、出られないときに確認するポイント(サブネットとルートテーブル・セキュリティグループ・ネットワーク ACL)を整理します。AWS のサービスにだけつなげればよい場合に使える VPC エンドポイントにも触れます。実践では、関数をパブリックサブネットに接続してタイムアウトすることを確かめてから、プライベートサブネットと 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 を経由させます。
- 関数はプライベートサブネットに接続する
- NAT ゲートウェイは、インターネットゲートウェイへのルートがあるパブリックサブネットに作る(Elastic IP 付き)
- プライベートサブネットのルートテーブルで、
0.0.0.0/0のターゲットを NAT ゲートウェイにする
NAT ゲートウェイはパブリックサブネットに置かれますが、NAT ゲートウェイへのルートを書くのはプライベートサブネットのルートテーブルです。関数からの通信は NAT ゲートウェイの Elastic IP を送信元にしてインターネットに出ていきます。
| 関数を接続するサブネット | サブネットの 0.0.0.0/0 のターゲット | インターネットに出られるか |
|---|---|---|
| パブリックサブネット | インターネットゲートウェイ | 出られない(関数にパブリック IP アドレスが無い) |
| プライベートサブネット | なし(local だけ) | 出られない |
| プライベートサブネット | パブリックサブネットの NAT ゲートウェイ | 出られる(送信元は NAT ゲートウェイの Elastic IP) |





「外に出したいからパブリックサブネットに置く」は 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 障害対策 ── プライベートサブネットから外に出られなくなるのを防ぐ で扱っています。
実践
VPC に接続していない Lambda 関数 lambda-nat-fn を、まずパブリックサブネットに接続して、外部(https://checkip.amazonaws.com)への接続がタイムアウトすることを確かめます。続けて NAT ゲートウェイを作り、関数の接続先をプライベートサブネットに付け替えて、外部に出られるようになることと、送信元が NAT ゲートウェイの Elastic IP になることを確認します。
前提条件
- リージョン:
ap-northeast-1(東京) - Lambda・VPC・EC2 の操作権限を持つ IAM ユーザーまたはロールでコンソールにログイン済みであること
以下のリソースが作成済みであることを前提とします。
まだ用意していない場合は、「作り方の参考」の記事の手順で作れます。リソース名は、この記事の名前に読み替えてください。
| リソース種別 | リソース名 | 内容 | 作り方の参考 |
|---|---|---|---|
| VPC | lambda-nat-vpc | CIDR 10.0.0.0/16 | Amazon VPC で仮想ネットワークを構築しサブネットを設定する ※AZ を 2 つにする |
| パブリックサブネット | lambda-nat-public-1a / lambda-nat-public-1c | 10.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-1c | 10.0.11.0/24(1a)/ 10.0.12.0/24(1c) | 同上 |
| ルートテーブル | lambda-nat-private-rt | 2 つのプライベートサブネットに関連付け。local のルートだけ | VPC のルートテーブルでトラフィックの流れを制御する |
| セキュリティグループ | lambda-nat-fn-sg | インバウンドルールなし。アウトバウンドはすべて許可 | セキュリティグループとネットワーク ACL でアクセスを制御する |
| IAM ロール | lambda-nat-fn-role | AWSLambdaBasicExecutionRole と AWSLambdaVPCAccessExecutionRole をアタッチ | AWS Lambda で関数を作成しイベント駆動で実行する |
| Lambda 関数 | lambda-nat-fn | Python 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-natgw | lambda-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 からそのままインターネットに出られます。


手順 2: 関数をパブリックサブネットに接続する
lambda-nat-fn の「設定」タブを開き、左側の「VPC」を選択して「編集」をクリックします。以下を設定します。
- VPC:
lambda-nat-vpc - サブネット:
lambda-nat-public-1aとlambda-nat-public-1c - セキュリティグループ:
lambda-nat-fn-sg
その他の項目はデフォルトのままにして、「保存」をクリックします。


関数の更新が終わるまで待ちます。Hyperplane ENI の作成に数分かかることがあります。
手順 3: パブリックサブネットではタイムアウトすることを確かめる
「テスト」タブで、手順 1 と同じイベント check-ip のまま「テスト」をクリックします。
10 秒待ったあと「実行中の関数: 失敗」と表示されるので、「詳細」を開き、「Response」の errorType が Sandbox.Timedout、errorMessage に Task timed out after 10.00 seconds が含まれることを確認します。インターネットゲートウェイへのルートがあるサブネットに接続したのに、外部に接続できていません。


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


手順 4: パブリックサブネットに NAT ゲートウェイを作る
上部の検索バーに VPC と入力し、「VPC」を選択します。左側ナビゲーションの「NAT ゲートウェイ」を選択し、「NAT ゲートウェイを作成」をクリックします。以下を設定します。
- 名前:
lambda-nat-natgw - アベイラビリティーモード:
ゾーナル(初期表示が「リージョナル – 新規」の場合は切り替えます。ゾーナルにすると、サブネット・接続タイプ・Elastic IP の欄が表示されます) - サブネット:
lambda-nat-public-1a - 接続タイプ:
パブリック - Elastic IP 割り当て ID: 「Elastic IP を割り当て」をクリックして新しく割り当てる
その他の項目はデフォルトのままにして、「NAT ゲートウェイを作成」をクリックします。


状態が Available(利用可能)になるまで数分待ちます。詳細画面に表示される lambda-nat-natgw のプライマリパブリック IPv4 アドレスを控えておきます。
手順 5: プライベートサブネットのルートを NAT ゲートウェイに向ける
左側ナビゲーションの「ルートテーブル」から lambda-nat-private-rt を選択し、「ルート」タブの「ルートを編集」をクリックします。「ルートを追加」をクリックし、以下を設定します。
- 送信先:
0.0.0.0/0 - ターゲット: 「NAT ゲートウェイ」を選び、その下の入力欄で
lambda-nat-natgwの NAT ゲートウェイ ID を選択
「変更を保存」をクリックします。


手順 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 つだけが表示されていることを確認します。


手順 7: 外へ出られるようになったことを確かめる
「テスト」タブで、同じイベント check-ip のまま「テスト」をクリックします。
実行結果が成功になり、レスポンスに "status": 200 が返ることを確認します。ip の値が、手順 4 で控えた lambda-nat-natgw のパブリック IPv4 アドレスと同じであることも確認します。関数の通信が、プライベートサブネットのルートに従って NAT ゲートウェイを通り、その Elastic 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 ごとに置く
参照先
- VPC に接続された Lambda 関数にインターネットアクセスを有効にする – AWS Lambda
- Lambda 関数に Amazon VPC 内のリソースへのアクセスを許可する – AWS Lambda
- Lambda でのネットワークに関する問題のトラブルシューティング – AWS Lambda
- VPC の Lambda 関数へのインターネットアクセスを許可する | AWS re:Post
- Lambda 関数で発生する ETIMEDOUT エラーのトラブルシューティング | AWS re:Post
- NAT ゲートウェイの料金 – Amazon Virtual Private Cloud
- ゲートウェイエンドポイント – Amazon Virtual Private Cloud













