10 KiB
Starter Policy Pack Guide
This guide covers the StellaOps starter policy pack (starter-day1), a production-ready policy designed for organizations beginning their software supply chain security journey.
Quick Start
Install and activate the starter policy in under 5 minutes:
# Install the starter policy pack
stellaops policy install starter-day1
# Validate a policy file
stellaops policy validate policies/starter-day1.yaml
# Simulate policy against a scan
stellaops policy simulate --policy policies/starter-day1.yaml --scan <scan-id>
Overview
The starter policy implements a sensible security posture:
| What | Action | Rationale |
|---|---|---|
| Reachable HIGH/CRITICAL vulnerabilities | Block | Highest risk - exploitable code paths |
| Reachable MEDIUM vulnerabilities | Warn | Moderate risk - review recommended |
| Unreachable vulnerabilities | Allow (logged) | Low risk - no exploitable path |
| VEX-covered vulnerabilities | Allow | Evidence-based exception |
| Unknowns > 5% of packages | Block | Quality gate for metadata coverage |
| Unsigned SBOM (production) | Block | Integrity requirement |
| Unsigned verdict (production) | Block | Compliance attestation |
Rule-by-Rule Explanation
Rule 1: Block Reachable HIGH/CRITICAL
- name: block-reachable-high-critical
description: "Block deployments with reachable HIGH or CRITICAL vulnerabilities"
match:
severity:
- CRITICAL
- HIGH
reachability: reachable
unless:
vexStatus: not_affected
vexJustification:
- vulnerable_code_not_present
- vulnerable_code_cannot_be_controlled_by_adversary
- inline_mitigations_already_exist
action: block
message: "Reachable {severity} vulnerability {cve} must be remediated or have VEX justification"
What it does: Blocks any deployment containing HIGH or CRITICAL severity vulnerabilities where the vulnerable code is reachable (can be executed).
VEX bypass: If a VEX statement marks the vulnerability as not_affected with proper justification, the block is bypassed. Valid justifications:
vulnerable_code_not_present- The vulnerable function isn't compiled invulnerable_code_cannot_be_controlled_by_adversary- Input cannot reach vulnerable codeinline_mitigations_already_exist- Application-level mitigations in place
Rule 2: Warn on Reachable MEDIUM
- name: warn-reachable-medium
description: "Warn on reachable MEDIUM severity vulnerabilities"
match:
severity: MEDIUM
reachability: reachable
unless:
vexStatus: not_affected
action: warn
message: "Reachable MEDIUM vulnerability {cve} should be reviewed"
What it does: Generates a warning (but allows deployment) for MEDIUM severity reachable vulnerabilities.
When to upgrade: If your security posture matures, consider changing action: warn to action: block.
Rule 3: Allow Unreachable
- name: ignore-unreachable
description: "Allow unreachable vulnerabilities but log for awareness"
match:
reachability: unreachable
action: allow
log: true
message: "Vulnerability {cve} is unreachable - allowing"
What it does: Allows vulnerabilities where static analysis proves the code cannot be reached.
Logging: Even allowed findings are logged for audit purposes.
Rule 4: Unknowns Budget
- name: fail-on-unknowns
description: "Block if too many packages have unknown metadata"
type: aggregate
match:
unknownsRatio:
gt: ${settings.unknownsThreshold}
action: block
message: "Unknown packages exceed threshold ({unknownsRatio}% > {threshold}%)"
What it does: Blocks deployment if more than 5% of packages lack sufficient metadata for analysis.
Why: High unknowns ratio indicates poor SBOM quality or unsupported package ecosystems.
Rules 5-6: Signed Artifacts (Production)
- name: require-signed-sbom-prod
match:
environment: production
require:
signedSbom: true
action: block
message: "Production deployment requires signed SBOM"
- name: require-signed-verdict-prod
match:
environment: production
require:
signedVerdict: true
action: block
message: "Production deployment requires signed verdict"
What they do: Require cryptographically signed SBOM and verdict attestations for production environments.
Why: Ensures integrity and non-repudiation of security assessments.
Rule 7: Default Allow
- name: default-allow
description: "Allow everything not matched by above rules"
match:
always: true
action: allow
What it does: Explicit default action for any finding not matched by prior rules.
Environment Overrides
The starter policy supports environment-specific overrides:
Development (overrides/development.yaml)
apiVersion: policy.stellaops.io/v1
kind: PolicyOverride
metadata:
name: starter-day1-dev
parent: starter-day1
environment: development
spec:
settings:
defaultAction: warn # Never block in dev
unknownsThreshold: 0.20 # Allow more unknowns (20%)
ruleOverrides:
- name: block-reachable-high-critical
action: warn # Downgrade to warn
- name: require-signed-sbom-prod
enabled: false # Disable signing requirements
- name: require-signed-verdict-prod
enabled: false
Staging (overrides/staging.yaml)
apiVersion: policy.stellaops.io/v1
kind: PolicyOverride
metadata:
name: starter-day1-staging
parent: starter-day1
environment: staging
spec:
settings:
unknownsThreshold: 0.10 # 10% unknowns budget
ruleOverrides:
- name: require-signed-sbom-prod
enabled: false # No signing in staging
Production (Default)
Production uses the base policy with all rules enabled.
Customization Guide
Adjusting Severity Thresholds
To block MEDIUM vulnerabilities too:
ruleOverrides:
- name: warn-reachable-medium
action: block
Changing Unknowns Budget
To allow 10% unknowns:
settings:
unknownsThreshold: 0.10
Adding Custom Rules
Insert rules before default-allow:
rules:
# ... existing rules ...
# Custom: Block specific CVE
- name: block-specific-cve
match:
cve: CVE-2024-1234
action: block
message: "CVE-2024-1234 is explicitly blocked by policy"
- name: default-allow
match:
always: true
action: allow
Source Allowlists
Trust only specific VEX sources:
settings:
vexSources:
allowlist:
- redhat-csaf
- canonical-usn
- vendor-security
requireTrustScore: 0.7
Troubleshooting
"Reachable HIGH vulnerability must be remediated"
Cause: A HIGH/CRITICAL vulnerability exists in code that can execute.
Solutions:
- Update the affected package to a fixed version
- Create a VEX statement if the vulnerability doesn't apply:
stellaops vex create --cve CVE-2024-1234 --status not_affected \ --justification vulnerable_code_not_present - Apply a temporary exception (with approval):
exceptions: - cve: CVE-2024-1234 expires: 2025-02-01 approver: security-team reason: "Patch scheduled for next sprint"
"Unknown packages exceed threshold"
Cause: Too many packages lack metadata for vulnerability analysis.
Solutions:
- Ensure SBOMs are complete with package versions
- Check for unsupported package ecosystems
- Temporarily increase threshold in non-production:
settings: unknownsThreshold: 0.15
"Production deployment requires signed SBOM"
Cause: Attempting production deployment without signed SBOM.
Solutions:
- Sign SBOM during build:
stellaops sbom sign --sbom sbom.json --key-id <key> - Verify signing is configured in CI/CD pipeline
Rule Not Matching as Expected
Use simulation mode to debug:
stellaops policy simulate --policy policy.yaml --scan <scan-id> --verbose
Check:
- Rule order (first match wins)
- Severity casing (use uppercase: HIGH, CRITICAL)
- Reachability values (reachable, unreachable, unknown)
Migration Path to Custom Policies
Step 1: Start with Starter Policy
Deploy starter-day1 as-is to establish baseline.
Step 2: Monitor and Tune
Review policy decisions for 2-4 weeks:
- Which rules trigger most?
- Which findings need exceptions?
- What patterns emerge?
Step 3: Create Overlays
Add overlays for organization-specific needs:
apiVersion: policy.stellaops.io/v1
kind: PolicyOverride
metadata:
name: acme-corp-policy
parent: starter-day1
spec:
ruleOverrides:
- name: block-reachable-high-critical
unless:
# Add company-specific VEX sources
vexSource:
- acme-security-team
Step 4: Graduate to Custom Policy
When ready, fork the starter policy and customize fully:
# Export starter policy as starting point
stellaops policy pull --from registry.stellaops.io/policies/starter-day1:1.0.0 \
--output ./my-custom-policy/
# Modify as needed
vim ./my-custom-policy/base.yaml
# Validate changes
stellaops policy validate ./my-custom-policy/
# Push to your registry
stellaops policy push --policy ./my-custom-policy/base.yaml \
--to myregistry.example.com/policies/acme-policy:1.0.0 --sign
CLI Reference
| Command | Description |
|---|---|
stellaops policy validate <path> |
Validate policy against schema |
stellaops policy install <name> |
Install policy pack |
stellaops policy list-packs |
List available policy packs |
stellaops policy simulate --policy <path> --scan <id> |
Simulate policy evaluation |
stellaops policy push --policy <path> --to <ref> |
Push to OCI registry |
stellaops policy pull --from <ref> |
Pull from OCI registry |
stellaops policy export-bundle --policy <path> --output <file> |
Create offline bundle |
stellaops policy import-bundle --bundle <file> |
Import offline bundle |