npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
- When establishing continuous security monitoring across AWS, Azure, and GCP environments
- When compliance requirements demand automated posture assessment against CIS, SOC 2, or PCI DSS
- When security teams need visibility into cloud misconfigurations across multiple accounts and subscriptions
- When building a security operations workflow that detects and remediates drift from security baselines
- When migrating workloads to the cloud and need to enforce security guardrails
Do not use for runtime workload protection (use CWPP tools like Falco or Aqua), for application security testing (use DAST/SAST tools), or for network intrusion detection (use cloud-native IDS like GuardDuty or Network Watcher).
Prerequisites
- Multi-cloud credentials with read-only security audit permissions across all target environments
- Prowler v3+ installed (
pip install prowler) - ScoutSuite installed (
pip install scoutsuite) - AWS Config, Azure Policy, and GCP Organization Policy enabled in respective environments
- Central logging destination (S3 bucket, Log Analytics Workspace, or Cloud Storage) for findings aggregation
- Notification channels configured (Slack, PagerDuty, email) for critical finding alerts
Workflow
Step 1: Deploy Cloud-Native CSPM Services
Enable the built-in CSPM capabilities in each cloud provider for baseline posture assessment.
# AWS: Enable Security Hub with FSBP and CIS standards
aws securityhub enable-security-hub --enable-default-standards
aws securityhub batch-enable-standards --standards-subscription-requests \
'[{"StandardsArn":"arn:aws:securityhub:::standards/cis-aws-foundations-benchmark/v/1.4.0"}]'
# Azure: Enable Microsoft Defender for Cloud (CSPM tier)
az security pricing create --name CloudPosture --tier standard
az security auto-provisioning-setting update --name default --auto-provision on
# GCP: Enable Security Command Center Premium
gcloud services enable securitycenter.googleapis.com
gcloud scc settings update --organization=ORG_ID \
--enable-asset-discoveryStep 2: Run Prowler for Multi-Cloud Assessment
Execute Prowler to perform comprehensive security checks across all three cloud providers.
# AWS assessment with all CIS checks
prowler aws \
--profile production \
-M json-ocsf csv html \
-o ./prowler-results/aws/ \
--compliance cis_1.4_aws cis_1.5_aws
# Azure assessment
prowler azure \
--subscription-ids SUB_ID_1 SUB_ID_2 \
-M json-ocsf csv html \
-o ./prowler-results/azure/ \
--compliance cis_2.0_azure
# GCP assessment
prowler gcp \
--project-ids project-1 project-2 \
-M json-ocsf csv html \
-o ./prowler-results/gcp/ \
--compliance cis_2.0_gcp
# View summary across all providers
prowler aws --list-complianceStep 3: Run ScoutSuite for Cross-Cloud Comparison
Use ScoutSuite for a unified multi-cloud security assessment with visual reporting.
# Scan AWS
python3 -m ScoutSuite aws --profile production \
--report-dir ./scoutsuite/aws/
# Scan Azure
python3 -m ScoutSuite azure --cli \
--all-subscriptions \
--report-dir ./scoutsuite/azure/
# Scan GCP
python3 -m ScoutSuite gcp --user-account \
--all-projects \
--report-dir ./scoutsuite/gcp/
# Each produces an HTML report with risk-scored findingsStep 4: Build Automated Compliance Monitoring Pipeline
Create a scheduled pipeline that runs CSPM checks daily and routes findings to appropriate channels.
# Create a daily Prowler scan with EventBridge + CodeBuild (AWS)
cat > buildspec.yml << 'EOF'
version: 0.2
phases:
install:
commands:
- pip install prowler
build:
commands:
- prowler aws -M json-ocsf -o s3://security-findings-bucket/prowler/$(date +%Y%m%d)/
- prowler aws --compliance cis_1.5_aws -M csv -o s3://security-findings-bucket/prowler/compliance/
post_build:
commands:
- |
CRITICAL=$(cat output/*.json | grep -c '"CRITICAL"')
if [ "$CRITICAL" -gt 0 ]; then
aws sns publish --topic-arn arn:aws:sns:us-east-1:ACCOUNT:security-alerts \
--subject "Prowler: $CRITICAL critical findings" \
--message "Review at s3://security-findings-bucket/prowler/$(date +%Y%m%d)/"
fi
EOF
# Schedule with EventBridge
aws events put-rule \
--name daily-prowler-scan \
--schedule-expression "cron(0 6 * * ? *)" \
--state ENABLEDStep 5: Configure Finding Aggregation and Deduplication
Aggregate findings from multiple CSPM tools and cloud providers into a unified view.
# findings_aggregator.py - Normalize and deduplicate CSPM findings
import json
import hashlib
from datetime import datetime
def normalize_finding(finding, source):
"""Normalize findings from different CSPM tools to a common format."""
normalized = {
'id': hashlib.sha256(f"{finding.get('ResourceId','')}{finding.get('CheckId','')}".encode()).hexdigest()[:16],
'source': source,
'cloud': finding.get('Provider', 'unknown'),
'account': finding.get('AccountId', finding.get('SubscriptionId', '')),
'region': finding.get('Region', ''),
'resource_type': finding.get('ResourceType', ''),
'resource_id': finding.get('ResourceId', ''),
'severity': finding.get('Severity', 'INFO').upper(),
'status': finding.get('Status', 'FAIL'),
'title': finding.get('CheckTitle', finding.get('Title', '')),
'description': finding.get('StatusExtended', ''),
'compliance': finding.get('Compliance', {}),
'remediation': finding.get('Remediation', {}).get('Recommendation', {}).get('Text', ''),
'timestamp': datetime.utcnow().isoformat()
}
return normalized
def aggregate_findings(prowler_file, scoutsuite_file):
findings = {}
for file_path, source in [(prowler_file, 'prowler'), (scoutsuite_file, 'scoutsuite')]:
with open(file_path) as f:
for line in f:
raw = json.loads(line)
normalized = normalize_finding(raw, source)
if normalized['status'] == 'FAIL':
findings[normalized['id']] = normalized
return sorted(findings.values(), key=lambda x: {'CRITICAL':0,'HIGH':1,'MEDIUM':2,'LOW':3}.get(x['severity'],4))Step 6: Implement Drift Detection and Auto-Remediation
Set up automated responses to configuration drift that violates security baselines.
# AWS Config auto-remediation for non-compliant S3 buckets
aws configservice put-remediation-configurations --remediation-configurations '[{
"ConfigRuleName": "s3-bucket-public-read-prohibited",
"TargetType": "SSM_DOCUMENT",
"TargetId": "AWS-DisableS3BucketPublicReadWrite",
"Parameters": {
"S3BucketName": {"ResourceValue": {"Value": "RESOURCE_ID"}}
},
"Automatic": true,
"MaximumAutomaticAttempts": 3,
"RetryAttemptSeconds": 60
}]'
# Azure Policy for auto-remediation
az policy assignment create \
--name "enforce-storage-encryption" \
--policy "/providers/Microsoft.Authorization/policyDefinitions/404c3081-a854-4457-ae30-26a93ef643f9" \
--scope "/subscriptions/SUB_ID" \
--enforcement-mode Default
# GCP Organization Policy constraint
gcloud resource-manager org-policies set-policy policy.yaml --organization=ORG_ID
# policy.yaml: constraint: constraints/storage.publicAccessPrevention, enforcement: trueKey Concepts
| Term | Definition |
|---|---|
| CSPM | Cloud Security Posture Management, the practice of continuously monitoring cloud infrastructure for misconfigurations and compliance violations |
| Configuration Drift | Unintended changes to cloud resource configurations that deviate from the approved security baseline over time |
| Security Baseline | A documented set of minimum security configuration requirements that all cloud resources must meet |
| Compliance Framework | A structured set of security controls and requirements (CIS, SOC 2, PCI DSS, NIST) against which cloud configurations are evaluated |
| Finding Severity | Risk classification of a misconfiguration based on exploitability and potential impact (Critical, High, Medium, Low, Informational) |
| Auto-Remediation | Automated corrective action that restores a non-compliant resource to its required configuration without manual intervention |
Tools & Systems
- Prowler: Open-source multi-cloud security assessment tool with 300+ checks aligned to CIS, PCI DSS, HIPAA, and NIST
- ScoutSuite: Multi-cloud security auditing tool producing risk-scored HTML reports from API-collected configuration data
- AWS Security Hub: AWS-native CSPM with aggregated findings and compliance standard evaluation
- Microsoft Defender for Cloud: Azure-native CSPM with secure score, regulatory compliance, and workload protection
- GCP Security Command Center: GCP-native security platform with asset inventory, vulnerability scanning, and compliance monitoring
Common Scenarios
Scenario: Establishing CSPM for a Multi-Cloud Enterprise
Context: An enterprise runs production workloads across AWS (primary), Azure (identity and Microsoft services), and GCP (data analytics). The security team needs unified posture visibility.
Approach:
- Enable cloud-native CSPM in each provider: Security Hub, Defender for Cloud, SCC
- Deploy Prowler scans as daily scheduled jobs in each environment via CI/CD pipelines
- Normalize and aggregate findings into a central data lake using the aggregation script
- Build dashboards in Grafana or Kibana showing posture scores by cloud, account, and severity
- Configure auto-remediation for known-good fixes (public access blocks, encryption enablement)
- Route CRITICAL findings to PagerDuty for immediate response and HIGH findings to Jira tickets
- Produce weekly compliance reports for executive stakeholders showing trend data
Pitfalls: Running CSPM tools with overly broad permissions creates a high-value target. Use dedicated service accounts with read-only permissions and rotate credentials regularly. Different CSPM tools may report the same misconfiguration differently, so deduplication logic must account for varying resource ID formats and finding titles across tools.
Output Format
Cloud Security Posture Management Dashboard
==============================================
Organization: Acme Corp
Assessment Date: 2026-02-23
Environments: AWS (12 accounts), Azure (8 subscriptions), GCP (5 projects)
POSTURE SCORES:
AWS: 82/100 (+3 from last week)
Azure: 76/100 (-1 from last week)
GCP: 79/100 (+5 from last week)
Overall: 79/100
FINDINGS BY SEVERITY:
Critical: 18 (AWS: 7, Azure: 8, GCP: 3)
High: 67 (AWS: 28, Azure: 24, GCP: 15)
Medium: 234 (AWS: 98, Azure: 87, GCP: 49)
Low: 412 (AWS: 178, Azure: 134, GCP: 100)
TOP FAILING CATEGORIES:
1. IAM overly permissive policies (43 findings)
2. Encryption not enabled at rest (38 findings)
3. Public network exposure (29 findings)
4. Logging and monitoring gaps (24 findings)
5. Unused credentials and keys (19 findings)
AUTO-REMEDIATION (Last 7 Days):
Findings auto-remediated: 34
Manual remediation pending: 51
Exceptions approved: 8References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md1.9 KB
API Reference: Implementing Cloud Security Posture Management
Libraries
Prowler (Multi-Cloud CSPM)
- Install:
pip install prowler - Docs: https://docs.prowler.com/
- CLI:
prowler aws --compliance cis_level1 -M json - Supported: AWS, Azure, GCP, Kubernetes
- Compliance frameworks: CIS, SOC2, PCI-DSS, HIPAA, NIST 800-53, GDPR
boto3 (AWS Posture Checks)
- Install:
pip install boto3 - Key services: S3, IAM, EC2, CloudTrail, Config, SecurityHub
ScoutSuite (Multi-Cloud Auditing)
- Install:
pip install scoutsuite - Docs: https://github.com/nccgroup/ScoutSuite
- CLI:
scout aws --report-dir /tmp/scout-report
AWS Posture Check APIs
| Service | Method | Check |
|---|---|---|
| S3 | get_public_access_block() |
Public access settings |
| S3 | get_bucket_encryption() |
Default encryption |
| IAM | get_account_summary() |
Root MFA status |
| IAM | list_access_keys() |
Key age/rotation |
| EC2 | describe_security_groups() |
Open ports (0.0.0.0/0) |
| CloudTrail | get_trail_status() |
Logging active |
| Config | describe_config_rules() |
Compliance rules |
Prowler Check Categories
- IAM: Access keys, MFA, password policy, root usage
- Storage: S3 public access, encryption, versioning
- Network: Security groups, VPC flow logs, NACLs
- Logging: CloudTrail, Config, VPC flow logs
- Encryption: EBS, RDS, S3, KMS key rotation
Severity Mapping
- CRITICAL: Root MFA disabled, CloudTrail off, public DB
- HIGH: S3 public access, open SSH/RDP, unencrypted volumes
- MEDIUM: Key rotation >90d, missing tags, flow logs off
- LOW: Informational findings, best practice suggestions
External References
- Prowler Documentation: https://docs.prowler.com/
- ScoutSuite: https://github.com/nccgroup/ScoutSuite
- AWS Security Hub: https://docs.aws.amazon.com/securityhub/
- CIS Benchmarks: https://www.cisecurity.org/benchmark/amazon_web_services
Scripts 1
agent.py7.6 KB
#!/usr/bin/env python3
"""Cloud Security Posture Management (CSPM) agent across AWS, Azure, and GCP."""
import json
import argparse
import subprocess
from datetime import datetime
from collections import Counter
try:
import boto3
from botocore.exceptions import ClientError
except ImportError:
boto3 = None
def run_prowler_scan(provider="aws", compliance="cis_level1", output_format="json"):
"""Run Prowler CSPM scan against a cloud provider."""
cmd = ["prowler", provider, "--compliance", compliance,
"-M", output_format, "--output-directory", "/tmp/prowler-output"]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
return {"status": "completed", "returncode": result.returncode,
"output_dir": "/tmp/prowler-output"}
except FileNotFoundError:
return {"error": "Prowler not installed. Run: pip install prowler"}
except subprocess.TimeoutExpired:
return {"error": "Prowler scan timed out after 10 minutes"}
def check_aws_security_posture(region="us-east-1"):
"""Run basic AWS security posture checks using boto3."""
if boto3 is None:
return {"error": "boto3 not installed"}
findings = []
s3 = boto3.client("s3", region_name=region)
try:
buckets = s3.list_buckets().get("Buckets", [])
for bucket in buckets:
name = bucket["Name"]
try:
pab = s3.get_public_access_block(Bucket=name)
config = pab["PublicAccessBlockConfiguration"]
if not all([config["BlockPublicAcls"], config["BlockPublicPolicy"],
config["IgnorePublicAcls"], config["RestrictPublicBuckets"]]):
findings.append({"check": "S3_PUBLIC_ACCESS", "resource": name,
"severity": "HIGH", "status": "FAIL",
"detail": "Public access block not fully enabled"})
except ClientError:
findings.append({"check": "S3_PUBLIC_ACCESS", "resource": name,
"severity": "HIGH", "status": "FAIL",
"detail": "No public access block configured"})
try:
s3.get_bucket_encryption(Bucket=name)
except ClientError:
findings.append({"check": "S3_ENCRYPTION", "resource": name,
"severity": "MEDIUM", "status": "FAIL",
"detail": "Default encryption not enabled"})
except ClientError as e:
findings.append({"check": "S3_ACCESS", "status": "ERROR", "detail": str(e)})
iam = boto3.client("iam", region_name=region)
try:
acct_summary = iam.get_account_summary()["SummaryMap"]
if acct_summary.get("AccountMFAEnabled", 0) == 0:
findings.append({"check": "ROOT_MFA", "resource": "root-account",
"severity": "CRITICAL", "status": "FAIL",
"detail": "Root account MFA not enabled"})
users = iam.list_users()["Users"]
for user in users:
keys = iam.list_access_keys(UserName=user["UserName"])["AccessKeyMetadata"]
for key in keys:
age = (datetime.utcnow() - key["CreateDate"].replace(tzinfo=None)).days
if age > 90:
findings.append({"check": "IAM_KEY_ROTATION", "resource": user["UserName"],
"severity": "MEDIUM", "status": "FAIL",
"detail": f"Access key {key['AccessKeyId']} is {age} days old"})
except ClientError as e:
findings.append({"check": "IAM_ACCESS", "status": "ERROR", "detail": str(e)})
ec2 = boto3.client("ec2", region_name=region)
try:
sgs = ec2.describe_security_groups()["SecurityGroups"]
for sg in sgs:
for rule in sg.get("IpPermissions", []):
for ip_range in rule.get("IpRanges", []):
if ip_range.get("CidrIp") == "0.0.0.0/0":
port = rule.get("FromPort", "all")
if port in [22, 3389, 0, -1]:
findings.append({"check": "SG_OPEN_PORTS", "resource": sg["GroupId"],
"severity": "HIGH", "status": "FAIL",
"detail": f"Port {port} open to 0.0.0.0/0"})
except ClientError as e:
findings.append({"check": "EC2_ACCESS", "status": "ERROR", "detail": str(e)})
ct = boto3.client("cloudtrail", region_name=region)
try:
trails = ct.describe_trails()["trailList"]
if not trails:
findings.append({"check": "CLOUDTRAIL_ENABLED", "resource": "account",
"severity": "CRITICAL", "status": "FAIL",
"detail": "No CloudTrail trails configured"})
for trail in trails:
status = ct.get_trail_status(Name=trail["TrailARN"])
if not status.get("IsLogging"):
findings.append({"check": "CLOUDTRAIL_LOGGING", "resource": trail["Name"],
"severity": "CRITICAL", "status": "FAIL",
"detail": "CloudTrail is not actively logging"})
except ClientError as e:
findings.append({"check": "CLOUDTRAIL_ACCESS", "status": "ERROR", "detail": str(e)})
return findings
def generate_posture_report(findings):
"""Generate a CSPM posture report from findings."""
severity_counts = Counter(f["severity"] for f in findings if f.get("severity"))
check_counts = Counter(f["check"] for f in findings)
fail_count = sum(1 for f in findings if f.get("status") == "FAIL")
pass_rate = round((1 - fail_count / max(len(findings), 1)) * 100, 1)
print(f"\n{'='*60}")
print(f" CSPM POSTURE REPORT")
print(f" Generated: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC")
print(f"{'='*60}\n")
print(f"--- SUMMARY ---")
print(f" Total Checks: {len(findings)}")
print(f" Failed: {fail_count}")
print(f" Pass Rate: {pass_rate}%\n")
print(f"--- BY SEVERITY ---")
for sev in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]:
count = severity_counts.get(sev, 0)
bar = "#" * count
print(f" {sev:<10} {count:>3} {bar}")
print(f"\n--- FAILED CHECKS ---")
for f in findings:
if f.get("status") == "FAIL":
print(f" [{f['severity']}] {f['check']}: {f.get('resource', 'N/A')}")
print(f" {f.get('detail', '')}")
print(f"\n{'='*60}\n")
return {"total": len(findings), "failed": fail_count, "pass_rate": pass_rate,
"by_severity": dict(severity_counts)}
def main():
parser = argparse.ArgumentParser(description="CSPM Agent")
parser.add_argument("--provider", default="aws", choices=["aws", "azure", "gcp"])
parser.add_argument("--region", default="us-east-1")
parser.add_argument("--prowler", action="store_true", help="Run Prowler scan")
parser.add_argument("--scan", action="store_true", help="Run built-in posture scan")
parser.add_argument("--output", help="Save report to JSON")
args = parser.parse_args()
if args.prowler:
result = run_prowler_scan(args.provider)
print(json.dumps(result, indent=2))
elif args.scan:
findings = check_aws_security_posture(args.region)
report = generate_posture_report(findings)
if args.output:
with open(args.output, "w") as f:
json.dump({"findings": findings, "summary": report}, f, indent=2, default=str)
print(f"[+] Report saved to {args.output}")
else:
parser.print_help()
if __name__ == "__main__":
main()