Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

azure_validator — cross-validate Prowler Azure findings

A validation harness that re-checks Prowler's Azure findings with independent evidence so you can separate real issues from false positives. It mirrors the gcp_validator design: for every Prowler check it runs up to five methods and reports each verdict side-by-side plus a consensus and a false-positive / false-negative flag.

The five validation methods

# Method What it does
1 API A direct ARM read of the exact property (via Resource Graph / ARM REST).
2 Prowler replica Re-implements Prowler's exact pass/fail rule, linked to the Prowler Hub page.
3 Logs Corroborates from Azure Monitor Activity Logs (recent write operations on the resource).
4 Alternate A different signal (e.g. networkAcls.defaultAction=Deny vs publicNetworkAccess=Disabled).
5 Exposure For public-exposure checks only: attempts to reach the resource from the internet.

A method that doesn't apply returns N/A with a reason instead of a fabricated verdict. Consensus (excluding method 2) is compared to the Prowler finding → AGREE / LIKELY_FALSE_POSITIVE / LIKELY_FALSE_NEGATIVE / INCONCLUSIVE.

Install

cd azure_validator
python -m venv .venv && . .venv/bin/activate      # (Windows: .venv\Scripts\activate)
pip install -r requirements.txt

Authenticate

The tool only needs read access. Credentials are resolved in this order:

# 1. Explicit service principal (flags or env vars):
python run_all.py -s SUB --tenant-id T --client-id C --client-secret S --prowler out.json
#    ...or a certificate instead of a secret:
python run_all.py -s SUB --tenant-id T --client-id C --cert-path /path/sp.pem
#    ...or the standard env vars:
export AZURE_TENANT_ID=... AZURE_CLIENT_ID=... AZURE_CLIENT_SECRET=...

# 2. Otherwise DefaultAzureCredential (managed identity, az login, etc.):
az login
export AZURE_SUBSCRIPTION_ID=<sub-guid>

Recommended roles: Reader + Reader and Data Access, plus Monitoring Reader (method 3). Entra checks additionally need Microsoft Graph read permissions on the principal (e.g. Directory.Read.All, Policy.Read.All).

Usage

# All implemented checks, compared to a Prowler OCSF/CSV export:
python run_all.py --subscription SUB_ID --prowler prowler-output.ocsf.json -o report.xlsx

# Only Storage:
python run_all.py -s SUB_ID --service storage --prowler out.ocsf.json

# Enable the method-5 internet probe (makes real outbound connections):
python run_all.py -s SUB_ID --service storage --enable-exposure-probe

# List what's implemented:
python run_all.py --list

# Run ONE control by itself (from the azure_validator directory):
python -m checks.storage.storage_account_public_network_access_disabled -s SUB_ID --prowler out.ocsf.json

--prowler accepts Prowler's OCSF JSON or CSV. Without it, the tool validates live Azure state and reports each method's verdict.

Output

A .xlsx with a Validation sheet (one row per resource per check) and a Summary sheet, identical in shape to the GCP tool. LIKELY_FALSE_POSITIVE rows are highlighted.

Audit evidence (screenshots)

Add --evidence-dir DIR (alias --screenshots DIR) to write a per-finding PNG evidence card — the check, resource, every method's PASS/FAIL, the actual config values read from the API, a UTC capture timestamp, and an Azure Portal deep-link. The Excel also gains a hyperlinked Console Link column.

python run_all.py -s SUB --prowler out.ocsf.json --evidence-dir ./evidence
# only the exceptions worth attaching to findings:
python run_all.py -s SUB --prowler out.ocsf.json --evidence-dir ./evidence --evidence-findings-only

Images are generated headless (Pillow) from data the tool already collected, so they carry provenance (API source + timestamp) suitable as audit evidence; the deep-link lets you also grab a live Portal screenshot if a reviewer wants one.

Coverage

All 191 Azure checks across 21 services are implemented.

Service n Service n Service n
defender 26 app 20 entra 19
storage 19 monitor 15 vm 12
sqlserver 12 network 11 postgresql 10
keyvault 10 aks 8 cosmosdb 7
mysql 6 databricks 4 containerregistry 3
iam 3 recovery 2 apim/aisearch/policy/appinsights 1 each

Discovery uses Azure Resource Graph (one KQL endpoint returning full resource properties), so most property checks are a few lines; sub-resource settings (blob/file service, SQL auditing, App Service config, flexible-server parameters) are fetched via ARM REST on demand; Entra uses Microsoft Graph.

Checks reported MANUAL / best-effort

Some controls can't be proven from a single read-only ARM/Graph property, so they run what they can and mark the rest MANUAL with a reason rather than guessing. These include: Defender assessment-based checks (endpoint protection, system updates, container image scan/vulns), vm_backup_* / vm_jit_access / recovery_vault_* (Recovery Services data-plane), runtime-version "is latest" checks (app_*_version_is_latest, app_function_latest_runtime_version), function app-settings checks (App Insights, access keys, identity roles), NSG flow-log checks, apim_threat_detection_llm_jacking, and the Entra MFA / Conditional-Access / sign-in checks. Each check's docstring states its exact predicate and Hub link — worth a review against your Prowler version.

Adding a check

  1. Create checks/<service>/<check_id>.py.
  2. Subclass azval.resource_check.ResourceCheck (or a service base), set check_id, implement discover_resources() + evaluate() (and any of the five methods that apply).
  3. run_all.py discovers it automatically; python -m checks.<service>.<check_id> runs it alone.

About

Cross-validate Prowler Azure findings with 5 independent methods to cut false positives; Excel report + per-finding PNG audit evidence with Azure Portal deep-links.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages