Custodian policies for Infrastructure Code

This package allows cloud custodian to evaluate policies directly against infrastructure as code source assets.

It also provides a separate cli for better command line ux for source asset evaluation.

Install

We currently only support python > 3.10 on mac and linux, to run on windows we recommend using our docker images.

pip install c7n_left

We also provide signed docker images. These images are built on top of chainguard’s wolfi linux distribution which is designed to be minimal, auditable, and secure.

docker pull cloudcustodian/c7n_left:dev

Images signatures can be verified using cosign

export IMAGE=$(docker image inspect cloudcustodian/c7n-left:dev -f '{{index .RepoDigests 0}}')
cosign verify $IMAGE \
   --certificate-identity 'https://github.com/cloud-custodian/cloud-custodian/.github/workflows/docker.yml@refs/heads/main' \
   --certificate-oidc-issuer 'https://token.actions.githubusercontent.com'

Usage

 c7n-left run --help

Usage: c7n-left run [OPTIONS]

  evaluate policies against IaC sources.

  c7n-left -p policy_dir -d terraform_root --filters "severity=HIGH"

  WARNING - CLI interface subject to change.

Options:
  --format TEXT
  --filters TEXT                  filter policies or resources as k=v pairs
                                  with globbing
  -p, --policy-dir PATH
  -d, --directory PATH
  -o, --output [cli|github|json]
  --output-file FILENAME
  --output-query TEXT
  --summary [policy|resource]
  --help                          Show this message and exit.

We’ll create an empty directory with a policy in it

policies:
  - name: test
    resource: terraform.aws_s3_bucket
    metadata:
      severity: medium
    filters:
      - server_side_encryption_configuration: absent

And now we can use it to evaluate a terraform root module

 c7n-left run -p policies -d module
Running 1 policies on 1 resources
test - terraform.aws_s3_bucket
  Failed
  File: s3.tf:1-8
  1 resource "aws_s3_bucket" "example" {                                                                                
  2   bucket = "my-custodian-test-bucket"                                                                               
  3   acl    = "private"                                                                                                
  4                                                                                                                     
  5   tags = {                                                                                                          
  6     original-tag = "original-value"                                                                                 
  7   }                                                                                                                 
  8 }                                                                                                                   

Evaluation complete 0.00 seconds -> 1 Failures
           Summary - By Policy           
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
┃ Severity  Policy  Result            ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩
│ medium    test    1 failed 0 passed │
└──────────┴────────┴───────────────────┘
0 compliant of 1 total, 1 resource has 1 policy violation

For running in docker, you’ll need to use volume mounts to provide access to the policy directory and terraform root module.

docker run -ti --rm -v $(pwd)/policies:/policies -v $(pwd)/root-module:/module \
       cloudcustodian/c7n-left:dev run -p /policies -d /module

If the terraform root module has other remote module dependencies, you’ll need to fetch those first using terraform before running c7n-left.

terraform get -update

CLI Filters

Which policies and which resources are evaluated can be controlled via command line via --filters option.

Available filters

  • name - policy name

  • category - policy category

  • severity - minimum policy severity (unknown, low, medium, high, critical)

  • type - resource type, ie. aws_security_group

  • id - resource id ie. aws_vpc.example

Multiple values for a given filter can be specified as comma separate values, and all filters except severity support globbing.

Examples

# run all encryption policies on ebs volumes and sqs queues
c7n-left run -p policy_dir -d terraform --filters="category=encryption type=aws_ebs_volume,aws_sqs_queue"

# run all medium and higher level policies cost policies
c7n-left run -p policy_dir -d terraform --filters="severity=medium category=cost"

policy values for severity and category are specified in its metadata section. ie

policies:
  - name: check-encryption
    resource: [aws_ebs_volume, aws_sqs_queue]
    metadata:
      category: [encryption, security]
      severity: high
    filters:
       - kms_master_key_id: absent

Outputs

if your using this in github actions, we have special output mode for reporting annotations directly into pull requests with --output github

We also display a summary output after displaying resource matches, there are two summary displays available, the default policy summary, and a resource summary which can be enabled via --summary resource.

Policy Language

Policies for c7n-left support a few additional capabilities beyond what’s common for custodian policies.

Policies can be specified against multiple resource types either as an array or glob.

policies:
  - name: check-encryption
    resource: [aws_ebs_volume, aws_sqs_queue]

A traverse filter is available that allows for multi-hop graph traversal from a resource to any related resource.

ie, here’s a policy against an aws ec2 instance, that checks if any of the security groups attached to the instance, have a permission defined that allows access from 0.0.0.0/0

policies:
 - name: check-security-group-open-cidr
   resource: terraform.aws_instance
   description: "EC2 should not be open to world on ssh"
   filters:
     - type: traverse
       resources:
         - aws_security_group
         - aws_security_ingress_permission
       attrs:
         - Ipv4: 0.0.0.0/0