> ## Documentation Index
> Fetch the complete documentation index at: https://community.rifteo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloud Audit

> AWS, Azure, and GCP security audit — IAM, storage exposure, networking, secrets, encryption, logging, and compliance.

<Info>
  **Category:** Audit
</Info>

**Load this context**

Ask your agent:

```
get the cloud-audit context
```

***

## Summary

A cloud security audit methodology covering AWS, Azure, and GCP across 13 phases — from pre-engagement scoping to final reporting.

* Phase 1 covers pre-engagement setup: confirming scope, access level, and verifying tooling connectivity across AWS, Azure, and GCP
* Phase 2 reviews IAM: wildcard permissions, unused access keys, MFA enforcement, cross-account trust relationships, overly permissive roles on compute, Owner/Contributor assignments (Azure), and primitive roles on GCP service accounts
* Phase 3 checks storage exposure: public S3 buckets, Azure Blob containers with public access, and GCS buckets with `allUsers` or `allAuthenticatedUsers` bindings
* Phase 4 audits network security: security groups open to `0.0.0.0/0`, VPC flow logs, NACLs, publicly accessible RDS/OpenSearch instances, NSG rules (Azure), and open firewall rules (GCP)
* Phase 5 verifies encryption: unencrypted EBS volumes, RDS instances, managed disks, KMS key rotation, CloudFront HTTPS enforcement, and CMEK coverage on GCP
* Phase 6 reviews logging and monitoring: CloudTrail multi-region coverage, GuardDuty, Security Hub, Azure Monitor diagnostic settings, Microsoft Defender for Cloud, and GCP Cloud Audit Logs
* Phase 7 covers secrets management: hardcoded secrets in Lambda/Cloud Functions env vars, EC2 user data, SSM Parameter Store, CloudFormation outputs, and Key Vault expiry
* Phase 8 audits compute and containers: IMDSv1 on EC2, EKS public endpoints, privileged ECS tasks, Kubernetes RBAC cluster-admin bindings, root pods, and missing resource limits
* Phase 9 reviews serverless and PaaS: public Lambda policies, deprecated runtimes, App Service authentication, Cloud Run public access
* Phase 10 maps all findings to CIS Benchmarks, ISO 27001, SOC 2, and PCI-DSS
* Phases 11–13 enforce a validation gate, false positive filter, and structured per-finding reporting with severity guidance

***

## CONTEXT.md

### When to Use This Context

Load this context when:

* Auditing AWS, Azure, or GCP environments
* Reviewing IAM policies, roles, and permissions for least-privilege violations
* Checking for publicly exposed storage (S3, Azure Blob, GCS)
* Assessing network security groups, firewall rules, and VPC configurations
* Reviewing encryption posture at rest and in transit
* Assessing logging, monitoring, and incident response readiness
* Identifying hardcoded secrets in compute, serverless, and pipeline configs
* Mapping findings to CIS Benchmarks, ISO 27001, SOC 2, or PCI-DSS

**Key focus areas:** IAM least privilege, public exposure, encryption at rest/transit, logging gaps, network segmentation, secrets management, container security, serverless misconfigurations, compliance mapping.

**Out of scope:** Application-layer vulnerabilities (use `web-app-pentest` or `api-security-review`), OS-level exploitation, social engineering.

***

### Phase 1 — Pre-Engagement & Scoping

Before any active enumeration, establish scope and access level:

* Confirm which cloud accounts/subscriptions/projects are in scope
* Confirm access level: read-only auditor role, or broader permissions?
* Document the engagement type: configuration review only, or active exploitation allowed?
* Collect cloud account IDs, organization structure, and environment names (prod/staging/dev)
* Verify that audit logging is capturing your own activity (to avoid surprises for the client)

```bash theme={"system"}
# AWS — verify caller identity before anything else
aws sts get-caller-identity

# Azure — confirm active subscription
az account show
az account list --output table

# GCP — confirm active project
gcloud config list
gcloud projects list
```

***

### Phase 2 — IAM & Identity Review

This is the highest-priority phase. IAM misconfigurations are the root cause of most cloud breaches.

#### AWS IAM

```bash theme={"system"}
# Full account authorization details — users, groups, roles, policies
aws iam get-account-authorization-details --output json > iam_details.json

# List all IAM users, roles, and customer-managed policies
aws iam list-users --output table
aws iam list-roles --output table
aws iam list-policies --scope Local --output table

# Generate credential report (access key age, MFA status, password last used)
aws iam generate-credential-report
aws iam get-credential-report --output text --query Content | base64 -d > credential_report.csv
```

**Check for wildcard permissions (`*`):**

```bash theme={"system"}
aws iam get-account-authorization-details | \
  python3 -c "
import json, sys
data = json.load(sys.stdin)
for policy in data.get('Policies', []):
    for version in policy.get('PolicyVersionList', []):
        if version.get('IsDefaultVersion'):
            doc = version['Document']
            stmts = doc.get('Statement', [])
            if isinstance(stmts, dict): stmts = [stmts]
            for s in stmts:
                actions = s.get('Action', [])
                resources = s.get('Resource', [])
                if '*' in actions or '*' in resources:
                    print(f\"[WILDCARD] Policy: {policy['PolicyName']}\")
"
```

**MFA enforcement:**

```bash theme={"system"}
# Check root MFA
aws iam get-account-summary | grep -i mfa

# Users with console access but no MFA
aws iam list-users --output json | \
  python3 -c "
import json, sys, subprocess
users = json.load(sys.stdin)['Users']
for u in users:
    mfa = json.loads(subprocess.check_output(['aws','iam','list-mfa-devices','--user-name',u['UserName']]))
    if not mfa['MFADevices']:
        print(f\"[NO MFA] {u['UserName']}\")
"
```

**Unused access keys (>90 days):**

```bash theme={"system"}
awk -F',' 'NR>1 && $11 != "N/A" && $11 != "no_information" {
  cmd = "date -d \""$11"\" +%s"; cmd | getline key_ts; close(cmd)
  now = systime()
  diff = (now - key_ts) / 86400
  if (diff > 90) print "[STALE KEY] User: "$1" Key1 last used: "$11" ("int(diff)" days ago)"
}' credential_report.csv
```

**Cross-account trust relationships:**

```bash theme={"system"}
aws iam list-roles --output json | python3 -c "
import json, sys
roles = json.load(sys.stdin)['Roles']
account_id = '<YOUR_ACCOUNT_ID>'
for r in roles:
    policy = r['AssumeRolePolicyDocument']
    stmts = policy.get('Statement', [])
    for s in stmts:
        principal = s.get('Principal', {})
        aws = principal.get('AWS', '') if isinstance(principal, dict) else str(principal)
        if isinstance(aws, list): aws = ' '.join(aws)
        if aws and account_id not in aws and aws != '*':
            print(f\"[CROSS-ACCOUNT TRUST] Role: {r['RoleName']} → {aws}\")
        elif aws == '*':
            print(f\"[PUBLIC TRUST] Role: {r['RoleName']} → Anyone!\")
"
```

**Password policy:**

```bash theme={"system"}
aws iam get-account-password-policy
# Check: MinimumPasswordLength >= 14, RequireUppercase, RequireLowercase,
#         RequireNumbers, RequireSymbols, MaxPasswordAge <= 90,
#         PasswordReusePrevention >= 24
```

#### Azure IAM

```bash theme={"system"}
# List all role assignments and flag high-privilege ones
az role assignment list --all | \
  python3 -c "
import json, sys
assignments = json.load(sys.stdin)
high_priv = ['Owner','Contributor','User Access Administrator']
for a in assignments:
    if a['roleDefinitionName'] in high_priv:
        print(f\"[HIGH PRIV] {a['roleDefinitionName']} → {a['principalName']} ({a['principalType']}) on {a['scope']}\")
"

# Check for external/guest users with elevated roles
az ad user list --filter "userType eq 'Guest'" --output table

# Check Privileged Identity Management (PIM) — are privileged roles time-bound?
az rest --method GET \
  --url "https://management.azure.com/subscriptions/<SUB_ID>/providers/Microsoft.Authorization/roleEligibilitySchedules?api-version=2020-10-01"

# List custom role definitions
az role definition list --custom-role-only true --output table
```

#### GCP IAM

```bash theme={"system"}
# List all IAM bindings — flag primitive roles and public bindings
gcloud projects get-iam-policy <PROJECT_ID> --format=json > gcp_iam.json

python3 -c "
import json
with open('gcp_iam.json') as f:
    policy = json.load(f)
primitive = ['roles/owner','roles/editor','roles/viewer']
for b in policy.get('bindings', []):
    for m in b['members']:
        if b['role'] in primitive:
            print(f\"[PRIMITIVE ROLE] {b['role']} → {m}\")
        if m in ['allUsers', 'allAuthenticatedUsers']:
            print(f\"[PUBLIC BINDING] {b['role']} → {m}\")
"

# Check service account key age (flag keys older than 90 days)
gcloud iam service-accounts list --format="value(email)" | while read sa; do
  gcloud iam service-accounts keys list --iam-account="$sa" \
    --format="table(name,validAfterTime,keyType)" 2>/dev/null
done
```

***

### Phase 3 — Storage Exposure

Publicly readable or writable storage is one of the most common and severe cloud misconfigurations.

#### AWS S3

