Skip to content

Commit

Permalink
feat: place sql lambda handler explicitly in a private isolated network
Browse files Browse the repository at this point in the history
BREAKING CHANGE: previously the default VPC strategy was used, but as
a database should always be in an isolated subnet, this default makes
a lot more sense. But will break code if your VPC does not have an
isolated subnet, and for example only has egress only subnets.

So provider now allows you to specify a vpcSubnet selection.
  • Loading branch information
dnz-bdeboer committed May 2, 2024
1 parent ac1b9ef commit 2791bb9
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 2 deletions.
12 changes: 11 additions & 1 deletion src/provider.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { existsSync } from "fs"
import * as path from "path"
import { Duration, Stack } from "aws-cdk-lib"
import { IVpc } from "aws-cdk-lib/aws-ec2"
import { IVpc, SubnetType, SubnetSelection } from "aws-cdk-lib/aws-ec2"
import { IFunction, Runtime } from "aws-cdk-lib/aws-lambda"
import * as lambda from "aws-cdk-lib/aws-lambda-nodejs"
import { IDatabaseCluster, IServerlessCluster } from "aws-cdk-lib/aws-rds"
Expand All @@ -19,6 +19,13 @@ export interface RdsSqlProps {
*/
readonly vpc: IVpc

/**
* Where to place the networkprovivder lambda within the VPC.
*
* @default - the isolated subnet if not specified
*/
readonly vpcSubnets?: SubnetSelection

/**
* Your database.
*/
Expand Down Expand Up @@ -104,6 +111,9 @@ export class Provider extends Construct {
const logger = props.logger ?? false
const fn = new lambda.NodejsFunction(scope, id, {
vpc: props.vpc,
vpcSubnets: props.vpcSubnets ?? {
subnetType: SubnetType.PRIVATE_ISOLATED,
},
entry: entry,
runtime: Runtime.NODEJS_20_X,
timeout: props.timeout ?? Duration.seconds(300),
Expand Down
63 changes: 62 additions & 1 deletion test/stack.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,21 @@ test("role without database", () => {
region: "us-east-1",
},
})
const vpc = new ec2.Vpc(stack, "Vpc")
const vpc = new ec2.Vpc(stack, "Vpc", {
subnetConfiguration: [
{
cidrMask: 28,
name: "rds",
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
],
})

const cluster = new rds.ServerlessCluster(stack, "Cluster", {
vpc: vpc,
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
engine: rds.DatabaseClusterEngine.auroraPostgres({
version: rds.AuroraPostgresEngineVersion.VER_11_13,
}),
Expand Down Expand Up @@ -117,3 +128,53 @@ test("absence of security group is detected", () => {
},
})
})

test("vpcSubnet selection can be specified", () => {
const app = new cdk.App()
const stack = new cdk.Stack(app, "TestStack", {
env: {
account: "123456789",
region: "us-east-1",
},
})
const vpc = new ec2.Vpc(stack, "Vpc", {
subnetConfiguration: [
{
cidrMask: 28,
name: "rds",
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
},
{
cidrMask: 28,
name: "nat",
subnetType: ec2.SubnetType.PUBLIC,
},
],
})

const cluster = new rds.ServerlessCluster(stack, "Cluster", {
vpc: vpc,
// vpcSubnets: {
// subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
// },
engine: rds.DatabaseClusterEngine.auroraPostgres({
version: rds.AuroraPostgresEngineVersion.VER_11_13,
}),
})

const provider = new Provider(stack, "Provider", {
vpc: vpc,
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
},
cluster: cluster,
secret: cluster.secret!,
})

expect(() => {
new Role(stack, "Role", {
provider: provider,
roleName: "role",
})
}).toThrowError()
})

0 comments on commit 2791bb9

Please sign in to comment.