The Cloud Custodian Plugin runs Cloud Custodian policies in dry-run mode, converts each policy execution into a standardized per-check payload, and then executes CCF OPA bundles against that payload to generate evidence.
- Load Cloud Custodian policy YAML from config.
- Parse top-level
policiesand iterate one policy entry per check. - Run each check with:
custodian run --dryrun -s <output-dir> <single-policy-file>- Build a standardized payload from execution output and
resources.json. - Evaluate each OPA policy bundle path from agent
EvalRequest.policyPaths. - Send evidence via the plugin gRPC helper (
CreateEvidence).
This plugin always enforces read-only Cloud Custodian execution:
--dryrunis always used.- Mutating actions are not applied.
- For AWS checks, the plugin runs with
--region allto evaluate across all AWS regions by default.
All plugin config fields are strings (agent gRPC map<string,string> contract).
| Key | Required | Description |
|---|---|---|
policies_yaml |
Conditionally | Inline Cloud Custodian policy YAML. Preferred over policies_path when both are set. |
policies_path |
Conditionally | Local path, file://, http://, or https:// location for policy YAML. Used when policies_yaml is empty. |
custodian_binary |
No | Path/name of Cloud Custodian executable. Default: custodian. |
check_timeout_seconds |
No | Per-check timeout in seconds. Default: 300. |
policy_labels |
No | JSON map of labels merged into generated evidence labels. |
debug_dump_payloads |
No | Boolean (true/false) toggle to write standardized check payload JSON files for troubleshooting. Default: false. |
debug_payload_output_dir |
No | Directory where debug payload JSON files are written. If set, debug dumping is auto-enabled. Default when enabled without explicit path: debug-standardized-payloads. |
Validation rules:
- At least one of
policies_yamlorpolicies_pathmust be provided. custodian_binarymust resolve on PATH (or as explicit executable path).check_timeout_secondsmust be a positive integer.- Policy YAML must include top-level
policiesarray.
plugins:
cloud_custodian:
source: ./dist/plugin
policies:
- ./policy-bundle
config:
policies_yaml: |
policies:
- name: ec2-public-ip-check
resource: aws.ec2
filters:
- type: value
key: PublicIpAddress
op: not-null
custodian_binary: custodian
check_timeout_seconds: "300"
policy_labels: '{"team":"cloud-security","environment":"prod"}'plugins:
cloud_custodian:
source: ./dist/plugin
policies:
- ./policy-bundle
config:
policies_path: file:///etc/ccf/cloud-custodian.yaml
custodian_binary: /usr/local/bin/custodianEach policy/check iteration produces one payload with this shape:
{
"schema_version": "v1",
"source": "cloud-custodian",
"check": {
"name": "ec2-public-ip-check",
"resource": "aws.ec2",
"provider": "aws",
"index": 0,
"metadata": {}
},
"execution": {
"status": "success",
"dry_run": true,
"exit_code": 0,
"started_at": "2026-03-06T12:00:00Z",
"ended_at": "2026-03-06T12:00:01Z",
"duration_ms": 1000,
"stdout": "...",
"stderr": "",
"error": "",
"errors": []
},
"result": {
"matched_resource_count": 3,
"resources": [{"...": "..."}],
"artifact_path": "/tmp/ccf-cloud-custodian-123/001-ec2-public-ip-check",
"resources_path": "/tmp/ccf-cloud-custodian-123/001-ec2-public-ip-check/ec2-public-ip-check/resources.json"
},
"raw_policy": {
"name": "ec2-public-ip-check",
"resource": "aws.ec2",
"filters": []
}
}provider extraction rule:
aws.s3->aws- non
<provider>.<resource>formats ->unknown
- Cloud Custodian CLI must be installed and executable.
- Cloud/provider credentials must be available in the plugin process environment (ambient credentials/profile/env vars).
Run:
go test ./...