<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: folarin oyenuga</title>
    <description>The latest articles on DEV Community by folarin oyenuga (@olufolarin).</description>
    <link>https://dev.to/olufolarin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F539511%2Fd0185647-2aaf-4068-ab97-d5db59f60895.png</url>
      <title>DEV Community: folarin oyenuga</title>
      <link>https://dev.to/olufolarin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/olufolarin"/>
    <language>en</language>
    <item>
      <title>I built a tool to find every AWS resource you can't tag</title>
      <dc:creator>folarin oyenuga</dc:creator>
      <pubDate>Tue, 01 Sep 2026 17:14:46 +0000</pubDate>
      <link>https://dev.to/olufolarin/i-built-a-tool-to-find-every-aws-resource-you-cant-tag-56o8</link>
      <guid>https://dev.to/olufolarin/i-built-a-tool-to-find-every-aws-resource-you-cant-tag-56o8</guid>
      <description>&lt;p&gt;AWS doesn't publish a list of untaggable resources. can-i-tag-aws scrapes the IAM docs so you can write SCP tagging policies that don't break prod.    &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tagging is the backbone of AWS cost allocation, compliance, and access control. Every well-run organization eventually writes an SCP that says "you cannot create a resource without a CostCenter tag."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then someone's deployment breaks, because they tried to create a resource that cannot be tagged.&lt;/p&gt;

&lt;p&gt;So I built can-i-tag-aws, an open source tool that automatically detects every AWS resource that cannot be tagged.&lt;/p&gt;

&lt;p&gt;This isn't a hypothetical problem. I work on a multi-tenant, cloud-native Kubernetes platform that hosts thousands of team workloads in namespaces, and I've watched SCP tag-enforcement policies block legitimate deployments because they targeted resources that cannot physically carry tags. In one incident, enforcement policies had to be disabled org-wide to unblock every team on the platform while the root cause was found. In another stretch, four separate SCP enforcement failures surfaced in quick succession, one of them during a full deployment halt. Every time, the failure had the same shape: the policy assumed every resource could be tagged.&lt;/p&gt;

&lt;h3&gt;
  
  
  The problem nobody talks about
&lt;/h3&gt;

&lt;p&gt;Not all AWS resources support tagging. That's not controversial. What's surprising is that AWS does not publish a single, consolidated list of what can't be tagged.&lt;/p&gt;

&lt;p&gt;The information exists, but it's scattered across 400+ pages of the IAM Service Authorization Reference, one page per service. To build an SCP tagging policy that actually works, you need three kinds of exclusions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Service-level: entire services with no tagging API at all&lt;/li&gt;
&lt;li&gt;Resource-level: specific resource types inside otherwise-taggable services&lt;/li&gt;
&lt;li&gt;Instance-level: AWS-managed default instances of taggable types (like default.redis7 ElastiCache parameter groups, which reject tags because AWS owns them, not your account)
Without all three, your policy either blocks legitimate API calls or leaves compliance holes. And the list changes as AWS ships new services.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What AWS gives you (and where it falls short)
&lt;/h3&gt;

&lt;p&gt;AWS has pieces of the puzzle, but none of them answer "what can't I tag?" proactively:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource Groups Tagging API&lt;/strong&gt;: only sees resources that already exist in your account. It can't tell you about a service before you deploy it.&lt;br&gt;
&lt;strong&gt;AWS Config rules&lt;/strong&gt;: reactive. They flag non-compliant resources after creation, and they still assume the resource is taggable.&lt;br&gt;
&lt;strong&gt;Per-service documentation&lt;/strong&gt;: accurate but scattered. Nobody is going to read 400+ pages by hand, and the answers go stale as AWS updates services.&lt;br&gt;
&lt;strong&gt;Cost Allocation Reports&lt;/strong&gt;: silently omit untaggable resources, which makes FinOps teams chase attribution gaps that can never be closed.&lt;br&gt;
&lt;strong&gt;The gap&lt;/strong&gt;: there is no proactive, consolidated, machine-readable answer to "which AWS resources cannot be tagged?" That's what this tool fills.&lt;/p&gt;
&lt;h3&gt;
  
  
  What can-i-tag-aws does
