Cloud Security Posture skill for Claude Code

Find the public bucket before someone else does. Claude audits cloud accounts with read-only roles across every region: it confirms logging baselines, runs Prowler against a CIS framework, adds targeted CLI checks for public data, open admin ports and risky identities, then collapses findings into root causes. Fixes go into Terraform or CDK after usage evidence and confirmation, each paired with an SCP or org policy guardrail.

  • namecloud-security-posture
  • size231 lines · ≈2,900 tokens
  • files1
  • licenseMIT
  • updated

What Claude sees before loading it

This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.

description: Audits AWS, GCP, and Azure accounts for posture risks with read-only access - public buckets and snapshots, open security groups and firewall rules, IAM sprawl, stale keys, missing root MFA, disabled CloudTrail or GuardDuty - using Prowler, native services (Security Hub, IAM Access Analyzer, Security Command Center, Defender for Cloud), and targeted CLI checks, then ranks findings and fixes them in IaC with preventive guardrails. Use when asked to audit a cloud account, run Prowler or a CIS benchmark, find public resources, or clean up IAM.

Try asking

  • Run a read-only security audit of our AWS org and tell me what is publicly exposed
  • Prowler gave us 2,400 failed checks. Turn this CSV into a prioritized fix plan
  • Find GCP resources shared with allUsers and firewall rules open to the internet

Use it when

  • You inherited cloud accounts and need to know their worst exposures
  • A CIS benchmark or Prowler scan is required for an audit or customer questionnaire
  • You suspect public buckets, snapshots, or open admin ports
  • IAM users, keys, and roles have grown without review

Skip it when

  • You are writing or debugging a specific IAM policy — use aws-iam instead
  • Signs of active compromise are present — use incident-response instead
  • The concern is container images or pod specs — use container-security instead

How to check the result

Re-run the same Prowler command and targeted CLI checks to show fixed items now pass, and prove each guardrail by attempting the blocked action in a sandbox account and getting AccessDenied.

The common mistake it prevents

Closing a security group or blocking public access on a bucket straight from the console without checking flow or access logs, breaking a production dependency and drifting from Terraform.

~/.claude/skills/cloud-security-posture/SKILL.md

--- name: cloud-security-posture description: Audits AWS, GCP, and Azure accounts for posture risks with read-only access - public buckets and snapshots, open security groups and… license: MIT ---

An audit is done when you know every account and region in scope, the internet-exposed and publicly shared resources are listed with owners, identity risks (root, long-lived keys, wildcard admin, cross-account trust) are ranked, and each fix lands in IaC with a guardrail that stops the same misconfiguration from returning. A 3,000-row Prowler CSV handed over unread is not an audit.

Ground rules

  • Audit only accounts the user owns or is authorized to assess. Use read-only credentials: AWS managed policies SecurityAudit plus ViewOnlyAccess, GCP roles/iam.securityReviewer plus roles/cloudasset.viewer, Azure Reader plus Security Reader.
  • Do not change resources during the audit. Remediation is a separate step, and any change that can break traffic or delete data (closing a security group, deleting keys, blocking public access on a bucket serving a website) requires explicit user confirmation after naming the resource and its current use.
  • Scan every enabled region. Attackers launch resources in regions you never look at.
  • Treat each finding as a lead: a “public” bucket may be an intentional static site behind CloudFront. Confirm intent with the owner before calling it a breach.
  • If you find evidence of active compromise (unknown IAM users, crypto-mining instances, unfamiliar access keys in use), stop the audit and switch to incident-response.

Workflow

- [ ] 1. Inventory: org, accounts/projects/subscriptions, enabled regions, owners
- [ ] 2. Confirm logging and detection baselines exist (you need them to judge anything)
- [ ] 3. Run a CSPM scan (Prowler) and pull native findings
- [ ] 4. Targeted checks for the highest-impact risks
- [ ] 5. Triage: exposure x data sensitivity x exploitability; dedupe by root cause
- [ ] 6. Remediate in IaC with confirmation; add preventive guardrails
- [ ] 7. Re-scan and record residual risk

1. Inventory

aws organizations list-accounts --query 'Accounts[?Status==`ACTIVE`].[Id,Name]' --output table
aws ec2 describe-regions --query 'Regions[].RegionName' --output text
gcloud projects list --format='table(projectId,name,parent.id)'
az account list --query '[].{name:name,id:id,state:state}' -o table

Note accounts with no owner, no IaC, or created by a former employee: they carry the most drift.

2. Logging and detection baselines