```bash theme={"system"}
# Check public access block settings on every bucket
for bucket in $(aws s3api list-buckets --query 'Buckets[*].Name' --output text); do
  echo "=== $bucket ==="
  aws s3api get-public-access-block --bucket "$bucket" 2>/dev/null || \
    echo "[WARNING] No public access block configured"
done

# Check bucket policy for Principal: "*"
aws s3api get-bucket-policy --bucket <BUCKET_NAME> 2>/dev/null | \
  python3 -c "
import json, sys
policy = json.loads(json.load(sys.stdin)['Policy'])
for s in policy.get('Statement', []):
    p = s.get('Principal', '')
    if p == '*' or (isinstance(p, dict) and p.get('AWS') == '*'):
        print(f\"[PUBLIC POLICY] Effect: {s['Effect']}, Action: {s.get('Action')}\")
"

# Check encryption, versioning, and logging
aws s3api get-bucket-encryption --bucket <BUCKET_NAME> 2>/dev/null || \
  echo "[NO ENCRYPTION] Bucket has no default encryption"
aws s3api get-bucket-versioning --bucket <BUCKET_NAME>
aws s3api get-bucket-logging --bucket <BUCKET_NAME>
```

#### Azure Blob Storage

```bash theme={"system"}
# Flag storage accounts with public blob access enabled
az storage account list | python3 -c "
import json, sys
accounts = json.load(sys.stdin)
for a in accounts:
    if a.get('allowBlobPublicAccess', True):
        print(f\"[PUBLIC BLOB] {a['name']} in {a['resourceGroup']}\")
"

# Check minimum TLS version and HTTPS enforcement
az storage account list --query "[?enableHttpsTrafficOnly==\`false\`].[name,resourceGroup]" --output table
az storage account list --query "[?minimumTlsVersion!='TLS1_2'].[name,minimumTlsVersion]" --output table
```

#### GCP Cloud Storage

```bash theme={"system"}
# Check IAM policy on each bucket for public bindings
for bucket in $(gsutil ls); do
  echo "=== $bucket ==="
  gsutil iam get "$bucket" | python3 -c "
import json, sys
policy = json.load(sys.stdin)
for b in policy.get('bindings', []):
    for m in b['members']:
        if m in ['allUsers', 'allAuthenticatedUsers']:
            print(f\"[PUBLIC] Role: {b['role']} → {m}\")
"
done

# Check uniform bucket-level access (disables legacy ACLs)
gsutil uniformbucketlevelaccess get gs://<BUCKET_NAME>
```

***

### Phase 4 — Network Security

#### AWS

```bash theme={"system"}
# Security groups open to the world on sensitive ports
aws ec2 describe-security-groups --output json | python3 -c "
import json, sys
sgs = json.load(sys.stdin)['SecurityGroups']
sensitive_ports = [22, 3389, 1433, 3306, 5432, 27017, 6379, 9200, 8080, 8443]
for sg in sgs:
    for rule in sg.get('IpPermissions', []):
        from_port = rule.get('FromPort', 0)
        to_port = rule.get('ToPort', 65535)
        for cidr in rule.get('IpRanges', []):
            if cidr['CidrIp'] == '0.0.0.0/0':
                for p in sensitive_ports:
                    if from_port <= p <= to_port:
                        print(f\"[OPEN TO WORLD] SG: {sg['GroupId']} ({sg['GroupName']}) Port: {p}\")
        for cidr in rule.get('Ipv6Ranges', []):
            if cidr['CidrIpv6'] == '::/0':
                for p in sensitive_ports:
                    if from_port <= p <= to_port:
                        print(f\"[OPEN TO WORLD IPv6] SG: {sg['GroupId']} Port: {p}\")
"

# VPC Flow Logs — check every VPC
aws ec2 describe-vpcs --query 'Vpcs[*].VpcId' --output text | tr '\t' '\n' | while read vpc; do
  logs=$(aws ec2 describe-flow-logs --filter "Name=resource-id,Values=$vpc" --query 'FlowLogs[*].FlowLogId' --output text)
  [ -z "$logs" ] && echo "[NO FLOW LOGS] VPC: $vpc"
done

# Publicly accessible RDS instances
aws rds describe-db-instances --query \
  'DBInstances[*].[DBInstanceIdentifier,PubliclyAccessible,DBSubnetGroup.VpcId]' \
  --output table

# OpenSearch domains — check endpoint and access policies
aws opensearch list-domain-names --output text --query 'DomainNames[*].DomainName' | \
  tr '\t' '\n' | while read domain; do
    aws opensearch describe-domain --domain-name "$domain" \
      --query 'DomainStatus.[DomainName,Endpoint,AccessPolicies]' --output text
done

# Check for default VPCs (should be deleted in prod)
aws ec2 describe-vpcs --filters "Name=is-default,Values=true" --output table
```

#### Azure

```bash theme={"system"}
# NSG rules allowing any source to any port
az network nsg list --query '[*].name' --output tsv | while read nsg; do
  rg=$(az network nsg show --name "$nsg" --query resourceGroup --output tsv 2>/dev/null)
  az network nsg rule list --nsg-name "$nsg" --resource-group "$rg" \
    --query "[?access=='Allow' && sourceAddressPrefix=='*'].[name,destinationPortRange,direction]" \
    --output table 2>/dev/null | grep -v "^$" | awk -v n="$nsg" '{print "[NSG OPEN] " n ": " $0}'
done

# VMs with public IPs
az vm list-ip-addresses --output table

# Azure Bastion and Firewall deployment status
az network bastion list --output table
az network firewall list --output table
```

#### GCP

```bash theme={"system"}
# Firewall rules open to 0.0.0.0/0
gcloud compute firewall-rules list --format=json | python3 -c "
import json, sys
rules = json.load(sys.stdin)
for r in rules:
    if '0.0.0.0/0' in r.get('sourceRanges', []):
        for allow in r.get('allowed', []):
            ports = allow.get('ports', ['ALL'])
            print(f\"[OPEN TO WORLD] Rule: {r['name']} Proto: {allow['IPProtocol']} Ports: {ports}\")
"

# Subnets without VPC Flow Logs
gcloud compute networks subnets list --format=json | python3 -c "
import json, sys
subnets = json.load(sys.stdin)
for s in subnets:
    if not s.get('enableFlowLogs', False):
        print(f\"[NO FLOW LOGS] Subnet: {s['name']} in {s['region']}\")
"

# Check for default network (should be deleted)
gcloud compute networks list --filter="name=default"
```

***

### Phase 5 — Encryption & Data Protection

#### AWS

```bash theme={"system"}
# Unencrypted EBS volumes
aws ec2 describe-volumes \
  --query 'Volumes[?Encrypted==`false`].[VolumeId,State,Size]' \
  --output table

# Default EBS encryption status
aws ec2 get-ebs-encryption-by-default

# Unencrypted RDS instances
aws rds describe-db-instances \
  --query 'DBInstances[?StorageEncrypted==`false`].[DBInstanceIdentifier,DBInstanceClass]' \
  --output table

# KMS keys without rotation enabled
aws kms list-keys --output text --query 'Keys[*].KeyId' | tr '\t' '\n' | while read key; do
  rotation=$(aws kms get-key-rotation-status --key-id "$key" --query RotationEnabled --output text)
  [ "$rotation" = "False" ] && echo "[NO ROTATION] KMS Key: $key"
done

# Secrets Manager secrets with no rotation
aws secretsmanager list-secrets --output json | python3 -c "
import json, sys
secrets = json.load(sys.stdin)['SecretList']
for s in secrets:
    if not s.get('RotationEnabled', False):
        print(f\"[NO ROTATION] Secret: {s['Name']}\")
"

# CloudFront distributions allowing HTTP
aws cloudfront list-distributions --query \
  'DistributionList.Items[?DefaultCacheBehavior.ViewerProtocolPolicy==`allow-all`].[Id,DomainName]' \
  --output table
```

#### Azure

```bash theme={"system"}
# Unencrypted managed disks
az disk list --query "[?encryptionSettingsCollection.enabled!=\`true\`].[name,resourceGroup]" --output table

# Azure SQL databases with TDE disabled
az sql db list --server <SERVER> --resource-group <RG> \
  --query "[?transparentDataEncryption.status!='Enabled'].[name]" --output table

# Storage accounts not using customer-managed keys
az storage account list \
  --query "[?encryption.keySource!='Microsoft.Keyvault'].[name,encryption.keySource]" \
  --output table
```

#### GCP

```bash theme={"system"}
# Disks without CMEK
gcloud compute disks list --format=json | python3 -c "
import json, sys
disks = json.load(sys.stdin)
for d in disks:
    if not d.get('diskEncryptionKey', {}).get('kmsKeyName'):
        print(f\"[NO CMEK] Disk: {d['name']}\")
"

# Cloud SQL instances not requiring SSL
gcloud sql instances list --format=json | python3 -c "
import json, sys
instances = json.load(sys.stdin)
for i in instances:
    ssl = i.get('settings', {}).get('ipConfiguration', {}).get('requireSsl', False)
    if not ssl:
        print(f\"[NO SSL REQUIRED] SQL Instance: {i['name']}\")
"

# KMS key rotation status
gcloud kms keys list --location=global --keyring=<KEYRING> \
  --format="table(name,rotationPeriod,nextRotationTime)"
```

***

### Phase 6 — Logging & Monitoring

Missing or incomplete logging means breaches go undetected.

#### AWS

```bash theme={"system"}
# CloudTrail — multi-region coverage and log file validation
aws cloudtrail describe-trails --include-shadow-trails true --output json | python3 -c "
import json, sys
trails = json.load(sys.stdin)['trailList']
for t in trails:
    print(f\"Trail: {t['Name']} | Multi-region: {t.get('IsMultiRegionTrail')} | Log validation: {t.get('LogFileValidationEnabled')} | S3: {t['S3BucketName']}\")
"

# GuardDuty enabled in every region?
for region in $(aws ec2 describe-regions --query 'Regions[*].RegionName' --output text); do
  status=$(aws guardduty list-detectors --region "$region" --query 'DetectorIds' --output text 2>/dev/null)
  [ -z "$status" ] && echo "[GUARDDUTY DISABLED] Region: $region"
done

# AWS Config and Security Hub
aws configservice describe-configuration-recorders --output table
aws securityhub get-enabled-standards --output table 2>/dev/null || \
  echo "[SECURITY HUB DISABLED]"

# CloudWatch alarms (should cover root login, IAM changes, SG changes, CloudTrail changes)
aws cloudwatch describe-alarms --output table
```

#### Azure

```bash theme={"system"}
# Subscription-level diagnostic settings
az monitor diagnostic-settings subscription list --output table

# Activity Log retention >= 90 days?
az monitor log-profiles list --output json | python3 -c "
import json, sys
profiles = json.load(sys.stdin)
for p in profiles:
    days = p.get('retentionPolicy', {}).get('days', 0)
    enabled = p.get('retentionPolicy', {}).get('enabled', False)
    if not enabled or days < 90:
        print(f\"[SHORT RETENTION] Profile: {p['name']} Days: {days} Enabled: {enabled}\")
"

# Microsoft Defender for Cloud plans
az security pricing list --output table

# Log Analytics workspaces (Microsoft Sentinel is deployed on top of these)
# Confirm Sentinel is enabled via the Azure portal or REST API
az monitor log-analytics workspace list \
  --query "[*].[name,resourceGroup,location,provisioningState]" --output table

# Defender for Cloud alerts
az security alert list --output table
```

#### GCP

```bash theme={"system"}
# Cloud Audit Logs — confirm DATA_READ, DATA_WRITE, ADMIN_READ for critical services
gcloud projects get-iam-policy <PROJECT_ID> --format=json | python3 -c "
import json, sys
policy = json.load(sys.stdin)
for rule in policy.get('auditConfigs', []):
    print(f\"Service: {rule['service']}\")
    for log in rule.get('auditLogConfigs', []):
        print(f\"  Log type: {log['logType']}\")
"

# Cloud Logging export sinks
gcloud logging sinks list --format=table

# Security Command Center
gcloud scc findings list --organization=<ORG_ID> 2>/dev/null || \
  echo "[SCC] Check manually in Cloud Console"

# Alert policies
gcloud monitoring alert-policies list --format=table 2>/dev/null

# Log retention buckets
gcloud logging buckets list --location=global
```

***

### Phase 7 — Secrets Management

Hardcoded or improperly stored secrets are consistently among the top findings in cloud audits.

#### AWS

```bash theme={"system"}
# Lambda environment variables — look for plaintext secrets
aws lambda list-functions --query 'Functions[*].FunctionName' --output text | \
  tr '\t' '\n' | while read fn; do
    env=$(aws lambda get-function-configuration --function-name "$fn" \
      --query 'Environment.Variables' --output json 2>/dev/null)
    echo "$env" | python3 -c "
import json, sys, re
env = json.load(sys.stdin)
if not env: sys.exit()
pattern = re.compile(r'(password|secret|key|token|credential|pwd|passwd|api_key|private)', re.IGNORECASE)
for k in env:
    if pattern.search(k):
        print(f'[PLAINTEXT SECRET] Function env var: {k}')
" 2>/dev/null
done

# SSM parameters stored as String instead of SecureString
aws ssm describe-parameters --output json | python3 -c "
import json, sys, re
params = json.load(sys.stdin)['Parameters']
pattern = re.compile(r'(password|secret|key|token|credential)', re.IGNORECASE)
for p in params:
    if p['Type'] != 'SecureString' and pattern.search(p['Name']):
        print(f\"[UNENCRYPTED PARAM] {p['Name']} (Type: {p['Type']})\")
"

# CloudFormation stack outputs containing secrets
aws cloudformation list-stacks --query \
  'StackSummaries[?StackStatus!=`DELETE_COMPLETE`].StackName' --output text | \
  tr '\t' '\n' | while read stack; do
    aws cloudformation describe-stacks --stack-name "$stack" \
      --query 'Stacks[0].Outputs[*].[OutputKey,OutputValue]' --output text 2>/dev/null | \
      grep -iE '(password|secret|key|token)' | \
      sed "s/^/[STACK OUTPUT SECRET] $stack: /"
done
```