&lt;/h3&gt;

&lt;p&gt;It parses the IAM Service Authorization Reference and classifies every resource type across all AWS services. A resource is considered taggable if it has the aws:ResourceTag/${TagKey} condition key or is in scope of a tagging action (TagResource, CreateTags, AddTags). Anything with neither is untaggable.&lt;/p&gt;

&lt;p&gt;The output is a single JSON file with:&lt;/p&gt;

&lt;p&gt;Every untaggable resource, grouped by service, with the reason&lt;br&gt;
Conditionally taggable types (taggable in general, but AWS-managed default instances reject tags), with &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the exact ARN patterns to exclude from SCPs&lt;br&gt;
Mixed-support services broken down per resource type&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"total_services"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;475&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"services_without_tagging_api"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;124&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"total_untaggable_resources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;511&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"conditionally_taggable_resource_types"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;(Numbers from the latest weekly run at the time of writing. The whole point is that they drift, so run it rather than trusting a blog post.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No AWS credentials needed. It works offline against the docs. If you want account-specific confirmation, an optional &lt;code&gt;--live&lt;/code&gt; flag validates findings against your account via boto3.&lt;/p&gt;

&lt;p&gt;Fastest way to try it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/output:/app/output ghcr.io/olu-folarin/can-i-tag-aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The design decision that matters most
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Instance-level detection, spotting AWS-managed defaults like default.redis7 that reject tags despite their type being taggable, can't be looked up anywhere, because AWS doesn't publish a registry of managed default instances. So the tool infers them by naming convention.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inference means occasional false positives, which forced an explicit choice about which way to fail. The tool errs toward inclusion, and the reasoning is asymmetric:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An unnecessary exclusion in your SCP is harmless. You've exempted a resource that would have passed anyway. A missing exclusion blocks a real deployment at create time, in production, for a team that has no idea why.&lt;br&gt;
One failure mode costs nothing, the other pages someone. So the bias goes toward the harmless one. If you take nothing else from this post: when your detection is heuristic, decide deliberately which direction it fails, and write that decision down (you might just be saving yourself the stress of trying to figure out what informed the operating design decision months/years down the line).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Keeping it true over time
&lt;/h3&gt;

&lt;p&gt;A point-in-time list of untaggable resources starts rotting the day you generate it, so the repo maintains itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A weekly scheduled run re-scrapes the reference and regenerates the dataset&lt;/li&gt;
&lt;li&gt;A pre-flight canary checks the docs' structure first and fails loudly if AWS has restructured the pages, so the run aborts rather than parsing garbage&lt;/li&gt;
&lt;li&gt;A post-scrape invariant gate sanity-checks the results (counts within plausible bounds) before anything is committed&lt;/li&gt;
&lt;li&gt;Graduated auto-merge: small drifts merge automatically, anything changing more than 25% of the dataset is held for human review, because a swing that large is more likely a parsing problem than AWS reinventing itself overnight&lt;/li&gt;
&lt;li&gt;A dead-man's-switch opens a GitHub issue (deduplicated) when a run fails, so a silent breakage can't quietly become a stale dataset
The tool also keeps timestamped history with a diff command, so you can see exactly when AWS added or dropped tagging support for anything, and update your policies on evidence rather than on rumour.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Who it's for (and uses beyond the README)
&lt;/h3&gt;

