srini-cybersec/cloudguardian
GitHub: srini-cybersec/cloudguardian
Stars: 0 | Forks: 0
# CloudGuardian
[](https://github.com/srini-cybersec/cloudguardian/actions/workflows/ci.yml)
[](LICENSE)
[](https://www.python.org/downloads/)
[](https://github.com/psf/black)
## Why CloudGuardian?
Cloud breaches almost never look like zero-days — they look like
**misconfiguration**. A public S3 bucket, an SSH port open to `0.0.0.0/0`, an
IAM policy with `Action="*" Resource="*"`. Cloud-Security-Posture-Management
(CSPM) tools catch these issues at runtime; **CloudGuardian shifts that left**
into the pull request, before the resource is ever provisioned.
It is:
- **Air-gap safe** — pure-Python, zero network calls, no telemetry. Safe for
regulated environments and offline CI runners.
- **Multi-format** — one tool for Terraform HCL, CloudFormation (YAML + JSON),
Kubernetes manifests, and standalone IAM policy documents.
- **CI/CD-native** — emits SARIF 2.1.0 for GitHub Code Scanning, plus
JSON / CSV / HTML / Rich-console formats.
- **Opinionated but tunable** — every rule has a CWE, references, compliance
mapping, and a remediation snippet. Disable any rule with one flag.
## Problem statement
Modern teams ship 100s of IaC changes per week. Reviewing every one for cloud
security best practice is impossible by hand. Existing scanners either:
- run only at runtime (too late — the breach already happened), or
- target one format (Terraform-only, Kubernetes-only), forcing teams to glue
together a half-dozen pipelines.
CloudGuardian is a single Python tool that ingests the four most common cloud
config formats and applies a unified, well-cited rule pack with a single
threshold and a single exit code.
## Architecture
┌──────────────────────────────────────────────────────────────────┐
│ CloudGuardian CLI │
│ (Click — scan / rules / stats subcommands) │
└─────────────┬───────────────────────────────────────┬────────────┘
│ │
▼ ▼
┌─────────────┐ ┌──────────────┐
│ File walker │ ──► classifier ──► │ Config │
│ (recursive) │ (TF / CFN / K8S / │ (.cloudguardian.yml +
└─────┬───────┘ IAM JSON) │ env vars + CLI flags)
│ └──────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ Parsers │
│ ┌──────────┐ ┌──────────────┐ ┌──────┐ ┌─────────┐ │
│ │ HCL/TF │ │ CloudFormation│ │ K8s │ │ IAM JSON│ │
│ │ lexer + │ │ (YAML + JSON │ │ YAML │ │ │ │
│ │ parser │ │ intrinsics) │ │ │ │ │ │
│ └──────────┘ └──────────────┘ └──────┘ └─────────┘ │
│ ──► Resource (unified schema) │
└──────────────────────────┬───────────────────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ Rule engine │
│ 25+ rules across AWS / Azure / GCP / Kubernetes │
│ Each rule: id, severity, CWE, compliance, fix │
└──────────────────────────┬───────────────────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ Reporters │
│ console (Rich) │ json │ sarif │ html │ csv │
│ + risk score (0-100) + verdict │
└──────────────────────────────────────────────────────┘
## Quick start
### Install
git clone https://github.com/srini-cybersec/cloudguardian
cd cloudguardian
pip install -e .
### Scan a directory
cloudguardian scan ./infra
╭───────────────────── CloudGuardian ─────────────────────╮
│ Tool version 1.0.0 │
│ Files scanned 4 │
│ Resources 12 │
│ Findings 9 │
│ Risk score 100 / 100 │
│ Verdict CRITICAL │
╰─────────────────────────────────────────────────────────╯
Findings by severity
┏━━━━━━━━━━┳━━━━━━━┓
┃ Severity ┃ Count ┃
┡━━━━━━━━━━╇━━━━━━━┩
│ CRITICAL │ 4 │
│ HIGH │ 3 │
│ MEDIUM │ 2 │
│ LOW │ 0 │
│ INFO │ 0 │
└──────────┴───────┘
### Emit SARIF for GitHub Code Scanning
cloudguardian scan ./infra \
--format sarif \
--output cloudguardian.sarif \
--fail-on HIGH
Wire it into Actions:
- name: CloudGuardian
run: |
pip install cloudguardian
cloudguardian scan . --format sarif --output cg.sarif --fail-on HIGH
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: cg.sarif
### List rules and stats
cloudguardian rules --cloud aws --severity HIGH
cloudguardian stats
### Docker
docker build -t cloudguardian:local .
docker run --rm -v "$(pwd):/work:ro" cloudguardian:local scan /work --fail-on HIGH
## Built-in rules (excerpt)
| ID | Cloud | Severity | Title |
|----|-------|----------|-------|
| CG-AWS-S3-001 | aws | CRITICAL | S3 bucket grants a public canned ACL |
| CG-AWS-S3-002 | aws | HIGH | S3 bucket has no server-side encryption |
| CG-AWS-S3-003 | aws | MEDIUM | S3 bucket versioning is disabled |
| CG-AWS-SG-001 | aws | CRITICAL | SG exposes SSH/RDP/DB to 0.0.0.0/0 |
| CG-AWS-SG-002 | aws | CRITICAL | SG allows ALL ports from public internet |
| CG-AWS-EBS-001 | aws | HIGH | EBS volume created without encryption |
| CG-AWS-RDS-001 | aws | HIGH | RDS instance is publicly accessible |
| CG-AWS-RDS-002 | aws | HIGH | RDS storage is not encrypted |
| CG-AWS-IAM-001 | aws | CRITICAL | IAM policy grants `*:*` admin |
| CG-AWS-IAM-002 | aws | CRITICAL | Root account access key provisioned |
| CG-AWS-EC2-001 | aws | HIGH | EC2 does not enforce IMDSv2 |
| CG-AWS-LAMBDA-001 | aws | HIGH | Lambda permission has `Principal="*"` |
| CG-AWS-CT-001 | aws | MEDIUM | CloudTrail is not multi-region |
| CG-AWS-KMS-001 | aws | MEDIUM | KMS CMK rotation disabled |
| CG-AZ-STG-001 | azure | CRITICAL | Azure storage allows public blob |
| CG-AZ-NET-001 | azure | CRITICAL | NSG exposes SSH/RDP publicly |
| CG-AZ-SQL-001 | azure | HIGH | Azure SQL allows obsolete TLS |
| CG-GCP-STG-001 | gcp | CRITICAL | GCS bucket public (allUsers) |
| CG-GCP-NET-001 | gcp | CRITICAL | GCP firewall exposes admin port |
| CG-GCP-GCE-001 | gcp | HIGH | GCE uses full cloud-platform scope |
| CG-K8S-001 | k8s | CRITICAL | Container runs privileged |
| CG-K8S-002 | k8s | HIGH | runAsNonRoot not enforced |
| CG-K8S-003 | k8s | HIGH | hostPID/hostIPC/hostNetwork enabled |
| CG-K8S-004 | k8s | HIGH | Dangerous Linux capabilities added |
| CG-K8S-005 | k8s | CRITICAL | RBAC wildcard verbs+resources |
| CG-IAM-STMT-001 | aws | HIGH | IAM statement uses wildcard Action |
| CG-IAM-STMT-002 | aws | HIGH | Allow + NotAction (deny-list trap) |
| CG-IAM-STMT-003 | aws | CRITICAL | Public Principal without Condition |
| CG-IAM-STMT-005 | aws | HIGH | Privilege-escalation primitive |
Run `cloudguardian rules` for the full live list.
## Configuration
`.cloudguardian.yml` (project-root, optional):
fail_on: HIGH
disabled_rules:
- CG-AWS-S3-004 # logging is enforced elsewhere
exclude_paths:
- .terraform/
- modules/vendor/
output_format: sarif
include_info: false
Every option also accepts an env-var override:
`CLOUDGUARDIAN_FAIL_ON`, `CLOUDGUARDIAN_DISABLED_RULES`,
`CLOUDGUARDIAN_EXCLUDE_PATHS`, `CLOUDGUARDIAN_OUTPUT_FORMAT`.
## CI/CD recipes
### Block merges on CRITICAL findings only
cloudguardian scan . --fail-on CRITICAL
Exit code is `0` if no finding meets the threshold, `1` otherwise — perfect
for `pre-commit`, `make check`, or any pipeline gate.
### Generate human-readable HTML for the PR artifacts tab
cloudguardian scan . --format html --output report.html
### Combine with `pre-commit`
repos:
- repo: local
hooks:
- id: cloudguardian
name: CloudGuardian (IaC posture)
entry: cloudguardian scan . --fail-on HIGH
language: system
pass_filenames: false
## Security considerations
CloudGuardian is **read-only** by design:
If you discover a security issue, please open a private security advisory
on GitHub rather than a public issue.
## Development
pip install -r requirements-dev.txt
pip install -e .
black src tests
ruff check src tests
mypy src
bandit -r src -ll
pytest --cov=src/cloudguardian --cov-report=term-missing
Layout:
src/cloudguardian/
├── cli.py # Click entry-point
├── config.py # YAML + env-var configuration
├── engine.py # discover → parse → evaluate → report
├── models.py # Severity, Resource, Finding, ScanReport
├── parsers/ # HCL, CloudFormation, K8s, IAM
├── rules/ # built-in rule pack (one module per cloud)
└── reporters/ # console, json, sarif, html, csv
Adding a rule is ~25 lines: see any module in `src/cloudguardian/rules/` for
the pattern.
## License
MIT — see [LICENSE](LICENSE).