- Go 94.3%
- Makefile 5.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .github/workflows | ||
| docs | ||
| .gitignore | ||
| .goreleaser.yml | ||
| capacity.go | ||
| capacity_test.go | ||
| CHANGELOG.md | ||
| client.go | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| main.go | ||
| Makefile | ||
| provider.go | ||
| PUBLISHING.md | ||
| README.md | ||
| renovate.json5 | ||
| resource_garage_admin_token.go | ||
| resource_garage_bucket.go | ||
| resource_garage_bucket_key.go | ||
| resource_garage_cluster_layout.go | ||
| resource_garage_key.go | ||
| terraform-registry-manifest.json | ||
Terraform Provider for Garage
A Terraform provider for Garage object storage using the Admin API v2.
Requirements
- Garage v2.x - This provider uses Garage Admin API v2
- Terraform >= 1.0
- Go >= 1.24 (to build from source)
Resources
| Resource | Description |
|---|---|
garage_key |
Manage S3 access keys |
garage_bucket |
Create buckets with lifecycle policies |
garage_bucket_key |
Manage bucket permissions |
garage_admin_token |
Scoped admin API tokens |
garage_cluster_layout |
Cluster topology management |
Quick Start
terraform {
required_providers {
garage = {
source = "arsolitt/garagehq"
version = ">= 0.0.1"
}
}
}
provider "garage" {
host = "127.0.0.1:3903"
scheme = "http"
token = var.garage_token
}
resource "garage_bucket" "example" {
global_alias = "my-bucket"
}
resource "garage_key" "example" {
name = "my-app-key"
}
resource "garage_bucket_key" "example" {
bucket_id = garage_bucket.example.id
access_key_id = garage_key.example.access_key_id
read = true
write = true
owner = false
}
Examples
Loki Stack
Complete setup for Grafana Loki:
resource "garage_key" "loki" {
name = "loki-storage"
}
resource "garage_bucket" "loki_chunks" {
global_alias = "loki-chunks"
expiration_days = 14
}
resource "garage_bucket" "loki_ruler" {
global_alias = "loki-ruler"
expiration_days = 30
}
resource "garage_bucket" "loki_admin" {
global_alias = "loki-admin"
}
resource "garage_bucket_key" "loki_chunks" {
bucket_id = garage_bucket.loki_chunks.id
access_key_id = garage_key.loki.access_key_id
read = true
write = true
owner = false
}
resource "garage_bucket_key" "loki_ruler" {
bucket_id = garage_bucket.loki_ruler.id
access_key_id = garage_key.loki.access_key_id
read = true
write = true
owner = false
}
resource "garage_bucket_key" "loki_admin" {
bucket_id = garage_bucket.loki_admin.id
access_key_id = garage_key.loki.access_key_id
read = true
write = true
owner = true
}
Backup Retention Policy
Different retention for different backup types:
resource "garage_key" "backup" {
name = "backup-service"
}
resource "garage_bucket" "daily" {
global_alias = "daily-backups"
expiration_days = 7
}
resource "garage_bucket" "weekly" {
global_alias = "weekly-backups"
expiration_days = 30
}
resource "garage_bucket" "monthly" {
global_alias = "monthly-backups"
expiration_days = 365
}
resource "garage_bucket_key" "backup" {
for_each = {
daily = garage_bucket.daily.id
weekly = garage_bucket.weekly.id
monthly = garage_bucket.monthly.id
}
bucket_id = each.value
access_key_id = garage_key.backup.access_key_id
read = true
write = true
owner = false
}
Read-Only Access for CDN
resource "garage_bucket" "cdn_assets" {
global_alias = "cdn-assets"
}
resource "garage_key" "cdn_reader" {
name = "cdn-pull-only"
}
resource "garage_bucket_key" "cdn_readonly" {
bucket_id = garage_bucket.cdn_assets.id
access_key_id = garage_key.cdn_reader.access_key_id
read = true
write = false
owner = false
}
Scoped Admin Token for Monitoring
resource "garage_admin_token" "prometheus" {
name = "prometheus-monitoring"
scope = [
"GetClusterStatus",
"GetClusterHealth"
]
never_expires = true
}
Single Node Development Cluster
variable "node_id" {
type = string
}
resource "garage_cluster_layout" "dev" {
roles {
id = var.node_id
zone = "local"
capacity = "10G"
tags = ["dev", "standalone"]
}
}
Multi-Node Production Cluster
resource "garage_cluster_layout" "production" {
roles {
id = "node-dc1-a"
zone = "datacenter-1"
capacity = "2T"
tags = ["storage", "ssd", "primary"]
}
roles {
id = "node-dc1-b"
zone = "datacenter-1"
capacity = "2T"
tags = ["storage", "ssd", "primary"]
}
roles {
id = "node-dc2-a"
zone = "datacenter-2"
capacity = "2T"
tags = ["storage", "ssd", "secondary"]
}
# Gateway for edge traffic
roles {
id = "gateway-edge"
zone = "datacenter-1"
tags = ["gateway", "edge"]
# No capacity = gateway mode
}
}
Provider Configuration
Static Credentials
provider "garage" {
host = "garage.example.com:3903"
scheme = "https"
token = "your-admin-token"
}
Environment Variables
variable "garage_host" {
default = ""
description = "Override Garage host"
}
variable "garage_token" {
default = ""
sensitive = true
description = "Override Garage admin token"
}
provider "garage" {
host = coalesce(var.garage_host, env.GARAGE_HOST, "127.0.0.1:3903")
scheme = coalesce(env.GARAGE_SCHEME, "http")
token = coalesce(var.garage_token, env.GARAGE_TOKEN)
}
Supported environment variables:
GARAGE_HOST- Admin API host:portGARAGE_SCHEME- http or httpsGARAGE_TOKEN- Admin token
Building from Source
git clone https://github.com/arsolitt/terraform-provider-garagehq
cd terraform-provider-garage
make build
Local Installation
For local development and testing:
make install
This installs the provider to your local Terraform plugin directory.
Development
make build # Build the provider
make test # Run tests with coverage
make lint # Format and lint code
make clean # Clean build artifacts
Documentation
- Provider Documentation
- Getting Started Guide
- Bucket Lifecycle Policies
- Admin Token Management
- Cluster Management
Releasing
This project uses automated releases via GitHub Actions:
- Merge PRs with conventional commit messages
- Release Please creates a release PR
- Merge the release PR to trigger a new release
- GoReleaser builds and publishes binaries
See PUBLISHING.md for details.
Troubleshooting
Connection Refused
Ensure Garage is running and the admin API is accessible:
curl -H "Authorization: Bearer $TOKEN" http://localhost:3903/v2/GetClusterHealth
Permission Denied
Verify your admin token has the required permissions. Some operations require specific scopes.
Secret Key Not Available
The secret_access_key is only available on initial creation. If you need to recover it, you'll need to recreate the key.
Lifecycle Policy Not Working
Ensure the S3 API is accessible (default port 3900). The provider uses the S3 API for lifecycle configuration, not the admin API.
License
MIT License - see LICENSE for details.