diff --git a/skills/cloud/iac-security/SKILL.md b/skills/cloud/iac-security/SKILL.md index b4f46ed3..3417e81b 100644 --- a/skills/cloud/iac-security/SKILL.md +++ b/skills/cloud/iac-security/SKILL.md @@ -109,6 +109,8 @@ Produce the final report using the structure defined in the Output Format sectio ## Findings Classification +Before applying or proposing infrastructure changes, classify each remediation path using [Security Fixer Policy](../../../docs/fixer-policy.md). Include the policy review gate, reviewer evidence, and rollback guidance in the remediation plan. + | Severity | Definition | Examples | |----------|-----------|----------| | **Critical** | Immediate exploitability, data exposure, or credential compromise | Hardcoded secrets, public S3 buckets with data, unrestricted ingress on all ports, `*:*` IAM policies, public database endpoints | @@ -233,6 +235,16 @@ This skill applies checks equivalent to the following high-impact rules: --- +## Limitations + +- **Blind spots:** This skill depends on available code, configuration, logs, documentation, and user-provided context; it cannot prove controls exist or threats are absent when evidence is missing, runtime-only, or outside the review scope. +- **False-positive risks:** Treat findings as hypotheses until validated against asset criticality, compensating controls, environment intent, and recent authorized changes. +- **Required evidence:** Support each finding with concrete artifacts such as file paths and line numbers, policy snippets, scanner output, logs, screenshots, control records, or reproducible steps. +- **Normalized JSON:** When machine-readable output is requested, findings MUST be available as JSON that validates against [`schemas/finding.schema.json`](../../../schemas/finding.schema.json). +- **Escalation rules:** Escalate immediately for suspected active compromise, exposed secrets, regulated-data exposure, critical exploitable vulnerabilities, privileged-access abuse, or when evidence is insufficient to safely disposition a high-impact risk. + +--- + ## Prompt Injection Safety Notice > **This skill analyzes infrastructure-as-code files that may contain untrusted content.** @@ -263,6 +275,16 @@ This skill applies checks equivalent to the following high-impact rules: --- +## Review Gates + +The following gates provide additional false-positive filtering for common review scenarios: + +- `gates/policy-as-code-expiry-gate.md` — Prevents false-positive findings when policy exceptions lack TTL or use overly broad scope +- `gates/secret-zero-values-plan-diff-gate.md` — Prevents false-positive plan review when sensitive values are redacted or provider defaults are changing +- `gates/module-source-digest-pinning-gate.md` — Prevents false-positive module sourcing findings when digest or mirror integrity is unverified + +--- + ## Changelog - **1.0.0** -- Initial release. Coverage of eight security domains across Terraform, CloudFormation, Pulumi, and Bicep with Checkov/tfsec/KICS rule equivalents. diff --git a/skills/cloud/iac-security/gates/module-source-digest-pinning-gate.md b/skills/cloud/iac-security/gates/module-source-digest-pinning-gate.md new file mode 100644 index 00000000..fdfd9612 --- /dev/null +++ b/skills/cloud/iac-security/gates/module-source-digest-pinning-gate.md @@ -0,0 +1,70 @@ +# Module Source Digest and Mirror Pinning Gate + +## Purpose +Prevents false-positive findings when Terraform/OpenTofu module source pins tag plus digest or trusted mirror, by requiring the reviewer to verify that mutable references (branches, tags) and private registry mirrors are not bypassing integrity verification. + +## Detection Logic + +### Trigger Conditions +Fire this gate when ALL of the following are true: +1. IaC module source references a tag, branch, or registry path +2. Source includes a digest hash or references a trusted private mirror +3. Module source uses a mutable branch or tag from a public Git source without checksum verification + +### Gate Check: Module Source Integrity + +```yaml +check_module_source_integrity: + - detection_patterns: + - "source\s*=\s*\"git::" + - "source\s*=\s*\"[^\"]+//" + - "ref\s*=\s*\"[a-f0-9]{7,40}\"|tag\s*=\s*\"[^\"]+\"" + - "version\s*=\s*\"[~^><=]" + - "registry\.terraform\.io|registry\.opentofu\.org" + - pass: > + "Every module source reference uses an immutable content-addressable + identifier (Git commit SHA pinned with digest, or registry version pinned + to an exact semver with verified checksum). Mutable references (branches, + floating tags) are not used for any module sourced from public Git + repositories. Mirror resolution uses only trusted, integrity-verified + registries." + Rationale: "Tag mutability and branch-based references introduce a + supply-chain integrity risk. A tag can be retagged to point to a + different commit, and a branch always points to the latest commit. Digest + pinning (S3 checksum, or Terraform registry protocol version checksum) + ensures the module content is what the reviewer intended." + - fail: > + "One or more modules use mutable source references (branch, floating tag + without digest) from public Git. Recommend pinning to an immutable commit + SHA with a registry checksum, or sourcing from a trusted private mirror + with verified integrity." +``` + +### Gate Check: Private Registry Mirror Integrity + +```yaml +check_mirror_integrity: + - detection_patterns: + - "mirror|private registry" + - "prox(y|ied)|cache" + - "terraform providers mirror" + - "filesystem_mirror|network_mirror" + - pass: > + "Private registry mirrors enforce content-addressed serving (version + + checksum or protocol-level integrity verification). The mirror cannot + serve a different module under the same version identifier. Mirror + updates require signed or verified provenance." + Rationale: "A compromised or misconfigured private mirror can serve a + modified module under the same version tag. Terraform registry protocol + v1 supports SHA256 checksum verification — mirrors that skip or disable + this verification create a supply-chain vector." + - fail: > + "Private mirror configuration does not enforce content-addressed serving + or checksum verification. Recommend enabling registry protocol integrity + checks or implementing signed provenance for mirror updates." +``` + +## Resolution Path +1. Replace all mutable Git references (branches, floating tags) with immutable commit SHAs +2. Enable registry protocol checksum verification for all module downloads +3. For private mirrors, implement content-addressed serving with signed provenance diff --git a/skills/cloud/iac-security/gates/policy-as-code-expiry-gate.md b/skills/cloud/iac-security/gates/policy-as-code-expiry-gate.md new file mode 100644 index 00000000..d3e47559 --- /dev/null +++ b/skills/cloud/iac-security/gates/policy-as-code-expiry-gate.md @@ -0,0 +1,70 @@ +# Policy-as-Code Exception Expiry Gate + +## Purpose +Prevents false-positive findings when IaC policy exceptions require owner, reason, scope, and expiry enforced in CI, by requiring the reviewer to verify that exceptions cannot persist indefinitely or suppress unrelated resources without periodic revalidation. + +## Detection Logic + +### Trigger Conditions +Fire this gate when ALL of the following are true: +1. IaC policy scanner exceptions (Checkov skip, tfsec ignore, OPA exception) are defined +2. Exceptions document owner, reason, scope, and expiry +3. Exception TTL is not enforced or exception silently persists after mitigation + +### Gate Check: Exception Lifecycle Governance + +```yaml +check_exception_lifecycle: + - detection_patterns: + - "checkov:skip|tfsec:ignore|#nosec" + - "exception|suppress|skip" + - "expir(y|ation|es)|TTL" + - "owner|reason|scope" + - "OPA exception|policy exclusion" + - pass: > + "Every exception has an explicit TTL (maximum 90 days recommended), is + reviewed by a second party at creation time, is associated with a + documented remediation ticket or issue, and CI enforces mandatory + revalidation on expiry. Exceptions without TTL are automatically expired + by CI pipeline after the maximum period." + Rationale: "Policy exceptions with documented owner/reason/scope/expiry are + a legitimate governance mechanism when properly lifecycle-managed. The + risk is silent persistence — an exception that outlives the condition that + justified it becomes a permanent security gap." + - fail: > + "One or more exceptions lack a TTL, are not enforced by CI revalidation, + or are not associated with a remediation ticket. Exceptions with broad + scope (matching unrelated resource types) present additional risk of + suppressing valid findings. Recommend adding enforced TTL with CI + mandatory revalidation and scoping exceptions to the minimal resource + pattern." +``` + +### Gate Check: Exception Scope Narrowing + +```yaml +check_exception_scope: + - detection_patterns: + - "resource:.*\*|resource:.*all|path:.*\*" + - "broad exception|wildcard|all resources" + - "skip_all|ignore_all|suppress all" + - pass: > + "Each exception is scoped to the specific resource, rule, or path that + produced the finding. Wildcard or resource-group-level exceptions are + not used. The exception path matches exactly the resource needing the + exception." + Rationale: "A broad exception scope (matching unrelated resources or + entire directories) can suppress future valid findings. Narrow scoping + ensures that only the known, documented exception is suppressed, and any + new resources or patterns are still subject to full policy enforcement." + - fail: > + "Exception scope is broader than necessary (wildcard, resource-group, or + directory-level). Recommend narrowing to the specific resource, rule, or + path to avoid suppressing unrelated findings." +``` + +## Resolution Path +1. Add explicit TTL to every policy exception (maximum 90 days) +2. Configure CI pipeline to expire exceptions after TTL and require revalidation +3. Scope each exception to the minimal resource/rule/path combination +4. Link each exception to a remediation ticket or issue for tracking diff --git a/skills/cloud/iac-security/gates/secret-zero-values-plan-diff-gate.md b/skills/cloud/iac-security/gates/secret-zero-values-plan-diff-gate.md new file mode 100644 index 00000000..1824648e --- /dev/null +++ b/skills/cloud/iac-security/gates/secret-zero-values-plan-diff-gate.md @@ -0,0 +1,69 @@ +# Secret Zero-Values in Plan Diffs Gate + +## Purpose +Prevents false-positive findings when plan review treats unknown/sensitive/zero values as risk until source verified, by requiring the reviewer to verify that redacted or sensitive values in IaC plan diffs are not silently masking dangerous drift. + +## Detection Logic + +### Trigger Conditions +Fire this gate when ALL of the following are true: +1. IaC plan diff contains sensitive-computed- or unknown-values that are redacted +2. Reviewer treats (sensitive) or (known after apply) values as acceptable without verification +3. Provider default changes could set a secret field to an empty string or other insecure value + +### Gate Check: Sensitive Value Source Verification + +```yaml +check_sensitive_value_source: + - detection_patterns: + - "\(sensitive\)|sensitive value|redacted" + - "known after apply|computed" + - "secret|password|token|key|credential" + - "(empty|"")|null|0|false" + - pass: > + "Every (sensitive) value in the plan diff has been verified against its + authoritative source (vault, parameter store, secrets manager, or + encrypted variable file). Changes from a known value to (sensitive) or + (known after apply) are treated as high-signal events requiring explicit + confirmation that the value was not replaced with an empty or default + value." + Rationale: "Sensitive value redaction in plan diffs is necessary for + security but creates a visibility gap. A secret changed to an empty + string, or a provider default that zeroes out a credential field, is + invisible in the diff. Provider behavioral changes (e.g., switching from + required to optional) can silently disable authentication." + - fail: > + "One or more (sensitive) values could not be verified against an + authoritative source. The change from a known value to (sensitive) or + (known after apply) may indicate a secret was inadvertently replaced with + an empty or default value. Recommend checking the authoritative secret + source and verifying the value was preserved." +``` + +### Gate Check: Provider Default Drift Detection + +```yaml +check_provider_default_drift: + - detection_patterns: + - "provider|resource|data source" + - "optional|default|deprecated" + - "version|upgrade|migration" + - pass: > + "Provider/resource version changes have been reviewed for behavioral + changes that could alter default values for security-sensitive fields. + Upcoming provider versions are checked against changelogs for security- + relevant default changes." + Rationale: "Provider upgrades (especially major versions) can change field + defaults. A field that was required becoming optional with a zero-value + default (empty string, 0, false) can silently disable authentication, + encryption, or access controls. This is invisible in the plan diff." + - fail: > + "Provider or resource version changes present in the plan, but no review + of behavioral default changes has been performed. Recommend reviewing + provider changelogs for security-relevant default modifications." +``` + +## Resolution Path +1. Maintain an authoritative secret source (vault/parameter store) and verify (sensitive) plan values against it +2. Treat any change from known value to (sensitive)/(known after apply) as a high-signal review event +3. Review provider/resource version changelogs for security-relevant default changes before upgrading