|
1 | | -# cleancloud.yaml |
| 1 | +# cleancloud.yaml — Policy-as-code configuration |
| 2 | +# Auto-detected in the current directory. Override with: cleancloud scan --config path/to/cleancloud.yaml |
2 | 3 | version: 1 |
3 | 4 |
|
| 5 | +# ── Filtering precedence (strongest first) ──────────────────────────────────── |
| 6 | +# 1. Exceptions — explicit human approvals, bypass all other filters |
| 7 | +# 2. Tag filtering — resource-scope exclusion by tag/label |
| 8 | +# 3. Rule enable/disable + params — pre-scan rule selection |
| 9 | +# 4. Defaults — global fallbacks for min_cost / confidence / override_risk_level |
| 10 | +# 5. Thresholds — CI/CD exit-code policy |
| 11 | + |
| 12 | +# ── Defaults ───────────────────────────────────────────────────────────────── |
| 13 | +# Global fallbacks applied to all rules unless overridden at the rule level. |
| 14 | +# min_cost: per-finding, using estimated_monthly_cost_usd (not total across findings). |
| 15 | +defaults: |
| 16 | + min_cost: 10 # suppress findings below $10/month estimated cost |
| 17 | + confidence: MEDIUM # suppress LOW confidence findings globally |
| 18 | + |
| 19 | +# ── Tag filtering ──────────────────────────────────────────────────────────── |
| 20 | +# Suppress findings on resources that carry these tags/labels. |
| 21 | +# Applied AFTER exceptions — explicitly-excepted resources are never re-suppressed by a tag rule. |
| 22 | +# Useful for excluding intentional infrastructure (prod keep-warm, IaC-managed resources). |
4 | 23 | tag_filtering: |
5 | 24 | enabled: true |
| 25 | + mode: exclude # "exclude" suppresses findings on matched resources (only supported mode) |
6 | 26 | ignore: |
7 | 27 | - key: env |
8 | | - value: production |
9 | | - - key: team |
10 | | - value: platform |
11 | | - - key: team |
| 28 | + values: [production, staging] # suppress findings on prod and staging resources |
| 29 | + - key: cleancloud-ignore # key-only match (any value) |
| 30 | + |
| 31 | +# ── Rule configuration ─────────────────────────────────────────────────────── |
| 32 | +# Enable or disable rules, tune thresholds, or pass parameters to individual rules. |
| 33 | +# Rules not listed here are enabled by default (opt-out model). |
| 34 | +# Per-rule settings override defaults above. |
| 35 | +# Rule IDs must match exactly — a typo raises an error at scan start with a suggestion. |
| 36 | +# Run `cleancloud scan --help` or see docs/rules.md for the full list. |
| 37 | +rules: |
| 38 | + aws.resource.untagged: |
| 39 | + enabled: false # team manages tags separately |
| 40 | + |
| 41 | + aws.ec2.ami.old: |
| 42 | + enabled: true |
| 43 | + min_cost: 5 # only flag AMIs with estimated cost >= $5/month (overrides default) |
| 44 | + |
| 45 | + aws.rds.instance.idle: |
| 46 | + enabled: true |
| 47 | + min_cost: 100 # suppress RDS findings below $100/month estimated cost |
| 48 | + params: |
| 49 | + idle_days: 21 # require 21 days idle before flagging (default: 14) |
| 50 | + |
| 51 | + gcp.sql.instance.idle: |
| 52 | + enabled: true |
| 53 | + params: |
| 54 | + idle_days: 21 # require 21 days idle before flagging (default: 14) |
| 55 | + |
| 56 | + azure.compute.snapshot.old: |
| 57 | + enabled: true |
| 58 | + params: |
| 59 | + max_age_days: 60 # flag snapshots older than 60 days (default: 90) |
| 60 | + confidence: LOW # include LOW confidence findings for this rule (overrides global default) |
| 61 | + |
| 62 | + aws.sagemaker.endpoint.idle: |
| 63 | + enabled: true |
| 64 | + # override_risk_level overrides the `risk` field on findings — affects display and reporting only. |
| 65 | + # It does NOT affect fail_on_confidence thresholds (which use signal strength, not risk). |
| 66 | + override_risk_level: HIGH |
| 67 | + |
| 68 | +# ── Categories ─────────────────────────────────────────────────────────────── |
| 69 | +# Override the default category without using the --category CLI flag. |
| 70 | +# Equivalent to: cleancloud scan --provider aws --category all |
| 71 | +# CLI --category flag takes precedence when explicitly set. |
| 72 | +# categories: |
| 73 | +# include: [hygiene, ai] # run both hygiene and AI/ML rules |
| 74 | + |
| 75 | +# ── Exceptions ─────────────────────────────────────────────────────────────── |
| 76 | +# Strongest filter — excepted resources bypass tag filtering and all other suppression. |
| 77 | +# Fields: rule_id (exact), resource_id (glob: *, ?, [seq]), account_id, region, reason. |
| 78 | +# account_id and region narrow the match — omit to match any account/region. |
| 79 | +# Document the reason for every exception — these are git-reviewable approvals. |
| 80 | +# Note: require_reason / require_ticket enforcement planned for a future release. |
| 81 | +exceptions: |
| 82 | + - rule_id: aws.ec2.instance.stopped |
| 83 | + resource_id: i-0abc1234567890def |
| 84 | + reason: "Bastion host — kept stopped intentionally, started on demand" |
| 85 | + expires_at: "2026-12-31" # exception reviewed quarterly; auto-expires if not renewed |
| 86 | + |
| 87 | + - rule_id: aws.rds.instance.idle |
| 88 | + resource_id: db-prod-reporting |
| 89 | + reason: "Quarterly reporting DB — idle between cycles, do not terminate" |
| 90 | + |
| 91 | + - rule_id: aws.rds.instance.idle |
| 92 | + resource_id: "db-test-*" # glob — suppress all test databases |
| 93 | + reason: "Test databases are ephemeral and frequently idle" |
| 94 | + |
| 95 | + - rule_id: aws.ebs.unattached |
| 96 | + resource_id: "vol-*" |
| 97 | + account_id: "111111111111" # narrow to a specific AWS account |
| 98 | + region: us-west-2 # narrow to a specific region |
| 99 | + reason: "Archive volumes in legacy account, migration planned" |
| 100 | + |
| 101 | + - rule_id: gcp.sql.instance.idle |
| 102 | + resource_id: my-project:us-central1:analytics-db |
| 103 | + reason: "Idle between quarterly runs" |
| 104 | + |
| 105 | +# ── Thresholds ─────────────────────────────────────────────────────────────── |
| 106 | +# Config-file equivalents of --fail-on-* CLI flags. |
| 107 | +# CLI flags take precedence if both are set. |
| 108 | +# fail_on_confidence uses signal strength (LOW/MEDIUM/HIGH), not the override_risk_level above. |
| 109 | +# |
| 110 | +# Exit codes: |
| 111 | +# 0 — No findings (or all filtered/suppressed) |
| 112 | +# 1 — Unexpected error (bug or infrastructure failure) |
| 113 | +# 2 — Policy violation — a threshold was breached (CI/CD should fail here) |
| 114 | +# 3 — Permission error — insufficient IAM/RBAC permissions to complete scan |
| 115 | +# |
| 116 | +# Threshold evaluation order (OR logic — first breach triggers exit 2): |
| 117 | +# 1. fail_on_findings: true → any remaining finding |
| 118 | +# 2. fail_on_confidence: X → any finding with confidence >= X |
| 119 | +# 3. fail_on_cost: X → total estimated_monthly_cost_usd across findings >= X |
| 120 | +thresholds: |
| 121 | + fail_on_confidence: HIGH # exit 2 if any HIGH confidence finding remains after filtering |
| 122 | + fail_on_cost: 500 # exit 2 if total estimated waste >= $500/month |
| 123 | + fail_on_findings: false # exit 2 on any finding (most strict — usually too noisy for CI) |
0 commit comments