report/conf/report.yaml (300 lines of code) (raw):
AWSTemplateFormatVersion: '2010-09-09'
Description: Reporting for mobile notifications
Mappings:
Constants:
App:
Value: report
Stack:
Value: mobile-notifications
StageVariables:
CODE:
NotificationAlarmPeriod: 1200
ScalingUpPeriod: 300
ScalingUpThreshold: 20
ScalingDownPeriod: 300
ScalingDownThreshold: 15
InstanceType: "t4g.micro"
PROD:
NotificationAlarmPeriod: 1200
ScalingUpPeriod: 300
ScalingUpThreshold: 20
ScalingDownPeriod: 300
ScalingDownThreshold: 15
InstanceType: "t4g.micro"
Outputs:
LoadBalancerUrl:
Value:
!GetAtt LoadBalancerToPrivateASG.DNSName
Parameters:
AMI:
Description: AMI used by the instances,
Type: AWS::EC2::Image::Id
Stage:
Type: String
AllowedValues:
- CODE
- PROD
Description: Environment name
VPCSecurityGroup:
Type: AWS::EC2::SecurityGroup::Id
Description: The default security group of the VPC
VpcId:
Type: AWS::EC2::VPC::Id
Description: The VPC
PublicSubnets:
Type: List<AWS::EC2::Subnet::Id>
Description: The public subnets of the VPC for the loadbalancer
PrivateSubnets:
Type: List<AWS::EC2::Subnet::Id>
Description: The private subnets of the VPC for the autoscaling group
ASGMinSize:
Type: Number
Description: Minimum size of the autoscaling group
ASGMaxSize:
Type: Number
Description: Maximum size of the autoscaling group
DistBucket:
Type: String
Description: The name of the s3 bucket containing the server artifact
AppCertArn:
Type: String
Description: ACM Certificate for app use
HostedZone:
Type: String
Description: The HostedZone, should contain the trailing dot zone.example.com.
DomainName:
Type: String
Description: The domain name of the ELB, should contain the trailing dot stuff.zone.example.com.
Resources:
DnsRecord:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: !Ref HostedZone
Name: !Ref DomainName
ResourceRecords:
- !GetAtt LoadBalancerToPrivateASG.DNSName
TTL: 60
Type: CNAME
GuardianAccessSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: SSH and management server access from Guardian network
SecurityGroupIngress:
- SourceSecurityGroupId: !Ref VPCSecurityGroup
FromPort: 22
IpProtocol: tcp
ToPort: 22
VpcId: !Ref VpcId
HighCpuAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmActions: [!Ref ScaleUpPolicy]
AlarmDescription: !Sub
- Scale-Up if cpu is greater than ${Threshold}% over last ${Period} seconds
- Threshold: !FindInMap [ StageVariables, !Ref Stage, ScalingUpThreshold ]
Period: !FindInMap [ StageVariables, !Ref Stage, ScalingUpPeriod ]
ComparisonOperator: GreaterThanOrEqualToThreshold
Dimensions:
- Name: AutoScalingGroupName
Value: !Ref PrivateReportAutoscalingGroup
EvaluationPeriods: 1
MetricName: CPUUtilization
Namespace: AWS/EC2
Period: !FindInMap [ StageVariables, !Ref Stage, ScalingUpPeriod ]
Statistic: Average
Threshold: !FindInMap [ StageVariables, !Ref Stage, ScalingUpThreshold ]
LowCpuAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmActions: [!Ref ScaleDownPolicy]
AlarmDescription: !Sub
- Scale-Down if cpu is lower than ${Threshold}% over last ${Period} seconds
- Threshold: !FindInMap [ StageVariables, !Ref Stage, ScalingDownThreshold ]
Period: !FindInMap [ StageVariables, !Ref Stage, ScalingDownPeriod ]
ComparisonOperator: LessThanThreshold
Dimensions:
- Name: AutoScalingGroupName
Value: !Ref PrivateReportAutoscalingGroup
EvaluationPeriods: 1
MetricName: CPUUtilization
Namespace: AWS/EC2
Period: !FindInMap [ StageVariables, !Ref Stage, ScalingDownPeriod ]
Statistic: Average
Threshold: !FindInMap [ StageVariables, !Ref Stage, ScalingDownThreshold ]
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Open up HTTP access to load balancer
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 80
IpProtocol: tcp
ToPort: 80
- CidrIp: 0.0.0.0/0
FromPort: 443
IpProtocol: tcp
ToPort: 443
SecurityGroupIngress:
- FromPort: 9000
IpProtocol: tcp
SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup
ToPort: 9000
VpcId: !Ref VpcId
LoadBalancerToPrivateASG:
Type: AWS::ElasticLoadBalancing::LoadBalancer
Properties:
CrossZone: true
HealthCheck:
HealthyThreshold: 2
Interval: 30
Target: HTTP:9000/healthcheck
Timeout: 10
UnhealthyThreshold: 10
Listeners:
- InstancePort: 9000
LoadBalancerPort: 443
Protocol: HTTPS
SSLCertificateId: !Ref AppCertArn
SecurityGroups:
- !Ref LoadBalancerSecurityGroup
Subnets: !Ref PublicSubnets
LoadBalancerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Open up HTTP access to load balancer
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 9000
IpProtocol: tcp
ToPort: 9000
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
FromPort: 443
IpProtocol: tcp
ToPort: 443
VpcId: !Ref VpcId
NotificationsReportInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref NotificationsReportRole
NotificationsReportRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Path: /
ManagedPolicyArns: [ !Sub 'arn:aws:iam::${AWS::AccountId}:policy/ssm-scala-v1' ]
Policies:
- PolicyName: root
PolicyDocument:
Statement:
- Action: s3:GetObject
Effect: Allow
Resource: !Sub arn:aws:s3:::${DistBucket}/*
- Action: ec2:DescribeTags
Effect: Allow
Resource: '*'
- Action:
- cloudwatch:*
- logs:*
Effect: Allow
Resource: '*'
- Action:
- autoscaling:DescribeAutoScalingInstances
- autoscaling:DescribeAutoScalingGroups
Resource: '*'
Effect: Allow
- Effect: Allow
Action:
- kinesis:PutRecord
- kinesis:PutRecords
- kinesis:DescribeStream
Resource: !Sub arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/mobile-log-aggregation-${Stage}
- PolicyName: dynamo
PolicyDocument:
Statement:
- Action: dynamodb:*
Effect: Allow
Resource:
- !Sub arn:aws:dynamodb:eu-west-1:${AWS::AccountId}:table/mobile-notifications-reports-${Stage}
- !Sub arn:aws:dynamodb:eu-west-1:${AWS::AccountId}:table/mobile-notifications-reports-${Stage}/index/*
- PolicyName: conf
PolicyDocument:
Statement:
- Action: ssm:GetParametersByPath
Effect: Allow
Resource:
!Sub
- arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/notifications/${Stage}/${Stack}
- Stack: !FindInMap [Constants, Stack, Value]
PrivateReportAutoscalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AvailabilityZones: !GetAZs
HealthCheckGracePeriod: 400
HealthCheckType: ELB
LaunchConfigurationName: !Ref ReportLaunchConfig
LoadBalancerNames:
- !Ref LoadBalancerToPrivateASG
MaxSize: !Ref ASGMaxSize
MinSize: !Ref ASGMinSize
NotificationConfiguration:
NotificationTypes:
- autoscaling:EC2_INSTANCE_LAUNCH_ERROR
- autoscaling:EC2_INSTANCE_TERMINATE_ERROR
TopicARN: !Sub arn:aws:sns:eu-west-1:${AWS::AccountId}:AutoscalingNotifications${Stage}
Tags:
- Key: Stage
PropagateAtLaunch: true
Value: !Ref Stage
- Key: Stack
PropagateAtLaunch: true
Value: !FindInMap [Constants, Stack, Value]
- Key: App
PropagateAtLaunch: true
Value: !FindInMap [Constants, App, Value]
VPCZoneIdentifier: !Ref PrivateSubnets
ReportLaunchConfig:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
AssociatePublicIpAddress: false
IamInstanceProfile: !Ref NotificationsReportInstanceProfile
ImageId: !Ref AMI
InstanceType: !FindInMap [StageVariables, !Ref Stage, InstanceType]
SecurityGroups:
- !Ref InstanceSecurityGroup
- !Ref GuardianAccessSecurityGroup
- !Ref VPCSecurityGroup
MetadataOptions:
HttpTokens: required
UserData:
Fn::Base64:
!Sub
- |
#!/bin/bash -ev
aws --region ${AWS::Region} s3 cp s3://${DistBucket}/${Stack}/${Stage}/${App}/${App}_1.0-latest_all.deb /tmp
dpkg -i /tmp/${App}_1.0-latest_all.deb
/opt/aws-kinesis-agent/configure-aws-kinesis-agent ${AWS::Region} mobile-log-aggregation-${Stage} /var/log/${App}/application.log
- Stack: !FindInMap [Constants, Stack, Value]
App: !FindInMap [Constants, App, Value]
ScaleDownPolicy:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AdjustmentType: ChangeInCapacity
AutoScalingGroupName: !Ref PrivateReportAutoscalingGroup
Cooldown: 3600
ScalingAdjustment: -1
ScaleUpPolicy:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AdjustmentType: PercentChangeInCapacity
AutoScalingGroupName: !Ref PrivateReportAutoscalingGroup
Cooldown: 300
ScalingAdjustment: 100