Skip to content

jaradat13/cloudsec-scanner

Repository files navigation

cloudsec-scanner

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.


What It Scans

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

Quick Start

1. Install

git clone <repo>
cd cloudsec-scanner
pip install -r requirements.txt

2. Generate a signing key pair (once)

python main.py --generate-keys
# Creates: private.pem (keep secret), public.pem (shareable)

3. Run a scan

# 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.pem

4. Verify a report hasn't been tampered with

python main.py --verify report.json --public-key public.pem
# ✅ Report verified successfully

Report Format

The 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..."
  }
}

How tamper-evidence works

  1. The payload is serialized to canonical JSON (sorted keys, no whitespace) — this is deterministic.
  2. A SHA-256 digest of that canonical JSON is computed.
  3. The digest is RSA-signed with your private key (PKCS#1 v1.5 + SHA-256).
  4. Anyone with public.pem can 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).


Authentication

AWS

Uses boto3 credential chain:

  • Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
  • ~/.aws/credentials file (--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": "*"
}

Azure

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.


Deployment

Docker

# 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.pem

AWS Lambda (Scheduled, daily)

cd 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.


CLI Reference

--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

Exit Codes

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"

Honest Limitations

  • Read-only: The scanner never modifies your infrastructure. It only calls Describe*, List*, and Get* 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-explain flag 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.

About

Scans AWS and Azure for misconfigurations, generates signed JSON reports, and uses Claude for AI-powered remediation.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors