mirror of
https://github.com/swift-server/swift-aws-lambda-runtime.git
synced 2026-05-03 07:22:27 +00:00
74e4efdbac
Apply recommendations in code and documentation - [CI] restrict permissions to read-all instead of the default write-all - All examples README.md : add a note about Lambda functions configuration with improved security and scalability changes for production environment - Swift docc documentation: add a note about Lambda functions configuration with improved security and scalability changes for production environment --------- Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
230 lines
7.6 KiB
YAML
230 lines
7.6 KiB
YAML
AWSTemplateFormatVersion: '2010-09-09'
|
|
Transform: AWS::Serverless-2016-10-31
|
|
Description: SAM Template for ServiceLifecycle Lambda with PostgreSQL RDS
|
|
|
|
# This is an example SAM template for the purpose of this project.
|
|
# When deploying such infrastructure in production environment,
|
|
# we strongly encourage you to follow these best practices for improved security and resiliency
|
|
# - Enable access loggin on API Gateway
|
|
# See: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html)
|
|
# - Ensure that AWS Lambda function is configured for function-level concurrent execution limit
|
|
# See: https://docs.aws.amazon.com/lambda/latest/dg/lambda-concurrency.html
|
|
# https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html
|
|
# - Check encryption settings for Lambda environment variable
|
|
# See: https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-encryption.html
|
|
# - Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ)
|
|
# See: https://docs.aws.amazon.com/lambda/latest/dg/invocation-async-retain-records.html#invocation-dlq
|
|
|
|
Parameters:
|
|
|
|
DBName:
|
|
Type: String
|
|
Default: servicelifecycle
|
|
Description: Database name
|
|
MinLength: "1"
|
|
MaxLength: "64"
|
|
AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*'
|
|
ConstraintDescription: Must begin with a letter and contain only alphanumeric characters
|
|
|
|
Resources:
|
|
# VPC for RDS and Lambda
|
|
VPC:
|
|
Type: AWS::EC2::VPC
|
|
Properties:
|
|
CidrBlock: 10.0.0.0/16
|
|
EnableDnsHostnames: true
|
|
EnableDnsSupport: true
|
|
Tags:
|
|
- Key: Name
|
|
Value: ServiceLifecycle-VPC
|
|
|
|
# Private Subnet 1 for RDS
|
|
PrivateSubnet1:
|
|
Type: AWS::EC2::Subnet
|
|
Properties:
|
|
VpcId: !Ref VPC
|
|
AvailabilityZone: !Select [0, !GetAZs '']
|
|
CidrBlock: 10.0.3.0/24
|
|
MapPublicIpOnLaunch: false
|
|
Tags:
|
|
- Key: Name
|
|
Value: ServiceLifecycle-Private-Subnet-1
|
|
|
|
# Private Subnet 2 for RDS
|
|
PrivateSubnet2:
|
|
Type: AWS::EC2::Subnet
|
|
Properties:
|
|
VpcId: !Ref VPC
|
|
AvailabilityZone: !Select [1, !GetAZs '']
|
|
CidrBlock: 10.0.4.0/24
|
|
MapPublicIpOnLaunch: false
|
|
Tags:
|
|
- Key: Name
|
|
Value: ServiceLifecycle-Private-Subnet-2
|
|
|
|
# Security Group for RDS
|
|
DatabaseSecurityGroup:
|
|
Type: AWS::EC2::SecurityGroup
|
|
Properties:
|
|
GroupName: ServiceLifecycle-DB-SG
|
|
GroupDescription: Security group for PostgreSQL database
|
|
VpcId: !Ref VPC
|
|
Tags:
|
|
- Key: Name
|
|
Value: ServiceLifecycle-DB-SecurityGroup
|
|
|
|
# Security Group for Lambda
|
|
LambdaSecurityGroup:
|
|
Type: AWS::EC2::SecurityGroup
|
|
Properties:
|
|
GroupName: ServiceLifecycle-Lambda-SG
|
|
GroupDescription: Security group for Lambda function
|
|
VpcId: !Ref VPC
|
|
SecurityGroupEgress:
|
|
- IpProtocol: tcp
|
|
FromPort: 5432
|
|
ToPort: 5432
|
|
CidrIp: 10.0.0.0/16
|
|
Description: Allow PostgreSQL access within VPC only
|
|
Tags:
|
|
- Key: Name
|
|
Value: ServiceLifecycle-Lambda-SecurityGroup
|
|
|
|
# DB Subnet Group (required for RDS)
|
|
DatabaseSubnetGroup:
|
|
Type: AWS::RDS::DBSubnetGroup
|
|
Properties:
|
|
DBSubnetGroupDescription: Subnet group for PostgreSQL database
|
|
SubnetIds:
|
|
- !Ref PrivateSubnet1
|
|
- !Ref PrivateSubnet2
|
|
Tags:
|
|
- Key: Name
|
|
Value: ServiceLifecycle-DB-SubnetGroup
|
|
|
|
# Database credentials stored in Secrets Manager
|
|
DatabaseSecret:
|
|
Type: AWS::SecretsManager::Secret
|
|
Properties:
|
|
Name: !Sub "${AWS::StackName}-db-credentials"
|
|
Description: RDS database credentials
|
|
GenerateSecretString:
|
|
SecretStringTemplate: '{"username":"postgres"}'
|
|
GenerateStringKey: "password"
|
|
PasswordLength: 16
|
|
ExcludeCharacters: '"@/\\'
|
|
|
|
# Database Security Group Ingress Rule (added separately to avoid circular dependency)
|
|
DatabaseSecurityGroupIngress:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref DatabaseSecurityGroup
|
|
IpProtocol: tcp
|
|
FromPort: 5432
|
|
ToPort: 5432
|
|
SourceSecurityGroupId: !Ref LambdaSecurityGroup
|
|
Description: Allow PostgreSQL access from Lambda security group
|
|
|
|
# PostgreSQL RDS Instance
|
|
PostgreSQLDatabase:
|
|
Type: AWS::RDS::DBInstance
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
DBInstanceIdentifier: servicelifecycle-postgres
|
|
DBInstanceClass: db.t3.micro
|
|
Engine: postgres
|
|
EngineVersion: '17.6'
|
|
MasterUsername: !Join ['', ['{{resolve:secretsmanager:', !Ref DatabaseSecret, ':SecretString:username}}']]
|
|
MasterUserPassword: !Join ['', ['{{resolve:secretsmanager:', !Ref DatabaseSecret, ':SecretString:password}}']]
|
|
DBName: !Ref DBName
|
|
AllocatedStorage: "20"
|
|
StorageType: gp2
|
|
VPCSecurityGroups:
|
|
- !Ref DatabaseSecurityGroup
|
|
DBSubnetGroupName: !Ref DatabaseSubnetGroup
|
|
PubliclyAccessible: false
|
|
BackupRetentionPeriod: 0
|
|
MultiAZ: false
|
|
StorageEncrypted: true
|
|
DeletionProtection: false
|
|
Tags:
|
|
- Key: Name
|
|
Value: ServiceLifecycle-PostgreSQL
|
|
|
|
# Lambda function
|
|
ServiceLifecycleLambda:
|
|
Type: AWS::Serverless::Function
|
|
Properties:
|
|
CodeUri: .build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/LambdaWithServiceLifecycle/LambdaWithServiceLifecycle.zip
|
|
Timeout: 60
|
|
Handler: swift.bootstrap # ignored by the Swift runtime
|
|
Runtime: provided.al2
|
|
MemorySize: 128
|
|
Architectures:
|
|
- arm64
|
|
VpcConfig:
|
|
SecurityGroupIds:
|
|
- !Ref LambdaSecurityGroup
|
|
SubnetIds:
|
|
- !Ref PrivateSubnet1
|
|
- !Ref PrivateSubnet2
|
|
Environment:
|
|
Variables:
|
|
LOG_LEVEL: trace
|
|
DB_HOST: !GetAtt PostgreSQLDatabase.Endpoint.Address
|
|
DB_USER: !Join ['', ['{{resolve:secretsmanager:', !Ref DatabaseSecret, ':SecretString:username}}']]
|
|
DB_PASSWORD: !Join ['', ['{{resolve:secretsmanager:', !Ref DatabaseSecret, ':SecretString:password}}']]
|
|
DB_NAME: !Ref DBName
|
|
Events:
|
|
HttpApiEvent:
|
|
Type: HttpApi
|
|
|
|
Outputs:
|
|
# API Gateway endpoint
|
|
APIGatewayEndpoint:
|
|
Description: API Gateway endpoint URL for the Lambda function
|
|
Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com"
|
|
Export:
|
|
Name: !Sub "${AWS::StackName}-APIEndpoint"
|
|
|
|
# Database connection details
|
|
DatabaseEndpoint:
|
|
Description: PostgreSQL database endpoint hostname
|
|
Value: !GetAtt PostgreSQLDatabase.Endpoint.Address
|
|
Export:
|
|
Name: !Sub "${AWS::StackName}-DBEndpoint"
|
|
|
|
DatabasePort:
|
|
Description: PostgreSQL database port
|
|
Value: !GetAtt PostgreSQLDatabase.Endpoint.Port
|
|
Export:
|
|
Name: !Sub "${AWS::StackName}-DBPort"
|
|
|
|
DatabaseName:
|
|
Description: PostgreSQL database name
|
|
Value: !Ref DBName
|
|
Export:
|
|
Name: !Sub "${AWS::StackName}-DBName"
|
|
|
|
DatabaseSecretArn:
|
|
Description: ARN of the secret containing database credentials
|
|
Value: !Ref DatabaseSecret
|
|
Export:
|
|
Name: !Sub "${AWS::StackName}-DBSecretArn"
|
|
|
|
# Connection string instructions
|
|
DatabaseConnectionInstructions:
|
|
Description: Instructions to get the connection string
|
|
Value: !Sub "Use 'aws secretsmanager get-secret-value --secret-id ${DatabaseSecret}' to retrieve credentials"
|
|
Export:
|
|
Name: !Sub "${AWS::StackName}-DBConnectionInstructions"
|
|
|
|
# Individual connection details for manual connection
|
|
ConnectionDetails:
|
|
Description: Database connection details
|
|
Value: !Sub |
|
|
Hostname: ${PostgreSQLDatabase.Endpoint.Address}
|
|
Port: ${PostgreSQLDatabase.Endpoint.Port}
|
|
Database: ${DBName}
|
|
Credentials: Use AWS Secrets Manager to retrieve username and password
|