AWS Lambda “функция не смогла подключиться к файловой системе Amazon EFS”

Вопрос или проблема

Я уже несколько дней пытаюсь настроить работу развертывания Lambda+EFS

Я использую Pulumi на Python

Все, что я пробовал, заканчивается:

Ошибка вызова API: Функция не смогла подключиться к файловой системе Amazon EFS с арном точки доступа arn:aws:elasticfilesystem:eu-west-2:003478557222:access-point/fsap-0bf5cec491c7daa7d. Проверьте свою сетевую конфигурацию и повторите попытку.

Я хочу, чтобы они оба находились в частной подсети без NAT-шлюза

В этой статье:
https://docs.aws.amazon.com/lambda/latest/dg/troubleshooting-invocation.html#troubleshooting-invocation-efsconnect
…говорится, что эта ошибка вызвана:

Функция не смогла установить соединение с файловой системой функции с протоколом NFS (TCP порт 2049). Проверьте настройки группы безопасности и маршрутизации для подсетей VPC.

Сначала я думал, что могу поместить Lambda и точку монтирования EFS в одну и ту же группу безопасности, и тогда не нужны будут явные правила входящего/исходящего трафика NFS. Насколько я понимаю, это не сработало.

В процессе следования различным советам и документации я в итоге получил две группы безопасности (например, как описано здесь: https://docs.aws.amazon.com/efs/latest/ug/network-access.html), одна из которых имеет исходящий NFS, а другая – входящий. Это тоже не работает.

Я начинаю подозревать, что эта ошибка может иметь другую причину, так как, по моим подсчетам, я попробовал почти все комбинации правил ГС, пытаясь обеспечить подключение.

Но, возможно, я совершил какую-то глупость, которую не замечаю.

Мой текущий код выглядит так:

vpc = awsx.ec2.Vpc(
    "myvpc",
    subnet_specs=[
        awsx.ec2.SubnetSpecArgs(type=awsx.ec2.SubnetType.PUBLIC),
        awsx.ec2.SubnetSpecArgs(type=awsx.ec2.SubnetType.PRIVATE),
    ],
    subnet_strategy=awsx.ec2.SubnetAllocationStrategy.AUTO,
    number_of_availability_zones=1,
    nat_gateways=awsx.ec2.NatGatewayConfigurationArgs(
        strategy=awsx.ec2.NatGatewayStrategy.NONE,
    ),
    # разрешить конечные точки VPC:
    enable_dns_hostnames=True,
    enable_dns_support=True,
)
lambda_sg = aws.ec2.SecurityGroup(
    "lambda-sg",
    vpc_id=vpc.vpc_id,
    ingress=[],
    egress=[],
)
def lambda_sg_rules(subnet_ids: Sequence[str]):
    subnets = [aws.ec2.get_subnet(id=subnet_id) for subnet_id in subnet_ids]
    cidr_blocks = [subnet.cidr_block for subnet in subnets]
    aws.ec2.SecurityGroupRule(
        "lambda-sg-ingress-https",
        security_group_id=lambda_sg.id,
        type="ingress",
        from_port=443,
        to_port=443,
        protocol="tcp",
        cidr_blocks=pulumi.Output.all(*cidr_blocks),
    )
    aws.ec2.SecurityGroupRule(
        "lambda-sg-egress-nfs",
        security_group_id=lambda_sg.id,
        type="egress",
        from_port=2049,
        to_port=2049,
        protocol="tcp",
        cidr_blocks=pulumi.Output.all(*cidr_blocks),
    )
vpc.private_subnet_ids.apply(lambda_sg_rules)

efs_sg = aws.ec2.SecurityGroup(
    "efs-sg",
    vpc_id=vpc.vpc_id,
    ingress=[],
    egress=[],
)
aws.ec2.SecurityGroupRule(
    "efs-sg-ingress-nfs",
    security_group_id=efs_sg.id,
    type="ingress",
    from_port=2049,
    to_port=2049,
    protocol="tcp",
    source_security_group_id=lambda_sg.id,
)
aws.ec2.SecurityGroupRule(
    "efs-sg-egress-all",
    security_group_id=efs_sg.id,
    type="egress",
    from_port=0,
    to_port=0,
    protocol="-1",
    cidr_blocks=["0.0.0.0/0"],
)

# если Lambda находится в частной подсети без NAT, то нужно добавить конечные точки VPC
for service in ("ssm", "ssmmessages", "ec2messages", "logs", "elasticfilesystem"):
    aws.ec2.VpcEndpoint(
        f"{service}-endpoint",
        vpc_id=vpc.vpc_id,
        service_name=f"com.amazonaws.{aws.get_region().name}.{service}",
        vpc_endpoint_type="Interface",
        private_dns_enabled=True,
        subnet_ids=vpc.private_subnet_ids,
        security_group_ids=[lambda_sg.id, efs_sg.id],
    )

db_efs = aws.efs.FileSystem("db-filesystem")
aws.efs.BackupPolicy(
    "db-filesystem-backup-policy",
    file_system_id=db_efs.id,
    backup_policy=aws.efs.BackupPolicyBackupPolicyArgs(status="ENABLED"),
)
db_efs_mount_targets = vpc.public_subnet_ids.apply(
    lambda subnet_ids: [
        aws.efs.MountTarget(
            f"db-filesystem-mount-target-subnet-{i}",
            file_system_id=db_efs.id,
            subnet_id=subnet_id,
            security_groups=[lambda_sg.id],
        )
        for i, subnet_id in enumerate(subnet_ids)
    ]
)
aws.efs.AccessPointRootDirectoryCreationInfoArgs
db_efs_access_point = aws.efs.AccessPoint(
    "db-filesystem-accesspoint",
    file_system_id=db_efs.id,
    posix_user=aws.efs.AccessPointPosixUserArgs(
        uid=1000,
        gid=1000,
    ),
    root_directory=aws.efs.AccessPointRootDirectoryArgs(
        path="/dbroot",
        creation_info=aws.efs.AccessPointRootDirectoryCreationInfoArgs(
            owner_gid=1000,
            owner_uid=1000,
            permissions="755",
        ),
    ),
    opts=pulumi.ResourceOptions(depends_on=db_efs_mount_targets),
)

lambda_network_policy = aws.iam.get_policy_document(
    statements=[
        aws.iam.GetPolicyDocumentStatementArgs(
            effect="Allow",
            actions=[
                "ec2:CreateNetworkInterface",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DeleteNetworkInterface",
            ],
            resources=["*"],
        ),
    ]
)
lambda_logging_policy = aws.iam.get_policy_document(
    statements=[
        aws.iam.GetPolicyDocumentStatementArgs(
            effect="Allow",
            actions=[
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
            ],
            resources=["arn:aws:logs:*:*:*"],
        )
    ]
)
djangoadmin_lambda_role = aws.iam.Role(
    "djangoadmin-lambda-role",
    assume_role_policy=lambda_assume_role_policy.json,
    managed_policy_arns=[
        "arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy",
        "arn:aws:iam::aws:policy/AmazonElasticFileSystemClientReadWriteAccess",
    ],
)
aws.iam.RolePolicy(
    "djangoadmin-lambda-network-policy",
    role=djangoadmin_lambda_role.name,
    policy=lambda_network_policy.json,
)
aws.iam.RolePolicy(
    "djangoadmin-lambda-logging-policy",
    role=djangoadmin_lambda_role.name,
    policy=lambda_logging_policy.json,
)

djangoadmin_lambda_log_group = aws.cloudwatch.LogGroup(
    "djangoadmin-lambda-log-group",
    name=f"/aws/lambda/{APP_NAME}",
    retention_in_days=30,
)
djangoadmin_lambda = aws.lambda_.Function(
    "djangoadmin-lambda",
    opts=pulumi.ResourceOptions(depends_on=[djangoadmin_lambda_log_group]),
    package_type="Image",
    image_uri=lambda_image_uri,
    architectures=["arm64"],
    memory_size=512,
    timeout=30,
    reserved_concurrent_executions=1,  # ограничить максимальную параллельность
    file_system_config=aws.lambda_.FunctionFileSystemConfigArgs(
        arn=db_efs_access_point.arn,
        local_mount_path="/mnt/efs",
    ),
    role=djangoadmin_lambda_role.arn,
    environment=aws.lambda_.FunctionEnvironmentArgs(
        variables={
            "AWS_LWA_PORT": "5000",
        },
    ),
    vpc_config=aws.lambda_.FunctionVpcConfigArgs(
        subnet_ids=vpc.private_subnet_ids,
        security_group_ids=[lambda_sg.id],
    ),
    logging_config=aws.lambda_.FunctionLoggingConfigArgs(
        log_format="JSON",
        log_group=djangoadmin_lambda_log_group.name,
    ),
)

Ответ или решение

Если ваша функция AWS Lambda не может подключиться к файловой системе Amazon EFS, есть несколько ключевых аспектов, которые могут вызвать проблему. Давайте подробно рассмотрим возможные причины и их решения, основываясь на предоставленном сценарии и конфигурации.

1. Сетевые настройки VPC

Ваша конфигурация показывает, что вы создали VPC с частными подсетями и без NAT-шлюза. Это может стать проблемой, если ваша Lambda-функция и EFS находятся в разных сетевых сегментах. Поскольку вы нацелены на частные подсети, убедитесь, что обе службы находятся в одной VPC и частных подсетях.

Рекомендации:

  • Проверьте, что Lambda-функция и EFS Mount Target находятся в одной и той же VPC.
  • Убедитесь, что EFS доступен через NFS (TCP порт 2049), и что настройка маршрутизации корректна.

2. Настройки Security Group

Ваше текущее использование двух security group (SG) для Lambda и EFS – это правильный подход. Однако, необходимо проверить, корректные ли правила заданы для NFS.

Возможные проблемы:

  1. Security Group для Lambda:

    • Вы настроили egress правило для порта 2049, однако, возможно, оно не срабатывает должным образом.
    • Попробуйте добавить ingress правило в Security Group EFS, чтобы позволить трафик от вашей Lambda функции.
  2. Security Group для EFS:

    • Правило ingress NFS указывает на Security Group вашей Lambda, но убедитесь, что вы правильно указали source_security_group_id.

Примеры правил:

# Для Lambda
aws.ec2.SecurityGroupRule(
    "lambda-sg-egress-nfs",
    security_group_id=lambda_sg.id,
    type="egress",
    from_port=2049,
    to_port=2049,
    protocol="tcp",
    cidr_blocks=["0.0.0.0/0"],  # или более ограниченный CIDR для безопасности
)

# Для EFS
aws.ec2.SecurityGroupRule(
    "efs-sg-ingress-nfs",
    security_group_id=efs_sg.id,
    type="ingress",
    from_port=2049,
    to_port=2049,
    protocol="tcp",
    source_security_group_id=lambda_sg.id,
)

3. Проверка маршрутизации

Маршруты внутри VPC могут повлиять на ваше подключение. Убедитесь, что:

  • Подсети имеют маршруты на уровне VPC, и ваш EFS Mount Target доступен из частных подсетей Lambda.

4. Проверка конфигурации файловой системы

Убедитесь, что файловая система EFS правильно настроена:

  • Проверьте, что EFS Mounted Target без проблем доступен в ожидании соединений.
  • Проверьте, существует ли точка доступа EFS (Access Point) и правильно ли указаны пути и параметры доступа.

5. Логирование и диагностика

Для дальнейшей диагностики вы можете:

  • Включить дополнительное логирование в вашей Lambda-функции, чтобы отслеживать любые проблемы с подключением.
  • Используйте CloudWatch для анализа логов вашей Lambda, чтобы получить дополнительную информацию о произошедших ошибках.

Заключение

Чтобы успешно установить соединение между AWS Lambda и Amazon EFS, необходимо убедиться в корректной настройке сетевой инфраструктуры и безопасности. Следуя приведённым выше рекомендациям и внимательно проверяя конфигурацию, вы сможете устранить возникшие трудности. Если проблема не устраняется, рассмотрите возможность обращения в службу поддержки AWS для более детального анализа конфигурации.

Оцените материал
Добавить комментарий

Капча загружается...