Closed6
VPC Lambda構成にした際にNATゲートウェイやVPCエンドポイントを使用しを使わずにインターネットアクセスした場合の挙動

APIサーバをVPC Lambda構成で以下のように、NATゲートウェイを利用してインターネットアクセスしていたが、そもそも個人環境で秘匿情報等もほぼないのと、料金が高くつくため放置してもそこまで高くない構成にしようと思い、VPCエンドポイントを使用してインターネットアクセスが可能な構成に変更しようと考えた。
元々そのような構成のもの触っているものの、実際にVPCエンドポイントがないとどのような挙動になるのかまでは終えていなかったため、ログを残す。
※期待値としては、Lambda→SQSにキューイングする構成にしており、その際に何らかエラーが出る想定
まずは以下のようにLambda Functionをプライベートサブネットからパブリックサブネットに移動。
resource "aws_lambda_function" "shop_api" {
function_name = "dev-shop-api"
description = "Shop API"
role = aws_iam_role.shop_api.arn
package_type = "Image"
image_uri = "${data.terraform_remote_state.ecr.outputs.shop_api.url}:shop_api_v0.0.0"
timeout = 20
memory_size = 128
vpc_config {
ipv6_allowed_for_dual_stack = false
security_group_ids = [aws_security_group.shop_api.id]
subnet_ids = data.terraform_remote_state.network.outputs.vpc.public_subnet_ids
# subnet_ids = data.terraform_remote_state.network.outputs.vpc.private_subnet_ids # NOTE: NAT使いたくないのでプライベートサブネットは使わない
}
lifecycle {
ignore_changes = [image_uri]
}
// 省略
}

これでAPIリクエストを送信すると、Lambda側で以下のようなエラーのログを確認できる。
2025/04/05 17:58:00 ERROR failed to send queue message error="failed to send message to SQS: operation error SQS: SendMessage, exceeded maximum number of attempts, 3, https response error StatusCode: 0, RequestID: , request send failed, Post \"https://sqs.ap-northeast-1.amazonaws.com/\": dial tcp 18.183.37.28:443: connect: connection timed out"

どうやら、Lambda 関数から SQS にメッセージを送信しようとした際に、ネットワーク接続がタイムアウトして失敗したことを示している模様。
-
exceeded maximum number of attempts, 3
: 3回リトライしても失敗。 -
connect: connection timed out
: 接続タイムアウト。 -
dial tcp ...:443
: TCP 443 ポートへの接続ができない。 -
宛先
: sqs.ap-northeast-1.amazonaws.com(SQSエンドポイント)
ようするに、VPC に接続された Lambda は、ENI経由で Subnet に入るが、Public IP を持たず、NAT もない場合は外に出られない。
なので、SQS 用の VPC エンドポイントを作成して、Lambda が SQS に直接プライベートネットワークでアクセスできるように設定する。

この辺りを見てた

前提として、以下の外部通信向けのセキュリティグループは既に定義済み
resource "aws_security_group" "shop_api" {
name = "dev-shop-api-sg"
description = "Security group for API service running in the VPC"
vpc_id = data.terraform_remote_state.network.outputs.vpc.id
}
resource "aws_vpc_security_group_egress_rule" "shop_api_egress" {
security_group_id = aws_security_group.shop_api.id
description = "Allow Lambda to access external resources (e.g. RDS, DynamoDB, APIs)"
ip_protocol = "-1"
cidr_ipv4 = "0.0.0.0/0"
}

以下できればおそらく動くはず。
- VPC エンドポイントとそれのセキュリティグループの作成
- Lambda Function 側で設定したセキュリティグループに上記で作成したセキュリティグループを追加
SQS用のVPCエンドポイント
resource "aws_vpc_endpoint" "sqs" {
vpc_id = data.terraform_remote_state.network.outputs.vpc.id
service_name = "com.amazonaws.ap-northeast-1.sqs"
vpc_endpoint_type = "Interface"
subnet_ids = data.terraform_remote_state.network.outputs.vpc.public_subnet_ids # エンドポイントに関連付けるセキュリティグループ
security_group_ids = [aws_security_group.vpc_endpoint_sqs.id] # プライベートDNSを有効にすることで、内部DNSでアクセス可能に
private_dns_enabled = true
}
VPC エンドポイント用のセキュリティグループの作成
# VPC エンドポイント用のセキュリティグループ
resource "aws_security_group" "vpc_endpoint_sqs" {
name = "${local.fqn}-api-vpc-endpoint-sqs"
description = "Allow SQS VPC endpoint"
vpc_id = data.terraform_remote_state.network.outputs.vpc.id
}
# Lambda 用セキュリティグループ(shop_api)から SQS VPC エンドポイントのセキュリティグループへの HTTPS(443番ポート)アクセスを許可
resource "aws_security_group_rule" "allow_https_from_lambda" {
type = "ingress"
from_port = 443
to_port = 443
protocol = "tcp"
security_group_id = aws_security_group.vpc_endpoint_sqs.id # ルールを適用するセキュリティグループID(VPCエンドポイント用SG)
source_security_group_id = aws_security_group.shop_api.id # ルールを適用する元セキュリティグループID(Lambda用SG)
description = "Allow Lambda SG to access VPC Endpoint"
}
このスクラップは5ヶ月前にクローズされました