Skip to main content

cloudsec-audit

Continuous cloud security posture auditing for AWS — IAM, network, storage, and compliance checks in a single pip-installable Python library.

PyPI version Python 3.9+ License: MIT MITRE ATT&CK


The Problem

Cloud misconfigurations cause the majority of cloud breaches, yet most teams run audits manually or quarterly. Existing CSPM tools are expensive SaaS platforms. There is no open-source Python library for continuous, scriptable cloud posture auditing that developers can embed directly in their own CI/CD pipelines and workflows.

The Solution

cloudsec-audit uses native AWS SDK clients (boto3) to continuously audit IAM permissions, network exposure, storage access controls, and logging configurations — producing prioritized, actionable findings with MITRE ATT&CK mappings and compliance framework evidence.


Install

pip install cloudsec-audit

Quick Start

Python API

from cloudsec_audit import CloudSecAudit, AWSSession

# Uses ambient credentials (env vars, ~/.aws/credentials, instance profile)
audit = CloudSecAudit(
    session=AWSSession(),
    regions=["us-east-1", "eu-west-1"],
)

report = audit.run()
print(report.summary())

# Export results
report.to_json("findings.json")
report.to_markdown("findings.md")
report.to_csv("findings.csv")

# Compliance evidence report
compliance = audit.compliance_report(frameworks=["CIS", "SOC2", "PCI-DSS"])
print(compliance.summary())
compliance.to_json("compliance-evidence.json")

CLI

# Full audit, default region
cloudsec-audit

# Multi-region with a named profile
cloudsec-audit --profile prod-readonly --regions us-east-1 eu-west-1 ap-southeast-1

# IAM-only audit, save results
cloudsec-audit --only iam --output iam-findings.json

# Assume a cross-account audit role
cloudsec-audit --role-arn arn:aws:iam::123456789012:role/SecurityAuditRole

# Generate compliance report
cloudsec-audit --compliance CIS SOC2 --output-compliance compliance.json

# Debug mode
cloudsec-audit --log-level DEBUG

Analyzers

IAMAnalyzer

Audits IAM roles, users, policies, and trust relationships.

Detects:

  • Root account without MFA or with active access keys
  • Long-lived IAM access keys (default: > 90 days)
  • Console users without MFA
  • Users or roles with AdministratorAccess
  • Inline policies with wildcard Action or Resource
  • Cross-account trust misconfigurations
  • Wildcard principal (*) in trust policies
  • Weak account password policy
from cloudsec_audit import IAMAnalyzer, AWSSession

analyzer = IAMAnalyzer(
    session=AWSSession(),
    key_age_threshold_days=90,
    unused_threshold_days=45,
)
findings = analyzer.run()

for f in findings:
    print(f"[{f.severity.value}] {f.title}")
    print(f"  Resource: {f.resource_id}")
    if f.attack_path:
        print(f"  Blast radius: {f.attack_path.blast_radius}")
    for step in f.remediation_steps:
        print(f"  Fix {step.order}: {step.description}")
        if step.code_snippet:
            print(f"    $ {step.code_snippet}")

NetworkExposureAuditor

Audits security groups, NACLs, and VPC configurations.

Detects:

  • Security groups allowing all traffic (-1) from 0.0.0.0/0
  • Publicly exposed sensitive ports (SSH, RDP, all database ports, Docker, Kubernetes)
  • Permissive Network ACL rules
  • VPCs without flow logs enabled
from cloudsec_audit import NetworkExposureAuditor, AWSSession

auditor = NetworkExposureAuditor(
    session=AWSSession(),
    regions=["us-east-1", "us-west-2"],
    check_flow_logs=True,
)
findings = auditor.run()

StorageAuditor

Audits S3 bucket security configurations.

Detects:

  • Buckets with public ACL grants (AllUsers, AuthenticatedUsers)
  • Bucket policies with Principal: "*"
  • Missing server-side encryption (SSE-S3 or SSE-KMS)
  • Disabled access logging
  • Versioning not enabled
  • S3 account-level public access block not fully configured
from cloudsec_audit import StorageAuditor, AWSSession

auditor = StorageAuditor(
    session=AWSSession(),
    check_encryption=True,
    check_logging=True,
    check_versioning=True,
)
findings = auditor.run()

Compliance Frameworks

ComplianceReporter maps findings to controls and generates audit-ready evidence:

Framework Controls Covered
CIS AWS Foundations Benchmark v1.5 IAM, S3, Networking, Logging
SOC 2 (CC controls) CC6.x, CC7.x, A1.x
ISO 27001 A.9, A.10, A.12, A.13
HIPAA 164.312
PCI-DSS v4.0 Requirements 1, 3, 7, 8, 10
from cloudsec_audit import ComplianceReporter

reporter = ComplianceReporter(
    findings=findings,
    frameworks=["CIS", "SOC2", "HIPAA"],
    account_id="123456789012",
)

report_data = reporter.generate()

print(reporter.summary())
# ============================================================
#   COMPLIANCE SUMMARY — Account: 123456789012
#   Generated: 2026-04-16 10:30 UTC
# ============================================================
#   CIS           73.1%   Pass:19  Fail:5  Total:26
#   SOC2          83.3%   Pass:5   Fail:1  Total:6
#   HIPAA         75.0%   Pass:3   Fail:1  Total:4

reporter.to_json("evidence-report.json")

# List only failing controls
for ctrl in reporter.failing_controls(framework="CIS"):
    print(f"FAIL [{ctrl.control_id}] {ctrl.description}")

Finding Schema

Every finding includes:

