The Roomba for Your Cloud Learns New Floors
Cloud Custodian · releaseCloud Custodian 0.9.53.0 just gave your cloud a much bigger broom. If you have never met the project: Cloud Custodian is an open-source rules engine that lets you write simple YAML policies that find, tag, clean up, and enforce rules on your cloud resources across AWS, Azure, and GCP. Think of it as a Roomba for your cloud bill and your security posture: you write the rules once, and it quietly wanders around your accounts deleting forgotten junk, slapping tags on unlabeled servers, and flagging anything that breaks policy. Platform teams, security folks, and anyone who has ever opened a cloud console and muttered “who left this here?” use it daily.
This release matters because Custodian can now govern a whole lot more of your world: every custom resource (CRD) in your Kubernetes clusters, your growing pile of AI services, the new S3 lakehouse formats, and even Google Workspace users who skipped MFA.
What’s New in 0.9.53.0
The short version: Custodian grew 23 new resource types and a stack of new filters and actions, spread across AWS, Azure, GCP, and Kubernetes. The long version is better. Here are the four stories worth your time.
Kubernetes: Policies for Any Custom Resource, No Plugin Required
This is the headline. Custodian’s Kubernetes support historically knew about a fixed list of resource types: if your platform ran on custom resources, the engine was blind to them until someone wrote support upstream.
The new k8s custom-resource type changes that: it discovers any installed CRD at scan time and lists that CRD’s instances too. Neither the definition nor the instances need to be declared ahead of time.
Why care? Because platform teams run their real infrastructure on CRDs: databases, cert-manager certificates, Argo applications, internal abstractions. Policy-as-code could not touch any of it without bespoke plugin work.
Now a single generic resource type covers all of them, today and for every CRD you install next year. Your governance rules finally speak your platform’s language.
Building it turned up a real bug: on CRDs with many objects, listing silently stopped after the first page of results. The fix (PR #11081) ships in this release too, verified against a real cluster by the custom-resource author (PR #11083).
The exact identifier is k8s.custom-resource. Every discovered CRD’s instances land under that single resource type, each tagged with the identity of the CRD it came from — crd_group, crd_version, crd_plural, crd_scope — so you scope by CRD identity in a plain value filter (the project’s own test suite uses Karpenter NodePools as the worked example):
policies:
- name: audit-karpenter-nodepools
resource: k8s.custom-resource
filters:
- type: value
key: crd_group
value: karpenter.shA filters: block is optional — with none, you simply get every custom resource in the cluster. Implementation and tests: PR #11083.
AI Sprawl Gets a Custodian Policy
Your company’s AI footprint grew this year. Its governance did not. 0.9.53.0 quietly closes that gap with a batch of AI-surface resources: five Q Business resource types (application, index, plugin, data accessor, data source), an AIOps investigation group resource, and a new deployments filter for Bedrock custom models that finds Active models older than 14 days that are serving exactly nothing:
policies:
- name: bedrock-undeployed-custom-models
resource: aws.bedrock-custom-model
filters:
- type: value
key: modelStatus
value: Active
- type: value
key: creationTime
op: gt
value_type: age
value: 14
- type: deployments
status: Active
value: absentThat is a policy for custom models that are billing you for storage while doing absolutely nothing. The filter queries ListCustomModelDeployments for each model and can require a deployment to be present or absent, optionally scoped by deployment status. The Q Business resources ship with a cross-account filter on applications and universal tagging on everything. See PR #10944 for the Bedrock filter and PR #10990 for Q Business.
S3 Tables and S3 Files: The Lakehouse Joins the Party
AWS’s newer storage formats now have first-class support. S3 Tables (the Iceberg-native table store) get two resources: aws.s3-table-bucket and aws.s3-table, with cross-account filters that evaluate table bucket and table policies, plus has-statement and replication filters, and tag, remove-tag, and mark-for-op (tag a resource now for a delayed action later) actions. S3 Files adds three more: aws.s3files-file-system, aws.s3files-mount-target, and aws.s3files-access-point, with cross-account and has-statement on file systems, plus subnet, security-group, and network-location filters on mount targets.
Every filter and action here is the standard Custodian set, pointed at the new lakehouse types — for example, flag S3 Tables shared outside your org:
policies:
- name: s3tables-shared-outside-org
resource: aws.s3-table
filters:
- type: cross-account
whitelist_org_ids:
- o-your-org-idBoth new types carry the full filter and action set listed above, so inventory and remediation work the same as on any other Custodian resource.
If your data platform team just discovered that “temporary” analytics buckets live forever, these are for you. The work landed in PR #10973 (Tables) and PR #10972 (Files).
Google Workspace MFA Reporting
A first for the project: gcp.workspace-user lets policies report Google Workspace users who have not enrolled in two-step verification. This is enabling work for the CIS GCP Benchmark control that requires MFA for all non-service accounts, and it matters technically because Workspace users are not GCP resources at all: they live in Cloud Identity, are read through the Admin SDK Directory API, and are authorized by domain-wide delegation rather than GCP IAM. Custodian’s session layer had to learn all of that. The policy is exactly as simple as you hope:
policies:
- name: gcp-workspace-users-without-mfa
resource: gcp.workspace-user
filters:
- type: value
key: isEnrolledIn2Sv
value: false
- type: value
key: suspended
value: falseFull details, including the operational prerequisites — domain-wide delegation with an impersonated Workspace admin, GOOGLE_WORKSPACE_SUBJECT, and customer scoping via GOOGLE_WORKSPACE_CUSTOMER (defaulting to my_customer) — in PR #10950. A follow-up will add auditing of security-key usage.
Also worth a look: an API Gateway v2 route resource, a Vertex AI metadata-store artifact resource, IoT expansion (certificates, OTA updates, policies — PR #11098), SSM tagging everywhere (tag, remove-tag, mark-for-op on SSM-managed instances — the hybrid mi-* kind; EC2 i-* instances already tag via EC2 — plus ops items, patch baselines, maintenance windows, and associations — PR #11093), rds-global-cluster and event-connection resources, surfacing notifications and a filter expression on AWS Budgets (PR #11116), Azure ML archive and cancel actions, an Azure NSG remove-rules action, a GCP KMS cryptokey update action, and parent-scoped dimensions in the Azure metric filter.
The Quiet Core Upgrades
Two core changes did not get their own story above but deserve a look. --vars-file (PR #10939) lets you inject variables at custodian run time without editing your policy files — the same mechanism c7n-org (Custodian’s multi-account runner) uses for account vars, finally available in the main CLI. Your vars-file entries are expanded first, then the standard framework variables (like account_id and region) are layered on top, so built-ins always win:
custodian run -s out policy.yml --vars-file vars.ymlvars.yml is plain key-value YAML — the PR author’s own use case was a source_region for notification queues that live in a different region than the one being scanned:
# vars.yml
source_region: us-east-1Reference it anywhere in the policy with the standard placeholder syntax, {source_region}, exactly like the built-ins — and on a name collision the framework built-ins ({account_id}, {region}) win:
policies:
- name: cross-region-notify
resource: aws.ec2
actions:
- type: notify
to: [ops@example.com]
transport:
type: sns
topic: alarms-{source_region}And dynamic tagging (PR #10968) is now standardized across providers: the “give this tag a default value only if it is not already set” authoring pattern, previously AWS-only, now works the same way on Azure and GCP, and aws.asg tag actions got fixed to share the same resolution logic.
Correctness Fixes Worth Knowing About
No security advisories in this release, but three fixes address silent wrongness in a tool whose whole job is complete, correct inventory:
- Kube listing dropped resources past page one. The pagination fix above (PR #11081) means policies on large clusters no longer silently skip everything after the first page.
- The resolver served cached responses across different request headers. The URI cache key now includes request headers (PR #11148), so an
urifilter keyed on headers gets fresh answers. - The kube resource cache ignored the resource type. Cache keys now include it (PR #11168), preventing cross-type cache collisions.
Upgrade Notes
Nothing here is a fire drill, but four changes alter what your existing policies can see or touch:
- CloudWatch dashboards lost an action. The
rename-tagaction is gone fromaws.cloudwatch-dashboard, replaced by native CloudWatch tagging, so audit any policies that still reference it. PR #11090 - KMS and Route53 now skip AWS-managed resources. Actions no longer fire on resources AWS owns and you cannot really manage. PR #11050
- Tagging tolerates mid-run deletions. Resources deleted between inventory and the tag action no longer cause hard failures. PR #11089
- SSM compliance filters honor defaults.
ec2ssm-compliance now respects advertised state defaults instead of requiring explicit values. PR #10883
Closing
Upgrade, point a policy at your messiest CRD, and let the Roomba finally reach the corners.