TheArchitect

Cost Optimization

AWS architecture template · SAA-C03: CloudWatch budget alarm → Lambda optimiser → Auto Scaling (Spot) + EC2 + S3 (lifecycle) + RDS (right-sized)

Cost Optimization is a free AWS architecture template built with Auto Scaling, CloudWatch, EC2, Lambda, RDS and S3. Open it in TheArchitect to edit the diagram, estimate monthly cost, and export the CloudFormation or Terraform that deploys it.

Budget AlarmCost OptimiserMixed-Instance…Spot FleetTiered ArchiveRight-Sized DB
Cost Optimization architecture diagram

AWS services in this template

  • Auto Scaling
  • CloudWatch
  • EC2
  • Lambda
  • RDS
  • S3

Deployment notes

Needs input

  • Add Spot Instance purchase options and S3 lifecycle rules before deploying.

Generated CloudFormation — 7 resources

Logical IDResource type
BudgetAlarmcloudwatchAWS::CloudWatch::Alarm
CostOptimiserlambdaAWS::Lambda::Function
MixedInstanceASGautoscalingAWS::AutoScaling::AutoScalingGroup
SpotFleetec2AWS::EC2::Instance
TieredArchives3AWS::S3::Bucket
RightSizedDBrdsAWS::RDS::DBInstance
CostOptimiserlambdaTieredArchives3PermissionAWS::Lambda::Permission
View the full CloudFormation template
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "Generated by TheArchitect — https://www.thecloudarchitect.dev",
  "Metadata": {
    "TheArchitect": {
      "Edges": [
        {
          "From": "BudgetAlarmcloudwatch",
          "To": "CostOptimiserlambda",
          "Label": "trigger"
        },
        {
          "From": "CostOptimiserlambda",
          "To": "TieredArchives3",
          "Label": "archive"
        },
        {
          "From": "CostOptimiserlambda",
          "To": "RightSizedDBrds",
          "Label": "analyse"
        }
      ]
    }
  },
  "Resources": {
    "BudgetAlarmcloudwatch": {
      "Type": "AWS::CloudWatch::Alarm",
      "Properties": {
        "AlarmName": "saa-cost-monthly-budget",
        "AlarmDescription": "Alert when estimated charges exceed the monthly threshold.",
        "Namespace": "AWS/Billing",
        "MetricName": "EstimatedCharges",
        "Statistic": "Maximum",
        "Period": 86400,
        "EvaluationPeriods": 1,
        "Threshold": 100,
        "ComparisonOperator": "GreaterThanThreshold",
        "TreatMissingData": "notBreaching"
      }
    },
    "CostOptimiserlambda": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "FunctionName": "saa-cost-optimizer",
        "Runtime": "nodejs20.x",
        "Handler": "index.handler",
        "MemorySize": 512,
        "Architectures": [
          "arm64"
        ],
        "Timeout": 30,
        "Description": "Scheduled optimiser: identifies idle resources and right-sizing opportunities.",
        "Environment": {
          "Variables": {
            "APP_ENV": "demo",
            "LOG_LEVEL": "info"
          }
        },
        "TracingConfig": {
          "Mode": "Active"
        },
        "Code": {
          "ZipFile": "exports.handler = async (event) => ({ statusCode: 200, body: JSON.stringify({ ok: true, requestId: event.requestContext?.requestId || 'demo' }) });"
        }
      }
    },
    "MixedInstanceASGautoscaling": {
      "Type": "AWS::AutoScaling::AutoScalingGroup",
      "Properties": {
        "MinSize": "1",
        "MaxSize": "6",
        "DesiredCapacity": "2"
      }
    },
    "SpotFleetec2": {
      "Type": "AWS::EC2::Instance",
      "Properties": {
        "InstanceType": "t3.micro"
      }
    },
    "TieredArchives3": {
      "Type": "AWS::S3::Bucket",
      "Properties": {
        "BucketName": "saa-cost-archive",
        "VersioningConfiguration": {
          "Status": "Enabled"
        },
        "OwnershipControls": {
          "Rules": [
            {
              "ObjectOwnership": "BucketOwnerEnforced"
            }
          ]
        },
        "BucketEncryption": {
          "ServerSideEncryptionConfiguration": [
            {
              "ServerSideEncryptionByDefault": {
                "SSEAlgorithm": "AES256"
              }
            }
          ]
        },
        "PublicAccessBlockConfiguration": {
          "BlockPublicAcls": true,
          "BlockPublicPolicy": true,
          "IgnorePublicAcls": true,
          "RestrictPublicBuckets": true
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": "saa-cost-archive"
          }
        ],
        "NotificationConfiguration": {
          "LambdaConfigurations": [
            {
              "Event": "s3:ObjectCreated:*",
              "Function": {
                "Fn::GetAtt": [
                  "CostOptimiserlambda",
                  "Arn"
                ]
              }
            }
          ]
        }
      },
      "DependsOn": [
        "CostOptimiserlambdaTieredArchives3Permission"
      ]
    },
    "RightSizedDBrds": {
      "Type": "AWS::RDS::DBInstance",
      "Properties": {
        "DBInstanceIdentifier": "saa-cost-appdb",
        "Engine": "postgres",
        "DBName": "appdb",
        "DBInstanceClass": "db.t3.micro",
        "VPCSecurityGroups": [
          "data-store-sg"
        ],
        "PubliclyAccessible": false,
        "AllocatedStorage": "20",
        "MaxAllocatedStorage": 100,
        "StorageType": "gp3",
        "MasterUsername": "appadmin",
        "ManageMasterUserPassword": true,
        "StorageEncrypted": true,
        "BackupRetentionPeriod": 7
      }
    },
    "CostOptimiserlambdaTieredArchives3Permission": {
      "Type": "AWS::Lambda::Permission",
      "DependsOn": [
        "CostOptimiserlambda"
      ],
      "Properties": {
        "Action": "lambda:InvokeFunction",
        "FunctionName": {
          "Ref": "CostOptimiserlambda"
        },
        "Principal": "s3.amazonaws.com",
        "SourceAccount": {
          "Ref": "AWS::AccountId"
        },
        "SourceArn": {
          "Fn::Sub": "arn:${AWS::Partition}:s3:::saa-cost-archive"
        }
      }
    }
  }
}

Generated by TheArchitect from the diagram above. Review values such as names, CIDR ranges and instance sizes before deploying to your account.

Related templates