Using Terraform’s S3 backend with Garage, a self-hosted S3-compatible object store.
AWS CLI profile#
Configure a named AWS profile pointing to the Garage endpoint. Use credential_process to avoid storing secrets on disk — see AWS CLI for details.
# ~/.aws/config
[profile terraform]
services = terraform
credential_process = sh -c 'echo "{\"Version\":1,\"AccessKeyId\":\"$AWS_TF_ACCESS_KEY_ID\",\"SecretAccessKey\":\"$AWS_TF_SECRET_ACCESS_KEY\",\"SessionToken\":\"\"}"'
[services terraform]
s3 =
endpoint_url = https://garage.example.comBackend configuration#
terraform {
backend "s3" {
profile = "terraform"
bucket = "tf-bucket"
# Garage uses path-style URLs (`host/bucket/key`) not virtual-hosted
use_path_style = true
# Native S3 locking (Terraform 1.10+), no DynamoDB needed
use_lockfile = true
key = "project/env/component/terraform.tfstate"
# Skips AWS STS `GetCallerIdentity`, unavailable on Garage
skip_credentials_validation = true
# Skips AWS account ID lookup, not applicable to self-hosted S3
skip_requesting_account_id = true
}
}Reading remote state from another module#
Use terraform_remote_state to consume outputs from a different root module. The config block mirrors the backend configuration of the target module.
data "terraform_remote_state" "example" {
backend = "s3"
config = {
profile = "terraform"
bucket = "tf-bucket"
use_path_style = true
use_lockfile = true
key = "project/env/component/terraform.tfstate"
skip_credentials_validation = true
skip_requesting_account_id = true
}
}