Are we there yet—Terraform 0.14?
By: Marko Bevc
Tags: Terraform, Infrastructure As Code

It hasn’t been long since Hashicorp released latest stable version of Terraform 0.13, and there is already first release candidate (RC1) 0.14 available (that blog post mentions a Beta release, but there haven’t been much changes in the following RC1) including some new features mentioned in the 1.0 roadmap at the HashiConf Digital 2020 US!

Unsurprisingly, due to the shorter release cycle there are fewer major new features in 0.14 compared to previous releases, such as 0.13 or 0.12, but nevertheless it does introduce some interesting new ones and removes some backwards compatibility.

Let’s have a look at what is already included in RC1 release (it shouldn’t change much in the GA release planned for later this month)!

0.14 release highlights

Terraform 0.14 is focusing more on core functionality, workflow efficiency and security, rather than big changes. It is still a major release and also includes some small changes in behavior that you may need to consider when upgrading. We will look at those later on.

Most notable changes in Terraform 0.14 are:

Sensitive input variables and derived sensitivity : You can now mark input variables as sensitive, and have those values redacted from the Terraform console output. This feature focuses on providing a tool for practitioners to help suppress the output of values from Terraform and infrastructure pipelines using Terraform, into systems that may not have the same controls; for example logging or monitoring. Sensitive input variables provide a building block for protecting sensitive information more thoroughly. We’re hoping that some follow-up release of Terraform adds asymmetric encryption or something similar.

: You can now mark input variables as sensitive, and have those values redacted from the Terraform console output. This feature focuses on providing a tool for practitioners to help suppress the output of values from Terraform and infrastructure pipelines using Terraform, into systems that may not have the same controls; for example logging or monitoring. Sensitive input variables provide a building block for protecting sensitive information more thoroughly. We’re hoping that some follow-up release of Terraform adds asymmetric encryption or something similar. Concise diffs by default : Terraform 0.12 included a change in the way the plan file and diff was rendered — resulting in notably more verbose output when compared to Terraform 0.11. Terraform 0.14 will ship with a new concise diff format. This feature will allow you to better understand which resources, attributes, and blocks are being modified, and can help you make more informed decisions about which actions Terraform intends to take. When Terraform is run in automation as a part of a deployment pipeline, the concise diff makes it easier to review which changes have occurred over time.

: Terraform 0.12 included a change in the way the plan file and diff was rendered — resulting in notably more verbose output when compared to Terraform 0.11. Terraform 0.14 will ship with a new concise diff format. This feature will allow you to better understand which resources, attributes, and blocks are being modified, and can help you make more informed decisions about which actions Terraform intends to take. When Terraform is run in automation as a part of a deployment pipeline, the concise diff makes it easier to review which changes have occurred over time. Provider Dependency Lock File : The provider dependency lock file can be used to ensure the collection of external dependencies used for a given configuration are consistent. It is similar to existing mechanisms in tools like NPM, Cargo and RubyGems. This will help prevent unexpected changes to your infrastructure codebase due to an inadvertent upgrade. This feature takes provider version pinning one step further by creating a lockfile that will prevent accidental upgrades or changes to the version of a provider in use for a given configuration.

: The provider dependency lock file can be used to ensure the collection of external dependencies used for a given configuration are consistent. It is similar to existing mechanisms in tools like NPM, Cargo and RubyGems. This will help prevent unexpected changes to your infrastructure codebase due to an inadvertent upgrade. This feature takes provider version pinning one step further by creating a lockfile that will prevent accidental upgrades or changes to the version of a provider in use for a given configuration. Officially supported ARM64 releases for Linux: ARM64 is now an officially supported platform for Terraform binary.

Now I’m going to take a look at each of those changes with examples, to show what it all means and how it reflects when used in Terraform code.

Sensitive values

You’ll be able to mark input variables as “sensitive”, which will result in Terraform redacting that value from CLI output. The same also applies to module outputs and module outputs with the sensitive=true attribute set will also see their values redacted throughout a Terraform plan .

