CloudBudgetMasterCloudBudgetMaster

← All articles

Strategy

Advanced Cloud Cost Optimization Strategy You’re Missing

October 15, 2026·7 min read·CloudBudgetMaster

How a tag‑driven decommissioning strategy can cut hidden AWS spend

Most engineering and platform teams focus on rightsizing instances, buying Savings Plans, or cleaning up obvious orphaned assets. The resources that slip through the cracks are those that are still attached to a project tag but have been idle for weeks or months. By combining strict tag policies with an automated decommissioning pipeline, you can continuously prune idle resources, keep Savings Plans intact, and see the dollar impact in real time.

Build a reliable tagging foundation

A clean tag hierarchy is the backbone of any automated cost‑control workflow. Without it, you cannot reliably query for idle assets or guarantee that a decommissioned resource will not break a production workload.

Define a minimal tag set

  1. Environment – dev, staging, prod
  2. Owner – email or IAM role identifier
  3. Project – short code that matches your internal project tracker
  4. Expiration – ISO‑8601 date when the resource should be reviewed

Enforce tags at creation time

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Deny",
    "Action": "*",
    "Resource": "*",
    "Condition": {
      "StringNotLikeIfExists": {
        "aws:TagKeys": ["Environment","Owner","Project","Expiration"]
      }
    }
  }]
}

Tag propagation for legacy resources

Run a one‑off script that adds missing tags based on naming conventions or CloudTrail logs:

aws resourcegroupstaggingapi get-resources \
  --resource-type-filters ec2:instance rds:db \
  --query 'ResourceTagMappingList[?Tags[?Key==`Name`]]' \
  --output json > missing-tags.json
# Process JSON and call tag-resource for each ARN

Store the output in a version‑controlled repo so you can audit changes.

Identify idle resources with automated queries

Once tags are in place, you can use AWS Cost Explorer, AWS Config, and Amazon Athena to surface idle assets.

Use Cost Explorer for usage‑based filters

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:t2.micro"]}}' \
  --metrics "UnblendedCost"

Look for resources with zero usage over the last 30 days.

Leverage AWS Config rules

Enable the managed rule ec2-instance-no-public-ip and rds-instance-deletion-protection-enabled to flag mis‑configurations that often accompany idle assets. Add a custom rule that checks the Expiration tag against the current date.

Query with Athena for cross‑service visibility

Create a unified cost‑and‑usage table:

