Skip to content
 
 

Latest commit

 

History

570 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

    _     ______   _ ____  _____
   / \   |__  / | | |  _ \| ____|
  / _ \    / /| | | | |_) |  _|
 / ___ \  / /_| |_| |  _ <| |___
/_/   \_\/____|\___|_| \_\_____|
    _    _   _    _    _  __   ____________ ____
   / \  | \ | |  / \  | | \ \ / /__  / ____|  _ \
  / _ \ |  \| | / _ \ | |  \ V /  / /|  _| | |_) |
 / ___ \| |\  |/ ___ \| |___| |  / /_| |___|  _ <
/_/   \_\_| \_/_/   \_\_____|_| /____|_____|_| \_\

azure-analyzer

CI CodeQL License: MIT

One PowerShell command, 38 read-only assessment tools (+ 1 opt-in), one unified HTML and Markdown report. Cloud-first by default: target remote GitHub and Azure DevOps repositories without cloning anything by hand.

Sample Reports

What you get

  • Unified findings JSON with Schema 2.2 metadata (severity, frameworks, MITRE mappings, remediation snippets, evidence URIs, entity references, deep links).
  • Interactive HTML report with sortable findings tree, framework heatmap, CSV export.
  • Markdown report for Git commit workflows.
  • Entity store (JSON) with deduplicated cross-tool findings.
  • Resilience map renderer (Track B) with tier-aware heatmap cells, edge-style resolution, blast-radius traversal, and graceful RTO/RPO overlay fallback.
  • External Attack Surface Management (EASM, in flight): passive perimeter discovery from typosquats (DNSTwist) and, in follow-up PRs, subdomain enumeration (Amass / Subfinder), host probing (httpx), commercial scans (Shodan / Censys), and Microsoft Defender EASM workspace consumption. Findings correlate back to existing AzureResource entities or fall back to a new ExternalAsset bucket. See docs/design/easm-integration.md.
  • Graph mapping (in flight): Conditional Access policy graph (R1, enabled) emits ConditionalAccessPolicy entities plus AppliesTo / Excludes edges to users, groups, applications, and named locations, alongside a five-rule risk rubric for disabled-covers-privileged, GA-excluded-from-MFA, report-only stagnation, oversized break-glass, and no-strong-control gaps. Pre-registered family for follow-up PRs: AzureHound, BloodHound CE, ROADrecon, GraphRunner, PIM eligibility / activation graph, Microsoft Entra Permissions Management, and Semperis Forest Druid. See docs/design/graph-mapping-integration.md.
  • Optional local findings viewer scaffold (-Show) that starts on 127.0.0.1 with a session token and health probe.

Quickest start

From PSGallery (once published)

The module manifest, tags, and release pipeline are PSGallery-ready. The first release tag (v*.*.*) on main triggers the release.yml PSGallery publish step, which uploads AzureAnalyzer.psd1 + AzureAnalyzer.psm1 (plus the manifest-listed runtime files) under the AzureAnalyzer package id. Once the first publish lands, this is the recommended install path:

Install-Module -Name AzureAnalyzer -Scope CurrentUser
Import-Module AzureAnalyzer
Connect-AzAccount -TenantId "<tenant-id>"
Invoke-AzureAnalyzer -SubscriptionId "<subscription-id>"

PSGallery ships only the orchestrator and report renderers. Every external scanner (azqr, PSRule, Maester, Trivy, ...) is a soft dependency and is fetched on demand by the manifest-driven installer at first run. See the External tools (soft dependencies) section below for the full list of what is installed where.

From source checkout

git clone https://github.com/martinopedal/azure-analyzer.git && cd azure-analyzer
Import-Module .\AzureAnalyzer.psd1
Connect-AzAccount -TenantId "<tenant-id>"
Invoke-AzureAnalyzer -SubscriptionId "<subscription-id>"  # outputs to output/, report.html, report.md

Without Azure credentials (fixture mode)

# Run against bundled test fixtures, no Azure login required
.\Invoke-AzureAnalyzer.ps1 -FixtureMode -OutputPath .\output-fixture

Produces real results.json, entities.json, HTML and Markdown reports from fixture data in tests/fixtures/. Useful for contributors, CI pipelines, and demo environments without cloud credentials. Use -FixturePath <dir> to supply custom fixtures.

