| name | review-aws-tagging |
| description | [pr-review-focus-area: AWS Tagging] Audit AWS resource tag compliance against an organization taxonomy (cost center, owner, environment, data classification, etc.). |
| user-invocable | true |
| disable-model-invocation | true |
| allowed-tools | ["Read","Bash","Grep","Glob","AskUserQuestion"] |
| argument-hint | [taxonomy-file or inline:key1,key2] |
AWS Tag Compliance Review
Verify AWS resources are tagged in conformance with an organization taxonomy. Reports per-resource-type coverage, per-resource offender lists, and an overall compliance verdict. This skill is strictly read-only — it never mutates tags.
Invocation
The user runs /review-aws-tagging [taxonomy-file or inline:key1,key2,...]. The argument may be:
- A path to a YAML taxonomy file.
- An
inline: specifier listing required tag keys (for example inline:Owner,CostCenter,Environment).
- Omitted — the skill looks for
.claude/tagging-taxonomy.yml or prompts for the taxonomy.
Execution Steps
Run steps in order. Each step reports PASS, FINDING, SKIPPED (prerequisite missing), or INCONCLUSIVE. Never fabricate tag values, resource ARNs, or account ids.
1. Load Taxonomy
- If the argument is a file path, read the YAML. Expected schema per tag:
tags:
- key: Owner
required: true
severity: HIGH
allowed_values: null
allowed_regex: "^[a-z0-9_-]+$"
- key: Environment
required: true
severity: HIGH
allowed_values: [prod, staging, dev, sandbox]
- key: CostCenter
required: true
severity: MEDIUM
allowed_regex: "^CC-[0-9]{4}$"
- key: DataClassification
required: false
severity: LOW
allowed_values: [public, internal, confidential, restricted]
- If the argument is
inline:key1,key2,..., synthesize a minimal taxonomy with every key required: true, severity: MEDIUM.
- If neither is supplied, use AskUserQuestion to request the required tag keys and their allowed values.
- If the taxonomy cannot be loaded, mark this step SKIPPED and stop.
2. Scan IaC
- Glob for Terraform (
*.tf), CloudFormation (*.yaml, *.yml, *.json templates), CDK output, and Pulumi code under the repo.
- For each
aws_* Terraform resource that supports tags, collect:
- Its
tags = { ... } block.
- Any
default_tags from the provider block in the same module.
- Tags inherited via
locals spread.
- For each CloudFormation
AWS::*::* resource, read its Properties.Tags list.
- Resolve each resource's effective tag set — provider default_tags merged with resource-local tags, with resource-local winning on conflict.
- Normalize tag keys to a case-sensitive form (AWS is case-sensitive). Do not silently lowercase.
- For every effective tag set, compare against the taxonomy:
- Required key missing → MISSING finding at the taxonomy-declared severity.
- Key present but value fails
allowed_values / allowed_regex → INVALID finding at the taxonomy-declared severity.
- Unknown key not in taxonomy → report as HOUSEKEEPING (low priority), not a FINDING.
3. Scan Live (Optional)
-
Probe AWS credentials with the shared helper. Prefer ${CLAUDE_PLUGIN_ROOT}/scripts/cloud-auth-check.sh and fall back to plugins/infra/scripts/cloud-auth-check.sh when running from the plugin dev repo.
AUTH="${CLAUDE_PLUGIN_ROOT:-plugins/infra}/scripts/cloud-auth-check.sh"
[ -x "$AUTH" ] || AUTH="plugins/infra/scripts/cloud-auth-check.sh"
"$AUTH" aws
If the JSON status is MISSING_CLI, UNAUTHENTICATED, or EXPIRED, mark this step SKIPPED with the detail field as the reason and continue with IaC-only.
-
Ask via AskUserQuestion whether to include live scanning. Default to no.
-
If enabled, paginate aws resourcegroupstaggingapi get-resources --tags-per-page 100 across the target regions. Capture ResourceARN and Tags.
-
For each ARN, diff against the taxonomy the same way as step 2.
-
Record resources that appear live but not in IaC as HOUSEKEEPING drift (likely click-ops) — surface them separately rather than mixing with tagging findings.
4. Compute Coverage
- Bucket findings by AWS resource type (for example
aws_s3_bucket, aws_instance, aws_rds_cluster).
- For each bucket, compute
compliance % = (resources with all required tags present and valid) / (total resources).
- Report any type below 100% as a row in the coverage matrix.
5. Report
- Build the coverage matrix.
- Build the offender list, grouped by severity (HIGH → MEDIUM → LOW).
- For each offender, list the exact missing keys and invalid values — never propose a tag value that was not supplied by the user or present in the taxonomy.
Output Format
## AWS Tagging Review — <taxonomy source>
**Scope:** <IaC | IaC + Live> **Required tags:** Owner, Environment, CostCenter
### Coverage Matrix
| Resource Type | Total | Fully Compliant | % |
| ---------------------- | ----- | --------------- | - |
| aws_s3_bucket | 12 | 10 | 83% |
| aws_instance | 34 | 20 | 59% |
| aws_rds_cluster | 3 | 3 | 100% |
...
### Offenders — HIGH severity
| Resource | Missing | Invalid | Source |
| -------- | ------- | ------- | ------ |
| aws_s3_bucket.logs | Owner, Environment | — | terraform/storage/s3.tf:42 |
| aws_instance.bastion | — | Environment="production" (expected one of prod/staging/dev/sandbox) | terraform/network/bastion.tf:18 |
...
### Offenders — MEDIUM severity
...
### Housekeeping (unknown tags, live-only resources)
...
### Totals
- Scanned: <N> resources (<X> IaC, <Y> live)
- MISSING: <N> INVALID: <N> Compliant: <N>
### Verdict: <COMPLIANT | PARTIAL | NON-COMPLIANT>
Verdict
- COMPLIANT — every required tag present with a valid value on every resource in scope.
- PARTIAL — 90% or more resources compliant and no HIGH-severity missing tags.
- NON-COMPLIANT — below 90% compliance, or any HIGH-severity missing tags, or any INVALID value with HIGH severity.
Rules
- Read-only AWS calls only. Use
aws resourcegroupstaggingapi get-resources, aws sts get-caller-identity, and nothing else in this skill. Never emit aws ec2 create-tags, aws s3api put-bucket-tagging, aws resourcegroupstaggingapi tag-resources, or any other mutating command.
- Never fabricate tag values or ARNs. Report only values that were read from IaC or live AWS responses. If the taxonomy demands a value you cannot verify, mark the field INCONCLUSIVE.
- Graceful skip. If the taxonomy cannot be loaded, stop and report. If live scanning is enabled but
aws or credentials are missing, mark live SKIPPED and continue with IaC-only.
- Case-sensitive keys. Do not collapse
owner and Owner — report them as distinct.
- Never propose tag values. Suggest "add Owner tag" but do not invent a value like
Owner=platform-team unless the user supplied that value in the taxonomy or the repo.
- No persona. Procedural and imperative only.
$ARGUMENTS