Skip to main content

Terraform Policy Authoring

Policy authoring with Terraform systems allows you to write Rego rules which are evaluated against the contents of the Terraform plan JSON file. This page assumes you are familiar with the OPA concepts of packages and the rules they contain as well as the Styra DAS Policy Lifecycle.

Terraform plans enable you to see what changes Terraform needs to make to cloud resources before it makes them. The policies you define in Styra DAS determine whether the changes in the plan are safe to make or not. The basic rules that you write are partial-set rules that either reject or monitor a request. The Terraform system type supports the following entry points for policy evaluation: enforce and deny to reject a Terraform resource change, and monitor and warn to provide a warning about a Terraform resource change.

Each of the partial sets contain either a single string indicating the message to return to the user or an object which includes the message field. The object can also include custom user-defined fields. Styra DAS will always add "allowed": false to the returned object if not explicitly defined.

info

Terraform policy rules which return evaluation decisions must be defined in policy packages which follow the naming format package policy.<provider>.<resource>. See the Policy Structure section for additional details.

Rule Formats

The following rule formats are supported when defining policies for a Terraform system.

Enforce - Results in a policy failure.

enforce[decision] {
...
decision := {
"allowed": false,
"message": "Message explaining why there is a problem"
}
}

Monitor - Results in a policy warning.

monitor[decision] {
...
decision := {
"allowed": false,
"message": "Message explaining why there is a problem"
}
}

Additional Supported Formats

For compatibility reasons, the following rule formats are also supported, though we recommend you define rules using the formats in the Rule Formats section above.

Deny - Results in a policy failure.

deny[decision] {
...
decision := {
"message": "Message explaining why there is a problem"
}
}

deny[message] {
...
message := "Message explaining why there is a problem"
}

Warn - Results in a policy warning.

warn[decision] {
...
decision := {
"message": "Message explaining why there is a problem"
}
}

warn[message] {
...
message := "Message explaining why there is a problem"
}

Policy Package and Module Structure

Styra DAS Terraform system policies are organized based on the provider and the resources/services within that provider (i.e., package policy.<provider>.<resource>) to mirror the provider >> resource structure of Terraform. This structure also helps organize your policy rules according to the resources/services they impact. For example, policy rules relating to AWS S3 buckets should reside within modules in the policy.aws.s3 package. You can create multiple policy modules within each package for further organization. For example, the policy.aws.s3 package could include encryption.rego, versioning.rego, and replication.rego.

While policy rules may be placed at any level within the policy hierarchy (e.g., a policy.utils package with helpers), only the enforce/deny and monitor/warn rules in modules following the package policy.<provider>.<resource> hierarchy will be applied to Terraform plans.

For example, the enforce rule in the first example policy below will be applied to Terraform plans while the following two monitor and enforce rules will not as they reside in packages which do not follow the policy.<provider>.<resource> hierarchy.

package policy.myprovider.myresouce

# Enforce rule will be applied to Terraform plan evaluation
enforce[decision] {
...
}
package policy.myprovider

# Monitor rule will not be applied to Terraform plan evaluation
monitor[decision] {
...
}
package policy.myprovider.myresouce.utils

# Enforce rule will not be applied to Terraform plan evaluation
enforce[decision] {
...
}

The structure of policies within Styra DAS Stacks is the same as the structure of policies within Styra DAS Systems. Rules you add to packages following the stacks.<stackID>.policy.<provider>.<resource> hierarchy at the stack level are applied to Terraform plans of associated Terraform systems.

The names of provider and resource in the package path may be any values useful to you to organize your rules (e.g., policy.foo.bar), however, the aws, azure, and gcp provider names are meaningful in the Styra DAS UI as they enable displaying rules associated with those providers from Styra's Terraform Policy Library within the policy builder UI (accessible via the Add rule button in the policy editor).

Default Terraform Policy Packages and Modules

Upon creation of a new Styra DAS Terraform system, three policy packages and modules are automatically added to your system to get you started and to provide a policy organization guide. These default packages and modules are:

  • package policy.aws.ec2 with rules.rego located in the policy >> aws >> ec2 sub-folder.
  • package policy.azure.vms with rules.rego located in the policy >> azure >> vms sub-folder.
  • package policy.gcp.compute with rules.rego located in the policy >> gcp >> compute sub-folder.

When editing these policy modules in Styra DAS, usage of Styra's Terraform Policy library is enabled. You can add rules from the policy library by clicking the Add rule button when editing policies.

Add additional modules to the default policy packages by clicking on the options menu on the policy.<provider> folder and selecting Add Policy. Define a new or existing package path (e.g., kms if adding KMS policies to the policy.aws package) and define a module name.

If not needed for your use case, delete any default packages and modules. If needed in the future, manually add them using Add Policy.

Custom Terraform Policy Packages and Modules

Create custom policy packages and modules to meet your specific Terraform use cases, whether for Terraform providers other than AWS, Azure, or Google Cloud, or for policies relating to Terraform Cloud or Terraform Enterprise runs.

For example, for Terraform systems integrated with Terraform Cloud/Enterprise, create a policy which prevents Friday deploys via Terraform Cloud/Enterprise by defining rules in a policy.tfc.runs package:

package policy.tfc.runs

enforce[decision] {
message := "No deployments allowed on Fridays"

time.weekday(time.now_ns()) == "Friday"

decision := {
"allowed": false,
"message": message
}
}

Terraform Policy Tests and Data Sources

Test policies can be placed anywhere within a Styra DAS Terraform system, however, Styra typically recommends you put them in separate packages so that they are not downloaded by the OPA agent as part of the policy bundle, helping to reduce the bundle size.

Data sources can also be added to your Terraform system. Data sources provide a dedicated location for injecting external data which can be used as part of policy evaluation (e.g., an LDAP data source with user roles and permissions).

note

Data sources cannot be placed at a path which is a prefix of a policy package path or another data source path.

Styra's Terraform Policy Library

Styra's growing Terraform Policy Library includes pre-built rules for AWS, Azure, and Google Cloud to help organizations follow IaC best practices. Rules from the policy library can be added via the Styra DAS policy builder UI by clicking the Add rule button when viewing/editing a policy module with a package prefix of policy.<provider>, where <provider> is aws, azure, or gcp.

For example, a pre-built rule which does not require any configuration options, such as requiring S3 buckets to be encrypted, would be added to your policy file like so:

enforce[decision] {
data.global.systemtypes["terraform:1.0"].library.provider.aws.s3.unencrypted.v1.unencrypted_s3_bucket[message]

decision := {
"allowed": false,
"message": message
}
}

The list of current pre-built rules can also be found on the Terraform Policy Library Rules page.

For information on writing custom policies, see the Styra Academy or the Open Policy Agent policy language documentation.