How can I use Lambda functions in an Amazon VPC to retrieve Secrets Manager secrets?

4 minute read
0

My AWS Lambda function in an Amazon Virtual Private Cloud (Amazon VPC) can't access AWS Secrets Manager.

Short description

Lambda functions run in a secure Amazon VPC with access to AWS services and the internet. The Lambda service owns this Amazon VPC, and the it isn't connected to your default Amazon VPC.

Lambda functions that are connected to your Amazon VPC can access the internet only when you configure your Amazon VPC to provide access. The network interfaces that Lambda creates within your Amazon VPC use private IP addresses and can't connect to the internet using an internet gateway.

For more information, see Internet and service access for VPC-connected functions.

Note: It's a best practice not to place Lambda functions in an Amazon VPC unless the function must access other resources in the Amazon VPC.

Resolution

Lambda network configuration

To allow a Lambda function that's connected to an Amazon VPC to access Secrets Manager, follow one of these methods:

Attach a NAT gateway to a private subnet

Give your function internet access. Place the function in private subnets and route the outbound traffic to a NAT gateway in a public subnet. The NAT gateway has a public IP address and connects to the internet through the VPC's internet gateway.

Use an Amazon VPC interface endpoint

Set up an Amazon VPC interface endpoint for Secrets Manager. Your Amazon VPC then connects Secrets Manager from your Lambda function without internet access. Verify that the Amazon VPC endpoint security group allows port 443 inbound traffic from the Lambda security group or IP address range. Also, verify that the Lambda security group allows port 443 outbound traffic to the Amazon VPC endpoint security group or IP address range.

Note: If you use AWS PrivateLink VPC endpoints, then make sure that you configure the DHCP options with your Amazon VPC for Domain Name System (DNS). For more information, see DNS attributes for your Amazon VPC.

For example, the following AWS CloudFormation template establishes a Lambda function inside of a VPC's private subnet. This allows private access to AWS Secrets Manager through VPC endpoints:

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 execution role permissions

Grant permissions to the Lambda execution role to access Secrets Manager secrets. Use the GetSecretValue API call to get the Secrets Manager secret. For more information, see Example: Permission to retrieve secret values.

(Optional) AWS Key Management Service (AWS KMS) permissions

If the Secrets Manager secret is encrypted with an AWS KMS customer managed key instead of the managed key aws/secretsmanager, then additional configuration is required. Make sure to allow the Decrypt API action permission as either the Lambda execution role or the AWS KMS key policy.

Related information

How do I troubleshoot permissions issues with Lambda?

2 Comments

Is it possible to add some CloudFormation template examples?

replied a year ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
MODERATOR
replied a year ago