Please note that this post, first published over a year ago, may now be out of date.
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.
- 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.
- 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.
- 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. - 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. - The
debug
command, which did not offer additional functionality, has been removed. - Terraform 0.14 will add support
terraform login
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 executingcd
before Terraform run. - There are two new functions,
alltrue
andanytrue
, which serve as a sort of dynamic version of the&&
and||
or operators respectively. You can use this with afor
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.
We offer hands-on AWS training as part of our SaaS Growth subscription, to help your team make the best use of the AWS cloud. Book a free chat to find out more.
For some topics, you can also get the same training just on the topic you need - see our Terraform training and Kubernetes training pages.
This blog is written exclusively by The Scale Factory team. We do not accept external contributions.