Created
October 4, 2020 20:42
-
-
Save efekarakus/2d69190e54b8d9a3719f2bd81181b73f to your computer and use it in GitHub Desktop.
regular aurora template
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AWSTemplateFormatVersion: '2010-09-09' | |
Description: 'CloudFormation Template to create Aurora Postgresql Cluster DB Instance' | |
############################################################################### | |
# Parameters | |
############################################################################### | |
Parameters: | |
ParentVPCStack: | |
Description: 'Provide Stack name of parent VPC stack based on VPC-3AZs yaml template. Refer Cloudformation dashboard in AWS Console to get this.' | |
Type: String | |
MinLength: '1' | |
MaxLength: '128' | |
AllowedPattern: '^[a-zA-Z]+[0-9a-zA-Z\-]*$' | |
ParentSSHBastionStack: | |
Description: 'Provide Stack name of parent Amazon Linux bastion host stack based on VPC-SSH-Bastion yaml template. Refer Cloudformation dashboard in AWS Console to get this.' | |
Type: String | |
MinLength: '1' | |
MaxLength: '128' | |
AllowedPattern: '^[a-zA-Z]+[0-9a-zA-Z\-]*$' | |
DBName: | |
Description: Database Name | |
Type: String | |
MinLength: '1' | |
MaxLength: '64' | |
AllowedPattern: "^[a-zA-Z]+[0-9a-zA-Z_]*$" | |
ConstraintDescription: Must start with a letter. Only numbers, letters, and _ accepted. max length 64 characters | |
DBPort: | |
Description: TCP/IP Port for the Database Instance | |
Type: Number | |
Default: 5432 | |
ConstraintDescription: 'Must be in the range [1115-65535]' | |
MinValue: 1115 | |
MaxValue: 65535 | |
DBUsername: | |
Description: Database master username | |
Type: String | |
MinLength: '1' | |
MaxLength: '16' | |
AllowedPattern: "^[a-zA-Z]+[0-9a-zA-Z_]*$" | |
ConstraintDescription: Must start with a letter. Only numbers, letters, and _ accepted. max length 16 characters | |
DBEngineVersion: | |
Description: Select Database Engine Version | |
Type: String | |
Default: 9.6.8 | |
AllowedValues: | |
- 9.6.8 | |
- 9.6.9 | |
- 9.6.11 | |
- 9.6.12 | |
- 9.6.16 | |
- 10.4 | |
- 10.5 | |
- 10.6 | |
- 10.7 | |
- 10.11 | |
- 11.4 | |
- 11.6 | |
DBInstanceClass: | |
Default: db.r4.large | |
Description: Database Instance Class. db.r5 instance classes are supported for Aurora PostgreSQL 10.6 or later. db.t3.medium instance class is supported for Aurora PostgreSQL 10.7 or later. | |
Type: String | |
AllowedValues: | |
- db.t3.medium | |
- db.r4.large | |
- db.r4.xlarge | |
- db.r4.2xlarge | |
- db.r4.4xlarge | |
- db.r4.8xlarge | |
- db.r4.16xlarge | |
- db.r5.large | |
- db.r5.xlarge | |
- db.r5.2xlarge | |
- db.r5.4xlarge | |
- db.r5.8xlarge | |
- db.r5.12xlarge | |
- db.r5.16xlarge | |
- db.r5.24xlarge | |
DBSnapshotName: | |
Description: Optional. DB Snapshot ID to restore database. Leave this blank if you are not restoring from a snapshot. | |
Type: String | |
Default: "" | |
LambdaBootStrapS3Bucket: | |
Description: Optional. Specify S3 bucket name for e.g. apgbootstrapscripts where Lambda DB Bootstrap Python script is stored. | |
Default: '' | |
Type: String | |
LambdaBootStrapS3Key: | |
Description: Optional. Specify S3 key for e.g. lambda/dbbootstrap.zip where Lambda DB Bootstrap Python script is stored. | |
Default: '' | |
Type: String | |
########################################################################### | |
# Mandatory tags that will be added to all resources that support tags | |
########################################################################### | |
EnvironmentStage: | |
Type: String | |
Description: The environment tag is used to designate the Environment Stage of the associated AWS resource. | |
AllowedValues: | |
- dev | |
- test | |
- pre-prod | |
- prod | |
Default: dev | |
Application: | |
Type: String | |
Description: The Application tag is used to designate the application of the associated AWS resource. In this capacity application does not refer to an installed software component, but rather the overall business application that the resource supports. | |
AllowedPattern: "^[a-zA-Z]+[a-zA-Z ]+[a-zA-Z]+$" | |
ConstraintDescription: provide a valid application name containing only letters and spaces | |
ApplicationVersion: | |
Type: String | |
Description: The ApplicationVersion tag is used to designate the specific version of the application. Format should be in the Pattern - "#.#.#" | |
Default: '1.0.0' | |
AllowedPattern: '^[a-zA-Z0-9\.\-]+$' | |
ConstraintDescription: provide a valid application version | |
ProjectCostCenter: | |
Type: String | |
Description: The ProjectCostCenter tag is used to designate the cost center associated with the project of the given AWS resource. | |
AllowedPattern: "^[a-zA-Z0-9]+$" | |
ConstraintDescription: provide a valid cost center | |
ServiceOwnersEmailContact: | |
Type: String | |
Description: The ServiceOwnersEmailContact tag is used to designate business owner(s) email address associated with the given AWS resource for sending outage or maintenance notifications | |
AllowedPattern: '^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$' | |
ConstraintDescription: provide a valid email address. | |
NotificationList: | |
Type: String | |
Description: The Email notification list is used to configure a SNS topic for sending cloudwatch alarm and RDS Event notifications | |
AllowedPattern: '^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$' | |
ConstraintDescription: provide a valid email address. | |
Confidentiality: | |
Type: String | |
Description: The Confidentiality tag is used to designate the confidentiality classification of the data that is associated with the resource. | |
AllowedValues: | |
- public | |
- private | |
- confidential | |
- pii/phi | |
Compliance: | |
Type: String | |
Description: The Compliance tag is used to specify the Compliance level for the AWS resource. | |
AllowedValues: | |
- hipaa | |
- sox | |
- fips | |
- other | |
- none | |
############################################################################### | |
# Parameter groups | |
############################################################################### | |
Metadata: | |
AWS::CloudFormation::Interface: | |
ParameterGroups: | |
- | |
Label: | |
default: Environment | |
Parameters: | |
- EnvironmentStage | |
- | |
Label: | |
default: DB Parameters | |
Parameters: | |
- DBName | |
- DBPort | |
- DBUsername | |
- DBInstanceClass | |
- DBEngineVersion | |
- DBSnapshotName | |
- NotificationList | |
- LambdaBootStrapS3Bucket | |
- LambdaBootStrapS3Key | |
- | |
Label: | |
default: Networking | |
Parameters: | |
- ParentVPCStack | |
- ParentSSHBastionStack | |
- | |
Label: | |
default: Mandatory Tags | |
Parameters: | |
- Application | |
- ApplicationVersion | |
- ProjectCostCenter | |
- ServiceOwnersEmailContact | |
- Confidentiality | |
- Compliance | |
############################################################################### | |
# Mappings | |
############################################################################### | |
Mappings: | |
DBFamilyMap: | |
"9.6.8": | |
"family": "aurora-postgresql9.6" | |
"9.6.9": | |
"family": "aurora-postgresql9.6" | |
"9.6.11": | |
"family": "aurora-postgresql9.6" | |
"9.6.12": | |
"family": "aurora-postgresql9.6" | |
"9.6.16": | |
"family": "aurora-postgresql9.6" | |
"10.4": | |
"family": "aurora-postgresql10" | |
"10.5": | |
"family": "aurora-postgresql10" | |
"10.6": | |
"family": "aurora-postgresql10" | |
"10.7": | |
"family": "aurora-postgresql10" | |
"10.11": | |
"family": "aurora-postgresql10" | |
"11.4": | |
"family": "aurora-postgresql11" | |
"11.6": | |
"family": "aurora-postgresql11" | |
############################################################################### | |
# Conditions | |
############################################################################### | |
Conditions: | |
IsUseDBSnapshot: !Not [!Equals [!Ref DBSnapshotName, ""]] | |
IsNotUseDBSnapshot: !Not [Condition: IsUseDBSnapshot] | |
IsProd: !Equals [!Ref EnvironmentStage, 'prod'] | |
IsReplica: !Or [!Equals [!Ref EnvironmentStage, 'pre-prod'], Condition: IsProd] | |
DoDBBootStrap: !And | |
- !Not [!Equals [!Ref LambdaBootStrapS3Bucket, '']] | |
- !Not [!Equals [!Ref LambdaBootStrapS3Key, '']] | |
- !Not [Condition: IsUseDBSnapshot] | |
DoEnableIAM: !Not [!Equals [!Ref DBEngineVersion, '9.6.8']] | |
############################################################################### | |
# Resources | |
############################################################################### | |
Resources: | |
MonitoringIAMRole: | |
Type: AWS::IAM::Role | |
Condition: IsProd | |
Properties: | |
AssumeRolePolicyDocument: | |
Version: "2012-10-17" | |
Statement: | |
- | |
Effect: "Allow" | |
Principal: | |
Service: | |
- "monitoring.rds.amazonaws.com" | |
Action: | |
- "sts:AssumeRole" | |
Path: "/" | |
ManagedPolicyArns: | |
- arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole | |
DBBootStrapLambdaRole: | |
Type: AWS::IAM::Role | |
Condition: DoDBBootStrap | |
Properties: | |
AssumeRolePolicyDocument: | |
Version: "2012-10-17" | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: | |
- lambda.amazonaws.com | |
Action: | |
- sts:AssumeRole | |
Path: "/" | |
ManagedPolicyArns: | |
- 'arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole' | |
Policies: | |
- | |
PolicyName: "secretaccess" | |
PolicyDocument: | |
Version: "2012-10-17" | |
Statement: | |
- | |
Effect: "Allow" | |
Action: "secretsmanager:GetSecretValue" | |
Resource: !Ref AuroraMasterSecret | |
DBSNSTopic: | |
Type: AWS::SNS::Topic | |
Properties: | |
Subscription: | |
- Endpoint: !Ref NotificationList | |
Protocol: email | |
DBSubnetGroup: | |
Type: 'AWS::RDS::DBSubnetGroup' | |
Properties: | |
DBSubnetGroupDescription: !Ref 'AWS::StackName' | |
SubnetIds: !Split [',', {'Fn::ImportValue': !Sub '${ParentVPCStack}-SubnetsPrivate'}] | |
ClusterSecurityGroup: | |
Type: 'AWS::EC2::SecurityGroup' | |
Properties: | |
GroupDescription: !Ref 'AWS::StackName' | |
SecurityGroupIngress: | |
- IpProtocol: tcp | |
FromPort: !Ref DBPort | |
ToPort: !Ref DBPort | |
SourceSecurityGroupId: {'Fn::ImportValue': !Sub '${ParentSSHBastionStack}-BastionSecurityGroupID'} | |
Description: 'Access to Bastion Host Security Group' | |
- IpProtocol: tcp | |
FromPort: !Ref DBPort | |
ToPort: !Ref DBPort | |
SourceSecurityGroupId: {'Fn::ImportValue': !Sub '${ParentVPCStack}-SecretRotationLambdaSecurityGroup'} | |
Description: 'Access to Lambda Security Group' | |
VpcId: {'Fn::ImportValue': !Sub '${ParentVPCStack}-VPC'} | |
Tags: | |
- Key: Name | |
Value: !Sub '${AWS::StackName}-AuroraClusterSecurityGroup' | |
ClusterSecurityGroupIngress: | |
Type: 'AWS::EC2::SecurityGroupIngress' | |
Properties: | |
GroupId: !GetAtt 'ClusterSecurityGroup.GroupId' | |
IpProtocol: -1 | |
SourceSecurityGroupId: !Ref ClusterSecurityGroup | |
Description: 'Self Reference' | |
RDSDBClusterParameterGroup: | |
Type: AWS::RDS::DBClusterParameterGroup | |
Properties: | |
Description: !Join [ "- ", [ "Aurora PG Cluster Parameter Group for Cloudformation Stack ", !Ref DBName ] ] | |
Family: !FindInMap [DBFamilyMap, !Ref DBEngineVersion, "family"] | |
Parameters: | |
rds.force_ssl: 1 | |
DBParamGroup: | |
Type: AWS::RDS::DBParameterGroup | |
Properties: | |
Description: !Join [ "- ", [ "Aurora PG Database Instance Parameter Group for Cloudformation Stack ", !Ref DBName ] ] | |
Family: !FindInMap [DBFamilyMap, !Ref DBEngineVersion, "family"] | |
Parameters: | |
shared_preload_libraries: auto_explain,pg_stat_statements,pg_hint_plan,pgaudit | |
log_statement: "ddl" | |
log_connections: 1 | |
log_disconnections: 1 | |
log_lock_waits: 1 | |
log_min_duration_statement: 5000 | |
auto_explain.log_min_duration: 5000 | |
auto_explain.log_verbose: 1 | |
log_rotation_age: 1440 | |
log_rotation_size: 102400 | |
rds.log_retention_period: 10080 | |
random_page_cost: 1 | |
track_activity_query_size: 16384 | |
idle_in_transaction_session_timeout: 7200000 | |
statement_timeout: 7200000 | |
search_path: '"$user",public' | |
AuroraKMSCMK: | |
Type: 'AWS::KMS::Key' | |
DeletionPolicy: Retain | |
Properties: | |
KeyPolicy: | |
Version: '2012-10-17' | |
Statement: | |
- Effect: Allow | |
Principal: | |
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root' | |
Action: 'kms:*' | |
Resource: '*' | |
- Effect: Allow | |
Principal: | |
AWS: '*' | |
Action: | |
- 'kms:Encrypt' | |
- 'kms:Decrypt' | |
- 'kms:ReEncrypt*' | |
- 'kms:GenerateDataKey*' | |
- 'kms:CreateGrant' | |
- 'kms:ListGrants' | |
- 'kms:DescribeKey' | |
Resource: '*' | |
Condition: | |
StringEquals: | |
'kms:CallerAccount': !Ref 'AWS::AccountId' | |
'kms:ViaService': !Sub 'rds.${AWS::Region}.amazonaws.com' | |
AuroraKMSCMKAlias: | |
Type: 'AWS::KMS::Alias' | |
DeletionPolicy: Retain | |
DependsOn: AuroraDBCluster | |
Properties: | |
AliasName: !Sub 'alias/${AuroraDBCluster}' | |
TargetKeyId: !Ref AuroraKMSCMK | |
AuroraMasterSecret: | |
Condition: IsNotUseDBSnapshot | |
Type: AWS::SecretsManager::Secret | |
Properties: | |
Name: !Join ['/', [!Ref EnvironmentStage, 'aurora-pg', !Ref 'AWS::StackName']] | |
Description: !Join ['', ['Aurora PostgreSQL Master User Secret ', 'for CloudFormation Stack ', !Ref 'AWS::StackName']] | |
Tags: | |
- | |
Key: EnvironmentStage | |
Value: !Ref EnvironmentStage | |
- | |
Key: DatabaseEngine | |
Value: 'Aurora PostgreSQL' | |
- | |
Key: StackID | |
Value: !Ref 'AWS::StackId' | |
GenerateSecretString: | |
SecretStringTemplate: !Join ['', ['{"username": "', !Ref DBUsername, '"}']] | |
GenerateStringKey: "password" | |
ExcludeCharacters: '"@/\' | |
PasswordLength: 16 | |
SecretAuroraClusterAttachment: | |
Condition: IsNotUseDBSnapshot | |
Type: AWS::SecretsManager::SecretTargetAttachment | |
Properties: | |
SecretId: !Ref AuroraMasterSecret | |
TargetId: !Ref AuroraDBCluster | |
TargetType: AWS::RDS::DBCluster | |
AuroraSecretResourcePolicy: | |
Condition: IsNotUseDBSnapshot | |
Type: AWS::SecretsManager::ResourcePolicy | |
Properties: | |
SecretId: !Ref AuroraMasterSecret | |
ResourcePolicy: | |
Version: "2012-10-17" | |
Statement: | |
- | |
Effect: "Deny" | |
Principal: | |
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root" | |
Action: "secretsmanager:DeleteSecret" | |
Resource: "*" | |
CreateSecretRotationLambdaRole: | |
Condition: IsNotUseDBSnapshot | |
Type: AWS::IAM::Role | |
Properties: | |
AssumeRolePolicyDocument: | |
Version: "2012-10-17" | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: | |
- lambda.amazonaws.com | |
Action: | |
- sts:AssumeRole | |
Path: "/" | |
ManagedPolicyArns: | |
- 'arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole' | |
- 'arn:aws:iam::aws:policy/SecretsManagerReadWrite' | |
- 'arn:aws:iam::aws:policy/IAMFullAccess' | |
Policies: | |
- | |
PolicyName: "AdditionalPermissions" | |
PolicyDocument: | |
Version: "2012-10-17" | |
Statement: | |
- | |
Effect: "Allow" | |
Action: | |
- "cloudformation:DescribeStackResources" | |
- "cloudformation:DeleteStack" | |
Resource: !Sub 'arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/serverlessrepo-${AWS::StackName}-SecretRotationLambdaStack/*' | |
- | |
Effect: "Allow" | |
Action: | |
- "lambda:DeleteFunction" | |
- "lambda:GetFunctionConfiguration" | |
- "lambda:RemovePermission" | |
Resource: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:SecretsManager-SecretRotationFn-${AWS::StackName}' | |
CreateSecretRotationLambdaFn: | |
Condition: IsNotUseDBSnapshot | |
Type: AWS::Lambda::Function | |
DependsOn: | |
- CreateSecretRotationLambdaRole | |
Properties: | |
Code: | |
ZipFile: | | |
import cfnresponse | |
import boto3 | |
from botocore.vendored import requests | |
def lambda_handler(event, context): | |
slrepoclient = boto3.client('serverlessrepo') | |
cfclient = boto3.client('cloudformation') | |
lambdaclient = boto3.client('lambda') | |
SecretsManagerEndpoint = event['ResourceProperties']['SecretsManagerEndpoint'] | |
SecretRotationLambdaFnName = event['ResourceProperties']['SecretRotationLambdaFnName'] | |
SecretRotationLambdaStackName = event['ResourceProperties']['SecretRotationLambdaStackName'] | |
SubnetIds = event['ResourceProperties']['SubnetIds'] | |
SecretRotationLambdaSG = event['ResourceProperties']['SecretRotationLambdaSG'] | |
responseData = {} | |
try: | |
if event['RequestType'] == 'Create': | |
serverlessreporesponse = slrepoclient.create_cloud_formation_change_set(ApplicationId='arn:aws:serverlessrepo:us-east-1:297356227824:applications/SecretsManagerRDSPostgreSQLRotationSingleUser', | |
Capabilities=['CAPABILITY_IAM', 'CAPABILITY_RESOURCE_POLICY'], | |
ParameterOverrides=[ | |
{ | |
'Name': 'endpoint', | |
'Value': SecretsManagerEndpoint | |
}, | |
{ | |
'Name': 'functionName', | |
'Value': SecretRotationLambdaFnName | |
}, | |
], | |
StackName=SecretRotationLambdaStackName) | |
waiter = cfclient.get_waiter('change_set_create_complete') | |
waiter.wait(ChangeSetName=serverlessreporesponse['ChangeSetId'],WaiterConfig={'Delay': 10,'MaxAttempts': 60}) | |
cloudformationresponse = cfclient.execute_change_set(ChangeSetName=serverlessreporesponse['ChangeSetId']) | |
waiter = cfclient.get_waiter('stack_create_complete') | |
waiter.wait(StackName=serverlessreporesponse['StackId'],WaiterConfig={'Delay': 10,'MaxAttempts': 60}) | |
lambdaresponse = lambdaclient.add_permission(FunctionName=SecretRotationLambdaFnName,StatementId='SecretsManagerAccess',Action='lambda:InvokeFunction',Principal='secretsmanager.amazonaws.com') | |
lambdaresponse = lambdaclient.update_function_configuration(FunctionName=SecretRotationLambdaFnName,VpcConfig={'SubnetIds': SubnetIds,'SecurityGroupIds': SecretRotationLambdaSG}) | |
responseData['Data'] = "SUCCESS: Secret Rotation Lambda created successfully." | |
responseData['SecretRotationLambdaARN'] = lambdaclient.get_function(FunctionName=SecretRotationLambdaFnName)['Configuration']['FunctionArn'] | |
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "None") | |
elif event['RequestType'] == 'Delete': | |
SecretRotationLambdaStackName = 'serverlessrepo-' + SecretRotationLambdaStackName | |
response = cfclient.delete_stack(StackName=SecretRotationLambdaStackName) | |
waiter = cfclient.get_waiter('stack_delete_complete') | |
waiter.wait(StackName='string',WaiterConfig={'Delay': 10,'MaxAttempts': 60}) | |
responseData['Data'] = "SUCCESS: Stack delete complete." | |
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "None") | |
else: | |
responseData['Data'] = "{} is unsupported stack operation for this lambda function.".format(event['RequestType']) | |
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "None") | |
except Exception as e: | |
print(e) | |
responseData['Data'] = "ERROR: Exception encountered!" | |
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "None") | |
Description: >- | |
Create Secret Rotation Lambda function using AWS Serverless Application Repository with template provided by AWS Secrets Manager | |
Handler: index.lambda_handler | |
MemorySize: 128 | |
Role: !GetAtt CreateSecretRotationLambdaRole.Arn | |
Runtime: python3.6 | |
Timeout: 120 | |
VpcConfig: | |
SecurityGroupIds: !Split [',', {'Fn::ImportValue': !Sub '${ParentVPCStack}-SecretRotationLambdaSecurityGroup'}] | |
SubnetIds: !Split [',', {'Fn::ImportValue': !Sub '${ParentVPCStack}-SubnetsPrivate'}] | |
CreateSecretRotationLambdaFnTrigger: | |
Condition: IsNotUseDBSnapshot | |
Type: Custom::LambdaAPGSecretsManager | |
Version: "1.0" | |
Properties: | |
ServiceToken: !GetAtt 'CreateSecretRotationLambdaFn.Arn' | |
SecretsManagerEndpoint: !Sub 'https://secretsmanager.${AWS::Region}.amazonaws.com' | |
SecretRotationLambdaFnName: !Sub 'SecretsManager-SecretRotationFn-${AWS::StackName}' | |
SecretRotationLambdaStackName: !Sub '${AWS::StackName}-SecretRotationLambdaStack' | |
SubnetIds: !Split [',', {'Fn::ImportValue': !Sub '${ParentVPCStack}-SubnetsPrivate'}] | |
SecretRotationLambdaSG: !Split [',', {'Fn::ImportValue': !Sub '${ParentVPCStack}-SecretRotationLambdaSecurityGroup'}] | |
AuroraSecretRotationSchedule: | |
Condition: IsNotUseDBSnapshot | |
Type: AWS::SecretsManager::RotationSchedule | |
DependsOn: | |
- SecretAuroraClusterAttachment | |
- AuroraDBFirstInstance | |
Properties: | |
SecretId: !Ref AuroraMasterSecret | |
RotationLambdaARN: !GetAtt CreateSecretRotationLambdaFnTrigger.SecretRotationLambdaARN | |
RotationRules: | |
AutomaticallyAfterDays: 30 | |
AuroraDBCluster: | |
Type: AWS::RDS::DBCluster | |
DeletionPolicy: Snapshot | |
UpdateReplacePolicy: Snapshot | |
Properties: | |
Engine: aurora-postgresql | |
EngineVersion: !Ref DBEngineVersion | |
DatabaseName: !If [IsUseDBSnapshot, !Ref "AWS::NoValue", !Ref DBName] | |
Port: !Ref DBPort | |
MasterUsername: | |
!If [IsUseDBSnapshot, !Ref "AWS::NoValue", !Join ['', ['{{resolve:secretsmanager:', !Ref AuroraMasterSecret, ':SecretString:username}}' ]]] | |
MasterUserPassword: | |
!If [IsUseDBSnapshot, !Ref "AWS::NoValue", !Join ['', ['{{resolve:secretsmanager:', !Ref AuroraMasterSecret, ':SecretString:password}}' ]]] | |
DBSubnetGroupName: !Ref DBSubnetGroup | |
VpcSecurityGroupIds: | |
- !Ref ClusterSecurityGroup | |
BackupRetentionPeriod: !If [IsProd, 35, 7] | |
DBClusterParameterGroupName: !Ref RDSDBClusterParameterGroup | |
SnapshotIdentifier: !If [IsUseDBSnapshot, !Ref DBSnapshotName, !Ref "AWS::NoValue"] | |
StorageEncrypted: !If [IsUseDBSnapshot, !Ref "AWS::NoValue", true] | |
KmsKeyId: !If [IsNotUseDBSnapshot, !Ref AuroraKMSCMK, !Ref 'AWS::NoValue'] | |
EnableIAMDatabaseAuthentication: !If [DoEnableIAM, true, !Ref "AWS::NoValue"] | |
Tags: | |
- | |
Key: EnvironmentStage | |
Value: !Ref EnvironmentStage | |
- | |
Key: Application | |
Value: !Ref Application | |
- | |
Key: ApplicationVersion | |
Value: !Ref ApplicationVersion | |
- | |
Key: ProjectCostCenter | |
Value: !Ref ProjectCostCenter | |
- | |
Key: ServiceOwnersEmailContact | |
Value: !Ref ServiceOwnersEmailContact | |
- | |
Key: Confidentiality | |
Value: !Ref Confidentiality | |
- | |
Key: Compliance | |
Value: !Ref Compliance | |
AuroraDBFirstInstance: | |
Type: AWS::RDS::DBInstance | |
Properties: | |
CopyTagsToSnapshot: true | |
DBInstanceClass: | |
Ref: DBInstanceClass | |
DBClusterIdentifier: !Ref AuroraDBCluster | |
Engine: aurora-postgresql | |
EngineVersion: !Ref DBEngineVersion | |
DBParameterGroupName: | |
Ref: DBParamGroup | |
MonitoringInterval: !If [IsProd, 1, 0] | |
MonitoringRoleArn: !If [IsProd, !GetAtt MonitoringIAMRole.Arn, !Ref "AWS::NoValue"] | |
AutoMinorVersionUpgrade: !If [IsProd, 'false', 'true'] | |
DBSubnetGroupName: !Ref DBSubnetGroup | |
PubliclyAccessible: false | |
EnablePerformanceInsights: true | |
PerformanceInsightsKMSKeyId: !Ref AuroraKMSCMK | |
PerformanceInsightsRetentionPeriod: !If [IsProd, 731, 7] | |
Tags: | |
- | |
Key: EnvironmentStage | |
Value: !Ref EnvironmentStage | |
- | |
Key: Application | |
Value: !Ref Application | |
- | |
Key: ApplicationVersion | |
Value: !Ref ApplicationVersion | |
- | |
Key: ProjectCostCenter | |
Value: !Ref ProjectCostCenter | |
- | |
Key: ServiceOwnersEmailContact | |
Value: !Ref ServiceOwnersEmailContact | |
- | |
Key: Confidentiality | |
Value: !Ref Confidentiality | |
- | |
Key: Compliance | |
Value: !Ref Compliance | |
AuroraDBSecondInstance: | |
Condition: IsReplica | |
Type: AWS::RDS::DBInstance | |
DependsOn: | |
- AuroraDBFirstInstance | |
Properties: | |
CopyTagsToSnapshot: true | |
DBInstanceClass: | |
Ref: DBInstanceClass | |
DBClusterIdentifier: !Ref AuroraDBCluster | |
Engine: aurora-postgresql | |
EngineVersion: !Ref DBEngineVersion | |
DBParameterGroupName: | |
Ref: DBParamGroup | |
MonitoringInterval: !If [IsProd, 1, 0] | |
MonitoringRoleArn: !If [IsProd, !GetAtt MonitoringIAMRole.Arn, !Ref "AWS::NoValue"] | |
AutoMinorVersionUpgrade: !If [IsProd, 'false', 'true'] | |
DBSubnetGroupName: !Ref DBSubnetGroup | |
PubliclyAccessible: false | |
EnablePerformanceInsights: true | |
PerformanceInsightsKMSKeyId: !Ref AuroraKMSCMK | |
PerformanceInsightsRetentionPeriod: !If [IsProd, 731, 7] | |
Tags: | |
- | |
Key: EnvironmentStage | |
Value: !Ref EnvironmentStage | |
- | |
Key: Application | |
Value: !Ref Application | |
- | |
Key: ApplicationVersion | |
Value: !Ref ApplicationVersion | |
- | |
Key: ProjectCostCenter | |
Value: !Ref ProjectCostCenter | |
- | |
Key: ServiceOwnersEmailContact | |
Value: !Ref ServiceOwnersEmailContact | |
- | |
Key: Confidentiality | |
Value: !Ref Confidentiality | |
- | |
Key: Compliance | |
Value: !Ref Compliance | |
CPUUtilizationAlarm1: | |
Type: "AWS::CloudWatch::Alarm" | |
Properties: | |
ActionsEnabled: true | |
AlarmActions: | |
- Ref: DBSNSTopic | |
AlarmDescription: 'CPU_Utilization' | |
Dimensions: | |
- Name: DBInstanceIdentifier | |
Value: | |
Ref: AuroraDBFirstInstance | |
MetricName: CPUUtilization | |
Statistic: Maximum | |
Namespace: 'AWS/RDS' | |
Threshold: '80' | |
Unit: Percent | |
ComparisonOperator: 'GreaterThanOrEqualToThreshold' | |
Period: '60' | |
EvaluationPeriods: '5' | |
TreatMissingData: 'notBreaching' | |
CPUUtilizationAlarm2: | |
Condition: IsReplica | |
Type: "AWS::CloudWatch::Alarm" | |
Properties: | |
ActionsEnabled: true | |
AlarmActions: | |
- Ref: DBSNSTopic | |
AlarmDescription: 'CPU_Utilization' | |
Dimensions: | |
- Name: DBInstanceIdentifier | |
Value: | |
Ref: AuroraDBSecondInstance | |
MetricName: CPUUtilization | |
Statistic: Maximum | |
Namespace: 'AWS/RDS' | |
Threshold: '80' | |
Unit: Percent | |
ComparisonOperator: 'GreaterThanOrEqualToThreshold' | |
Period: '60' | |
EvaluationPeriods: '5' | |
TreatMissingData: 'notBreaching' | |
MaxUsedTxIDsAlarm1: | |
Type: "AWS::CloudWatch::Alarm" | |
Properties: | |
ActionsEnabled: true | |
AlarmActions: | |
- Ref: DBSNSTopic | |
AlarmDescription: 'Maximum Used Transaction IDs' | |
Dimensions: | |
- Name: DBInstanceIdentifier | |
Value: | |
Ref: AuroraDBFirstInstance | |
MetricName: 'MaximumUsedTransactionIDs' | |
Statistic: Average | |
Namespace: 'AWS/RDS' | |
Threshold: '600000000' | |
Unit: Count | |
ComparisonOperator: 'GreaterThanOrEqualToThreshold' | |
Period: '60' | |
EvaluationPeriods: '5' | |
TreatMissingData: 'notBreaching' | |
MaxUsedTxIDsAlarm2: | |
Condition: IsReplica | |
Type: "AWS::CloudWatch::Alarm" | |
Properties: | |
ActionsEnabled: true | |
AlarmActions: | |
- Ref: DBSNSTopic | |
AlarmDescription: 'Maximum Used Transaction IDs' | |
Dimensions: | |
- Name: DBInstanceIdentifier | |
Value: | |
Ref: AuroraDBSecondInstance | |
MetricName: 'MaximumUsedTransactionIDs' | |
Statistic: Average | |
Namespace: 'AWS/RDS' | |
Threshold: '600000000' | |
Unit: Count | |
ComparisonOperator: 'GreaterThanOrEqualToThreshold' | |
Period: '60' | |
EvaluationPeriods: '5' | |
TreatMissingData: 'notBreaching' | |
FreeLocalStorageAlarm1: | |
Type: "AWS::CloudWatch::Alarm" | |
Properties: | |
ActionsEnabled: true | |
AlarmActions: | |
- Ref: DBSNSTopic | |
AlarmDescription: 'Free Local Storage' | |
Dimensions: | |
- Name: DBInstanceIdentifier | |
Value: | |
Ref: AuroraDBFirstInstance | |
MetricName: 'FreeLocalStorage' | |
Statistic: Average | |
Namespace: 'AWS/RDS' | |
Threshold: '5368709120' | |
Unit: Bytes | |
ComparisonOperator: 'LessThanOrEqualToThreshold' | |
Period: '60' | |
EvaluationPeriods: '5' | |
TreatMissingData: 'notBreaching' | |
FreeLocalStorageAlarm2: | |
Condition: IsReplica | |
Type: "AWS::CloudWatch::Alarm" | |
Properties: | |
ActionsEnabled: true | |
AlarmActions: | |
- Ref: DBSNSTopic | |
AlarmDescription: 'Free Local Storage' | |
Dimensions: | |
- Name: DBInstanceIdentifier | |
Value: | |
Ref: AuroraDBSecondInstance | |
MetricName: 'FreeLocalStorage' | |
Statistic: Average | |
Namespace: 'AWS/RDS' | |
Threshold: '5368709120' | |
Unit: Bytes | |
ComparisonOperator: 'LessThanOrEqualToThreshold' | |
Period: '60' | |
EvaluationPeriods: '5' | |
TreatMissingData: 'notBreaching' | |
DatabaseClusterEventSubscription: | |
Type: 'AWS::RDS::EventSubscription' | |
Properties: | |
EventCategories: | |
- failover | |
- failure | |
- notification | |
SnsTopicArn: !Ref DBSNSTopic | |
SourceIds: [!Ref AuroraDBCluster] | |
SourceType: 'db-cluster' | |
DatabaseInstanceEventSubscription: | |
Type: 'AWS::RDS::EventSubscription' | |
Properties: | |
EventCategories: | |
- availability | |
- configuration change | |
- deletion | |
- failover | |
- failure | |
- maintenance | |
- notification | |
- recovery | |
SnsTopicArn: !Ref DBSNSTopic | |
SourceIds: | |
- !Ref AuroraDBFirstInstance | |
- !If [IsReplica, !Ref AuroraDBSecondInstance, !Ref "AWS::NoValue"] | |
SourceType: 'db-instance' | |
DBParameterGroupEventSubscription: | |
Type: 'AWS::RDS::EventSubscription' | |
Properties: | |
EventCategories: | |
- configuration change | |
SnsTopicArn: !Ref DBSNSTopic | |
SourceIds: [!Ref DBParamGroup] | |
SourceType: 'db-parameter-group' | |
DBBootStrapLambdaFn: | |
Condition: DoDBBootStrap | |
Type: AWS::Lambda::Function | |
DependsOn: | |
- DBBootStrapLambdaRole | |
Properties: | |
Code: | |
S3Bucket: !Ref LambdaBootStrapS3Bucket | |
S3Key: !Ref LambdaBootStrapS3Key | |
Description: >- | |
BootStrap newly Created Aurora PostgreSQL Database | |
Handler: dbbootstrap.handler | |
MemorySize: 128 | |
Role: !GetAtt DBBootStrapLambdaRole.Arn | |
Runtime: python3.6 | |
Timeout: 60 | |
VpcConfig: | |
SecurityGroupIds: !Split [',', {'Fn::ImportValue': !Sub '${ParentVPCStack}-SecretRotationLambdaSecurityGroup'}] | |
SubnetIds: !Split [',', {'Fn::ImportValue': !Sub '${ParentVPCStack}-SubnetsPrivate'}] | |
Environment: | |
Variables: | |
DBHost: !GetAtt 'AuroraDBCluster.Endpoint.Address' | |
DBPort: !GetAtt 'AuroraDBCluster.Endpoint.Port' | |
DBUser: !Ref DBUsername | |
DBName: !Ref DBName | |
Secret_ARN: !Ref AuroraMasterSecret | |
Region_Name: !Ref "AWS::Region" | |
DBBootStrapLambdaFnTrigger: | |
Condition: DoDBBootStrap | |
Type: Custom::LambdaAPGBootStrap | |
DependsOn: | |
- AuroraDBFirstInstance | |
- AuroraSecretRotationSchedule | |
Version: "1.0" | |
Properties: | |
ServiceToken: !GetAtt 'DBBootStrapLambdaFn.Arn' | |
############################################################################### | |
# Outputs | |
############################################################################### | |
Outputs: | |
ClusterEndpoint: | |
Description: 'Aurora Cluster/Writer Endpoint' | |
Value: !GetAtt 'AuroraDBCluster.Endpoint.Address' | |
ReaderEndpoint: | |
Description: 'Aurora Reader Endpoint' | |
Value: !GetAtt 'AuroraDBCluster.ReadEndpoint.Address' | |
Port: | |
Description: 'Aurora Endpoint Port' | |
Value: !GetAtt 'AuroraDBCluster.Endpoint.Port' | |
DBUsername: | |
Description: 'Database master username' | |
Value: !Ref DBUsername | |
DBName: | |
Description: 'Database Name' | |
Value: !Ref DBName | |
PSQLCommandLine: | |
Description: PSQL Command Line | |
Value: !Join | |
- '' | |
- - 'psql --host=' | |
- !GetAtt 'AuroraDBCluster.Endpoint.Address' | |
- ' --port=' | |
- !GetAtt 'AuroraDBCluster.Endpoint.Port' | |
- ' --username=' | |
- !Ref DBUsername | |
- ' --dbname=' | |
- !Ref DBName | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment