Skip to content

CLI Scanner

Free command-line tool to audit Azure Key Vaults for expiring secrets, certificates, and keys.


Overview

The CertifyClouds Scanner (cc-scan) is a standalone CLI tool that scans all your Azure Key Vaults across every subscription and reports:

  • Expiring and expired secrets, certificates, and keys
  • Security misconfigurations (14 built-in checks)
  • A 0-100 score using the CertifyClouds compliance rules
  • Full inventory with metadata, tags, and status

It runs locally, uses your existing Azure credentials, and never reads secret values.


Install

pip install certifyclouds
pipx install certifyclouds

Recommended if you want an isolated install that doesn't affect your system Python.

brew tap certifyclouds/certifyclouds
brew install certifyclouds

macOS and Linux. Manages Python dependencies automatically.

Requires Python 3.11+. Works on macOS, Linux, and Windows.

Azure Cloud Shell

cc-scan works out of the box in Azure Cloud Shell, Python and az login are pre-configured.


Quick Start

# 1. Sign in to Azure
az login

# 2. Run the scanner
cc-scan

On first run, you'll be prompted to register with your email (free, no password). After that, the scan runs automatically.


Commands & Flags

Output

Flag Description Default
--format Output format: table, json, csv, html table
-o, --output FILE Write output to a file instead of stdout -

Filters

Flag Description Example
--expiring N Only show items expiring within N days --expiring 30
--expired Only show already-expired items -
--type TYPE Only show: secrets, certificates, or keys --type secrets
--vault NAME Only scan specific vault(s) (repeatable) --vault prod-kv
--subscription ID Only scan specific subscription(s) (repeatable) --subscription abc-123

Security

Flag Description
--security Show security findings only (skip vault inventory)
--fail-on LEVEL Exit 1 when a finding is at or above this severity: critical, high, medium, low or never. Default high

Authentication

Flag Description Default
--auth METHOD Azure auth: cli or default cli
--key KEY API key (overrides saved config) -
--register Re-register or change email -
--offline Skip the licence server check after the scan -

Performance

Flag Description Default
--workers N Parallel scan workers (max 20) 5
--timeout N Scan timeout in seconds 300

Other

Flag Description
-v, --verbose Increase verbosity (-v info, -vv debug)
--version Show version and exit
--help Show help and exit

Environment Variables

All flags can be set via environment variables. Flags take priority over env vars.

Variable Equivalent Flag
CC_SCAN_KEY --key
CC_SCAN_FORMAT --format
CC_SCAN_AUTH --auth
CC_SCAN_WORKERS --workers
CC_SCAN_TIMEOUT --timeout
CC_SCAN_OFFLINE --offline (set to true or 1)
CC_SCAN_FAIL_ON --fail-on

Output Formats

Table (default)

Rich terminal output with a subscription tree, expiry warnings, and security findings.

cc-scan

JSON

Machine-readable output including all scan data and security findings.

cc-scan --format json
cc-scan --format json -o results.json

CSV

Flat CSV with one row per asset. Good for spreadsheets and data analysis.

cc-scan --format csv -o inventory.csv

HTML

Standalone HTML report with charts, tables, and colour-coded status. Suitable for sharing with stakeholders.

cc-scan --format html -o report.html

Security Checks

Every scan automatically runs 14 security checks:

ID Severity Finding
SEC-001 CRITICAL Expired secret still enabled
SEC-002 CRITICAL Expired certificate still enabled
SEC-003 HIGH Public network access enabled on vault
SEC-004 HIGH Soft delete disabled
SEC-005 HIGH Purge protection disabled
SEC-006 MEDIUM Secret has no expiry date
SEC-007 MEDIUM Certificate has no expiry date
SEC-008 MEDIUM RBAC authorization not enabled
SEC-009 LOW Standard SKU (no HSM backing)
SEC-010 INFO Secret expiring within 30 days
SEC-011 INFO Certificate expiring within 30 days
SEC-012 CRITICAL Expired key still enabled
SEC-013 MEDIUM Key has no expiry date
SEC-014 INFO Key expiring within 30 days

Use --security to show only findings without the full vault inventory.


Score

Every scan gets a score from 0 to 100, based on the CertifyClouds compliance checks a Key Vault scan can run.

When the scan could not read part of what a check needs, for example a vault's certificates, that check is left out and the score is marked partial. The output lists what was left out. If nothing could be read, there is no score.

The score always covers the whole scan. --type, --expiring and --expired narrow the listing, not the score. It appears in the table and HTML output, in the score object of the JSON output, and on stderr with --format csv. It does not change the exit code.


