A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://developer.hashicorp.com/terraform/cloud-docs/policy-enforcement/sentinel below:

Define Sentinel policies in HCP Terraform | Terraform

Define Sentinel policies in HCP Terraform

This topic describes how to create and manage custom policies using Sentinel policy language. For instructions about how to use pre-written Sentinel policies from the registry, refer to Run pre-written Sentinel policies.

To define a policy, create a file and declare an import function to include reusable libraries, external data, and other functions. Sentinel policy language includes several types of elements you can import using the import function.

Declare and configure additional Sentinel policy language elements. The details depend on which elements you want to use in your policy. Refer to the Sentinel documentation for additional information.

Note: HCP Terraform Free edition includes one policy set of up to five policies. In HCP Terraform Plus and Premium editions, you can connect a policy set to a version control repository or create policy set versions with the API. Refer to HCP Terraform pricing for details.

A policy can include imports that enable a policy to access reusable libraries, external data, and functions. Refer to imports in the Sentinel documentation for more details.

HCP Terraform provides four imports to define policy rules for the plan, configuration, state, and run associated with a policy check.

You can create mocks of these imports to use with the the Sentinel CLI mocking and testing features. Refer to Mocking Terraform Sentinel Data for more details.

HCP Terraform does not support custom imports.

The following functions and idioms will be useful as you start writing Sentinel policies for Terraform.

Iterate over modules and find resources

The most basic Sentinel task for Terraform is to enforce a rule on all resources of a given type. Before you can do that, you need to get a collection of all the relevant resources from all modules. The easiest way to do that is to copy and use a function like the following into your policies.

The following example uses the tfplan import. Refer to our guides for other examples of functions that iterate over the tfconfig and tfstate imports.

import "tfplan"
import "strings"

# Find all resources of specific type from all modules using the tfplan import
find_resources_from_plan = func(type) {
    resources = {}
    for tfplan.module_paths as path {
        for tfplan.module(path).resources[type] else {} as name, instances {
            for instances as index, r {
                # Get the address of the resource instance
                if length(path) == 0 {
                    # root module
                    address = type + "." + name + "[" + string(index) + "]"
                } else {
                    # non-root module
                    address = "module." + strings.join(path, ".module.") + "." +
                              type + "." + name + "[" + string(index) + "]"
                }
                # Add the instance to resources, setting the key to the address
                resources[address] = r
            }
        }
    }
    return resources
}

Call the function to get all resources of a desired type by passing the type as a string in quotation marks:

aws_instances = find_resources_from_plan("aws_instance")

This example function does several useful things while finding resources:

Validate resource attributes

Once you have a collection of resources instances of a desired type indexed by their addresses, you usually want to validate that one or more resource attributes meets some conditions by iterating over the resource instances.

While you could use Sentinel's all and any expressions directly inside Sentinel rules, your rules would only report the first violation because Sentinel uses short-circuit logic. It is therefore usually preferred to use a for loop outside of your rules so that you can report all violations that occur. You can do this inside functions or directly in the policy itself.

Here is a function that calls the find_resources_from_plan function and validates that the instance types of all EC2 instances being provisioned are in a given list:

# Validate that all EC2 instances have instance_type in the allowed_types list
validate_ec2_instance_types = func(allowed_types) {
    validated = true
    aws_instances = find_resources_from_plan("aws_instance")
    for aws_instances as address, r {
        # Determine if the attribute is computed
        if r.diff["instance_type"].computed else false is true {
            print("EC2 instance", address,
                  "has attribute, instance_type, that is computed.")
        } else {
            # Validate that each instance has allowed value
            if (r.applied.instance_type else "") not in allowed_types {
                print("EC2 instance", address, "has instance_type",
                    r.applied.instance_type, "that is not in the allowed list:",
                    allowed_types)
                validated = false
            }
        }
    }
    return validated
}

The boolean variable validated is initially set to true, but it is set to false if any resource instance violates the condition requiring that the instance_type attribute be in the allowed_types list. Since the function returns true or false, it can be called inside Sentinel rules.

Note that this function prints a warning message for every resource instance that violates the condition. This allows writers of Terraform code to fix all violations after just one policy check. It also prints warnings when the attribute being evaluated is computed and does not evaluate the condition in this case since the applied value will not be known.

While this function allows a rule to validate an attribute against a list, some rules will only need to validate an attribute against a single value; in those cases, you could either use a list with a single value or embed that value inside the function itself, drop the allowed_types parameter from the function definition, and use the is operator instead of the in operator to compare the resource attribute against the embedded value.

Write Rules

Having used the standardized find_resources_from_plan function and having written your own function to validate that resources instances of a specific type satisfy some condition, you can define a list with allowed values and write a rule that evaluates the value returned by your validation function.

# Allowed Types
allowed_types = [
    "t2.small",
    "t2.medium",
    "t2.large",
]

# Main rule
main = rule {
    validate_ec2_instance_types(allowed_types)
}

Validate multiple conditions in a single policy

If you want a policy to validate multiple conditions against resources of a specific type, you could define a separate validation function for each condition or use a single function to evaluate all the conditions. In the latter case, you would make this function return a list of boolean values, using one for each condition. You can then use multiple Sentinel rules that evaluate those boolean values or evaluate all of them in your main rule. Here is a partial example:

# Function to validate that S3 buckets have private ACL and use KMS encryption
validate_private_acl_and_kms_encryption = func() {
    result = {
        "private":          true,
        "encrypted_by_kms": true,
    }
    s3_buckets = find_resources_from_plan("aws_s3_bucket")
    # Iterate over resource instances and check that S3 buckets
    # have private ACL and are encrypted by a KMS key
    # If an S3 bucket is not private, set result["private"] to false
    # If an S3 bucket is not encrypted, set result["encrypted_by_kms"] to false
    for s3_buckets as joined_path, resource_map {
        #...
    }
    return result
}

# Call the validation function
validations = validate_private_acl_and_kms_encryption()

# ACL rule
is_private = rule {
    validations["private"]
}

# KMS Encryption Rule
is_encrypted_by_kms = rule {
    validations["encrypted_by_kms"]
}

# Main rule
main = rule {
    is_private and is_encrypted_by_kms
}

You can write similar functions and policies to restrict Terraform configurations using the tfconfig import and to restrict Terraform state using the tfstate import.

  1. Group your policies into sets and apply them to your workspaces. Refer to Create policy sets for additional information.
  2. View results and address Terraform runs that do not comply with your policies. Refer to View results for additional information.
  3. You can also view Sentinel policy results in JSON format. Refer to View Sentinel JSON results for additional information.

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4