如何在 Amazon VPC 中使用 Lambda 函數來擷取 Secrets Manager 的保密內容?

3 分的閱讀內容
0

我在 Amazon Virtual Private Cloud (Amazon VPC) 中的 AWS Lambda 函數無法存取 AWS Secrets Manager。

簡短說明

Lambda 函數在安全的 Amazon VPC 中執行且可存取 AWS 服務和網際網路。Lambda 服務擁有此 Amazon VPC,而且其未連接到您的預設 Amazon VPC

您必須將 Amazon VPC 設定為提供存取權限,連接到 Amazon VPC 的 Lambda 函數才能存取網際網路。Lambda 在 Amazon VPC 內建立的網絡介面會使用私有 IP 地址,而且無法使用網際網路閘道連線到網際網路。

如需更多資訊,請參閱 VPC 連接函數的網際網路和服務存取權限

注意: 除非該函數必須存取 Amazon VPC 中的其他資源,否則最好不要將 Lambda 函數放置在 Amazon VPC 中。

解決方法

Lambda 網路組態

若要允許連接到 Amazon VPC 的 Lambda 函數存取 Secrets Manager,請使用下列其中一種方法:

將 NAT 閘道連接至私有子網路

為您的函數提供網際網路存取權。將函數放置在私有子網路中,並將輸出流量路由到公用子網路中的 NAT 閘道。NAT 閘道具備公用 IP 地址,並透過 VPC 的網際網路閘道連線到網際網路。

使用 Amazon VPC 介面端點

為 Secrets Manager 設定 Amazon VPC 介面端點。然後,您的 Amazon VPC 無需網際網路存取權限,即可從 Lambda 函數連接 Secrets Manager。確定 Amazon VPC 端點安全群組允許來自 Lambda 安全群組或 IP 地址範圍的連接埠 443 輸入流量。此外,確定 Lambda 安全群組允許連接埠 443 輸出流量連接至 Amazon VPC 端點安全群組或 IP 地址範圍。

注意: 如果您使用 AWS PrivateLink VPC 端點,請務必使用適用於網域名稱系統 (DNS) 的 Amazon VPC 來設定 DHCP 選項。如需更多資訊,請參閱 Amazon VPC 的 DNS 屬性

例如,下列 AWS CloudFormation 範本會在 VPC 的私有子網路內建立 Lambda 函數。這允許透過 VPC 端點私人存取 AWS Secrets Manager:

AWSTemplateFormatVersion: "2010-09-09"
Description: "Lambda Secrets Manager"
Resources:
    EC2SecurityGroup:
        Type: "AWS::EC2::SecurityGroup"
        Properties:
            GroupDescription: "launch-wizard-19 created 2022-03-23T11:10:16.721+05:30"
            GroupName: "launch-wizard-19"
            VpcId: !Ref EC2VPC
            SecurityGroupIngress:
              -
                CidrIp: "10.0.0.0/16"
                FromPort: 443
                IpProtocol: "tcp"
                ToPort: 443
            SecurityGroupEgress:
              -
                CidrIp: "10.0.0.0/16"
                FromPort: 443
                IpProtocol: "tcp"
                ToPort: 443


    LambdaFunction:
        Type: "AWS::Lambda::Function"
        Properties:
            Description: "AWS Lambda to AWS Secrets Manager"
            FunctionName: "SecretsManagerLambda"
            Handler: "index.lambda_handler"
            Architectures:
              - "x86_64"
            Code:
              ZipFile: |
                import json
                import boto3
                client = boto3.client('secretsmanager')

                def lambda_handler(event, context):
                    response = client.get_secret_value(
                    SecretId='string',
                    VersionId='string',
                    VersionStage='string'
                    )
                    print(response)
                    # TODO implement
                    return {
                        'statusCode': 200,
                        'body': json.dumps('Hello from Lambda!')
                    }



            MemorySize: 128
            Role: !GetAtt IAMRole.Arn
            Runtime: "python3.11"
            Timeout: 30
            TracingConfig:
                Mode: "PassThrough"
            EphemeralStorage:
                Size: 512
            VpcConfig:
              SecurityGroupIds:
                - !Ref EC2SecurityGroup
              SubnetIds:
                - !Ref EC2Subnet

    EC2VPC:
        Type: "AWS::EC2::VPC"
        Properties:
            CidrBlock: "10.0.0.0/16"
            EnableDnsSupport: true
            EnableDnsHostnames: true
            InstanceTenancy: "default"

    EC2Subnet:
        Type: "AWS::EC2::Subnet"
        Properties:
            AvailabilityZone: !Sub "${AWS::Region}b"
            CidrBlock: "10.0.7.0/24"
            VpcId: !Ref EC2VPC
            MapPublicIpOnLaunch: false
            Tags:
              -
                Key: "Name"
                Value: "Private-new-availability"

    EC2VPCEndpoint:
        Type: "AWS::EC2::VPCEndpoint"
        Properties:
            VpcEndpointType: "Interface"
            VpcId: !GetAtt EC2Subnet.VpcId
            ServiceName: !Sub "com.amazonaws.${AWS::Region}.secretsmanager"
            PolicyDocument: |
                {
                  "Statement": [
                    {
                      "Action": "*",
                      "Effect": "Allow",
                      "Principal": "*",
                      "Resource": "*"
                    }
                  ]
                }
            SubnetIds:
              - !Ref EC2Subnet
            PrivateDnsEnabled: true
            SecurityGroupIds:
              - !Ref EC2SecurityGroup

    IAMRole:
        Type: "AWS::IAM::Role"
        Properties:
            Path: "/"
            RoleName: "Lambdapermissions"
            AssumeRolePolicyDocument: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
            ManagedPolicyArns:
              - !Ref IAMManagedPolicy


            Description: "Allows Lambda functions to call AWS services on your behalf."

    IAMManagedPolicy:
        Type: "AWS::IAM::ManagedPolicy"
        Properties:
            ManagedPolicyName: "LambdaSecretsPolicy"
            Path: "/"
            PolicyDocument: |
                {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Sid": "Statement1",
                            "Effect": "Allow",
                            "Action": [
                                "secretsmanager:GetSecretValue",
                                "ec2:CreateNetworkInterface",
                                "ec2:DescribeNetworkInterfaces",
                                "ec2:DeleteNetworkInterface"
                            ],
                            "Resource": "*"
                        }
                    ]
                }

Lambda 執行角色權限

將權限授予 Lambda 執行角色,以便存取 Secrets Manager 的保密內容。使用 GetSecretValue API 呼叫來取得 Secrets Manager 的保密內容。如需更多資訊,請參閱範例: 擷取秘密值的權限

(選用) AWS Key Management Service (KMS) 權限

如果 Secrets Manager 的保密內容是使用 AWS KMS 客戶託管金鑰來加密,而非使用託管金鑰 aws/secretsmanager 加密,則需要額外的設定。請確定已授予解密 API 動作權限做為 Lambda 執行角色或 AWS KMS 金鑰政策。

相關資訊

如何疑難排解 Lambda 的權限問題?