A RetroSearch Logo

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

Search Query:

Showing content from https://developer.hashicorp.com/sentinel/docs/features/terraform/tfconfig-v2 below:

tfconfig/v2 - terraform - Features | Sentinel

The tfconfig/v2 import provides access to a Terraform configuration.

The Terraform configuration is the set of *.tf files that are used to describe the desired infrastructure state. Policies using the tfconfig import can access all aspects of the configuration: providers, resources, data sources, modules, and variables.

Some use cases for tfconfig include:

The data in the tfconfig/v2 import is sourced from the JSON configuration file that is generated by the terraform show -json command. For more information on the file format, see the JSON Output Format page.

To configure the import, you must add the import to your configuration file and provide the path to the appropriate plan file.

import "plugin" "tfconfig/v2" {
  config = {
    "path": "./path/to/plan.json"
  }
}

The tfconfig/v2 import is structured as a series of collections, keyed as a specific format, such as resource address, module address, or a specifically-formatted provider key.

tfconfig/v2
├── strip_index() (function)
├── providers
│   └── (indexed by [module_address:]provider[.alias])
│       ├── provider_config_key (string)
│       ├── name (string)
│       ├── full_name (string)
│       ├── alias (string)
│       ├── module_address (string)
│       ├── config (block expression representation)
│       └── version_constraint (string)
├── resources
│   └── (indexed by address)
│       ├── address (string)
│       ├── module_address (string)
│       ├── mode (string)
│       ├── type (string)
│       ├── name (string)
│       ├── provider_config_key (string)
│       ├── provisioners (list)
│       │   └── (ordered provisioners for this resource only)
│       ├── config (block expression representation)
│       ├── count (expression representation)
│       ├── for_each (expression representation)
│       └── depends_on (list of strings)
├── provisioners
│   └── (indexed by resource_address:index)
│       ├── resource_address (string)
│       ├── type (string)
│       ├── index (string)
│       └── config (block expression representation)
├── variables
│   └── (indexed by module_address:name)
│       ├── module_address (string)
│       ├── name (string)
│       ├── default (value)
│       └── description (string)
├── outputs
│   └── (indexed by module_address:name)
│       ├── module_address (string)
│       ├── name (string)
│       ├── sensitive (boolean)
│       ├── value (expression representation)
│       ├── description (string)
│       └── depends_on (list of strings)
└── module_calls
    └── (indexed by module_address:name)
        ├── module_address (string)
        ├── name (string)
        ├── source (string)
        ├── config (block expression representation)
        ├── count (expression representation)
        ├── depends_on (expression representation)
        ├── for_each (expression representation)
        └── version_constraint (string)

The collections are:

These collections are specifically designed to be used with the filter quantifier expression in Sentinel, so that one can collect a list of resources to perform policy checks on without having to write complex module or configuration traversal. As an example, the following code will return all aws_instance resource types within the configuration, regardless of what module they are in:

all_aws_instances = filter tfconfig.resources as _, r {
    r.mode is "managed" and
        r.type is "aws_instance"
}

You can add specific attributes to the filter to narrow the search, such as the module address. The following code would return resources in a module named foo only:

all_aws_instances = filter tfconfig.resources as _, r {
    r.module_address is "module.foo" and
        r.mode is "managed" and
        r.type is "aws_instance"
}
Address Differences Between tfconfig, tfplan, and tfstate

This import deals with configuration before it is expanded into a resource graph by Terraform. As such, it is not possible to compute an index as the import is building its collections and computing addresses for resources and modules.

As such, addresses found here may not always match the expanded addresses found in the tfplan/v2 and tfstate/v2 imports, specifically when count and for_each, are used.

As an example, consider a resource named null_resource.foo with a count of 2 located in a module named bar. While there will possibly be entries in the other imports for module.bar.null_resource.foo[0] and module.bar.null_resource.foo[1], in tfconfig/v2, there will only be a module.bar.null_resource.foo. As mentioned in the start of this section, this is because configuration actually defines this scaling, whereas expansion actually happens when the resource graph is built, which happens as a natural part of the refresh and planning process.

The strip_index helper function, found in this import, can assist in removing the indexes from addresses found in the tfplan/v2 and tfstate/v2 imports so that data from those imports can be used to reference data in this one.

The strip_index helper function can be used to remove indexes from addresses found in tfplan/v2 and tfstate/v2, by removing the indexes from each resource.

This can be used to help facilitate cross-import lookups for data between plan, state, and config.

import "tfconfig/v2" as tfconfig
import "tfplan/v2" as tfplan
 
main = rule {
    all filter tfplan.resource_changes as _, rc {
        rc.mode is "managed" and
            rc.type is "aws_instance"
    } as _, rc {
        tfconfig.resources[tfconfig.strip_index(rc.address)].config.ami.constant_value is "ami-abcdefgh012345"
    }
}

Most collections in this import will have one of two kinds of expression representations. This is a verbose format for expressing a (parsed) configuration value independent of the configuration source code, which is not 100% available to a policy check in HCP Terraform.

(expression representation)
├── constant_value (value)
└── references (list of strings)

There are two major parts to an expression representation:

For example, to determine if an output is based on a particular resource value, one could do:

import "tfconfig/v2" as tfconfig
 
main = rule {
    tfconfig.outputs["instance_id"].value.references is ["aws_instance.foo"]
}

Note: The representation does not account for complex interpolations or other expressions that combine constants with other expression data. For example, the partially constant data in "foo${var.bar}" would be lost.

Block Expression Representation

Expanding on the above, a multi-value expression representation (such as the kind found in a resources collection element) is similar, but the root value is a keyed map of expression representations. This is repeated until a "scalar" expression value is encountered, ie: a field that is not a block in the resource's schema.

(block expression representation)
└── (attribute key)
    ├── (child block expression representation)
    │   └── (...)
    ├── constant_value (value)
    └── references (list of strings)

As an example, one can validate expressions in an aws_instance resource using the following:

import "tfconfig/v2" as tfconfig
 
main = rule {
    tfconfig.resources["aws_instance.foo"].config.ami.constant_value is "ami-abcdefgh012345"
}

Note that nested blocks, sometimes known as sub-resources, will be nested in configuration as as list of blocks (reflecting their ultimate nature as a list of objects). An example would be the aws_instance resource's ebs_block_device block:

import "tfconfig/v2" as tfconfig
 
main = rule {
    tfconfig.resources["aws_instance.foo"].config.ebs_block_device[0].volume_size < 10
}

The providers collection is a collection representing the configurations of all provider instances across all modules in the configuration.

This collection is indexed by an opaque key. This is currently module_address:provider.alias, the same value as found in the provider_config_key field. module_address and the colon delimiter are omitted for the root module.

The provider_config_key field is also found in the resources collection and can be used to locate a provider that belongs to a configured resource.

The fields in this collection are as follows:

The resources collection is a collection representing all of the resources found in all modules in the configuration.

This collection is indexed by the resource address.

The fields in this collection are as follows:

The provisioners collection is a collection of all of the provisioners found across all resources in the configuration.

While normally bound to a resource in an ordered fashion, this collection allows for the filtering of provisioners within a single expression.

This collection is indexed with a key following the format resource_address:index, with each field matching their respective field in the particular element below:

The variables collection is a collection of all variables across all modules in the configuration.

Note that this tracks variable definitions, not values. See the tfplan/v2variables collection for variable values set within a plan.

This collection is indexed by the key format module_address:name, with each field matching their respective name below. module_address and the colon delimiter are omitted for the root module.

The outputs collection is a collection of all outputs across all modules in the configuration.

Note that this tracks variable definitions, not values. See the tfstate/v2outputs collection for the final values of outputs set within a state. The tfplan/v2 output_changes collection also contains a more complex collection of planned output changes.

This collection is indexed by the key format module_address:name, with each field matching their respective name below. module_address and the colon delimiter are omitted for the root module.

The module_calls collection is a collection of all module declarations at all levels within the configuration.

Note that this is the module stanza in any particular configuration, and not the module itself. Hence, a declaration for module.foo would actually be declared in the root module, which would be represented by a blank field in module_address.

This collection is indexed by the key format module_address:name, with each field matching their respective name below. module_address and the colon delimiter are omitted for the root module.


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

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

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