Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

An S3 backend does not make Terraform state safe by itself. Before you run Terraform, verify the exact bucket, region, object key and workspace path; enable and test locking; grant IAM access to both state and lock objects; keep credentials out of backend configuration; enable recovery controls; and treat every backend change as a state migration.

1. Confirm the exact S3 object Terraform will use

The S3 backend requires a bucket, key and AWS region. Terraform stores state as an S3 object at that key, so a typo can make an operator inspect, lock or update a different state file from the one intended.

Default workspace

In the default workspace, Terraform uses the configured key unchanged. With this configuration:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
terraform {
  backend "s3" {
    bucket = "company-terraform-state"
    key    = "network/terraform.tfstate"
    region = "us-east-1"
  }
}

the state object is s3://company-terraform-state/network/terraform.tfstate.

Named workspaces

Other workspaces use the pattern <workspace_key_prefix>/<workspace_name>/<key>. The default workspace prefix is env:. If the key above is used with a workspace named staging, the resulting object path is:

s3://company-terraform-state/env:/staging/network/terraform.tfstate

That path is easy to overlook because the configured key is not the complete path for a named workspace. A policy, backup job or incident response procedure that covers only network/terraform.tfstate will miss the workspace objects.

Pre-run path checklist

  • Check the bucket name and AWS account in which it exists.
  • Check the region in the backend block against the bucket’s actual region.
  • Check the configured key character for character, including prefixes and file extension.
  • Run terraform workspace show and confirm that it is the workspace you intend to change.
  • Resolve the full object path for that workspace before inspecting or editing IAM rules.
  • Do not treat workspace names as security boundaries. Use S3 object-path permissions when different teams need different access.

Document the resulting path for each production workspace. This prevents an operator from running a command in a similarly named workspace or account and believing that the expected state was changed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

2. Do not assume S3 state locking is enabled

S3 locking is opt-in. Set use_lockfile = true in the backend configuration when you want Terraform to create a lock object alongside the state:

terraform {
  backend "s3" {
    bucket         = "company-terraform-state"
    key            = "network/terraform.tfstate"
    region         = "us-east-1"
    use_lockfile   = true
  }
}

For a state key ending in network/terraform.tfstate, the lock object is network/terraform.tfstate.tflock. For a named workspace, the lock file follows that workspace’s expanded path.

Locking behavior and failed runs

Terraform-supported backends lock automatically for operations that could write state. If Terraform cannot acquire the lock, the operation stops rather than proceeding concurrently. This protects against two applies overwriting each other’s state, but only when the backend’s locking mechanism is configured and its permissions are correct.

Do not use -lock=false as a routine workaround. It removes the protection precisely when concurrent operators or automation are most likely to cause corruption.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

DynamoDB migration details

The current S3 backend documentation marks DynamoDB locking arguments as deprecated. Both DynamoDB settings and use_lockfile may appear temporarily when migrating from an older Terraform setup, but new configurations should follow the documented S3 lockfile mechanism and a planned removal path for the deprecated settings.

When force-unlock is appropriate

Use terraform force-unlock only when an operation failed after creating a lock and automatic unlocking did not complete. Confirm that the lock belongs to your failed operation and that no apply or plan is still running. Removing another operator’s lock can permit two writers to proceed at once.

3. Align IAM with every state and lock object

A default-workspace policy is not automatically sufficient for a workspace-based design. The documented minimum for a default-only state consists of:

Resource Required S3 actions Purpose
State bucket s3:ListBucket Allow Terraform to list the bucket as required by the backend.
Default state object s3:GetObject, s3:PutObject Read the current state and write the new state.
State lock object s3:GetObject, s3:PutObject, s3:DeleteObject Read, create/update and remove the .tflock object.

Terraform does not require s3:DeleteObject on the default state file in this documented case because it does not delete that file. A lockfile is different: removing the lock after a successful operation requires delete permission on the lock object.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Workspace-aware policies

For workspaces, grant access to the expanded object prefixes, not just the literal backend key. A policy may need to list the relevant prefix and read or write each workspace state object. Non-default workspace operations can also require deleting a workspace state object, so include that action where the lifecycle and Terraform operation require it. Apply the same precision to every corresponding .tflock object.

Use resource ARNs and s3:prefix conditions to limit access to the required bucket paths. Include the lockfile prefix in those conditions; otherwise Terraform may be able to read state but fail to lock, or lock one path while the policy protects another.

Separate administration from environment access when needed

