Install any skill in seconds. Free to start, no credit card required.
Get Started Free →AWS/Azure/GCP security auditing, container and Kubernetes hardening, Infrastructure as Code scanning, and cloud compliance assessment
.claude/skills/masriyan-cloud-security-container-hardening/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 236% | 0% |
| case-21 | ✗→✓ | ▲ Improved | 245% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 92% | 0% |
| case-06 | ✓→✗ | ▼ Worse | 341% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 214% | 0% |
Enable Claude to assist with cloud security assessments across AWS, Azure, and GCP, container and Kubernetes security hardening, Infrastructure as Code (Terraform, CloudFormation, Kubernetes manifests) scanning, and cloud compliance reporting against CIS Benchmarks and major frameworks.
This skill activates when the user asks about:
bashpip install pyyaml boto3 requests
Recommended cloud security tools:
AWS CLI — AWS auditing and managementScoutSuite — Multi-cloud security auditProwler — AWS/Azure/GCP security assessmentCheckov — IaC static analysistfsec — Terraform security scannerTrivy — Container and IaC vulnerability scannerkube-bench — CIS Kubernetes BenchmarkFalco — Container runtime securityWhen the user asks to audit AWS security:
Quick AWS security checks using CLI:
bash# IAM: Find users without MFA aws iam get-account-summary aws iam list-users | jq '.Users[].UserName' | xargs -I{} aws iam list-mfa-devices --user-name {} # Find overly permissive policies aws iam list-policies --scope Local --only-attached | jq '.Policies[].PolicyName' # S3: Find public buckets aws s3api list-buckets --query 'Buckets[].Name' | xargs -I{} aws s3api get-bucket-acl --bucket {} aws s3api list-buckets --query 'Buckets[].Name' | xargs -I{} aws s3api get-bucket-policy-status --bucket {} # Security groups: Find wide-open rules aws ec2 describe-security-groups --filters "Name=ip-permission.cidr,Values=0.0.0.0/0" \ --query 'SecurityGroups[*].{ID:GroupId,Name:GroupName,Rules:IpPermissions}' # CloudTrail: Verify logging aws cloudtrail describe-trails aws cloudtrail get-trail-status --name [trail-name] # Root account check aws iam get-account-summary --query 'SummaryMap.AccountMFAEnabled'
AWS IAM Security Checklist:
Identity & Access Management:
[ ] Root account has MFA enabled
[ ] Root account has no access keys
[ ] All IAM users have MFA enabled
[ ] No IAM users with AdministratorAccess unless necessary
[ ] All IAM users have individual credentials (no shared)
[ ] Password policy: min 14 chars, complexity, rotation ≤90 days
[ ] Access keys rotated every 90 days
[ ] Unused credentials disabled (>90 days no use)
[ ] No inline policies; use managed policies
S3 Security:
[ ] Block Public Access enabled at account level
[ ] No buckets with public READ ACL
[ ] Server-side encryption enabled (SSE-S3 or SSE-KMS)
[ ] Versioning enabled for critical buckets
[ ] MFA Delete enabled for critical buckets
[ ] Access logging enabled
[ ] Bucket policies use HTTPS-only conditions
Networking:
[ ] No security groups with 0.0.0.0/0 → port 22 (SSH)
[ ] No security groups with 0.0.0.0/0 → port 3389 (RDP)
[ ] VPC Flow Logs enabled
[ ] No default VPC in use for production workloads
[ ] Private subnets for database and application tiers
Monitoring & Detection:
[ ] CloudTrail enabled in all regions
[ ] CloudTrail log file integrity validation enabled
[ ] GuardDuty enabled
[ ] Security Hub enabled and findings reviewed
[ ] Config rules configured for compliance
[ ] CloudWatch alarms for: root login, failed auth, security group changesCritical AWS Finding Templates:
markdown**CRITICAL: S3 Bucket Publicly Readable** Bucket: example-data-prod Finding: GetBucketAcl returns AllUsers:READ Risk: All objects publicly readable — potential data breach Fix: aws s3api put-bucket-acl --bucket example-data-prod --acl private Enable: aws s3api put-public-access-block --bucket example-data-prod \ --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true **HIGH: Security Group Allows SSH from Internet** Group: sg-0abc123 (web-servers) Rule: Inbound TCP 22 from 0.0.0.0/0 Risk: SSH brute-force, CVE exploitation Fix: Change source from 0.0.0.0/0 to your VPN/bastion host IP
When the user asks to audit Azure:
bash# Login and set subscription az login az account set --subscription [subscription-id] # Check RBAC assignments az role assignment list --all --include-inherited \ --query "[?roleDefinitionName=='Owner' || roleDefinitionName=='Contributor'].{Name:principalName,Role:roleDefinitionName}" # Storage account public access az storage account list --query "[?allowBlobPublicAccess==true].name" # NSG rules allowing any source az network nsg list --query "[*].{NSG:name}" | jq '.[].NSG' | xargs -I{} \ az network nsg rule list --nsg-name {} --resource-group [rg] \ --query "[?sourceAddressPrefix=='*'].{Rule:name,Port:destinationPortRange}" # Key Vault access policies az keyvault list --query "[*].name" | xargs -I{} az keyvault show --name {} \ --query 'properties.accessPolicies'
Azure Security Checklist:
Identity:
[ ] Global Administrator role has MFA
[ ] No more than 3-5 Global Administrators
[ ] Privileged Identity Management (PIM) for elevated roles
[ ] Guest accounts reviewed quarterly
[ ] Legacy authentication blocked (Conditional Access)
Storage:
[ ] No public blob containers (allowBlobPublicAccess = false)
[ ] Secure transfer required (HTTPS only)
[ ] Storage accounts use private endpoints
[ ] Storage logs enabled (read/write/delete)
[ ] Customer-managed keys for sensitive data
Networking:
[ ] NSGs restrict management ports (22, 3389) from internet
[ ] Azure DDoS Protection enabled
[ ] Network Watcher flow logs enabled
Monitoring:
[ ] Azure Monitor Diagnostic Settings for all resources
[ ] Security Center (Defender for Cloud) enabled
[ ] Log Analytics Workspace connected
[ ] Alerts for privileged role assignmentsWhen the user asks to review a Dockerfile or container security:
Claude reads and analyzes the Dockerfile directly:
Dockerfile Security Review:
dockerfile# BEFORE (insecure) FROM ubuntu:latest # ← Never use latest RUN apt-get install -y curl # ← Install what you need during build COPY . . # ← Copies everything including .env files RUN chmod 777 /app # ← World-writable is dangerous CMD ["./app"] # ← Runs as root by default EXPOSE 0-65535 # ← Never expose all ports # AFTER (secure) FROM ubuntu:24.04 AS builder # Pin specific version RUN apt-get update && apt-get install -y --no-install-recommends curl \ && rm -rf /var/lib/apt/lists/* # Clean up after install WORKDIR /app FROM ubuntu:24.04 AS runtime # Multi-stage: minimal runtime image WORKDIR /app COPY --from=builder /app/bin/myapp ./ # Only copy what's needed RUN groupadd -r appgroup && useradd -r -g appgroup appuser RUN chown -R appuser:appgroup /app USER appuser # Non-root user EXPOSE 8080 # Only expose necessary port HEALTHCHECK --interval=30s --timeout=3s \ CMD curl -f http://localhost:8080/health || exit 1 CMD ["./myapp"]
Dockerfile Audit Checklist:
[ ] Base image version pinned (not latest)
[ ] Multi-stage build used to minimize final image
[ ] Runs as non-root user (USER instruction)
[ ] No COPY . . (copies .env, secrets)
[ ] .dockerignore exists and excludes .env, *.key, secrets/
[ ] Package caches cleaned after installation (rm -rf /var/lib/apt/lists/*)
[ ] No RUN commands with passwords, tokens, or secrets
[ ] HEALTHCHECK defined
[ ] Only necessary ports EXPOSE'd
[ ] Read-only filesystem where possible
[ ] No setuid/setgid binaries in final imageContainer image scanning:
bash# Scan with Trivy trivy image myapp:latest --severity HIGH,CRITICAL trivy image myapp:latest --format json --output scan-results.json # Docker bench security (runtime checks) docker run --rm --net host --pid host --userns host --cap-add audit_control \ -v /etc:/etc:ro -v /usr/bin/containerd:/usr/bin/containerd:ro \ -v /usr/bin/runc:/usr/bin/runc:ro \ -v /usr/lib/systemd:/usr/lib/systemd:ro \ -v /var/lib:/var/lib:ro -v /var/run/docker.sock:/var/run/docker.sock:ro \ docker/docker-bench-security
When the user asks to audit Kubernetes security:
bash# Run CIS Kubernetes Benchmark docker run --pid=host -v /etc:/etc:ro -v /var/lib:/var/lib:ro \ -v /usr/bin/kubelet:/usr/bin/kubelet:ro \ aquasec/kube-bench:latest # Check for privileged pods kubectl get pods --all-namespaces -o json | \ jq '.items[] | select(.spec.containers[].securityContext.privileged==true) | .metadata.name + " in " + .metadata.namespace' # Check RBAC for overly permissive ClusterRoles kubectl get clusterrolebindings -o json | \ jq '.items[] | select(.roleRef.name=="cluster-admin") | .subjects[]?' # Check for pods running as root kubectl get pods --all-namespaces -o json | \ jq '.items[] | select(.spec.securityContext.runAsUser==0 or .spec.containers[].securityContext.runAsUser==0) | .metadata.name'
Secure Pod Spec Template:
yamlapiVersion: v1 kind: Pod metadata: name: secure-app spec: securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 2000 seccompProfile: type: RuntimeDefault automountServiceAccountToken: false # Disable unless needed containers: - name: app image: myapp:v1.2.3@sha256:abc123 # Pin by digest securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsNonRoot: true capabilities: drop: - ALL # Drop ALL capabilities add: - NET_BIND_SERVICE # Add back only what's needed resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" # Always set limits cpu: "500m" volumeMounts: - name: tmp mountPath: /tmp # Writable volume for /tmp if needed volumes: - name: tmp emptyDir: {}
Kubernetes Security Checklist:
RBAC:
[ ] No wildcards (*) in ClusterRole rules
[ ] cluster-admin role not assigned to service accounts
[ ] Each workload uses a dedicated service account
[ ] ServiceAccount token auto-mount disabled by default
Pod Security:
[ ] All pods have securityContext defined
[ ] runAsNonRoot: true for all containers
[ ] allowPrivilegeEscalation: false
[ ] readOnlyRootFilesystem: true where possible
[ ] capabilities: drop: [ALL]
[ ] No hostPID, hostIPC, hostNetwork
[ ] No privileged: true
Networking:
[ ] Default deny NetworkPolicy in all namespaces
[ ] Only required pod-to-pod communication allowed
[ ] Egress restricted (not just ingress)
Secrets Management:
[ ] No secrets in environment variables (use mounted secrets or vault)
[ ] No secrets in ConfigMaps
[ ] External secrets management (Vault, AWS SSM, Azure Key Vault)
[ ] ETCD encryption at rest enabled
Image Security:
[ ] All images from private registry (not Docker Hub public)
[ ] Image digest pinning (not mutable tags)
[ ] Admission controller (OPA, Kyverno) enforcing policy
[ ] Image scanning in CI/CD pipelineWhen the user asks to scan Terraform or CloudFormation:
Claude reads the IaC files directly and identifies issues:
Common Terraform Misconfigurations:
hcl# INSECURE: S3 bucket with public access resource "aws_s3_bucket" "bad" { bucket = "my-bucket" acl = "public-read" # ← PUBLIC READ! } # SECURE: S3 bucket with all public access blocked resource "aws_s3_bucket" "good" { bucket = "my-bucket" } resource "aws_s3_bucket_public_access_block" "good" { bucket = aws_s3_bucket.good.id block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true } # INSECURE: Security group allows all inbound resource "aws_security_group_rule" "bad" { type = "ingress" from_port = 0 to_port = 65535 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] # ← OPEN TO INTERNET! }
Automated IaC scanning:
bash# Checkov (Terraform, CloudFormation, K8s, Dockerfile) checkov -d ./terraform/ --framework terraform --output json > checkov-results.json checkov -d ./k8s-manifests/ --framework kubernetes # tfsec (Terraform focused) tfsec ./terraform/ --format json --out tfsec-results.json # Trivy (IaC, container, filesystem) trivy config ./terraform/ trivy config ./k8s-manifests/ # Use iac_scanner.py python scripts/iac_scanner.py --path ./terraform/ --output findings.json python scripts/iac_scanner.py --path ./k8s-manifests/ --type kubernetes --output k8s_audit.json
| Finding | CIS AWS | SOC2 | PCI-DSS | HIPAA | |---------|---------|------|---------|-------| | MFA not enforced | 1.10, 1.14 | CC6.1 | 8.3.2 | 164.312(d) | | Public S3 bucket | 2.1.5 | CC6.7 | 3.4 | 164.312(a)(2)(iv) | | CloudTrail disabled | 3.1, 3.2 | CC7.2 | 10.2 | 164.312(b) | | SSH open to internet | 5.2 | CC6.6 | 1.2.1 | 164.312(e)(1) | | Root account used | 1.7 | CC6.1 | 7.1.1 | 164.308(a)(1) |
iac_scanner.pybashpython scripts/iac_scanner.py --path ./terraform/ --output findings.json python scripts/iac_scanner.py --path ./k8s-manifests/ --type kubernetes --output k8s_audit.json
| Condition | Adjacent Skill | |-----------|---------------| | Cloud assets discovered via recon | ← Skill 01 (Recon & OSINT) | | Cloud vulnerabilities for CSOC alerts | → Skill 11 (CSOC Automation) | | Implement cloud hardening recommendations | → Skill 15 (Blue Team Defense) |
Attack-path-driven cloud security:
iam:PassRole, wildcard actions, cross-account trust, OIDC federation to CI/CD). Think in attack paths (CNAPP/CSPM-style), not isolated misconfigs.Precision rule: report each finding as misconfig → reachable identity/data → blast radius, with the exact CLI/IaC fix.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 10,433 | 18,206 | +75% | 1 | 1 | 0% | 1,873 | 5,890 | +214% | 0 | 0 | — |
case-07 | fail→pass | 12,480 | 14,863 | +19% | 1 | 1 | 0% | 2,085 | 6,997 | +236% | 0 | 0 | — |
case-21 | fail→pass | 10,701 | 8,495 | -21% | 1 | 1 | 0% | 1,745 | 6,016 | +245% | 0 | 0 | — |
case-02 | pass→pass | 9,280 | 8,662 | -7% | 1 | 1 | 0% | 1,843 | 6,264 | +240% | 0 | 0 | — |
case-03 | pass→pass | 17,137 | 16,287 | -5% | 1 | 1 | 0% | 2,777 | 7,261 | +161% | 0 | 0 | — |
case-04 | pass→pass | 11,852 | 6,545 | -45% | 1 | 1 | 0% | 2,006 | 5,771 | +188% | 0 | 0 | — |
case-05 | pass→pass | 11,577 | 8,218 | -29% | 1 | 1 | 0% | 1,899 | 6,044 | +218% | 0 | 0 | — |
case-06 | pass→fail | 8,971 | 10,400 | +16% | 1 | 1 | 0% | 1,426 | 6,287 | +341% | 0 | 0 | — |
case-08 | pass→pass | 8,168 | 5,746 | -30% | 1 | 1 | 0% | 1,474 | 5,665 | +284% | 0 | 0 | — |
case-09 | pass→pass | 9,031 | 11,739 | +30% | 1 | 1 | 0% | 1,577 | 6,823 | +333% | 0 | 0 | — |
case-10 | pass→pass | 2,531 | 5,367 | +112% | 1 | 1 | 0% | 382 | 5,421 | +1319% | 0 | 0 | — |
case-11 | pass→pass | 6,467 | 8,004 | +24% | 1 | 1 | 0% | 1,186 | 6,068 | +412% | 0 | 0 | — |
case-12 | pass→pass | 5,042 | 5,752 | +14% | 1 | 1 | 0% | 921 | 5,605 | +509% | 0 | 0 | — |
case-13 | pass→pass | 10,085 | 6,223 | -38% | 1 | 1 | 0% | 1,716 | 5,648 | +229% | 0 | 0 | — |
case-14 | pass→pass | 4,887 | 6,304 | +29% | 1 | 1 | 0% | 924 | 5,780 | +526% | 0 | 0 | — |
case-15 | pass→pass | 7,981 | 6,602 | -17% | 1 | 1 | 0% | 1,382 | 5,615 | +306% | 0 | 0 | — |
case-16 | pass→pass | 10,622 | 10,845 | +2% | 1 | 1 | 0% | 1,646 | 6,321 | +284% | 0 | 0 | — |
case-17 | pass→pass | 8,627 | 9,505 | +10% | 1 | 1 | 0% | 1,678 | 6,270 | +274% | 0 | 0 | — |
case-18 | fail→pass | 14,451 | 1,932 | -87% | 1 | 1 | 0% | 2,529 | 4,867 | +92% | 0 | 0 | — |
case-19 | pass→pass | 12,610 | 14,375 | +14% | 1 | 1 | 0% | 2,271 | 7,065 | +211% | 0 | 0 | — |
case-20 | pass→pass | 10,709 | 8,669 | -19% | 1 | 1 | 0% | 1,995 | 6,070 | +204% | 0 | 0 | — |
case-22 | pass→pass | 12,476 | 16,034 | +29% | 1 | 1 | 0% | 2,098 | 7,234 | +245% | 0 | 0 | — |
case-23 | pass→pass | 3,304 | 5,531 | +67% | 1 | 1 | 0% | 605 | 5,563 | +820% | 0 | 0 | — |
case-24 | pass→pass | 6,416 | 5,611 | -13% | 1 | 1 | 0% | 1,192 | 5,532 | +364% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +8 percentage points is the difference between those two pass rates over the 24 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.