&lt;p&gt;The obvious audience: platform engineers writing SCP tagging policies, and security teams auditing tag enforcement. But the output is just structured data, so it plugs into more workflows:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FinOps&lt;/strong&gt;: identify which resources will never appear in cost allocation reports, so you stop investigating attribution gaps that are structurally impossible to close.&lt;br&gt;
&lt;strong&gt;Policy-as-code (OPA, Conftest, Checkov)&lt;/strong&gt;: skip mandatory-tag checks on resource types that can never pass them, cutting false positives from CI.&lt;br&gt;
&lt;strong&gt;Landing zone rollouts&lt;/strong&gt;: run it as a pre-flight check before enabling tag-enforcement SCPs on new OUs or acquired accounts.&lt;br&gt;
&lt;strong&gt;CMDB and asset inventory&lt;/strong&gt;: don't design workflows that depend on tags for resources that can't carry them.&lt;br&gt;
&lt;strong&gt;Drift monitoring&lt;/strong&gt;: track when AWS adds or drops tagging support, and update policies accordingly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Honest limitations
&lt;/h3&gt;

&lt;p&gt;It scrapes HTML docs, so if AWS restructures the IAM reference, parsing can break. The canary catches this and opens an issue rather than publishing bad data. It's a point-in-time snapshot, which is why the weekly re-run matters. And instance-level detection is convention-based, with the fail-safe bias described above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;If you've ever had a tagging SCP break a deployment, or a FinOps report with unexplainable gaps, this is the reference list you previously had to build by hand. It's MIT licensed, runs in Docker with zero credentials, and the output is plain JSON you can feed into whatever governance pipeline you already have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repo&lt;/strong&gt;: &lt;a href="//github.com/olu-folarin/can-i-tag-aws"&gt;can-i-tag-aws&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Docker Image&lt;/strong&gt;: &lt;a href="//ghcr.io/olu-folarin/can-i-tag-aws"&gt;can-i-tag-aws&lt;/a&gt;&lt;br&gt;
Issues and PRs welcome, especially reports of AWS-managed resources that reject tags despite their type showing as taggable.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>aws</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>folarin oyenuga</dc:creator>
      <pubDate>Mon, 01 Jun 2026 08:06:10 +0000</pubDate>
      <link>https://dev.to/olufolarin/-4adl</link>
      <guid>https://dev.to/olufolarin/-4adl</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/olufolarin/how-systematic-ebs-optimization-delivered-significant-annual-savings-a3h" class="crayons-story__hidden-navigation-link"&gt;How Systematic EBS Optimization Delivered Significant Annual Savings&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/olufolarin" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F539511%2Fd0185647-2aaf-4068-ab97-d5db59f60895.png" alt="olufolarin profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/olufolarin" class="crayons-story__secondary fw-medium m:hidden"&gt;
              folarin oyenuga
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                folarin oyenuga
                
              
              &lt;div id="story-author-preview-content-3218539" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/olufolarin" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F539511%2Fd0185647-2aaf-4068-ab97-d5db59f60895.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;folarin oyenuga&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/olufolarin/how-systematic-ebs-optimization-delivered-significant-annual-savings-a3h" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Feb 1&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/olufolarin/how-systematic-ebs-optimization-delivered-significant-annual-savings-a3h" id="article-link-3218539"&gt;
          How Systematic EBS Optimization Delivered Significant Annual Savings
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/aws"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;aws&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/finops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;finops&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devops&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/kubernetes"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;kubernetes&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/olufolarin/how-systematic-ebs-optimization-delivered-significant-annual-savings-a3h" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/olufolarin/how-systematic-ebs-optimization-delivered-significant-annual-savings-a3h#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>How Systematic EBS Optimization Delivered Significant Annual Savings</title>
      <dc:creator>folarin oyenuga</dc:creator>
      <pubDate>Sun, 01 Feb 2026 23:10:57 +0000</pubDate>
      <link>https://dev.to/olufolarin/how-systematic-ebs-optimization-delivered-significant-annual-savings-a3h</link>
      <guid>https://dev.to/olufolarin/how-systematic-ebs-optimization-delivered-significant-annual-savings-a3h</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zot5cda1eeoc8feyb4e.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7zot5cda1eeoc8feyb4e.jpeg" alt=" " width="800" height="448"&gt;&lt;/a&gt;## Definitions &amp;amp; Scope&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Orphaned volume&lt;/strong&gt; (in this context): An EBS volume that is unattached, not referenced by any PersistentVolume/PersistentVolumeClaim, not part of backup/DR workflows, not snapshot-dependent for active AMI pipelines, and confirmed deletable by volume owners.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scope&lt;/strong&gt;: Production EKS cluster spanning multiple AWS regions, supporting 1000+ namespaces.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;In cloud environments, EBS volumes accumulate silently. Engineers spin up instances for testing, experiments are abandoned, services are decommissioned—and volumes are left behind. Still attached to your AWS bill.&lt;/p&gt;