#### Azure

```bash theme={"system"}
# Key Vault secrets expiring within 30 days
az keyvault secret list --vault-name <VAULT_NAME> --output json | python3 -c "
import json, sys
from datetime import datetime, timezone
secrets = json.load(sys.stdin)
now = datetime.now(timezone.utc)
for s in secrets:
    exp = s.get('attributes', {}).get('expires')
    if exp:
        exp_dt = datetime.fromisoformat(exp.replace('Z', '+00:00'))
        days = (exp_dt - now).days
        if days < 30:
            print(f\"[EXPIRING] Secret: {s['id'].split('/')[-1]} Expires in {days} days\")
"

# App Service settings referencing plaintext secrets instead of Key Vault
az webapp config appsettings list --name <APP_NAME> --resource-group <RG> \
  --output json | python3 -c "
import json, sys, re
settings = json.load(sys.stdin)
pattern = re.compile(r'(password|secret|key|token|credential)', re.IGNORECASE)
for s in settings:
    if pattern.search(s['name']) and not s['value'].startswith('@Microsoft.KeyVault'):
        print(f\"[PLAINTEXT SECRET] AppSetting: {s['name']}\")
"
```

#### GCP

```bash theme={"system"}
# Cloud Functions environment variables — look for plaintext secrets
gcloud functions list --format=json | python3 -c "
import json, sys, re
funcs = json.load(sys.stdin)
pattern = re.compile(r'(password|secret|key|token|credential)', re.IGNORECASE)
for f in funcs:
    for k in f.get('environmentVariables', {}):
        if pattern.search(k):
            print(f\"[PLAINTEXT SECRET] Function: {f['name']} EnvVar: {k}\")
"

# Secret Manager inventory
gcloud secrets list --format=table
```

***

### Phase 8 — Compute & Container Security

#### AWS EC2 & ECS/EKS

```bash theme={"system"}
# IMDSv1 enabled — vulnerable to SSRF → metadata credential theft
aws ec2 describe-instances --output json | python3 -c "
import json, sys
for r in json.load(sys.stdin)['Reservations']:
    for i in r['Instances']:
        if i.get('MetadataOptions', {}).get('HttpTokens') != 'required':
            name = next((t['Value'] for t in i.get('Tags', []) if t['Key']=='Name'), i['InstanceId'])
            print(f\"[IMDSv1 ENABLED] {name} ({i['InstanceId']})\")
"

# EKS — public API endpoint exposure
aws eks list-clusters --output text | tr '\t' '\n' | while read cluster; do
  aws eks describe-cluster --name "$cluster" \
    --query 'cluster.resourcesVpcConfig.[endpointPublicAccess,endpointPrivateAccess]' \
    --output text | awk -v c="$cluster" '{print "Cluster: " c " | Public/Private: " $0}'
done

# Privileged ECS task definitions
aws ecs list-task-definitions --output text | tr '\t' '\n' | while read td; do
  privileged=$(aws ecs describe-task-definition --task-definition "$td" \
    --query 'taskDefinition.containerDefinitions[?privileged==`true`].name' \
    --output text 2>/dev/null)
  [ -n "$privileged" ] && echo "[PRIVILEGED CONTAINER] TaskDef: $td Containers: $privileged"
done
```

#### Kubernetes (EKS/AKS/GKE)

```bash theme={"system"}
# cluster-admin bindings — who has full cluster access?
kubectl get clusterrolebindings -o json | python3 -c "
import json, sys
for b in json.load(sys.stdin)['items']:
    if b.get('roleRef', {}).get('name') == 'cluster-admin':
        for s in b.get('subjects', []):
            print(f\"[CLUSTER-ADMIN] {s.get('kind')}: {s.get('name')} ({s.get('namespace', 'cluster-wide')})\")
"

# Pods running as root or unknown UID
kubectl get pods --all-namespaces -o json | python3 -c "
import json, sys
for p in json.load(sys.stdin)['items']:
    ns, name = p['metadata']['namespace'], p['metadata']['name']
    for c in p.get('spec', {}).get('containers', []):
        sc = c.get('securityContext', {})
        psc = p.get('spec', {}).get('securityContext', {})
        run_as = sc.get('runAsUser', psc.get('runAsUser'))
        if run_as == 0 or run_as is None:
            print(f\"[ROOT/UNKNOWN UID] {ns}/{name} container: {c['name']}\")
"

# Privileged containers
kubectl get pods --all-namespaces -o json | python3 -c "
import json, sys
for p in json.load(sys.stdin)['items']:
    ns, name = p['metadata']['namespace'], p['metadata']['name']
    for c in p.get('spec', {}).get('containers', []):
        if c.get('securityContext', {}).get('privileged'):
            print(f\"[PRIVILEGED POD] {ns}/{name} container: {c['name']}\")
"

# Host network/PID/IPC access
kubectl get pods --all-namespaces -o json | python3 -c "
import json, sys
for p in json.load(sys.stdin)['items']:
    ns, name = p['metadata']['namespace'], p['metadata']['name']
    spec = p.get('spec', {})
    if spec.get('hostNetwork'): print(f'[HOST NETWORK] {ns}/{name}')
    if spec.get('hostPID'): print(f'[HOST PID] {ns}/{name}')
    if spec.get('hostIPC'): print(f'[HOST IPC] {ns}/{name}')
"

# Pods without resource limits
kubectl get pods --all-namespaces -o json | python3 -c "
import json, sys
for p in json.load(sys.stdin)['items']:
    ns, name = p['metadata']['namespace'], p['metadata']['name']
    for c in p.get('spec', {}).get('containers', []):
        if not c.get('resources', {}).get('limits'):
            print(f'[NO RESOURCE LIMITS] {ns}/{name} container: {c[\"name\"]}')
"

# Policy enforcement — check PSP, Gatekeeper, or Kyverno
kubectl get psp 2>/dev/null || echo "PSP deprecated — check for Gatekeeper/Kyverno"
kubectl get constrainttemplate 2>/dev/null
kubectl get clusterpolicy 2>/dev/null

# Network policies — is there a default deny?
kubectl get networkpolicies --all-namespaces -o table
```

***

### Phase 9 — Serverless & PaaS Security

#### AWS Lambda

```bash theme={"system"}
# Lambda functions with public resource-based policies
aws lambda list-functions --query 'Functions[*].FunctionName' --output text | \
  tr '\t' '\n' | while read fn; do
    policy=$(aws lambda get-policy --function-name "$fn" --output json 2>/dev/null)
    echo "$policy" | python3 -c "
import json, sys
try:
    p = json.loads(json.load(sys.stdin)['Policy'])
    for s in p.get('Statement', []):
        principal = s.get('Principal', '')
        if principal == '*' or (isinstance(principal, dict) and principal.get('AWS') == '*'):
            print(f'[PUBLIC LAMBDA] Effect={s[\"Effect\"]} Action={s.get(\"Action\")}')
except: pass
" 2>/dev/null
done

# Deprecated Lambda runtimes
aws lambda list-functions --output json | python3 -c "
import json, sys
fns = json.load(sys.stdin)['Functions']
deprecated = {
    'python2.7', 'python3.6', 'python3.7',
    'nodejs10.x', 'nodejs12.x', 'nodejs14.x',
    'dotnetcore2.1', 'dotnetcore3.1',
    'ruby2.5', 'java8'
}
for f in fns:
    runtime = f.get('Runtime', '')
    if runtime in deprecated:
        print(f\"[DEPRECATED RUNTIME] {f['FunctionName']}: {runtime}\")
"
```

#### Azure Functions & App Service

```bash theme={"system"}
# Authentication enabled on App Services?
az webapp list --query "[?httpsOnly==\`false\`].[name,resourceGroup]" --output table
az webapp list --query "[?siteConfig.minTlsVersion!='1.2'].[name,siteConfig.minTlsVersion]" --output table
```

#### GCP Cloud Functions & Cloud Run

```bash theme={"system"}
# Cloud Functions — publicly invokable without auth?
gcloud functions get-iam-policy <FUNCTION_NAME> --region=<REGION> | \
  grep -A2 "allUsers\|allAuthenticatedUsers"

# Cloud Run — ingress policy
gcloud run services list --format=json | python3 -c "
import json, sys
for s in json.load(sys.stdin):
    annotations = s.get('metadata', {}).get('annotations', {})
    print(f\"Service: {s['metadata']['name']} Ingress: {annotations.get('run.googleapis.com/ingress', 'all')}\")
"
```

***

### Phase 10 — Compliance & Benchmark Mapping

For each finding, map to the relevant control:

