Python tooling to collect Azure configuration data, evaluate it for known findings, and review the results locally in a web dashboard.
This repository currently has three main Python entry points:
azure-collect.py: connects to Azure through the Azure CLI and writes collected JSON datasets to disk.azure-findings.py: reads the collected JSON and evaluates it against a library of predefined checks, then writes findings output.azure-present.py: starts a local Flask dashboard for browsing collected datasets and findings.
The normal workflow is:
- Run
azure-collect.pyto gather raw data. - Run
azure-findings.pyto generate findings from that data. - Run
azure-present.pyto inspect the datasets and findings in a browser.
Example installation steps:
apt install pipenv
curl -fsSL 'https://azurecliprod.blob.core.windows.net/$root/deb_install.sh' | sudo bash
git clone https://github.com/yg-ht/azure-assess.git
cd azure-assess
pipenv install -r requirements.txtYou may also want to pre-emptively install / re-install the Az CLI extensions. This can be done with:
AZURE_EXTENSION_DIR="$PWD/.azure-cliextensions" pipenv run bash -lc '
set -euo pipefail
EXT_DIR="${AZURE_EXTENSION_DIR:?AZURE_EXTENSION_DIR must be set}"
EXTS=(
application-insights
bastion
databricks
datafactory
ml
)
echo "[*] Using Azure CLI:"
az version --output jsonc
echo "[*] Using extension dir: $EXT_DIR"
mkdir -p "$EXT_DIR"
for ext in "${EXTS[@]}"; do
echo "[*] Removing extension: $ext"
az extension remove --name "$ext" --only-show-errors >/dev/null 2>&1 || true
rm -rf "$EXT_DIR/$ext"
done
az config set extension.use_dynamic_install=no --only-show-errors >/dev/null
for ext in "${EXTS[@]}"; do
echo "[*] Installing extension: $ext"
az extension add --name "$ext" --yes --only-show-errors
done
echo "[*] Installed extensions:"
az extension list --query "[].{name:name,version:version,path:path}" --output table
echo "[*] Verifying Azure ML command group:"
az ml --help >/dev/null
echo "[OK] Azure CLI extensions reinstalled cleanly and az ml loads"
'```
## Script Reference
### `azure-collect.py`
Purpose:
Collect JSON configuration data from the target Azure tenant or subscription and save it into an output directory. This is the raw data capture stage for the rest of the tooling.
Typical usage:
```bash
mkdir -p ~/azure-collect-data
pipenv run python azure-collect.py -o ~/azure-collect-dataParameters:
-o,--output-dir: directory where collected JSON files are written. Default:azure-collect-d,--debug: enable debug output-e,--endpoint: collect only endpoints matching the supplied text instead of collecting everything-l,--listendpoints: list all non-parameterised endpoints and exit-L,--listparamendpoints: list all parameterised endpoints and exit-n,--donotenrich: disable enrichment steps and perform enumeration only-p,--paramendpointsonly: collect only parameter-driven datasets--auth-method: authentication mode for Azure CLI. Supported values:existing,device-code,browser,service-principal,managed-identity. Default:existing--tenant-id: Azure tenant ID for login and/or context selection. Defaults toAZURE_TENANT_ID--subscription-id: Azure subscription ID to select after authentication. Defaults toAZURE_SUBSCRIPTION_ID--client-id: service principal or user-assigned managed identity client ID. Defaults toAZURE_CLIENT_ID--client-secret: service principal client secret. Defaults toAZURE_CLIENT_SECRET--client-certificate: certificate path for service principal auth. Defaults toAZURE_CLIENT_CERTIFICATE_PATH--client-certificate-password: certificate password for service principal auth. Defaults toAZURE_CLIENT_CERTIFICATE_PASSWORD
Notes:
- The script expects the Azure CLI to be installed and available on
PATH. - Some collection endpoints require Azure CLI extensions, such as
application-insightsandazure-iot. The script enables Azure CLI dynamic extension install and will also tryaz extension add --name <extension>when Azure CLI reports a missing extension. - The default authentication mode is
existing, which reuses the current Azure CLI session and does not trigger a login flow. - If
--auth-method existingis used and no valid Azure CLI session is present, the tool exits with guidance instead of forcing device code authentication. - Authentication validation checks both the current Azure account context and token acquisition for Azure Resource Manager and Microsoft Graph before collection starts.
--subscription-idapplies the Azure CLI account context after authentication and can also be supplied throughAZURE_SUBSCRIPTION_ID.- Output files are timestamped in their filenames, which is used by the dashboard to track dataset history.
Authentication examples:
# Reuse an existing Azure CLI session
az login
pipenv run python azure-collect.py --auth-method existing
# Trigger device code login explicitly
pipenv run python azure-collect.py --auth-method device-code --tenant-id <tenant-id>
# Trigger browser-based login explicitly
pipenv run python azure-collect.py --auth-method browser --tenant-id <tenant-id>
# Use service principal credentials from environment variables
export AZURE_TENANT_ID=<tenant-id>
export AZURE_CLIENT_ID=<client-id>
export AZURE_CLIENT_SECRET=<client-secret>
export AZURE_SUBSCRIPTION_ID=<subscription-id>
pipenv run python azure-collect.py --auth-method service-principal
# Use a user-assigned managed identity
export AZURE_CLIENT_ID=<managed-identity-client-id>
pipenv run python azure-collect.py --auth-method managed-identity --subscription-id <subscription-id>Purpose:
Analyse the JSON produced by azure-collect.py, print a status summary for all checks, and generate SARIF output for the findings in the found state.
Typical usage:
pipenv run python azure-findings.py -i ~/azure-collect-dataParameters:
-i,--input-dir: directory containing JSON produced byazure-collect.py. Default:azure-collect-o,--output-file: path for the SARIF 2.1.0 findings output. Default:<input-dir>/azure-findings.json--no-save: do not write findings JSON files; print summary output only--flat-output-file: path for the flattened findings output used byazure-present.py. Default:<input-dir>/azure-findings-flat.json
Outputs:
azure-findings.json: SARIF 2.1.0 output containing the full set of findings in thefoundstateazure-findings-flat.json: flattened findings rows for easier dashboard display
Purpose: Run a local web interface for browsing the collected datasets and findings output. The dashboard now groups timestamped dataset versions and defaults to the latest collected snapshot for each dataset type.
Typical usage:
pipenv run python azure-present.py -i ~/azure-collect-dataParameters:
-i,--input-dir: directory containing collected JSON and optional findings output. Default:azure-collect
Notes:
- The Flask app listens on
127.0.0.1:5000. - The dashboard shows the latest dataset snapshot by default and allows switching to older timestamped versions where available.
- If
azure-findings-flat.jsonexists in the input directory, findings are also available through the dashboard.
mkdir -p ~/azure-collect-data
pipenv run python azure-collect.py -o ~/azure-collect-data
pipenv run python azure-findings.py -i ~/azure-collect-data
pipenv run python azure-present.py -i ~/azure-collect-dataThen open http://127.0.0.1:5000/ in a browser.