Organizations with stronger account boundaries can keep state administration in one account and assume roles into target environment accounts. This is an optional isolation pattern, not a prerequisite for every deployment. If you use it, test the complete role chain: the principal that runs Terraform needs permission to access the state bucket and to assume the target role, while the target role needs the infrastructure permissions for the plan.

4. Keep credentials and secrets out of backend configuration

Do not hardcode AWS access keys, secret keys or other sensitive values in the backend block. HashiCorp warns that values supplied with -backend-config or embedded in configuration can be persisted in the .terraform directory and plan files.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use standard credential sources

Prefer environment variables and the AWS SDK’s standard credential chain, such as an approved profile, workload identity, instance role, container role or CI-provided short-lived credentials. Keep the backend block limited to non-secret settings such as bucket, key and region whenever possible.

After initialization, inspect local metadata and generated plans for credentials or tokens. Add .terraform/, state copies and plan artifacts to the appropriate ignore rules, and do not commit them to source control. If a credential was written into a plan, cache or log, rotate it rather than assuming that deleting the file removed every copy.

5. Protect the confidentiality and recoverability of state

Terraform state is operational data, not merely a cache. It can contain resource identifiers, connection details and values marked sensitive by a provider. Anyone who can read the object may learn information that is useful for changing infrastructure or accessing systems.

Enable versioning for recovery

HashiCorp’s S3 backend reference states: “It is highly recommended that you enable Bucket Versioning on the S3 bucket to allow for state recovery in the case of accidental deletions and human error.” Enable versioning before production use and make sure the people responsible for recovery know how to identify and restore a prior object version.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Versioning is a recovery control, not a permission model. Restrict who can read current and previous versions, and account for their retention and deletion permissions in your security design.

Use encryption with the required permissions

The backend supports the encrypt option for server-side encryption. If you use a customer-managed KMS key, the Terraform identity also needs the documented KMS permissions, including kms:Encrypt, kms:Decrypt and kms:GenerateDataKey. A successful S3 policy with a missing KMS grant will still produce access errors.

Encryption at rest does not replace least-privilege access, credential hygiene or monitoring. Combine it with S3 access controls and audit logging so reads, writes, deletes and permission changes can be investigated.

Check the bucket before the first apply

  • Versioning is enabled and recovery ownership is assigned.
  • Public access is blocked and bucket policies do not grant unintended principals access.
  • Encryption settings match the organization’s requirements.
  • Audit logs cover object access and administrative changes.
  • Lifecycle rules do not expire the current state or historical versions before the recovery period ends.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

6. Treat backend edits as state operations

Changing a bucket, key, region, workspace prefix, locking method or encryption setting changes where Terraform expects state. Terraform requires another terraform init before plans, applies or state commands after backend configuration changes.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Safe reconfiguration sequence

  1. Record the current bucket, key, region, locking settings and every workspace in use.
  2. Back up the current state before changing the backend. Keep the backup in a protected location and label which workspace it belongs to.
  3. Update the backend configuration and run terraform init.
  4. Read Terraform’s migration prompt carefully. It may offer to copy state and can migrate multiple workspaces.
  5. Approve migration only after confirming the source and destination accounts, buckets, keys and permissions.
  6. For each workspace, verify that the destination object exists and represents the expected state before running a plan.
  7. Keep the old copy until the migration has been reviewed and the recovery process is known to work.

Initialization is not a harmless syntax check: an incorrect answer to the migration prompt can place state in an unintended object or leave workspaces split between locations.

Moving to a managed multi-user workflow

When migrating workspaces from S3 to HCP Terraform, change the backend configuration and initialize to migrate state as described in HashiCorp’s tutorial. Coordinate the move with everyone using those workspaces. Stop active runs, or wait for them to finish, before moving a workspace into a multi-user environment; otherwise an old runner can write state after the migration has begun.

7. A pre-run review you can automate

Use this review before a production plan or apply:

  1. Identity: confirm the AWS account, role or profile and the intended Terraform workspace.
  2. Location: derive the full S3 object path from bucket, region, key and workspace prefix.
  3. Locking: confirm use_lockfile = true, locate the matching .tflock path and verify lock permissions.
  4. Authorization: test list, read and write access to the exact state path; test lock read, write and delete access separately.
  5. Secrets: check that no credentials appear in backend arguments, .terraform metadata, plans or logs.
  6. Recovery: confirm versioning, encryption, KMS grants where applicable, audit logs and a tested restoration owner.
  7. Change control: if any backend value changed, back up state, initialize, review migration, and verify every workspace.

These checks address the failure modes that cause the most expensive surprises: operating on the wrong object, allowing concurrent writers, denying Terraform access to its lock, exposing credentials, losing historical state, or migrating only part of a workspace set.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.