Files
esdp/serverless/serverless.infra.yml

398 lines
13 KiB
YAML

service: esdp-infra
app: esdp-api-app
frameworkVersion: '4'
stages:
shared:
observability: false
params:
# Single shared database name for all app stages (dev/alpha/beta/prod)
db_name: esdp
# Your public IP in CIDR form for direct DB access (lock this down).
admin_cidr: 70.36.57.88/32
provider:
name: aws
runtime: nodejs22.x
region: ca-central-1
resources:
Resources:
EsdpVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: ${self:service}-${sls:stage}-vpc
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: ${self:service}-${sls:stage}-igw
VpcGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId:
Ref: EsdpVpc
InternetGatewayId:
Ref: InternetGateway
PublicSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: EsdpVpc
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ''
CidrBlock: 10.0.0.0/24
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: ${self:service}-${sls:stage}-public-a
PublicSubnetB:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: EsdpVpc
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ''
CidrBlock: 10.0.1.0/24
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: ${self:service}-${sls:stage}-public-b
PrivateSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: EsdpVpc
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ''
CidrBlock: 10.0.10.0/24
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: ${self:service}-${sls:stage}-private-a
PrivateSubnetB:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: EsdpVpc
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ''
CidrBlock: 10.0.11.0/24
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: ${self:service}-${sls:stage}-private-b
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: EsdpVpc
Tags:
- Key: Name
Value: ${self:service}-${sls:stage}-public-rt
PublicRoute:
Type: AWS::EC2::Route
DependsOn: VpcGatewayAttachment
Properties:
RouteTableId:
Ref: PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: InternetGateway
PublicSubnetARouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId:
Ref: PublicSubnetA
RouteTableId:
Ref: PublicRouteTable
PublicSubnetBRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId:
Ref: PublicSubnetB
RouteTableId:
Ref: PublicRouteTable
NatEip:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId:
Fn::GetAtt:
- NatEip
- AllocationId
SubnetId:
Ref: PublicSubnetA
Tags:
- Key: Name
Value: ${self:service}-${sls:stage}-nat
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: EsdpVpc
Tags:
- Key: Name
Value: ${self:service}-${sls:stage}-private-rt
PrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId:
Ref: NatGateway
PrivateSubnetARouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId:
Ref: PrivateSubnetA
RouteTableId:
Ref: PrivateRouteTable
PrivateSubnetBRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId:
Ref: PrivateSubnetB
RouteTableId:
Ref: PrivateRouteTable
LambdaSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ${self:service}-${sls:stage} Lambda security group
VpcId:
Ref: EsdpVpc
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: ${self:service}-${sls:stage}-lambda-sg
ProxySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ${self:service}-${sls:stage} RDS proxy security group
VpcId:
Ref: EsdpVpc
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
SourceSecurityGroupId:
Ref: LambdaSecurityGroup
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
CidrIp: ${param:admin_cidr}
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: ${self:service}-${sls:stage}-proxy-sg
RdsSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ${self:service}-${sls:stage} RDS security group
VpcId:
Ref: EsdpVpc
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
SourceSecurityGroupId:
Ref: ProxySecurityGroup
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
CidrIp: ${param:admin_cidr}
Tags:
- Key: Name
Value: ${self:service}-${sls:stage}-rds-sg
DbSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: ${self:service}-${sls:stage} DB subnet group
SubnetIds:
- Ref: PublicSubnetA
- Ref: PublicSubnetB
DbSecret:
Type: AWS::SecretsManager::Secret
Properties:
Description: ${self:service}-${sls:stage} RDS master credentials
GenerateSecretString:
SecretStringTemplate: '{"username":"esdp_admin"}'
GenerateStringKey: password
PasswordLength: 32
ExcludeCharacters: '"@/\\'
DbProxyRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- rds.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: ${self:service}-${sls:stage}-db-proxy-secrets
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource:
- Ref: DbSecret
DbProxy:
Type: AWS::RDS::DBProxy
Properties:
DBProxyName: ${self:service}-${sls:stage}-proxy
EngineFamily: POSTGRESQL
IdleClientTimeout: 1800
RequireTLS: true
RoleArn:
Fn::GetAtt:
- DbProxyRole
- Arn
VpcSubnetIds:
- Ref: PrivateSubnetA
- Ref: PrivateSubnetB
VpcSecurityGroupIds:
- Ref: ProxySecurityGroup
Auth:
- AuthScheme: SECRETS
SecretArn:
Ref: DbSecret
IAMAuth: DISABLED
DbProxyTargetGroup:
Type: AWS::RDS::DBProxyTargetGroup
Properties:
DBProxyName:
Ref: DbProxy
TargetGroupName: default
DBInstanceIdentifiers:
- Ref: PostgresDb
ConnectionPoolConfigurationInfo:
MaxConnectionsPercent: 75
MaxIdleConnectionsPercent: 50
ConnectionBorrowTimeout: 120
PostgresDb:
Type: AWS::RDS::DBInstance
DeletionPolicy: Snapshot
UpdateReplacePolicy: Snapshot
Properties:
DBInstanceIdentifier: ${self:service}-${sls:stage}-postgres
Engine: postgres
# EngineVersion intentionally omitted so AWS uses the current default/latest for RDS Postgres.
AutoMinorVersionUpgrade: true
DBInstanceClass: db.t4g.micro
AllocatedStorage: 20
StorageType: gp3
StorageEncrypted: true
PubliclyAccessible: true
MultiAZ: false
DBName: ${param:db_name}
BackupRetentionPeriod: 7
CopyTagsToSnapshot: true
DeletionProtection: true
VPCSecurityGroups:
- Ref: RdsSecurityGroup
DBSubnetGroupName:
Ref: DbSubnetGroup
MasterUsername:
Fn::Sub: '{{resolve:secretsmanager:${DbSecret}::username}}'
MasterUserPassword:
Fn::Sub: '{{resolve:secretsmanager:${DbSecret}::password}}'
Outputs:
VpcId:
Value:
Ref: EsdpVpc
PrivateSubnetAId:
Value:
Ref: PrivateSubnetA
PrivateSubnetBId:
Value:
Ref: PrivateSubnetB
LambdaSecurityGroupId:
Value:
Ref: LambdaSecurityGroup
ProxySecurityGroupId:
Value:
Ref: ProxySecurityGroup
RdsSecurityGroupId:
Value:
Ref: RdsSecurityGroup
DbName:
Value: ${param:db_name}
DbPort:
Value: 5432
DbEndpointAddress:
Value:
Fn::GetAtt:
- PostgresDb
- Endpoint.Address
DbEndpointPort:
Value:
Fn::GetAtt:
- PostgresDb
- Endpoint.Port
DbSecretArn:
Value:
Ref: DbSecret
DbProxyEndpoint:
Value:
Fn::GetAtt:
- DbProxy
- Endpoint