Auditor Mode

Generate control-centric compliance reports with evidence-grade citations and framework coverage:

# Run with Auditor profile
Invoke-AzureAnalyzer -SubscriptionId "<subscription-id>" -Profile Auditor

# Outputs:
#   output/audit-report.html      - Auditor-focused HTML with control-domain sections
#   output/audit-report.md         - Markdown audit report variant
#   output/audit-evidence/*.csv    - Evidence exports (CSV, JSON, XLSX)
#   output/audit-evidence/*.json
#   output/audit-evidence/*.xlsx

Auditor mode produces:

  • Executive summary with scope, methodology, and severity distribution
  • Control-domain sections grouped by framework (CIS, NIST, MCSB, ISO 27001)
  • Attack-path and blast-radius analysis from Track A/B data
  • Policy coverage vs. ALZ reference gaps
  • Remediation appendix grouped by finding type
  • Evidence exports sanitized of all credentials

See docs/design/track-f-auditor-redesign.md for the full design.

See docs/getting-started for installation, first run, and common scenarios →

Feature highlights
  • 38 tools (+ 1 opt-in) across Azure (azqr, PSRule, Powerpipe, AzGovViz, Prowler, Defender for Cloud, ...), Entra (Maester, Identity Correlator, ...), GitHub (gitleaks, Trivy, Scorecard, zizmor), and Azure DevOps (pipeline security, service connections, repos).
  • Schema 2.2 metadata: Frameworks, Pillar, Impact, Effort, DeepLinkUrl, RemediationSnippets, EvidenceUris, BaselineTags, MitreTactics, MitreTechniques, EntityRefs, ToolVersion.
  • Phase 0 foundation contract: report architecture is selected with explicit thresholds and headroom, output/report-manifest.json captures picker and verification metadata, and normalizers can contribute edges through optional EdgeCollector introspection without breaking legacy signatures.
  • Attack-path renderer (Track A): AttackPathRenderer now emits a tier-aware Cytoscape model/data-island with a shared edge budget report, finding pivot map, and hydration hints for Tier 1-4.
  • Policy enforcement track (Track C): ALZ hierarchy fuzzy-match scoring (Round 2 weights), vendored AzAdvertizer + ALZ catalog lookups, AzGovViz policy-edge emission (PolicyAssignedTo, PolicyEnforces, ExemptedFrom, InheritsFrom), and policy metadata in report-manifest.json (policy.alz.mode). Use -AlzReferenceMode {Auto|Force|Off} to control ALZ suggestion activation.
  • Read-only everywhere. No write permissions on any cloud. See PERMISSIONS.md for exact scopes.
  • HTML and Markdown reports with executive summary, top recommendations, heatmap, framework coverage matrix, filtering, and CSV export.
  • Manifest-driven installer: Run with -InstallMissingModules to auto-fetch prerequisites (PSGallery modules, allow-listed package managers, HTTPS-only git clones).
  • Hardened Log Analytics sink errors: sink failures now use structured New-FindingError messages with mandatory remediation and credential-safe details, and sink raw-throw regressions are ratcheted in tests.
  • Uniform correlator dispatch: identity-correlator now uses a thin Invoke-* wrapper entrypoint while keeping correlation logic in shared modules.
  • Shared credential sanitization contract: CI watchdog issue-body generation now reuses modules/shared/Sanitize.ps1::Remove-Credentials (no local sanitizer drift).
  • Pre-flight required-input resolution: required tool inputs are collected before dispatch using CLI > environment > prompt > fail-fast with non-interactive safety.
  • Consistent wrapper error exits: Falco, KubeBench, Kubescape, DefenderForCloud, Gitleaks, AksKarpenterCost, and AksRightsizing now emit structured New-FindingError/Format-FindingErrorMessage throws instead of raw throw strings.
  • Repo input consistency: repo-scoped wrappers now use -RepoPath (local) and -RemoteUrl (remote) as canonical inputs, with legacy aliases preserved for compatibility.
  • Mandatory scanner-param prompts (#426): when a scanner is selected but its mandatory parameter is missing, Read-MandatoryScannerParam resolves it via env var (AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID, ADO_ORG, GITHUB_REPOSITORY, AZUREANALYZER_REPO_PATH) or interactive prompt. CI / -NonInteractive runs skip the scanner with a sanitized warning instead of failing late inside the underlying tool.
  • Safer dry-runs for side-effecting wrappers: Invoke-Falco and elevated Invoke-AksKarpenterCost now support -WhatIf/-Confirm (SupportsShouldProcess) before cluster install/elevated kubectl actions.
  • ADO consumption parameter consistency: Invoke-AdoConsumption now uses canonical -AdoOrg / -AdoProject names, with legacy -Organization / -Project aliases retained for backward compatibility.
  • Opt-in LLM triage scaffold: defaults to 3-model rubberduck consensus, discovers your available Copilot models at runtime (gh copilot models list), supports -TriageModel Auto|Explicit:<model-id> plus explicit -SingleModel opt-out, and applies credential sanitization on prompt + response paths.
Tool catalog (38 enabled + 1 opt-in)

See docs/reference/tool-catalog.md. The catalog documents each tool's scope axis (subscription, managementGroup, tenant, repository, ado, or workspace), which maps directly to the -SubscriptionId / -ManagementGroupId / -TenantId / -RepoPath (or -RemoteUrl) / -AdoOrg / -WorkspaceResourceId parameters on Invoke-AzureAnalyzer.ps1.

Tool output audit (Track D)

See docs/tool-output-audit.md and docs/tool-output-audit.json for per-tool wrapper-vs-normalizer field-coverage entries (audit-first input for #432b FindingRow extension).

External tools (soft dependencies)

The PSGallery package ships only the orchestrator wrappers, normalizers, report renderers, and tools/tool-manifest.json. It does not bundle the upstream scanners. At first run, Install-PrerequisitesFromManifest (in modules/shared/Installer.ps1) reads the manifest and installs each enabled tool through one of four kinds:

install.kind What it does Where it lands
psmodule Install-Module from PSGallery (with retry + 300s timeout) User scope module path
cli Allow-listed package manager (winget / brew / pipx / pip / snap) Manager-specific install location
gitclone HTTPS-only git clone against the host allow-list (github.com, dev.azure.com, *.visualstudio.com, *.ghe.com) tools/_vendored/<tool>/
none Pure PowerShell or REST against an existing SDK / CLI; nothing to install n/a

Every install path is wrapped in Invoke-WithInstallRetry + Invoke-WithTimeout so a stuck winget / brew session cannot hang the orchestrator. Failures throw structured New-InstallerError records (with Category, Remediation, and a sanitized Details payload) and the affected tool is skipped, not the whole run.

To install everything up front instead of lazily on first use:

Invoke-AzureAnalyzer -InstallMissingModules ...

Tool inventory by provider and scope

The 38 enabled tools (+ 1 opt-in) break down as follows. The full per-tool catalog with parameters, frameworks, and required scopes lives in docs/reference/tool-catalog.md; permissions lives in PERMISSIONS.md and docs/consumer/permissions/.

Azure (subscription / management group / workspace, Reader baseline)

psmodule install kind unless noted.

Tool Scope Install What it scans
azqr subscription cli Azure Quick Review posture across resource types
psrule subscription psmodule PSRule for Azure rule pack
powerpipe subscription cli Powerpipe compliance benchmarks (CIS, NIST, PCI)
prowler subscription cli Prowler Azure security posture
defender-for-cloud subscription psmodule Defender for Cloud recommendations + secure score
finops subscription psmodule Idle resource detection (FinOps signals)
azure-cost subscription psmodule Azure Consumption API top-N cost hotspots
azure-quota subscription cli Quota and usage reports
appinsights subscription psmodule Application Insights performance signals
loadtesting subscription psmodule Azure Load Testing failed and regressed runs
falco subscription psmodule Falco AKS runtime anomaly detection (helm install opt-in)
kubescape subscription cli Kubescape AKS posture
kube-bench subscription none kube-bench AKS node CIS compliance (kubectl Job)
aks-rightsizing subscription psmodule Container Insights utilization + size recommendations
aks-karpenter-cost subscription psmodule Karpenter consolidation + node utilization (opt-in elevated RBAC)
sentinel-coverage workspace psmodule Microsoft Sentinel coverage and posture
sentinel-incidents workspace psmodule Microsoft Sentinel active incidents
azgovviz managementGroup gitclone AzGovViz tenant governance + policy report
alz-queries managementGroup psmodule ALZ Resource Graph compliance queries (50+)
wara subscription psmodule Well-Architected Reliability Assessment

Microsoft 365 / Microsoft Graph (tenant, Graph read-only scopes)

Tool Provider Install What it scans
maester microsoft365 psmodule Maester Entra and M365 security baseline
identity-correlator graph psmodule Cross-source identity correlation (Entra + Azure RBAC)
identity-graph-expansion graph psmodule Identity graph expansion (group, role, app assignments)
conditional-access-graph graph psmodule Conditional Access policy graph + 5-rule risk rubric

Disabled-by-default Graph family (scaffolded for follow-up PRs): azurehound, bloodhound-ce, roadrecon, graphrunner, pim-graph, entra-permissions-mgmt, forest-druid. See docs/design/graph-mapping-integration.md.

GitHub (repository, read-only PAT or unauthenticated)

Tool Provider Install What it scans
scorecard github cli OpenSSF Scorecard threshold check
gh-actions-billing github cli GitHub Actions minutes + monthly budget governance
gitleaks cli cli gitleaks secrets scanner (cloud-first via RemoteClone.ps1)
trivy cli cli Trivy vulnerability scanner (filesystem or repo)
zizmor cli cli zizmor GitHub Actions YAML scanner
bicep-iac cli cli Bicep IaC validation
terraform-iac cli cli Terraform IaC validation
infracost cli cli Infracost IaC cost estimation

Azure DevOps (org / project, read-only PAT)

install.kind = none for every ADO tool: pure REST through an existing PAT.

Tool Scope What it scans
ado-pipelines ado Pipeline security posture (auth modes, approvals, secrets)
ado-connections ado Service connection inventory + auth posture
ado-repos-secrets ado Repos secret scanning (gitleaks-driven)
ado-pipeline-correlator ado Cross-pipeline run correlator (ties findings to runs)
ado-consumption ado Pipeline consumption + monthly budget governance

EASM (tenant, internet-perimeter)

dnstwist (cli) ships enabled. The remaining EASM family (amass, subfinder, httpx, shodan, censys, defender-easm) is scaffolded as enabled: false for follow-up PRs. See docs/design/easm-integration.md.

Optional, opt-in

Tool Trigger Notes
copilot-triage -EnableAiTriage Routes findings through GitHub Copilot for AI triage; defaults to a 3-model rubberduck consensus, discovers your available models at runtime, applies credential sanitization on prompt + response paths.

The single source of truth is tools/tool-manifest.json. If you want to add or toggle a tool, edit the manifest and the catalog, README counts, and PERMISSIONS index regenerate automatically through tools/Update-ToolPins.ps1 (weekly bumper) or by running the three generators by hand. See docs/reference/tool-catalog-contributor.md for the contributor view.

All parameters and advanced usage

See docs/reference/orchestrator-params.md for every Invoke-AzureAnalyzer.ps1 parameter, plus scenario-specific grouping (subscription scan, repo scan, multi-tenant, CI/CD, Kubernetes). After Import-Module .\AzureAnalyzer.psd1, Invoke-AzureAnalyzer now exposes the same typed parameters in Get-Command / Get-Help as the script entrypoint.

Environment variables

azure-analyzer honours a small set of opt-in environment variables for CI / quiet-mode use:

  • AZUREANALYZER_NO_BANNER=1 -- suppress the ASCII banner. Also auto-suppressed when CI=true or GITHUB_ACTIONS=true.
  • AZURE_ANALYZER_SUPPRESS_TOOL_MISSING_WARNINGS=1 -- silence <tool> is not installed. Skipping... notices from every wrapper. Routes through Write-Verbose instead. Belt-and-suspenders kill-switch for noisy CI / Pester transcripts (#472). Truthy values: 1, true, yes, on (case-insensitive).
  • AZURE_ANALYZER_ORCHESTRATED=1 (set automatically by Invoke-AzureAnalyzer.ps1) -- tells wrappers they were launched by the orchestrator, not standalone.
  • AZURE_ANALYZER_EXPLICIT_TOOLS=trivy,gitleaks,... (set automatically) -- comma-separated CSV of tools the user named via -IncludeTools. Empty when no filter was passed.

Contributing

See docs/contributing/ to add a new tool, extend the orchestrator, or contribute documentation. The architecture docs cover how azure-analyzer works under the hood, and design proposals belong under docs/design/.

Testing

  • Invoke-Pester -Path .\tests -CI: full Pester suite (baseline is enforced by tests/workflows/PesterBaselineGuard.Tests.ps1 and grows over time).
  • Invoke-Pester -Path .\tests\wrappers -CI: wrapper contract suite, including E2E wrapper-to-normalizer coverage for zizmor, gitleaks, and trivy.
  • Invoke-Pester -Path .\tests\wrappers -Tag 'LiveTool' -CI: optional live-CLI wrapper smoke tier (gitleaks, trivy, zizmor, scorecard) that exercises real binaries when present and enforces deterministic v1 envelopes (Findings is always an array).
  • Invoke-Pester -Path .\tests\e2e -Output Detailed: end-to-end harness that drives Invoke-AzureAnalyzer's output pipeline (FindingRow → EntityStore → results.json + entities.json → HTML + Markdown reports) across three surfaces (Azure subscription, GitHub repo, Tenant / management-group) with synthetic fixtures under tests/e2e/fixtures/.
  • Invoke-Pester -Path .\tests\wrappers\MissingToolRuntime.Tests.ps1: cross-platform runtime coverage for missing-tool behavior in Invoke-Trivy, Invoke-Kubescape, and Invoke-Scorecard.
  • Invoke-Pester -Path .\tests\e2e\WrapperCoverageParity.Tests.ps1 -CI: validates E2E wrapper coverage tracker stays in lockstep with tools/tool-manifest.json.
  • Invoke-Pester -Path .\tests\shared\TestIsolation.Tests.ps1 -CI: guard rail for cross-file state leaks.

CI notes

  • Required status check: Analyze (actions), the only check enforced in branch protection. PowerShell is not scanned by CodeQL (no supported extractor); Actions scanning covers workflow injection risks.
  • Auto-Rebase and Rerun-Failed-Checks skip on non-agent branches: The PR Auto-Rebase Conflicts and PR Auto-Rerun On Push workflows only trigger on agent-owned branch prefixes (squad/, copilot/, fix/, feat/, ci/, docs/). If you push from a branch without one of these prefixes, the workflows will show as skipped. This is expected behavior, not a failure.
  • Manifest hygiene: keep tools/tool-manifest.json entries alphabetized by tool name (case-insensitive); this is enforced by tests/manifest/Manifest.Sorted.Tests.ps1.
  • CodeQL (Analyze (actions)) uses a global workflow concurrency queue to reduce GitHub App installation API throttling during PR bursts.
  • Workflow hotfix-debt contract: every .github/workflows/*.yml continue-on-error: true directive must carry an inline tracking marker comment (# tracked: martinopedal/azure-analyzer#604 - hotfix-debt) immediately above it.
  • Markdown Check hardening: the links (lychee) job scopes PR runs to changed Markdown files (scheduled/manual runs still scan the full corpus), clears .lycheecache between retry attempts, and passes GITHUB_TOKEN to reduce transient GitHub/rate-limit flakes.
  • Scheduled Scan requires OIDC repo variables (AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID, AZURE_CLIENT_ID). Scheduled runs skip analyzer execution without going red when these variables are not configured; manual dispatch still fails fast on missing or malformed values.
Maintainer notes

See CONTRIBUTING.md for full CI workflow and squad infrastructure (maintainer-only) documentation. The docs/contributor/ directory covers contributor setup and development workflows. The .squad/ and .copilot/skills/ subtrees contain AI team coordination state and are excluded from archive downloads. They are not part of the shipped tool.

Maintainer notes

See CONTRIBUTING.md for full CI workflow and squad infrastructure (maintainer-only) documentation. The docs/contributor/ directory covers contributor setup and development workflows. The .squad/ and .copilot/skills/ subtrees contain AI team coordination state and are excluded from archive downloads. They are not part of the shipped tool.

About

Automated Azure assessment bundling azqr, PSRule, AzGovViz and ALZ graph queries

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages