Skip to main content

Policies

Torque role: Account admin

Why use policies?

Using policies for the consumption of environments offers a multitude of benefits that empower organizations to optimize their cloud usage. Firstly, policies allow for effective cost control by setting limits on resource consumption, ensuring that cloud spending remains within budgetary constraints. Moreover, these policies enable the efficient management of resources by capping the number of concurrent resources per user, preventing resource sprawl, and ensuring fair allocation. Additionally, policies can restrict the duration of an environments uptime, enhancing security and minimizing the risk of unused resources running indefinitely. In sum, the implementation of policies for environment consumption not only fosters financial prudence but also enhances resource governance and security, making it an invaluable asset in the realm of cloud management.

Torque policies are triggered as part of the environment deployment pipeline for specific environment lifecycle events (launch, extend environment for example) or during the deployment of environments (e.g. when evaluating a Terraform module included in the environment). Torque policies are powered by OPA (Open Policy Agent). For a step-by-step tutorial, see Video: Torque policies (end-to-end).

Example Use Cases

You can use Torque policies for cost and consumption control. Examples include:

  • Limiting the maximal duration of environments
  • Limiting the concurrent number of environments per user
  • Limiting the total cost of environments
  • And more.

In this article:

How policies work

Policies are based on two basic elements: trigger and context. Trigger determines when the policy is activated, and context is the data the policy needs to get ("input" in OPA terms). The context is provided automatically by Torque. Users can also define user data ("data" in OPA terms) in the Torque policy. The context (or input) is the actual environment data the end user is trying to deploy, and the user data sets values to the limitations imposed by the admin who set up the policy.

Torque supports 3 types of triggers, which are defined by the package being used in the policy's .rego file:

  • Consumption policies (triggered on catalog launch). To define a consumption policy, the ".rego" file must use the package name torque.consumption
  • Environment lifecycle policies (triggered on launch after completing the launch dialog, or extend). To define an environment lifecycle policy, the ".rego" file must use the package name torque.environment
  • Terraform evaluation policies (triggered on terraform plan for terraform grains). To define a terraform plan evaluation policy, the ".rego" file must use the package name torque.terraform_plan
Note

Policies are applied on the space or account level, as explained in How to set up a policy.

Policy labels

There are 5 labels that will be automatically applied to policies in Torque, in the Policies administration page:

  • Built-in label is assigned to policies that come out of the box with Torque. For details about the policies, see https://github.com/QualiTorque/opa
  • Terraform label is assigned to policies that evaluate the Terraform plan on the environment's Terraform grain. These policies are triggered when Torque deploys the Terraform grain's plan during the environment's initialization
  • Environment label is assigned to policies that are triggered when the environment is launched (upon completing the launch wizard) or extended
  • Consumption label is assigned to policies that are triggered when the catalog item is clicked
  • Approval label is assigned to policies that could require approval to launch the environment
  • Annotations label is assigned to files that are used to evaluate dynamic environment annotations. See Environment Annotations.

Locale Dropdown

Torque built-in policies

Torque provides many built-in policies, both for environment lifecycle and Terraform plan evaluation, which represent some of the more common use cases when deploying environments. Some examples include:

  • Allow only specific AWS instance types to be used
  • Allow deploying only to specific Azure locations
  • Allow only environments with an expected cost of < 10$

Custom policies

There may come a time when you will need to go beyond the common use case and write your own policies and rules. This is possible using custom policies. Custom policies are .rego files that reside in your git repository. When you add the policy repository to Torque, Torque automatically discovers the repository and identifies its .rego files as policies, allowing you to choose which policies to import into Torque. Same as with built-in policies, you select where to apply the policy (on the entire account or specific teams) and configure the relevant data.

Developing your own policies

Developing Torque policies

  1. Package: For Torque to recognize and be able to execute your policy, you need to use the torque packages. The packages that are currently available are torque.consumption, torque.environment and torque.terraform_plan. So your first line of the rego file which is the package name should be one of these packages.
  2. terraform_plan policies need at least one deny rule to be valid. For example, a terraform_plan policy can look like this:

package torque.terraform_plan

deny[reason] {
all := resources["aws_iam"]
count(all) > 0
reason:= "Deployment contains IAM changes"
}

  1. environment and consumption policies need to return at least one result object with a decision element in it. The decision value can be one of "Denied", "Manual" or "Approved". In addition to the decision element, you can optionally add a reason element that explains the reason for the decision. For example, an environment policy can look like this:

package torque.environment

result = { "decision": "Denied", "reason": "Environment duration exceeds 5 hours" } if {
input.duration_minutes > 300

}

Inputs

Based on the policy type (environment , consumption or terraform_plan) Torque will provide input to OPA once the policy is injected. For terraform_plan policies, the input is the terraform plan output. For environment policies, the input is the following json object:

{
"blueprint": {
"name": "my-bp-name",
"repository": "my-repo",
"labels": [],
"url": "https://github.com/...",
"last_modified": "0001-01-01T00:00:00",
"grains": [
{
"kind": "terraform",
"name": "helloTF"
}
]
},
"inputs": [
{
"name": "input_name",
"type": "string",
"value": "input_value",
"sensitive": false, // true|false
"description": null
}
],
"workflows": [
{
"name": "<workflow_name>",
"schedules": [
"* * * * *",
"0 * * * *" //null in schedules means the schedule was disabled
],
"inputs": {
"<input_name_1>": "<input_value_1>",
"<input_name_2>": "<input_value_2>"
}
}
],
"timezone": "Asia/Jerusalem",
"duration_minutes": 100, // in launch, the requested duration. In extend, the total duration before the extension
"extend_duration_minutes": 100, // null if the action is "launch"
"blueprint_avg_hourly_cost": null,
"space_name": "my_space",
"user_email": "me.l@mycorp.com",
"entity_name": "my-env", //environment name
"action_identifier": {
"entity_type": "Environment",
"entity_id": null,
"action_type": "Launch" // options: "Launch", "Extend"
}
"owner_active_environments_in_space": 1// # of the current owner's active environments in space
"owner_active_environments_in_account": 1 // # of the current owner's active environments in the account
"active_environments_in_space": 1 // total # of active environments in the space
"active_environments_in_account": 2 // total # of active environments in the account
}

Usage example:

A policy that denies environments with a requested duration over 3 hours:
result = { "decision": "Denied", "reason": "Requested environment duration exceeds 180 minutes" } if {
input.duration_minutes > 180
}

For consumption policies, the input is similar to the object in environment policies, except the consumption policies are triggered before the user completes the launch dialog, which means the blueprint input values and workflow details are not available yet. Therefore, the relevant sections are omitted from the input json object:

{
"blueprint": {
"name": "my-bp-name",
"repository": "my-repo",
"labels": [],
"url": "https://github.com/...",
"last_modified": "0001-01-01T00:00:00",
"grains": [
{
"kind": "terraform",
"name": "helloTF"
}
]
},

"timezone": "Asia/Jerusalem",
"duration_minutes": 100, // in launch, the requested duration. In extend, the total duration before the extension
"extend_duration_minutes": 100, // null if the action is "launch"
"blueprint_avg_hourly_cost": null,
"space_name": "my_space",
"user_email": "me.l@mycorp.com",
"entity_name": "my-env", //environment name
"action_identifier": {
"entity_type": "Environment",
"entity_id": null,
"action_type": "Launch" // options: "Launch", "Extend"
}
"owner_active_environments_in_space": 1// # of the current owner's active environments in space
"owner_active_environments_in_account": 1 // # of the current owner's active environments in the account
"active_environments_in_space": 1 // total # of active environments in the space
"active_environments_in_account": 2 // total # of active environments in the account
}

data

The data object is the user-defined inputs that will also be passed to OPA for evaluation. The data object structure is defined by the policy writer, and the values are provided through the Torque UI.

For example, the policy can look like this:

A policy that denies environments with a requested duration that is longer than defined in the *data* object:
result = { "decision": "Denied", "reason": "Environment duration exceeds the configured max duration" } if {
input.duration_minutes > data.max_duration_minutes
}

In this case, the policy expects a data object with one key: max_duration_minutes.

In Torque, it would look like this:

Locale Dropdown

So you can enter whichever value you want as the maximum duration to be enforced on environments.

Rego restricted functions

Torque supports all rego built-in functions, except the following list:

  • "http.send";
  • "opa.runtime";
  • "rego.parse_module";
  • "time.now_ns";
  • "trace";

For more details on how to develop policies, see OPA documentation and OPA playground.

Notes
  • For example, custom policies, see Quali Torque built-in OPA policy templates.
  • Note that Torque points to a specific commit. Therefore, to introduce a new version of a custom policy, develop, test and pass the policy through your regular git flow. Once you are done, update the commit version in Torque by clicking "Update Rego".

Approval policies

Torque allows you to configure your policy with conditions that will trigger manual approval of an environment request by a set of designated approvers via multiple optional channels: email, Microsoft Teams or Slack channels, ServiceNow and more.

For example, you could have an approval policy that sets the max_duration for environments at 3 hours, so attempting to launch an environment with a duration that is longer than 3 hours will require approval.

Notes

Approvers are defined in the Approval Channels administration page.

How to set up a policy

  1. Go to Administration > Policy Repositories and click Add a Repository.

  2. Select the git repository, specify the repository's URL, and give it a name.

    Locale Dropdown

  3. Click Connect. Provide authorization credentials if the repository is private.

    A green checkmark next to the repository's URL indicates that the repository has been added successfully.

    Locale Dropdown

  4. Click Discover Policies.

  5. Select the policies you want to import into Torque and click Generate Policies.

    Locale Dropdown

    The policies are displayed in the Policies page.

    Locale Dropdown

  6. Click a generated policy and edit the details.

    a. Optionally change the Name, and provide a Description.

    b. In Spaces, set the scope of the policy - All spaces or specific ones.

    c. In Data, set the policy's limitations.

  7. Click Save.

  8. Enable the policy.

    Locale Dropdown

Duplicate a policy

You can also duplicate any built-in or custom policy to create a similar version with different user data. For example, You could have a policy that allows the use of cloud region "us-east-1" for the US team, and another one for the EU team that allows region "eu-west-1".

Locale Dropdown

Updating policies

Torque's custom policies are version controlled in git. Next to each policy, you can see the specific commit which is currently being used for that policy across the account:

Locale Dropdown

From time to time, there will be a need to modify the policy's code (rego file). However, we must update the policy without any disruption to the users. This means that the data object format and the rego file must match.

Clicking on the policy there is an option to update the rego:

Locale Dropdown

If there is no change in the data object format, the update is completed and applied across the account. However, if there is a change in the data object, we cannot complete the update until the user will complete the change of the data object, otherwise the policy will start failing and will cause a disruption for the account users. Therefore, when Torque detects a change in the format of the data object, it will load the new data object structure and wait for the user to modify it. Once done, the user needs to invoke the "update-rego" again and at this point it will complete successfully as the rego code and the data format match.

Video: Torque policies (end-to-end tutorial)