Advanced Cloud Cost Optimization Strategy Most Teams Overlook
The hidden cost of idle resources and why most teams miss it
Most cloud‑cost checklists focus on obvious levers: reserved instances, rightsizing, and storage tiering. Those actions capture low‑ hanging fruit, but they leave a persistent source of waste—idle compute that remains running because no one has a process to turn it off. The problem is not just a few forgotten EC2 instances; it is a systemic gap in how teams manage temporal workloads across multiple accounts and regions. When a resource is only needed during business hours, on‑call rotations, or scheduled batch windows, leaving it running 24/7 adds dollars to the bill without delivering value.
The advanced strategy that many organizations overlook is combining AWS Compute Optimizer recommendations with automated instance scheduling. Compute Optimizer tells you which instances are under‑utilized, while an instance‑scheduler (either the AWS‑provided solution or a custom Lambda workflow) enforces a start/stop policy based on tags. Together they create a feedback loop that continuously identifies waste and removes it without manual intervention.
Below is a step‑by‑step guide that engineers, founders, and platform teams can follow today. All commands are copy‑paste ready, and every console path is listed so you can verify the configuration.
Prerequisites and account preparation
Before you implement the automated scheduling loop, make sure the following are in place:
- Read‑only IAM role that can access Compute Optimizer, CloudWatch, and EC2 APIs. If you already have a FinOps or Cloud‑Ops role, add the following managed policies:
-
ComputeOptimizerReadOnlyAccess-AmazonEC2ReadOnlyAccess-CloudWatchReadOnlyAccess - AWS CLI version 2 installed and configured with the read‑only role:
bash aws configure set role_arn arn:aws:iam::123456789012:role/FinOpsReadOnly aws configure set source_profile default - Tagging discipline – decide on a tag key that signals a schedule, e.g.,
Schedule=business-hours. Document the tag in your internal wiki so developers know how to opt‑in. - Centralized logging – enable CloudTrail in all accounts and regions you plan to scan. This is required for Compute Optimizer to collect usage data.
Step 1 – Enable AWS Compute Optimizer across accounts
Compute Optimizer needs at least 14 days of usage data to generate reliable recommendations. Enabling it once per organization is enough; the service automatically discovers new accounts linked via AWS Organizations.
- Open the AWS Management Console → Compute Optimizer → Settings.
- Click Enable and select All accounts and All regions.
- Confirm the IAM role you created in the prerequisites has
ComputeOptimizerReadOnlyAccess. - (Optional) Use the CLI to enable it programmatically:
bash aws compute-optimizer update-enrollment-status \ --status Active \ --region us-east-1
Tip: After enabling, give the service 24‑48 hours to ingest data before pulling recommendations.
Step 2 – Pull under‑utilized instance recommendations
Once Compute Optimizer has data, you can retrieve a list of instances that are consistently below a utilization threshold (e.g., CPU < 20% and Memory < 30%).
aws compute-optimizer get-recommendations \
--account-ids 123456789012 \
--service EC2Instance \
--filters name=UtilizationMetric,values=CPUUtilization,MemoryUtilization \
--max-results 1000 \
--query "recommendations[?utilizationMetrics[?value<`20`]].{InstanceId:instanceArn,CurrentType:instanceType,RecommendedType:recommendedInstanceType}" \
--output table
The output shows each instance ARN, its current type, and the recommended smaller type. Export the list to a CSV for the next step:
aws compute-optimizer get-recommendations \
--service EC2Instance \
--output json > recommendations.json
jq -r '.recommendations[] | [.instanceArn, .instanceType, .recommendedInstanceType] | @csv' recommendations.json > recommendations.csv
Step 3 – Tag instances for scheduled shutdown
The automation works on a tag‑driven model. Add the Schedule=business-hours tag to any instance you want to stop outside of working hours. You can bulk‑tag using the CSV from the previous step.
while IFS=, read -r arn current recommended; do
instance_id=$(echo $arn | cut -d/ -f2)
aws ec2 create-tags \
--resources $instance_id \
--tags Key=Schedule,Value=business-hours
done < recommendations.csv
If you prefer a more selective approach, review the CSV manually and tag only the instances you are comfortable stopping.
Step 4 – Deploy the AWS Instance Scheduler solution
AWS provides a Serverless Instance Scheduler CloudFormation template that creates a Lambda function, DynamoDB table, and EventBridge rules. The solution reads the Schedule tag and starts/stops instances based on a configurable schedule.
- Open the AWS CloudFormation console.
- Choose Create stack → With new resources (standard).
- In Specify template, paste the URL of the official template:
https://aws-quickstart.s3.amazonaws.com/quickstart-aws-instance-scheduler/templates/instance-scheduler.template.yaml - Provide a stack name, e.g.,
instance-scheduler-prod. - In Parameters, set:
- TagName =
Schedule- TagValue =business-hours- ScheduleExpression =cron(0 18 ? * MON-FRI *)for stop at 6 PM UTC, Monday‑Friday. - StartScheduleExpression =cron(0 8 ? * MON-FRI *)for start at 8 AM UTC, Monday‑Friday. - Review and create the stack.
The stack creates:
- A DynamoDB table that stores schedule definitions.
- A Lambda function (InstanceScheduler) that reads tags and issues StartInstances / StopInstances API calls.
- Two EventBridge rules that trigger the Lambda at the start and stop times.
Note: If you need a different time zone, adjust the cron expressions accordingly. The scheduler respects daylight‑saving changes automatically when you use the
cronsyntax with a specific time zone.
Step 5 – Verify the automation and monitor savings
After the stack is active, test the workflow on a single instance:
INSTANCE_ID=i-0abcd1234efgh5678
aws ec2 stop-instances --instance-ids $INSTANCE_ID
aws lambda invoke --function-name InstanceScheduler --payload '{"action":"test"}' response.json
cat response.json
Check CloudWatch Logs for the Lambda function to confirm it read the tag and issued the stop command. Once verified, let the scheduler run on its schedule.
Monitoring cost impact
To see the dollar impact of stopped instances, use the Cost Explorer API with a filter for InstanceId and UsageType=BoxUsage.
aws ce get-cost-and-usage \
--time-period Start=$(date -d '-30 days' +%Y-%m-%d),End=$(date +%Y-%m-%d) \
--granularity DAILY \
--filter '{"Dimensions":{"Key":"USAGE_TYPE","Values":["BoxUsage"]}}' \
--metrics "UnblendedCost" \
--group-by Type=DIMENSION,Key=RESOURCE_ID \
--output table
Compare the daily cost before and after the scheduler activation. The difference is the direct savings from idle time elimination.
Step 6 – Integrate with CloudBudgetMaster’s free AWS waste finder
If you want a quick sanity check before committing to the full automation, try CloudBudgetMaster’s free AWS waste finder. It scans your account read‑only and lists idle resources with an estimated dollar impact. Use the tool to validate that the instances you tagged are indeed the biggest waste contributors.
Step 7 – Scale the solution across multiple accounts and regions
Large organizations often run dozens of accounts under AWS Organizations. The Instance Scheduler can be deployed once per OU (Organizational Unit) and then referenced by member accounts.
- In the CloudFormation stack, set DeployInAllRegions to
true. - Use Service Catalog to make the stack a portfolio product, allowing account owners to launch it with a single click.
- Store a central tag policy in AWS Organizations to enforce the
Scheduletag on all new EC2 instances.
aws organizations create-policy \
--content '{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Action":"ec2:RunInstances","Condition":{"StringNotEquals":{"aws:TagKeys":"Schedule"}}}]}' \
--description "Enforce Schedule tag on all EC2 instances" \
--name "EnforceScheduleTag" \
--type SERVICE_CONTROL_POLICY
Attach the policy to the root or specific OUs. This guarantees that any new instance will be eligible for automated start/stop.
Comparison of three rightsizing approaches
| Approach | Setup effort | Ongoing maintenance | Granularity | Typical savings |
|---|---|---|---|---|
| Manual rightsizing (CLI/Console) | Low – one‑time review | High – requires periodic re‑evaluation | Instance‑level only | 5‑15 % of compute spend |
| Compute Optimizer only | Medium – enable service + export reports | Medium – need to act on recommendations manually | Instance‑level + recommendation confidence | 10‑20 % of compute spend |
| Compute Optimizer + Instance Scheduler (automated) | High – CloudFormation, tagging policy, Lambda | Low – automation runs daily | Instance‑level + temporal (hours‑of‑day) | 20‑35 % of compute spend, plus operational overhead reduction |
The table shows why the combined approach is the most powerful yet often missed. It captures both under‑utilization and when the resource is needed.
Common pitfalls and how to avoid them
| Pitfall | Symptom | Fix |
|---|---|---|
| Tag missing on new instances | Scheduler ignores the instance, it stays running 24/7 | Enforce a Service Control Policy that requires the Schedule tag on RunInstances. |
| Scheduler stops a critical service | Unexpected downtime during off‑hours | Use a whitelist tag, e.g., Schedule=never-stop, and exclude those resources in the DynamoDB schedule definition. |
| Compute Optimizer data lag | Recommendations stale or missing | Wait at least 14 days after enabling the service before pulling data. |
| Lambda throttling during mass start/stop | Errors in CloudWatch logs, instances not started | Increase Lambda concurrency limit or split the operation into batches of 50 instances. |
Extending the strategy beyond EC2
The same tag‑driven scheduling concept works for other services that support start/stop APIs:
- RDS – use rds:start-db-instance / rds:stop-db-instance
- ElastiCache – elasticache:start-replication-group / elasticache:stop-replication-group
- Redshift – redshift:resume-cluster / redshift:pause-cluster
Create separate Lambda functions or extend the existing one with additional service handlers. The core idea—identify idle resources, tag them, and let a scheduler enforce a lifecycle—remains identical.
Frequently asked questions
How often should I refresh Compute Optimizer recommendations?
Compute Optimizer updates its recommendations daily, but you only need to pull a new report once a week for most workloads. For rapidly changing environments, a nightly cron job that runs the get-recommendations CLI command ensures you never miss a new idle instance.
Does the Instance Scheduler incur additional costs?
The scheduler runs on AWS Lambda, DynamoDB, and EventBridge—all of which have generous free tiers. In a typical production environment the monthly cost is well under $5, far outweighed by the compute savings it generates.
Can I schedule resources in multiple time zones?
Yes. The CloudFormation template accepts a ScheduleExpression that can include a timezone parameter. Define separate schedule entries for each region or business unit that operates in a different time zone.
What if I need to keep an instance running for a few extra hours on a holiday?
Add a temporary tag override, e.g., Schedule=override,OverrideStart=2024-12-26T08:00:00Z,OverrideStop=2024-12-26T20:00:00Z. The Lambda function can be extended to read these override fields and adjust the start/stop times for that specific day.
Key takeaways
- Idle compute is a silent, high‑impact cost driver that most teams ignore.
- AWS Compute Optimizer provides data‑driven under‑utilization recommendations.
- Tag‑driven Instance Scheduler automates start/stop based on business‑hour windows.
- Combining the two creates a self‑correcting loop that continuously trims waste.
- Enforce tagging via Service Control Policies to guarantee coverage across accounts.
- The approach scales to RDS, ElastiCache, Redshift, and other start/stop‑capable services.
- CloudBudgetMaster’s free AWS waste finder can validate the biggest waste before you automate.
Create a free account to start tracking your cloud spend today.
CloudBudgetMaster automates the entire workflow for AWS today: it scans your account read‑only, surfaces idle and wasted resources, and reports the dollar impact. Support for GCP, Azure, and Snowflake is coming soon.
CloudBudgetMaster