CREATE EXTERNAL TABLE IF NOT EXISTS cloud_costs (
  line_item_usage_start string,
  line_item_resource_id string,
  line_item_usage_type string,
  line_item_unblended_cost double,
  resource_tags map<string,string>
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://my-cost-and-usage-bucket/cur/';

Then run:

SELECT resource_tags['Project'] AS project,
       line_item_resource_id AS arn,
       SUM(line_item_unblended_cost) AS cost,
       MAX(line_item_usage_start) AS last_used
FROM cloud_costs
WHERE line_item_usage_type NOT LIKE '%DataTransfer%'
GROUP BY project, line_item_resource_id
HAVING MAX(line_item_usage_start) < date_add('day', -30, current_date);

The result set is a precise list of resources that have not been used in the past month.

Create automated decommissioning pipelines

Manual ticket creation for each idle resource is error‑prone and slow. A serverless pipeline can close the loop from detection to termination.

Architecture overview

  1. EventBridge rule triggers daily and runs an Athena query (via StartQueryExecution).
  2. Step Functions orchestrates the workflow: fetch query results, evaluate the Expiration tag, and decide between stop, terminate, or notify.
  3. Lambda functions perform the actual API calls (aws ec2 stop-instances, aws rds delete-db-instance, etc.).
  4. SNS sends a summary email to the resource Owner with an undo link that invokes a Lambda to cancel the termination.

Sample Step Functions definition (YAML)

StartAt: RunAthenaQuery
States:
  RunAthenaQuery:
    Type: Task
    Resource: arn:aws:states:::athena:startQueryExecution.sync
    Parameters:
      QueryString: "SELECT ..."   # same query from the previous section
      QueryExecutionContext:
        Database: default
      ResultConfiguration:
        OutputLocation: s3://my-athena-results/
    Next: ProcessResults
  ProcessResults:
    Type: Map
    ItemsPath: "$.ResultSet.Rows"
    Iterator:
      StartAt: EvaluateResource
      States:
        EvaluateResource:
          Type: Choice
          Choices:
            - Variable: "$.Expiration"
              StringLessThan: "{{now}}"
              Next: DeleteResource
            - Variable: "$.UsageHours"
              NumericLessThan: 1
              Next: StopResource
          Default: NotifyOwner
        StopResource:
          Type: Task
          Resource: arn:aws:states:::lambda:invoke
          Parameters:
            FunctionName: stopResourceFunction
            Payload:
              arn.$: "$.Arn"
          End: true
        DeleteResource:
          Type: Task
          Resource: arn:aws:states:::lambda:invoke
          Parameters:
            FunctionName: deleteResourceFunction
            Payload:
              arn.$: "$.Arn"
          End: true
        NotifyOwner:
          Type: Task
          Resource: arn:aws:states:::lambda:invoke
          Parameters:
            FunctionName: notifyOwnerFunction
            Payload:
              arn.$: "$.Arn"
          End: true

Deploy the state machine with the AWS CLI:

aws stepfunctions create-state-machine \
  --name TagDrivenDecommissioner \
  --definition file://state-machine.yaml \
  --role-arn arn:aws:iam::123456789012:role/StepFunctionsExecutionRole

Safety nets

Align decommissioning with Savings Plans and Reserved Instances

A common pitfall is to delete an idle instance that is covered by a Savings Plan, inadvertently reducing the plan’s utilization.

Identify covered resources

aws savingsplans describe-savings-plans \
  --query 'SavingsPlans[?State==`active`].{Id:SavingsPlanId,Region:Region,InstanceFamily:InstanceFamily}'

Cross‑reference the list with the idle resources from Athena. If an idle instance matches a Savings Plan, prefer stop over terminate.

Adjust commitments dynamically

If a Savings Plan is under‑utilized for more than 30 days, consider the Modify Savings Plan API (currently in preview) or purchase a new plan that better matches your actual workload mix. Document the decision in a shared spreadsheet to keep finance and engineering aligned.

Manual vs automated tag‑driven decommissioning

Aspect Manual ticket‑based cleanup Automated tag‑driven pipeline
Frequency Weekly or ad‑hoc Daily scheduled run
Human effort High – each resource requires review Low – only exception notifications need attention
Error rate Prone to missed resources or accidental deletion Guardrails (Expiration tag, SNS undo) reduce errors
Visibility Spreadsheet or ticket system Real‑time dashboard via CloudWatch metrics
Cost impact reporting Manual aggregation Immediate dollar impact shown in Cost Explorer or CloudBudgetMaster

Integrate the workflow with CloudBudgetMaster

The free AWS waste finder gives you a quick snapshot of idle resources before you commit to a full pipeline. Run it from the Tools menu, copy the list of ARNs, and feed them into the Step Functions state machine.

Once the pipeline is live, create a free account to let CloudBudgetMaster continuously monitor the dollar impact of each termination. The platform pulls the same Cost Explorer data you use in the Athena query, so you get a single source of truth for budgeting and forecasting.

Frequently asked questions

How often should the decommissioning pipeline run?

A daily schedule balances freshness with API rate limits. For very large environments you can stagger runs by account or region to stay within service quotas.

What if a stopped instance is needed again?

The pipeline sends an SNS message with a signed URL that re‑starts the instance. The URL is valid for 48 hours, giving the owner time to react.

Does this approach work for serverless services?

Serverless resources such as Lambda functions do not have a stop state, but you can use the aws lambda delete-function API for functions that have not been invoked in the analysis window. Add a separate Step Functions branch for serverless.

Will terminating idle resources affect my compliance reports?

Because every resource carries an Owner and Project tag, you retain full auditability. The termination event is logged in CloudTrail, and the SNS notification is archived in an S3 bucket for later review.

Key takeaways

CloudBudgetMaster automates this entire workflow. It scans AWS in read‑only mode today, identifies idle and wasted resources, and reports the dollar impact of each recommendation. Support for GCP, Azure, and Snowflake is coming soon.

Stop guessing where your AWS bill comes from

Upload a CSV, no signup. CloudBudgetMaster finds idle, unused, and overspending AWS resources automatically. GCP and Azure coming soon.

Run a free check