Skip to content

Commit 1fa895a

Browse files
committed
Use pgbouncer's public IP if it is in a public subnet
1 parent 15c9f6a commit 1fa895a

File tree

6 files changed

+36
-17
lines changed

6 files changed

+36
-17
lines changed

integration_tests/cdk/app.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,21 @@ def __init__(
8383
removal_policy=RemovalPolicy.DESTROY,
8484
)
8585

86-
pgstac_db.db.connections.allow_default_port_from_any_ipv4()
86+
assert pgstac_db.security_group
87+
88+
pgstac_db.security_group.add_ingress_rule(
89+
aws_ec2.Peer.any_ipv4(), aws_ec2.Port.tcp(5432)
90+
)
8791

8892
PgStacApiLambda(
8993
self,
9094
"pgstac-api",
95+
connection_target=pgstac_db.connection_target,
96+
db_secret=pgstac_db.pgstac_secret,
9197
api_env={
9298
"NAME": app_config.build_service_name("STAC API"),
9399
"description": f"{app_config.stage} STAC API",
94100
},
95-
vpc=vpc,
96-
connection_target=pgstac_db.connection_target,
97-
db_secret=pgstac_db.pgstac_secret,
98101
)
99102

100103
TitilerPgstacApiLambda(
@@ -104,7 +107,6 @@ def __init__(
104107
"NAME": app_config.build_service_name("titiler pgSTAC API"),
105108
"description": f"{app_config.stage} titiler pgstac API",
106109
},
107-
vpc=vpc,
108110
connection_target=pgstac_db.connection_target,
109111
db_secret=pgstac_db.pgstac_secret,
110112
buckets=[],
@@ -116,7 +118,6 @@ def __init__(
116118
TiPgApiLambda(
117119
self,
118120
"tipg-api",
119-
vpc=vpc,
120121
connection_target=pgstac_db.connection_target,
121122
db_secret=pgstac_db.pgstac_secret,
122123
api_env={

lib/database/PgBouncer.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export interface PgBouncerProps {
7070
export class PgBouncer extends Construct {
7171
public readonly instance: ec2.Instance;
7272
public readonly pgbouncerSecret: secretsmanager.Secret;
73+
public readonly securityGroup: ec2.SecurityGroup;
7374

7475
// The max_connections parameter in PgBouncer determines the maximum number of
7576
// connections to open on the actual database instance. We want that number to
@@ -134,6 +135,13 @@ export class PgBouncer extends Construct {
134135
})
135136
);
136137

138+
// Create a security group and allow connections from the Lambda IP ranges for this region
139+
this.securityGroup = new ec2.SecurityGroup(this, "PgBouncerSecurityGroup", {
140+
vpc: props.vpc,
141+
description: "Security group for PgBouncer instance",
142+
allowAllOutbound: true,
143+
});
144+
137145
// Create PgBouncer instance
138146
this.instance = new ec2.Instance(this, "Instance", {
139147
vpc: props.vpc,
@@ -142,6 +150,7 @@ export class PgBouncer extends Construct {
142150
? ec2.SubnetType.PUBLIC
143151
: ec2.SubnetType.PRIVATE_WITH_EGRESS,
144152
},
153+
securityGroup: this.securityGroup,
145154
instanceType,
146155
instanceName: props.instanceName,
147156
machineImage: ec2.MachineImage.fromSsmParameter(
@@ -161,6 +170,7 @@ export class PgBouncer extends Construct {
161170
],
162171
userData: this.loadUserDataScript(pgBouncerConfig, props.database),
163172
userDataCausesReplacement: true,
173+
associatePublicIpAddress: props.usePublicSubnet,
164174
});
165175

166176
// Allow PgBouncer to connect to RDS
@@ -201,7 +211,9 @@ export class PgBouncer extends Construct {
201211
new CustomResource(this, "pgbouncerSecretBootstrapper", {
202212
serviceToken: secretUpdaterFn.functionArn,
203213
properties: {
204-
instanceIp: this.instance.instancePrivateIp,
214+
instanceIp: props.usePublicSubnet
215+
? this.instance.instancePublicIp
216+
: this.instance.instancePrivateIp,
205217
},
206218
});
207219
}

lib/database/index.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ export class PgStacDatabase extends Construct {
3636
db: rds.DatabaseInstance;
3737
pgstacSecret: secretsmanager.ISecret;
3838
private _pgBouncerServer?: PgBouncer;
39+
3940
public readonly connectionTarget: rds.IDatabaseInstance | ec2.Instance;
41+
public readonly securityGroup?: ec2.SecurityGroup;
4042

4143
constructor(scope: Construct, id: string, props: PgStacDatabaseProps) {
4244
super(scope, id);
@@ -153,7 +155,9 @@ export class PgStacDatabase extends Construct {
153155
secret: this.pgstacSecret,
154156
},
155157
dbMaxConnections: parseInt(defaultParameters.maxConnections),
156-
usePublicSubnet: true,
158+
usePublicSubnet:
159+
!props.vpcSubnets ||
160+
props.vpcSubnets.subnetType === ec2.SubnetType.PUBLIC,
157161
pgBouncerConfig: {
158162
poolMode: "transaction",
159163
maxClientConn: 1000,
@@ -168,6 +172,7 @@ export class PgStacDatabase extends Construct {
168172

169173
this.pgstacSecret = this._pgBouncerServer.pgbouncerSecret;
170174
this.connectionTarget = this._pgBouncerServer.instance;
175+
this.securityGroup = this._pgBouncerServer.securityGroup;
171176
} else {
172177
this.connectionTarget = this.db;
173178
}

lib/stac-api/index.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ export class PgStacApiLambda extends Construct {
2020
constructor(scope: Construct, id: string, props: PgStacApiLambdaProps) {
2121
super(scope, id);
2222

23-
console.log(props)
24-
console.log(props.lambdaFunctionOptions);
2523
this.stacApiLambdaFunction = new lambda.Function(this, "lambda", {
2624
// defaults
2725
runtime: lambda.Runtime.PYTHON_3_11,
@@ -47,9 +45,11 @@ export class PgStacApiLambda extends Construct {
4745
});
4846

4947
props.dbSecret.grantRead(this.stacApiLambdaFunction);
48+
5049
if (props.vpc){
51-
this.stacApiLambdaFunction.connections.allowTo(props.connectionTarget, ec2.Port.tcp(5432));
50+
this.stacApiLambdaFunction.connections.allowTo(props.connectionTarget, ec2.Port.tcp(5432), "allow connections from stac-fastapi-pgstac");
5251
}
52+
5353
const stacApi = new HttpApi(this, `${Stack.of(this).stackName}-stac-api`, {
5454
defaultDomainMapping: props.stacApiDomainName ? {
5555
domainName: props.stacApiDomainName

lib/tipg-api/index.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {
22
Stack,
33
aws_ec2 as ec2,
4-
aws_rds as rds,
54
aws_lambda as lambda,
65
aws_logs as logs,
6+
aws_rds as rds,
77
aws_secretsmanager as secretsmanager,
88
CfnOutput,
99
Duration,
@@ -45,9 +45,11 @@ import {
4545
});
4646

4747
props.dbSecret.grantRead(this.tiPgLambdaFunction);
48+
4849
if (props.vpc){
4950
this.tiPgLambdaFunction.connections.allowTo(props.connectionTarget, ec2.Port.tcp(5432), "allow connections from tipg");
5051
}
52+
5153
const tipgApi = new HttpApi(this, `${Stack.of(this).stackName}-tipg-api`, {
5254
defaultDomainMapping: props.tipgApiDomainName ? {
5355
domainName: props.tipgApiDomainName
@@ -92,7 +94,6 @@ import {
9294
*/
9395
readonly dbSecret: secretsmanager.ISecret;
9496

95-
9697
/**
9798
* Customized environment variables to send to titiler-pgstac runtime.
9899
*/

lib/titiler-pgstac-api/index.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,10 @@ import { CustomLambdaFunctionProps } from "../utils";
103103
*/
104104
readonly vpc?: ec2.IVpc;
105105

106-
/**
107-
* RDS Instance with installed pgSTAC or pgbouncer server.
108-
*/
109-
readonly connectionTarget: rds.IDatabaseInstance | ec2.IInstance;
106+
/**
107+
* RDS Instance with installed pgSTAC or pgbouncer server.
108+
*/
109+
readonly connectionTarget: rds.IDatabaseInstance | ec2.IInstance;
110110

111111
/**
112112
* Subnet into which the lambda should be deployed.

0 commit comments

Comments
 (0)