Exit Codes

For CI/CD integration. When several apply, the first one in this table wins:

Code Meaning
2 The scan could not run or read nothing: an Azure sign-in or SDK error, no subscription visible (or none matching --subscription), every subscription's Key Vault list failed, the scan timed out, or Ctrl-C
3 No API key and no terminal to register in, or registration failed
1 A finding at or above --fail-on (default high)
4 The scan finished, but some subscriptions, vaults or item types could not be read, or a subscription or vault passed to --subscription or --vault was not found
0 None of the above

An invalid or revoked API key does not change the exit code. The scanner prints a warning on stderr and finishes the scan.

Example: GitHub Actions gate

- name: Audit Key Vaults
  env:
    CC_SCAN_KEY: ${{ secrets.CC_SCAN_KEY }}
  run: |
    pip install certifyclouds
    cc-scan --format json -o results.json

This needs an Azure sign-in first. See CI/CD Integration for sign-in without a stored secret on GitHub Actions, Azure DevOps and GitLab.


Azure Permissions

The scanner is read-only. It lists vaults, then lists the secrets, certificates and keys in each vault and reads each certificate's details. It never reads a secret value or key material.

Subscription level

  • Reader on each subscription, to find the vaults and read their settings

Vault level

  • Vaults that use Azure RBAC: Key Vault Reader
  • Vaults that use access policies: List on secrets, certificates and keys, plus Get on certificates

The scanner never reads secret values

Key Vault Reader reads metadata only (names, expiry dates, tags, certificate details). It cannot read secret values or use keys. Do not use Key Vault Secrets User for scanning: it can read secret values and cannot list certificates or keys. See Microsoft's Key Vault built-in roles.

Assign roles

# Subscription-level Reader
az role assignment create \
  --assignee <your-user-or-sp> \
  --role "Reader" \
  --scope /subscriptions/<sub-id>

# RBAC vaults: Key Vault Reader (per vault, or at resource group or subscription scope)
az role assignment create \
  --assignee <your-user-or-sp> \
  --role "Key Vault Reader" \
  --scope /subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault>

# Access-policy vaults: List on secrets, certificates and keys, Get on certificates
az keyvault set-policy \
  --name <vault> \
  --object-id <your-user-or-sp-object-id> \
  --secret-permissions list \
  --certificate-permissions get list \
  --key-permissions list

Registration & API Keys

First run

On first run, cc-scan prompts for your email and registers a free API key. The key is saved to ~/.certifyclouds/config.json.

Re-register

cc-scan --register

Use a specific key

cc-scan --key cc-scan-abc1234567

Or set the environment variable:

export CC_SCAN_KEY=cc-scan-abc1234567

Offline Mode

Use --offline to skip the licence server check after the scan. That check sends the usage counts and looks for a newer version. With --offline, the scan talks only to Azure.

cc-scan --offline

--offline still needs an API key, saved or set in CC_SCAN_KEY. Without one, the scanner asks you to register, which calls the licence server.

When online, the scanner sends only aggregate counts (number of vaults, secrets, etc.) after each scan. It never sends vault names, secret names, or any identifiable data.


Updating

pip install --upgrade certifyclouds
pipx upgrade certifyclouds
brew upgrade certifyclouds

The scanner checks for updates after each scan and shows a notification when a new version is available.

Check your current version:

cc-scan --version

Troubleshooting

"No Azure credentials found"

Run az login first, or set service principal environment variables:

export AZURE_CLIENT_ID=...
export AZURE_CLIENT_SECRET=...
export AZURE_TENANT_ID=...
cc-scan --auth default

"Access denied (check RBAC permissions)"

Your identity doesn't have the required vault-level roles. See Azure Permissions above.

"Firewall restriction"

The vault's network rules are blocking your IP. You need to either:

  • Add your IP to the vault's firewall allow list
  • Connect via a VNet that has access
  • Use Azure Cloud Shell (runs inside Azure's network)

Timeout on large environments

Increase the timeout and workers:

cc-scan --timeout 600 --workers 10

"Azure SDK not installed"

The Azure SDK packages weren't installed. Reinstall:

pip install --force-reinstall certifyclouds

What's Next?

The scanner shows you the problem. CertifyClouds Pro fixes it automatically.

  • Continuous monitoring with scheduled scans and dashboards
  • Automated rotation for secrets and certificates
  • Dependency mapping: know which App Services use which secrets
  • Multi-cloud sync: propagate secrets to AWS and GCP
  • Compliance scoring and audit trail

Start a free trial