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¶
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¶
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.
JSON¶
Machine-readable output including all scan data and security findings.
CSV¶
Flat CSV with one row per asset. Good for spreadsheets and data analysis.
HTML¶
Standalone HTML report with charts, tables, and colour-coded status. Suitable for sharing with stakeholders.
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¶
Use a specific key¶
Or set the environment variable:
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.
--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¶
The scanner checks for updates after each scan and shows a notification when a new version is available.
Check your current 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:
"Azure SDK not installed"¶
The Azure SDK packages weren't installed. Reinstall:
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