Metadata-Version: 2.4
Name: presidio-hardened-scoutsuite
Version: 0.2.0
Summary: Presidio security-hardened distribution of ScoutSuite — runs the multi-cloud auditor out of process with hardened defaults, report redaction, and a least-privilege deployment model.
Project-URL: Homepage, https://github.com/presidio-v/presidio-hardened-scoutsuite
Project-URL: Source, https://github.com/presidio-v/presidio-hardened-scoutsuite
Project-URL: Upstream, https://github.com/nccgroup/ScoutSuite
Author: Presidio
License: MIT
License-File: LICENSE
Keywords: audit,aws,azure,cloud-security,gcp,hardening,scoutsuite
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Information Technology
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security
Requires-Python: >=3.9
Provides-Extra: dev
Requires-Dist: pytest-cov>=5; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: scoutsuite
Requires-Dist: scoutsuite==5.14.0; extra == 'scoutsuite'
Description-Content-Type: text/markdown

# presidio-hardened-scoutsuite

[![CI](https://github.com/presidio-v/presidio-hardened-scoutsuite/actions/workflows/ci.yml/badge.svg)](https://github.com/presidio-v/presidio-hardened-scoutsuite/actions/workflows/ci.yml)
[![CodeQL](https://github.com/presidio-v/presidio-hardened-scoutsuite/actions/workflows/codeql.yml/badge.svg)](https://github.com/presidio-v/presidio-hardened-scoutsuite/actions/workflows/codeql.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)

A Presidio security-hardened **distribution of [ScoutSuite](https://github.com/nccgroup/ScoutSuite)**,
NCC Group's multi-cloud security auditing tool.

> **Wrapper, not a fork.** ScoutSuite is **GPL-2.0**. Rather than fork or import
> it, this project drives the upstream `scout` CLI **out of process** and wraps
> it with hardened defaults, report redaction, supply-chain integrity, and a
> least-privilege deployment model. That keeps the wrapper a separate,
> non-derivative work — so *this* code is **MIT** — while you still run stock,
> trusted-upstream ScoutSuite underneath. See
> [`LICENSES/README.md`](./LICENSES/README.md).

---

## What "hardened" means here

| Axis | What you get |
|---|---|
| **Runtime credential & data safety** | Env scrubbed to cloud creds only; 0700 report dir + `umask 0077`; secrets redacted out of the report and ScoutSuite's logs; `--fail-on-secret` gate |
| **Secure-by-default policy** | Curated, CIS-aligned **AWS baseline ruleset** applied by default (high-impact IAM/logging/network controls forced to `danger`) |
| **Supply-chain & build integrity** | Hash-pinned `requirements.lock`, CycloneDX SBOM, CodeQL, Dependabot, **cosign-signed** images + build provenance; release blocked if the lock isn't pinned |
| **Hardened deployment** | Distroless, non-root, `--read-only` container; bundled **least-privilege AWS audit role** (read-only + explicit `Deny`, MFA + `ExternalId` trust) |

---

## How it works

```
presidio-scout aws ──▶ launcher ──▶ [ scout aws … ] ──▶ redact ──▶ report_guard ──▶ report/
                       (validate     (subprocess;       (scrub      (CSP + integrity
                        + harden)     env-scoped)        secrets)     manifest)
```

1. **launcher** — validates the provider + pass-through flags (fail-closed
   allowlist), forces `--no-browser` and a locked-down `--report-dir`, wires in
   the curated ruleset, and scrubs the environment.
2. **subprocess** — stock ScoutSuite runs with only the cloud credentials it
   needs.
3. **redact** — credentials are scrubbed out of the report files and ScoutSuite's
   own output.
4. **report_guard** — a strict CSP is injected into the HTML report and a
   SHA-256 integrity manifest is recorded.

---

## Install

The wrapper has **no runtime dependencies** and never imports ScoutSuite. You
supply `scout` yourself (recommended: a pinned virtualenv or the container).

```bash
pip install presidio-hardened-scoutsuite          # wrapper only (MIT)

# Convenience extra that also installs ScoutSuite (GPL-2.0) into your env:
pip install 'presidio-hardened-scoutsuite[scoutsuite]'
```

Or use the hardened container (bundles a pinned ScoutSuite):

```bash
docker run --rm --read-only --tmpfs /tmp \
  -e AWS_PROFILE=auditor \
  -v "$HOME/.aws:/tmp/.aws:ro" \
  -v "$PWD/scoutsuite-report:/report" \
  ghcr.io/presidio-v/presidio-hardened-scoutsuite:latest \
  aws --report-dir /report
```

---

## CLI usage

```bash
presidio-scout aws                          # audit AWS with the hardened defaults
presidio-scout aws --report-dir ./out       # choose the (0700) report directory
presidio-scout aws -- --profile auditor     # pass-through flags after '--' (allowlisted)
presidio-scout aws --fail-on-secret         # non-zero exit if a secret survives redaction
presidio-scout aws --no-baseline            # use ScoutSuite's default ruleset instead
presidio-scout aws --dry-run                # print the hardened command, run nothing
presidio-scout azure                        # Azure audit with the hardened Azure baseline
presidio-scout gcp                          # GCP audit with the hardened GCP baseline
```

AWS, Azure, and GCP each ship a curated baseline; other providers fall back to
ScoutSuite's default ruleset (with a warning) until their baselines land.

Anything after `--` is forwarded to ScoutSuite **only if it's on the
pass-through allowlist** (`--profile`, `--region(s)`, `--services`, `--skip`,
`--max-rate`, …). Flags the launcher owns (`--report-dir`, `--ruleset`,
`--no-browser`) and unknown flags are rejected with exit code 2 — a new upstream
flag can't silently weaken a run until it's vetted and added.

Exit codes: `0` ok · `2` invalid invocation / `scout` not found · `3` report
guard failure (e.g. `--fail-on-secret`).

---

## Library usage

```python
from presidio_scoutsuite import build_plan, run, redact_report_dir, guard_report

plan = build_plan("aws", "scoutsuite-report", ruleset="src/presidio_scoutsuite/policy/aws-cis.json")
print(plan.redacted_command())          # scout aws --no-browser --report-dir … --ruleset …

result = run(plan)                      # subprocess.CompletedProcess
redact_report_dir(plan.report_dir)      # scrub secrets out of the report
guard = guard_report(plan.report_dir)   # inject CSP + build integrity manifest
print(len(guard.manifest), "files;", len(guard.html_hardened), "HTML hardened")
```

---

## Least-privilege audit identities

ScoutSuite needs broad **read-only** access. Bundled, ready-to-apply identities
grant exactly that and nothing else, per cloud:

- **AWS** ([`iam/aws/`](./iam/aws/)) — the two managed read-only policies, a
  supplemental read policy with an explicit `Deny` on any non-read action, and a
  trust policy requiring MFA + a random `ExternalId`.
- **Azure** ([`iam/azure/`](./iam/azure/)) — `Reader` + `Security Reader` (or a
  custom `*/read` role with **no `dataActions`**, so secret/key values stay
  unreadable), plus minimal directory read for the Azure AD findings.
- **GCP** ([`iam/gcp/`](./iam/gcp/)) — `roles/viewer` +
  `roles/iam.securityReviewer` (or a custom role listing only `*.list`/`*.get`
  permissions), assumed via service-account **impersonation** over a downloaded
  key.

---

## Curated rulesets

Curated baselines ship for **AWS, Azure, and GCP** under
[`src/presidio_scoutsuite/policy/`](./src/presidio_scoutsuite/policy/)
(`aws-cis.json`, `azure-cis.json`, `gcp-cis.json`). Each enables a CIS-aligned
subset of ScoutSuite's findings and elevates the high-impact ones to `danger`.
Override with `--ruleset PATH` or opt out with `--no-baseline`.

A ruleset's keys are the **filenames** of finding rules that live inside
ScoutSuite. If a baseline names a rule the pinned ScoutSuite doesn't ship (a typo
or an upstream rename), ScoutSuite silently drops that control. To catch that,
each provider ships a rule-name inventory (`policy/<provider>.rules.txt`) tracking
the pinned upstream version, and a validator checks the baselines against it:

```bash
presidio-scout-validate                  # offline: baselines ⊆ checked-in manifests (runs in CI)
presidio-scout-validate --source installed   # release: baselines ⊆ the installed ScoutSuite
```

CI runs the offline check on every push; the release pipeline runs the
`installed` check against the pinned ScoutSuite so the manifest can't drift from
upstream unnoticed. Regenerate a manifest with
`ruleset.installed_rules("<provider>")` (see the header of each `.rules.txt`).

---

## Roadmap

| Version | Highlights |
|---|---|
| **0.1.0** | Out-of-process hardened launcher, report redaction + guard, AWS-first curated ruleset + least-privilege IAM, hardened container, full supply-chain posture |
| **0.2.0** | Azure + GCP curated baselines & least-privilege IAM; ruleset rule-name validation against the pinned ScoutSuite (offline manifest in CI, installed-source drift check at release) |
| **0.3.0** _(planned)_ | Deeper report guard (subresource integrity, offline viewer), signed report manifests |
| **0.4.0** _(planned)_ | SLSA provenance verification on pull; reproducible-build attestation |

---

## Running tests

```bash
pip install -e ".[dev]"
pytest --cov=presidio_scoutsuite --cov-report=term-missing
ruff check . && ruff format --check .
```

Tests run **without ScoutSuite installed** — the subprocess boundary is injected.

---

## Project structure

```
presidio-hardened-scoutsuite/
├── src/presidio_scoutsuite/
│   ├── launcher.py        # build/run the hardened scout subprocess
│   ├── redact.py          # secret detection + in-place redaction
│   ├── report_guard.py    # CSP injection + integrity manifest
│   ├── ruleset.py         # baseline rule-name validation (presidio-scout-validate)
│   ├── cli.py             # presidio-scout entrypoint
│   ├── errors.py          # exception hierarchy
│   └── policy/            # curated baselines (aws/azure/gcp-cis.json) + rule manifests
├── iam/{aws,azure,gcp}/   # least-privilege audit identities per cloud
├── tests/
├── Dockerfile             # distroless, non-root
├── requirements.lock      # hash-pinned runtime tree (incl. ScoutSuite)
├── .github/workflows/     # ci, codeql, sbom, release (cosign + provenance)
├── LICENSE                # MIT (this wrapper)
└── LICENSES/README.md     # GPL-2.0 notice for bundled ScoutSuite
```

---

## License

MIT for this wrapper — see [LICENSE](./LICENSE). It bundles/installs ScoutSuite
(GPL-2.0-only) separately; see [LICENSES/README.md](./LICENSES/README.md).

## Security

See [SECURITY.md](./SECURITY.md).

## SDLC

Developed under the Presidio hardened-family SDLC:
<https://github.com/presidio-v/presidio-hardened-docs/blob/main/sdlc/sdlc-report.md>.
