Files
T
mukul975 27c6414ca5 Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills:
- scripts/agent.py: 80-150 line Python agents using real libraries (impacket,
  boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.)
- references/api-reference.md: real API documentation with method signatures
- LICENSE: MIT license for all skill folders
2026-03-10 21:02:12 +01:00

159 lines
6.3 KiB
Python

#!/usr/bin/env python3
"""Agent for building cloud security posture management across AWS/Azure/GCP."""
import os
import json
import argparse
from datetime import datetime
import boto3
from botocore.exceptions import ClientError
def check_s3_public_buckets(session):
"""Check for publicly accessible S3 buckets."""
s3 = session.client("s3")
buckets = s3.list_buckets()["Buckets"]
findings = []
for b in buckets:
name = b["Name"]
try:
pab = s3.get_public_access_block(Bucket=name)
config = pab["PublicAccessBlockConfiguration"]
if not all([config.get("BlockPublicAcls"), config.get("IgnorePublicAcls"),
config.get("BlockPublicPolicy"), config.get("RestrictPublicBuckets")]):
findings.append({"bucket": name, "issue": "Incomplete public access block", "severity": "HIGH"})
except ClientError:
findings.append({"bucket": name, "issue": "No public access block configured", "severity": "HIGH"})
return findings
def check_unencrypted_ebs(session):
"""Check for unencrypted EBS volumes."""
ec2 = session.client("ec2")
volumes = ec2.describe_volumes()["Volumes"]
unencrypted = [
{"volume_id": v["VolumeId"], "state": v["State"], "size_gb": v["Size"]}
for v in volumes if not v.get("Encrypted")
]
return unencrypted
def check_public_security_groups(session):
"""Check for security groups allowing unrestricted inbound access."""
ec2 = session.client("ec2")
sgs = ec2.describe_security_groups()["SecurityGroups"]
findings = []
dangerous_ports = [22, 3389, 3306, 5432, 1433, 27017]
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":
from_port = rule.get("FromPort", 0)
to_port = rule.get("ToPort", 65535)
severity = "CRITICAL" if any(from_port <= p <= to_port for p in dangerous_ports) else "HIGH"
findings.append({
"sg_id": sg["GroupId"],
"sg_name": sg.get("GroupName"),
"port_range": f"{from_port}-{to_port}",
"source": "0.0.0.0/0",
"severity": severity,
})
return findings
def check_iam_users_without_mfa(session):
"""Check for IAM users without MFA enabled."""
iam = session.client("iam")
users = iam.list_users()["Users"]
no_mfa = []
for user in users:
mfa_devices = iam.list_mfa_devices(UserName=user["UserName"])["MFADevices"]
if not mfa_devices:
no_mfa.append({"username": user["UserName"], "created": str(user["CreateDate"])})
return no_mfa
def check_rds_public_access(session):
"""Check for RDS instances with public accessibility."""
rds = session.client("rds")
instances = rds.describe_db_instances()["DBInstances"]
public = [
{"instance": db["DBInstanceIdentifier"], "engine": db["Engine"], "endpoint": db.get("Endpoint", {}).get("Address", "")}
for db in instances if db.get("PubliclyAccessible")
]
return public
def check_cloudtrail_enabled(session):
"""Check if CloudTrail is enabled with multi-region logging."""
ct = session.client("cloudtrail")
trails = ct.describe_trails()["trailList"]
multiregion = [t for t in trails if t.get("IsMultiRegionTrail")]
if not multiregion:
return {"status": "FAIL", "detail": "No multi-region CloudTrail found"}
return {"status": "PASS", "trails": len(multiregion)}
def calculate_posture_score(findings_summary):
"""Calculate an overall security posture score."""
total_checks = sum(findings_summary.values())
if total_checks == 0:
return 100
critical = findings_summary.get("critical", 0)
high = findings_summary.get("high", 0)
medium = findings_summary.get("medium", 0)
deductions = (critical * 15) + (high * 8) + (medium * 3)
return max(0, 100 - deductions)
def main():
parser = argparse.ArgumentParser(description="Cloud Security Posture Management Agent")
parser.add_argument("--profile", default=os.getenv("AWS_PROFILE"))
parser.add_argument("--region", default=os.getenv("AWS_DEFAULT_REGION", "us-east-1"))
parser.add_argument("--output", default="cspm_report.json")
args = parser.parse_args()
session = boto3.Session(profile_name=args.profile, region_name=args.region)
account = session.client("sts").get_caller_identity()["Account"]
print(f"[+] CSPM scan for account {account}")
report = {"account": account, "scan_date": datetime.utcnow().isoformat(), "findings": {}}
print("[+] Checking S3 bucket public access...")
report["findings"]["s3_public"] = check_s3_public_buckets(session)
print(f" Issues: {len(report['findings']['s3_public'])}")
print("[+] Checking unencrypted EBS volumes...")
report["findings"]["unencrypted_ebs"] = check_unencrypted_ebs(session)
print(f" Unencrypted: {len(report['findings']['unencrypted_ebs'])}")
print("[+] Checking public security groups...")
report["findings"]["public_sgs"] = check_public_security_groups(session)
print(f" Open rules: {len(report['findings']['public_sgs'])}")
print("[+] Checking IAM users without MFA...")
report["findings"]["no_mfa_users"] = check_iam_users_without_mfa(session)
print(f" Without MFA: {len(report['findings']['no_mfa_users'])}")
print("[+] Checking public RDS instances...")
report["findings"]["public_rds"] = check_rds_public_access(session)
print(f" Public: {len(report['findings']['public_rds'])}")
print("[+] Checking CloudTrail...")
report["findings"]["cloudtrail"] = check_cloudtrail_enabled(session)
critical = sum(1 for f in report["findings"].get("public_sgs", []) if f.get("severity") == "CRITICAL")
high = len(report["findings"]["s3_public"]) + len(report["findings"]["no_mfa_users"])
medium = len(report["findings"]["unencrypted_ebs"])
report["posture_score"] = calculate_posture_score({"critical": critical, "high": high, "medium": medium})
print(f"\n[+] Posture Score: {report['posture_score']}/100")
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"[+] Report saved to {args.output}")
if __name__ == "__main__":
main()