| Standard                        | Reference                                                                                                                                       |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| CIS AWS Foundations Benchmark   | [https://www.cisecurity.org/benchmark/amazon\_web\_services](https://www.cisecurity.org/benchmark/amazon_web_services)                          |
| CIS Azure Foundations Benchmark | [https://www.cisecurity.org/benchmark/azure](https://www.cisecurity.org/benchmark/azure)                                                        |
| CIS GCP Foundations Benchmark   | [https://www.cisecurity.org/benchmark/google\_cloud\_computing\_platform](https://www.cisecurity.org/benchmark/google_cloud_computing_platform) |
| ISO 27001:2022                  | Annex A controls (A.5–A.8)                                                                                                                      |
| SOC 2 (Type II)                 | Trust Services Criteria (CC6, CC7, CC8, CC9)                                                                                                    |
| PCI-DSS v4.0                    | Requirements 1 (network), 2 (defaults), 7 (access), 8 (identity), 10 (logging)                                                                  |
| NIST CSF                        | Identify / Protect / Detect / Respond / Recover                                                                                                 |

**Common finding mappings:**

| Finding                  | CIS       | ISO    | SOC2  | PCI  |
| ------------------------ | --------- | ------ | ----- | ---- |
| IAM wildcard permissions | AWS 1.16  | A.5.15 | CC6.1 | 7.2  |
| Public S3 bucket         | AWS 2.1.1 | A.8.12 | CC6.6 | 1.3  |
| No MFA on root           | AWS 1.5   | A.5.17 | —     | 8.4  |
| No CloudTrail            | AWS 3.1   | A.8.15 | CC7.2 | 10.2 |
| Unencrypted EBS          | AWS 2.2.1 | A.8.24 | —     | 3.5  |
| SG open to world         | AWS 5.3   | A.8.21 | —     | 1.2  |

***

### Phase 11 — Validation Gate

Before reporting any finding, confirm all of the following:

```
[ ] Reproduced the misconfiguration using CLI/API commands (not just console screenshots)
[ ] Confirmed the resource is actively in use (not a dev/test artifact clearly outside scope)
[ ] Verified the impact is real — e.g. a public S3 bucket actually contains sensitive data
[ ] Evidence captured: full CLI command + output, or console screenshot + URL
[ ] Finding is within agreed scope (account IDs, regions, resource types)
[ ] Cross-checked against the false positive filter below
[ ] Severity is justified — not inflated or deflated
[ ] Compliance mapping is accurate for the specific control version
```

***

### Phase 12 — False Positive Filter

Do not report without further investigation:

* **Public S3 bucket that is intentionally public** — verify it hosts a static website or CDN assets; check the bucket policy for explicit intent
* **Cross-account IAM role with broad permissions** — verify the trusted account is not a legitimate vendor or internal account (e.g. AWS Config, Security Hub service roles)
* **Open port 443/80 on a security group** — web-facing services need these; only report if they expose non-web services (RDP, SSH, DB ports)
* **Primitive GCP roles on Compute Engine service agent** — Google-managed SAs often use Editor; check it is a Google-managed SA before flagging
* **KMS key without auto-rotation** — asymmetric keys do not support auto-rotation; check key type before reporting
* **Lambda without VPC** — only a finding if the Lambda accesses internal VPC resources (RDS, ElastiCache)
* **Missing CloudTrail in a region with no resources** — confirm the region is genuinely unused before flagging
* **Short CloudTrail retention** — check if logs are streamed to a SIEM with longer retention first

***

### Phase 13 — Reporting

Every finding must include:

| Field                        | Content                                                                               |
| ---------------------------- | ------------------------------------------------------------------------------------- |
| **Title**                    | Short, action-oriented (e.g. "S3 Bucket Publicly Readable — Production Data Exposed") |
| **Severity**                 | Critical / High / Medium / Low / Informational                                        |
| **Cloud Provider / Service** | AWS S3, Azure Blob, GCP Cloud Storage, etc.                                           |
| **Affected Resource**        | ARN, resource ID, or full path                                                        |
| **CIS Benchmark Reference**  | Control number and title                                                              |
| **Other Compliance**         | ISO / SOC2 / PCI references                                                           |
| **Steps to Reproduce**       | Exact CLI command and output                                                          |
| **Evidence**                 | Command output or screenshot                                                          |
| **Impact**                   | What an attacker can do if this is exploited                                          |
| **Recommendation**           | Specific remediation step with example config or command                              |

**Severity guidance:**

* **Critical** — Direct data exposure (public bucket with PII/credentials), unauthenticated RCE, complete loss of access control (public trust on IAM role)
* **High** — Wildcard IAM permissions, no MFA on privileged accounts, unencrypted sensitive data at rest, open RDP/SSH to world
* **Medium** — No logging/monitoring, missing rotation policy, IMDSv1 enabled, no flow logs, overly broad service roles
* **Low** — Short password policy, missing optional security features when other controls exist
* **Informational** — Best practice deviations with no direct exploit path

Use the `finding-writer` skill to convert raw notes into structured findings. Use `compliance-gap-analyzer` to aggregate findings into a gap report. Use `pentest-report` to assemble the full engagement deliverable.

***

## Related contexts

<CardGroup cols={2}>
  <Card title="web-app-pentest" href="/contexts/web-app-pentest">
    Full web application pentest methodology: recon, auth, injection, business logic

    `Rifteo-Community/contexts`
  </Card>

  <Card title="code-audit" href="/contexts/code-audit">
    Source code security review: secrets, auth logic, injection sinks, crypto, dependencies

    `Rifteo-Community/contexts`
  </Card>
</CardGroup>
