The Cloud Custodian Plugin runs Cloud Custodian policies in dry-run mode, builds a full inventory baseline for each configured resource type, converts each resource/policy pair into a standardized per-resource payload, and then executes CCF OPA bundles against those payloads to generate evidence.
- Load Cloud Custodian policy YAML from config.
- Parse top-level
policiesand iterate one policy entry per check. - Register runtime-derived subject templates for each configured resource type during runner-v2
Init. - Run one unfiltered inventory collection for each unique resource type.
- Run each configured check with:
custodian run --dryrun -s <output-dir> <single-policy-file>- Compare each check's matched resources with the inventory baseline.
- Build one standardized payload per resource per check. Matched resources are marked
non_compliant; baseline resources not matched by that check are markedcompliant. - 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 unlessaws_regionsis configured. - On execution failures or timeouts, the plugin includes the tail of any generated
custodian-run.logartifacts in the execution error.
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. |
custodian_debug |
No | Boolean (true/false) toggle to pass --debug to Cloud Custodian. This increases Cloud Custodian diagnostic output on stderr. Default: false. |
custodian_verbose |
No | Boolean (true/false) toggle to pass -v to Cloud Custodian. This increases Cloud Custodian diagnostic output on stderr. Default: false. |
custodian_aws_api_trace |
No | Boolean (true/false) toggle to inject a temporary Python sitecustomize.py into the Custodian child process. Logs botocore API start/end/error events to stderr and custodian-aws-api-trace.jsonl in the check output directory. Default: false. |
custodian_network_diagnostics |
No | Boolean (true/false) toggle to run Go DNS/TLS preflight probes for relevant AWS service endpoints before Custodian starts and log child process TCP socket snapshots while Custodian is running. DNS/TLS probe failures are logged as warnings and surfaced in evidence as execution.warnings. Concrete aws_regions are narrowed to regions with reachable resource service endpoints before Custodian runs; if none are reachable for a check, that check is skipped, later checks continue, and the accumulated diagnostic warnings are returned after reachable evidence is submitted. If no concrete aws_regions are configured, service-derived probes are skipped unless custodian_network_diagnostic_endpoints is configured. For AWS resource types not mapped to diagnostic services, diagnostics warn and continue unless explicit endpoints are configured. Invalid configured endpoints still fail before execution. Default: false. |
custodian_network_diagnostic_endpoints |
No | Comma or whitespace separated list of additional endpoint hostnames, host:port values, or HTTPS URLs to DNS/TLS probe when custodian_network_diagnostics is enabled. Non-HTTPS URL schemes are rejected. Use this for AWS VPC endpoint DNS names such as vpce-123.backup.eu-west-1.vpce.amazonaws.com. Default: unset. |
custodian_log_tail_during_run |
No | Boolean (true/false) toggle to tail discovered custodian-run.log artifacts during the monitor loop, not only after process exit. Default: false. |
aws_regions |
No | Comma or whitespace separated AWS regions passed as repeated --region flags. Duplicate entries are removed while preserving order. Default: unset, which falls back to --region all for AWS checks. |
check_timeout_seconds |
No | Per-check timeout in seconds. Default: 300. |
policy_labels |
No | JSON map of labels merged into generated evidence labels. |
resource_identity_fields |
No | JSON object mapping Cloud Custodian resource types to ordered identity field paths. Built-in defaults are used after configured fields. Example: {"aws.ec2":["InstanceId","Arn"]}. |
debug_dump_payloads |
No | Boolean (true/false) toggle to write standardized resource 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. |
preserve_execution_artifacts |
No | Boolean (true/false) toggle to keep the temporary Cloud Custodian execution root after a check execution failure for postmortem review. Default: false. |
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.resource_identity_fields, when set, must be valid JSON and each resource type must include at least one field path.- 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 resource/check iteration produces one payload with this shape:
{
"schema_version": "v2",
"source": "cloud-custodian",
"check": {
"name": "ec2-public-ip-check",
"resource": "aws.ec2",
"provider": "aws",
"index": 0,
"metadata": {}
},
"resource": {
"id": "i-1234567890abcdef0",
"type": "aws.ec2",
"provider": "aws",
"account_id": "123456789012",
"region": "us-east-1",
"identity_fields": {
"InstanceId": "i-1234567890abcdef0"
},
"data": {"...": "..."}
},
"assessment": {
"status": "non_compliant",
"matched": true,
"inventory_status": "baseline",
"matched_resource_count": 3,
"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"
},
"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": []
},
"raw_policy": {
"name": "ec2-public-ip-check",
"resource": "aws.ec2",
"filters": []
}
}Generated evidence labels include resource_id, resource_type, provider,
and any available account_id/region. The resource subject includes the
resource identifier as a link and a resource_id property. When the AWS
resource identifier is an ARN, generated evidence includes an AWS Resource
Explorer link using an exact id:<arn> search. AWS S3 bucket names are parsed
as arn:aws:s3:::<bucket-name> for Resource Explorer links. AWS Route53 hosted
zone identifiers such as /hostedzone/Z123 are normalized to full ARNs such as
arn:aws:route53:::hostedzone/Z123.
assessment.inventory_status is baseline for resources found in the unfiltered
inventory run. If a policy returns a resource that is not present in the baseline,
the plugin still evaluates it as non_compliant and sets
inventory_status to missing_from_baseline.
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 ./...