CloudMust be onCheck
AWSOrg or multi-region CloudTrail with log file validation; GuardDuty in every region; Config recorderaws cloudtrail describe-trails --query 'trailList[].[Name,IsMultiRegionTrail,IsOrganizationTrail,LogFileValidationEnabled]', aws guardduty list-detectors --region <r>
GCPAdmin Activity audit logs (always on), Data Access logs for sensitive services, Security Command Centergcloud logging sinks list, org IAM audit config
AzureActivity Log exported to Log Analytics; Defender for Cloud plans on critical resource typesaz monitor diagnostic-settings subscription list

Missing baselines are findings in their own right and go near the top of the report.

3. CSPM scan

Default: Prowler (open source, AWS/Azure/GCP/Kubernetes/M365/GitHub, maps to CIS and other frameworks).

pipx install prowler            # official container images are also published; see the Prowler docs
prowler -v
prowler aws --list-compliance   # exact framework IDs vary by version
prowler aws --profile audit --compliance cis_4.0_aws --output-formats csv json-ocsf html -o ./prowler-out
prowler aws --profile audit --services s3 iam ec2 --severity critical high
prowler gcp --project-ids prod-123 staging-456
prowler azure --az-cli-auth

Flags differ across major releases; run prowler <provider> --help and use the IDs from --list-compliance rather than guessing. For multi-account AWS, run per account by assuming a read-only audit role (--role arn:aws:iam::<acct>:role/ProwlerAudit) from a central account. Record intentional exceptions in a mutelist file (--mutelist-file) with a reason per entry instead of deleting rows from the report.

Also pull what the platform already knows: AWS Security Hub CSPM findings and IAM Access Analyzer external-access findings, GCP Security Command Center findings, Azure Defender for Cloud recommendations. ScoutSuite still works for a one-off multi-cloud HTML report but releases have slowed; prefer Prowler or the native services for anything you plan to rerun.

4. Targeted high-impact checks

Run these even when the scanner is green; they cover the incidents that actually happen.

AWS public data:

ACCT=$(aws sts get-caller-identity --query Account --output text)
aws s3control get-public-access-block --account-id "$ACCT"          # all four flags should be true
for b in $(aws s3api list-buckets --query 'Buckets[].Name' --output text); do
  s=$(aws s3api get-bucket-policy-status --bucket "$b" --query PolicyStatus.IsPublic --output text 2>/dev/null)
  [ "$s" = "True" ] && echo "PUBLIC POLICY: $b"
done
aws ec2 describe-snapshots --owner-ids self --restorable-by-user-ids all --query 'Snapshots[].SnapshotId'
aws ec2 describe-images --owners self --executable-users all --query 'Images[].ImageId'
aws rds describe-db-instances --query 'DBInstances[?PubliclyAccessible==`true`].DBInstanceIdentifier'

AWS network exposure (repeat per region):

aws ec2 describe-security-groups \
  --filters Name=ip-permission.cidr,Values=0.0.0.0/0 \
  --query 'SecurityGroups[].{id:GroupId,name:GroupName,ports:IpPermissions[].[FromPort,ToPort,IpProtocol]}'
aws ec2 describe-security-groups --filters Name=ip-permission.ipv6-cidr,Values=::/0 --query 'SecurityGroups[].GroupId'

Flag 0.0.0.0/0 or ::/0 on 22, 3389, database ports (3306, 5432, 1433, 27017, 6379, 9200), and protocol -1 (all traffic). Then check whether the group is attached to anything (aws ec2 describe-network-interfaces --filters Name=group-id,Values=<sg>).

AWS identity:

aws iam get-account-summary --query 'SummaryMap.[AccountMFAEnabled,AccountAccessKeysPresent]'
aws iam generate-credential-report >/dev/null; sleep 5
aws iam get-credential-report --query Content --output text | base64 --decode > cred.csv
# columns to read: password_enabled, mfa_active, access_key_1_last_rotated, access_key_1_last_used_date
aws iam list-policies --scope Local --query 'Policies[].Arn' --output text   # then inspect for "Action":"*","Resource":"*"
aws accessanalyzer list-analyzers

Rank: root access keys present or root without MFA; IAM users with console access and no MFA; access keys older than 90 days or unused for 90 days; customer policies granting *:*; role trust policies that allow any principal or an external account without sts:ExternalId; GitHub OIDC trust without a sub condition pinning repo and branch. Least-privilege rewrites belong to aws-iam.

GCP:

gcloud asset search-all-iam-policies --scope=organizations/<ORG_ID> \
  --query='policy:(allUsers OR allAuthenticatedUsers)' --format='table(resource,policy.bindings.role)'
gcloud compute firewall-rules list --filter='direction=INGRESS AND sourceRanges:0.0.0.0/0' \
  --format='table(name,network,allowed[].map().firewall_rule().list())'
gcloud iam service-accounts keys list --iam-account=<sa-email> --managed-by=user

Also look for primitive roles (roles/owner, roles/editor) granted to users or default compute service accounts.

Azure:

az storage account list --query "[?allowBlobPublicAccess==\`true\`].[name,resourceGroup]" -o table
az graph query -q "Resources | where type =~ 'microsoft.network/networksecuritygroups' | mv-expand r=properties.securityRules | where r.properties.direction=='Inbound' and r.properties.access=='Allow' and r.properties.sourceAddressPrefix in ('*','0.0.0.0/0','Internet') | project name, resourceGroup, port=r.properties.destinationPortRange"
az role assignment list --all --query "[?roleDefinitionName=='Owner'].[principalName,scope]" -o table

5. Triage

PriorityPattern
CriticalPublic read/write on buckets or snapshots holding customer data; admin ports open to the internet on live hosts; root keys in use; active anomalous GuardDuty/SCC findings
HighUsers without MFA holding admin; long-lived keys with broad permissions; cross-account trust to unknown accounts; audit logging disabled
MediumUnused but permissive roles; unencrypted volumes by default; missing GuardDuty in unused regions
LowBenchmark hygiene with no exposure (password policy length, tagging)

Collapse repeats into root causes: 40 open security groups from one Terraform module are one finding with one fix.

6. Remediate and prevent

  • Fix in the IaC source (Terraform, CDK, Pulumi), not the console, or drift reappears on the next apply. Check git log on the resource before assuming it is unintended.
  • Before closing a port or blocking public access, check usage: VPC Flow Logs, S3 server access logs or CloudTrail data events, load balancer logs. Present the evidence and get confirmation.
  • Rotate rather than delete keys in use: create new, deploy, watch last_used, then deactivate, then delete after a wait.
  • Add a guardrail per finding class:
RiskAWSGCPAzure
Public bucketsAccount-level S3 Block Public Access; SCP denying s3:PutAccountPublicAccessBlock changesOrg policy storage.publicAccessPreventionAzure Policy denying allowBlobPublicAccess
Long-lived keysSCP denying iam:CreateAccessKey except break-glass; OIDC for CIOrg policy iam.disableServiceAccountKeyCreationWorkload identity federation; policy on secrets expiry
Region sprawlSCP denying actions outside approved regionsOrg policy gcp.resourceLocationsAllowed locations policy
Drift in PRsCheckov, Trivy config, or tfsec-style scan in CI on IaCsamesame

7. Verify

Re-run the same Prowler command and diff FAIL counts per check; re-run each targeted CLI check for fixed items. Confirm guardrails by attempting the blocked action in a sandbox account (expect AccessDenied) rather than assuming the SCP or org policy applied.

Report template

# Cloud posture audit: <org> (<date>)
**Scope:** <accounts/projects/subscriptions>, regions: <all enabled | list>
**Method:** read-only; Prowler <version> (<frameworks>), native findings, targeted CLI checks
**Not covered:** <workloads inside VMs, Kubernetes in-cluster config, SaaS>

## Summary
| Priority | Findings | Root causes |

## Findings
### [C-1] Customer export bucket readable by anyone (AWS 1234-prod, us-east-1)
**Evidence:** `get-bucket-policy-status` IsPublic=True; policy grants `s3:GetObject` to `*`
**Impact:** <data class, object count>   **Owner:** <team>
**Fix:** remove statement in `terraform/s3_exports.tf`; enable account Block Public Access
**Guardrail:** SCP + Access Analyzer alert on new external access

## Baselines
| Control | Status per account |

## Accepted / intentional exceptions (mutelist)

Gotchas

  • Prowler PASS on “Block Public Access” at the bucket level does not mean the account setting is on; check both.
  • Security groups referencing other groups are not exposure; a load balancer group open to 0.0.0.0/0 on 443 is usually intended. Focus on management and data ports.
  • Credential reports are cached for up to four hours; regenerate before final numbers.
  • GuardDuty, Security Hub, and Access Analyzer are regional on AWS; one disabled region is a blind spot.
  • Prowler and Security Hub both bill API calls or findings in large orgs; scope with --services while iterating.

About this skill

Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.

esc