Introduction#
GitHub shows basic concepts of vpc endpoints
- gateway endpoint s3 service
- interface endpoints for ssm ec2 connection
- interface endpooint to invoke lambda from vpc
VPC Stack#
create a vpc with public, private-nat-subnet, private-isolated-subnet,
this.vpc = new aws_ec2.Vpc(this, 'DemoVpc', {vpcName: 'DemoVpc',cidr: props.cidr,maxAzs: 1,enableDnsHostnames: true,enableDnsSupport: true,subnetConfiguration: [{name: 'Public',cidrMask: 24,subnetType: aws_ec2.SubnetType.PUBLIC},{name: 'PrivateNat',cidrMask: 24,subnetType: aws_ec2.SubnetType.PRIVATE_WITH_NAT},{name: 'Isolated',cidrMask: 24,subnetType: aws_ec2.SubnetType.PRIVATE_ISOLATED}]})this.vpc.applyRemovalPolicy(RemovalPolicy.DESTROY)
Add VPC Endpoints#
add gateway endpoint s3
this.vpc.addGatewayEndpoint('S3Endpoint', {service: aws_ec2.GatewayVpcEndpointAwsService.S3// default all subnets})
add interface endpoint for ssm ec2 connection
// vpc service endpoints ssm ec2this.vpc.addInterfaceEndpoint('SsmEndpoint', {service: aws_ec2.InterfaceVpcEndpointAwsService.SSM,privateDnsEnabled: true,subnets: {subnetType: aws_ec2.SubnetType.PRIVATE_ISOLATED}})this.vpc.addInterfaceEndpoint('SsmMessage', {service: aws_ec2.InterfaceVpcEndpointAwsService.SSM_MESSAGES,privateDnsEnabled: true,subnets: {subnetType: aws_ec2.SubnetType.PRIVATE_ISOLATED}})this.vpc.addInterfaceEndpoint('Ec2Message', {service: aws_ec2.InterfaceVpcEndpointAwsService.EC2_MESSAGES,privateDnsEnabled: true,subnets: {subnetType: aws_ec2.SubnetType.PRIVATE_ISOLATED}})
Private EC2#
launch an ec2 instance in the isolated subnet
export class Ec2Stack extends Stack {constructor(scope: Construct, id: string, props: Ec2Props) {super(scope, id, props)new aws_ec2.Instance(this, 'PrivateEc2', {instanceName: 'PrivateEc2',vpc: props.vpc,vpcSubnets: {subnetType: aws_ec2.SubnetType.PRIVATE_ISOLATED},instanceType: aws_ec2.InstanceType.of(aws_ec2.InstanceClass.T2,aws_ec2.InstanceSize.SMALL),machineImage: new aws_ec2.AmazonLinuxImage({generation: aws_ec2.AmazonLinuxGeneration.AMAZON_LINUX_2}),role: props.role,securityGroup: props.sg})}}
Lambda RDS in VPC#
- create a RDS in private subnest
- add vpc endpoints so lambda can access rds and secrete manager
- check lambda and rds security group
- test lambda fetch data from rds tables
get the existed vpc
const vpc = aws_ec2.Vpc.fromLookup(this, "Vpc", {vpcId: props.vpcId,vpcName: props.vpcName,});
add vpc endpoint to access secrete manager
vpc.addInterfaceEndpoint("SecreteManagerVpcEndpoint", {service:aws_ec2.InterfaceVpcEndpointAwsService.SECRETS_MANAGER,privateDnsEnabled: true,subnets: {subnetType: aws_ec2.SubnetType.PRIVATE_ISOLATED,},});
db credentials by secret manager
const credentials = aws_rds.Credentials.fromGeneratedSecret("mysqlSecret",{secretName: "mysql-secret-name",});
aws rds db instance in private subnets
const rds = new aws_rds.DatabaseInstance(this,"RdsIntance",{// production => RETAINremovalPolicy: RemovalPolicy.DESTROY,databaseName: props.dbName,// make sure combination version and instance typeengine: aws_rds.DatabaseInstanceEngine.mysql({version: aws_rds.MysqlEngineVersion.VER_8_0_28,}),instanceType: aws_ec2.InstanceType.of(aws_ec2.InstanceClass.BURSTABLE3,aws_ec2.InstanceSize.SMALL),vpc,vpcSubnets: {// production => private subnetsubnetType: aws_ec2.SubnetType.PRIVATE_ISOLATED,},credentials: credentials,securityGroups: [securityGroup]});
Lambda Stack#
role for lambda
const role = new aws_iam.Role(this, "RoleForLambdaRdsVpc", {roleName: "RoleForLambdaAccessRdsVpc",assumedBy: new aws_iam.ServicePrincipal("lambda.amazonaws.com"),});role.attachInlinePolicy(new aws_iam.Policy(this, "PolicyForLambdaAccessRdsVpc", {policyName: "PolicyForLambdaAccessRdsVpc",statements: [new aws_iam.PolicyStatement({effect: aws_iam.Effect.ALLOW,actions: ["rds:*"],resources: ["*"],}),],}));role.addManagedPolicy(aws_iam.ManagedPolicy.fromManagedPolicyArn(this,"AWSLambdaVPCAccessExecutionRole","arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"));role.addManagedPolicy(aws_iam.ManagedPolicy.fromManagedPolicyArn(this,"LambdaSecretManager","arn:aws:iam::aws:policy/SecretsManagerReadWrite"));
lambda function in vpc
new aws_lambda.Function(this, "LambdaRdsVpc", {functionName: props.functionName,runtime: aws_lambda.Runtime.PYTHON_3_8,code: aws_lambda.Code.fromAsset(path.join(__dirname, "lambda/package.zip")),handler: "index.handler",timeout: Duration.seconds(10),memorySize: 512,role,vpc,vpcSubnets: {subnetType: aws_ec2.SubnetType.PRIVATE_ISOLATED,},environment: {SECRET_ARN:(credentials.secret &&credentials.secret?.secretArn.toString()) ||"",},});
stack output
new CfnOutput(this, "SECRET_ARN", {value:(credentials.secret && credentials.secret?.secretArn) ||"",});
Troubleshooting#
- run create_table.py to test
- get rds credentials from secrete manager
- rds connector, lambda and rds subnets and security group
- create IcaDb database
- create employee table in IcaDb database
- fetch data from employee table
- launch private EC2 instances in the same securityGroup as interface endpoints
- specify region when running aws s3 commands
aws s3 ls s3://$BUCKET_NAME/ --region -us-east-2