Note: Sensitive values are still recorded in the state, and so will be visible to anyone who is able to access the state data. For more information, please read the documentation on Sensitive Data in State.

For example, you can define a variable as sensitive by setting the argument to true:

variable "user_information" {

type = object({

name = string

address = string

})

sensitive = true

}



resource "some_resource" "a" {

name = var.user_information.name

address = var.user_information.address



nested_block {

user_information = var.user_information # a sensitive variable

other_information = "not sensitive data"

}

}

Terraform will obfuscate the value of user_information from display in plan or apply output, or even in some cases where a sensitive variable is used in a nested block, the whole block can be redacted. This happens with resources that can have multiple blocks of the same type, where the values must be unique:

Terraform will perform the following actions:



# some_resource.a will be created

+ resource "some_resource" "a" {

+ name = (sensitive)

+ address = (sensitive)

~ nested_block {

# At least one attribute in this block is (or was) sensitive,

# so its contents will not be displayed.

}

}



Plan: 1 to add, 0 to change, 0 to destroy.

Terraform 0.14 also adds the ability to expand upon values which the provider schema defines as “sensitive”. This existing feature prevents the value of that attribute from being displayed in logs or regular output. By enabling this experimental feature Terraform 0.14 extends this functionality by also propagating the sensitive mark through the plan.

terraform {

experiments = [provider_sensitive_attrs]

}

Concise Diff Format

Terraform 0.12 moved from showing only the changed attribute path/values, to showing the entire resource with changed values prefixed with ~ . This can result in very large diffs which make it difficult to reason about the actual changes. So the diff renderer used by outputs has been updated to hide unchanged and irrelevant fields. If any attributes, collection elements, or blocks are hidden, a count will be kept and displayed at the end of the parent scope. This tries to ensure that the output is clear and easy to read.

Examples:

Change to attributes:

# test_resource.foo will be updated in-place

~ resource "test_resource" "foo" {

id = "foo_123"

~ checksum = 28987129 -> (known after apply)

- mode = "test" -> null

name = "Foo Test"

tags = []

~ totals = {

- "bar" = 5 -> null

+ "baz" = 5

# (2 unchanged elements hidden)

}

~ values = [

- "alpha",

- "gamma",

+ "alpaca",

+ "goblin",

+ "zephyr",

# (23 unchanged elements hidden)

]

# (5 unchanged attributes hidden)



# (3 unchanged blocks hidden)

}

Adding a new block looks like:

# test_resource.foo will be updated in-place

~ resource "test_resource" "foo" {

id = "foo_123"

~ checksum = 28987129 -> (known after apply)

name = "Foo Test"

tags = []

# (8 unchanged attributes hidden)



+ sub_item {

+ identifier = "bar"

+ size = 4

+ type = "whatever"

}

# (3 unchanged blocks hidden)

}

Provider dependency lock file

Until now we had external dependencies stored in .terraform folder as a sort of local, directory-specific "lock" of the selected versions of those dependencies. If you ran terraform init again in the same working directory then Terraform would select those same versions again. But with common use case patterns being changed due many people on a team all using Terraform together, either on their separate workstations (so each has their own working directory) or in an ephemeral remote execution environment (so an entirely new working directory is created for each run).

Therefore Terraform 0.14 introduces a new dependency lock file, focused on providers, to simplify managing Terraform automation. The dependency lock file launching with Terraform 0.14 is generated automatically when Terraform init is run. The generated lockfile should be committed into a version control system (VCS) so that we are guaranteed to have exactly the same provider versions selected on future runs. Upgrading to a new provider (or collection of providers) can be completed by running init -upgrade .

Example of a lockfile entry:

