はじめに

AWS Lambdaを使用していると、「連携先のAPIがIP制限(ホワイトリスト)をかけているため、Lambdaからのアクセスを固定IPにしたい」という要件に直面することがあります。

LambdaはデフォルトではIPアドレスが動的に変わるため、VPCNAT Gatewayを組み合わせる構成をとるのが一般的です。

今回は、この構成をCloudFormationを使って構築し、Go言語のLambda関数で実際に固定IP化を確認する手順を解説します。

ソースコード

以下のソースコードを元に解説していきます。
https://github.com/tkhs1121/fix-ip-lambda-cloudformation-template

アーキテクチャ概要

Lambda単体では固定IPを持てないため、以下のリソースを組み合わせます。

  1. VPC: カスタムVPCを作成します。
  2. Public Subnet: インターネットへの出口となる NAT Gateway を配置し、Elastic IP (固定IP) を割り当てます。
  3. Private Subnet: Lambda関数 を配置します。
  4. Routing: Lambdaからのインターネット向け通信を NAT Gateway へルーティングします。

これにより、Lambdaがインターネットへ出る際は必ずNAT Gatewayを経由するため、通信相手にはNAT GatewayのElastic IPが送信元として見えます。

実装例の環境

本記事のコード例では以下の環境を使用しますが、VPC構成の考え方は他の言語やランタイムでも共通です。

  • IaC: AWS CloudFormation (AWS SAM)
  • Language: Go (v1.26)
  • Runtime: provided.al2023
  • Architecture: arm64

CloudFormationテンプレートのポイント

1. ネットワーク構築 (VPC/Subnet/NAT Gateway)

最も重要なのは、NAT Gatewayルートテーブル の設定です。

template-vpc.yaml では以下のように定義しています。

  • NAT Gateway: パブリックサブネットに配置し、EIP (Elastic IP) を割り当てます。
  • ルートテーブル: プライベートサブネットの 0.0.0.0/0 (インターネット行き) のターゲットを NAT Gateway に向けます。

2. Lambda関数のVPC設定

Lambda関数をVPC内に配置するには、VpcConfig プロパティでサブネットとセキュリティグループを指定します。

# template-lambda.yaml (抜粋)
      VpcConfig:
        SecurityGroupIds: [!ImportValue FixIPLambda-SecurityGroup]
        SubnetIds: [!ImportValue FixIPLambda-PrivateSubnet1] # プライベートサブネットを指定

デプロイ手順

VPCとLambdaの依存関係があるため、以下の順序でデプロイします。

下準備

# デプロイ先のリージョン(例: オレゴン)
export TargetRegion="us-west-2"
export AppName="fix-ip-lambda"
# S3バケット名は全世界で一意である必要があるためリージョン名を含める
export BucketName="${AppName}-${TargetRegion}"

Step 1: アーティファクト用S3バケットの作成

aws cloudformation deploy \
    --stack-name "${AppName}-s3" \
    --template-file template-s3.yaml \
    --parameter-overrides BucketName="${BucketName}" \
    --region "${TargetRegion}"

Step 2: VPCネットワークの構築

ここでNAT GatewayとElastic IPが作成されます。

aws cloudformation deploy \
    --stack-name "${AppName}-vpc" \
    --template-file template-vpc.yaml \
    --capabilities CAPABILITY_IAM \
    --region "${TargetRegion}"

Step 3: Lambda関数のデプロイ

AWS SAM CLIを使ってビルド・デプロイを行います。

# ビルド
sam build --template-file template-lambda.yaml

# デプロイ
sam deploy \
    --stack-name  "${AppName}-exec" \
    --s3-bucket "${BucketName}" \
    --capabilities CAPABILITY_IAM \
    --region "${TargetRegion}" \
    --parameter-overrides \
        URL="https://httpbin.org/ip" \
        FixIPEnabled="true"

動作確認

デプロイ完了後、Lambdaを実行してログを確認します。
https://httpbin.org/ip などのIP確認サービスへアクセスし、レスポンスに含まれるIPアドレスが、VPCスタックで作成された Elastic IP と一致していれば成功です。

// main.go (抜粋)
func handler() (string, error) {
    // ...
    resp, err := http.Get(url)
    // ...
    // ここで返ってくるIPが固定IPになっているか確認
    fmt.Println("Reponse from", url, ":", responseBody)
    return responseBody, nil
}

コストに関する注意点

この構成はIP固定化の標準的な手法ですが、コストには注意が必要です。

  • NAT Gateway: 起動している時間に対して課金されます(東京リージョン 約 $0.062/時間 ≒ 月額 $45 前後 ※リージョンによる)。
  • データ転送: NAT Gatewayを経由するデータ通信量に応じた料金も発生します。

検証目的で作成した場合は、不要になったら以下のコマンドでスタックを削除し、課金を停止することを推奨します。

# 削除順序: Lambda -> VPC -> S3
aws cloudformation delete-stack --stack-name "${AppName}-exec" --region "${TargetRegion}"
aws cloudformation delete-stack --stack-name "${AppName}-vpc" --region "${TargetRegion}"
# S3は中身を空にしてから削除
aws s3 rm s3://${BucketName} --recursive
aws cloudformation delete-stack --stack-name "${AppName}-s3" --region "${TargetRegion}"

まとめ

  • LambdaのIP固定化には VPC + NAT Gateway 構成を使用する。
  • Lambdaは プライベートサブネット に配置し、インターネット通信を NAT Gateway に向ける。
  • NAT Gatewayはコストがかかるため、運用設計時に費用対効果を考慮する。