Lambda MicroVMsのVPC EgressコネクタでVPC内プライベートリソースへの接続を検証してみた
はじめに
Lambda MicroVMsでは、MicroVMからの外向き通信(Egress)として、デフォルトの INTERNET_EGRESS と、VPC内のサブネット・セキュリティグループを指定する VPC_EGRESS を選択できます。
| 項目 | INTERNET_EGRESS | VPC_EGRESS |
|---|---|---|
| 接続先 | インターネット | 指定VPCのサブネット |
| インターネット到達 | ✅ 常に可能 | サブネットのルートテーブル次第 |
| プライベートリソース到達 | ❌ 不可 | ✅ 可能 |
| 事前準備 | 不要(デフォルト) | コネクタ作成が必要 |
| SG制御 | なし | コネクタにSGをアタッチ |
| ENI | なし | Lambda基盤側で管理 |
VPC_EGRESS は「閉域専用」の機能ではありません。コネクタを配置するサブネットのルートテーブルにNAT Gatewayへのデフォルトルートがあれば、VPC内リソースとインターネットの両方に到達できます。一方、デフォルトルートを持たないサブネットに配置すれば、VPC内通信に限定した構成も取れます。
プライベートサブネットに配置したRDS、ElastiCache、内部APIなどにMicroVMから接続したい場合は、VPC Egressコネクタを利用します。本記事では、その接続先の代替としてEC2上の簡易HTTPサーバーを用意し、VPC Egressコネクタ経由で到達できるかを検証します。RDS/ElastiCacheへの接続検証は本記事のスコープ外です。
この記事では以下を検証します。
- VPC Egressコネクタの作成手順と状態遷移
- NAT Gateway経由のコネクタでの到達性
- デフォルトルートを持たない閉域コネクタでの到達性
- セキュリティグループによるアクセス制御
- ENIの実態とライフサイクル
- 複数コネクタ指定時の挙動
- サブネット跨ぎ通信
- DNS解決
- コネクタ削除時のMicroVMへの影響
検証環境の準備
VPC構成
CloudFormationで以下の構成を作成しました。
- VPC:
10.0.0.0/16(DNS Hostnames / DNS Supportともに有効) - NATサブネット(
10.0.0.0/24, ap-northeast-1a): Regional NAT Gateway経由でインターネット疎通あり - 閉域サブネット(
10.0.1.0/24, ap-northeast-1a): ルートテーブルにデフォルトルートなし、VPC内通信のみ - ターゲットEC2: NATサブネット内、port 80で簡易HTTPサーバー(JSONレスポンスを返す)
セキュリティグループの設計
VPC Egressコネクタでは、コネクタ側のSGがMicroVMからの出口トラフィックを制御します。ターゲット側のSGでは、コネクタSGをソースとしてインバウンドを許可する設計です。
| SG | 用途 | ルール |
|---|---|---|
| connector-sg | NAT経由コネクタ用 | Egress: 全開放(0.0.0.0/0) |
| connector-isolated-sg | 閉域コネクタ用 | Egress: VPC内のみ(10.0.0.0/16) |
| target-sg | ターゲットEC2用 | Ingress: 上記2つのSGからport 80を許可 |
この設計により、ターゲット側でコネクタ経由のトラフィックのみを許可できます。
CloudFormationテンプレート(vpc.yaml)
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Lambda MicroVMs VPC Egress Test - Regional NAT Gateway + Isolated Subnet'
Parameters:
ProjectName:
Type: String
Default: 'microvms-egress-test'
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: '10.0.0.0/16'
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Ref ProjectName
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub '${ProjectName}-igw'
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
NATGatewayEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
- Key: Name
Value: !Sub '${ProjectName}-nat-eip'
RegionalNATGateway:
Type: AWS::EC2::NatGateway
DependsOn: InternetGatewayAttachment
Properties:
AvailabilityMode: regional
ConnectivityType: public
VpcId: !Ref VPC
AvailabilityZoneAddresses:
- AvailabilityZone: !Select [0, !GetAZs '']
AllocationIds:
- !GetAtt NATGatewayEIP.AllocationId
Tags:
- Key: Name
Value: !Sub '${ProjectName}-regional-nat-gw'
NATSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: '10.0.0.0/24'
AvailabilityZone: !Select [0, !GetAZs '']
Tags:
- Key: Name
Value: !Sub '${ProjectName}-nat-subnet-1a'
NATRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub '${ProjectName}-nat-rt'
NATRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref NATRouteTable
DestinationCidrBlock: '0.0.0.0/0'
NatGatewayId: !Ref RegionalNATGateway
NATSubnetAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref NATSubnet
RouteTableId: !Ref NATRouteTable
IsolatedSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: '10.0.1.0/24'
AvailabilityZone: !Select [0, !GetAZs '']
Tags:
- Key: Name
Value: !Sub '${ProjectName}-isolated-subnet-1a'
IsolatedRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub '${ProjectName}-isolated-rt'
IsolatedSubnetAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref IsolatedSubnet
RouteTableId: !Ref IsolatedRouteTable
ConnectorSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: 'SG for MicroVM VPC Egress Connector (NAT subnet)'
VpcId: !Ref VPC
SecurityGroupEgress:
- IpProtocol: '-1'
CidrIp: '0.0.0.0/0'
Tags:
- Key: Name
Value: !Sub '${ProjectName}-connector-sg'
ConnectorIsolatedSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: 'SG for MicroVM VPC Egress Connector (isolated subnet)'
VpcId: !Ref VPC
SecurityGroupEgress:
- IpProtocol: '-1'
CidrIp: '10.0.0.0/16'
Tags:
- Key: Name
Value: !Sub '${ProjectName}-connector-isolated-sg'
TargetSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: 'SG for target resource in VPC'
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ConnectorSG
Description: 'From MicroVM connector (NAT)'
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ConnectorIsolatedSG
Description: 'From MicroVM connector (isolated)'
Tags:
- Key: Name
Value: !Sub '${ProjectName}-target-sg'
TargetInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64}}'
InstanceType: t4g.nano
SubnetId: !Ref NATSubnet
SecurityGroupIds:
- !Ref TargetSG
UserData:
Fn::Base64: |
#!/bin/bash
dnf install -y python3
cat > /home/ec2-user/server.py << 'EOF'
import http.server, json, time, socket
class H(http.server.BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-Type','application/json')
self.end_headers()
self.wfile.write(json.dumps({"source":"vpc-target","host":socket.gethostname(),"time":time.time()}).encode())
http.server.HTTPServer(('0.0.0.0',80),H).serve_forever()
EOF
python3 /home/ec2-user/server.py &
Tags:
- Key: Name
Value: !Sub '${ProjectName}-target'
スタックのデプロイは以下のコマンドで実行しました。
aws cloudformation deploy \
--stack-name microvms-egress-test \
--template-file vpc.yaml \
--region ap-northeast-1
NetworkConnectorOperatorRoleの作成
VPC Egressコネクタを作成するには、Lambda基盤がCustomerアカウントのVPCにENIを作成するためのIAMロールが必要です。
信頼ポリシーでは lambda.amazonaws.com を信頼し、aws:SourceAccount 条件で自アカウントに限定します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "XXXXXXXXXXXX"
}
}
}
]
}
権限ポリシーではENIの作成・削除・タグ付けを許可します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterface",
"ec2:DeleteNetworkInterface",
"ec2:CreateTags"
],
"Resource": "*"
}
]
}
aws iam create-role \
--role-name NetworkConnectorOperatorRole \
--assume-role-policy-document file://trust-policy.json
aws iam put-role-policy \
--role-name NetworkConnectorOperatorRole \
--policy-name NetworkConnectorENIPolicy \
--policy-document file://eni-policy.json
コネクタ作成と状態遷移
NAT経由コネクタの作成
NATサブネットとコネクタ用SG(Egress全開放)を指定してコネクタを作成します。
aws lambda-core create-network-connector \
--connector-name nat-egress-connector \
--connector-type VPC_EGRESS \
--vpc-config SubnetIds=subnet-XXXXXXXXXXXXXXXXX,SecurityGroupIds=sg-XXXXXXXXXXXXXXXXX \
--operator-role-arn arn:aws:iam::XXXXXXXXXXXX:role/NetworkConnectorOperatorRole \
--region ap-northeast-1
{
"NetworkConnector": {
"ConnectorArn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:network-connector:nat-egress-connector",
"ConnectorName": "nat-egress-connector",
"ConnectorIdentifier": "nc-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"ConnectorType": "VPC_EGRESS",
"State": "PENDING",
"VpcConfig": {
"SubnetIds": ["subnet-XXXXXXXXXXXXXXXXX"],
"SecurityGroupIds": ["sg-XXXXXXXXXXXXXXXXX"],
"VpcId": "vpc-XXXXXXXXXXXXXXXXX"
},
"OperatorRoleArn": "arn:aws:iam::XXXXXXXXXXXX:role/NetworkConnectorOperatorRole"
}
}
閉域コネクタの作成
閉域サブネットとコネクタ用SG(EgressをVPC内のみに限定)を指定します。
aws lambda-core create-network-connector \
--connector-name isolated-egress-connector \
--connector-type VPC_EGRESS \
--vpc-config SubnetIds=subnet-XXXXXXXXXXXXXXXXX,SecurityGroupIds=sg-XXXXXXXXXXXXXXXXX \
--operator-role-arn arn:aws:iam::XXXXXXXXXXXX:role/NetworkConnectorOperatorRole \
--region ap-northeast-1
状態遷移: PENDING → ACTIVE
今回の検証では、いずれのコネクタも約4〜5分でPENDINGからACTIVEに遷移しました。ACTIVEになるまでMicroVMにアタッチして使用することはできません。
aws lambda-core get-network-connector \
--identifier nc-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX \
--region ap-northeast-1
MicroVM起動と接続確認
MicroVMの起動
run-microvm の --egress-network-connectors パラメータでコネクタARNを指定します。
aws lambda-microvms run-microvm \
--microvm-image-identifier arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:microvm-image:egress-test-app-v3 \
--egress-network-connectors ConnectorArn=arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:network-connector:nat-egress-connector \
--region ap-northeast-1
検証用MicroVMでは /fetch?url=<URL> エンドポイントで内部から外向きHTTPリクエストを実行します。
NAT経由コネクタの検証
NAT経由コネクタをアタッチしたMicroVMから、VPC内ターゲットとインターネットの両方に到達できることを確認しました。
| 接続先 | 結果 |
|---|---|
| VPC内ターゲット (10.0.0.126) | ✅ 200 OK |
| インターネット (checkip.amazonaws.com) | ✅ 到達、出口IP = NAT GW EIP |
VPC内ターゲットへの接続:
curl "https://<microvm-endpoint>/fetch?url=http://10.0.0.126"
{"status": 200, "body": "{\"source\": \"vpc-target\", \"host\": \"ip-10-0-0-126\", \"time\": 1750668000.0}"}
インターネットへの接続:
curl "https://<microvm-endpoint>/fetch?url=http://checkip.amazonaws.com"
XX.XXX.XXX.XXX
出口IPはNAT GatewayのEIPと一致しました。本構成では、コネクタを配置したサブネットのデフォルトルートがNAT Gatewayを向いているため、MicroVMからのインターネット向けトラフィックはNAT Gatewayを経由します。
閉域コネクタの検証
閉域コネクタをアタッチしたMicroVMでは、VPC内ターゲットには到達できましたが、インターネットには到達できませんでした。
| 接続先 | 結果 |
|---|---|
| VPC内ターゲット (10.0.0.126) | ✅ 200 OK |
| インターネット (checkip.amazonaws.com) | ❌ タイムアウト |
VPC内ターゲットへの接続:
curl "https://<microvm-endpoint>/fetch?url=http://10.0.0.126"
{"status": 200, "body": "{\"source\": \"vpc-target\", \"host\": \"ip-10-0-0-126\", \"time\": 1750668100.0}"}
インターネットへの接続:
curl "https://<microvm-endpoint>/fetch?url=http://checkip.amazonaws.com"
タイムアウトとなり、接続できませんでした。
インターネットに到達できない主因は、閉域サブネットのルートテーブルにデフォルトルート(0.0.0.0/0)が存在しないことです。コネクタSGのEgress制限(VPC内のみ)は追加の防御層として機能します。
サブネット跨ぎ通信
閉域コネクタ(10.0.1.0/24)をアタッチしたMicroVMから、NATサブネット(10.0.0.0/24)内のターゲットEC2に到達できました。VPCのローカルルート(10.0.0.0/16 → local)により、コネクタが配置されたサブネットとは異なるサブネットのリソースにも到達できます。
VPC内DNS解決
MicroVMからターゲットEC2のプライベートDNS名を使って接続できるかを確認しました。
curl "https://<microvm-endpoint>/fetch?url=http://ip-10-0-0-126.ap-northeast-1.compute.internal"
{"status": 200, "body": "{\"source\": \"vpc-target\", \"host\": \"ip-10-0-0-126\", \"time\": 1750668200.0}"}
本検証環境では、VPCの EnableDnsHostnames と EnableDnsSupport が有効な状態で、MicroVMからEC2のプライベートDNS名を名前解決し、接続できることを確認しました。
セキュリティグループによるフィルタリング
ターゲットEC2のSG(target-sg)からコネクタSGのインバウンド許可を削除し、MicroVMからの接続がタイムアウトすることを確認しました。
SGのインバウンドルールを削除した状態で同じリクエストを送ると、接続がタイムアウトしました。ルールを戻すと再び200 OKが返ります。コネクタSGをソースとしたSG間参照が正しく機能していることが確認できました。
ENIの実態
本検証では、ENIはコネクタ作成時にLambda基盤側で作成され、MicroVMの起動・停止に伴うENI数の増減は確認されませんでした。
MicroVM増加とENI数の関係
VPC内のENI数を describe-network-interfaces で監視しながらMicroVMを複数台起動しました。
| タイミング | 自アカウントから確認できたENI数 | 備考 |
|---|---|---|
| コネクタACTIVE後 | 1 | ターゲットEC2のENIのみ |
| MicroVM 1台目起動(NAT経由) | 1 | 増加なし |
| MicroVM 2台目起動(同コネクタ) | 1 | 増加なし |
| MicroVM 3台目起動(閉域) | 1 | 増加なし |
MicroVMを何台起動しても、自アカウントから確認できるCustomer VPC内のENI数は増加しませんでした。
CloudTrailイベントから読み解くENIライフサイクル
CloudTrailで CreateNetworkInterface イベントを追跡したところ、本検証では以下の挙動を観測しました。
- ENIはコネクタ作成時(
create-network-connector実行時)に作成されていた - MicroVMの起動・停止時には、ENIの作成・削除イベントは確認されなかった
- コネクタ削除時に
DeleteNetworkInterfaceが呼ばれていた - 今回作成した各コネクタでは、2回の
CreateNetworkInterfaceが記録されていた- 1回目:
request-validation-session(セッション名から権限検証目的と推測されるENI) - 2回目: 実稼働用とみられるENI
- 1回目:
CloudTrailイベントの主要な属性は以下のとおりです。
| 属性 | 値 |
|---|---|
| invokedBy | network-connectors.lambda.amazonaws.com |
| AssumedRole | NetworkConnectorOperatorRole |
| タグ | aws:lambda:networkConnectorName, aws:lambda:networkConnectorId |
Hyperplane ENIとの類似性
describe-network-interfaces でENIを直接参照すると InvalidNetworkInterfaceID.NotFound になりました。CloudTrail上ではLambda基盤によるENI作成が確認できるため、Customer VPCのサブネット側に作成される一方で、自アカウントからは直接参照できないクロスアカウントENIとして扱われていることを示唆しています。
この挙動は、従来のLambda関数をVPCに接続する際のHyperplane ENIと観測上似た特徴を持っています。コネクタ単位でENIを共有し、複数MicroVMのEgressトラフィックを集約する構造と推測されます。
制約検証
複数VPC Egressコネクタの同時指定
--egress-network-connectors に複数のコネクタARNを指定してMicroVMの起動を試みました。
aws lambda-microvms run-microvm \
--microvm-image-identifier arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:microvm-image:egress-test-app-v3 \
--egress-network-connectors \
ConnectorArn=arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:network-connector:nat-egress-connector \
ConnectorArn=arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:network-connector:isolated-egress-connector \
--region ap-northeast-1
結果はInternalFailureでした。CLI上は複数要素を指定できましたが、実行結果はInternalFailureとなり、複数コネクタを同時指定したMicroVM起動は成功しませんでした。
コネクタ削除時のMicroVMへの影響
稼働中のMicroVMにアタッチされているコネクタを削除した場合の挙動を確認しました。
aws lambda-core delete-network-connector \
--identifier nc-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX \
--region ap-northeast-1
| 項目 | 結果 |
|---|---|
| MicroVMの状態 | RUNNING継続(停止しない) |
| Ingress(HTTP_INGRESS経由のアクセス) | ✅ 正常 |
| Egress(VPC内ターゲットへの接続) | ❌ タイムアウト |
まとめ
VPC Egressコネクタを使うことで、Lambda MicroVMsからVPC内のプライベートリソースへ接続できることを確認しました。今回の検証では、EC2上の簡易HTTPサーバーをターゲットにし、NAT Gateway経由のコネクタと、デフォルトルートを持たない閉域コネクタの2構成で到達性を確認しました。
NAT Gatewayへのデフォルトルートがあるサブネットにコネクタを配置した場合は、VPC内ターゲットとインターネットの両方に到達できました。一方、デフォルトルートを持たない閉域サブネットに配置した場合は、VPC内ターゲットには到達できましたが、インターネット向け通信はタイムアウトしました。
コネクタの利用には NetworkConnectorOperatorRole の準備と、ACTIVE になるまでの待機が必要です。本検証では、コネクタ作成から ACTIVE になるまで約4〜5分かかりました。また、作成済みのコネクタを複数のMicroVMで利用でき、数台規模の起動では自アカウントから確認できるVPC内ENI数は増加しませんでした。
プライベートサブネット上のデータベースや内部APIなど、VPC内リソースへLambda MicroVMsから接続したい場合に、VPC Egressコネクタは有効な選択肢になりそうです。
参考リンク







