A Python tool that scans AWS and Azure for common security misconfigurations, produces tamper-evident signed JSON reports, and uses Claude (Anthropic) to explain each finding in plain English with step-by-step remediation.
| Provider | Resource | Checks |
|---|---|---|
| AWS | S3 Buckets | Public ACLs, public access block disabled, no encryption, versioning off, logging off |
| AWS | IAM | Root MFA disabled, root access keys, user MFA missing, stale access keys (>90d), wildcard admin policies |
| AWS | Security Groups | All-traffic open (0.0.0.0/0), dangerous ports open (SSH/22, RDP/3389, MySQL/3306, Postgres/5432, MongoDB/27017, Redis/6379) |
| Azure | NSGs | All-ports wildcard rules, dangerous ports open from internet |
git clone <repo>
cd cloudsec-scanner
pip install -r requirements.txtpython main.py --generate-keys
# Creates: private.pem (keep secret), public.pem (shareable)# AWS only, sign the report, explain with LLM
export ANTHROPIC_API_KEY=sk-ant-...
python main.py --providers aws --explain --sign --key private.pem --output report.json
# AWS + Azure
python main.py \
--providers aws azure \
--subscription-id <AZURE_SUB_ID> \
--explain \
--sign --key private.pem \
--output report.json
# Filter to CRITICAL and HIGH only
python main.py --providers aws --severity CRITICAL HIGH --explain
# Without LLM (just findings + signed report)
python main.py --providers aws --sign --key private.pempython main.py --verify report.json --public-key public.pem
# ✅ Report verified successfullyThe output is a tamper-evident JSON envelope:
{
"payload": {
"schema_version": "1.0",
"generated_at": "2025-01-15T10:30:00+00:00",
"scanner": "cloudsec-scanner",
"summary": {
"total_findings": 12,
"severity_counts": { "CRITICAL": 2, "HIGH": 5, "MEDIUM": 3, "LOW": 2 },
"resource_types": ["IAMAccount", "S3Bucket", "SecurityGroup"]
},
"findings": [
{
"resource_type": "SecurityGroup",
"resource_id": "sg-0abc123",
"check": "OpenPort22",
"severity": "HIGH",
"detail": "SG 'web-sg' allows SSH (port 22) from 0.0.0.0/0.",
"llm_analysis": {
"explanation": "This security group allows anyone on the internet to attempt SSH connections to your instances.",
"risk": "Attackers can run automated brute-force attacks against SSH. A weak or default password would grant full server access.",
"remediation": {
"summary": "Restrict SSH to specific trusted IP ranges only.",
"steps": [
"Go to EC2 → Security Groups → Select the group",
"Edit inbound rules → Remove the 0.0.0.0/0 SSH rule",
"Add a new rule: Type=SSH, Source=Your IP or VPN CIDR"
],
"example_code": "aws ec2 revoke-security-group-ingress --group-id sg-0abc123 --protocol tcp --port 22 --cidr 0.0.0.0/0"
},
"fix_effort": "Low"
}
}
]
},
"integrity": {
"algorithm": "RSA-SHA256-PKCS1v15",
"sha256": "a3f9b2...",
"signature": "base64-encoded-RSA-signature...",
"public_key_fingerprint": "sha256-of-public-key..."
}
}- The
payloadis serialized to canonical JSON (sorted keys, no whitespace) — this is deterministic. - A SHA-256 digest of that canonical JSON is computed.
- The digest is RSA-signed with your private key (PKCS#1 v1.5 + SHA-256).
- Anyone with
public.pemcan re-canonicalize the payload, recompute the digest, and verify the signature — any modification to any field will break verification.
HMAC-SHA256 signing is also supported as a lighter alternative (no PKI required).
Uses boto3 credential chain:
- Environment variables (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY) ~/.aws/credentialsfile (--profile my-profile)- IAM Instance Role / ECS Task Role / Lambda Execution Role (automatic)
Minimum IAM permissions needed (read-only):
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets", "s3:GetBucketAcl", "s3:GetBucketPublicAccessBlock",
"s3:GetBucketEncryption", "s3:GetBucketVersioning", "s3:GetBucketLogging",
"iam:GetAccountSummary", "iam:ListUsers", "iam:ListMFADevices",
"iam:GetLoginProfile", "iam:ListAccessKeys", "iam:ListPolicies", "iam:GetPolicyVersion",
"ec2:DescribeSecurityGroups"
],
"Resource": "*"
}Uses DefaultAzureCredential:
az login(local dev)- Managed Identity (Azure VMs, Container Instances)
- Environment variables (
AZURE_CLIENT_ID,AZURE_CLIENT_SECRET,AZURE_TENANT_ID)
Minimum role: Network Contributor (read) or custom role with Microsoft.Network/networkSecurityGroups/read.
# Build
docker build -t cloudsec-scanner .
# Run
docker run --rm \
-e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
-e AWS_DEFAULT_REGION=us-east-1 \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
-v $(pwd)/keys:/app/keys:ro \
-v $(pwd)/reports:/app/reports \
cloudsec-scanner \
--providers aws --explain --sign --key /app/keys/private.pemcd deploy/
# Build dependency layer first
mkdir -p layer/python
pip install -r ../requirements.txt -t layer/python
cd layer && zip -r ../layer.zip python && cd ..
# Deploy
terraform init
terraform apply \
-var="report_bucket=my-security-reports" \
-var="signing_secret=$(openssl rand -hex 32)" \
-var="anthropic_api_key=$ANTHROPIC_API_KEY" \
-var="alert_email=security@mycompany.com"The Lambda function runs on a schedule (default: daily), stores the signed report to S3, and sends an SNS email alert if CRITICAL or HIGH findings are detected.
--providers aws azure Cloud providers to scan (default: aws)
--region us-east-1 AWS region
--profile PROFILE AWS named profile
--subscription-id ID Azure subscription ID
--severity CRITICAL HIGH Filter by severity
--explain Enrich findings with LLM explanations
--model MODEL Anthropic model (default: claude-sonnet-4-20250514)
--max-explain N Max findings to send to LLM (default: 20)
--sign Sign report with RSA key
--key private.pem RSA private key for signing
--hmac-secret SECRET HMAC secret (alternative to --key)
--output report.json Output file path
--verify report.json Verify an existing report
--public-key public.pem RSA public key for verification
--generate-keys Generate RSA key pair
--quiet Suppress terminal output
| Code | Meaning |
|---|---|
| 0 | Scan complete, no CRITICAL findings |
| 1 | Scan complete, CRITICAL findings found |
| 2 | Verification failed (tampered report) |
This makes the scanner usable in CI/CD pipelines:
python main.py --providers aws --severity CRITICAL || echo "CRITICAL findings — blocking deploy"- Read-only: The scanner never modifies your infrastructure. It only calls
Describe*,List*, andGet*APIs. - No cross-account: Scans the account/subscription your credentials have access to. For multi-account orgs, run once per account or use AWS Organizations + CloudFormation StackSets.
- LLM analysis costs money: Each finding sent to the LLM costs API tokens. The
--max-explainflag caps this (default: 20 findings per run). - Not a replacement for AWS Security Hub / Defender for Cloud: Those services have deeper integration and continuous monitoring. This tool is best for point-in-time checks and CI/CD gates.
- Azure support is NSG-only: Azure has many more security surfaces (Storage, Key Vault, RBAC). PRs welcome.