Lambda MicroVMsのVPC EgressコネクタでVPC内プライベートリソースへの接続を検証してみた

Lambda MicroVMsのVPC EgressコネクタでVPC内プライベートリソースへの接続を検証してみた

Lambda MicroVMsのVPC Egressコネクタを作成し、NAT Gateway経由とデフォルトルートを持たない閉域サブネット構成の2パターンで、VPC内リソースへの到達性、セキュリティグループ制御、ENIのライフサイクルを検証しました。
2026.06.24

はじめに

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への影響

https://docs.aws.amazon.com/lambda/latest/dg/lambda-microvms-networking.html

検証環境の準備

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の EnableDnsHostnamesEnableDnsSupport が有効な状態で、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

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コネクタは有効な選択肢になりそうです。

参考リンク

https://docs.aws.amazon.com/cli/latest/reference/lambda-core/create-network-connector.html

https://docs.aws.amazon.com/cli/latest/reference/lambda-microvms/run-microvm.html

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事