&lt;p&gt;While investigating resources lacking mandatory tags for a compliance initiative, I found &lt;strong&gt;over a thousand unattached EBS volumes&lt;/strong&gt; consuming &lt;strong&gt;60 TB&lt;/strong&gt; of storage. The original goal was to add tags to untagged resources. But I saw an opportunity: many of these volumes appeared genuinely orphaned. If I could safely identify and remove them, the cost savings would be significant.&lt;/p&gt;

&lt;p&gt;The naive approach "delete all unattached volumes" often causes incidents. Volumes might be referenced by automation, support disaster recovery, or be temporarily detached during deployments. I'd seen rushed cleanup campaigns end in emergency snapshot restores, lost engineering hours and damaged engineering trust.&lt;/p&gt;

&lt;p&gt;I needed a systematic way to determine which volumes could be safely deleted, when, and how.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: 7-Step Verification Methodology
&lt;/h2&gt;

&lt;p&gt;Every volume passed through 7 independent checks before deletion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Volume Age &amp;amp; IOPS Analysis (Triage)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Check&lt;/strong&gt;: How old is the volume? What's the IOPS configuration?&lt;/p&gt;

&lt;p&gt;Volume age correlates with orphan likelihood. Volumes untouched for 6+ months are strong candidates. But age alone isn't enough. IOPS analysis surfaces cost outliers that deserve priority attention.&lt;/p&gt;

&lt;p&gt;During triage, I discovered a 750GB io1 volume provisioned at 15,000 IOPS. Annual cost: quite significant for a single volume. It's easy to simply focus on storage (GB) and nothing more. The real cost driver for io1/io2 volumes is provisioned IOPS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson&lt;/strong&gt;: IOPS analysis should not be excluded from your verification, especially for io1/io2 volumes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Attachment State Verification
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Check&lt;/strong&gt;: Is this volume currently attached to any EC2 instance?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ec2 describe-volumes &lt;span class="nt"&gt;--filters&lt;/span&gt; &lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;status,Values&lt;span class="o"&gt;=&lt;/span&gt;available
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Status &lt;code&gt;available&lt;/code&gt; means unattached. But unattached ≠ deletable. I move to further verification.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Kubernetes PV/PVC Cross-Reference
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Check&lt;/strong&gt;: Is this volume referenced by any PersistentVolume or PersistentVolumeClaim?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pv &lt;span class="nt"&gt;-o&lt;/span&gt; json | jq &lt;span class="s1"&gt;'.items[] | select(.spec.awsElasticBlockStore.volumeID)'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A volume might be unattached at the EC2 level but still referenced by Kubernetes. Deleting it would break the next pod that tries to mount it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: CloudTrail Activity Analysis
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Check&lt;/strong&gt;: When was this volume last accessed? By whom?&lt;/p&gt;

&lt;p&gt;CloudTrail reveals the last &lt;code&gt;AttachVolume&lt;/code&gt;, &lt;code&gt;DetachVolume&lt;/code&gt;, or &lt;code&gt;CreateSnapshot&lt;/code&gt; events. Volumes with no activity for 6+ months are strong deletion candidates. Recent activity means someone's still using it, even if it's currently detached.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Snapshot &amp;amp; AMI Pipeline Check
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Check&lt;/strong&gt;: Is this volume part of an active snapshot workflow or AMI build process?&lt;/p&gt;

&lt;p&gt;Snapshots and AMIs indicate the volume is referenced by automation, launch templates, or image build pipelines. Even if the volume itself isn't directly backing an AMI (snapshots do that), its existence in an active workflow means deletion could break restore processes or future builds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Tag &amp;amp; Naming Convention Analysis
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Check&lt;/strong&gt;: Do tags or naming patterns indicate purpose?&lt;/p&gt;

