Pull-mirror of the OpenTofu provider for Garage. Upstream: Arsolitt/terraform-provider-garagehq (MIT)
  • Go 94.3%
  • Makefile 5.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-30 21:40:55 +03:00
.github/workflows ci: pin trivy-action to existing v-prefixed tag 2026-08-27 23:51:16 +03:00
docs feat(cluster_layout): accept capacity as string with unit suffixes 2026-02-20 17:47:30 +03:00
.gitignore chore: update provider configuration 2026-02-20 17:47:30 +03:00
.goreleaser.yml chore: update provider configuration 2026-02-20 17:47:30 +03:00
capacity.go feat(cluster_layout): accept capacity as string with unit suffixes 2026-02-20 17:47:30 +03:00
capacity_test.go feat(cluster_layout): accept capacity as string with unit suffixes 2026-02-20 17:47:30 +03:00
CHANGELOG.md chore(main): release 1.1.2 2026-08-30 09:50:36 +03:00
client.go style: apply gofmt to client.go and provider.go 2026-08-27 23:50:43 +03:00
go.mod fix(deps): update garage-admin-sdk-golang for Garage v2.3.0 routingRules 2026-08-28 10:31:45 +02:00
go.sum fix(deps): update garage-admin-sdk-golang for Garage v2.3.0 routingRules 2026-08-28 10:31:45 +02:00
LICENSE fix: lint 2025-11-17 08:51:39 +00:00
main.go chore: apply code formatting changes 2025-11-20 10:43:26 +00:00
Makefile chore: update provider configuration 2026-02-20 17:47:30 +03:00
provider.go style: apply gofmt to client.go and provider.go 2026-08-27 23:50:43 +03:00
PUBLISHING.md docs(publishing): update GPG key requirements and remove fingerprint instructions 2026-02-20 12:34:35 +03:00
README.md feat(cluster_layout): accept capacity as string with unit suffixes 2026-02-20 17:47:30 +03:00
renovate.json5 chore: update renovate config to use best-practices preset 2026-01-10 09:08:29 +00:00
resource_garage_admin_token.go feat: add garage_admin_token resource 2026-02-20 10:40:30 +03:00
resource_garage_bucket.go fix(bucket): avoid nil-deref panic in lifecycle helpers (#4) 2026-08-28 00:00:07 +03:00
resource_garage_bucket_key.go refactor(bucket-key): migrate to api v2 2026-02-20 10:40:30 +03:00
resource_garage_cluster_layout.go feat(cluster_layout): accept capacity as string with unit suffixes 2026-02-20 17:47:30 +03:00
resource_garage_key.go refactor(client)!: migrate to garage admin api v2 2026-02-20 10:40:30 +03:00
terraform-registry-manifest.json fix: correct protocol version in manifest to 5.0 only 2025-11-20 21:58:08 +00:00

Terraform Provider for Garage

A Terraform provider for Garage object storage using the Admin API v2.

CI Go Report Card

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:port
  • GARAGE_SCHEME - http or https
  • GARAGE_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

Releasing

This project uses automated releases via GitHub Actions:

  1. Merge PRs with conventional commit messages
  2. Release Please creates a release PR
  3. Merge the release PR to trigger a new release
  4. 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.