Sentinel
Write your first policy
With Sentinel installed, you are ready to create your first policy.
In this tutorial, you will write a Sentinel policy for HashiCups, a fictional coffee shop. This policy will validate coffee orders, ensuring they meet specific criterias. Sentinel policies let you enforce business rules to standardize your operations.
Prerequisites
To follow this tutorial, you need the Sentinel CLI installed locally on your machine.
Tip
  You can find the complete configuration for these tutorials in the Learn Sentinel Get Started GitHub repository. The configuration for this specific tutorial is in the 01-write-policy branch.
Create a directory for your Sentinel policies.
$ mkdir learn-sentinel-hashicups
Change into the directory.
$ cd learn-sentinel-hashicups
Set up the Sentinel file structure
Before writing your first policy, we recommend you set up the file structure for your Sentinel project. While you can format it in any way, the following structure helps organize your policies and makes it easier to manage as your project grows.
The recommended structure includes a Sentinel configuration file and a policies directory.
Create the Sentinel configuration file. Sentinel uses this file to determine how to load and apply your policies. You will add contents to this file later in this tutorial.
$ touch sentinel.hcl
Create a policies directory to store your Sentinel policies.
$ mkdir policies
Your project structure should now look like the following.
learn-sentinel-hashicups/
├── sentinel.hcl
└── policies/
Write policy
HashiCups wants to ensure each coffee order is valid — the order should only contain valid coffee names and sizes.
Create a file for this policy.
$ touch policies/validate_coffee_order.sentinel
Open policies/validate_coffee_order.sentinel in your text editor, paste in the configuration below, and save the file.
policies/validate_coffee_order.sentinel
# Parameters and variables
param coffee_name default "HCP Aeropress"
param coffee_size default "small"
# Valid coffee names
valid_coffees = [
  "HCP Aeropress",
  "Packer Spiced Latte",
  "Vaulatte",
  "Nomadicano",
  "Terraspresso",
  "Vagrante espresso",
  "Connectaccino",
  "Boundary Red Eye",
  "Waypointiato",
]
valid_sizes = ["small", "medium", "large"]
## Rules
# Validate coffee name
validate_name = rule {
  coffee_name in valid_coffees
}
# Validate coffee size
validate_size = rule {
  coffee_size in valid_sizes
}
# Main rule to validate a coffee order
main = rule {
  validate_name and
  validate_size
}
This is a complete Sentinel policy that you can evaluate. The following sections review each block of this configuration in more detail.
Parameters and Variables
Sentinel uses both parameters and variables to store and reference data within your policy. While they may seem similar, they serve different purposes and have distinct characteristics.
Parameters
Parameters let you pass external values into a policy, making your policies more flexible and reusable.
This policy defines coffee_name and coffee_size as parameters with default values for a coffee order. You can override these defaults when you apply the policy, allowing you to test different scenarios without changing the policy code.
policies/validate_coffee_order.sentinel
param coffee_name default "HCP Aeropress"
param coffee_size default "small"
Variables
Sentinel uses variables to store and reference data within your policy. They can hold simple values, lists, or complex data structures. Variables are useful for internal data organization and constants, which helps improves the readability and maintainability of your policy.
This policy contains two variables.
- The valid_coffeeslist contains all available coffee names from the HashiCups menu.
- The orderlist contains all available sizes.
policies/validate_coffee_order.sentinel
valid_coffees = [
  "HCP Aeropress",
  "Packer Spiced Latte",
  "Vaulatte",
  "Nomadicano",
  "Terraspresso",
  "Vagrante espresso",
  "Connectaccino",
  "Boundary Red Eye",
  "Waypointiato",
]
valid_sizes = ["small", "medium", "large"]
Rules
Rules are the core of Sentinel policies. They define the conditions that must be true for a policy to pass. Rules can use logical operators to combine multiple conditions, rules and functions to perform more complex evaluations.
Sentinel returns the result of the main function. If a rule within the main rule fails, Sentinel will notify you that both the main rule and the sub-rule fails. If a function within the main rule fails, Sentinel will only notify you the main rule failed.
This policy contains three rules:
- The validate_namerule checks if the coffee name is in the list of valid coffees.
- The validate_sizerule ensures the size is one of the allowed values.
- The mainrule combines the results of validate_name and validate_size using the and operator.
policies/validate_coffee_order.sentinel
# Validate coffee name
validate_name = rule {
  coffee_name in valid_coffees
}
# Validate coffee size
validate_size = rule {
  coffee_size in valid_sizes
}
# Main rule to validate a coffee order
main = rule {
  validate_name and
  validate_size
}
Format the policy
Format your policy to ensure your configuration is readable. You must explicitly specify the file you want to format.
$ sentinel fmt policies/validate_coffee_order.sentinel 
1 file(s) formatted.
Define Sentinel configuration file
The Sentinel configuration file, typically named sentinel.hcl, is a crucial component in managing your Sentinel policies. You can manage all your policies from a single file, making it easier to organize and maintain your policy set. The configuration file also makes it easier to integrate Sentinel policy checks into your continuous integration and deployment pipelines.
Open sentinel.hcl in your text editor, paste in the configuration below, and save the file.
sentinel.hcl
policy "validate_coffee_order" {
  source = "./policies/validate_coffee_order.sentinel"
}
policy "validate_coffee_order_override" {
  source = "./policies/validate_coffee_order.sentinel"
  params = {
    coffee_name = "Cappuccino"
    coffee_size = "extra-large"
  }
}
Each policy block in the sentinel.hcl file defines a policy that Sentinel should evaluate. You can have multiple policy blocks, allowing you to manage several policies in one configuration file. 
The source parameter specifies the location of the Sentinel policy file relative to the sentinel.hcl file. In this example, ./policies/validate_coffee_order.sentinel tells Sentinel to look for the policy file in the policies subdirectory.
You can define multiple policy blocks with different parameters, allowing you to test various scenarios without modifying the policy file itself. For example, you can create different configuration files for different environments (e.g., development, staging, production) with appropriate parameter overrides.
This configuration defines two policy instances.
- The validate_coffee_orderpolicy uses the default parameter values.
- The validate_coffee_order_overridepolicy overrides the default parameters with an invalid name and size.
Apply the policy
Apply your policy with the Sentinel CLI. Notice, the validate_coffee_order passes and the validate_coffee_order_override fails as expected.
$ sentinel apply
Execution trace. The information below will show the values of all
the rules evaluated. Note that some rules may be missing if
short-circuit logic was taken.
Note that for collection types and long strings, output may be
truncated; re-run "sentinel apply" with the -json flag to see the
full contents of these values.
The trace is displayed due to a failed policy.
Pass - validate_coffee_order.sentinel
Fail - validate_coffee_order_override.sentinel
Description:
  Main rule to validate a coffee order
