A Terraform configuration can specify a backend, which is where state data files can be stored.
To configure a backend, add a nested backend block within the top-level terraform block. A standard backend will only be used to store the configuration state, but an enhanced backed will also be able to perform operations over your configuration.
If a configuration includes no backend block, Terraform defaults to using the local backend, which stores state as a plain file in the current working directory.
terraform {
# A standard backend created to use an AWS S3 storage bucket
# The backup of your configuration statefile will be stored locally
backend "s3" {
bucket = "example-bucket"
key = "tf-infra/terraform.tfstate"
region = "us-east-1"
}
# If using Terraform Cloud a `cloud` block is created
cloud {
hostname = "app.terraform.io"
organization = "company"
workspaces {
tags = ["app"]
}
}
}
Running terraform init
with the -backend-config
flag can be used for partial
backend configuration.
terraform init -backend-config=backend.hcl
Running the above command tells terraform to use the configuration stored in
backend.hcl
to fill out the configuration value for the backend
block in main.tf
.
# main.tf
terraform {
required_version = ">= 1.2.0"
backend "remote" {}
}
# backend.hcl
workspaces = { name = "workspace" }
hostname = "app.terraform.io"
origanization = "company"
Using the terraform_remote_state
data source will retrieve and use the root
module output values from another Terraform configuration, using the latest state
snapshot from the remote backend.
terraform_remote_state
only exposes output values which often include sensitive
information. It is recommended to explicitly push data for external consumption
to a separate location instead of access it via remote state.
data "aws_s3_bucket" "staging" {
bucket = "bucket.staging.com"
}
resource "aws_instance" "web" {
subnet_id = "${data.aws_s3_bucket.staging.subnet_id}"
}
State locking is done automatically for all operations that could write state. Preventing others from from acquiring the lockfile and potentially corrupting it.
Terraform does not notify if a lock is complete, if the operation takes longer than expected, it will output a status message.
Terraform has a force-unlock
command to manually unlock state if doing so fails.
If you unlock the state when someone else is holding the lock it could cause downstream
issues as multiple writers will be created.
terraform force-unlock LOCK_ID
The value for LOCK_ID
is available only if an attempt to unlock state has failed
previously.
A statefile can contain sensitive data and is a possible attack vector for malicious actors.
When using a local backend, state is store in plan-text JSON (.json
) files:
git
repositoryA benefit to using Terraform Cloud is it has built-in guarantees for securing information about the statefile
You can store state with Third-Party backends (i.e. S3), but you should vet your choices’ capabilities and determine if it will meet your standards for security and compliance.
Given the example of using S3, you would need to ensure that encryption and versioning are turned on and create a custom trail for data events.
When executing a remote plan or apply in a CLI-driven run, an archive of your
configuration directory is uploaded to Terraform Cloud. You can define paths to
ignore with .terraformignore
file at the root of you configuration directory.
If the file is not present, the archive will exclude only the .git/
and
.terraform/
directories.
# Local .terraform directories
**/.terraform/*
# .tfstate files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
crash.*.log
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
*.tfvars
*.tfvars.json
# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# Include override files you do wish to add to version control using negated pattern
# !example_override.tf
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*
# Ignore CLI configuration files
.terraformrc
terraform.rc