The shift to cloud-native has transformed the way organizations do business, keep up with the competition and meet the demands of customer expectations. From the infrastructure that maintains IT operations to the applications that supply customers with the ability to interact with their data, the velocity in which DevOps teams have to deliver these services has significantly increased, leaving little to no room for error. In order to properly manage infrastructure growth, tools like Terraform have helped organizations to create, change and improve infrastructure. However, as people, we are prone to error, which inevitably increases the risk that our organizations need to assume. At Styra, we believe that one of the best ways to mitigate risk is by creating declarative policies that empower your teams to decrease risk because they know what the policies are.
Terraform is a tool that allows you to describe a plan for your infrastructure. You can do things like build a virtual machine in Amazon Web Services to run containers in docker on your local machine. The important elements are that you declare the infrastructure resources that you want and the place, or places, that provide those resources. Here is a simple example of Terraform that creates a virtual machine in AWS.
To build this system I would run a terraform init to pull down the AWS Terraform provider and any other dependencies I may need. Once this is completed, I can run terraform plan -out plan.binary , which will refresh Terraform state from AWS and show me if there is anything my plan will change. Because this is the first time running, there isn't a state so the plan will return that if I run apply, the EC2 instance will be created. At this point, I can run terraform apply and my VM would be created (assuming I have the proper credentials for AWS). This is great, but, as I mentioned earlier, I want to make sure that my Terraform meets some best practices policies before I run that apply. I also have some standard things that I've used with Terraform in the past and I'd like to codify those so that whenever I write Terraform I can check and make sure I put those policies in as well.
A bit on Open Policy Agent and Rego
Hopefully, you're here because you already know how awesome OPA is and you just want to get into the nuts and bolts of how to use the new Terraform system type, but, just in case you're new, let me tell you about OPA and Styra DAS. OPA is a highly performant agent that allows you to query a declarative policy to get a policy result. For example, let's say that I have a policy that all my EC2 instances need to have a contact tag so that I can reach out to my team about unused instances. Here is what the policy would look like in Rego.
This rule is pretty simple. I'm going to iterate over all the planned modules and all those modules resources to find any that are of type aws_instance. Once I've found one (or many) I'm going to check if it has a tag with the Contact key value. If the contact is there, the rule would exit but if it's not there, I'm going to return a deny with a message with the name of the resource that needs the contact tag added.
Styra DAS Terraform System Type (A way to pull it all together)
I now have the start of a policy but I want to make that policy more accessible to the rest of my team. It would also be awesome if, as I'm developing the policy, I could validate the impact that the policy would have on the rest of my team's Terraform. I can do this by using the new Terraform system in Styra DAS. This will help me not only manage my policy but will also help write policies as it has several libraries and pre-defined rules. To start, all I need to do is log in to my Styra DAS tenant.
Once I'm logged in, I can create a Terraform system. One of the nice features of DAS is the helpful quickstart that will walk me through how to use the Terraform system and get more familiar. Now that I have a Terraform system, I'm going to pull down the Styra CLI and the OPA config file. The Styra CLI is an extension of the OPA CLI that has all the same features with the addition of a vet command to help with analyzing policy against a config file like a Terraform plan state file. To get the state file I run terraform plan -out plan.binary then I run terraform show -json plan.binary > plan.json. Now that I have the plan changes as JSON and the Styra CLI I can run styra vet plan.json -c <my_opa_config.yaml>. I don't have any policy in Styra DAS at the moment but I like to run the policy empty so that I can get a decision log in Styra DAS to help with development.
Develop, test and publish the policy
Awesome, now we have a Terraform system and the Styra CLI is set up locally and we can see our first decisions in Styra DAS. Now it's time to configure the policy. Personally, I like writing policy in Styra DAS directly because I can use code completion, preview and validation features. If you are not familiar with Rego you can also test out the policy builder feature that lets you describe your policy in English sentences that get translated to Rego. You can also connect the system up to a git repository so that the policy can be in source control.
If I expand the system we can see that there are folders already available. The policies folder is where I'm going to put my AWS Terraform policy. Conveniently, there is already an aws folder with an ec2 folder in it with a rules.rego file. It's up to you at this point how you want to structure your policy but since this is a policy for an EC2 this is where I'm going to write my policy. Since this isn't one of the prebuilt policies I'm going to open the code view and write my policy in as shown below.
You can see some really cool things already in the UI that are super helpful as I developed this policy. The first thing I'd like to point out is the violations box next to the policy card. This is showing me that there are previous Terraform plans that I’ve run that are not compliant with my policy. One thing I can do to confirm that is to click the “preview” button. This will use that same decision as the input for OPA and show me what the results would be.
Now if I click “publish” this policy and re-run the Styra CLI in my terminal, this rule will pass and the decision log will show allow because the rule is in monitor mode. If I click the Enforce button on the rule card (with a bit of time for the OPA bundle to get built) and re-run it will now fail that the Styra vet command failed and I can see a nice “Denied” decision in the decision log with the message about the instance needing a contact tag.
Awesome, I now have a policy to check to make sure that when I create an EC2 instance using Terraform that I have a contact tag for it. In addition to the policy that I just wrote there are also a bunch of policies that come with Styra DAS that are just a click away. We are also hard at work to get more of these rules done and to even have compliance standards like MITRE ATT&CK for Cloud and the CIS Benchmarks.
Keep an eye out as we continue to expand the library of rules as well as add additional system types and use cases to Styra DAS. As always be sure to check out all the awesome things we have going on over athttps://www.styra.com and be sure to sign up for a Styra DAS Free trialand test out this awesome Terraform system type.