2026, Jan 08 00:03

Почему AWS Lambda в VPC уходит в таймаут при доступе к S3 и как решить

Разбираем, почему AWS Lambda в VPC уходит в таймаут при обращении к S3: проблема в отсутствии доступа в Интернет. Решения: без VPC, NAT Gateway или VPC endpoint.

Если функция AWS Lambda, которая должна всего лишь получить список бакетов S3, стабильно упирается в таймаут на 30 секунд, первое желание — искать недостающие права или синтаксические ошибки. На практике почти всегда виновата сеть: код исполняется, но не успевает достучаться до конечной точки API S3.

Минимальный пример, который уходит в таймаут

Ниже функция на boto3, которая перечисляет бакеты S3. Она нарочно предельно простая, и всё же при отсутствии сетевого маршрута от Lambda к S3 она будет уходить в таймаут.

import boto3

def entrypoint(evt, ctx):
    s3_bucket_id = "<myS3_bucket>"
    object_key = "<path_to/file.csv>"

    s3res = boto3.resource('s3')
    for b in s3res.buckets.all():
        print(b.name)

Окружение IaC выдаёт функции права и назначает очень разрешающую группу безопасности, из-за чего таймаут поначалу выглядит странно.

resource "aws_iam_role" "exec_role" {
  name = "${var.fn_name}_role"
  assume_role_policy = jsonencode({
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = { Service = "lambda.amazonaws.com" }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "s3_full_access" {
  role       = aws_iam_role.exec_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
}

resource "aws_iam_role_policy_attachment" "logs_basic" {
  role       = aws_iam_role.exec_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

resource "aws_iam_role_policy_attachment" "vpc_access" {
  role       = aws_iam_role.exec_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
}
data "aws_vpc" "default_net" {
  default = true
}

resource "aws_security_group" "fn_sg" {
  name        = "sg_${var.fn_name}"
  description = "Allow all the ports needed for lambda"
  vpc_id      = data.aws_vpc.default_net.id

  ingress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
resource "aws_s3_bucket_policy" "fn_bucket_perms" {
  bucket = "superset-dockerfiles"
  policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Principal = { AWS = aws_iam_role.exec_role.arn },
        Action = ["s3:GetObject", "s3:ListBucket"],
        Resource = [
          "arn:aws:s3:::superset-dockerfiles",
          "arn:aws:s3:::superset-dockerfiles/*"
        ]
      }
    ]
  })
}

Что на самом деле вызывает таймаут

2025-05-16T14:37:13.093Z fdb6***4165 Task timed out after 30.03 seconds

Проблема не в boto3 и не в IAM. Функция работает внутри VPC, и по умолчанию Lambda в VPC не имеет доступа в Интернет. API S3 — в публичной сети. Без маршрута из VPC к публичной конечной точке S3 запросы не завершаются, и функция падает по таймауту. Одних правок правил security group недостаточно — это вопрос маршрутизации, а не фильтрации портов. Как уже отмечалось, таймаут — классический симптом отсутствия сетевой связности.

Как решить проблему

Есть три корректных варианта, и выбор зависит от того, нужно ли функции обращаться к приватным ресурсам внутри вашей VPC. Самое простое — запускать Lambda вне какой‑либо VPC. Когда функция не прикреплена к VPC, у неё по умолчанию есть доступ в Интернет, и она может напрямую обращаться к API S3. Если функция должна остаться в VPC, настройте приватные подсети с маршрутом на NAT Gateway, чтобы обеспечить исходящий доступ в Интернет из VPC. Либо добавьте в VPC endpoint для S3, чтобы функция могла работать с S3 без выхода в публичный Интернет.

Изменений в код Python для этой конкретной проблемы не требуется, потому что корень — в сетевой достижимости. Как только появляется валидный маршрут к S3, тот же вызов boto3 для перечисления бакетов выполняется успешно.

Почему это важно

Легко выдать нужные права и всё равно упереться в сетевые ограничения. Таймауты тратят время выполнения и скрывают истинную причину, особенно когда в логах нет явных ошибок подключения. Понимание того, что Lambda, подключённая к VPC, не имеет доступа в Интернет без явной настройки, помогает избежать неверных диагнозов и не гоняться за ложными следами в IAM или логике приложения.

Выводы

Если вашей функции Lambda не нужно общаться с приватными ресурсами, запускайте её вне VPC — так проще и надёжнее. Если нужно, обеспечьте либо NAT Gateway с корректной маршрутизацией для исходящего доступа в Интернет, либо создайте endpoint S3, чтобы вызовы к S3 оставались внутри сети AWS. При наличии корректного сетевого пути базовые операции boto3 — вроде перечисления бакетов или получения объектов — будут работать как ожидается.