Virtual Event
Join us for the next HashiConf Digital October 12-15, 2020 Register for Free

Enforce Policy with Sentinel [Team & Governance]

team & governance

Write a Sentinel policy for a Terraform deployment

In this tutorial, you will create policies and test them in the Sentinel CLI using data from the mock import data you downloaded in the previous guide.

You will choose the data to import based on what characteristics you want your policy to restrict. For example, you could use the tfrun import to restrict resources based on cost estimation. You could specify a limited number of providers to use in configuration with the tfconfig/v2 import. For more information about each import type, review the Terraform Cloud docs.

Visit Katacoda scenario for a safe environment with pre-generated Terraform data to build a multi-requirement Sentinel policy.

»Review the tfplan/v2 import mock data structure

Open the file named mock-tfplan-v2.sentinel in your text editor. Find the resource_changes collection. This Terraform data is a key/value collection for all of the resources in your configuration file. The data below is truncated, but your file should contain this collection with these values.

resource_changes = {
    "aws_s3_bucket.demo": {
        "address": "aws_s3_bucket.demo",
        "change": {
            "actions": [
                "create",
            ],
            "after": {
                "acl":                                  "public-read",
                "bucket_prefix":                        null,
                "cors_rule":                            [],
                "force_destroy":                        true,
                "grant":                                [],
                "lifecycle_rule":                       [],
                "logging":                              [],
                "object_lock_configuration":            [],
                "replication_configuration":            [],
                "server_side_encryption_configuration": [],
                "tags": {
                    "Environment": "Learn",
                    "Name":        "HashiCorp",
                },
##...
        },
        "deposed":        "",
        "index":          null,
        "mode":           "managed",
        "module_address": "",
        "name":           "demo",
        "provider_name":  "aws",
        "type":           "aws_s3_bucket",
    },

Terraform captures the attributes of any created or modified resource in the plan. You use this data in your Sentinel policies to determine which resources or attributes to restrict while in the planning stage.

»Build your policy

At the core of a policy, Sentinel evaluates your requirements against your imported data to two possible outcomes: Pass or Fail. Sentinel defines conditions with variables and operators to store values and make comparisons of logical expressions.

Change into the local machine named learn-sentinel-policies.

$ cd ~/learn-sentinel-policies

Create a file called restrict-s3-buckets.sentinel. Copy and paste the policy below.

import "tfplan/v2" as tfplan

s3_buckets = filter tfplan.resource_changes as _, rc {
  rc.type is "aws_s3_bucket" and
  (rc.change.actions contains "create" or rc.change.actions is ["update"])
}

required_tags = [
    "Name",
    "Environment",
]

allowed_acls = [
    "private",
    "public-read",
]

bucket_tags = rule {
    all s3_buckets as _, instances {
        all required_tags as rt {
        instances.change.after.tags contains rt
        }
    }
}

acl_allowed = rule {
    all s3_buckets as _, buckets {
    buckets.change.after.acl in allowed_acls
    }
}

main = rule {
    (bucket_tags and acl_allowed) else false
}

Sentinel determines what specific resources or data to evaluate from the import based on a filter expression. In the above policy, you will find a variable identifier called s3_buckets assigned to the filter expression. The expression returns a map of tfplan.resource_changes: a selector that searches the tfplan data collection for a field called resource_changes for S3 buckets created or updated in the plan data.

The next section of this policy contains the list of required_tags, "Name" and "Environment", defined as variables. These are the tags your plan data are required to contain.

The two rules in this policy search for the ACLs and buckets in your variables and compare them to the values found in your tfplan/v2 import rule and the main rule. The contains operator in the bucket_tags rule means the bucket_tags must contain both of the values in your variable. The in operator in the acl_allowed rule means at least one value in the list of your allowed_acls variable must match your return data.

The main rule evaluates both the bucket_tags and acl_allowed rules. If both are true, Sentinel allows the policy to pass. The Sentinel policy divides rules this way to keep the main rule short and allows you to evaluate your policy based on multiple rule criteria.

»Run your policy in the Sentinel CLI

Now, apply the Sentinel logic to the policy with the mock data and ensure your policy runs as expected.

In your terminal, apply the policy and provide the policy name.

$ sentinel apply restrict-s3-buckets.sentinel

Your policy will pass because your plan data meets your criteria.

»Next steps

You created and identified the parts of a Sentinel policy in this guide. In the next guide, you will write tests for this policy against Terraform Cloud data with the Sentinel CLI.