Skip to main content

How to Evaluate Multi-Cloud Infrastructure

Stave evaluates any cloud provider and any service without engine changes. Each domain has its own controls and observation property namespace.

Available profiles

stave apply --profile aws-s3     # 67 S3 controls
stave apply --profile aws-iam # 41 IAM controls
stave apply --profile gcp-gcs # 7 GCS controls
stave apply --profile hipaa # HIPAA compliance (S3)

Standard mode (any domain)

Use --controls to point at any control directory:

# Evaluate S3 buckets
stave apply --controls controls/s3 --observations obs/ --max-unsafe 168h

# Evaluate IAM accounts
stave apply --controls controls/iam --observations obs/ --max-unsafe 168h

# Evaluate GCS buckets
stave apply --controls controls/gcs --observations obs/ --max-unsafe 168h

# Evaluate DNS records
stave apply --controls controls/dns --observations obs/ --max-unsafe 168h

Mixing domains in one evaluation

Point --controls at multiple directories or a parent directory:

# Evaluate all domains
stave apply --controls controls/ --observations obs/ --max-unsafe 168h

Controls only fire on assets that match their predicates. S3 controls check properties.storage.kind == "bucket". IAM controls check properties.identity.kind == "user". They coexist without conflict.

Writing observations for non-S3 domains

IAM observation (account-level)

{
"schema_version": "obs.v0.1",
"captured_at": "2026-01-01T00:00:00Z",
"assets": [{
"id": "aws-account-root",
"type": "aws_iam_account",
"vendor": "aws",
"properties": {
"identity": {
"kind": "account",
"root": { "mfa_enabled": false, "has_access_keys": true, "hardware_mfa": false }
}
}
}]
}

IAM observation (user-level)

{
"schema_version": "obs.v0.1",
"captured_at": "2026-01-01T00:00:00Z",
"assets": [{
"id": "iam-user-alice",
"type": "aws_iam_user",
"vendor": "aws",
"properties": {
"identity": {
"kind": "user",
"policies": {
"has_admin_access": true,
"has_self_modify": false,
"passrole_unrestricted": false,
"statement_count": 12
},
"mfa": { "hardware_mfa": true },
"credentials": { "inactive_days": 5 }
}
}
}]
}

GCS observation

{
"schema_version": "obs.v0.1",
"captured_at": "2026-01-01T00:00:00Z",
"assets": [{
"id": "my-gcs-bucket",
"type": "gcp_gcs_bucket",
"vendor": "gcp",
"properties": {
"storage": {
"kind": "bucket",
"access": { "public_read": true }
}
}
}]
}

DNS observation

{
"schema_version": "obs.v0.1",
"captured_at": "2026-01-01T00:00:00Z",
"assets": [{
"id": "legacy-subdomain",
"type": "dns_record",
"vendor": "cloudflare",
"properties": {
"dns": {
"hostname": "old.example.com",
"record_type": "CNAME",
"target": "deleted-bucket.s3.amazonaws.com",
"target_exists": false,
"target_owned": false
}
}
}]
}

Property namespace reference

See docs/observation-contract.md for the full field dictionary:

  • S3: properties.storage.* (67 controls, 80+ fields)
  • IAM: properties.identity.* (41 controls, 20+ fields)
  • OpenSearch: properties.search_service.* (12 controls, Darkbeam/Wyze/Microsoft breach patterns)
  • GCS: properties.storage.* (7 controls, shared namespace with S3)
  • ECR: properties.container_registry.* (3 controls, container supply chain)
  • DNS: properties.dns.* (3 controls, vendor-agnostic)

Verify binary integrity across domains

stave version --verify

Shows control count per domain and the policy library hash — confirming which controls are embedded in the binary.