Finding(
    finding_id="uuid",
    title="Root account MFA is not enabled",
    description="...",
    severity=Severity.CRITICAL,           # CRITICAL / HIGH / MEDIUM / LOW / INFORMATIONAL
    category="IAM",
    subcategory="Root Account",
    cloud_provider=CloudProvider.AWS,
    resource_id="arn:aws:iam::123456789012:root",
    resource_type="AWS::IAM::Root",
    region="global",
    account_id="123456789012",
    mitre_tactics=["Persistence", "Privilege Escalation"],
    mitre_techniques=["T1078"],
    compliance_controls={"CIS": ["1.5"], "SOC2": ["CC6.1"]},
    attack_path=AttackPath(
        steps=["Attacker obtains root credentials", "No MFA — login succeeds", "Full account takeover"],
        blast_radius="Full AWS account takeover",
        mitre_technique="T1078 — Valid Accounts",
    ),
    remediation_steps=[
        RemediationStep(order=1, description="Enable MFA for root account"),
    ],
    raw_evidence={...},                   # Raw API response for evidence
    status=FindingStatus.OPEN,
    first_seen=datetime(...),
)

Authentication

from cloudsec_audit import AWSSession

# Ambient credentials (env vars, ~/.aws/credentials, EC2/ECS instance profile)
session = AWSSession()

# Named AWS CLI profile
session = AWSSession.from_profile("prod-readonly")

# Assume an IAM role (cross-account auditing)
session = AWSSession.from_role(
    role_arn="arn:aws:iam::TARGET_ACCOUNT:role/SecurityAuditRole",
    external_id="my-external-id",   # optional, for confused deputy protection
)

# Wrap an existing boto3 session
import boto3
session = AWSSession.from_boto_session(boto3.Session(region_name="eu-west-1"))

# Validate credentials before running
session.validate()
print(f"Auditing account: {session.account_id}")

CI/CD Integration

Add to your CI pipeline to fail builds on critical findings:

# .github/workflows/cloud-audit.yml
name: Cloud Security Audit

on:
  schedule:
    - cron: "0 6 * * *"   # Daily at 06:00 UTC
  push:
    branches: [main]

jobs:
  audit:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read

    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_AUDIT_ROLE_ARN }}
          aws-region: us-east-1

      - name: Install cloudsec-audit
        run: pip install cloudsec-audit

      - name: Run security audit
        run: |
          cloudsec-audit \
            --regions us-east-1 eu-west-1 \
            --output findings.json \
            --compliance CIS SOC2 \
            --output-compliance compliance.json
        # Exit code 1 = critical/high findings found → fails the build

      - name: Upload findings
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: security-findings
          path: |
            findings.json
            compliance.json

Cross-Account Auditing

from cloudsec_audit import CloudSecAudit, AWSSession

ACCOUNTS_TO_AUDIT = [
    ("arn:aws:iam::111111111111:role/SecurityAudit", "Production"),
    ("arn:aws:iam::222222222222:role/SecurityAudit", "Staging"),
    ("arn:aws:iam::333333333333:role/SecurityAudit", "Development"),
]

all_findings = []

for role_arn, account_name in ACCOUNTS_TO_AUDIT:
    print(f"Auditing {account_name}...")
    session = AWSSession.from_role(role_arn=role_arn)

    audit = CloudSecAudit(
        session=session,
        regions=["us-east-1", "eu-west-1"],
    )
    report = audit.run()
    all_findings.extend(report.findings)
    report.to_json(f"findings-{account_name.lower()}.json")

print(f"Total findings across all accounts: {len(all_findings)}")

Roadmap

  • AWS — IAM
  • AWS — Network (Security Groups, NACLs, VPC Flow Logs)
  • AWS — Storage (S3)
  • AWS — CloudTrail / GuardDuty configuration
  • AWS — RDS, Lambda, EKS checks
  • AWS — Secrets Manager / Parameter Store exposure
  • GCP — IAM, GCS, Firewall Rules
  • Azure — RBAC, Storage Accounts, NSGs
  • Slack / PagerDuty alerting integration
  • HTML dashboard report

Required IAM Permissions

Create a read-only audit role with these permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:Get*",
        "iam:List*",
        "ec2:Describe*",
        "s3:GetBucket*",
        "s3:ListAllMyBuckets",
        "s3:GetAccountPublicAccessBlock",
        "s3control:GetPublicAccessBlock",
        "sts:GetCallerIdentity"
      ],
      "Resource": "*"
    }
  ]
}

AWS managed policy SecurityAudit also covers these permissions.


License

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cloudsec_audit-1.0.0.tar.gz (40.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cloudsec_audit-1.0.0-py3-none-any.whl (43.2 kB view details)

Uploaded Python 3

File details

Details for the file cloudsec_audit-1.0.0.tar.gz.

File metadata

  • Download URL: cloudsec_audit-1.0.0.tar.gz
  • Upload date:
  • Size: 40.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for cloudsec_audit-1.0.0.tar.gz
Algorithm Hash digest
SHA256 bbdc397832bad9ce1c6a8b4f9ef7a3cedb8e436cb909b6d9edd4ab7e65a9b32d
MD5 73b5934efa42338bc1a65bc91e28d781
BLAKE2b-256 da0ed686b5c11326fae16efefd93359c23b12eda598add0e6f3de8f0b0b53169

See more details on using hashes here.

File details

Details for the file cloudsec_audit-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: cloudsec_audit-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 43.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for cloudsec_audit-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7f78554fc2896550c15f7f46650f431eaa6ad9d98af9879ee6c6905995c163bd
MD5 069cfa443ae3f1b04907227f08eb82a1
BLAKE2b-256 22273542c0b449a30938b3a828400f976ef3ac5c41c448c0e4c6eb86372452b3

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page