validate_coffee_order_override.sentinel:33:1 - Rule "main"
  Description:
    Main rule to validate a coffee order
  Value:
    false
validate_coffee_order_override.sentinel:23:1 - Rule "validate_name"
  Description:
    Validate coffee name
  Value:
    false
Notice when you applied your Sentinel policies, Sentinel automatically creates a .sentinel directory. Sentinel creates this runtime directory to store manifest files to associate Sentinel policy components with their source file. For example, in the .sentinel/policies/manifest.json, you will find the following.
Depending on where you source your policies and modules, we recommend you add the .sentinel directory to your .gitignore file. Sentinel will look for the policy in the dest path. Since this path is unique to each user at runtime, Sentinel may return an error.
.sentinel/policies/manifest.json
{
  "records": [
    {
      "key": "validate_coffee_order_override",
      "source": "./policies/validate_coffee_order.sentinel",
      "sourceSum": "",
      "dest": "/Users/education/learn-sentinel-get-started/policies/validate_coffee_order.sentinel"
    },
    {
      "key": "validate_coffee_order",
      "source": "./policies/validate_coffee_order.sentinel",
      "sourceSum": "",
      "dest": "/Users/education/learn-sentinel-get-started/policies/validate_coffee_order.sentinel"
    }
  ]
}
Apply specific policy
Alternatively, you can also apply a specific policy. Apply the validate_coffee_order.sentinel policy.
$ sentinel apply policies/validate_coffee_order.sentinel 
Pass - validate_coffee_order.sentinel
You can override the policy parameters in the CLI. Apply the policy with an invalid parameter. The policy should fail as expected.
$ sentinel apply -param coffee_name="Terraspresso" -param coffee_size="extra-large" policies/validate_coffee_order.sentinel 
Execution trace. The information below will show the values of all
the rules evaluated. Note that some rules may be missing if
short-circuit logic was taken.
Note that for collection types and long strings, output may be
truncated; re-run "sentinel apply" with the -json flag to see the
full contents of these values.
The trace is displayed due to a failed policy.
Fail - validate_coffee_order.sentinel
Description:
  Main rule to validate a coffee order
validate_coffee_order.sentinel:33:1 - Rule "main"
  Description:
    Main rule to validate a coffee order
  Value:
    false
validate_coffee_order.sentinel:23:1 - Rule "validate_name"
  Description:
    Validate coffee name
  Value:
    true
validate_coffee_order.sentinel:28:1 - Rule "validate_size"
  Description:
    Validate coffee size
  Value:
    false
The param block in the policy block override the -param flag. Sentinel will fail since the validate_coffee_order_override policy has invalid values in the param block.
$ sentinel apply -param coffee_name="Terraspresso" -param coffee_size="medium"
Update failing policy
Update the validate_coffee_order_override policy in the Sentinel configuration file with valid parameters. The following is an example of a valid coffee name and size.
sentinel.hcl
policy "validate_coffee_order" {
  source = "./policies/validate_coffee_order.sentinel"
}
policy "validate_coffee_order_override" {
  source = "./policies/validate_coffee_order.sentinel"
  params = {
    coffee_name = "Terraspresso"
    coffee_size = "medium"
  }
}
Verify that the policies are valid by applying Sentinel.
$ sentinel apply
Pass - validate_coffee_order.sentinel
Pass - validate_coffee_order_override.sentinel
Next steps
Now that you have created your first Sentinel policy, continue to the next tutorial to learn how to simplify policy logic with Sentinel functions.
For more information on topics covered in this tutorial, refer to the following documentation: