terraform page title tfplan v2 Imports Sentinel HCP Terraform example import tfplan v2 as tfplan import designed specifically for Terraform 0 12 This import requires Note This is documentation for the next version of the tfplan Sentinel Terraform 0 12 or higher and must currently be loaded by path using an alias The tfplan v2 import provides access to a Terraform plan

Answer:
---
page_title: tfplan/v2 - Imports - Sentinel - HCP Terraform
description: The tfplan/v2 import provides access to a Terraform plan.
---

-> **Note:** This is documentation for the next version of the `tfplan` Sentinel
import, designed specifically for Terraform 0.12. This import requires
Terraform 0.12 or higher, and must currently be loaded by path, using an alias,
example: `import "tfplan/v2" as tfplan`.

# Import: tfplan/v2

The `tfplan/v2` import provides access to a Terraform plan.

A Terraform plan is the file created as a result of `terraform plan` and is the
input to `terraform apply`. The plan represents the changes that Terraform needs
to make to infrastructure to reach the desired state represented by the
configuration.

<!-- BEGIN: TFC:only name:pnp-callout -->
@include 'tfc-package-callouts/policies.mdx'
<!-- END: TFC:only name:pnp-callout -->

In addition to the diff data available in the plan, there is a "planned state"
that is available through this import, via the
[`planned_values`](#the-planned_values-collection) collection. This collection
presents the Terraform state as how it might look after the plan data is
applied, but is not guaranteed to be the final state.

The data in the `tfplan/v2` import is sourced from the JSON configuration file
that is generated by the [`terraform show -json`](/terraform/cli/commands/show#json-output) command. For more information on
the file format, see the [JSON Output Format](/terraform/internals/json-format)
page.

The entirety of the JSON output file is exposed as a Sentinel map via the
[`raw`](#the-raw-collection) collection. This allows direct, low-level access to
the JSON data, but should only be used in complex situations where the
higher-level collections do not serve the purpose.

## Import Overview

The `tfplan/v2` import is structured as a series of _collections_, keyed as a
specific format depending on the collection.

```
tfplan/v2
├── terraform_version (string)
├── variables
│   └── (indexed by name)
│       ├── name (string)
│       └── value (value)
├── planned_values
│   ├── outputs (tfstate/v2 outputs representation)
│   └── resources (tfstate/v2 resources representation)
├── resource_changes
│   └── (indexed by address[:deposed])
│       ├── address (string)
│       ├── module_address (string)
│       ├── mode (string)
│       ├── type (string)
│       ├── name (string)
│       ├── index (float (number) or string)
│       ├── provider_name (string)
│       ├── deposed (string)
│       └── change (change representation)
├── resource_drift
│   └── (indexed by address[:deposed])
│       ├── address (string)
│       ├── module_address (string)
│       ├── mode (string)
│       ├── type (string)
│       ├── name (string)
│       ├── index (float (number) or string)
│       ├── provider_name (string)
│       ├── deposed (string)
│       └── change (change representation)
├── output_changes
│   └── (indexed by name)
│       ├── name (string)
│       └── change (change representation)
└── raw (map)
```

The collections are:

* [`variables`](#the-variables-collection) - The values of variables that have
  been set in the plan itself. This collection only contains variables set in
  the root module.
* [`planned_values`](#the-planned_values-collection) - The state representation
  of _planned values_, or an estimation of what the state will look like after
  the plan is applied.
* [`resource_changes`](#the-resource_changes-and-resource_drift-collections) - The set of change
  operations for resources and data sources within this plan.
* [`resource_drift`](#the-resource_changes-and-resource_drift-collections) - A description of the
  changes Terraform detected when it compared the most recent state to the prior saved state.
* [`output_changes`](#the-output_changes-collection) - The changes to outputs
  within this plan. This collection only contains outputs set in the root
  module.
* [`raw`](#the-raw-collection) - Access to the raw plan data as stored by
  HCP Terraform.

These collections are specifically designed to be used with the
[`filter`](https://docs.hashicorp.com/sentinel/language/collection-operations#filter-expression)
quantifier expression in Sentinel, so that one can collect a list of resources
to perform policy checks on without having to write complex discovery code. As
an example, the following code will return all `aws_instance` resource changes,
across all modules in the plan:

```
all_aws_instances = filter tfplan.resource_changes as _, rc {
	rc.mode is "managed" and
		rc.type is "aws_instance"
}
```

You can add specific attributes to the filter to narrow the search, such as the
module address, or the operation being performed. The following code would
return resources in a module named `foo` only, and further narrow the search
down to only resources that were being created:

```
all_aws_instances = filter tfplan.resource_changes as _, rc {
	rc.module_address is "module.foo" and
		rc.mode is "managed" and
		rc.type is "aws_instance" and
		rc.change.actions is ["create"]
}
```

### Change Representation

Certain collections in this import contain a _change representation_, an object
with details about changes to a particular entity, such as a resource (within
the [`resource_changes`](#the-resource_changes-collection) collection), or
output (within the [`output_changes`](#the-output_changes-collection)
collection).

```
(change representation)
├── actions (list)
├── before (value, or map)
├── after (value, or map)
└── after_unknown (boolean, or map of booleans)
```

This change representation contains the following fields:

* `actions` - A list of actions being carried out for this change. The order is
  important, for example a regular replace operation is denoted by `["delete",
  "create"]`, but a
  [`create_before_destroy`](/terraform/language/meta-arguments/lifecycle#create_before_destroy)
  resource will have an operation order of `["create", "delete"]`.
* `before` - The representation of the resource data object value before the
  action. For create-only actions, this is unset. For no-op actions, this value
  will be identical with `after`.
* `after` - The representation of the resource data object value after the
  action. For delete-only actions, this is unset. For no-op actions, this value
  will be identical with `before`. Note that unknown values will not show up in
  this field.
* `after_unknown` - A deep object of booleans that denotes any values that are
  unknown in a resource. These values were previously referred to as "computed"
  values. If the value cannot be found in this map, then its value should be
  available within `after`, so long as the operation supports it.

#### Actions

As mentioned above, actions show up within the `actions` field of a change
representation and indicate the type of actions being performed as part of the
change, and the order that they are being performed in.

The current list of actions are as follows:

* `create` - The action will create the associated entity. Depending on the
  order this appears in, the entity may be created alongside a copy of the
  entity before replacing it.
* `read`  - The action will read the associated entity. In practice, seeing this
  change type should be rare, as reads generally happen before a plan is
  executed (usually during a refresh).
* `update` - The action will update the associated entity in a way that alters its state
  in some way.
* `delete` - The action will remove the associated entity, deleting any
  applicable state and associated real resources or infrastructure.
* `no-op` - No action will be performed on the associated entity.

The `actions` field is a list, as some real-world actions are actually a
composite of more than one primitive action. At this point in time, this
is generally only applicable to resource replacement, in which the following
action orders apply:

* **Normal replacement:** `["delete", "create"]` - Applies to default lifecycle
  configurations.
* **Create-before-destroy:** `["create", "delete"]` - Applies when
  [`create_before_destroy`](/terraform/language/meta-arguments/lifecycle#create_before_destroy)
  is used in a lifecycle configuration.

Note that, in most situations, the plan will list all "changes", including no-op
changes. This makes filtering on change type crucial to the accurate selection
of data if you are concerned with the state change of a particular resource.

To filter on a change type, use exact list comparison. For example, the
following example from the [Import Overview](#import-overview) filters on
exactly the resources being created _only_:

```
all_aws_instances = filter tfplan.resource_changes as _, rc {
	rc.module_address is "module.foo" and
		rc.mode is "managed" and
		rc.type is "aws_instance" and
    rc.change.actions is ["create"]
}
```

#### `before`, `after`, and `after_unknown`

The exact attribute changes for a particular operation are outlined in the
`before` and `after` attributes. Depending on the entity being operated on, this
will either be a map (as with
[`resource_changes`](#the-resource_changes-collection)) or a singular value (as
with [`output_changes`](#the-output_changes-collection)).

What you can expect in these fields varies depending on the operation:

* For fresh create operations, `before` will generally be `null`, and `after`
  will contain the data you can expect to see after the change.
* For full delete operations, this will be reversed - `before` will contain
  data, and `after` will be `null`.
* Update or replace operations will have data in both fields relevant to their
  states before and after the operation.
* No-op operations should have identical data in `before` and `after`.

For resources, if a field cannot be found in `after`, it generally means one of
two things:

* The attribute does not exist in the resource schema. Generally, known
  attributes that do not have a value will show up as `null` or otherwise empty
  in `after`.
* The attribute is _unknown_, that is, it was unable to be determined at plan
  time and will only be available after apply-time values have been able to be
  calculated.

In the latter case, there should be a value for the particular attribute in
`after_unknown`, which can be checked to assert that the value is indeed
unknown, versus invalid:

```
import "tfplan/v2" as tfplan

no_unknown_amis = rule {
	all filter tfplan.resource_changes as _, rc {
		rc.module_address is "module.foo" and
			rc.mode is "managed" and
			rc.type is "aws_instance" and
			rc.change.actions is ["create"]
	} as _, rc {
		rc.change.after_unknown.ami else false is false
	}
}
```

For output changes, `after_unknown` will simply be `true` if the value won't be
known until the plan is applied.

## The `terraform_version` Value

The top-level `terraform_version` value in this import gives the Terraform
version that made the plan. This can be used to do version validation.

```
import "tfplan/v2" as tfplan
import "strings"

v = strings.split(tfplan.terraform_version, ".")
version_major = int(v[1])
version_minor = int(v[2])

main = rule {
	version_major is 12 and version_minor >= 19
}
```

-> **NOTE:** The above example will give errors when working with pre-release
versions (example: `0.12.0beta1`). Future versions of this import will include
helpers to assist with processing versions that will account for these kinds of
exceptions.

## The `variables` Collection

The `variables` collection is a collection of the variables set in the root
module when creating the plan.

This collection is indexed on the name of the variable.

The valid values are:

* `name` - The name of the variable, also used as the collection key.
* `value` - The value of the variable assigned during the plan.

## The `planned_values` Collection

The `planned_values` collection is a special collection in that it contains two
fields that alias to state collections with the _planned_ state set. This is the
best prediction of what the state will look like after the plan is executed.

The two fields are:

* `outputs` - The prediction of what output values will look like after the
  state is applied. For more details on the structure of this collection, see
  the [`outputs`](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfstate-v2#the-outputs-collection) collection in the
  [`tfstate/v2`](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfstate-v2) documentation.
* `resources` - The prediction of what resource values will look like after the
  state is applied. For more details on the structure of this collection, see
  the [`resources`](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfstate-v2#the-resources-collection) collection in the
  [`tfstate/v2`](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfstate-v2) documentation.

-> **NOTE:** Unknown values are omitted from the `planned_values` state
representations, regardless of whether or not they existed before. Use
[`resource_changes`](#the-resource_changes-collection) if awareness of unknown
data is important.

## The `resource_changes` and `resource_drift` Collections

The `resource_changes` and `resource_drift` collections are a set of change operations for resources
and data sources within this plan.

The `resource_drift` collection provides a description of the changes Terraform detected
when it compared the most recent state to the prior saved state.

The `resource_changes` collection includes all resources that have been found in the configuration and state,
regardless of whether or not they are changing.

~> When [resource targeting](/terraform/cli/commands/plan#resource-targeting) is in effect, the `resource_changes` collection will only include the resources specified as targets for the run. This may lead to unexpected outcomes if a policy expects a resource to be present in the plan. To prohibit targeted runs altogether, ensure [`tfrun.target_addrs`](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfrun#value-target_addrs) is undefined or empty.

This collection is indexed on the complete resource address as the key. If
`deposed` is non-empty, it is appended to the end, and may look something like
`aws_instance.foo:deposed-abc123`.

An element contains the following fields:

* `address` - The absolute resource address - also the key for the collection's
  index, if `deposed` is empty.

* `module_address` - The module portion of the absolute resource address.

* `mode` - The resource mode, either `managed` (resources) or `data` (data
  sources).

* `type` - The resource type, example: `aws_instance` for `aws_instance.foo`.

* `name` - The resource name, example: `foo` for `aws_instance.foo`.

* `index` - The resource index. Can be either a number or a string.

* `provider_name` - The name of the provider this resource belongs to. This
  allows the provider to be interpreted unambiguously in the unusual situation
  where a provider offers a resource type whose name does not start with its own
  name, such as the `googlebeta` provider offering `google_compute_instance`.

  -> **Note:** Starting with Terraform 0.13, the `provider_name` field contains the
  _full_ source address to the provider in the Terraform Registry. Example:
  `registry.terraform.io/hashicorp/null` for the null provider.

* `deposed` - An identifier used during replacement operations, and can be used
  to identify the exact resource being replaced in state.

* `change` - The data describing the change that will be made to this resource.
  For more details, see [Change Representation](#change-representation).

## The `output_changes` Collection

The `output_changes` collection is a collection of the change operations for
outputs within this plan.

Only outputs for the root module are included.

This collection is indexed by the name of the output. The fields in a collection
value are below:

* `name` -  The name of the output, also the index key.
* `change` - The data describing the change that will be made to this output.
  For more details, see [Change Representation](#change-representation).

## The `raw` Collection

The `raw` collection exposes the raw, unprocessed plan data, direct from the
data stored by HCP Terraform.

This is the same data that is produced by [`terraform show -json`](/terraform/cli/commands/show#json-output) on the plan file for the run this
policy check is attached to.

Use of this data is only recommended in expert situations where the data the
collections present may not exactly serve the needs of the policy. For more
information on the file format, see the [JSON Output
Format](/terraform/internals/json-format) page.

-> **NOTE:** Although designed to be relatively stable, the actual makeup for
the JSON output format is a Terraform CLI concern and as such not managed by
HCP Terraform. Use at your own risk, follow the [Terraform CLI
project](https://github.com/hashicorp/terraform), and watch the file format
documentation for any changes.

page title  tfplan v2   Imports   Sentinel   HCP Terraform description  The tfplan v2 import provides access to a Terraform plan            Note    This is documentation for the next version of the  tfplan  Sentinel import  designed specifically for Terraform 0 12  This import requires Terraform 0 12 or higher  and must currently be loaded by path  using an alias  example   import  tfplan v2  as tfplan      Import  tfplan v2  The  tfplan v2  import provides access to a Terraform plan   A Terraform plan is the file created as a result of  terraform plan  and is the input to  terraform apply   The plan represents the changes that Terraform needs to make to infrastructure to reach the desired state represented by the configuration        BEGIN  TFC only name pnp callout      include  tfc package callouts policies mdx       END  TFC only name pnp callout      In addition to the diff data available in the plan  there is a  planned state  that is available through this import  via the   planned values    the planned values collection  collection  This collection presents the Terraform state as how it might look after the plan data is applied  but is not guaranteed to be the final state   The data in the  tfplan v2  import is sourced from the JSON configuration file that is generated by the   terraform show  json    terraform cli commands show json output  command  For more information on the file format  see the  JSON Output Format   terraform internals json format  page   The entirety of the JSON output file is exposed as a Sentinel map via the   raw    the raw collection  collection  This allows direct  low level access to the JSON data  but should only be used in complex situations where the higher level collections do not serve the purpose      Import Overview  The  tfplan v2  import is structured as a series of  collections   keyed as a specific format depending on the collection       tfplan v2     terraform version  string      variables          indexed by name              name  string              value  value      planned values         outputs  tfstate v2 outputs representation          resources  tfstate v2 resources representation      resource changes          indexed by address  deposed               address  string              module address  string              mode  string              type  string              name  string              index  float  number  or string              provider name  string              deposed  string              change  change representation      resource drift          indexed by address  deposed               address  string              module address  string              mode  string              type  string              name  string              index  float  number  or string              provider name  string              deposed  string              change  change representation      output changes          indexed by name              name  string              change  change representation      raw  map       The collections are       variables    the variables collection    The values of variables that have   been set in the plan itself  This collection only contains variables set in   the root module      planned values    the planned values collection    The state representation   of  planned values   or an estimation of what the state will look like after   the plan is applied      resource changes    the resource changes and resource drift collections    The set of change   operations for resources and data sources within this plan      resource drift    the resource changes and resource drift collections    A description of the   changes Terraform detected when it compared the most recent state to the prior saved state      output changes    the output changes collection    The changes to outputs   within this plan  This collection only contains outputs set in the root   module      raw    the raw collection    Access to the raw plan data as stored by   HCP Terraform   These collections are specifically designed to be used with the   filter   https   docs hashicorp com sentinel language collection operations filter expression  quantifier expression in Sentinel  so that one can collect a list of resources to perform policy checks on without having to write complex discovery code  As an example  the following code will return all  aws instance  resource changes  across all modules in the plan       all aws instances   filter tfplan resource changes as    rc    rc mode is  managed  and   rc type is  aws instance         You can add specific attributes to the filter to narrow the search  such as the module address  or the operation being performed  The following code would return resources in a module named  foo  only  and further narrow the search down to only resources that were being created       all aws instances   filter tfplan resource changes as    rc    rc module address is  module foo  and   rc mode is  managed  and   rc type is  aws instance  and   rc change actions is   create              Change Representation  Certain collections in this import contain a  change representation   an object with details about changes to a particular entity  such as a resource  within the   resource changes    the resource changes collection  collection   or output  within the   output changes    the output changes collection  collection         change representation      actions  list      before  value  or map      after  value  or map      after unknown  boolean  or map of booleans       This change representation contains the following fields      actions    A list of actions being carried out for this change  The order is   important  for example a regular replace operation is denoted by    delete      create     but a     create before destroy    terraform language meta arguments lifecycle create before destroy    resource will have an operation order of    create    delete        before    The representation of the resource data object value before the   action  For create only actions  this is unset  For no op actions  this value   will be identical with  after      after    The representation of the resource data object value after the   action  For delete only actions  this is unset  For no op actions  this value   will be identical with  before   Note that unknown values will not show up in   this field     after unknown    A deep object of booleans that denotes any values that are   unknown in a resource  These values were previously referred to as  computed    values  If the value cannot be found in this map  then its value should be   available within  after   so long as the operation supports it        Actions  As mentioned above  actions show up within the  actions  field of a change representation and indicate the type of actions being performed as part of the change  and the order that they are being performed in   The current list of actions are as follows      create    The action will create the associated entity  Depending on the   order this appears in  the entity may be created alongside a copy of the   entity before replacing it     read     The action will read the associated entity  In practice  seeing this   change type should be rare  as reads generally happen before a plan is   executed  usually during a refresh      update    The action will update the associated entity in a way that alters its state   in some way     delete    The action will remove the associated entity  deleting any   applicable state and associated real resources or infrastructure     no op    No action will be performed on the associated entity   The  actions  field is a list  as some real world actions are actually a composite of more than one primitive action  At this point in time  this is generally only applicable to resource replacement  in which the following action orders apply       Normal replacement       delete    create      Applies to default lifecycle   configurations      Create before destroy       create    delete      Applies when     create before destroy    terraform language meta arguments lifecycle create before destroy    is used in a lifecycle configuration   Note that  in most situations  the plan will list all  changes   including no op changes  This makes filtering on change type crucial to the accurate selection of data if you are concerned with the state change of a particular resource   To filter on a change type  use exact list comparison  For example  the following example from the  Import Overview   import overview  filters on exactly the resources being created  only        all aws instances   filter tfplan resource changes as    rc    rc module address is  module foo  and   rc mode is  managed  and   rc type is  aws instance  and     rc change actions is   create                before    after   and  after unknown   The exact attribute changes for a particular operation are outlined in the  before  and  after  attributes  Depending on the entity being operated on  this will either be a map  as with   resource changes    the resource changes collection   or a singular value  as with   output changes    the output changes collection     What you can expect in these fields varies depending on the operation     For fresh create operations   before  will generally be  null   and  after    will contain the data you can expect to see after the change    For full delete operations  this will be reversed    before  will contain   data  and  after  will be  null     Update or replace operations will have data in both fields relevant to their   states before and after the operation    No op operations should have identical data in  before  and  after    For resources  if a field cannot be found in  after   it generally means one of two things     The attribute does not exist in the resource schema  Generally  known   attributes that do not have a value will show up as  null  or otherwise empty   in  after     The attribute is  unknown   that is  it was unable to be determined at plan   time and will only be available after apply time values have been able to be   calculated   In the latter case  there should be a value for the particular attribute in  after unknown   which can be checked to assert that the value is indeed unknown  versus invalid       import  tfplan v2  as tfplan  no unknown amis   rule    all filter tfplan resource changes as    rc     rc module address is  module foo  and    rc mode is  managed  and    rc type is  aws instance  and    rc change actions is   create      as    rc     rc change after unknown ami else false is false           For output changes   after unknown  will simply be  true  if the value won t be known until the plan is applied      The  terraform version  Value  The top level  terraform version  value in this import gives the Terraform version that made the plan  This can be used to do version validation       import  tfplan v2  as tfplan import  strings   v   strings split tfplan terraform version       version major   int v 1   version minor   int v 2    main   rule    version major is 12 and version minor    19             NOTE    The above example will give errors when working with pre release versions  example   0 12 0beta1    Future versions of this import will include helpers to assist with processing versions that will account for these kinds of exceptions      The  variables  Collection  The  variables  collection is a collection of the variables set in the root module when creating the plan   This collection is indexed on the name of the variable   The valid values are      name    The name of the variable  also used as the collection key     value    The value of the variable assigned during the plan      The  planned values  Collection  The  planned values  collection is a special collection in that it contains two fields that alias to state collections with the  planned  state set  This is the best prediction of what the state will look like after the plan is executed   The two fields are      outputs    The prediction of what output values will look like after the   state is applied  For more details on the structure of this collection  see   the   outputs    terraform cloud docs policy enforcement sentinel import tfstate v2 the outputs collection  collection in the     tfstate v2    terraform cloud docs policy enforcement sentinel import tfstate v2  documentation     resources    The prediction of what resource values will look like after the   state is applied  For more details on the structure of this collection  see   the   resources    terraform cloud docs policy enforcement sentinel import tfstate v2 the resources collection  collection in the     tfstate v2    terraform cloud docs policy enforcement sentinel import tfstate v2  documentation        NOTE    Unknown values are omitted from the  planned values  state representations  regardless of whether or not they existed before  Use   resource changes    the resource changes collection  if awareness of unknown data is important      The  resource changes  and  resource drift  Collections  The  resource changes  and  resource drift  collections are a set of change operations for resources and data sources within this plan   The  resource drift  collection provides a description of the changes Terraform detected when it compared the most recent state to the prior saved state   The  resource changes  collection includes all resources that have been found in the configuration and state  regardless of whether or not they are changing      When  resource targeting   terraform cli commands plan resource targeting  is in effect  the  resource changes  collection will only include the resources specified as targets for the run  This may lead to unexpected outcomes if a policy expects a resource to be present in the plan  To prohibit targeted runs altogether  ensure   tfrun target addrs    terraform cloud docs policy enforcement sentinel import tfrun value target addrs  is undefined or empty   This collection is indexed on the complete resource address as the key  If  deposed  is non empty  it is appended to the end  and may look something like  aws instance foo deposed abc123    An element contains the following fields      address    The absolute resource address   also the key for the collection s   index  if  deposed  is empty      module address    The module portion of the absolute resource address      mode    The resource mode  either  managed   resources  or  data   data   sources       type    The resource type  example   aws instance  for  aws instance foo       name    The resource name  example   foo  for  aws instance foo       index    The resource index  Can be either a number or a string      provider name    The name of the provider this resource belongs to  This   allows the provider to be interpreted unambiguously in the unusual situation   where a provider offers a resource type whose name does not start with its own   name  such as the  googlebeta  provider offering  google compute instance           Note    Starting with Terraform 0 13  the  provider name  field contains the    full  source address to the provider in the Terraform Registry  Example     registry terraform io hashicorp null  for the null provider      deposed    An identifier used during replacement operations  and can be used   to identify the exact resource being replaced in state      change    The data describing the change that will be made to this resource    For more details  see  Change Representation   change representation       The  output changes  Collection  The  output changes  collection is a collection of the change operations for outputs within this plan   Only outputs for the root module are included   This collection is indexed by the name of the output  The fields in a collection value are below      name     The name of the output  also the index key     change    The data describing the change that will be made to this output    For more details  see  Change Representation   change representation       The  raw  Collection  The  raw  collection exposes the raw  unprocessed plan data  direct from the data stored by HCP Terraform   This is the same data that is produced by   terraform show  json    terraform cli commands show json output  on the plan file for the run this policy check is attached to   Use of this data is only recommended in expert situations where the data the collections present may not exactly serve the needs of the policy  For more information on the file format  see the  JSON Output Format   terraform internals json format  page        NOTE    Although designed to be relatively stable  the actual makeup for the JSON output format is a Terraform CLI concern and as such not managed by HCP Terraform  Use at your own risk  follow the  Terraform CLI project  https   github com hashicorp terraform   and watch the file format documentation for any changes


terraform The tfstate import provides access to a Terraform state Warning The tfstate import is now deprecated and will be permanently removed in August 2025 page title tfstate Imports Sentinel HCP Terraform Import tfstate We recommend that you start using the updated tfstate v2 terraform cloud docs policy enforcement sentinel import tfstate v2 import as soon as possible to avoid disruptions The tfstate v2 import offers improved functionality and is designed to better support your policy enforcement needs

Answer:
---
page_title: tfstate - Imports - Sentinel - HCP Terraform
description: The tfstate import provides access to a Terraform state.
---

# Import: tfstate

~> **Warning:** The `tfstate` import is now deprecated and will be permanently removed in August 2025.
We recommend that you start using the updated [tfstate/v2](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfstate-v2) import as soon as possible to avoid disruptions.
The `tfstate/v2` import offers improved functionality and is designed to better support your policy enforcement needs.

The `tfstate` import provides access to the Terraform state.

<!-- BEGIN: TFC:only name:pnp-callout -->
@include 'tfc-package-callouts/policies.mdx'
<!-- END: TFC:only name:pnp-callout -->

The _state_ is the data that Terraform has recorded about a workspace at a
particular point in its lifecycle, usually after an apply. You can read more
general information about how Terraform uses state [here][ref-tf-state].

[ref-tf-state]: /terraform/language/state

-> **Note:** Since HCP Terraform currently only supports policy checks at plan
time, the usefulness of this import is somewhat limited, as it will usually give
you the state _prior_ to the plan the policy check is currently being run for.
Depending on your needs, you may find the
[`applied`](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfplan#value-applied) collection in `tfplan` more useful,
which will give you a _predicted_ state by applying plan data to the data found
here. The one exception to this rule is _data sources_, which will always give
up to date data here, as long as the data source could be evaluated at plan
time.

## Namespace Overview

The following is a tree view of the import namespace. For more detail on a
particular part of the namespace, see below.

-> Note that the root-level alias keys shown here (`data`, `outputs`, `path`,
and `resources`) are shortcuts to a [module namespace](#namespace-module) scoped
to the root module. For more details, see the section on [root namespace
aliases](#root-namespace-aliases).

```
tfstate
├── module() (function)
│   └── (module namespace)
│       ├── path ([]string)
│       ├── data
│       │   └── TYPE.NAME[NUMBER]
│       │       ├── attr (map of keys)
│       │       ├── depends_on ([]string)
│       │       ├── id (string)
│       │       └── tainted (boolean)
│       ├── outputs (root module only in TF 0.12 or later)
│       │   └── NAME
│       │       ├── sensitive (bool)
│       │       ├── type (string)
│       │       └── value (value)
│       └── resources
│           └── TYPE.NAME[NUMBER]
│               ├── attr (map of keys)
│               ├── depends_on ([]string)
│               ├── id (string)
│               └── tainted (boolean)
│
├── module_paths ([][]string)
├── terraform_version (string)
│
├── data (root module alias)
├── outputs (root module alias)
├── path (root module alias)
└── resources (root module alias)
```

## Namespace: Root

The root-level namespace consists of the values and functions documented below.

In addition to this, the root-level `data`, `outputs`, `path`, and `resources`
keys alias to their corresponding namespaces or values within the [module
namespace](#namespace-module).

### Function: `module()`

```
module = func(ADDR)
```

* **Return Type:** A [module namespace](#namespace-module).

The `module()` function in the [root namespace](#namespace-root) returns the
[module namespace](#namespace-module) for a particular module address.

The address must be a list and is the module address, split on the period (`.`),
excluding the root module.

Hence, a module with an address of simply `foo` (or `root.foo`) would be
`["foo"]`, and a module within that (so address `foo.bar`) would be read as
`["foo", "bar"]`.

[`null`][ref-null] is returned if a module address is invalid, or if the module
is not present in the state.

[ref-null]: https://docs.hashicorp.com/sentinel/language/spec#null

As an example, given the following module block:

```hcl
module "foo" {
  # ...
}
```

If the module contained the following content:

```hcl
resource "null_resource" "foo" {
  triggers = {
    foo = "bar"
  }
}
```

The following policy would evaluate to `true` if the resource was present in
the state:

```python
import "tfstate"

main = rule { tfstate.module(["foo"]).resources.null_resource.foo[0].attr.triggers.foo is "bar" }
```

### Value: `module_paths`

* **Value Type:** List of a list of strings.

The `module_paths` value within the [root namespace](#namespace-root) is a list
of all of the modules within the Terraform state at plan-time.

Modules not present in the state will not be present here, even if they are
present in the configuration or the diff.

This data is represented as a list of a list of strings, with the inner list
being the module address, split on the period (`.`).

The root module is included in this list, represented as an empty inner list, as
long as it is present in state.

As an example, if the following module block was present within a Terraform
configuration:

```hcl
module "foo" {
  # ...
}
```

The value of `module_paths` would be:

```
[
	[],
	["foo"],
]
```

And the following policy would evaluate to `true`:

```python
import "tfstate"

main = rule { tfstate.module_paths contains ["foo"] }
```

-> Note the above example only applies if the module is present in the state.

#### Iterating Through Modules

Iterating through all modules to find particular resources can be useful. This
[example][iterate-over-modules] shows how to use `module_paths` with the
[`module()` function](#function-module-) to find all resources of a
particular type from all modules using the `tfplan` import. By changing `tfplan`
in this function to `tfstate`, you could make a similar function find all
resources of a specific type in the current state.

[iterate-over-modules]: /terraform/cloud-docs/policy-enforcement/sentinel#sentinel-imports

### Value: `terraform_version`

* **Value Type:** String.

The `terraform_version` value within the [root namespace](#namespace-root)
represents the version of Terraform in use when the state was saved. This can be
used to enforce a specific version of Terraform in a policy check.

As an example, the following policy would evaluate to `true` as long as the
state was made with a version of Terraform in the 0.11.x series, excluding any
pre-release versions (example: `-beta1` or `-rc1`):

```python
import "tfstate"

main = rule { tfstate.terraform_version matches "^0\\.11\\.\\d+$" }
```

-> **NOTE:** This value is also available via the [`tfplan`](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfplan)
import, which will be more current when a policy check is run against a plan.
It's recommended you use the value in `tfplan` until HCP Terraform
supports policy checks in other stages of the workspace lifecycle. See the
[`terraform_version`][import-tfplan-terraform-version] reference within the
`tfplan` import for more details.

[import-tfplan-terraform-version]: /terraform/cloud-docs/policy-enforcement/sentinel/import/tfplan#value-terraform_version

## Namespace: Module

The **module namespace** can be loaded by calling
[`module()`](#function-module-) for a particular module.

It can be used to load the following child namespaces, in addition to the values
documented below:

* `data` - Loads the [resource namespace](#namespace-resources-data-sources),
  filtered against data sources.
* `outputs` - Loads the [output namespace](#namespace-outputs), which supply the
  outputs present in this module's state. Note that with Terraform 0.12 or
  later, this value is only available for the root namespace.
* `resources` - Loads the [resource
  namespace](#namespace-resources-data-sources), filtered against resources.

### Root Namespace Aliases

The root-level `data`, `outputs`, and `resources` keys both alias to their
corresponding namespaces within the module namespace, loaded for the root
module. They are the equivalent of running `module([]).KEY`.

### Value: `path`

* **Value Type:** List of strings.

The `path` value within the [module namespace](#namespace-module) contains the
path of the module that the namespace represents. This is represented as a list
of strings.

As an example, if the following module block was present within a Terraform
configuration:

```hcl
module "foo" {
  # ...
}
```

The following policy would evaluate to `true`, _only_ if the module was present
in the state:

```python
import "tfstate"

main = rule { tfstate.module(["foo"]).path contains "foo" }
```

## Namespace: Resources/Data Sources

The **resource namespace** is a namespace _type_ that applies to both resources
(accessed by using the `resources` namespace key) and data sources (accessed
using the `data` namespace key).

Accessing an individual resource or data source within each respective namespace
can be accomplished by specifying the type, name, and resource number (as if the
resource or data source had a `count` value in it) in the syntax
`[resources|data].TYPE.NAME[NUMBER]`. Note that NUMBER is always needed, even if
you did not use `count` in the resource.

In addition, each of these namespace levels is a map, allowing you to filter
based on type and name.

-> The (somewhat strange) notation here of `TYPE.NAME[NUMBER]` may imply that
the inner resource index map is actually a list, but it's not - using the square
bracket notation over the dotted notation (`TYPE.NAME.NUMBER`) is required here
as an identifier cannot start with number.

Some examples of multi-level access are below:

* To fetch all `aws_instance.foo` resource instances within the root module, you
  can specify `tfstate.resources.aws_instance.foo`. This would then be indexed
  by resource count index (`0`, `1`, `2`, and so on). Note that as mentioned
  above, these elements must be accessed using square-bracket map notation (so
  `[0]`, `[1]`, `[2]`, and so on) instead of dotted notation.
* To fetch all `aws_instance` resources within the root module, you can specify
  `tfstate.resources.aws_instance`. This would be indexed from the names of
  each resource (`foo`, `bar`, and so on), with each of those maps containing
  instances indexed by resource count index as per above.
* To fetch all resources within the root module, irrespective of type, use
  `tfstate.resources`. This is indexed by type, as shown above with
  `tfstate.resources.aws_instance`, with names being the next level down, and so
  on.

Further explanation of the namespace will be in the context of resources. As
mentioned, when operating on data sources, use the same syntax, except with
`data` in place of `resources`.

### Value: `attr`

* **Value Type:** A string-keyed map of values.

The `attr` value within the [resource
namespace](#namespace-resources-data-sources) is a direct mapping to the state
of the resource.

The map is a complex representation of these values with data going as far down
as needed to represent any state values such as maps, lists, and sets.

As an example, given the following resource:

```hcl
resource "null_resource" "foo" {
  triggers = {
    foo = "bar"
  }
}
```

The following policy would evaluate to `true` if the resource was in the state:

```python
import "tfstate"

main = rule { tfstate.resources.null_resource.foo[0].attr.triggers.foo is "bar" }
```

### Value: `depends_on`

* **Value Type:** A list of strings.

The `depends_on` value within the [resource
namespace](#namespace-resources-data-sources) contains the dependencies for the
resource.

This is a list of full resource addresses, relative to the module (example:
`null_resource.foo`).

As an example, given the following resources:

```hcl
resource "null_resource" "foo" {
  triggers = {
    foo = "bar"
  }
}

resource "null_resource" "bar" {
  # ...

  depends_on = [
    "null_resource.foo",
  ]
}
```

The following policy would evaluate to `true` if the resource was in the state:

```python
import "tfstate"

main = rule { tfstate.resources.null_resource.bar[0].depends_on contains "null_resource.foo" }
```

### Value: `id`

* **Value Type:** String.

The `id` value within the [resource
namespace](#namespace-resources-data-sources) contains the id of the resource.

-> **NOTE:** The example below uses a _data source_ here because the
[`null_data_source`][ref-tf-null-data-source] data source gives a static ID,
which makes documenting the example easier. As previously mentioned, data
sources share the same namespace as resources, but need to be loaded with the
`data` key. For more information, see the
[synopsis](#namespace-resources-data-sources) for the namespace itself.

[ref-tf-null-data-source]: https://registry.terraform.io/providers/hashicorp/null/latest/docs/data-sources/data_source

As an example, given the following data source:

```hcl
data "null_data_source" "foo" {
  # ...
}
```

The following policy would evaluate to `true`:

```python
import "tfstate"

main = rule { tfstate.data.null_data_source.foo[0].id is "static" }
```

### Value: `tainted`

* **Value Type:** Boolean.

The `tainted` value within the [resource
namespace](#namespace-resources-data-sources) is `true` if the resource is
marked as tainted in Terraform state.

As an example, given the following resource:

```hcl
resource "null_resource" "foo" {
  triggers = {
    foo = "bar"
  }
}
```

The following policy would evaluate to `true`, if the resource was marked as
tainted in the state:

```python
import "tfstate"

main = rule { tfstate.resources.null_resource.foo[0].tainted }
```

## Namespace: Outputs

The **output namespace** represents all of the outputs present within a
[module](#namespace-module). Outputs are present in a state if they were saved
during a previous apply, or if they were updated with known values during the
pre-plan refresh.

**With Terraform 0.11 or earlier** this can be used to fetch both the outputs
of the root module, and the outputs of any module in the state below the root.
This makes it possible to see outputs that have not been threaded to the root
module.

**With Terraform 0.12 or later** outputs are available in the top-level (root
module) namespace only and not accessible within submodules.

This namespace is indexed by output name.

### Value: `sensitive`

* **Value Type:** Boolean.

The `sensitive` value within the [output namespace](#namespace-outputs) is
`true` when the output has been [marked as sensitive][ref-tf-sensitive-outputs].

[ref-tf-sensitive-outputs]: /terraform/language/values/outputs#sensitive-suppressing-values-in-cli-output

As an example, given the following output:

```hcl
output "foo" {
  sensitive = true
  value     = "bar"
}
```

The following policy would evaluate to `true`:

```python
import "tfstate"

main = rule { tfstate.outputs.foo.sensitive }
```

### Value: `type`

* **Value Type:** String.

The `type` value within the [output namespace](#namespace-outputs) gives the
output's type. This will be one of `string`, `list`, or `map`. These are
currently the only types available for outputs in Terraform.

As an example, given the following output:

```hcl
output "string" {
  value = "foo"
}

output "list" {
  value = [
    "foo",
    "bar",
  ]
}

output "map" {
  value = {
    foo = "bar"
  }
}
```

The following policy would evaluate to `true`:

```python
import "tfstate"

type_string = rule { tfstate.outputs.string.type is "string" }
type_list = rule { tfstate.outputs.list.type is "list" }
type_map = rule { tfstate.outputs.map.type is "map" }

main = rule { type_string and type_list and type_map }
```

### Value: `value`

* **Value Type:** String, list, or map.

The `value` value within the [output namespace](#namespace-outputs) is the value
of the output in question.

Note that the only valid primitive output type in Terraform is currently a
string, which means that any int, float, or boolean value will need to be
converted before it can be used in comparison. This does not apply to primitives
within maps and lists, which will be their original types.

As an example, given the following output blocks:

```hcl
output "foo" {
  value = "bar"
}

output "number" {
  value = "42"
}

output "map" {
  value = {
    foo    = "bar"
    number = 42
  }
}
```

The following policy would evaluate to `true`:

```python
import "tfstate"

value_foo = rule { tfstate.outputs.foo.value is "bar" }
value_number = rule { int(tfstate.outputs.number.value) is 42 }
value_map_string = rule { tfstate.outputs.map.value["foo"] is "bar" }
value_map_int = rule { tfstate.outputs.map.value["number"] is 42 }

main = rule { value_foo and value_number and value_map_string and value_map_int }
```

page title  tfstate   Imports   Sentinel   HCP Terraform description  The tfstate import provides access to a Terraform state         Import  tfstate       Warning    The  tfstate  import is now deprecated and will be permanently removed in August 2025  We recommend that you start using the updated  tfstate v2   terraform cloud docs policy enforcement sentinel import tfstate v2  import as soon as possible to avoid disruptions  The  tfstate v2  import offers improved functionality and is designed to better support your policy enforcement needs   The  tfstate  import provides access to the Terraform state        BEGIN  TFC only name pnp callout      include  tfc package callouts policies mdx       END  TFC only name pnp callout      The  state  is the data that Terraform has recorded about a workspace at a particular point in its lifecycle  usually after an apply  You can read more general information about how Terraform uses state  here  ref tf state     ref tf state    terraform language state       Note    Since HCP Terraform currently only supports policy checks at plan time  the usefulness of this import is somewhat limited  as it will usually give you the state  prior  to the plan the policy check is currently being run for  Depending on your needs  you may find the   applied    terraform cloud docs policy enforcement sentinel import tfplan value applied  collection in  tfplan  more useful  which will give you a  predicted  state by applying plan data to the data found here  The one exception to this rule is  data sources   which will always give up to date data here  as long as the data source could be evaluated at plan time      Namespace Overview  The following is a tree view of the import namespace  For more detail on a particular part of the namespace  see below      Note that the root level alias keys shown here   data    outputs    path   and  resources   are shortcuts to a  module namespace   namespace module  scoped to the root module  For more details  see the section on  root namespace aliases   root namespace aliases        tfstate     module    function           module namespace              path    string              data                 TYPE NAME NUMBER                      attr  map of keys                      depends on    string                      id  string                      tainted  boolean              outputs  root module only in TF 0 12 or later                  NAME                     sensitive  bool                      type  string                      value  value              resources                 TYPE NAME NUMBER                      attr  map of keys                      depends on    string                      id  string                      tainted  boolean        module paths      string      terraform version  string        data  root module alias      outputs  root module alias      path  root module alias      resources  root module alias          Namespace  Root  The root level namespace consists of the values and functions documented below   In addition to this  the root level  data    outputs    path   and  resources  keys alias to their corresponding namespaces or values within the  module namespace   namespace module        Function   module         module   func ADDR           Return Type    A  module namespace   namespace module    The  module    function in the  root namespace   namespace root  returns the  module namespace   namespace module  for a particular module address   The address must be a list and is the module address  split on the period        excluding the root module   Hence  a module with an address of simply  foo   or  root foo   would be    foo     and a module within that  so address  foo bar   would be read as    foo    bar        null   ref null  is returned if a module address is invalid  or if the module is not present in the state    ref null   https   docs hashicorp com sentinel language spec null  As an example  given the following module block      hcl module  foo                   If the module contained the following content      hcl resource  null resource   foo      triggers         foo    bar             The following policy would evaluate to  true  if the resource was present in the state      python import  tfstate   main   rule   tfstate module   foo    resources null resource foo 0  attr triggers foo is  bar             Value   module paths       Value Type    List of a list of strings   The  module paths  value within the  root namespace   namespace root  is a list of all of the modules within the Terraform state at plan time   Modules not present in the state will not be present here  even if they are present in the configuration or the diff   This data is represented as a list of a list of strings  with the inner list being the module address  split on the period         The root module is included in this list  represented as an empty inner list  as long as it is present in state   As an example  if the following module block was present within a Terraform configuration      hcl module  foo                   The value of  module paths  would be                 foo           And the following policy would evaluate to  true       python import  tfstate   main   rule   tfstate module paths contains   foo             Note the above example only applies if the module is present in the state        Iterating Through Modules  Iterating through all modules to find particular resources can be useful  This  example  iterate over modules  shows how to use  module paths  with the   module    function   function module   to find all resources of a particular type from all modules using the  tfplan  import  By changing  tfplan  in this function to  tfstate   you could make a similar function find all resources of a specific type in the current state    iterate over modules    terraform cloud docs policy enforcement sentinel sentinel imports      Value   terraform version       Value Type    String   The  terraform version  value within the  root namespace   namespace root  represents the version of Terraform in use when the state was saved  This can be used to enforce a specific version of Terraform in a policy check   As an example  the following policy would evaluate to  true  as long as the state was made with a version of Terraform in the 0 11 x series  excluding any pre release versions  example    beta1  or   rc1        python import  tfstate   main   rule   tfstate terraform version matches   0   11     d                NOTE    This value is also available via the   tfplan    terraform cloud docs policy enforcement sentinel import tfplan  import  which will be more current when a policy check is run against a plan  It s recommended you use the value in  tfplan  until HCP Terraform supports policy checks in other stages of the workspace lifecycle  See the   terraform version   import tfplan terraform version  reference within the  tfplan  import for more details    import tfplan terraform version    terraform cloud docs policy enforcement sentinel import tfplan value terraform version     Namespace  Module  The   module namespace   can be loaded by calling   module      function module   for a particular module   It can be used to load the following child namespaces  in addition to the values documented below      data    Loads the  resource namespace   namespace resources data sources     filtered against data sources     outputs    Loads the  output namespace   namespace outputs   which supply the   outputs present in this module s state  Note that with Terraform 0 12 or   later  this value is only available for the root namespace     resources    Loads the  resource   namespace   namespace resources data sources   filtered against resources       Root Namespace Aliases  The root level  data    outputs   and  resources  keys both alias to their corresponding namespaces within the module namespace  loaded for the root module  They are the equivalent of running  module     KEY        Value   path       Value Type    List of strings   The  path  value within the  module namespace   namespace module  contains the path of the module that the namespace represents  This is represented as a list of strings   As an example  if the following module block was present within a Terraform configuration      hcl module  foo                   The following policy would evaluate to  true    only  if the module was present in the state      python import  tfstate   main   rule   tfstate module   foo    path contains  foo            Namespace  Resources Data Sources  The   resource namespace   is a namespace  type  that applies to both resources  accessed by using the  resources  namespace key  and data sources  accessed using the  data  namespace key    Accessing an individual resource or data source within each respective namespace can be accomplished by specifying the type  name  and resource number  as if the resource or data source had a  count  value in it  in the syntax   resources data  TYPE NAME NUMBER    Note that NUMBER is always needed  even if you did not use  count  in the resource   In addition  each of these namespace levels is a map  allowing you to filter based on type and name      The  somewhat strange  notation here of  TYPE NAME NUMBER   may imply that the inner resource index map is actually a list  but it s not   using the square bracket notation over the dotted notation   TYPE NAME NUMBER   is required here as an identifier cannot start with number   Some examples of multi level access are below     To fetch all  aws instance foo  resource instances within the root module  you   can specify  tfstate resources aws instance foo   This would then be indexed   by resource count index   0    1    2   and so on   Note that as mentioned   above  these elements must be accessed using square bracket map notation  so     0      1      2    and so on  instead of dotted notation    To fetch all  aws instance  resources within the root module  you can specify    tfstate resources aws instance   This would be indexed from the names of   each resource   foo    bar   and so on   with each of those maps containing   instances indexed by resource count index as per above    To fetch all resources within the root module  irrespective of type  use    tfstate resources   This is indexed by type  as shown above with    tfstate resources aws instance   with names being the next level down  and so   on   Further explanation of the namespace will be in the context of resources  As mentioned  when operating on data sources  use the same syntax  except with  data  in place of  resources        Value   attr       Value Type    A string keyed map of values   The  attr  value within the  resource namespace   namespace resources data sources  is a direct mapping to the state of the resource   The map is a complex representation of these values with data going as far down as needed to represent any state values such as maps  lists  and sets   As an example  given the following resource      hcl resource  null resource   foo      triggers         foo    bar             The following policy would evaluate to  true  if the resource was in the state      python import  tfstate   main   rule   tfstate resources null resource foo 0  attr triggers foo is  bar             Value   depends on       Value Type    A list of strings   The  depends on  value within the  resource namespace   namespace resources data sources  contains the dependencies for the resource   This is a list of full resource addresses  relative to the module  example   null resource foo     As an example  given the following resources      hcl resource  null resource   foo      triggers         foo    bar         resource  null resource   bar               depends on          null resource foo              The following policy would evaluate to  true  if the resource was in the state      python import  tfstate   main   rule   tfstate resources null resource bar 0  depends on contains  null resource foo             Value   id       Value Type    String   The  id  value within the  resource namespace   namespace resources data sources  contains the id of the resource        NOTE    The example below uses a  data source  here because the   null data source   ref tf null data source  data source gives a static ID  which makes documenting the example easier  As previously mentioned  data sources share the same namespace as resources  but need to be loaded with the  data  key  For more information  see the  synopsis   namespace resources data sources  for the namespace itself    ref tf null data source   https   registry terraform io providers hashicorp null latest docs data sources data source  As an example  given the following data source      hcl data  null data source   foo                   The following policy would evaluate to  true       python import  tfstate   main   rule   tfstate data null data source foo 0  id is  static             Value   tainted       Value Type    Boolean   The  tainted  value within the  resource namespace   namespace resources data sources  is  true  if the resource is marked as tainted in Terraform state   As an example  given the following resource      hcl resource  null resource   foo      triggers         foo    bar             The following policy would evaluate to  true   if the resource was marked as tainted in the state      python import  tfstate   main   rule   tfstate resources null resource foo 0  tainted           Namespace  Outputs  The   output namespace   represents all of the outputs present within a  module   namespace module   Outputs are present in a state if they were saved during a previous apply  or if they were updated with known values during the pre plan refresh     With Terraform 0 11 or earlier   this can be used to fetch both the outputs of the root module  and the outputs of any module in the state below the root  This makes it possible to see outputs that have not been threaded to the root module     With Terraform 0 12 or later   outputs are available in the top level  root module  namespace only and not accessible within submodules   This namespace is indexed by output name       Value   sensitive       Value Type    Boolean   The  sensitive  value within the  output namespace   namespace outputs  is  true  when the output has been  marked as sensitive  ref tf sensitive outputs     ref tf sensitive outputs    terraform language values outputs sensitive suppressing values in cli output  As an example  given the following output      hcl output  foo      sensitive   true   value        bar         The following policy would evaluate to  true       python import  tfstate   main   rule   tfstate outputs foo sensitive            Value   type       Value Type    String   The  type  value within the  output namespace   namespace outputs  gives the output s type  This will be one of  string    list   or  map   These are currently the only types available for outputs in Terraform   As an example  given the following output      hcl output  string      value    foo     output  list      value          foo        bar          output  map      value         foo    bar             The following policy would evaluate to  true       python import  tfstate   type string   rule   tfstate outputs string type is  string    type list   rule   tfstate outputs list type is  list    type map   rule   tfstate outputs map type is  map     main   rule   type string and type list and type map            Value   value       Value Type    String  list  or map   The  value  value within the  output namespace   namespace outputs  is the value of the output in question   Note that the only valid primitive output type in Terraform is currently a string  which means that any int  float  or boolean value will need to be converted before it can be used in comparison  This does not apply to primitives within maps and lists  which will be their original types   As an example  given the following output blocks      hcl output  foo      value    bar     output  number      value    42     output  map      value         foo       bar      number   42            The following policy would evaluate to  true       python import  tfstate   value foo   rule   tfstate outputs foo value is  bar    value number   rule   int tfstate outputs number value  is 42   value map string   rule   tfstate outputs map value  foo   is  bar    value map int   rule   tfstate outputs map value  number   is 42    main   rule   value foo and value number and value map string and value map int


terraform Learn how to use Sentinel policy language to create custom policies including Define custom Sentinel policies imports to define rules and useful functions 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 terraform cloud docs policy enforcement define policies prewritten sentinel page title Define custom Sentinel policies

Answer:
---
page_title: Define custom Sentinel policies
description: >-
  Learn how to use Sentinel policy language to create custom policies, including
  imports to define rules and useful functions.
---

# Define custom Sentinel policies

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](/terraform/cloud-docs/policy-enforcement/define-policies/prewritten-sentinel).

## Overview

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.

<!-- BEGIN: TFC:only name:pnp-callout -->
@include 'tfc-package-callouts/policies.mdx'
<!-- END: TFC:only name:pnp-callout -->

## Declare an `import` function

A policy can include imports that enable a policy to access reusable libraries, external data, and functions. Refer to [imports](https://docs.hashicorp.com/sentinel/concepts/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.

- [tfplan](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfplan) - Access a Terraform plan, which is the file created as a result of the [`terraform plan` command](/terraform/cli/commands/plan). The plan represents the changes that Terraform must make to reach the desired infrastructure state described in the configuration.
- [tfconfig](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfconfig) - Access a Terraform configuration. The configuration is the set of `.tf` files that describe the desired infrastructure state.
- [tfstate](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfstate) - Access the Terraform [state](/terraform/language/state). Terraform uses state to map real-world resources to your configuration.
- [tfrun](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfrun) - Access data associated with a [run in HCP Terraform](/terraform/cloud-docs/run/remote-operations). For example, you could retrieve the run's workspace.

You can create mocks of these imports to use with the the [Sentinel
CLI](https://docs.hashicorp.com/sentinel/commands) mocking and testing features. Refer to [Mocking Terraform Sentinel Data](/terraform/cloud-docs/policy-enforcement/sentinel/mock) for more details.

<!-- BEGIN: TFC:only name:pnp-callout -->
HCP Terraform does not support custom imports.
<!-- END: TFC:only name:pnp-callout -->

## Declare additional elements

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. You can find similar
functions that iterate over the `tfconfig` and `tfstate` imports
[here](https://github.com/hashicorp/terraform-guides/tree/master/governance/second-generation/common-functions).

```python
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:

```python
aws_instances = find_resources_from_plan("aws_instance")
```

This example function does several useful things while finding resources:

- It checks every module (including the root module) for resources of the
  specified type by iterating over the `module_paths` namespace. The top-level
  `resources` namespace is more convenient, but it only reveals resources from
  the root module.
- It iterates over the named resources and [resource
  instances](/terraform/language/expressions/references#resources)
  found in each module, starting with `tfplan.module(path).resources[type]`
  which is a series of nested maps keyed by resource names and instance counts.
- It uses the Sentinel [`else`
  operator](https://docs.hashicorp.com/sentinel/language/spec#else-operator) to
  recover from `undefined` values which would occur for modules that don't have
  any resources of the specified type.
- It builds a flat `resources` map of all resource instances of the specified
  type. Using a flat map simplifies the code used by Sentinel policies to
  evaluate rules.
- It computes an `address` variable for each resource instance and uses this as
  the key in the `resources` map. This allows writers of Sentinel policies to
  print the full [address](/terraform/cli/state/resource-addressing) of each
  resource instance that violate a policy, using the same address format used in
  plan and apply logs. Doing this tells users who see violation messages exactly
  which resources they need to modify in their Terraform code to comply with the
  Sentinel policies.
- It sets the value of the `resources` map to the data associated with the
  resource instance (`r`). This is the data that Sentinel policies apply rules
  against.

### 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](https://docs.hashicorp.com/sentinel/language/boolexpr#any-all-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](https://docs.hashicorp.com/sentinel/language/loops) 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:

```python
# 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](/terraform/cloud-docs/policy-enforcement/sentinel/import/tfplan#value-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.

```python
# 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:

```python
# 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.

## Next steps

1. Group your policies into sets and apply them to your workspaces. Refer to [Create policy sets](/terraform/cloud-docs//policy-enforcement/create-sets) for additional information.
1. View results and address Terraform runs that do not comply with your policies. Refer to [View results](/terraform/cloud-docs/policy-enforcement/view-results) for additional information.
1. You can also view Sentinel policy results in JSON format. Refer to [View Sentinel JSON results]((/terraform/cloud-docs/policy-enforcement/view-json-results) for additional information.

page title  Define custom Sentinel policies description       Learn how to use Sentinel policy language to create custom policies  including   imports to define rules and useful functions         Define custom Sentinel policies   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   terraform cloud docs policy enforcement define policies prewritten sentinel       Overview  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          BEGIN  TFC only name pnp callout      include  tfc package callouts policies mdx       END  TFC only name pnp callout         Declare an  import  function  A policy can include imports that enable a policy to access reusable libraries  external data  and functions  Refer to  imports  https   docs hashicorp com sentinel concepts 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      tfplan   terraform cloud docs policy enforcement sentinel import tfplan    Access a Terraform plan  which is the file created as a result of the   terraform plan  command   terraform cli commands plan   The plan represents the changes that Terraform must make to reach the desired infrastructure state described in the configuration     tfconfig   terraform cloud docs policy enforcement sentinel import tfconfig    Access a Terraform configuration  The configuration is the set of   tf  files that describe the desired infrastructure state     tfstate   terraform cloud docs policy enforcement sentinel import tfstate    Access the Terraform  state   terraform language state   Terraform uses state to map real world resources to your configuration     tfrun   terraform cloud docs policy enforcement sentinel import tfrun    Access data associated with a  run in HCP Terraform   terraform cloud docs run remote operations   For example  you could retrieve the run s workspace   You can create mocks of these imports to use with the the  Sentinel CLI  https   docs hashicorp com sentinel commands  mocking and testing features  Refer to  Mocking Terraform Sentinel Data   terraform cloud docs policy enforcement sentinel mock  for more details        BEGIN  TFC only name pnp callout     HCP Terraform does not support custom imports       END  TFC only name pnp callout          Declare additional elements  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  You can find similar functions that iterate over the  tfconfig  and  tfstate  imports  here  https   github com hashicorp terraform guides tree master governance second generation common functions       python 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      python aws instances   find resources from plan  aws instance        This example function does several useful things while finding resources     It checks every module  including the root module  for resources of the   specified type by iterating over the  module paths  namespace  The top level    resources  namespace is more convenient  but it only reveals resources from   the root module    It iterates over the named resources and  resource   instances   terraform language expressions references resources    found in each module  starting with  tfplan module path  resources type     which is a series of nested maps keyed by resource names and instance counts    It uses the Sentinel   else    operator  https   docs hashicorp com sentinel language spec else operator  to   recover from  undefined  values which would occur for modules that don t have   any resources of the specified type    It builds a flat  resources  map of all resource instances of the specified   type  Using a flat map simplifies the code used by Sentinel policies to   evaluate rules    It computes an  address  variable for each resource instance and uses this as   the key in the  resources  map  This allows writers of Sentinel policies to   print the full  address   terraform cli state resource addressing  of each   resource instance that violate a policy  using the same address format used in   plan and apply logs  Doing this tells users who see violation messages exactly   which resources they need to modify in their Terraform code to comply with the   Sentinel policies    It sets the value of the  resources  map to the data associated with the   resource instance   r    This is the data that Sentinel policies apply rules   against       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  https   docs hashicorp com sentinel language boolexpr any all 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  https   docs hashicorp com sentinel language loops  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      python   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   terraform cloud docs policy enforcement sentinel import tfplan value 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      python   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      python   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      Next steps  1  Group your policies into sets and apply them to your workspaces  Refer to  Create policy sets   terraform cloud docs  policy enforcement create sets  for additional information  1  View results and address Terraform runs that do not comply with your policies  Refer to  View results   terraform cloud docs policy enforcement view results  for additional information  1  You can also view Sentinel policy results in JSON format  Refer to  View Sentinel JSON results    terraform cloud docs policy enforcement view json results  for additional information