Integration & Automation
A practical guide to getting started with policy as code
Modern enterprises have learned the value of automation in their end-to-end software development lifecycles (SDLCs). Automation mechanisms provide consistent and reliable methods to build and deploy code and their related environments without human intervention. This post highlights ways in which you can get started with policy as code (PaC). It’s used to enforce security configuration policies, service configuration standards, and complement automations you may already be using for code and environment development and deployment.
PaC is a software automation approach, similar to infrastructure as code (IaC), that aids the assessment of an organization’s configuration and validation compliance requirements through the use of software automation constructs. You can use a consistent and automated means of enforcing enterprise standards and best practices across your organization while minimizing manual processes. Pre-built and pre-validated software constructs are used to assess compliance factors in software code—both when code is initially written, and again when it’s deployed for use. The result is confidence that deployed assets are in fact compliant with policy rules.
Previous blog posts have more thoroughly described the four main types of controls (preventative, proactive, detective, and responsive) used to assess and react to compliancy matters. For more details, see Governance at scale: Enforce permissions and compliance by using policy as code and Cloud governance and compliance on AWS with policy as code.
The following diagram suggests where such controls are typically employed.
Choosing your PaC approach
The following is a recommended set of steps to help prepare you for choosing the right approach for PaC.
Assess suitable policies
Many organizations don’t have a well-documented set of compliance policies. Additionally, those that are documented might not be readily subject to codification. An initial assessment is required to assemble the list of target policies in a suitable inventory style. A smaller, initial set of PaC automation targets can then be assembled using the following criteria:
- For those new to PaC, it’s recommended that policies be chosen that aren’t overly complex, and are easily codified. For example, “I want to make sure that Service X is not configured with property Y.”
- Start small:
- Identify a few key areas where you want to either reduce misconfigurations or reduce your overall security risks.
- Map out impact vs. complexity of implementation. Start with putting together a list of known configuration issues in your accounts.
- Pick the highest risk areas to automate. Capture both the risk (critical, high, medium, low) according to your organization’s InfoSec or Security team as well as using third-party recommendations (such as NIST or CIS benchmarks). Capture the quantity of occurrences of each configuration finding per service. This provides you with a snapshot of both risk severity as well as misconfiguration occurrence. Prioritize the top items from each list and begin defining target policy rules (preventive, proactive).
- Be agile and iterate.
- It’s common for enterprises to use a centralized, manual, human-driven process to author and assess complex, critical, or often-changing policies. For enterprises new to PaC, it’s therefore best to target less critical policies, such as those that are commonly assessed in a repetitive, undifferentiated manner across workloads. These compliance actions are more suitable for automation and for authoring by teams outside of the centralized compliance organization.
Determine the degree of shift-left
“Shift-left” is a well-known practice and philosophy designed to find and correct defects earlier in the SDLC, thereby reducing the number of compliance-related issues that leak into the production. When considering PaC, you should implement these constructs early in the software development phases where proactive controls can be used.
How far you shift left depends on technology and resources available across the organization. Ideally, PaC constructs should be considered at the point where IaC templates are initially created. If you use AWS CloudFormation, it’s recommended to start with AWS CloudFormation Guard running from the AWS Command Line Interface (AWS CLI), allowing you to define and run rules at the individual resource level as well as other related resources within the same CloudFormation template file. If you have more complex rules requiring logic evaluations that can’t be defined as CloudFormation Guard rules, or runtime parameter assessment is required, then AWS CloudFormation Hooks is recommended.
Code-defined AWS CDK option
Consider migrating from a pure template or nested-stack IaC approach and instead using a code-defined application and resources approach. One tool that can help with this approach is the migration capabilities of the AWS Cloud Development Kit (AWS CDK). This allows you to use your existing CloudFormation templates and AWS tools handle the heavy lifting to migrate your IaC to the AWS CDK. This initial step in migrating from AWS CloudFormation to the AWS CDK provides a simple translation of IaC to AWS CDK constructs of various levels:
- Level 1 – Level 1 constructs are also known as CloudFormation resources, and are the lowest-level construct, and offer no abstraction. Each Level 1 construct maps directly to a single CloudFormation resource.
- Level 2 – Level 2 constructs extend Level 1 constructs and allow encapsulation of rules, which allows you to specify acceptable values enables parameter validation. For example, if you want to block public access for Amazon Simple Storage Service (Amazon S3) buckets, your organization’s construct for Amazon S3 can force that required implementation by defaulting the attributes as needed and not allowing override.
- Level 3 – Level 3 constructs go a step further, allowing you to bundle architecture patterns together. This level not only encapsulates rules, but can drive best practices. You can also use AWS CDK aspects to validate your configurations, along with the AWS CDK Guard Validator, which allows you to validate both AWS managed CloudFormation Guard rules as well as customer managed CloudFormation Guard rules at the time of rule authoring.
Align PaC to your organization
A well-structured set of accounts will be comprised of organizational units (OUs) based on security compliance controls and needs (see AWS Organizations for more details). PaC constructs need to follow the same structure. Deployment of controls (whether using CloudFormation Hooks or CloudFormation Guard rules) should be based on where in the organization your workload is being deployed. For example, your enterprise policy may require the prohibition of public S3 buckets. However, there may be a unique business need to do so. In that case, you want this workload isolated in an OU that holds exceptions to the rules, and you can then exclude your Amazon S3 public policy from being evaluated against your workload.
Implement PaC
With the preceding preparation and consideration steps complete, you can now focus on the actual implementation of PaC. This section outlines a set of simple steps to get you started:
- Using the preceding preparation steps, first select and document the targeted policies and rules. Include test conditions and any rule references back to the organizational security policies:
- See if the rule already exists:
- Is there an existing managed proactive control that matches your rule?
- Is there a rule within the CloudFormation Guard Registry?
- Author the rule (either in CloudFormation Guard or CloudFormation Hooks).
- Write pass/fail unit test cases.
- Run the unit test cases.
- Write pass/fail integration tests with sample CloudFormation templates.
- Run the integration test cases.
- Commit the rule and tests to a centralized organization repository
- See if the rule already exists:
The next step is to define a repository to capture all of your PaC rules and constructs.
- For local development rule validation, complete the following steps:
- Download and install the CloudFormation Guard CLI (for more information, see Setting up AWS CloudFormation Guard or the AWS CloudFormation Guard User Guide).
- Clone the rule repository to your local development environment.
- Create or change the IaC resources (either AWS CloudFormation or AWS CDK).
- If AWS CDK, run
cdk synth
to generate the output CloudFormation template.
- If AWS CDK, run
- Run the CloudFormation Guard CLI to validate the CloudFormation template (for more details, see AWS CloudFormation Guard CLI parameters and command reference):
- For a pre-commit hook or a continuous integration and delivery (CI/CD) build process, complete the following steps:
- Download and set up the CloudFormation Guard CLI.
- Clone the rule repository.
- Clone the application repository with the IaC template or code.
- Run the CloudFormation Guard CLI to validate the CloudFormation template.
- Examine the return code to determine if the output contains any failures.
- For CloudFormation Hooks, you will need a build pipeline as well as the use of CloudFormation StackSets to deploy the hooks to the desired OUs or accounts. The build process will need to download and install the CloudFormation CLI. For instructions to build and deploy CloudFormation Hooks using StackSets, see Deploy CloudFormation Hooks to an Organization with service-managed StackSets.
After the chosen process has been prototyped on a few small projects, you begin to scale utilization to more numerous and more complex projects. As you become more adept and confident with PaC, you can pull in more rules to construct and validate.
Troubleshooting
The following common limitations could result in issues as you implement PaC:
- Conditions preventing shift-left – Be aware of conditions where you may not be able to implement PaC controls as early as the code author stage. If your code references configuration properties that require deploy time or resource provisioning evaluation (such as a value pulled from Parameter Store, a capability of AWS Systems Manager, or AWS Secrets Manager), then any CloudFormation template will fail because it will be unable to resolve such parameter values until runtime. When creating a new resource, be aware that values such as the resource identifier are not assigned until after the resource is created. In these cases, you may have to move PaC evaluations into a runtime phase using CloudFormation Hooks, or even using AWS Config rules as a post-runtime detective control.
- Nested CloudFormation templates – Nested templates are evaluated during the CloudFormation template deploy stage after a fully resolved template is generated. CloudFormation Guard only checks the resource definitions directly within the CloudFormation template being evaluated, and any nested templates are not included in the evaluation. These same restrictions to CloudFormation Guard also apply if you’re using this tool to use a repository pre-commit hook or during a build or test step. It is advisable to use PaC on non-nested stacks, or through re-factoring of nested stacks to avoid this runtime issue.
- Using proactive controls in the deploy phase – If evaluation of runtime or input parameters is required, CloudFormation Hooks or AWS Config managed hooks may be the better choice. With CloudFormation Hooks, the hook is evaluated at the time of deployment. CloudFormation template parameters are resolved at time of deployment, allowing them to be properly validated.
- Defaulting to detective controls – If parameterization and nesting still yield issues, then detective controls should be used. When a resource is deployed or changed, this change is observed by AWS Config, which can evaluate customer managed and AWS managed rule sets, which can create findings if any rules violations are detected.
Balancing controls across the SDLC timeline
A best practice is to make sure you have coverage throughout the lifecycle of your AWS resources. Pull as many of the controls as far left as possible, and balance these with additional controls purposefully placed later in the development timeline (such as detective controls or AWS Config rules). This allows PaC coverage in boundary cases or out-of-band events such as emergency changes to a resource through the AWS Management Console or AWS CLI. Policy errors introduced with such real-time changes are still caught by downstream detective processes, making sure that misconfigured services are highlighted.
Standard software best practices
PaC constructs are software elements. Standard software best practices should be used for the development and maintenance of PaC code constructs, including version control, comprehensive testing, usage of a central, democratized construct library, and standardized software lifecycle maintenance philosophies and toolsets.
PaC governance
Change management governance is required of PaC constructs, just as it is required for other software code assets. As more and more teams use shared PaC constructs, they will develop dependencies on those constructs, and shared change management mechanisms will be required. Multiple teams may want to add or modify rules, and changes will need to be validated per line of dependency. As you initially adopt PaC, begin engaging in thought leadership conversations around the typical lifecycle use cases and change management considerations required.
Lastly, establish naming and verbiage conventions for your rule code and files, rule method and definitions, as well as the rule alert and error messages. See the appendix at the end of this post for examples.
Conclusion
In this post, we detailed the concepts, processes, and steps to get started with PaC and adopt this into your software development lifecycle. PaC can improve your overall security posture, improve consistency of service usage across your organization, and reduce rework or workloads deployed to your AWS accounts. To get started, see the references listed in the appendix, and determine if you want to get started with using the AWS CDK, CloudFormation Guard, or CloudFormation Hooks (or a combination of each). Check out the sample code repositories and already published rules, then begin experimenting.
Appendix
References
The following are additional references you can use as you begin your PaC journey. These include references for background information as well as sample code and other how-to guides:
- Governance with PaC:
- CloudFormation Hooks:
- CloudFormation Hooks User Guide
- CloudFormation Hooks Lambda Invoker
- Proactively keep resources secure and compliant with AWS CloudFormation Hooks
- CloudFormation Hooks Samples
- CloudFormation Hooks Community Samples
- Build and Deploy CloudFormation Hooks using A CI/CD Pipeline
- AWS CloudFormation Hooks | Serverless Office Hours
- Publishing your extension in multiple Regions using AWS CloudFormation StackSets
- CloudFormation Guard:
- Control Tower Controls:
Also, check out the following new and noteworthy posts:
- Author AWS CloudFormation Hooks using the CloudFormation Guard domain specific language
- AWS CloudFormation Hooks now support custom AWS Lambda functions
- AWS CloudFormation Hooks introduces stack and change set target invocation points
Implement PaC constructs
The following are services and tools within AWS to implement the various PaC constructs:
- Preventive control:
- Service Control Policies (SCPs) – SCPs are a type of organization policy that you can use to manage permissions in your organization. SCPs offer central control over the maximum available permissions for all accounts in your organization. SCPs help you make sure your accounts stay within your organization’s access control guidelines.
- Proactive controls:
- AWS CloudFormation Hooks – Hooks proactively inspect the configuration of your AWS resources before provisioning. If non-compliant resources are found, AWS CloudFormation returns a failure status and either fails the operation or provides a warning and allows the operation to continue based on the hook failure mode. You can use pre-built hooks or build your own hooks using the AWS CloudFormation CLI.
- AWS Config rules – Evaluated as managed CloudFormation hooks, AWS Config rules evaluate the configuration settings of your AWS resources as they are being deployed through AWS CloudFormation.
- AWS CloudFormation Guard – AWS CloudFormation Guard is an open source, general-purpose, PaC evaluation tool. The CloudFormation Guard CLI provides a simple-to-use, yet powerful and expressive, declarative DSL that you can use to express PaC. In addition, you can use CLI commands to validate structured hierarchical JSON or YAML data against those rules. For additional details, see the GitHub repo.
- AWS CDK aspects – Aspects are a way to apply an operation to all constructs in a given scope. The aspect could modify the constructs, such as by adding tags. Or it could verify something about the state of the constructs, such as making sure that all buckets are encrypted.
- AWS CDK plugins – Plugins extend functionality of AWS CDK by adding new commands or modifying existing ones. Both AWS CDK aspects and plugins can be used for policy enforcement. The main difference is that aspects are invoked during synthesis and can modify resource configuration, whereas plugins are run after synthesis and can’t affect the generated template. An example of this is the CloudFormation Guard Validator plugin.
- AWS CloudFormation Guard rules – In CloudFormation Guard, rules are PaC rules. You write rules in the CloudFormation Guard DSL that you can validate your JSON- or YAML-formatted data against. Rules are made up of clauses.
- Open Policy Agent – The Open Policy Agent (OPA) is an open source, general-purpose policy engine that unifies policy evaluation across the stack. OPA provides a high-level declarative language that lets you specify PaC and simple APIs to offload policy decision-making from your software. You can use OPA to evaluate policies in microservices, Kubernetes, CI/CD pipelines, API gateways, and more. You can use OPA as the rules definition within AWS Config rules (see Using OPA to create AWS Config rules) as well as a way to validate your configurations before deployment (see Cloud governance and compliance on AWS with policy as code).
- Detective controls:
- AWS Config rules – Use AWS Config to evaluate the configuration settings of your AWS resources. You do this by creating AWS Config rules, which represent your ideal configuration settings. AWS Config provides customizable, predefined rules called managed rules to help you get started. While AWS Config continuously tracks the configuration changes that occur among your resources, it checks whether these changes don’t comply with the conditions in your rules.
- Responsive controls:
- The basic procedure used to establish this process is to define a workflow on what is needed to do based on the specific findings as well as understand the risk and priority of the findings. By defining the workflow and process, you can begin the steps to script the remediation of the findings, ultimately getting to the point where you can automate this remediation process. Not everything should be automated, but it’s a best practice to automate the well-understood configuration issues. Also, this process, whether fully automated or not, should continue to follow your organizational standards and processes for notifications as well as an incident ticketing process. This will allow your security and audit teams to be able to track findings and incidents, even if they are automatically remediated. Consider the following services:
Sample error message
The following is a sample error message:
- Rule file name:
s3_prohibit_public_access.guard
- Named rule:
S3_PROHIBIT_PUBLIC_READ
- Validation messages:
- Violation: SEC 1.1 No publicly accessible storage. All storage of files and data should not be publicly accessible. Access to these files should be controlled through application permissions.
- Fix: Set S3 Bucket PublicAccessBlockConfiguration properties for BlockPublicAcls, BlockPublicPolicy, IgnorePublicAcls, RestrictPublicBuckets parameters to true.
Sample security policy mapping
The following is an example of a security policy to AWS service mapping table.
Security Policy ID | Security Policy Title | Security Policy Definition | AWS Service | AWS Service Configuration Settings |
Sec 1.1 | No publicly accessible storage | All storage of files and data should not be publicly accessible. Access to these files should be controlled through application permissions. | Amazon S3 | |
Sec 1.2 | Storage should be encrypted | All storage (file, block, object) should be encrypted with a minimum of AES256. | Amazon S3 | |
Amazon EBS |
About the Authors
Andrew Timpone is a Senior Solutions Architect at AWS. With over 5 years of experience in cloud architecture, Andrew helps large enterprise customers solve their business problems using AWS. Andrew has over 25 years of IT experience with expertise in enterprise integration patterns. Andrew is married with three children and resides just south of Cleveland, OH, where he enjoys bicycle riding, archery, and vegetable gardening.
Dean Banwart has served as an AWS Sr. Customer Solutions Manager for over 5 years and currently works within the Enterprise Auto/Manufacturing vertical. Dean has over 45 years of professional engineering experience with expertise in the areas of telecommunications, systems engineering, manufacturing, and encryption technology. Dean is married with four children and resides in the Northwest suburbs of Chicago, where he enjoys outdoor sports, music, and restoration of vintage electronics and equipment.