digitalboard.core/roles/garage
Simon Bärlocher 3236ca332f
docs(collection): document all roles and fix metadata drift
Replace ansible-galaxy init placeholders across the collection and
correct documentation that drifted from the code, after a multi-agent
review of every role README against its defaults, tasks and templates.

Collection level:
- README: role table for all 16 roles, requirements and role-ordering
- galaxy.yml: declare community.docker and community.general deps,
  real description/tags/urls; normalize license to MIT-0
- meta/runtime.yml: requires_ansible '>=2.15.0'
- plugins/README: document the homarr_layout filter and
  garage_credentials lookup instead of scaffold boilerplate

Per-role meta/main.yml and README for the placeholder roles
(389ds, authentik, authentik_outpost_ldap, base, collabora, drawio,
garage, homarr, httpbin, keycloak, nextcloud, opencloud, traefik).

Correctness fixes found during review:
- keycloak: wrong domain default, drop invented keycloak_cert_resolver,
  document the provisioning feature
- garage: root_domain is .s3.<first-entry>, not the bare domain
- opnform: jwt/front_api secrets use `openssl rand -hex 32`; align the
  validation fail_msg in tasks/main.yml accordingly
- send: S3 example references garage_s3_domains[0] (was singular)
- opencloud: document required opencloud_wopi_domain

License normalized to MIT-0 across galaxy.yml, role meta and READMEs to
match the SPDX headers.
2026-05-27 23:12:24 +02:00
..
defaults docs(collection): document all roles and fix metadata drift 2026-05-27 23:12:24 +02:00
handlers feat: add basic garage s3 storage role 2025-11-07 17:35:32 +01:00
meta docs(collection): document all roles and fix metadata drift 2026-05-27 23:12:24 +02:00
tasks fix(garage): make bootstrap & provision idempotent across reruns 2026-05-27 23:12:23 +02:00
templates feat(drawio,garage): optional Authentik ForwardAuth in front of UIs 2026-05-27 23:12:23 +02:00
tests feat: add basic garage s3 storage role 2025-11-07 17:35:32 +01:00
vars feat: add basic garage s3 storage role 2025-11-07 17:35:32 +01:00
README.md docs(collection): document all roles and fix metadata drift 2026-05-27 23:12:24 +02:00

Garage

Ansible role to deploy Garage S3-compatible object storage via Docker Compose, with declarative key/bucket provisioning and an optional WebUI behind htpasswd or authentik ForwardAuth.

Requirements

  • Docker and Docker Compose installed on the target host
  • Ansible collection: community.docker
  • htpasswd (from apache2-utils / httpd-tools) when the WebUI is enabled and authentik ForwardAuth is not used
  • Traefik with a shared garage_traefik_network (default proxy)

Role variables

Full spec with types and defaults: meta/argument_specs.yml. The most common overrides:

Service

  • garage_s3_domains: FQDNs the S3 router accepts. The first entry is the canonical hostname; garage.toml derives the virtual-hosted-style S3 root_domain from it as .s3.<first-entry> (so buckets resolve under <bucket>.s3.<first-entry>).
  • garage_web_domain, garage_webui_domain: separate hostnames for the S3-website endpoint and the console.
  • garage_image, garage_replication_factor, garage_db_engine, garage_s3_region.

Required secrets

Generate with openssl rand -hex 32 (32 bytes / 64 hex chars):

  • garage_rpc_secret: node-to-node RPC secret
  • garage_admin_token: admin API token
  • garage_metrics_token: metrics endpoint token

WebUI authentication

Three modes:

  1. htpasswd (default): garage_webui_username / garage_webui_password in plaintext. The role hashes the password with htpasswd -nbBC 10, persists the hash on disk, and re-verifies with htpasswd -vbB so unchanged passwords don't churn the play.
  2. authentik ForwardAuth: set garage_webui_authentik_forward_auth: true and garage_webui_authentik_forward_auth_url: "https://auth.example.com/outpost.goauthentik.io/auth/traefik". AUTH_USER_PASS is dropped from the container env so authentik is the only gate.
  3. Disabled: garage_webui_enabled: false.

Layout bootstrap

Setting garage_bootstrap_enabled: true runs the bootstrap task, which joins the local node to the layout (zone: garage_bootstrap_zone, capacity: garage_bootstrap_capacity) on the first run. The check tolerates the 16-char truncation that garage layout show performs.

Declarative S3 keys and buckets

garage_s3_keys:
  - name: nextcloud
    buckets:
      - name: nextcloud-data
        permissions: [read, write]
  - name: backup
    buckets:
      - name: restic-prod
        permissions: [read, write, owner]

The role:

  • Lists existing keys (garage key list), creates missing ones
  • Lists existing buckets (garage bucket list), creates missing ones
  • Reads current permissions via garage bucket info and runs garage bucket allow only when the current RWO flags for the key don't already match the desired permissions

stdout parsing is hardened against ANSI escapes and interleaved INFO log lines, so probe noise no longer produces spurious changes.

Dependencies

  • Traefik network (garage_traefik_network, default proxy)
  • Internal network (garage_internal_network, default internal)

Example playbook

- hosts: storage_servers
  roles:
    - role: digitalboard.core.garage
      vars:
        garage_s3_domains:
          - "storage.example.com"
          - "storage.int.example.com"
        garage_rpc_secret: "{{ vault_garage_rpc_secret }}"
        garage_admin_token: "{{ vault_garage_admin_token }}"
        garage_metrics_token: "{{ vault_garage_metrics_token }}"
        garage_bootstrap_enabled: true
        garage_webui_authentik_forward_auth: true
        garage_webui_authentik_forward_auth_url: "https://auth.example.com/outpost.goauthentik.io/auth/traefik"
        garage_s3_keys:
          - name: nextcloud
            buckets:
              - name: nextcloud-data
                permissions: [read, write]

License

MIT-0