provider "registry.terraform.io/hashicorp/aws" {

version = "3.18.0"

constraints = "~> 3.18"

hashes = [

"h1:FJwsuowaG5CIdZ0WQyFZH9r6kIJeRKts9+GcRsTz1+Y=",

"h1:c/ntSXrDYM1mUir2KufijYebPcwKqS9CRGd3duDSGfY=",

"h1:yre4Ph76g9H84MbuhZ2z5MuldjSA4FsrX6538O7PCcY=",

"zh:04f0a50bb2ba92f3bea6f0a9e549ace5a4c13ef0cbb6975494cac0ef7d4acb43",

"zh:2082e12548ebcdd6fd73580e83f626ed4ed13f8cdfd51205d8696ffe54f30734",

"zh:246bcc449e9a92679fb30f3c0a77f05513886565e2dcc66b16c4486f51533064",

"zh:24de3930625ac9014594d79bfa42d600eca65e9022b9668b54bfd0d924e21d14",

"zh:2a22893a576ff6f268d9bf81cf4a56406f7ba79f77826f6df51ee787f6d2840a",

"zh:2b27485e19c2aaa9f15f29c4cff46154a9720647610171e30fc6c18ddc42ec28",

"zh:435f24ce1fb2b63f7f02aa3c84ac29c5757cd29ec4d297ed0618423387fe7bd4",

"zh:7d99725923de5240ff8b34b5510569aa4ebdc0bdb27b7bac2aa911a8037a3893",

"zh:7e3b5d0af3b7411dd9dc65ec9ab6caee8c191aee0fa7f20fc4f51716e67f50c0",

"zh:da0af4552bef5a29b88f6a0718253f3bf71ce471c959816eb7602b0dadb469ca",

]

}

If you don’t want to use this new behavior you can just run terraform init -upgrade and / or discard .terraform.lock immediately after it is created. The lockfile can equally be added to a list of files ignored by the VCS.

Other changes and upgrade notes

What else do you need to know before GA is releases (scheduled for next month? Looking at the RC1 CHANGELOG, I think there are some other changes worth mentioning:

Terraform will now support reading and writing all compatible state files, even from future versions of Terraform. This means you will be able to share state files with future Terraform versions until a new state file format version is needed, so you can commit to forward compatibility and invest more time in your infrastructure pipeline without worrying too much about potential future breaking changes. There are no plans of changing the state file format at this time from HashiCorp. (#26752)

The version argument inside provider configuration blocks has been deprecated since Terraform 0.12. As of 0.14 it will now also generate an explicit deprecation warning - use provider requirement declarations instead.

argument inside provider configuration blocks has been deprecated since Terraform 0.12. As of 0.14 it will now also generate an explicit deprecation warning - use provider requirement declarations instead. Terraform now requires at least macOS 10.12 Sierra or later.

TLS certificate verification for outbound HTTPS requests from Terraform CLI has been tighten.

The terraform 0.13upgrade subcommand and the associated upgrade mechanisms are no longer available. You need to complete the v0.13 upgrade process before upgrading to Terraform v0.14.

subcommand and the associated upgrade mechanisms are no longer available. You need to complete the v0.13 upgrade process before upgrading to Terraform v0.14. The debug command, which did not offer additional functionality, has been removed.

command, which did not offer additional functionality, has been removed. Terraform 0.14 will add support terraform login using OAuth 2 application scopes.

using OAuth 2 application scopes. A new global command line (CLI) option -chdir=... , placed before the selected subcommand, instructs Terraform to switch to a different working directory before executing the subcommand. Similar to executing cd before Terraform run.

, placed before the selected subcommand, instructs Terraform to switch to a different working directory before executing the subcommand. Similar to executing before Terraform run. There are two new functions, alltrue and anytrue , which serve as a sort of dynamic version of the && and || or operators respectively. You can use this with a for expression to valuate boolean conditions, such as in variable validation blocks, across all of the items in a list or set.

How to get started

So where to go next and how to get started using Terraform 0.14? If you want to give it a spin before GA, you can already download and install the appropriate binary from releases.hashicorp.com! If you are using Terraform Cloud (TFC), it can also be enabled by sending an email to support@hashicorp.com and requesting enabling beta releases.

There is already a draft upgrade guide with some initial details. In order to get your code prepared to run v0.14, you need to follow upgrade steps for v0.13, which will make it compatible with v0.14. You can read more about it in my previous Terraform blog.

HashiCorp would also welcome feedback on that upcoming release. Please use the community discussion forum created thread, or report bugs via GitHub.