This is a Terraform provider for managing Garage S3 buckets via the Garage Admin API.
Garage is an S3-compatible distributed object storage service designed for self-hosting at a small-to-medium scale. This provider allows you to manage Garage buckets declaratively using Terraform.
- Requirements
- Quick Start
- Using the Provider
- Resources
- Data Sources
- Examples
- Troubleshooting
- Developing the Provider
- About Garage
# Clone the repository
git clone <your-repo-url>
cd terraform-provider-garage
# Build the provider
go build -o terraform-provider-garageFor local development, use Terraform's development overrides.
Create or edit ~/.terraformrc:
provider_installation {
dev_overrides {
"jkossis/garage" = "/path/to/terraform-provider-garage"
}
direct {}
}Replace /path/to/terraform-provider-garage with the actual path to your repository directory.
Set your Garage endpoint and token:
export GARAGE_ENDPOINT="http://localhost:3903"
export GARAGE_TOKEN="your-admin-token-here"Create a file named main.tf:
terraform {
required_providers {
garage = {
source = "jkossis/garage"
}
}
}
provider "garage" {
# endpoint and token will be read from environment variables
}
resource "garage_bucket" "example" {
global_alias = "my-first-bucket"
}
output "bucket_id" {
value = garage_bucket.example.id
}# Initialize Terraform
terraform init
# Plan the changes
terraform plan
# Apply the configuration
terraform apply
# When you're done, destroy the resources
terraform destroyThe provider requires two configuration values:
endpoint- The URL of your Garage Admin API endpoint (default port: 3903)token- Your Garage admin API bearer token
These can be configured in three ways:
provider "garage" {
endpoint = "http://localhost:3903"
token = "your-admin-token-here"
}export GARAGE_ENDPOINT="http://localhost:3903"
export GARAGE_TOKEN="your-admin-token-here"provider "garage" {
endpoint = "http://localhost:3903"
# token will be read from GARAGE_TOKEN environment variable
}Manages a Garage S3 bucket.
Example Usage:
# Basic bucket
resource "garage_bucket" "example" {
global_alias = "my-bucket"
}
# Bucket with website hosting
resource "garage_bucket" "website" {
global_alias = "my-website"
website_enabled = true
website_index_document = "index.html"
website_error_document = "error.html"
}
# Bucket with quotas
resource "garage_bucket" "limited" {
global_alias = "limited-bucket"
max_size = 1073741824 # 1 GB in bytes
max_objects = 10000
}Schema:
global_alias(Required, String) - The global alias (name) for the bucket. Changing this forces a new resource.website_enabled(Optional, Bool) - Enable website hosting for this bucket. Default:falsewebsite_index_document(Optional, String) - The index document for website hosting (e.g., 'index.html')website_error_document(Optional, String) - The error document for website hosting (e.g., 'error.html')max_size(Optional, Int64) - Maximum size of the bucket in bytes. Leave unset for unlimited.max_objects(Optional, Int64) - Maximum number of objects in the bucket. Leave unset for unlimited.
Computed Attributes:
id(String) - The unique identifier of the bucket
Manages a Garage access key for S3 API authentication.
Example Usage:
# Create an auto-generated access key
resource "garage_key" "app" {
name = "my-application"
}
# Import a key with predefined credentials
resource "garage_key" "imported" {
id = "GK31c2f218a2e44f485b94239e"
secret_access_key = "7d37d093435a75809f8f090b072de87928d1c355db9d9340431b28e776374705"
name = "imported-key"
}
# Output credentials (use caution with secrets!)
output "access_key_id" {
value = garage_key.app.id
}
output "secret_access_key" {
value = garage_key.app.secret_access_key
sensitive = true
}Schema:
id(Optional, String) - The access key ID. If provided along withsecret_access_key, the key will be imported with predefined credentials. If not provided, one will be generated. Changing this forces a new resource.name(Optional, String) - A human-friendly name for the access keysecret_access_key(Optional, String, Sensitive) - The secret access key. If provided along withid, the key will be imported with predefined credentials. If not provided, one will be generated. Changing this forces a new resource.
Computed Attributes:
id(String) - The access key ID (computed when not provided)secret_access_key(String, Sensitive) - The secret access key (computed when not provided, only available on creation)
Important Notes:
- Importing Keys: To import a key with predefined credentials, both
idandsecret_access_keymust be provided together. Providing only one will result in an error. - Auto-generation: When neither
idnorsecret_access_keyare provided, Garage will automatically generate both values. - Secret Availability: The secret access key is only returned when the key is created. It's not available via the API after creation, so it won't be populated when using Terraform's
importcommand to import an existing key. - Immutability: Both
idandsecret_access_keyare immutable. Changing either value will force the creation of a new resource.
Manages permissions for an access key on a bucket.
Example Usage:
# Create bucket and key
resource "garage_bucket" "data" {
global_alias = "app-data"
}
resource "garage_key" "app" {
name = "application-key"
}
# Grant read/write permissions
resource "garage_bucket_permission" "app_access" {
bucket_id = garage_bucket.data.id
access_key_id = garage_key.app.id
read = true
write = true
owner = false
}
# Read-only access for another key
resource "garage_key" "readonly" {
name = "readonly-key"
}
resource "garage_bucket_permission" "readonly_access" {
bucket_id = garage_bucket.data.id
access_key_id = garage_key.readonly.id
read = true
write = false
owner = false
}Schema:
bucket_id(Required, String) - The ID of the bucket. Changing this forces a new resource.access_key_id(Required, String) - The ID of the access key. Changing this forces a new resource.read(Optional, Bool) - Grant read permission. Default:falsewrite(Optional, Bool) - Grant write permission. Default:falseowner(Optional, Bool) - Grant owner permission. Default:false
Computed Attributes:
id(String) - The unique identifier (format:bucket_id/access_key_id)
Permission Types:
- Read: List objects, download objects, read metadata
- Write: Upload objects, delete objects, modify metadata
- Owner: All read/write operations plus bucket management and permission grants
Retrieves information about an existing Garage bucket.
Example Usage:
# Look up bucket by global alias
data "garage_bucket" "example" {
global_alias = "my-bucket"
}
# Look up bucket by ID
data "garage_bucket" "by_id" {
id = "8d7c3c6e-7b9d-4c3a-9f2e-1a5b6c7d8e9f"
}
# Use data source output
output "bucket_info" {
value = {
id = data.garage_bucket.example.id
objects = data.garage_bucket.example.objects
bytes = data.garage_bucket.example.bytes
}
}Schema:
Either id or global_alias must be specified.
id(Optional, String) - The unique identifier of the bucketglobal_alias(Optional, String) - The primary global alias (name) of the bucket
Computed Attributes:
id(String) - The unique identifier of the bucketglobal_alias(String) - The primary global alias of the bucketglobal_aliases(List of String) - All global aliases for this bucketwebsite_enabled(Bool) - Whether website hosting is enabledwebsite_index_document(String) - The index document for website hostingwebsite_error_document(String) - The error document for website hostingmax_size(Int64) - Maximum size of the bucket in bytesmax_objects(Int64) - Maximum number of objects in the bucketobjects(Int64) - Current number of objects in the bucketbytes(Int64) - Current size of the bucket in bytesunfinished_uploads(Int64) - Number of unfinished multipart uploads
Check out the examples directory for more configurations:
- Basic Provider Configuration
- Bucket Resource Examples
- Access Key Resource Examples
- Bucket Permission Resource Examples
- Bucket Data Source Examples
If you see an error like "provider registry.terraform.io/jkossis/garage not found", make sure:
- You've set up the dev overrides in
~/.terraformrccorrectly - The path in dev overrides points to the directory containing the built binary
- You've built the provider binary (
go build -o terraform-provider-garage)
If you see connection errors:
- Verify your Garage instance is running and accessible
- Check that the endpoint URL is correct (including protocol and port)
- Verify your admin token is valid
- Check Garage logs for any API errors
This provider requires Garage Admin API v2. If you're using an older version of Garage:
- Upgrade to Garage >= 0.9.0
- Update your Garage configuration to enable API v2
- Regenerate your admin tokens if needed
If you wish to work on the provider, you'll first need Go installed on your machine (see Requirements above).
To compile the provider, run go install. This will build the provider and put the provider binary in the $GOPATH/bin directory.
To generate or update documentation, run go generate.
To run the full suite of acceptance tests, you'll need a running Garage instance with Admin API v2 enabled.
Set up your test environment:
export GARAGE_ENDPOINT="http://localhost:3903"
export GARAGE_TOKEN="your-test-admin-token"Then run the tests:
make testaccThis provider is published under the MPL-2.0 license.
Garage is an S3-compatible distributed object storage service designed for self-hosting at a small-to-medium scale. It's lightweight, easy to operate, and supports geo-distributed deployments.
For more information about Garage: