Closed6

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

tamaco489tamaco489

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]
  }

  // 省略
}
tamaco489tamaco489

これで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"
tamaco489tamaco489

どうやら、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 に直接プライベートネットワークでアクセスできるように設定する。

tamaco489tamaco489

前提として、以下の外部通信向けのセキュリティグループは既に定義済み

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"
}

tamaco489tamaco489

以下できればおそらく動くはず。

  • 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ヶ月前にクローズされました