&lt;p&gt;Tags like &lt;code&gt;kubernetes.io/created-for/pvc/name&lt;/code&gt; or naming patterns like &lt;code&gt;prometheus-data-*&lt;/code&gt; reveal original purpose. Cross-reference with current cluster state to determine if that workload still exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Senior Team Validation for High-Value Volumes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Check&lt;/strong&gt;: For volumes &amp;gt;1TB or with significant cost impact, get senior team sign-off.&lt;/p&gt;

&lt;p&gt;After successfully deleting 725 volumes across earlier phases (small and medium-value batches), I had 4 remaining high-value volumes including the expensive io1 volume from Step 1.&lt;/p&gt;

&lt;p&gt;I scheduled a live review session with senior engineers. I walked through my 7-step verification for each volume. They applied their own independent verification methods. Both approaches confirmed: all 4 volumes were safe to delete.&lt;/p&gt;

&lt;p&gt;All 4 were deleted during the call. Zero incidents.&lt;/p&gt;




&lt;h2&gt;
  
  
  Phased Execution
&lt;/h2&gt;

&lt;p&gt;I didn't delete 729 volumes on day one. Phased approach:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1&lt;/strong&gt;: 10 oldest, smallest volumes. 48-hour monitoring. Zero issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2&lt;/strong&gt;: Incremental batches (15 → 20 → 30 → 50 volumes), 24-48 hour monitoring windows between each.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 3&lt;/strong&gt;: 281 medium-value Prometheus volumes from decommissioned workloads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 4&lt;/strong&gt;: 4 high-value volumes with senior team validation.&lt;/p&gt;

&lt;p&gt;This was done under change control with documented approvals and audit-friendly evidence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Total timeline&lt;/strong&gt;: 5 weeks | &lt;strong&gt;Success rate&lt;/strong&gt;: 100% (729/729) | &lt;strong&gt;Production incidents&lt;/strong&gt;: 0&lt;/p&gt;




&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Volumes investigated&lt;/td&gt;
&lt;td&gt;1000+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Volumes deleted&lt;/td&gt;
&lt;td&gt;732 (729 by me, 3 via methodology adoption)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage reclaimed&lt;/td&gt;
&lt;td&gt;60 TB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Annual savings&lt;/td&gt;
&lt;td&gt;Significant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production incidents&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The team appreciated the systematic approach. A colleague subsequently adopted the methodology on another cluster, identifying 3 additional high-value volumes, demonstrating that reusable frameworks multiply impact beyond direct execution.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Systematic beats aggressive.&lt;/strong&gt; I could have deleted everything in a day. The 5-week phased approach with monitoring windows meant zero incidents and built enough trust that the methodology was adopted elsewhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IOPS costs dominate io1/io2 volumes.&lt;/strong&gt; It's important to reiterate that it's often easier to focus on storage (GB). Whereas a single io1 volume can cost more annually than twenty gp3 volumes combined.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dual verification builds trust.&lt;/strong&gt; For high-impact deletions, having senior engineers independently confirm your methodology eliminates doubt, enables organizational adoption and also provides an opportunity to see things through fresh perspectives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Look for adjacent opportunities.&lt;/strong&gt; The original task was tagging compliance. The cost savings emerged from noticing that many untagged volumes were also unused. Sometimes the bigger win is next to the assigned work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automate what you've validated.&lt;/strong&gt; Once you trust the methodology, bake it into your processes. Manual verification doesn't scale; time is invaluable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/olu-folarin/aws-ebs-optimization-methodology" rel="noopener noreferrer"&gt;aws-ebs-optimization-methodology&lt;/a&gt; - Reusable 7-step framework&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Have you tackled similar cloud cost challenges? What worked for you?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>finops</category>
      <category>devops</category>
      <category>kubernetes</category>
    </item>
  </channel>
</rss>
