| name | ops-aws-audit |
| description | Read-only AWS account hygiene audit — security baseline, unused/orphaned resources, and cost optimization across all configured regions. Produces severity-ranked findings (CRITICAL→LOW) plus a machine-readable findings.json. Cleanup actions are always human-gated, never automatic. Use for cost reviews, security sweeps, recurring account hygiene, or "audit my AWS". |
| argument-hint | [--quiet] [--schedule] [region,region] |
| allowed-tools | ["Bash","Read","Grep","Glob","AskUserQuestion","WebSearch","WebFetch"] |
| effort | medium |
| maxTurns | 30 |
What this does
Runs scripts/ops-aws-audit.sh — a read-only sweep that never mutates AWS.
It inventories and analyses, then writes a severity-ranked report.
Checks include (2026 baseline):
- IAM / credentials — root access key + root MFA, access keys older than
AUDIT_KEY_AGE_DAYS (default 90), console users without MFA, and whether an
IAM Access Analyzer (UNUSED_ACCESS) is configured.
- EC2 / EBS — unattached volumes,
gp2→gp3 candidates, unencrypted
volumes, unassociated Elastic IPs, security groups open to 0.0.0.0/0 on
SSH/RDP.
- RDS — unencrypted or publicly-accessible instances, and orphaned manual
snapshots whose source DB no longer exists.
- S3 — account-level Block Public Access, per-bucket default encryption and
lifecycle policies.
- CloudWatch Logs — log groups with no retention (billed forever).
- Lambda — deprecated/old runtimes.
- Security posture — GuardDuty, Security Hub standards, Cost Anomaly
Detection monitors, Compute Optimizer enrollment.
- Cost — per-service Usage spend (
RECORD_TYPE=Usage UnblendedCost) over
the last AUDIT_COST_DAYS with the Δ vs the prior window. Credits mask net CE
totals to ≈ $0 — this audit never uses unfiltered Blended/Unblended nets as burn.
Configuration (env, all optional)
| Var | Default | Meaning |
|---|
AUDIT_PROFILE | (unset) | Named AWS profile. Unset ⇒ standard chain (env keys / instance role / SSO). |
AUDIT_REGIONS | $AWS_REGION or us-east-1 | Comma-separated regions. |
AUDIT_OUTPUT_DIR | ~/.aws-audit-history/audit-<ts> | Where reports land. |
AUDIT_KEY_AGE_DAYS | 90 | Active access-key age threshold. |
AUDIT_COST_DAYS | 7 | Cost comparison window. |
How to run
bash "${CLAUDE_PLUGIN_ROOT}/scripts/ops-aws-audit.sh"
AUDIT_PROFILE=prod AUDIT_REGIONS=us-east-1,eu-central-1 \
bash "${CLAUDE_PLUGIN_ROOT}/scripts/ops-aws-audit.sh"
Outputs in AUDIT_OUTPUT_DIR: report.md (human), findings.json
(machine), raw/ (per-service snapshots + cost-delta.tsv), audit.log.
After the run, read findings.json and summarise CRITICAL/HIGH first.
Recurring schedule
--schedule installs a daily systemd --user timer via
scripts/install-aws-audit-cron.sh (Linux; this box uses systemd, not launchd):
bash "${CLAUDE_PLUGIN_ROOT}/scripts/install-aws-audit-cron.sh"
systemctl --user list-timers ops-aws-audit.timer
Dispatch to the background fleet instead:
claude --bg --name aws-audit -- bash "${CLAUDE_PLUGIN_ROOT}/scripts/ops-aws-audit.sh" --quiet
Cleanup is human-gated (never automatic)
This skill only audits. To act on a finding:
- Show the user the specific finding(s) and the exact
aws command(s).
- Get explicit per-batch approval (
ok / yes / proceed).
- For any deletion/rotation, snapshot state first; log resource IDs after.
- Root access keys can only be removed from a root console login — flag it,
do not attempt to "rotate root" from an IAM-user CLI session (that only
rotates the IAM user's own key, not the root key).