Analyze, Rightsize, and Govern Cloud Spend
Deploy over-provisioned AWS resources, then rightsize and govern cloud spend.
Introduction
30 Second Summary
Cloud bills have a way of creeping up when no one is watching. A single over-sized server or forgotten storage volume can quietly drain your budget month after month.
In this project, you will deploy intentionally wasteful AWS resources, then systematically use native AWS cost management tools to identify and fix the inefficiencies.
What You'll Build
A complete cost optimization lab environment where you deploy over-provisioned infrastructure via CloudFormation, then apply rightsizing strategies, flexible pricing models, and budget alerts to reduce spend.
By the end of this project, you'll have:
- A CloudFormation stack with tagged EC2 instances, EBS volumes, and an S3 bucket designed for cost allocation visibility.
- Hands-on experience with AWS Compute Optimizer and Trusted Advisor to identify cost-saving recommendations.
- Applied rightsizing changes including EC2 instance resizing, EBS gp2-to-gp3 migration, a Spot Instance for flexible pricing, and a budget alert for spend governance.
- Secret Mission: Implement a VPC Endpoint for S3 to eliminate NAT Gateway data transfer costs.
Are there any prerequisites?
You need access to an AWS sandbox or learning platform account with console access and permissions to create CloudFormation stacks, EC2 instances, EBS volumes, S3 buckets, and access Billing and Cost Management features. No local tools are required. All work is done in the AWS Console.
Deploy the Over-Provisioned CloudFormation Stack
The first step in any cost optimization effort is understanding what you are paying for. In the real world, teams often inherit cloud infrastructure that was over-provisioned during initial setup and never revisited.
In this step, you will deploy a CloudFormation stack that intentionally provisions oversized resources. You will also apply a consistent tagging strategy so you can track costs by project, environment, and owner.
In this step, get ready to:
- Create and deploy a CloudFormation stack with over-provisioned EC2, EBS, and S3 resources.
- Verify all deployed resources are running and correctly tagged.
- Activate cost allocation tags in the AWS Billing console.
Create the CloudFormation template
The template defines a full lab environment with resources that are deliberately larger than needed. This gives you clear rightsizing opportunities to work with in later steps.
- Open any plain text editor on your computer (Notepad on Windows, TextEdit in plain text mode on macOS, or any code editor).
- Create a new file and paste the following YAML template into it:
AWSTemplateFormatVersion: '2010-09-09'
Description: Cost Optimization Lab - Over-provisioned resources for rightsizing demonstration
Parameters:
LatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
Resources:
LabVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Project
Value: CostLab
- Key: Environment
Value: Sandbox
- Key: Owner
Value: Learner
- Key: CostCenter
Value: Training
- Key: Name
Value: CostLab-VPC
LabSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref LabVPC
CidrBlock: 10.0.1.0/24
MapPublicIpOnLaunch: true
Tags:
- Key: Project
Value: CostLab
- Key: Environment
Value: Sandbox
- Key: Owner
Value: Learner
- Key: CostCenter
Value: Training
- Key: Name
Value: CostLab-Subnet
LabInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Project
Value: CostLab
- Key: Name
Value: CostLab-IGW
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref LabVPC
InternetGatewayId: !Ref LabInternetGateway
LabRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref LabVPC
Tags:
- Key: Project
Value: CostLab
- Key: Name
Value: CostLab-RouteTable
PublicRoute:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref LabRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref LabInternetGateway
SubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref LabSubnet
RouteTableId: !Ref LabRouteTable
LabSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for Cost Optimization Lab
VpcId: !Ref LabVPC
Tags:
- Key: Project
Value: CostLab
- Key: Environment
Value: Sandbox
- Key: Owner
Value: Learner
- Key: CostCenter
Value: Training
- Key: Name
Value: CostLab-SG
LabInstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
Tags:
- Key: Project
Value: CostLab
LabInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref LabInstanceRole
OverProvisionedInstance:
Type: AWS::EC2::Instance
Properties:
InstanceType: t3.large
ImageId: !Ref LatestAmiId
SubnetId: !Ref LabSubnet
SecurityGroupIds:
- !Ref LabSecurityGroup
IamInstanceProfile: !Ref LabInstanceProfile
Tags:
- Key: Project
Value: CostLab
- Key: Environment
Value: Sandbox
- Key: Owner
Value: Learner
- Key: CostCenter
Value: Training
- Key: Name
Value: CostLab-OverProvisioned
OverProvisionedVolume:
Type: AWS::EC2::Volume
Properties:
AvailabilityZone: !GetAtt LabSubnet.AvailabilityZone
Size: 100
VolumeType: gp2
Tags:
- Key: Project
Value: CostLab
- Key: Environment
Value: Sandbox
- Key: Owner
Value: Learner
- Key: CostCenter
Value: Training
- Key: Name
Value: CostLab-OverSizedVolume
VolumeAttachment:
Type: AWS::EC2::VolumeAttachment
Properties:
Device: /dev/xvdf
InstanceId: !Ref OverProvisionedInstance
VolumeId: !Ref OverProvisionedVolume
LabBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub 'costlab-${AWS::AccountId}-${AWS::Region}'
Tags:
- Key: Project
Value: CostLab
- Key: Environment
Value: Sandbox
- Key: Owner
Value: Learner
- Key: CostCenter
Value: Training
Outputs:
InstanceId:
Description: EC2 Instance ID
Value: !Ref OverProvisionedInstance
VolumeId:
Description: EBS Volume ID
Value: !Ref OverProvisionedVolume
BucketName:
Description: S3 Bucket Name
Value: !Ref LabBucket
VPCId:
Description: VPC ID for Secret Mission
Value: !Ref LabVPC
RouteTableId:
Description: Route Table ID for Secret Mission
Value: !Ref LabRouteTable
What does this template do?
This template creates a deliberately wasteful lab environment so you have clear targets for optimization:
- A t3.large EC2 instance. This is over-provisioned for a demo workload that barely uses CPU or memory.
- A 100 GiB gp2 EBS volume. The older gp2 type costs 20% more per GiB than the newer gp3, and 100 GiB is far more than needed.
- An S3 bucket for demo data storage.
- A VPC with public subnet, internet gateway, route table, and security group for networking.
- An IAM role with SSM and S3 read-only access so you can connect to the instance later.
- Every resource is tagged with Project, Environment, Owner, and CostCenter for cost tracking.
- Save the file as cost-optimization-lab.yaml on your Desktop or Downloads folder.
File not saving as YAML?
Make sure your text editor is saving as plain text, not rich text. On macOS TextEdit, go to Format and choose Make Plain Text before saving. On Windows Notepad, change the Save as type dropdown to All Files and type the full filename including .yaml.
Help me save my CloudFormation template as a YAML file
✔️ Awesome, I've got everything!
Great. Make sure you have saved cost-optimization-lab.yaml and can locate it on your computer.
ⓧ I'd like to double check the full code
Here is the complete template. Make sure your file matches this exactly:
AWSTemplateFormatVersion: '2010-09-09'
Description: Cost Optimization Lab - Over-provisioned resources for rightsizing demonstration
Parameters:
LatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
Resources:
LabVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Project
Value: CostLab
- Key: Environment
Value: Sandbox
- Key: Owner
Value: Learner
- Key: CostCenter
Value: Training
- Key: Name
Value: CostLab-VPC
LabSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref LabVPC
CidrBlock: 10.0.1.0/24
MapPublicIpOnLaunch: true
Tags:
- Key: Project
Value: CostLab
- Key: Environment
Value: Sandbox
- Key: Owner
Value: Learner
- Key: CostCenter
Value: Training
- Key: Name
Value: CostLab-Subnet
LabInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Project
Value: CostLab
- Key: Name
Value: CostLab-IGW
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref LabVPC
InternetGatewayId: !Ref LabInternetGateway
LabRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref LabVPC
Tags:
- Key: Project
Value: CostLab
- Key: Name
Value: CostLab-RouteTable
PublicRoute:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref LabRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref LabInternetGateway
SubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref LabSubnet
RouteTableId: !Ref LabRouteTable
LabSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for Cost Optimization Lab
VpcId: !Ref LabVPC
Tags:
- Key: Project
Value: CostLab
- Key: Environment
Value: Sandbox
- Key: Owner
Value: Learner
- Key: CostCenter
Value: Training
- Key: Name
Value: CostLab-SG
LabInstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
Tags:
- Key: Project
Value: CostLab
LabInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref LabInstanceRole
OverProvisionedInstance:
Type: AWS::EC2::Instance
Properties:
InstanceType: t3.large
ImageId: !Ref LatestAmiId
SubnetId: !Ref LabSubnet
SecurityGroupIds:
- !Ref LabSecurityGroup
IamInstanceProfile: !Ref LabInstanceProfile
Tags:
- Key: Project
Value: CostLab
- Key: Environment
Value: Sandbox
- Key: Owner
Value: Learner
- Key: CostCenter
Value: Training
- Key: Name
Value: CostLab-OverProvisioned
OverProvisionedVolume:
Type: AWS::EC2::Volume
Properties:
AvailabilityZone: !GetAtt LabSubnet.AvailabilityZone
Size: 100
VolumeType: gp2
Tags:
- Key: Project
Value: CostLab
- Key: Environment
Value: Sandbox
- Key: Owner
Value: Learner
- Key: CostCenter
Value: Training
- Key: Name
Value: CostLab-OverSizedVolume
VolumeAttachment:
Type: AWS::EC2::VolumeAttachment
Properties:
Device: /dev/xvdf
InstanceId: !Ref OverProvisionedInstance
VolumeId: !Ref OverProvisionedVolume
LabBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub 'costlab-${AWS::AccountId}-${AWS::Region}'
Tags:
- Key: Project
Value: CostLab
- Key: Environment
Value: Sandbox
- Key: Owner
Value: Learner
- Key: CostCenter
Value: Training
Outputs:
InstanceId:
Description: EC2 Instance ID
Value: !Ref OverProvisionedInstance
VolumeId:
Description: EBS Volume ID
Value: !Ref OverProvisionedVolume
BucketName:
Description: S3 Bucket Name
Value: !Ref LabBucket
VPCId:
Description: VPC ID for Secret Mission
Value: !Ref LabVPC
RouteTableId:
Description: Route Table ID for Secret Mission
Value: !Ref LabRouteTable
Now deploy this template through the AWS Console.
- In the AWS Console, search for CloudFormation in the top search bar and select the service.
- On the Stacks page, click Create stack at the top right, then choose With new resources (standard).
- Under Specify template, select Upload a template file.
- Click Choose file and select your cost-optimization-lab.yaml file.
- Click Next.
- For Stack name, enter CostOptimizationLab.
- Leave the LatestAmiId parameter at its default value.
- Click Next through the Configure stack options page (keep all defaults).
- On the review page, scroll to the bottom. Check the box next to I acknowledge that AWS CloudFormation might create IAM resources.
- Click Submit.
Why acknowledge IAM resources?
The template creates an IAM Role and Instance Profile so the EC2 instance can communicate with AWS Systems Manager and read from S3. AWS requires you to explicitly confirm this because IAM resources can modify permissions in your account.
The stack will take 2-3 minutes to deploy. Wait until the status changes to CREATE_COMPLETE before moving on.
Stack shows ROLLBACK_COMPLETE or CREATE_FAILED?
Select your stack and click the Events tab. Look for the first event with a CREATE_FAILED status to identify the root cause. Common failures include insufficient permissions in your sandbox account or the S3 bucket name already existing in another account.
Help me debug my CloudFormation stack deployment failure
Verify the deployed resources
Now confirm that all resources were created correctly and are tagged with the cost allocation labels.
- In the AWS Console, search for EC2 and open the EC2 Dashboard.
- Click Instances in the left navigation.
- Locate the instance named CostLab-OverProvisioned. Confirm its Instance state is Running and its Instance type is t3.large.
- Click Elastic Block Store then Volumes in the left navigation.
- Locate the volume named CostLab-OverSizedVolume. Confirm it shows 100 GiB size and gp2 type.
- Search for S3 in the console and verify a bucket starting with costlab- exists.
- Click on the EC2 instance name, then select the Tags tab. Confirm you see all four tags: Project=CostLab, Environment=Sandbox, Owner=Learner, CostCenter=Training.
Instance not showing as Running?
Make sure you are in the same AWS Region where you deployed the stack. Check the region selector in the top right of the console. If the instance is in Pending state, wait another minute for it to initialize.
Help me find my EC2 instance after deploying the CloudFormation stack
Activate cost allocation tags
Tags on resources are just labels until you activate them for cost allocation. Once activated, AWS uses these tags to organize your costs in billing reports and Cost Explorer.
- In the AWS Console search bar, search for Billing and Cost Management and open the service.
- In the left navigation pane, click Cost allocation tags.
- Look for the User-defined cost allocation tags tab. Select the checkboxes next to Project, Environment, Owner, and CostCenter.
- Click Activate.
Why might the tags not appear immediately?
After you apply tags to resources, it can take up to 24 hours for the tag keys to appear on the cost allocation tags page. In a sandbox environment, the tags typically appear within minutes since the CloudFormation stack already applied them during creation.
If you do not see the tags listed yet, wait a few minutes and refresh the page. The activation step itself also takes up to 24 hours to fully reflect in billing reports, but you can still proceed with the rest of this lab.
Don't see Cost allocation tags in the navigation?
Some sandbox accounts may have restricted billing access. If you cannot see the Cost allocation tags option, your sandbox may not grant billing permissions. Check with your learning platform's instructions for enabling billing features.
Help me access cost allocation tags in my AWS sandbox account
Your lab environment is live and tagged for cost tracking. Next up, you will explore AWS Compute Optimizer and Trusted Advisor to identify exactly how much money these over-provisioned resources are wasting.
Explore Compute Optimizer and Trusted Advisor
Your over-provisioned infrastructure is deployed and tagged. Now you need to figure out exactly where the waste is hiding.
AWS provides two complementary tools for spotting cost inefficiencies. Compute Optimizer analyzes CloudWatch utilization metrics to recommend better-fitting resource configurations. Trusted Advisor runs best-practice checks across your entire account, flagging idle and underutilized resources.
In this step, get ready to:
- Opt in to AWS Compute Optimizer and explore the dashboard.
- Walk through Compute Optimizer recommendation categories for EC2, EBS, and idle resources.
- Review Trusted Advisor cost optimization checks.
Opt in to AWS Compute Optimizer
Compute Optimizer needs permission to analyze your resources before it can surface recommendations. The opt-in process creates a service-linked role that grants this access automatically.
- In the AWS Console search bar at the top, type Compute Optimizer and select it from the results.
- Click Get started.
- On the Account setup page, review the default data settings.
- Click Opt in.
What happens when you opt in?
A service-linked role is created automatically in your account. This role allows Compute Optimizer to read CloudWatch utilization metrics for your resources.
Compute Optimizer analyzes the last 14 days of CloudWatch data at no additional charge. Since your resources were just deployed, you will not see real recommendations yet. The dashboard layout is what matters here.
- After opting in, you are redirected to the Compute Optimizer dashboard. Confirm you see the Dashboard page with sections for Savings opportunity and Performance improvement opportunity.
Don't see the Get started button?
If your account has already been opted in (common in shared sandbox environments), you will land directly on the dashboard. This is fine. Continue to the next substep.
help me troubleshoot Compute Optimizer access in my sandbox account
Explore Compute Optimizer recommendation categories
The left navigation panel in Compute Optimizer organizes recommendations by resource type. Each category shows finding classifications like Over-provisioned, Under-provisioned, and Optimized.
- In the left navigation pane, click EC2 instances.
- Review the recommendations page. This page lists your running instances with their current specifications and recommended instance types. Look for finding classifications such as Over-provisioned and estimated monthly savings.
- In the left navigation pane, click EBS volumes.
- Review this page. For EBS volumes, Compute Optimizer recommends volume type changes (like gp2 to gp3) and shows the monthly price difference.
- In the left navigation pane, click Lambda functions.
- Review this page. For Lambda functions, Compute Optimizer recommends memory size adjustments to balance cost and performance.
- In the left navigation pane, click Idle resources.
- Review this page. It lists resources with low utilization that could be stopped or deleted entirely.
Why are recommendations empty?
Compute Optimizer needs at least 14 days of CloudWatch metrics to generate meaningful recommendations. Your lab resources were just deployed, so the dashboard will show no findings yet.
In a production environment, these categories would populate with specific instance type suggestions, volume type migrations, and estimated savings after two weeks of data collection.
What is the what-if visualization?
When Compute Optimizer has enough data, clicking into a specific resource shows a projected utilization graph. A dotted line shows how your workload would have performed on the recommended instance type. This helps you validate that the smaller instance can still handle your traffic peaks.
Explore Trusted Advisor cost optimization checks
Trusted Advisor takes a broader view than Compute Optimizer. It runs best-practice checks across your entire account and flags resources that are idle, underutilized, or missing cost-saving configurations.
- In the AWS Console search bar at the top, type Trusted Advisor and select it from the results.
- You will land on the Trusted Advisor Recommendations page. Look for the Potential monthly savings summary near the top.
- In the navigation pane on the left, click Cost optimization.
What support plan do I need?
Full cost optimization checks require AWS Business Support or higher. On a Basic or Developer plan, you only see Service Limits checks and a few Security checks.
Learning platform sandbox accounts typically include Business Support access. If you see the full Cost optimization category with multiple checks listed, your sandbox has the required access.
- Review the cost optimization checks. Look for these key checks in the list:
- Low utilization Amazon EC2 instances identifies instances with consistently low CPU usage that could be stopped or downsized.
- Underutilized Amazon EBS volumes flags volumes with low read/write activity.
- Unassociated Elastic IP Addresses finds Elastic IPs not attached to a running instance (these cost money when idle).
- Idle Load Balancers flags load balancers with no active backend instances.
- Amazon EC2 Reserved Instance optimization suggests commitment-based pricing for stable workloads.
Each check displays a color-coded status. Green means no issues detected. Yellow means investigation is recommended. Red means action is recommended.
How do check statuses work?
Trusted Advisor uses a traffic-light system for each check. Green means no problems detected. Yellow means investigation recommended. Red means action recommended.
In your sandbox, most checks will likely show green because the resources were just created. In a production account with months of history, you would see yellow and red flags highlighting specific resources to address.
Only seeing a few checks?
If the Cost optimization category shows very few checks, your sandbox account may be on a Basic or Developer Support plan. You can still review the checks that are available and understand the categories.
help me understand why I'm seeing limited Trusted Advisor checks
You now know how to find cost-saving recommendations across your AWS account. Next up, you will act on these findings by rightsizing your EC2 instance, migrating your EBS volume to a cheaper type, and setting up automated storage lifecycle rules.
Apply Rightsizing Strategies for Compute and Storage
In the last step, you explored AWS Compute Optimizer and Trusted Advisor to identify potential cost savings. Now it is time to act on those insights.
Rightsizing means matching your resource capacity to actual workload demands. In this step, you will downsize the over-provisioned EC2 instance, migrate the EBS volume to a more cost-effective type, and configure automated storage tiering for S3.
In this step, get ready to:
- Rightsize the EC2 instance from t3.large to t3.micro.
- Migrate the EBS volume from gp2 to gp3.
- Configure an S3 lifecycle rule for automated storage class transitions.
Rightsize the EC2 instance
Your CostLab-OverProvisioned instance is running as t3.large, which is far more compute power than this lab workload requires. Changing the instance type to t3.micro reduces the hourly cost significantly while still meeting the workload's needs.
- In the EC2 Console, click Instances in the left navigation pane.
- Select the instance named CostLab-OverProvisioned.
- Click Instance state, then choose Stop instance.
- When prompted for confirmation, click Stop.
- Wait for the instance state to show Stopped. This may take a minute or two.
Why do you have to stop the instance first?
AWS requires you to stop an EBS-backed instance before changing its type. The instance is moved to new hardware during this process, which is why a brief downtime period is required.
- With the instance still selected, click Actions, then Instance settings, then Change instance type.
- In the Instance type dropdown, select t3.micro.
- Click Change.
- Select the instance again and click Instance state, then Start instance.
- Wait for the instance state to return to Running.
Your instance is now running as t3.micro. You can verify this in the instance details panel under Instance type.
How much does rightsizing save here?
A t3.large has 2 vCPUs and 8 GiB of memory, while a t3.micro has 2 vCPUs and 1 GiB of memory. The hourly On-Demand cost for t3.large is roughly 2x that of t3.micro.
In a production scenario, this type of rightsizing across dozens or hundreds of instances adds up to significant monthly savings.
Instance type option is greyed out?
The Change instance type option is only available when the instance is in the Stopped state. Make sure you waited for the instance to fully stop before attempting the change.
Help me fix this
Migrate the EBS volume from gp2 to gp3
The EBS volume attached to your instance is using the older gp2 type. The newer gp3 type offers 20% lower cost per GiB with equal or better baseline performance.
- In the EC2 Console left navigation, expand Elastic Block Store and click Volumes.
- Select the 100 GiB volume named CostLab-OverSizedVolume.
- Click Actions, then choose Modify volume.
- Change the Volume type dropdown from gp2 to gp3.
- Leave IOPS at 3000 (baseline, included free with gp3).
- Leave Throughput at 125 MiB/s (baseline, included free with gp3).
- Click Modify and confirm the modification when prompted.
The volume state will show In-use - optimizing while the modification applies. This process happens live without interrupting the instance.
What are the cost savings of gp3 vs gp2?
The gp2 type costs $0.10 per GiB-month. The gp3 type costs $0.08 per GiB-month. For your 100 GiB volume, that is a $2/month savings.
Beyond cost, gp3 provides 3,000 baseline IOPS regardless of volume size. With gp2, a 100 GiB volume only gets 300 IOPS (3 IOPS per GiB). So you get better performance at a lower price.
Don't see Modify volume in the Actions menu?
Make sure you have selected the volume (checkbox ticked) before clicking Actions. The option only appears when a volume is selected and is in the in-use or available state.
Help me troubleshoot this
Configure an S3 lifecycle rule for automated storage tiering
Storage tiering automatically moves objects to cheaper storage classes as they age. You will create a lifecycle rule on your S3 bucket that transitions objects to S3 Standard-IA after 30 days, then to S3 Glacier Flexible Retrieval after 90 days.
- Navigate to the S3 Console.
- In the left navigation pane, click General purpose buckets.
- Click the bucket named costlab-{AccountId}-{Region} (your bucket name includes your account ID and region).
- Click the Management tab.
- Click Create lifecycle rule.
- In Lifecycle rule name, enter transition-to-ia.
- Under rule scope, choose This rule applies to all objects in the bucket.
- Check the acknowledgment box that confirms the rule applies to all objects.
- Under Lifecycle rule actions, check Transition current versions of objects between storage classes.
- In the first Storage class transitions row, select Standard-IA.
- In Days after object creation, enter 30.
- Click Add transition to add a second transition rule.
- In the second row, select Glacier Flexible Retrieval.
- In Days after object creation, enter 90.
- Click Create rule.
Your lifecycle rule now appears on the Management tab under Lifecycle rules.
What does this lifecycle rule do?
Objects stored in S3 Standard are automatically moved to S3 Standard-IA (Infrequent Access) after 30 days. After 90 days, they are moved to S3 Glacier Flexible Retrieval for long-term archival.
This demonstrates automated data lifecycle management. In production, this pattern reduces storage costs for data that is accessed less frequently over time.
Getting a rule validation error?
Make sure the Standard-IA transition is set to at least 30 days. S3 requires objects to be stored for a minimum of 30 days before transitioning to Standard-IA.
Also ensure your Glacier transition day count (90) is greater than the Standard-IA day count (30).
Help me fix my lifecycle rule
You have now applied three concrete cost optimizations: compute rightsizing, storage type migration, and automated lifecycle tiering. Next up, you will explore flexible pricing models with Spot Instances and set up budget alerts to govern ongoing spend.
Manage Spend with Spot Instances and Budget Alerts
In the previous step, you rightsized your EC2 instance, migrated your EBS volume to gp3, and set up an S3 lifecycle rule. Those are reactive optimizations that fix existing waste.
Now you will shift to proactive cost management. This means choosing cheaper pricing models before you deploy and setting up guardrails that alert you before spend gets out of control.
In this step, get ready to:
- Launch a Spot Instance to demonstrate flexible compute pricing.
- Explore Savings Plans recommendations for commitment-based discounts.
- Create a budget alert that notifies you when spend approaches a threshold.
Launch a Spot Instance
Spot Instances let you use spare EC2 capacity at up to 90% discount compared to On-Demand pricing. The trade-off is that AWS can reclaim the instance with a two-minute warning when it needs the capacity back.
For fault-tolerant or stateless workloads, this trade-off is well worth the savings. You will launch one now to see the pricing model in action.
- Return to the EC2 Console.
- Click Launch instances.
- In the Name field, enter SpotDemo.
- Under Application and OS Images, select Amazon Linux 2023 AMI.
- Under Instance type, select t3.micro.
- Expand the Advanced details section at the bottom of the page.
- Find the Purchasing option field and select Spot.
- Scroll down to Tags and click Add tag.
- Add a tag with Key Project and Value CostLab.
- Add a second tag with Key Environment and Value Sandbox.
- Click Launch instance.
You should see a success message confirming the instance is launching. Navigate back to your Instances list and confirm the SpotDemo instance shows a Running state.
What is a Spot Instance?
AWS has spare compute capacity that fluctuates throughout the day. Spot Instances let you bid on that spare capacity at steep discounts.
The catch is that AWS can interrupt your instance with a two-minute warning when demand rises. This makes Spot ideal for batch processing, CI/CD builds, and stateless web servers behind a load balancer.
Spot Instance not launching?
If the launch fails with a capacity error, it means no Spot capacity is available for t3.micro in your region. Try a different instance type like t3.small or wait a few minutes and retry.
Also check that your sandbox account has not reached its instance limit. You can see limits under EC2 > Limits.
Need more help?
Explore Savings Plans recommendations
Savings Plans offer up to 72% discount in exchange for committing to a consistent amount of compute usage (measured in $/hour) for a 1- or 3-year term. Unlike Reserved Instances, they are flexible across instance families, regions, and even services.
- Navigate to AWS Billing and Cost Management in the console.
- In the left navigation, expand Savings Plans and click Recommendations.
On this page, review the following elements to understand how AWS generates its recommendations:
- The lookback period options (7, 30, or 60 days of historical usage).
- The recommended commitment amounts based on your usage history.
- The estimated savings percentages for each recommendation.
- The difference between Compute Savings Plans (flexible across EC2, Fargate, Lambda) and EC2 Instance Savings Plans (locked to a specific instance family and region).
Why are recommendations minimal in my sandbox?
Savings Plans recommendations are based on your past 7, 30, or 60 days of On-Demand usage. A sandbox with limited history will show minimal or no recommendations.
The learning objective here is understanding the interface and the workflow. In a production account with months of usage data, this page becomes a powerful tool for identifying commitment opportunities.
Create a budget alert
AWS Budgets lets you set custom spending thresholds and receive alerts when your actual or forecasted spend approaches those limits. This is your last line of defense against unexpected charges.
- In AWS Billing and Cost Management, click Budgets in the left navigation.
- Click Create budget.
- Select Customize (advanced).
- For Budget type, choose Cost budget and click Next.
- Enter CostLab-Monthly-Budget as the Budget name.
- Set Period to Monthly and Recurring.
- Set Budgeting method to Fixed.
- Enter 10 as the Budget amount (in dollars).
- Click Next to proceed to alert configuration.
Now configure the alert threshold so you get notified before you hit the full budget amount:
- Click Add an alert threshold.
- Set the threshold to 80 % of budgeted amount.
- Set the trigger to Actual spend (not forecasted).
- Under Email recipients, enter your email address.
- Click Next to skip the actions step.
- Review your configuration and click Create budget.
You should see your new budget listed on the Budgets page with a status showing your current spend against the $10 threshold.
What does this budget cost me?
Budgets without actions are free. AWS also gives you 2 action-enabled budgets free per account. Additional active budgets cost $0.02 per day each.
Since you created a budget without automated actions (just an email alert), this budget costs nothing.
Don't see the Budgets option?
Some sandbox accounts restrict access to Billing features. If Budgets is not visible in the left navigation, try searching for "Budgets" in the top search bar of the AWS Console. If access is denied, your sandbox may require IAM permissions for billing access.
Help me troubleshoot Budgets access in my sandbox account.
You now have three layers of cost management in place: reactive rightsizing, discounted pricing models, and proactive budget alerts. Next up, you will tackle a Secret Mission that eliminates hidden data transfer costs with a VPC Endpoint.
Secret mission
Performance Tuning with VPC Endpoints
When EC2 instances access S3, data transfer charges can add up quickly through NAT Gateways. In this mission, you will create a Gateway VPC Endpoint that routes S3 traffic through the private AWS network at zero additional cost. This is one of the highest-impact, lowest-effort cost optimizations available in AWS.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. The t3.micro instances and small EBS volume in this lab cost a few cents per hour while running.
Cost warning
The EC2 instances (t3.micro On-Demand and Spot) incur compute charges every hour they run. The 100 GiB gp3 EBS volume incurs storage charges even when the instance is stopped. If you are not continuing immediately, choose Pause or Delete to avoid unexpected charges.
Resources you used:
- CloudFormation stack CostOptimizationLab (EC2 instance, EBS volume, S3 bucket, VPC, networking, IAM resources).
- EC2 Spot Instance SpotDemo (created outside the stack).
- VPC Endpoint s3-gateway-endpoint (Gateway type, no hourly charge).
- AWS Budget CostLab-Monthly-Budget (free, no ongoing cost).
Keep everything running
No action needed. Choose this if you are still actively exploring the cost optimization tools or want to wait for Compute Optimizer to generate recommendations after 14 days of CloudWatch metrics.
- Your t3.micro instances and EBS volume will continue incurring minor charges (a few cents per hour for compute, plus $0.08/GiB-month for gp3 storage).
- The budget alert at 80% of $10 will notify you if spend approaches your threshold.
- The Gateway VPC Endpoint incurs no charge while it exists.
Pause - I'll come back to this later
Stop the running EC2 instances to halt compute charges. EBS storage charges still apply while the volume exists.
- In the EC2 Console, select the CostLab-OverProvisioned instance.
- Choose Instance state then Stop instance.
- Select the SpotDemo instance.
- Choose Instance state then Terminate instance. Spot Instances cannot be stopped and resumed, so terminate it instead.
- The 100 GiB gp3 EBS volume will continue to incur $8/month in storage charges.
- The VPC Endpoint and Budget remain at no cost.
Delete - I don't want to use this again
Remove all project resources and start fresh. Follow these steps in order.
- Terminate the Spot Instance first (it is not managed by the stack). In EC2 Console, select SpotDemo, choose Instance state then Terminate instance.
- Delete the VPC Endpoint. Open the VPC Console, choose Endpoints in the navigation pane, select s3-gateway-endpoint, choose Actions then Delete VPC endpoints. Type delete to confirm, then choose Delete.
- Empty the S3 bucket (required before the stack can delete it). In the S3 Console, open the bucket costlab-{AccountId}-{Region}, select all objects (if any), and choose Delete. Confirm by typing permanently delete.
- Delete the CloudFormation stack. Open CloudFormation, select the CostOptimizationLab stack, and choose Delete. This removes the EC2 instance, EBS volume, S3 bucket, VPC, subnet, internet gateway, route table, security group, and IAM resources.
- Wait for the stack status to reach DELETE_COMPLETE. If deletion fails because the bucket was not empty, empty it and retry the deletion.
- Delete the budget. Open the Billing and Cost Management console, choose Budgets in the navigation pane, select CostLab-Monthly-Budget, choose Actions then Delete, and choose Confirm.
That's a Wrap!
That's a Wrap!
Nice work! You've just completed a full AWS cost optimization workflow, from deploying intentionally wasteful infrastructure to systematically identifying and fixing every inefficiency.
You've learned how to:
- Deployed a CloudFormation stack with cost allocation tags, then applied rightsizing strategies to reduce compute and storage costs (EC2 t3.large to t3.micro, EBS gp2 to gp3).
- Used AWS Compute Optimizer and Trusted Advisor to explore cost-saving recommendations, then configured a budget alert with email notifications to govern ongoing spend.
- Launched a Spot Instance for up to 90% compute savings and explored Savings Plans recommendations for commitment-based pricing discounts.
- Secret Mission: Created a Gateway VPC Endpoint for S3 to eliminate NAT Gateway data transfer costs.
Ready to quiz yourself?