Terraform
Policies API
Policies are rules that HCP Terraform enforces on Terraform runs. You can use policies to validate that the Terraform plan complies with security rules and best practices. HCP Terraform policy enforcement lets you use the policy-as-code frameworks Sentinel and Open Policy Agent (OPA) to apply policy checks to HCP Terraform workspaces. Refer to Policy Enforcement for more details.
Policy sets are collections of policies that you can apply globally or to specific projects and workspaces, in your organization. For each run in the selected workspaces, HCP Terraform checks the Terraform plan against the policy set and displays the results in the UI.
Note: HCP Terraform Free Edition includes one policy set of up to five policies. In HCP Terraform Plus Edition, you can connect a policy set to a version control repository or create policy set versions via the API. Refer to HCP Terraform pricing for details.
This page documents the API endpoints to create, read, update, and delete policies in an organization. To manage policy sets, use the Policy Sets API. To manage the policy results, use the Runs API.
Create a Policy
POST /organizations/:organization_name/policies
Parameter | Description |
---|---|
:organization_name | The organization to create the policy in. The organization must already exist in the system, and the token authenticating the API request must have permission to manage policies. ((More about permissions.) |
[permissions-citation]: #intentionally-unused---keep-for-maintainers)
This creates a new policy object for the organization, but does not upload the actual policy code. After creation, you must use the Upload a Policy endpoint (below) with the new policy's upload path. (This endpoint's response body includes the upload path in its links.upload
property.)
Status | Response | Reason |
---|---|---|
200 | JSON API document (type: "policies" ) | Successfully created a policy |
404 | JSON API error object | Organization not found, or user unauthorized to perform action |
422 | JSON API error object | Malformed request body (missing attributes, wrong types, etc.) |
Request Body
This POST endpoint requires a JSON object with the following properties as a request payload.
Properties without a default value are required.
Key path | Type | Default | Description |
---|---|---|---|
data.type | string | Must be "policies" . | |
data.attributes.name | string | The name of the policy, which can include letters, numbers, - , and _ . You cannot modify this name after creation. | |
data.attributes.description | string | null | Text describing the policy's purpose. This field supports Markdown and appears in the HCP Terraform UI. |
data.attributes.kind | string | sentinel | The policy-as-code framework for the policy. Valid values are "sentinel" and "opa" . |
data.attributes.query | string | The OPA query to run. Only valid for OPA policies. | |
data.attributes.enforcement-level | string | The enforcement level of the policy. For Sentinel, valid values are "hard-mandatory" , "soft-mandatory" , and "advisory" . For OPA, Valid values are "mandatory" and "advisory" . Refer to Managing Policies for details. | |
data.attributes.enforce | array[object] | DEPRECATED Use enforcement-level instead. An array of enforcement configurations that map policy file paths to their enforcement modes. Policies support a single file, so this array should consist of a single element. For Sentinel, if the path in the enforcement map does not match the Sentinel policy (<NAME>.sentinel ), then HCP Terraform uses the default hard-mandatory enforcement level. For OPA, the default enforcement level is advisory . | |
data.attributes.enforce[].path | string | DEPRECATED For Sentinel, must be <NAME>.sentinel , where <NAME> has the same value as data.attributes.name . For OPA, must be <NAME>.rego . | |
data.attributes.enforce[].mode | string | DEPRECATED Use enforcement-level instead. The enforcement level of the policy. For Sentinel, valid values are "hard-mandatory" , "soft-mandatory" , and "advisory" . For OPA, Valid values are "mandatory" and "advisory" . Refer to Managing Policies for details. | |
data.relationships.policy-sets.data[] | array[object] | [] | A list of resource identifier objects to define which policy sets include the new policy. These objects must contain id and type properties, and the type property must be policy-sets . For example,{ "id": "polset-3yVQZvHzf5j3WRJ1","type": "policy-sets" } . |
Sample Payload (Sentinel)
{
"data": {
"attributes": {
"enforcement-level": "hard-mandatory",
"name": "my-example-policy",
"description": "An example policy.",
"kind": "sentinel"
},
"relationships": {
"policy-sets": {
"data": [
{ "id": "polset-3yVQZvHzf5j3WRJ1", "type": "policy-sets" }
]
}
},
"type": "policies"
}
}
Sample Payload (OPA)
Note: We have deprecated the enforce
property in requests and responses but continue to provide it for backward compatibility. The below sample uses the deprecated enforce
property.
{
"data": {
"attributes": {
"enforce": [
{
"path": "my-example-policy.rego",
"mode": "advisory"
}
],
"name": "my-example-policy",
"description": "An example policy.",
"kind": "opa",
"query": "terraform.main"
},
"relationships": {
"policy-sets": {
"data": [
{ "id": "polset-3yVQZvHzf5j3WRJ1", "type": "policy-sets" }
]
}
},
"type": "policies"
}
}
Sample Request
curl \
--header "Authorization: Bearer $TOKEN" \
--header "Content-Type: application/vnd.api+json" \
--request POST \
--data @payload.json \
https://app.terraform.io/api/v2/organizations/my-organization/policies
Sample Response (Sentinel)
{
"data": {
"id":"pol-u3S5p2Uwk21keu1s",
"type":"policies",
"attributes": {
"name":"my-example-policy",
"description":"An example policy.",
"enforcement-level":"advisory",
"enforce": [
{
"path":"my-example-policy.sentinel",
"mode":"advisory"
}
],
"policy-set-count": 1,
"updated-at": null
},
"relationships": {
"organization": {
"data": { "id": "my-organization", "type": "organizations" }
},
"policy-sets": {
"data": [
{ "id": "polset-3yVQZvHzf5j3WRJ1", "type": "policy-sets" }
]
}
},
"links": {
"self":"/api/v2/policies/pol-u3S5p2Uwk21keu1s",
"upload":"/api/v2/policies/pol-u3S5p2Uwk21keu1s/upload"
}
}
}
Sample Response (OPA)
{
"data": {
"id":"pol-u3S5p2Uwk21keu1s",
"type":"policies",
"attributes": {
"name":"my-example-policy",
"description":"An example policy.",
"kind": "opa",
"query": "terraform.main",
"enforcement-level": "advisory",
"enforce": [
{
"path":"my-example-policy.rego",
"mode":"advisory"
}
],
"policy-set-count": 1,
"updated-at": null
},
"relationships": {
"organization": {
"data": { "id": "my-organization", "type": "organizations" }
},
"policy-sets": {
"data": [
{ "id": "polset-3yVQZvHzf5j3WRJ1", "type": "policy-sets" }
]
}
},
"links": {
"self":"/api/v2/policies/pol-u3S5p2Uwk21keu1s",
"upload":"/api/v2/policies/pol-u3S5p2Uwk21keu1s/upload"
}
}
}
Show a Policy
GET /policies/:policy_id
Parameter | Description |
---|---|
:policy_id | The ID of the policy to show. Refer to List Policies for reference information about finding IDs. |
Status | Response | Reason |
---|---|---|
200 | JSON API document (type: "policies" ) | The request was successful |
404 | JSON API error object | Policy not found or user unauthorized to perform action |
Sample Request
curl --request GET \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/vnd.api+json" \
https://app.terraform.io/api/v2/policies/pol-oXUppaX2ximkqp8w
Sample Response
{
"data": {
"id": "pol-oXUppaX2ximkqp8w",
"type": "policies",
"attributes": {
"name": "my-example-policy",
"description":"An example policy.",
"kind": "sentinel",
"enforcement-level": "soft-mandatory",
"enforce": [
{
"path": "my-example-policy.sentinel",
"mode": "soft-mandatory"
}
],
"policy-set-count": 1,
"updated-at": "2018-09-11T18:21:21.784Z"
},
"relationships": {
"organization": {
"data": { "id": "my-organization", "type": "organizations" }
},
"policy-sets": {
"data": [
{ "id": "polset-3yVQZvHzf5j3WRJ1", "type": "policy-sets" }
]
}
},
"links": {
"self": "/api/v2/policies/pol-oXUppaX2ximkqp8w",
"upload": "/api/v2/policies/pol-oXUppaX2ximkqp8w/upload",
"download": "/api/v2/policies/pol-oXUppaX2ximkqp8w/download"
}
}
}
Upload a Policy
PUT /policies/:policy_id/upload
Parameter | Description |
---|---|
:policy_id | The ID of the policy to upload code to. Refer to List Policies for reference information about finding the policy ID. The ID also appears in the response when you create a policy. |
This endpoint uploads code to an existing Sentinel or OPA policy.
Note: This endpoint does not use JSON-API's conventions for HTTP headers and body serialization.
Note: This endpoint limits the size of uploaded policies to 10MB. If a larger payload is uploaded, an HTTP 413 error will be returned, and the policy will not be saved. Consider refactoring policies into multiple smaller, more concise documents if you reach this limit.
Request Body
This PUT endpoint requires the text of a valid Sentinel or OPA policy with a Content-Type
of application/octet-stream
.
- Refer to Defining Sentinel Policies for details about writing Sentinel code.
- Refer to Defining OPA Policies for details about writing OPA code.
Sample Payload
main = rule { true }
Sample Request
curl \
--header "Authorization: Bearer $TOKEN" \
--header "Content-Type: application/octet-stream" \
--request PUT \
--data-binary @payload.file \
https://app.terraform.io/api/v2/policies/pol-u3S5p2Uwk21keu1s/upload
Update a Policy
PATCH /policies/:policy_id
Parameter | Description |
---|---|
:policy_id | The ID of the policy to update. Refer to List Policies for reference information about finding IDs. |
This endpoint can update the enforcement mode of an existing policy. To update the policy code itself, use the upload endpoint.
Status | Response | Reason |
---|---|---|
200 | JSON API document (type: "policies" ) | Successfully updated the policy |
404 | JSON API error object | Policy not found, or user unauthorized to perform action |
422 | JSON API error object | Malformed request body (missing attributes, wrong types, etc.) |
Request Body
This PATCH endpoint requires a JSON object with the following properties as a request payload.
Properties without a default value are required.
Key path | Type | Default | Description |
---|---|---|---|
data.type | string | Must be "policies" . | |
data.attributes.description | string | null | Text describing the policy's purpose. This field supports Markdown and appears in the HCP Terraform UI. |
data.attributes.query | string | The OPA query to run. This is only valid for OPA policies. | |
data.attributes.enforcement-level | string | The enforcement level of the policy. For Sentinel, valid values are "hard-mandatory" , "soft-mandatory" , and "advisory" . For OPA, Valid values are "mandatory" and "advisory" . Refer to Managing Policies for details. | |
data.attributes.enforce | array[object] | DEPRECATED Use enforcement-level instead. An array of enforcement configurations that map policy file paths to their enforcement modes. Policies support a single file, so this array should consist of a single element. For Sentinel, if the path in the enforcement map does not match the Sentinel policy (<NAME>.sentinel ), then HCP Terraform uses the default hard-mandatory enforcement level. For OPA, the default enforcement level is advisory . | |
data.attributes.enforce[].path | string | DEPRECATED For Sentinel, must be <NAME>.sentinel , where <NAME> has the same value as data.attributes.name . For OPA, must be <NAME>.rego . | |
data.attributes.enforce[].mode | string | DEPRECATED Use enforcement-level instead. The enforcement level of the policy. For Sentinel, valid values are "hard-mandatory" , "soft-mandatory" , and "advisory" . For OPA, Valid values are "mandatory" and "advisory" . Refer to Managing Policies for details. |
Sample Payload
{
"data": {
"attributes": {
"enforcement-level": "soft-mandatory"
},
"type":"policies"
}
}
Sample Request
curl \
--header "Authorization: Bearer $TOKEN" \
--header "Content-Type: application/vnd.api+json" \
--request PATCH \
--data @payload.json \
https://app.terraform.io/api/v2/policies/pol-u3S5p2Uwk21keu1s
Sample Response
{
"data": {
"id":"pol-u3S5p2Uwk21keu1s",
"type":"policies",
"attributes": {
"name":"my-example-policy",
"description":"An example policy.",
"kind": "sentinel",
"enforcement-level": "soft-mandatory",
"enforce": [
{
"path":"my-example-policy.sentinel",
"mode":"soft-mandatory"
}
],
"policy-set-count": 0,
"updated-at":"2017-10-10T20:58:04.621Z"
},
"relationships": {
"organization": {
"data": { "id": "my-organization", "type": "organizations" }
},
},
"links": {
"self":"/api/v2/policies/pol-u3S5p2Uwk21keu1s",
"upload":"/api/v2/policies/pol-u3S5p2Uwk21keu1s/upload",
"download":"/api/v2/policies/pol-u3S5p2Uwk21keu1s/download"
}
}
}
List Policies
GET /organizations/:organization_name/policies
Parameter | Description |
---|---|
:organization_name | The organization to list policies for. |
Status | Response | Reason |
---|---|---|
200 | Array of JSON API documents (type: "policies" ) | Success |
404 | JSON API error object | Organization not found, or user unauthorized to perform action |
Query Parameters
This endpoint supports pagination with standard URL query parameters; remember to percent-encode [
as %5B
and ]
as %5D
if your tooling doesn't automatically encode URLs.
Parameter | Description | |
---|---|---|
page[number] | Optional. If omitted, the endpoint will return the first page. | |
page[size] | Optional. If omitted, the endpoint will return 20 policies per page. | |
search[name] | Optional. Allows searching the organization's policies by name. | |
filter[kind] | Optional. If specified, restricts results to those with the matching policy kind value. Valid values are sentinel and opa |
Sample Request
curl \
--header "Authorization: Bearer $TOKEN" \
https://app.terraform.io/api/v2/organizations/my-organization/policies
Sample Response
{
"data": [
{
"attributes": {
"enforcement-level": "advisory",
"enforce": [
{
"mode": "advisory",
"path": "my-example-policy.sentinel"
}
],
"name": "my-example-policy",
"description": "An example policy.",
"policy-set-count": 0,
"updated-at": "2017-10-10T20:52:13.898Z",
"kind": "sentinel"
},
"id": "pol-u3S5p2Uwk21keu1s",
"relationships": {
"organization": {
"data": { "id": "my-organization", "type": "organizations" }
},
},
"links": {
"download": "/api/v2/policies/pol-u3S5p2Uwk21keu1s/download",
"self": "/api/v2/policies/pol-u3S5p2Uwk21keu1s",
"upload": "/api/v2/policies/pol-u3S5p2Uwk21keu1s/upload"
},
"type": "policies"
},
{
"id":"pol-vM2rBfj7V2Faq8By",
"type":"policies",
"attributes":{
"name":"policy1",
"description":null,
"enforcement-level": "advisory",
"enforce":[
{
"path":"policy1.rego",
"mode":"advisory"
}
],
"policy-set-count":1,
"updated-at":"2022-09-13T04:57:43.516Z",
"kind":"opa",
"query":"data.terraform.rules.policy1.rule"
},
"relationships":{
"organization":{
"data":{
"id":"hashicorp",
"type":"organizations"
}
},
"policy-sets":{
"data":[
{
"id":"polset-FYu3k5WY5eecwwdt",
"type":"policy-sets"
}
]
}
},
"links":{
"self":"/api/v2/policies/pol-vM2rBfj7V2Faq8By",
"upload":"/api/v2/policies/pol-vM2rBfj7V2Faq8By/upload",
"download":"/api/v2/policies/pol-vM2rBfj7V2Faq8By/download"
}
}
]
}
Delete a Policy
DELETE /policies/:policy_id
Parameter | Description |
---|---|
:policy_id | The ID of the policy to delete. Refer to List Policies for reference information about finding IDs. |
Status | Response | Reason |
---|---|---|
204 | No Content | Successfully deleted the policy |
404 | JSON API error object | Policy not found, or user unauthorized to perform action |
Sample Request
curl \
--header "Authorization: Bearer $TOKEN" \
--header "Content-Type: application/vnd.api+json" \
--request DELETE \
https://app.terraform.io/api/v2/policies/pl-u3S5p2Uwk21keu1s
Available Related Resources
The GET endpoints above can optionally return related resources, if requested with the include
query parameter. The following resource types are available:
Resource Name | Description |
---|---|
policy_sets | Policy sets that any returned policies are members of. |