Policy as Code automates enforcement and implementation via the policy to find out logical inconsistencies , syntax error, missing dependencies before they go into Infrastructure Provisioning process through the IAC. They act as guardrails and are proven to be valuable in Infra code testability. Policy as code ensures consistency and accountability with version control and transparency improving development efficiency. They reduce implementation error and deployment time along with prevention of drifts early in the development
Some Examples of Policy as Code are
Hashicorp Sentinel
Pulmi Crossguard
Open Policy Agent
Cloudformation Guard
In this blog we will be talking about CloudFormation Guard which is an opensource policy as code evaluation tool
The AWS’s Guard command line interface (CLI) provides a simple-to-use, yet powerful and expressive, declarative domain-specific language (DSL) that you can use to express policy as code. Also you can use CLI commands to validate structured hierarchical JSON or YAML data against those rules. Guard also provides a built-in unit testing framework to verify that your rules work as intended.
Cfn-lint is like typescript for js. It does thorough inspection of the template instruction. The linter shows error on wrong formats.
Cfn guard is opensource cli. For example Creating rules to ensure the cryptographic keys for ec2 is always set or The volume of ec2 is always less than 20 GB and is encrypted.
Installing the Cloudformation Guard CLI
curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/aws-cloudformation/cloudformation-guard/main/install-guard.sh | sh |
Set the path (optionally in ~/.bashconfig)
export PATH=~/.guard/bin:$PATH |
Check if cfn-guard is installed
Cfn-guard --version |
Rules are made of clauses based upon the Guard domain-specific language (DSL) that an be validated for json or yaml structures. Rules can be on plaintext and doesnot require an extension.
Guide to Migrating if youre already using cfn-guard 1.0 to 2.0 or later
cfn-guard migrate --output migrated_rules.guard --rules rules.guard |
Unit Testing Syntax
--- |
Validating multiple rules against a template.
cfn-guard validate --data /path/to/dataDirectory --rules /path/to/ruleDirectory |
Lets get started with ec2 volume size
We are saving this sample template to create a ec2 volume of type gp2 with size 10 gb
--- |
Creating a Rule
Now let’s create a rule that says the size should be less than or equal to 30 gb and type should be gp2
AWS::EC2::Volume { |
Now lets validate with the cfn-guard cli
cfn-guard validate -d your-test.template -r your-test.rules |
The Result for failed test because our yaml contains g[2 and the rule contains gp2
cfn-guard validate -d your-test.template -r your-test.rules your-test.template Status = FAIL FAILED rules your-test.rules/default FAIL --- Evaluating data your-test.template against rules your-test.rules Number of non-compliant resources 1 Resource = SampleVolume { Type = AWS::EC2::Volume Rule = your-test.rules/default { ALL { Check = VolumeType EQUALS "gp3" { ComparisonError { Error = Check was not compliant as property value [Path=/Resources/SampleVolume/Properties/VolumeType[L:8,C:18] Value="gp2"] not equal to value [Path=[L:0,C:0] Value="gp3"]. PropertyPath = /Resources/SampleVolume/Properties/VolumeType[L:8,C:18] Operator = EQUAL Value = "gp2" ComparedWith = "gp3" Code: 6. Properties: 7. Encrypted: true 8. Size: 10 9. VolumeType: gp2 } } } } } |
The guard test failed because gp2 was compared with gp3. The test passes when the value is gp2
Now let’s also modify the volume size to <= 40
It gives another error
Note the two errors for size
Value is 10 and compared with greater than or equal to 40 gb
The next error is as of previous for the type of the volume gp3
Now we can enforce rules for our Infrastructure as code