Multi-cloud security and cost swiss army knife — single binary, zero dependencies.
Audit IAM permissions, spot cost anomalies, find orphaned resources, flag insecure storage, detect overly permissive firewall rules, monitor TLS certificate expiry, enforce resource tagging, check service quota utilization, save and compare scan baselines, generate HTML reports, and more — across AWS, GCP, and Azure.
brew install stxkxs/tap/matlockgo install github.com/stxkxs/matlock@latestPre-built binaries for Linux, macOS, and Windows are attached to every GitHub release.
# macOS arm64 example
curl -sSL https://github.com/stxkxs/matlock/releases/latest/download/matlock_Darwin_arm64.tar.gz \
| tar -xz matlock
sudo mv matlock /usr/local/bin/Verify the download against the published SHA256 checksums:
curl -sSL https://github.com/stxkxs/matlock/releases/latest/download/checksums.txt | sha256sum --check --ignore-missingRequires Go 1.26+ and Task.
git clone https://github.com/stxkxs/matlock.git
cd matlock
task buildmatlock auto-detects available providers from environment variables and credential files. You only need to configure the providers you actually use.
matlock uses the standard AWS SDK credential chain.
# Option 1 — environment variables
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_REGION=us-east-1
# Option 2 — named profile
export AWS_PROFILE=my-profile
export AWS_REGION=us-east-1
# Option 3 — IAM role / instance metadata (no env vars needed)Required IAM permissions for a read-only audit role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:List*",
"iam:Get*",
"cloudtrail:LookupEvents",
"ce:GetCostAndUsage",
"ec2:Describe*",
"elasticloadbalancing:Describe*",
"s3:ListAllMyBuckets",
"s3:GetBucketAcl",
"s3:GetBucketEncryption",
"s3:GetBucketVersioning",
"s3:GetBucketLogging",
"s3:GetBucketPublicAccessBlock",
"s3:GetBucketTagging",
"acm:ListCertificates",
"acm:DescribeCertificate",
"rds:DescribeDBInstances",
"lambda:ListFunctions",
"lambda:GetFunction",
"lambda:ListTags",
"lambda:GetAccountSettings",
"iam:GetAccountSummary",
"servicequotas:GetServiceQuota",
"servicequotas:ListServiceQuotas"
],
"Resource": "*"
}
]
}# Option 1 — application default credentials (gcloud)
gcloud auth application-default login
# Option 2 — service account key
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json
export GOOGLE_CLOUD_PROJECT=my-project-id
# Required for cost diff
export GOOGLE_BILLING_ACCOUNT_ID=XXXXXX-XXXXXX-XXXXXXRequired IAM roles for the service account:
roles/iam.securityReviewerroles/logging.viewerroles/billing.viewerroles/storage.objectViewerroles/compute.viewerroles/certificatemanager.viewer(formatlock certs)compute.projects.getpermission (formatlock quota)
# Option 1 — Azure CLI
az login
export AZURE_SUBSCRIPTION_ID=...
# Option 2 — service principal
export AZURE_TENANT_ID=...
export AZURE_CLIENT_ID=...
export AZURE_CLIENT_SECRET=...
export AZURE_SUBSCRIPTION_ID=...Required role assignments:
Readeron the subscriptionCost Management Readeron the subscriptionKey Vault Reader+Key Vault Certificates Officer(orKey Vault Readerif using RBAC-enabled vaults) formatlock certs
Compares granted permissions against CloudTrail / Audit Log activity over the lookback window and reports unused, admin, and cross-account risks.
# Scan all auto-detected providers (90-day lookback)
matlock iam scan
# AWS only, last 30 days, show CRITICAL and HIGH only
matlock iam scan --provider aws --days 30 --severity HIGH
# Scan a specific principal
matlock iam scan --provider gcp --principal serviceAccount:scanner@my-project.iam.gserviceaccount.com
# JSON output for downstream tooling
matlock iam scan --output json --output-file report.json
# SARIF output for GitHub Advanced Security
matlock iam scan --output sarif --output-file results.sarif
# Increase parallelism for large accounts
matlock iam scan --concurrency 20Flags
| Flag | Default | Description |
|---|---|---|
--provider |
auto | Cloud providers to scan: aws, gcp, azure |
--days |
90 |
Audit log lookback window in days |
--principal |
Scan a single principal by name or ID | |
--severity |
LOW |
Minimum severity to report: CRITICAL, HIGH, MEDIUM, LOW, INFO |
--output |
table |
Output format: table, json, sarif |
--output-file |
Write output to file instead of stdout | |
--concurrency |
10 |
Maximum parallel goroutines per provider |
--profile |
AWS named profile to use for credentials |
Reads a JSON scan report and generates least-privilege Terraform policy files for each flagged principal.
# Generate fixes for all HIGH+ findings
matlock iam fix --from report.json
# Write fixes to a custom directory
matlock iam fix --from report.json --out ./tf-fixes
# Include MEDIUM severity fixes too
matlock iam fix --from report.json --severity MEDIUMWorkflow
matlock iam scan --output json --output-file report.json
matlock iam fix --from report.json --out ./fixes
ls ./fixes/
# minimal_lambda_executor.tf
# minimal_my_project_scanner_at_my_project_iam_gserviceaccount_com.tfFlags
| Flag | Default | Description |
|---|---|---|
--from |
(required) | Path to JSON report from matlock iam scan --output json |
--format |
terraform |
Output format: terraform, json |
--out |
./matlock-fixes |
Output directory for generated files |
--severity |
HIGH |
Minimum severity to generate fixes for |
Compares cloud spend between the last N days and the N days before that, surfacing unexpected increases service by service.
# Compare last 30 days vs the 30 days before
matlock cost diff
# 7-day comparison, AWS only
matlock cost diff --provider aws --days 7
# JSON output for alerting pipelines
matlock cost diff --output jsonFlags
| Flag | Default | Description |
|---|---|---|
--provider |
auto | Cloud providers to query |
--days |
30 |
Compare last N days vs N days before |
--threshold |
0 |
Only show services with >N% change (e.g. --threshold 20) |
--output |
table |
Output format: table, json |
--output-file |
Write output to file instead of stdout |
Cost increases >10% are shown in red; decreases are shown in green.
Finds unattached disks, reserved IPs with no instance, and idle load balancers. Reports estimated monthly cost.
# All providers
matlock orphans
# Only report resources costing more than $5/month
matlock orphans --min-cost 5
# JSON for Slack/PagerDuty integration
matlock orphans --output jsonFlags
| Flag | Default | Description |
|---|---|---|
--provider |
auto | Cloud providers to scan |
--min-cost |
0 |
Only report orphans with monthly cost above this USD threshold |
--output |
table |
Output format: table, json |
--output-file |
Write output to file instead of stdout |
The table includes a TOTAL row summing all monthly costs.
Audits object storage for public access, missing encryption, disabled versioning, and missing access logging.
# All providers
matlock storage audit
# HIGH and CRITICAL findings only
matlock storage audit --severity HIGH
# JSON for SIEM ingestion
matlock storage audit --output json --output-file storage-findings.jsonFlags
| Flag | Default | Description |
|---|---|---|
--provider |
auto | Cloud providers to scan |
--severity |
LOW |
Minimum severity to report |
--output |
table |
Output format: table, json |
--output-file |
Write output to file instead of stdout |
Checks security groups (AWS), firewall rules (GCP), and network security groups (Azure) for rules that expose sensitive ports to the internet.
Severity rules:
- CRITICAL —
0.0.0.0/0on SSH (22), RDP (3389), or database ports (3306, 5432, 1433, 27017, 6379, 9200) - HIGH —
0.0.0.0/0on any non-HTTP/HTTPS port - MEDIUM — unrestricted egress (all traffic to
0.0.0.0/0)
# All providers
matlock network audit
# AWS only, show CRITICAL findings
matlock network audit --provider aws --severity CRITICAL
# JSON output
matlock network audit --output json --output-file network-findings.jsonFlags
| Flag | Default | Description |
|---|---|---|
--provider |
auto | Cloud providers to scan |
--severity |
LOW |
Minimum severity to report |
--output |
table |
Output format: table, json |
--output-file |
Write output to file instead of stdout |
Lists TLS certificates from ACM (AWS), Certificate Manager (GCP), and Azure Key Vault that are expired or expiring soon.
Severity rules:
- CRITICAL — expired, or expiring within 7 days
- HIGH — expiring within 30 days
- MEDIUM — expiring within 60 days
- LOW — expiring within 90 days (default
--daysthreshold)
# All providers, warn on certs expiring within 90 days (default)
matlock certs
# Only show certs expiring within 30 days
matlock certs --days 30
# AWS only, CRITICAL and HIGH only
matlock certs --provider aws --severity HIGH
# JSON output
matlock certs --output json --output-file certs.jsonFlags
| Flag | Default | Description |
|---|---|---|
--provider |
auto | Cloud providers to scan |
--days |
90 |
Include certs expiring within this many days |
--severity |
LOW |
Minimum severity to report |
--output |
table |
Output format: table, json |
--output-file |
Write output to file instead of stdout |
GCP note: Certificate Manager must be enabled in your project (
gcloud services enable certificatemanager.googleapis.com). If the API is not enabled,matlock certsskips GCP with a warning.
Audits EC2 instances, S3 buckets, RDS databases, Lambda functions (AWS), compute instances and GCS buckets (GCP), and all resource types (Azure) for missing required tags or labels.
All findings are MEDIUM severity.
# Require owner, env, and cost-center tags across all providers
matlock tags --require owner,env,cost-center
# AWS only
matlock tags --provider aws --require owner,env
# JSON output
matlock tags --require owner,env --output json --output-file tags.jsonFlags
| Flag | Default | Description |
|---|---|---|
--provider |
auto | Cloud providers to scan |
--require |
(required) | Comma-separated tag/label keys that must be present |
--severity |
MEDIUM |
Minimum severity to report |
--output |
table |
Output format: table, json |
--output-file |
Write output to file instead of stdout |
Runs all security and cost scans (IAM, storage, network, orphans, certs, tags, secrets) in one shot and produces a single combined report. Skip specific domains with --skip.
# Full audit across all auto-detected providers
matlock audit
# Skip IAM and certs domains
matlock audit --skip iam,certs
# HIGH and CRITICAL findings only, JSON output
matlock audit --severity HIGH --output json --output-file audit.json
# SARIF output for GitHub Advanced Security
matlock audit --output sarif --output-file audit.sarif
# AWS only with custom thresholds
matlock audit --provider aws --iam-days 30 --cert-days 60 --require-tags owner,envFlags
| Flag | Default | Description |
|---|---|---|
--provider |
auto | Cloud providers to scan: aws, gcp, azure |
--skip |
Domains to skip: iam, storage, network, orphans, certs, tags, secrets |
|
--severity |
LOW |
Minimum severity to report |
--output |
table |
Output format: table, json, sarif |
--output-file |
Write output to file instead of stdout | |
--iam-days |
90 |
IAM audit log lookback period in days |
--cert-days |
90 |
Certificate expiry warning threshold in days |
--require-tags |
Required tags for tag audit (comma-separated) | |
--concurrency |
10 |
Max parallel goroutines for IAM scanning |
Lists all cloud resources across providers with type, region, tags, and creation date. Groups by type and region for a complete asset overview.
# List all resources across auto-detected providers
matlock inventory
# Filter to specific resource types
matlock inventory --type ec2,s3,lambda
# AWS only, JSON output
matlock inventory --provider aws --output json --output-file inventory.jsonFlags
| Flag | Default | Description |
|---|---|---|
--provider |
auto | Cloud providers to list: aws, gcp, azure |
--type |
all | Resource types to list (e.g. ec2, s3, lambda) |
--output |
table |
Output format: table, json |
--output-file |
Write output to file instead of stdout |
Checks service quota usage across cloud providers to prevent outages from silently hitting limits. Reports IAM, EC2, S3, Lambda, RDS quotas (AWS), compute project quotas (GCP), and compute/network/storage quotas (Azure).
# All providers, all quotas
matlock quota
# Only quotas above 50% utilization
matlock quota --threshold 50
# AWS only, JSON output
matlock quota --provider aws --output json --output-file quotas.jsonFlags
| Flag | Default | Description |
|---|---|---|
--provider |
auto | Cloud providers to check: aws, gcp, azure |
--threshold |
0 |
Minimum utilization percentage to report |
--output |
table |
Output format: table, json |
--output-file |
Write output to file instead of stdout |
Utilization is color-coded: green (<50%), yellow (50-80%), red (>80%).
Save any scan report as a named baseline for later comparison with matlock compare.
# Save a baseline from a scan report
matlock iam scan --output json --output-file scan.json
matlock baseline save --from scan.json --name pre-deploy
# List saved baselines
matlock baseline list
# Delete a baseline
matlock baseline delete --name old-scanBaselines are stored in ~/.matlock/baselines/.
Subcommands
| Subcommand | Description |
|---|---|
baseline save --from <file> --name <name> |
Save a report as a named baseline |
baseline list |
List all saved baselines with dates |
baseline delete --name <name> |
Delete a saved baseline |
Compares two scan reports (or a saved baseline against a current report) and classifies each finding as new, resolved, or unchanged.
# Compare a saved baseline against a new scan
matlock compare --baseline pre-deploy --current scan-after.json
# Compare two report files directly
matlock compare --from old-report.json --to new-report.json
# JSON output
matlock compare --from old.json --to new.json --output jsonFlags
| Flag | Default | Description |
|---|---|---|
--baseline |
Name of saved baseline to compare against | |
--current |
Path to current report JSON file | |
--from |
Path to older report JSON file | |
--to |
Path to newer report JSON file | |
--output |
table |
Output format: table, json |
--output-file |
Write output to file instead of stdout |
Use --baseline + --current or --from + --to (not both). Supports all report types: audit, IAM, storage, network, orphans, certs, tags, secrets, quotas.
End-to-end workflow
# Before a deploy: scan and save a baseline
matlock audit --output json --output-file audit.json
matlock baseline save --from audit.json --name pre-deploy-v2
# After the deploy: scan again and compare
matlock audit --output json --output-file audit-after.json
matlock compare --baseline pre-deploy-v2 --current audit-after.json
# Output shows:
# +NEW findings introduced since the baseline
# -RESOLVED findings that no longer appear
# =UNCHANGED findings present in bothYou can also skip baselines and compare any two JSON files directly:
matlock compare --from monday-scan.json --to friday-scan.json --output jsonGenerates a standalone, self-contained HTML report from any JSON scan output. Includes summary cards, severity breakdown, domain-specific tables, and client-side table sorting. Supports light and dark mode via prefers-color-scheme.
# Generate from an audit report
matlock audit --output json --output-file audit.json
matlock report --from audit.json --out report.html --open
# Generate from any scan report
matlock report --from iam-scan.json --out iam-report.html
# Explicit type override
matlock report --from data.json --type orphans --out orphans.htmlFlags
| Flag | Default | Description |
|---|---|---|
--from |
(required) | Path to scan report JSON file |
--out |
report.html |
Output HTML file path |
--type |
auto |
Report type: auto, audit, iam, storage, network, orphans, certs, tags, secrets, cost, quotas |
--open |
false |
Open the report in the default browser after generation |
| Flag | Description |
|---|---|
--quiet, -q |
Suppress all progress and summary output on stderr (for scripts) |
--version |
Print version, commit hash, and build date |
Upload IAM findings to GitHub Advanced Security (requires security-events: write permission):
name: matlock security scan
on:
schedule:
- cron: '0 6 * * 1' # every Monday at 06:00 UTC
workflow_dispatch:
permissions:
security-events: write
jobs:
iam-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install matlock
run: |
curl -sSL https://github.com/stxkxs/matlock/releases/latest/download/matlock_Linux_amd64.tar.gz \
| tar -xz matlock
sudo mv matlock /usr/local/bin/
- name: Run IAM scan
env:
AWS_ROLE_ARN: ${{ secrets.MATLOCK_ROLE_ARN }}
AWS_REGION: us-east-1
run: |
matlock iam scan \
--provider aws \
--severity HIGH \
--output sarif \
--output-file results.sarif \
--quiet
- name: Upload SARIF to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarifRun a unified audit across all domains in CI:
name: matlock full audit
on:
schedule:
- cron: '0 6 * * 1'
workflow_dispatch:
permissions:
security-events: write
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install matlock
run: |
curl -sSL https://github.com/stxkxs/matlock/releases/latest/download/matlock_Linux_amd64.tar.gz \
| tar -xz matlock
sudo mv matlock /usr/local/bin/
- name: Run full audit
env:
AWS_ROLE_ARN: ${{ secrets.MATLOCK_ROLE_ARN }}
AWS_REGION: us-east-1
run: |
matlock audit \
--provider aws \
--severity HIGH \
--output sarif \
--output-file audit.sarif \
--quiet
- name: Upload SARIF to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: audit.sarifmatlock:
image: ubuntu:24.04
before_script:
- curl -sSL https://github.com/stxkxs/matlock/releases/latest/download/matlock_Linux_amd64.tar.gz
| tar -xz matlock
- mv matlock /usr/local/bin/
script:
- matlock iam scan --output json --output-file report.json --quiet
- matlock storage audit --severity HIGH --output json --output-file storage.json --quiet
artifacts:
paths:
- report.json
- storage.json
expire_in: 30 days# Exit non-zero if any CRITICAL findings exist
matlock iam scan --severity CRITICAL --output json --quiet | \
jq -e '.findings | length == 0'| Format | Flag | Use case |
|---|---|---|
| Table | --output table |
Human-readable terminal output with colors |
| JSON | --output json |
Scripts, alerting, dashboards |
| SARIF | --output sarif |
GitHub Advanced Security, IDE integrations |
All formats can be written to a file with --output-file path/to/file.
matlock --version
# v0.1.0 (commit abc1234, built 2026-03-01T12:00:00Z)MIT — see LICENSE.