AWSTemplateFormatVersion: "2010-09-09" Description: "DBTop Monitoring Solution" Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: "Application Update - Disclaimer" Parameters: - ApplicationUpdateEnabled - ApplicationUpdateUrl - Label: default: "General Configuration" Parameters: - Username - AMIId - InstanceType - GitHubRepository - Label: default: "Network Configuration" Parameters: - VPCParam - SubnetParam - PublicAccess - SGInboundAccess ParameterLabels: Username: default: "Specify username for application access, temporary credentials will be sent by email." AMIId: default: "Specify AWS Linux AMI to be used for Application Deployment." InstanceType: default: "Specify instance type for Application Deployment." VPCParam: default: "Select VPC for Application Deployment." SubnetParam: default: "Select Subnet for Application Deployment, this subnet needs internet outbound access to reach AWS APIs." PublicAccess: default: "The deployment will assign private IP Address by default to access the application, you can assign Public IP Address to access the application in case you need it, Select (true) to assign Public IP Address." SGInboundAccess: default: "Specify CIDR inbound access rule, this will grant network access for the application." GitHubRepository: default: "AWS Github Repository source used for deployment." ApplicationUpdateEnabled: default: "Disclaimer : This Application could able to verify new versions, it will help to keep update with most popular features. Customer can review the code and validate data scope. Selecting (true) I acknowledge that this Application will access to url to verify new versions." ApplicationUpdateUrl: default: "URL used to verify new application versions." Parameters: VPCParam: Type: AWS::EC2::VPC::Id Description: Select VPC SubnetParam: Type: AWS::EC2::Subnet::Id Description: Select Subnet AMIId: Type: AWS::SSM::Parameter::Value Description: AWS AMI Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64' Username: Type: String Description: Username (email) AllowedPattern: "\\w[-\\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\\.)+[A-Za-z]{2,14}" InstanceType: Type: String Description: InstanceType Default: t3a.medium AllowedValues: - t3a.micro - t3a.small - t3a.medium - t3a.large - t3a.xlarge PublicAccess: Type: String Description: Assign Public IP Address Default: "false" AllowedValues: - "true" - "false" SGInboundAccess: Type: String Description: CIDR (0.0.0.0/0) GitHubRepository: Type: String Description: AWS Github Repository Default: aws-samples ApplicationUpdateUrl: Type: String Description: URL Default: https://version.code.ds.wwcs.aws.dev/ ApplicationUpdateEnabled: Type: String Description: Option Default: "true" AllowedValues: - "true" - "false" Conditions: isPublic: !Equals [ !Ref PublicAccess, true] Resources: InstanceProfile: Type: "AWS::IAM::InstanceProfile" DependsOn: IAMRoleEC2 Properties: Path: "/" Roles: [!Ref IAMRoleEC2] IAMPolicyEc2: Type: AWS::IAM::ManagedPolicy Properties: ManagedPolicyName: !Join [ "-", ["policy-ec2-db-top-solution", !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]] PolicyDocument: !Sub | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:GetLogEvents" ], "Resource": [ "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:RDSOSMetrics:log-stream:*" ] }, { "Effect": "Allow", "Action": [ "cloudwatch:GetMetricData" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "rds:DescribeDBInstances" ], "Resource": "arn:aws:rds:${AWS::Region}:${AWS::AccountId}:db:*" }, { "Effect": "Allow", "Action": [ "rds:DescribeDBClusters" ], "Resource": "arn:aws:rds:${AWS::Region}:${AWS::AccountId}:cluster:*" }, { "Effect": "Allow", "Action": [ "elasticache:DescribeReplicationGroups" ], "Resource": "arn:aws:elasticache:${AWS::Region}:${AWS::AccountId}:replicationgroup:*" }, { "Effect": "Allow", "Action": [ "elasticache:DescribeServerlessCaches" ], "Resource": "arn:aws:elasticache:${AWS::Region}:${AWS::AccountId}:serverlesscache:*" }, { "Effect": "Allow", "Action": "memorydb:DescribeClusters", "Resource": "arn:aws:memorydb:${AWS::Region}:${AWS::AccountId}:cluster/*" }, { "Effect": "Allow", "Action": "docdb-elastic:GetCluster", "Resource": "arn:aws:docdb-elastic:${AWS::Region}:${AWS::AccountId}:cluster/*" }, { "Effect": "Allow", "Action": "docdb-elastic:ListClusters", "Resource": "*" }, { "Effect": "Allow", "Action": "dynamodb:DescribeTable", "Resource": "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/*" }, { "Effect": "Allow", "Action": "dynamodb:ListTables", "Resource": "*" } ] } IAMRoleEC2: Type: "AWS::IAM::Role" DependsOn: IAMPolicyEc2 Properties: Path: "/" RoleName: !Join [ "-", ["role-ec2-db-top-solution", !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]] AssumeRolePolicyDocument: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}" MaxSessionDuration: 3600 Description: "Allows EC2 instance to call AWS services on your behalf." ManagedPolicyArns: - !Ref IAMPolicyEc2 - "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" IAMRoleCognito: Type: "AWS::IAM::Role" Properties: Path: "/" RoleName: !Join [ "-", ["role-cognito-db-top-solution", !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]] AssumeRolePolicyDocument: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"cognito-idp.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}" MaxSessionDuration: 3600 Description: "Allows Cognito to use SMS MFA on your behalf." Policies: - PolicyName: "CognitoPolicy" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "sns:publish" Resource: "*" EC2Instance: Type: "AWS::EC2::Instance" DependsOn: [CognitoUserPool,IAMRoleEC2] Properties: ImageId: !Ref AMIId InstanceType: !Ref InstanceType Tenancy: "default" EbsOptimized: true SourceDestCheck: true BlockDeviceMappings: - DeviceName: "/dev/xvda" Ebs: Encrypted: false VolumeSize: 20 VolumeType: "gp2" DeleteOnTermination: true IamInstanceProfile: !Ref InstanceProfile NetworkInterfaces: - AssociatePublicIpAddress: !Ref PublicAccess DeviceIndex: "0" GroupSet: - Ref: VPCSecurityGroup SubnetId: Ref: SubnetParam UserData: Fn::Base64: !Sub | #!/bin/bash sudo mkdir -p /aws/apps cd /tmp sudo yum install -y git git clone https://github.com/${GitHubRepository}/db-top-monitoring.git cd db-top-monitoring sudo cp -r server frontend conf /aws/apps echo '{ "aws_region": "${AWS::Region}","aws_cognito_user_pool_id": "${CognitoUserPool}","aws_cognito_user_pool_web_client_id": "${CognitoUserPoolClient}","aws_api_port": 3000, "aws_token_expiration":24, "aws_application_update_url" : "${ApplicationUpdateUrl}", "aws_application_update_enabled" : "${ApplicationUpdateEnabled}" }' > /aws/apps/conf/aws-exports.json cd /aws/apps sudo -u ec2-user sh conf/setup.sh 2>&1 | tee /tmp/setup.log sudo sed -i 's/GitHubRepository/${GitHubRepository}/g' /aws/apps/conf/update.sh Tags: - Key: "Name" Value: !Join [ "-", ["ec2-db-top-solution", !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]] VPCSecurityGroup: Type: "AWS::EC2::SecurityGroup" Properties: GroupDescription: !Join [ "_", ["sg_security_group_db_top_solution", !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]] GroupName: !Join [ "_", ["sg_security_group_db_top_solution", !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]] VpcId: !Ref VPCParam SecurityGroupIngress: - CidrIp: !Ref SGInboundAccess FromPort: 443 IpProtocol: "tcp" ToPort: 443 SecurityGroupEgress: - CidrIp: "0.0.0.0/0" IpProtocol: "-1" CognitoUserPool: Type: "AWS::Cognito::UserPool" Properties: UserPoolName: !Join [ "-", ["AwsDbTopSolutionUserPool", !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]] Policies: PasswordPolicy: MinimumLength: 8 RequireUppercase: true RequireLowercase: true RequireNumbers: true RequireSymbols: true TemporaryPasswordValidityDays: 7 LambdaConfig: {} AutoVerifiedAttributes: - "email" UsernameAttributes: - "email" MfaConfiguration: "OPTIONAL" SmsConfiguration: SnsCallerArn: !GetAtt IAMRoleCognito.Arn SnsRegion: !Ref AWS::Region EmailConfiguration: EmailSendingAccount: "COGNITO_DEFAULT" AdminCreateUserConfig: AllowAdminCreateUserOnly: true UserPoolTags: {} AccountRecoverySetting: RecoveryMechanisms: - Priority: 1 Name: "verified_email" UsernameConfiguration: CaseSensitive: false VerificationMessageTemplate: DefaultEmailOption: "CONFIRM_WITH_CODE" CognitoUserPoolClient: Type: "AWS::Cognito::UserPoolClient" Properties: UserPoolId: !Ref CognitoUserPool ClientName: !Join [ "-", ["AwsDbTopSolutionUserPoolClient", !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]] RefreshTokenValidity: 1 ReadAttributes: - "address" - "birthdate" - "email" - "email_verified" - "family_name" - "gender" - "given_name" - "locale" - "middle_name" - "name" - "nickname" - "phone_number" - "phone_number_verified" - "picture" - "preferred_username" - "profile" - "updated_at" - "website" - "zoneinfo" WriteAttributes: - "address" - "birthdate" - "email" - "family_name" - "gender" - "given_name" - "locale" - "middle_name" - "name" - "nickname" - "phone_number" - "picture" - "preferred_username" - "profile" - "updated_at" - "website" - "zoneinfo" ExplicitAuthFlows: - "ALLOW_REFRESH_TOKEN_AUTH" - "ALLOW_USER_SRP_AUTH" PreventUserExistenceErrors: "ENABLED" AllowedOAuthFlowsUserPoolClient: false IdTokenValidity: 1440 AccessTokenValidity: 1440 TokenValidityUnits: AccessToken: "minutes" IdToken: "minutes" RefreshToken: "days" CognitoUserPoolUser: Type: "AWS::Cognito::UserPoolUser" Properties: Username: !Ref Username UserPoolId: !Ref CognitoUserPool UserAttributes: - Name: "email_verified" Value: "true" - Name: "email" Value: !Ref Username Outputs: PublicAppURL: Description: Public Endpoint Value: !Join [ "", ["https://", !GetAtt EC2Instance.PublicIp]] Condition: isPublic PrivateAppURL: Description: Private Endpoint Value: !Join [ "", ["https://", !GetAtt EC2Instance.PrivateIp]]