Skip to content

Latest commit

 

History

History
211 lines (156 loc) · 8.19 KB

File metadata and controls

211 lines (156 loc) · 8.19 KB

Philosophy

Principiis obsta -- resist the beginnings.

IAM is the #1 compliance pain point. Every SOC2/ISO audit asks "who has access to what and when was it last used?" Stale credentials, wildcard policies, and missing MFA are not theoretical risks -- they are the attack surface. IAMSpectre surfaces these conditions early so they can be addressed before they become incidents.

The tool presents evidence and lets humans decide. It does not auto-revoke permissions, does not guess intent, and does not use ML where deterministic checks suffice.

Installation

# Homebrew
brew install ppiankov/tap/iamspectre

# Docker
docker pull ghcr.io/ppiankov/iamspectre:latest

# From source
git clone https://github.com/ppiankov/iamspectre.git
cd iamspectre && make build

Usage

AWS

iamspectre aws [flags]
Flag Default Description
--profile AWS profile name
--stale-days 90 Inactivity threshold (days)
--severity-min low Minimum severity: critical, high, medium, low
--format text Output format: text, json, sarif, spectrehub
-o, --output stdout Output file path
--timeout 5m Scan timeout

GCP

iamspectre gcp [flags]
Flag Default Description
--project GCP project ID (required)
--stale-days 90 Inactivity threshold (days)
--severity-min low Minimum severity: critical, high, medium, low
--format text Output format: text, json, sarif, spectrehub
-o, --output stdout Output file path
--timeout 5m Scan timeout

Azure

iamspectre azure [flags]
Flag Default Description
--tenant Azure tenant ID
--stale-days 90 Inactivity threshold (days)
--severity-min low Minimum severity: critical, high, medium, low
--format text Output format: text, json, sarif, spectrehub
-o, --output stdout Output file path
--timeout 5m Scan timeout
--include-guests true Include guest/external users in audit

Other commands

Command Description
iamspectre init Generate .iamspectre.yaml config and IAM policy
iamspectre version Print version, commit, and build date

Configuration

IAMSpectre reads .iamspectre.yaml from the current directory:

profile: production
project: my-gcp-project
tenant_id: my-azure-tenant-id
stale_days: 90
severity_min: medium
format: json
exclude:
  principals:
    - ci-bot
    - terraform@my-project.iam.gserviceaccount.com
  resource_ids:
    - arn:aws:iam::123456789012:role/service-linked-role

Generate a sample config with iamspectre init.

IAM permissions

IAMSpectre requires read-only access. Run iamspectre init to generate the minimal IAM policy.

AWS

  • iam:GenerateCredentialReport, iam:GetCredentialReport
  • iam:ListRoles, iam:ListPolicies, iam:GetPolicyVersion
  • sts:GetCallerIdentity

GCP

  • iam.serviceAccounts.list, iam.serviceAccountKeys.list
  • resourcemanager.projects.getIamPolicy

Azure

  • User.Read.All, Application.Read.All, Directory.Read.All
  • AuditLog.Read.All, UserAuthenticationMethod.Read.All

Output formats

Text (default): Human-readable table with severity, resource, and recommendation.

JSON (--format json): spectre/v1 envelope with findings and summary.

SARIF (--format sarif): SARIF v2.1.0 for GitHub Security tab integration.

SpectreHub (--format spectrehub): spectre/v1 envelope for SpectreHub ingestion.

Architecture

iamspectre/
├── cmd/iamspectre/main.go          # Entry point (LDFLAGS)
├── internal/
│   ├── commands/                   # Cobra CLI: aws, gcp, azure, init, version
│   ├── iam/                        # Shared types: Finding, Severity, Scanner
│   ├── aws/                        # AWS scanners: users, roles, policies
│   │   ├── credential_report.go    # Credential Report CSV parser
│   │   ├── user.go                 # Stale users, stale keys, no MFA
│   │   ├── role.go                 # Unused roles, cross-account trust
│   │   ├── policy.go               # Unattached, wildcard policies
│   │   ├── policy_document.go      # Policy document parser (StringOrSlice)
│   │   └── scanner.go              # AWS scanner orchestrator
│   ├── gcp/                        # GCP scanners: service accounts, bindings
│   │   ├── service_account.go      # Stale SAs, stale SA keys
│   │   ├── binding.go              # Overprivileged SA bindings
│   │   └── scanner.go              # GCP scanner orchestrator
│   ├── azure/                      # Azure AD scanners
│   │   ├── user.go                 # Stale users, guests, no MFA, legacy auth
│   │   ├── app.go                  # Stale apps, expired/expiring secrets
│   │   ├── service_principal.go    # Stale SPs, overprivileged apps
│   │   ├── role.go                 # Unused directory roles
│   │   └── scanner.go              # Azure scanner orchestrator
│   ├── analyzer/                   # Severity filtering, summary aggregation
│   └── report/                     # Text, JSON, SARIF, SpectreHub reporters
├── Makefile
└── go.mod

Key design decisions:

  • Subcommand-per-cloud (aws, gcp, azure) because each cloud has fundamentally different IAM models.
  • internal/iam/ holds shared types (Finding, Severity, Scanner interface) used by all clouds.
  • Each scanner implements Scanner interface: Scan(ctx, ScanConfig) (*ScanResult, error).
  • Bounded concurrency via errgroup.SetLimit(5). Scanner errors are collected, not fatal.
  • AWS credential report is fetched once and shared across user-level checks.
  • AWS policy documents handle the "string or array" pattern via custom StringOrSlice JSON unmarshaler.
  • GCP uses google.golang.org/api REST clients with interface-based mocking.
  • Azure uses azidentity for auth + direct REST calls to Microsoft Graph API.
  • Severity levels: critical > high > medium > low (numeric rank for filtering).
  • Recommendation field instead of cost estimation -- IAM findings are security risks, not dollar waste.

Project Status

Status: Beta · v0.1.0 · Pre-1.0

Milestone Status
AWS scanners: users, roles, policies (7 finding types) Complete
GCP scanners: service accounts, bindings (3 finding types) Complete
Azure AD scanners: users, apps, SPs, roles (10 finding types) Complete
Credential report parsing and key age analysis Complete
Cross-account trust and wildcard policy detection Complete
4 output formats (text, JSON, SARIF, SpectreHub) Complete
Config file + init command with IAM policy generation Complete
CI pipeline (test/lint/build) Complete
Homebrew + Docker distribution Complete
API stability guarantees Partial
v1.0 release Planned

Pre-1.0: CLI flags and config schemas may change between minor versions. JSON output structure (spectre/v1) is stable.

Known limitations

  • Single account/project/tenant. Scans one AWS account, GCP project, or Azure tenant at a time.
  • No Policy Analyzer integration. GCP service account "last used" detection relies on disabled status and key age, not the Policy Analyzer activity API.
  • No group membership analysis. Does not trace IAM group memberships to find inherited permissions.
  • No resource-level policy analysis. Only checks IAM policies, not S3 bucket policies, KMS key policies, etc.
  • Trust policy parsing. Cross-account trust detection checks Principal.AWS but does not evaluate complex condition expressions.
  • GCP binding scope. Only checks project-level IAM bindings, not folder or organization-level.
  • Azure AD Premium P1. Stale user/guest detection requires signInActivity (Azure AD Premium P1). Without P1, MFA and credential checks still work.
  • Azure overprivileged detection. Checks a static set of known dangerous Microsoft Graph API roles, not all possible permission combinations.