# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 AWSTemplateFormatVersion: 2010-09-09 Description: > Manage your AWS Outposts capacity using Amazon Cloudwatch and AWS Lambda Parameters: Email: Description: Email address or mailing list to send capacity notifications to. Type: String Default: test@example.com AllowedPattern: (?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]) ComputeThreshold: Description: Capacity threshold to use to generate alarms and restrict creating compute resources. Type: Number Default: 80 StorageThreshold: Description: Capacity threshold to use to generate alarms and restrict creating storage resources. Type: Number Default: 80 Subnet: Description: Subnet associated to the AWS Outpost were capacity will be managed Type: String Bucket: Description: Code from GitHub repository Type: String Default: change-me AdminIAMPolicyArnEC2: Type: String Description: ARN of IAM Policy associated with AWS Outposts administrators and that will be managed by solution AdminIAMPolicyArnEBS: Type: String Description: ARN of IAM Policy associated with AWS Outposts administrators and that will be managed by solution OutpostId: Type: String Description: Outpost Id for your Outpost Resources: #Alarms outpostsec2capacitybreachedm5dl: Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: EC2 Capacity has been breached for instance type m5.dl AlarmName: outposts-ec2-capacity-alarm-m5d.large ComparisonOperator: GreaterThanOrEqualToThreshold EvaluationPeriods: 1 MetricName: InstanceTypeCapacityUtilization Namespace: AWS/Outposts Period: 300 Statistic: Average Threshold: !Ref ComputeThreshold TreatMissingData: notBreaching Dimensions: - Name: InstanceType Value: m5d.large - Name: OutpostId Value: !Ref OutpostId outpostsec2capacitybreachedc5d9xl: Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: EC2 Capacity has been breached for instance type r5.24xl AlarmName: outposts-ec2-capacity-alarm-c5d.9xlarge ComparisonOperator: GreaterThanOrEqualToThreshold EvaluationPeriods: 1 MetricName: InstanceTypeCapacityUtilization Namespace: AWS/Outposts Period: 300 Statistic: Average Threshold: !Ref ComputeThreshold TreatMissingData: notBreaching Dimensions: - Name: InstanceType Value: c5d.9xlarge - Name: OutpostId Value: !Ref OutpostId outpostsec2capacitybreachedc524xl: Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: EC2 Capacity has been breached for instance type c5.24xl AlarmName: outposts-ec2-capacity-alarm-c5.24xlarge ComparisonOperator: GreaterThanOrEqualToThreshold EvaluationPeriods: 1 MetricName: InstanceTypeCapacityUtilization Namespace: AWS/Outposts Period: 300 Statistic: Average Threshold: !Ref ComputeThreshold TreatMissingData: notBreaching Dimensions: - Name: InstanceType Value: c5.24xlarge - Name: OutpostId Value: !Ref OutpostId outpostsec2capacitybreachedg4dn: Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: EC2 Capacity has been breached for instance type g4dn.2xlarge AlarmName: outposts-ec2-capacity-alarm-g4dn.2xlarge ComparisonOperator: GreaterThanOrEqualToThreshold EvaluationPeriods: 1 MetricName: InstanceTypeCapacityUtilization Namespace: AWS/Outposts Period: 300 Statistic: Average Threshold: !Ref ComputeThreshold TreatMissingData: notBreaching Dimensions: - Name: InstanceType Value: g4dn.2xlarge - Name: OutpostId Value: !Ref OutpostId outpostsec2capacitybreachedr5dl: Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: EC2 Capacity has been breached for instance type r5.dl AlarmName: outposts-ec2-capacity-alarm-r5d.large ComparisonOperator: GreaterThanOrEqualToThreshold EvaluationPeriods: 1 MetricName: InstanceTypeCapacityUtilization Namespace: AWS/Outposts Period: 300 Statistic: Average Threshold: !Ref ComputeThreshold TreatMissingData: notBreaching Dimensions: - Name: InstanceType Value: r5d.large - Name: OutpostId Value: !Ref OutpostId outpostsec2capacitybreachedr524xl: Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: EC2 Capacity has been breached for instance type r5.24xl AlarmName: outposts-ec2-capacity-alarm-r5.24xlarge ComparisonOperator: GreaterThanOrEqualToThreshold EvaluationPeriods: 1 MetricName: InstanceTypeCapacityUtilization Namespace: AWS/Outposts Period: 300 Statistic: Average Threshold: !Ref ComputeThreshold TreatMissingData: notBreaching Dimensions: - Name: InstanceType Value: r5.24xlarge - Name: OutpostId Value: !Ref OutpostId outpostsec2capacitybreachedi3en: Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: EC2 Capacity has been breached for instance type i3en.metal AlarmName: outposts-ec2-capacity-alarm-i3en.metal ComparisonOperator: GreaterThanOrEqualToThreshold EvaluationPeriods: 1 MetricName: InstanceTypeCapacityUtilization Namespace: AWS/Outposts Period: 300 Statistic: Average Threshold: !Ref ComputeThreshold TreatMissingData: notBreaching Dimensions: - Name: InstanceType Value: i3en.metal - Name: OutpostId Value: !Ref OutpostId outpostsebscapacitybreached: Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: EBS Capacity has been breached for volume type gp2 AlarmName: outposts-ebs-capacity-alarm-breach ComparisonOperator: GreaterThanOrEqualToThreshold EvaluationPeriods: 1 MetricName: EBSVolumeTypeCapacityUtilization Namespace: AWS/Outposts Period: 300 Statistic: Average Threshold: !Ref StorageThreshold TreatMissingData: notBreaching Dimensions: - Name: VolumeType Value: gp2 - Name: OutpostId Value: !Ref OutpostId #CloudWatch Custom Rule OutpostsEC2CapacityRule: Type: AWS::Events::Rule Properties: Description: The custom rule that will notify the lambda when an EC2 alarm changes state EventPattern: source: - "aws.cloudwatch" detail-type: - "CloudWatch Alarm State Change" resources: - Fn::GetAtt: - "outpostsec2capacitybreachedm5dl" - "Arn" - Fn::GetAtt: - "outpostsec2capacitybreachedc5d9xl" - "Arn" - Fn::GetAtt: - "outpostsec2capacitybreachedc524xl" - "Arn" - Fn::GetAtt: - "outpostsec2capacitybreachedg4dn" - "Arn" - Fn::GetAtt: - "outpostsec2capacitybreachedr5dl" - "Arn" - Fn::GetAtt: - "outpostsec2capacitybreachedr524xl" - "Arn" - Fn::GetAtt: - "outpostsec2capacitybreachedi3en" - "Arn" Name: OutpostsEC2CapacityRule State: ENABLED Targets: - Arn: Fn::GetAtt: - "outpostsec2capacitylambda" - "Arn" Id: OutpostsLambdaTargetEC2 - Arn: !Ref SNSTopic Id: EmailNotifEc2Alarm InputTransformer: InputPathsMap: alarm: "$.detail.alarmName" status: "$.detail.state.value" InputTemplate: | "The alarm has entered state " OutpostsEBSCapacityRule: Type: AWS::Events::Rule Properties: Description: The custom rule that will notify the lambda when an EBSalarm changes state EventPattern: source: - "aws.cloudwatch" detail-type: - "CloudWatch Alarm State Change" resources: - Fn::GetAtt: - "outpostsebscapacitybreached" - "Arn" Name: OutpostsEBSCapacityRule State: ENABLED Targets: - Arn: Fn::GetAtt: - "outpostsebscapacitylambda" - "Arn" Id: OutpostsLambdaTargetEBS - Arn: !Ref SNSTopic Id: EmailNotifEBSAlarm InputTransformer: InputPathsMap: alarm: "$.detail.alarmName" status: "$.detail.state.value" InputTemplate: | "The alarm has entered state " #SNS Topic and Subscription and Policy SNSTopic: Type: AWS::SNS::Topic Properties: Subscription: - Endpoint: !Ref Email Protocol: email TopicName: "outposts-ec2-capacity-alarm" KmsMasterKeyId: !Ref myKey SnsTopicPolicy: Type: "AWS::SNS::TopicPolicy" Properties: PolicyDocument: Statement: - Sid: TrustCWEToPublishEventsToMyTopic Effect: Allow Principal: Service: events.amazonaws.com Action: - "sns:Publish" Resource: Ref: SNSTopic Topics: - Ref: SNSTopic myKey: Type: AWS::KMS::Key Properties: Description: Symmetric CMK for SNS topic EnableKeyRotation: true PendingWindowInDays: 20 KeyPolicy: Version: '2012-10-17' Id: key-default-1 Statement: - Sid: Enables cloudwatch to publish Effect: Allow Principal: Service: events.amazonaws.com Action: kms:* Resource: '*' - Sid: Set primary key owner as Root Effect: Allow Principal: AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root" Action: kms:* Resource: '*' #Lambda IAM Roles EC2CapacityRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: sts:AssumeRole Path: / Policies: - PolicyName: outposts-ec2-capacity-lambda-policy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "iam:GetPolicyVersion" - "iam:GetPolicy" - "iam:CreatePolicyVersion" - "iam:DeletePolicyVersion" - "iam:SetDefaultPolicyVersion" Resource: !Ref AdminIAMPolicyArnEC2 EBSCapacityRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: sts:AssumeRole Path: / Policies: - PolicyName: outposts-ebs-capacity-lambda-policy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "iam:GetPolicyVersion" - "iam:GetPolicy" - "iam:CreatePolicyVersion" - "iam:DeletePolicyVersion" - "iam:SetDefaultPolicyVersion" Resource: !Ref AdminIAMPolicyArnEBS # Invoke permissions for the Cloudwatch Rules PermissionForEventsToInvokeLambda: Type: AWS::Lambda::Permission Properties: FunctionName: Ref: "outpostsec2capacitylambda" Action: "lambda:InvokeFunction" Principal: "events.amazonaws.com" SourceArn: Fn::GetAtt: - "OutpostsEC2CapacityRule" - "Arn" EBSInvokePermission: Type: AWS::Lambda::Permission Properties: FunctionName: Ref: "outpostsebscapacitylambda" Action: "lambda:InvokeFunction" Principal: "events.amazonaws.com" SourceArn: Fn::GetAtt: - "OutpostsEBSCapacityRule" - "Arn" #Lambda Functions outpostsec2capacitylambda: Type: "AWS::Lambda::Function" Properties: FunctionName: OutpostEC2CapacityLambda Handler: outpost-capacity-lambda-ec2.lambda_handler Runtime: python3.8 Code: S3Bucket: !Ref Bucket S3Key: "outpost-capacity-lambda-ec2.zip" Description: "" MemorySize: 128 Timeout: 10 Role: Fn::GetAtt: - EC2CapacityRole - Arn Environment: Variables: ec2_alarm_breached: outposts-ec2-capacity-breached policy_arn: !Ref AdminIAMPolicyArnEC2 policy_name: outposts-ec2-capacity subnet_id: !Ref Subnet outpostsebscapacitylambda: Type: "AWS::Lambda::Function" Properties: FunctionName: OutpostEBSCapacityLambda Handler: outpost-capacity-lambda-ebs.lambda_handler Runtime: python3.8 Code: S3Bucket: !Ref Bucket S3Key: "outpost-capacity-lambda-ebs.zip" Description: "" MemorySize: 128 Timeout: 10 Role: Fn::GetAtt: - EBSCapacityRole - Arn Environment: Variables: ebs_alarm_breached: outposts-ebs-capacity-breached policy_arn: !Ref AdminIAMPolicyArnEBS policy_name: outposts-ebs-capacity subnet_id: !Ref Subnet BasicExecutionPolicy: Type: AWS::IAM::Policy Properties: PolicyName: lambda-log PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: arn:aws:logs:*:*:* Roles: - Ref: EBSCapacityRole - Ref: EC2CapacityRole