From 6d25a6074b264585f392caee4ab2ea00d16adb6c Mon Sep 17 00:00:00 2001 From: Dominik Polakovics Date: Fri, 24 Apr 2026 21:15:32 +0200 Subject: [PATCH] feat: remove supabase --- hosts/web-arm/configuration.nix | 1 - .../modules/supabase/FUELTIDE_AUTH_SETUP.md | 215 -------- hosts/web-arm/modules/supabase/default.nix | 486 ------------------ .../web-arm/modules/supabase/env-generate.sh | 96 ---- .../modules/supabase/functions/main/index.ts | 144 ------ .../modules/supabase/kong-entrypoint.sh | 25 - hosts/web-arm/modules/supabase/kong.yml | 265 ---------- hosts/web-arm/modules/supabase/pooler.exs | 30 -- .../modules/supabase/sql/_supabase.sql | 2 - hosts/web-arm/modules/supabase/sql/jwt.sql | 4 - hosts/web-arm/modules/supabase/sql/logs.sql | 5 - hosts/web-arm/modules/supabase/sql/pooler.sql | 5 - .../web-arm/modules/supabase/sql/realtime.sql | 3 - hosts/web-arm/modules/supabase/sql/roles.sql | 6 - .../web-arm/modules/supabase/sql/webhooks.sql | 153 ------ hosts/web-arm/modules/supabase/vector.yml | 255 --------- hosts/web-arm/secrets.yaml | 120 ++--- 17 files changed, 60 insertions(+), 1755 deletions(-) delete mode 100644 hosts/web-arm/modules/supabase/FUELTIDE_AUTH_SETUP.md delete mode 100644 hosts/web-arm/modules/supabase/default.nix delete mode 100644 hosts/web-arm/modules/supabase/env-generate.sh delete mode 100644 hosts/web-arm/modules/supabase/functions/main/index.ts delete mode 100644 hosts/web-arm/modules/supabase/kong-entrypoint.sh delete mode 100644 hosts/web-arm/modules/supabase/kong.yml delete mode 100644 hosts/web-arm/modules/supabase/pooler.exs delete mode 100644 hosts/web-arm/modules/supabase/sql/_supabase.sql delete mode 100644 hosts/web-arm/modules/supabase/sql/jwt.sql delete mode 100644 hosts/web-arm/modules/supabase/sql/logs.sql delete mode 100644 hosts/web-arm/modules/supabase/sql/pooler.sql delete mode 100644 hosts/web-arm/modules/supabase/sql/realtime.sql delete mode 100644 hosts/web-arm/modules/supabase/sql/roles.sql delete mode 100644 hosts/web-arm/modules/supabase/sql/webhooks.sql delete mode 100644 hosts/web-arm/modules/supabase/vector.yml diff --git a/hosts/web-arm/configuration.nix b/hosts/web-arm/configuration.nix index 17927db..a5501ac 100644 --- a/hosts/web-arm/configuration.nix +++ b/hosts/web-arm/configuration.nix @@ -20,7 +20,6 @@ ./modules/blackbox-exporter.nix ./modules/updns.nix ./modules/atticd.nix - ./modules/supabase ./utils/modules/autoupgrade.nix ./utils/modules/promtail diff --git a/hosts/web-arm/modules/supabase/FUELTIDE_AUTH_SETUP.md b/hosts/web-arm/modules/supabase/FUELTIDE_AUTH_SETUP.md deleted file mode 100644 index 2f8b202..0000000 --- a/hosts/web-arm/modules/supabase/FUELTIDE_AUTH_SETUP.md +++ /dev/null @@ -1,215 +0,0 @@ -# Supabase auth setup: Google OAuth, Apple native sign-in (iOS), fueltide.io email - -This doc lists the **user-side steps** required to make the code changes in -this branch functional. Nothing here is performed by Nix — these are manual -actions on external services, LDAP, SOPS, and DNS. - -The Nix changes in this branch cover: - -- `hosts/web-arm/modules/supabase/default.nix` — GoTrue env for Google OAuth - (web code-exchange flow) and Apple native sign-in (iOS id_token flow, - `GOTRUE_EXTERNAL_APPLE_CLIENT_ID=io.fueltide.workout`), SMTP pointed at - `mail.cloonar.com:587`, `MAILER_AUTOCONFIRM=false`, `SITE_URL` + - `URI_ALLOW_LIST` for fueltide.io. -- `hosts/web-arm/modules/supabase/env-generate.sh` — new `auth.env` block - that pulls SMTP + Google creds from SOPS. -- `hosts/mail/modules/dkim-fueltide.nix` — installs a per-domain DKIM key - for fueltide.io into rspamd so outbound mail from `noreply@fueltide.io` is - signed. - -Apple sign-in is scoped to the **native iOS flow only**: the app uses -`AuthenticationServices` to obtain an Apple `id_token`, then calls -`supabase.auth.signInWithIdToken({ provider: 'apple', token, nonce })`. -GoTrue verifies the id_token against Apple's JWKS and checks that `aud` -matches `io.fueltide.workout`. No server-side client secret, `.p8` key, or -Services ID is needed. Android uses native Google sign-in (handled -separately) and no Apple browser flow is supported. - -Complete the six steps below **before** merging to master. Merging without -them will deploy a broken GoTrue (missing Google/SMTP creds → auth emails -fail, Google OAuth flows 500). - ---- - -## 1. LDAP service account + fueltide alias on `mail.cloonar.com` - -Mirrors the `gitea@cloonar.com` / `authelia@cloonar.com` pattern. The alias -on `noreply@fueltide.io` is what `smtpd_sender_login_maps` uses to let the -`supabase` SASL user send as that address without tripping -`reject_authenticated_sender_login_mismatch`. - -```bash -# on mail.cloonar.com -SMTP_PASS=$(openssl rand -base64 30 | tr -d '/+=' | head -c 32) -echo "SMTP_PASS (store this in SOPS, step 3): $SMTP_PASS" -CRYPT=$(mkpasswd -m sha-512 "$SMTP_PASS") - -cat > /tmp/supabase.ldif < goes into SOPS (step 3) -# public key: printed to stdout -> goes into DNS (step 4) -``` - -Wipe the temp dir once both are copied out. - -## 3. SOPS edits (two files) - -### `hosts/mail/secrets.yaml` - -```bash -nix-shell -p sops --run 'sops hosts/mail/secrets.yaml' -``` - -Add: - -```yaml -rspamd-dkim-fueltide-io-key: | - -----BEGIN PRIVATE KEY----- - - -----END PRIVATE KEY----- -``` - -### `hosts/web-arm/secrets.yaml` - -```bash -nix-shell -p sops --run 'sops hosts/web-arm/secrets.yaml' -``` - -Inside the existing `supabase-env` multiline value, append four new lines -(these are sourced as shell variables by `env-generate.sh`): - -``` -SMTP_USER=supabase@cloonar.com -SMTP_PASS= -GOOGLE_CLIENT_ID=<from step 5> -GOOGLE_SECRET=<from step 5> -``` - -## 4. DNS records for `fueltide.io` - -Add on whichever DNS provider hosts fueltide.io: - -``` -TXT @ v=spf1 mx a:mail.cloonar.com ~all -TXT default._domainkey v=DKIM1; k=rsa; p=<public key from step 2> -TXT _dmarc v=DMARC1; p=quarantine; rua=mailto:postmaster@cloonar.com; fo=1 -``` - -PTR for mail.cloonar.com is already set (it's been sending for cloonar.com). -If fueltide.io has no MX record, outbound is fine but bounces from remote MTAs -won't route — acceptable for one-way transactional mail. Add an MX pointing at -`mail.cloonar.com.` if you want bounces to be received. - -## 5. Google Cloud OAuth client (≈ 5 min) - -1. console.cloud.google.com → **APIs & Services → OAuth consent screen**. - External user type. App name `Fueltide`, user support email, developer - contact. Scopes: `openid`, `email`, `profile`. Submit (or keep in testing - if only internal users). -2. **Credentials → Create Credentials → OAuth client ID → Web application**. - Name `Supabase`. Authorised redirect URI: - `https://supabase.cloonar.com/auth/v1/callback`. -3. Copy Client ID + Client Secret → into SOPS as `GOOGLE_CLIENT_ID` and - `GOOGLE_SECRET`. - -## 6. Apple Developer — enable Sign in with Apple on the iOS App ID - -Only one action, no keys or Services IDs: - -1. developer.apple.com → **Certificates, IDs & Profiles → Identifiers → App - IDs**. Select `io.fueltide.workout` (Team `XWJ4DC7TBH`, see - `hosts/web-arm/sites/fueltide.io.nix`). Check **Sign in with Apple**. - Save. - -That's it on the Apple side. No Services ID, no Keys, no `.p8` download. -The iOS app obtains the `id_token` on-device via `AuthenticationServices` -and posts it to `supabase.auth.signInWithIdToken`; GoTrue validates it -against Apple's JWKS with `aud=io.fueltide.workout`. - -## 7. Merge and deploy - -Once steps 1–6 are done: - -```bash -./scripts/test-configuration web-arm -./scripts/test-configuration mail -git checkout master -git merge --no-ff <this-branch> -git push -``` - -Bento rolls out both hosts. On `web-arm.cloonar.com`: - -```bash -sudo systemctl restart supabase-env-generate -sudo cat /run/supabase/auth.env # expect SMTP + Google vars populated -sudo podman exec supabase-auth nc -vz mail.cloonar.com 587 -sudo podman restart supabase-auth -``` - -### Verification checklist - -- [ ] `/run/supabase/auth.env` contains `GOTRUE_SMTP_USER`, `GOTRUE_SMTP_PASS`, - `GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID`, `GOTRUE_EXTERNAL_GOOGLE_SECRET`. -- [ ] `podman inspect supabase-auth` shows - `GOTRUE_EXTERNAL_APPLE_ENABLED=true` and - `GOTRUE_EXTERNAL_APPLE_CLIENT_ID=io.fueltide.workout` in the env. -- [ ] `curl -X POST -H 'apikey: <anon>' -H 'Content-Type: application/json' \ - https://supabase.cloonar.com/auth/v1/signup \ - -d '{"email":"<real inbox>","password":"correct horse battery staple"}'` - delivers a mail with `From: noreply@fueltide.io` within ~30 s. -- [ ] Mail headers show `dkim=pass`, `spf=pass`, `dmarc=pass` - (`Authentication-Results` header). -- [ ] `POST /auth/v1/recover` triggers a reset mail. -- [ ] Browser visit to - `https://supabase.cloonar.com/auth/v1/authorize?provider=google` - completes and lands on `/auth/v1/callback`. Row in `auth.identities` - with `provider='google'`. -- [ ] From the iOS app: Sign in with Apple → - `supabase.auth.signInWithIdToken({ provider: 'apple', token, nonce })` - succeeds. Row in `auth.identities` with `provider='apple'` and - `identity_data.sub` matching the Apple user id. (Apple sign-in has no - browser flow here — it is tested from the app only.) -- [ ] Send a signup to [mail-tester.com](https://www.mail-tester.com/) — target - ≥ 9/10 spam score. - -## Rotation notes - -- **Google client secret**: no expiry; rotate via Google Cloud console if - leaked and update `GOOGLE_SECRET` in SOPS. -- **DKIM key**: no expiry, but best practice is to rotate yearly. Rotation - = regenerate keypair (step 2), replace the SOPS value (step 3), update DNS - (step 4), deploy. Keep both old+new DNS records live for 24h during - cutover. -- **SMTP LDAP password**: no expiry. To rotate, run `mkpasswd` again and - update both the LDAP userPassword attribute and SOPS `SMTP_PASS`. diff --git a/hosts/web-arm/modules/supabase/default.nix b/hosts/web-arm/modules/supabase/default.nix deleted file mode 100644 index e8bfdf8..0000000 --- a/hosts/web-arm/modules/supabase/default.nix +++ /dev/null @@ -1,486 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - kongEntrypoint = pkgs.writeTextFile { - name = "kong-entrypoint.sh"; - executable = true; - text = builtins.readFile ./kong-entrypoint.sh; - }; - - envGenerateScript = pkgs.writeShellScript "supabase-env-generate" - (builtins.readFile ./env-generate.sh); - - # Common extra options for all containers to join the supabase network - supabaseNet = [ "--network=supabase-net" ]; - -in -{ - # --- SOPS secret --- - sops.secrets.supabase-env = { }; - - # --- Persistent data directories --- - # Postgres data lives in a named podman volume (supabase-db-data) so podman - # owns the permissions on the container's postgres UID; logical dumps go to - # /var/backups/supabase where borg picks them up from /var. - systemd.tmpfiles.rules = [ - "d /var/lib/supabase/storage 0755 root root -" - "d /var/lib/supabase/functions 0755 root root -" - "d /var/lib/supabase/snippets 0755 root root -" - "d /var/backups/supabase 0700 root root -" - ]; - - - # --- Systemd services: network, env generation, and container ordering --- - systemd.services = - let - containerNames = [ - "supabase-db" - "supabase-analytics" - "supabase-auth" - "supabase-rest" - "supabase-realtime" - "supabase-storage" - "supabase-imgproxy" - "supabase-meta" - "supabase-studio" - "supabase-kong" - "supabase-vector" - "supabase-pooler" - "supabase-functions" - ]; - mkContainerDeps = name: { - "podman-${name}" = { - after = [ "init-supabase-network.service" "supabase-env-generate.service" ]; - requires = [ "init-supabase-network.service" "supabase-env-generate.service" ]; - }; - }; - in - lib.mkMerge (map mkContainerDeps containerNames ++ [ - { - init-supabase-network = { - description = "Create supabase-net Podman network"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - # '-' prefix tells systemd to ignore non-zero exit (network may already exist) - ExecStart = "-${pkgs.podman}/bin/podman network create supabase-net"; - }; - }; - supabase-env-generate = { - description = "Generate Supabase per-container env files from SOPS secrets"; - wantedBy = [ "multi-user.target" ]; - path = [ pkgs.jq ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = "${envGenerateScript} ${config.sops.secrets.supabase-env.path}"; - }; - }; - # Seed the edge-runtime's bootstrap `main` function. The container's - # entrypoint requires `/home/deno/functions/main/index.ts` to exist; - # without it edge-runtime fails with "could not find an appropriate - # entrypoint". Re-seed on every activation so updates to the bootstrap - # are picked up, while leaving user-authored functions untouched. - supabase-functions-seed = { - description = "Seed Supabase edge-functions main bootstrap"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - script = '' - install -d -m 0755 /var/lib/supabase/functions/main - install -m 0644 ${./functions/main/index.ts} /var/lib/supabase/functions/main/index.ts - ''; - }; - podman-supabase-functions = { - after = [ "supabase-functions-seed.service" ]; - requires = [ "supabase-functions-seed.service" ]; - }; - # Logical daily dump of the containerised Postgres cluster. Writes to - # /var/backups/supabase which is covered by the borg path /var; - # /var/lib/containers (the named-volume storage) is excluded from borg, - # so the dump is the only copy borg ships off-host. - supabase-db-backup = { - description = "pg_dumpall of the Supabase Postgres cluster"; - after = [ "podman-supabase-db.service" ]; - requires = [ "podman-supabase-db.service" ]; - serviceConfig = { - Type = "oneshot"; - }; - script = '' - set -euo pipefail - tmp=/var/backups/supabase/supabase-all.sql.tmp - out=/var/backups/supabase/supabase-all.sql - ${pkgs.podman}/bin/podman exec -u postgres supabase-db \ - pg_dumpall -U postgres --clean --if-exists > "$tmp" - mv "$tmp" "$out" - ''; - }; - } - ]); - - systemd.timers.supabase-db-backup = { - description = "Daily Supabase Postgres dump"; - wantedBy = [ "timers.target" ]; - timerConfig = { - OnCalendar = "*-*-* 02:30:00"; - Persistent = true; - }; - }; - - # --- Containers --- - virtualisation.oci-containers.containers = { - - # 1. PostgreSQL - supabase-db = { - image = "supabase/postgres:15.8.1.085"; - environment = { - POSTGRES_HOST = "/var/run/postgresql"; - PGPORT = "5432"; - POSTGRES_PORT = "5432"; - PGDATABASE = "postgres"; - POSTGRES_DB = "postgres"; - JWT_EXP = "3600"; - }; - environmentFiles = [ "/run/supabase/db.env" ]; - volumes = [ - "supabase-db-data:/var/lib/postgresql/data" - "${./sql/_supabase.sql}:/docker-entrypoint-initdb.d/migrations/97-_supabase.sql:ro" - "${./sql/realtime.sql}:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:ro" - "${./sql/logs.sql}:/docker-entrypoint-initdb.d/migrations/99-logs.sql:ro" - "${./sql/pooler.sql}:/docker-entrypoint-initdb.d/migrations/99-pooler.sql:ro" - "${./sql/webhooks.sql}:/docker-entrypoint-initdb.d/init-scripts/98-webhooks.sql:ro" - "${./sql/roles.sql}:/docker-entrypoint-initdb.d/init-scripts/99-roles.sql:ro" - "${./sql/jwt.sql}:/docker-entrypoint-initdb.d/init-scripts/99-jwt.sql:ro" - "supabase-db-config:/etc/postgresql-custom" - ]; - cmd = [ - "postgres" - "-c" "config_file=/etc/postgresql/postgresql.conf" - "-c" "log_min_messages=fatal" - ]; - extraOptions = supabaseNet ++ [ - "--network-alias=db" - "--shm-size=2g" - ]; - }; - - # 2. Analytics (Logflare) - supabase-analytics = { - image = "supabase/logflare:1.31.2"; - dependsOn = [ "supabase-db" ]; - environment = { - LOGFLARE_NODE_HOST = "127.0.0.1"; - DB_USERNAME = "supabase_admin"; - DB_DATABASE = "_supabase"; - DB_HOSTNAME = "db"; - DB_PORT = "5432"; - DB_SCHEMA = "_analytics"; - LOGFLARE_SINGLE_TENANT = "true"; - LOGFLARE_SUPABASE_MODE = "true"; - POSTGRES_BACKEND_SCHEMA = "_analytics"; - LOGFLARE_FEATURE_FLAG_OVERRIDE = "multibackend=true"; - }; - environmentFiles = [ "/run/supabase/analytics.env" ]; - extraOptions = supabaseNet ++ [ - "--network-alias=analytics" - ]; - }; - - # 3. Auth (GoTrue) - supabase-auth = { - image = "supabase/gotrue:v2.186.0"; - dependsOn = [ "supabase-db" "supabase-analytics" ]; - environment = { - GOTRUE_API_HOST = "0.0.0.0"; - GOTRUE_API_PORT = "9999"; - API_EXTERNAL_URL = "https://supabase.cloonar.com"; - GOTRUE_DB_DRIVER = "postgres"; - GOTRUE_SITE_URL = "https://app.fueltide.io"; - GOTRUE_URI_ALLOW_LIST = "https://app.fueltide.io,https://app.fueltide.io/**,https://app.stage.fueltide.io,https://app.stage.fueltide.io/**,io.fueltide.workout://"; - GOTRUE_DISABLE_SIGNUP = "false"; - GOTRUE_JWT_ADMIN_ROLES = "service_role"; - GOTRUE_JWT_AUD = "authenticated"; - GOTRUE_JWT_DEFAULT_GROUP_NAME = "authenticated"; - GOTRUE_JWT_EXP = "3600"; - GOTRUE_EXTERNAL_EMAIL_ENABLED = "true"; - GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED = "false"; - GOTRUE_MAILER_AUTOCONFIRM = "false"; - GOTRUE_SMTP_ADMIN_EMAIL = "noreply@fueltide.io"; - GOTRUE_SMTP_HOST = "mail.cloonar.com"; - GOTRUE_SMTP_PORT = "587"; - GOTRUE_SMTP_SENDER_NAME = "Fueltide"; - GOTRUE_MAILER_URLPATHS_INVITE = "/auth/v1/verify"; - GOTRUE_MAILER_URLPATHS_CONFIRMATION = "/auth/v1/verify"; - GOTRUE_MAILER_URLPATHS_RECOVERY = "/auth/v1/verify"; - GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE = "/auth/v1/verify"; - GOTRUE_EXTERNAL_PHONE_ENABLED = "false"; - GOTRUE_SMS_AUTOCONFIRM = "false"; - GOTRUE_EXTERNAL_GOOGLE_ENABLED = "true"; - GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI = "https://supabase.cloonar.com/auth/v1/callback"; - GOTRUE_EXTERNAL_APPLE_ENABLED = "true"; - GOTRUE_EXTERNAL_APPLE_CLIENT_ID = "io.fueltide.workout"; - }; - environmentFiles = [ "/run/supabase/auth.env" ]; - extraOptions = supabaseNet ++ [ - "--network-alias=auth" - ]; - }; - - # 4. REST (PostgREST) - supabase-rest = { - image = "postgrest/postgrest:v14.6"; - dependsOn = [ "supabase-db" ]; - environment = { - PGRST_DB_SCHEMAS = "public,storage,graphql_public"; - PGRST_DB_MAX_ROWS = "1000"; - PGRST_DB_EXTRA_SEARCH_PATH = "public"; - PGRST_DB_ANON_ROLE = "anon"; - PGRST_DB_USE_LEGACY_GUCS = "false"; - PGRST_APP_SETTINGS_JWT_EXP = "3600"; - }; - environmentFiles = [ "/run/supabase/rest.env" ]; - cmd = [ "postgrest" ]; - extraOptions = supabaseNet ++ [ - "--network-alias=rest" - ]; - }; - - # 5. Realtime - supabase-realtime = { - image = "supabase/realtime:v2.76.5"; - dependsOn = [ "supabase-db" ]; - environment = { - PORT = "4000"; - DB_HOST = "db"; - DB_PORT = "5432"; - DB_USER = "supabase_admin"; - DB_NAME = "postgres"; - DB_AFTER_CONNECT_QUERY = "SET search_path TO _realtime"; - DB_ENC_KEY = "supabaserealtime"; - ERL_AFLAGS = "-proto_dist inet_tcp"; - DNS_NODES = "''"; - RLIMIT_NOFILE = "10000"; - APP_NAME = "realtime"; - SEED_SELF_HOST = "true"; - RUN_JANITOR = "true"; - DISABLE_HEALTHCHECK_LOGGING = "true"; - }; - environmentFiles = [ "/run/supabase/realtime.env" ]; - extraOptions = supabaseNet ++ [ - # Hostname must be realtime-dev.supabase-realtime for tenant ID parsing - "--hostname=realtime-dev.supabase-realtime" - "--network-alias=realtime-dev.supabase-realtime" - ]; - }; - - # 6. Storage - supabase-storage = { - image = "supabase/storage-api:v1.44.2"; - dependsOn = [ "supabase-db" "supabase-rest" "supabase-imgproxy" ]; - environment = { - POSTGREST_URL = "http://rest:3000"; - STORAGE_PUBLIC_URL = "https://supabase.cloonar.com"; - REQUEST_ALLOW_X_FORWARDED_PATH = "true"; - FILE_SIZE_LIMIT = "52428800"; - STORAGE_BACKEND = "file"; - GLOBAL_S3_BUCKET = "stub"; - FILE_STORAGE_BACKEND_PATH = "/var/lib/storage"; - TENANT_ID = "stub"; - REGION = "stub"; - ENABLE_IMAGE_TRANSFORMATION = "true"; - IMGPROXY_URL = "http://imgproxy:5001"; - }; - environmentFiles = [ "/run/supabase/storage.env" ]; - volumes = [ - "/var/lib/supabase/storage:/var/lib/storage" - ]; - extraOptions = supabaseNet ++ [ - "--network-alias=storage" - ]; - }; - - # 7. Imgproxy - supabase-imgproxy = { - image = "darthsim/imgproxy:v3.30.1"; - environment = { - IMGPROXY_BIND = ":5001"; - IMGPROXY_LOCAL_FILESYSTEM_ROOT = "/"; - IMGPROXY_USE_ETAG = "true"; - IMGPROXY_AUTO_WEBP = "true"; - IMGPROXY_MAX_SRC_RESOLUTION = "16.8"; - }; - volumes = [ - "/var/lib/supabase/storage:/var/lib/storage" - ]; - extraOptions = supabaseNet ++ [ - "--network-alias=imgproxy" - ]; - }; - - # 8. Meta (pg-meta) - supabase-meta = { - image = "supabase/postgres-meta:v0.95.2"; - dependsOn = [ "supabase-db" ]; - environment = { - PG_META_PORT = "8080"; - PG_META_DB_HOST = "db"; - PG_META_DB_PORT = "5432"; - PG_META_DB_NAME = "postgres"; - PG_META_DB_USER = "supabase_admin"; - }; - environmentFiles = [ "/run/supabase/meta.env" ]; - extraOptions = supabaseNet ++ [ - "--network-alias=meta" - ]; - }; - - # 9. Studio - supabase-studio = { - image = "supabase/studio:2026.03.16-sha-5528817"; - dependsOn = [ "supabase-analytics" ]; - environment = { - HOSTNAME = "::"; - STUDIO_PG_META_URL = "http://meta:8080"; - POSTGRES_PORT = "5432"; - POSTGRES_HOST = "db"; - POSTGRES_DB = "postgres"; - PGRST_DB_SCHEMAS = "public,storage,graphql_public"; - PGRST_DB_MAX_ROWS = "1000"; - PGRST_DB_EXTRA_SEARCH_PATH = "public"; - DEFAULT_ORGANIZATION_NAME = "Default Organization"; - DEFAULT_PROJECT_NAME = "Default Project"; - SUPABASE_URL = "http://kong:8000"; - SUPABASE_PUBLIC_URL = "https://supabase.cloonar.com"; - NEXT_PUBLIC_ENABLE_LOGS = "true"; - NEXT_ANALYTICS_BACKEND_PROVIDER = "postgres"; - LOGFLARE_URL = "http://analytics:4000"; - SNIPPETS_MANAGEMENT_FOLDER = "/app/snippets"; - EDGE_FUNCTIONS_MANAGEMENT_FOLDER = "/app/edge-functions"; - }; - environmentFiles = [ "/run/supabase/studio.env" ]; - volumes = [ - "/var/lib/supabase/snippets:/app/snippets" - "/var/lib/supabase/functions:/app/edge-functions" - ]; - extraOptions = supabaseNet ++ [ - "--network-alias=studio" - ]; - }; - - # 10. Kong (API Gateway) - supabase-kong = { - image = "kong/kong:3.9.1"; - dependsOn = [ "supabase-studio" ]; - environment = { - KONG_DATABASE = "off"; - KONG_DECLARATIVE_CONFIG = "/usr/local/kong/kong.yml"; - KONG_DNS_ORDER = "LAST,A,CNAME"; - KONG_DNS_NOT_FOUND_TTL = "1"; - KONG_PLUGINS = "request-transformer,cors,key-auth,acl,basic-auth,request-termination,ip-restriction,post-function"; - KONG_NGINX_PROXY_PROXY_BUFFER_SIZE = "160k"; - KONG_NGINX_PROXY_PROXY_BUFFERS = "64 160k"; - KONG_PROXY_ACCESS_LOG = "/dev/stdout combined"; - }; - environmentFiles = [ "/run/supabase/kong.env" ]; - ports = [ - "127.0.0.1:8000:8000" - "127.0.0.1:8443:8443" - ]; - volumes = [ - "${./kong.yml}:/home/kong/temp.yml:ro" - "${kongEntrypoint}:/home/kong/kong-entrypoint.sh:ro" - ]; - entrypoint = "/home/kong/kong-entrypoint.sh"; - extraOptions = supabaseNet ++ [ - "--network-alias=kong" - ]; - }; - - # 11. Vector (log collection) - supabase-vector = { - image = "timberio/vector:0.53.0-alpine"; - environment = { }; - environmentFiles = [ "/run/supabase/vector.env" ]; - volumes = [ - "${./vector.yml}:/etc/vector/vector.yml:ro" - "/var/run/docker.sock:/var/run/docker.sock:ro" - ]; - cmd = [ "--config" "/etc/vector/vector.yml" ]; - extraOptions = supabaseNet ++ [ - "--network-alias=vector" - "--security-opt=label=disable" - ]; - }; - - # 12. Pooler (Supavisor) - supabase-pooler = { - image = "supabase/supavisor:2.7.4"; - dependsOn = [ "supabase-db" ]; - environment = { - PORT = "4000"; - CLUSTER_POSTGRES = "true"; - REGION = "local"; - ERL_AFLAGS = "-proto_dist inet_tcp"; - POOLER_POOL_MODE = "transaction"; - POSTGRES_PORT = "5432"; - POSTGRES_DB = "postgres"; - POOLER_TENANT_ID = "default-tenant"; - POOLER_DEFAULT_POOL_SIZE = "20"; - POOLER_MAX_CLIENT_CONN = "100"; - DB_POOL_SIZE = "10"; - }; - environmentFiles = [ "/run/supabase/pooler.env" ]; - volumes = [ - "${./pooler.exs}:/etc/pooler/pooler.exs:ro" - ]; - cmd = [ - "/bin/sh" "-c" - "/app/bin/migrate && /app/bin/supavisor eval \"$(cat /etc/pooler/pooler.exs)\" && /app/bin/server" - ]; - extraOptions = supabaseNet ++ [ - "--network-alias=pooler" - ]; - }; - - # 13. Edge Functions - supabase-functions = { - image = "supabase/edge-runtime:v1.71.2"; - dependsOn = [ "supabase-kong" ]; - environment = { - SUPABASE_URL = "http://kong:8000"; - SUPABASE_PUBLIC_URL = "https://supabase.cloonar.com"; - VERIFY_JWT = "false"; - }; - environmentFiles = [ "/run/supabase/functions.env" ]; - volumes = [ - "/var/lib/supabase/functions:/home/deno/functions" - "supabase-deno-cache:/root/.cache/deno" - ]; - cmd = [ "start" "--main-service" "/home/deno/functions/main" ]; - extraOptions = supabaseNet ++ [ - "--network-alias=functions" - ]; - }; - }; - - # --- Nginx reverse proxy --- - services.nginx.virtualHosts."supabase.cloonar.com" = { - forceSSL = true; - enableACME = true; - acmeRoot = null; - locations."/" = { - proxyPass = "http://127.0.0.1:8000"; - proxyWebsockets = true; - extraConfig = '' - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_read_timeout 86400s; - proxy_send_timeout 86400s; - client_max_body_size 50M; - ''; - }; - }; -} diff --git a/hosts/web-arm/modules/supabase/env-generate.sh b/hosts/web-arm/modules/supabase/env-generate.sh deleted file mode 100644 index c83bf28..0000000 --- a/hosts/web-arm/modules/supabase/env-generate.sh +++ /dev/null @@ -1,96 +0,0 @@ -set -euo pipefail -umask 077 -mkdir -p /run/supabase - -set -a -source "$1" -set +a - -# URL-encode password for use in connection strings -PG_PASS_ENCODED=$(printf '%s' "$POSTGRES_PASSWORD" | jq -sRr @uri) - -cat > /run/supabase/db.env <<EOF -POSTGRES_PASSWORD=$POSTGRES_PASSWORD -PGPASSWORD=$POSTGRES_PASSWORD -JWT_SECRET=$JWT_SECRET -EOF - -cat > /run/supabase/analytics.env <<EOF -DB_PASSWORD=$POSTGRES_PASSWORD -LOGFLARE_PUBLIC_ACCESS_TOKEN=$LOGFLARE_PUBLIC_ACCESS_TOKEN -LOGFLARE_PRIVATE_ACCESS_TOKEN=$LOGFLARE_PRIVATE_ACCESS_TOKEN -POSTGRES_BACKEND_URL=postgresql://supabase_admin:$PG_PASS_ENCODED@db:5432/_supabase -EOF - -cat > /run/supabase/auth.env <<EOF -GOTRUE_JWT_SECRET=$JWT_SECRET -GOTRUE_DB_DATABASE_URL=postgres://supabase_auth_admin:$PG_PASS_ENCODED@db:5432/postgres -GOTRUE_SMTP_USER=${SMTP_USER:-} -GOTRUE_SMTP_PASS=${SMTP_PASS:-} -GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID:-} -GOTRUE_EXTERNAL_GOOGLE_SECRET=${GOOGLE_SECRET:-} -EOF - -cat > /run/supabase/rest.env <<EOF -PGRST_JWT_SECRET=$JWT_SECRET -PGRST_APP_SETTINGS_JWT_SECRET=$JWT_SECRET -PGRST_DB_URI=postgres://authenticator:$PG_PASS_ENCODED@db:5432/postgres -EOF - -cat > /run/supabase/realtime.env <<EOF -DB_PASSWORD=$POSTGRES_PASSWORD -API_JWT_SECRET=$JWT_SECRET -SECRET_KEY_BASE=$SECRET_KEY_BASE -METRICS_JWT_SECRET=$JWT_SECRET -EOF - -cat > /run/supabase/storage.env <<EOF -ANON_KEY=$ANON_KEY -SERVICE_KEY=$SERVICE_ROLE_KEY -AUTH_JWT_SECRET=$JWT_SECRET -DATABASE_URL=postgres://supabase_storage_admin:$PG_PASS_ENCODED@db:5432/postgres -S3_PROTOCOL_ACCESS_KEY_ID=$S3_PROTOCOL_ACCESS_KEY_ID -S3_PROTOCOL_ACCESS_KEY_SECRET=$S3_PROTOCOL_ACCESS_KEY_SECRET -EOF - -cat > /run/supabase/meta.env <<EOF -PG_META_DB_PASSWORD=$POSTGRES_PASSWORD -CRYPTO_KEY=$PG_META_CRYPTO_KEY -EOF - -cat > /run/supabase/studio.env <<EOF -POSTGRES_PASSWORD=$PG_PASS_ENCODED -PG_META_CRYPTO_KEY=$PG_META_CRYPTO_KEY -SUPABASE_ANON_KEY=$ANON_KEY -SUPABASE_SERVICE_KEY=$SERVICE_ROLE_KEY -AUTH_JWT_SECRET=$JWT_SECRET -LOGFLARE_API_KEY=$LOGFLARE_PUBLIC_ACCESS_TOKEN -LOGFLARE_PUBLIC_ACCESS_TOKEN=$LOGFLARE_PUBLIC_ACCESS_TOKEN -LOGFLARE_PRIVATE_ACCESS_TOKEN=$LOGFLARE_PRIVATE_ACCESS_TOKEN -EOF - -cat > /run/supabase/kong.env <<EOF -SUPABASE_ANON_KEY=$ANON_KEY -SUPABASE_SERVICE_KEY=$SERVICE_ROLE_KEY -DASHBOARD_USERNAME=supabase -DASHBOARD_PASSWORD=$DASHBOARD_PASSWORD -EOF - -cat > /run/supabase/vector.env <<EOF -LOGFLARE_PUBLIC_ACCESS_TOKEN=$LOGFLARE_PUBLIC_ACCESS_TOKEN -EOF - -cat > /run/supabase/pooler.env <<EOF -POSTGRES_PASSWORD=$POSTGRES_PASSWORD -DATABASE_URL=ecto://supabase_admin:$PG_PASS_ENCODED@db:5432/_supabase -SECRET_KEY_BASE=$SECRET_KEY_BASE -VAULT_ENC_KEY=$VAULT_ENC_KEY -API_JWT_SECRET=$JWT_SECRET -METRICS_JWT_SECRET=$JWT_SECRET -EOF - -cat > /run/supabase/functions.env <<EOF -JWT_SECRET=$JWT_SECRET -SUPABASE_ANON_KEY=$ANON_KEY -SUPABASE_SERVICE_ROLE_KEY=$SERVICE_ROLE_KEY -EOF diff --git a/hosts/web-arm/modules/supabase/functions/main/index.ts b/hosts/web-arm/modules/supabase/functions/main/index.ts deleted file mode 100644 index 05b6ad6..0000000 --- a/hosts/web-arm/modules/supabase/functions/main/index.ts +++ /dev/null @@ -1,144 +0,0 @@ -import * as jose from 'https://deno.land/x/jose@v4.14.4/index.ts' - -console.log('main function started') - -const JWT_SECRET = Deno.env.get('JWT_SECRET') -const SUPABASE_URL = Deno.env.get('SUPABASE_URL') -const VERIFY_JWT = Deno.env.get('VERIFY_JWT') === 'true' - -// Create JWKS for ES256/RS256 tokens (newer tokens) -let SUPABASE_JWT_KEYS: ReturnType<typeof jose.createRemoteJWKSet> | null = null -if (SUPABASE_URL) { - try { - SUPABASE_JWT_KEYS = jose.createRemoteJWKSet( - new URL('/auth/v1/.well-known/jwks.json', SUPABASE_URL) - ) - } catch (e) { - console.error('Failed to fetch JWKS from SUPABASE_URL:', e) - } -} - -function getAuthToken(req: Request) { - const authHeader = req.headers.get('authorization') - if (!authHeader) { - throw new Error('Missing authorization header') - } - const [bearer, token] = authHeader.split(' ') - if (bearer !== 'Bearer') { - throw new Error(`Auth header is not 'Bearer {token}'`) - } - return token -} - -async function isValidLegacyJWT(jwt: string): Promise<boolean> { - if (!JWT_SECRET) { - console.error('JWT_SECRET not available for HS256 token verification') - return false - } - - const encoder = new TextEncoder(); - const secretKey = encoder.encode(JWT_SECRET) - - try { - await jose.jwtVerify(jwt, secretKey); - } catch (e) { - console.error('Symmetric Legacy JWT verification error', e); - return false; - } - return true; -} - -async function isValidJWT(jwt: string): Promise<boolean> { - if (!SUPABASE_JWT_KEYS) { - console.error('JWKS not available for ES256/RS256 token verification') - return false - } - - try { - await jose.jwtVerify(jwt, SUPABASE_JWT_KEYS) - } catch (e) { - console.error('Asymmetric JWT verification error', e); - return false - } - - return true; -} - -async function isValidHybridJWT(jwt: string): Promise<boolean> { - const { alg: jwtAlgorithm } = jose.decodeProtectedHeader(jwt) - - if (jwtAlgorithm === 'HS256') { - console.log(`Legacy token type detected, attempting ${jwtAlgorithm} verification.`) - - return await isValidLegacyJWT(jwt) - } - - if (jwtAlgorithm === 'ES256' || jwtAlgorithm === 'RS256') { - return await isValidJWT(jwt) - } - - return false; -} - -Deno.serve(async (req: Request) => { - if (req.method !== 'OPTIONS' && VERIFY_JWT) { - try { - const token = getAuthToken(req) - const isValidJWT = await isValidHybridJWT(token); - - if (!isValidJWT) { - return new Response(JSON.stringify({ msg: 'Invalid JWT' }), { - status: 401, - headers: { 'Content-Type': 'application/json' }, - }) - } - } catch (e) { - console.error(e) - return new Response(JSON.stringify({ msg: e.toString() }), { - status: 401, - headers: { 'Content-Type': 'application/json' }, - }) - } - } - - const url = new URL(req.url) - const { pathname } = url - const path_parts = pathname.split('/') - const service_name = path_parts[1] - - if (!service_name || service_name === '') { - const error = { msg: 'missing function name in request' } - return new Response(JSON.stringify(error), { - status: 400, - headers: { 'Content-Type': 'application/json' }, - }) - } - - const servicePath = `/home/deno/functions/${service_name}` - console.error(`serving the request with ${servicePath}`) - - const memoryLimitMb = 150 - const workerTimeoutMs = 1 * 60 * 1000 - const noModuleCache = false - const importMapPath = null - const envVarsObj = Deno.env.toObject() - const envVars = Object.keys(envVarsObj).map((k) => [k, envVarsObj[k]]) - - try { - const worker = await EdgeRuntime.userWorkers.create({ - servicePath, - memoryLimitMb, - workerTimeoutMs, - noModuleCache, - importMapPath, - envVars, - }) - return await worker.fetch(req) - } catch (e) { - const error = { msg: e.toString() } - return new Response(JSON.stringify(error), { - status: 500, - headers: { 'Content-Type': 'application/json' }, - }) - } -}) diff --git a/hosts/web-arm/modules/supabase/kong-entrypoint.sh b/hosts/web-arm/modules/supabase/kong-entrypoint.sh deleted file mode 100644 index f1da449..0000000 --- a/hosts/web-arm/modules/supabase/kong-entrypoint.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -# Legacy API keys, not sb_ API keys -> pass apikey through unchanged -export LUA_AUTH_EXPR="\$((headers.authorization ~= nil and headers.authorization:sub(1, 10) ~= 'Bearer sb_' and headers.authorization) or headers.apikey)" -export LUA_RT_WS_EXPR="\$(query_params.apikey)" - -# Substitute environment variables in the Kong declarative config -awk '{ - result = "" - rest = $0 - while (match(rest, /\$[A-Za-z_][A-Za-z_0-9]*/)) { - varname = substr(rest, RSTART + 1, RLENGTH - 1) - if (varname in ENVIRON) { - result = result substr(rest, 1, RSTART - 1) ENVIRON[varname] - } else { - result = result substr(rest, 1, RSTART + RLENGTH - 1) - } - rest = substr(rest, RSTART + RLENGTH) - } - print result rest -}' /home/kong/temp.yml > "$KONG_DECLARATIVE_CONFIG" - -# Remove empty key-auth credentials (unconfigured opaque keys) -sed -i '/^[[:space:]]*- key:[[:space:]]*$/d' "$KONG_DECLARATIVE_CONFIG" - -exec /entrypoint.sh kong docker-start diff --git a/hosts/web-arm/modules/supabase/kong.yml b/hosts/web-arm/modules/supabase/kong.yml deleted file mode 100644 index 52af820..0000000 --- a/hosts/web-arm/modules/supabase/kong.yml +++ /dev/null @@ -1,265 +0,0 @@ -_format_version: '2.1' -_transform: true - -consumers: - - username: DASHBOARD - - username: anon - keyauth_credentials: - - key: $SUPABASE_ANON_KEY - - username: service_role - keyauth_credentials: - - key: $SUPABASE_SERVICE_KEY - -acls: - - consumer: anon - group: anon - - consumer: service_role - group: admin - -basicauth_credentials: - - consumer: DASHBOARD - username: '$DASHBOARD_USERNAME' - password: '$DASHBOARD_PASSWORD' - -services: - - name: auth-v1-open - url: http://auth:9999/verify - routes: - - name: auth-v1-open - strip_path: true - paths: - - /auth/v1/verify - plugins: - - name: cors - - name: auth-v1-open-callback - url: http://auth:9999/callback - routes: - - name: auth-v1-open-callback - strip_path: true - paths: - - /auth/v1/callback - plugins: - - name: cors - - name: auth-v1-open-authorize - url: http://auth:9999/authorize - routes: - - name: auth-v1-open-authorize - strip_path: true - paths: - - /auth/v1/authorize - plugins: - - name: cors - - name: auth-v1-open-jwks - url: http://auth:9999/.well-known/jwks.json - routes: - - name: auth-v1-open-jwks - strip_path: true - paths: - - /auth/v1/.well-known/jwks.json - plugins: - - name: cors - - name: auth-v1 - url: http://auth:9999/ - routes: - - name: auth-v1-all - strip_path: true - paths: - - /auth/v1/ - plugins: - - name: cors - - name: key-auth - config: - hide_credentials: false - - name: request-transformer - config: - add: - headers: - - "Authorization: $LUA_AUTH_EXPR" - replace: - headers: - - "Authorization: $LUA_AUTH_EXPR" - - name: acl - config: - hide_groups_header: true - allow: - - admin - - anon - - name: rest-v1 - url: http://rest:3000/ - routes: - - name: rest-v1-all - strip_path: true - paths: - - /rest/v1/ - plugins: - - name: cors - - name: key-auth - config: - hide_credentials: false - - name: request-transformer - config: - add: - headers: - - "Authorization: $LUA_AUTH_EXPR" - replace: - headers: - - "Authorization: $LUA_AUTH_EXPR" - - name: acl - config: - hide_groups_header: true - allow: - - admin - - anon - - name: graphql-v1 - url: http://rest:3000/rpc/graphql - routes: - - name: graphql-v1-all - strip_path: true - paths: - - /graphql/v1 - plugins: - - name: cors - - name: key-auth - config: - hide_credentials: false - - name: request-transformer - config: - add: - headers: - - "Content-Profile: graphql_public" - - "Authorization: $LUA_AUTH_EXPR" - replace: - headers: - - "Authorization: $LUA_AUTH_EXPR" - - name: acl - config: - hide_groups_header: true - allow: - - admin - - anon - - name: realtime-v1-ws - url: http://realtime-dev.supabase-realtime:4000/socket - protocol: ws - routes: - - name: realtime-v1-ws - strip_path: true - paths: - - /realtime/v1/ - plugins: - - name: cors - - name: key-auth - config: - hide_credentials: false - - name: request-transformer - config: - add: - headers: - - "x-api-key:$LUA_RT_WS_EXPR" - replace: - querystring: - - "apikey:$LUA_RT_WS_EXPR" - - name: acl - config: - hide_groups_header: true - allow: - - admin - - anon - - name: realtime-v1-rest - url: http://realtime-dev.supabase-realtime:4000/api - protocol: http - routes: - - name: realtime-v1-rest - strip_path: true - paths: - - /realtime/v1/api - plugins: - - name: cors - - name: key-auth - config: - hide_credentials: false - - name: request-transformer - config: - add: - headers: - - "Authorization: $LUA_AUTH_EXPR" - replace: - headers: - - "Authorization: $LUA_AUTH_EXPR" - - name: acl - config: - hide_groups_header: true - allow: - - admin - - anon - - name: storage-v1 - url: http://storage:5000/ - routes: - - name: storage-v1-all - strip_path: true - paths: - - /storage/v1/ - plugins: - - name: cors - - name: request-transformer - config: - add: - headers: - - "Authorization: $LUA_AUTH_EXPR" - replace: - headers: - - "Authorization: $LUA_AUTH_EXPR" - - name: post-function - config: - access: - - | - local auth = kong.request.get_header("authorization") - if auth == nil or auth == "" or auth:find("^%s*$") then - kong.service.request.clear_header("authorization") - end - - name: functions-v1 - url: http://functions:9000/ - read_timeout: 150000 - routes: - - name: functions-v1-all - strip_path: true - paths: - - /functions/v1/ - plugins: - - name: cors - - name: well-known-oauth - url: http://auth:9999/.well-known/oauth-authorization-server - routes: - - name: well-known-oauth - strip_path: true - paths: - - /.well-known/oauth-authorization-server - plugins: - - name: cors - - name: meta - url: http://meta:8080/ - routes: - - name: meta-all - strip_path: true - paths: - - /pg/ - plugins: - - name: key-auth - config: - hide_credentials: false - - name: acl - config: - hide_groups_header: true - allow: - - admin - - name: dashboard - url: http://studio:3000/ - routes: - - name: dashboard-all - strip_path: true - paths: - - / - plugins: - - name: cors - - name: basic-auth - config: - hide_credentials: true diff --git a/hosts/web-arm/modules/supabase/pooler.exs b/hosts/web-arm/modules/supabase/pooler.exs deleted file mode 100644 index 791d61c..0000000 --- a/hosts/web-arm/modules/supabase/pooler.exs +++ /dev/null @@ -1,30 +0,0 @@ -{:ok, _} = Application.ensure_all_started(:supavisor) - -{:ok, version} = - case Supavisor.Repo.query!("select version()") do - %{rows: [[ver]]} -> Supavisor.Helpers.parse_pg_version(ver) - _ -> nil - end - -params = %{ - "external_id" => System.get_env("POOLER_TENANT_ID"), - "db_host" => "db", - "db_port" => System.get_env("POSTGRES_PORT"), - "db_database" => System.get_env("POSTGRES_DB"), - "require_user" => false, - "auth_query" => "SELECT * FROM pgbouncer.get_auth($1)", - "default_max_clients" => System.get_env("POOLER_MAX_CLIENT_CONN"), - "default_pool_size" => System.get_env("POOLER_DEFAULT_POOL_SIZE"), - "default_parameter_status" => %{"server_version" => version}, - "users" => [%{ - "db_user" => "pgbouncer", - "db_password" => System.get_env("POSTGRES_PASSWORD"), - "mode_type" => System.get_env("POOLER_POOL_MODE"), - "pool_size" => System.get_env("POOLER_DEFAULT_POOL_SIZE"), - "is_manager" => true - }] -} - -if !Supavisor.Tenants.get_tenant_by_external_id(params["external_id"]) do - {:ok, _} = Supavisor.Tenants.create_tenant(params) -end diff --git a/hosts/web-arm/modules/supabase/sql/_supabase.sql b/hosts/web-arm/modules/supabase/sql/_supabase.sql deleted file mode 100644 index 8882968..0000000 --- a/hosts/web-arm/modules/supabase/sql/_supabase.sql +++ /dev/null @@ -1,2 +0,0 @@ -\set pguser `echo "$POSTGRES_USER"` -CREATE DATABASE _supabase WITH OWNER :pguser; diff --git a/hosts/web-arm/modules/supabase/sql/jwt.sql b/hosts/web-arm/modules/supabase/sql/jwt.sql deleted file mode 100644 index 93a8041..0000000 --- a/hosts/web-arm/modules/supabase/sql/jwt.sql +++ /dev/null @@ -1,4 +0,0 @@ -\set jwt_secret `echo "$JWT_SECRET"` -\set jwt_exp `echo "$JWT_EXP"` -ALTER DATABASE postgres SET "app.settings.jwt_secret" TO :'jwt_secret'; -ALTER DATABASE postgres SET "app.settings.jwt_exp" TO :'jwt_exp'; diff --git a/hosts/web-arm/modules/supabase/sql/logs.sql b/hosts/web-arm/modules/supabase/sql/logs.sql deleted file mode 100644 index 794b086..0000000 --- a/hosts/web-arm/modules/supabase/sql/logs.sql +++ /dev/null @@ -1,5 +0,0 @@ -\set pguser `echo "$POSTGRES_USER"` -\c _supabase -create schema if not exists _analytics; -alter schema _analytics owner to :pguser; -\c postgres diff --git a/hosts/web-arm/modules/supabase/sql/pooler.sql b/hosts/web-arm/modules/supabase/sql/pooler.sql deleted file mode 100644 index 516d986..0000000 --- a/hosts/web-arm/modules/supabase/sql/pooler.sql +++ /dev/null @@ -1,5 +0,0 @@ -\set pguser `echo "$POSTGRES_USER"` -\c _supabase -create schema if not exists _supavisor; -alter schema _supavisor owner to :pguser; -\c postgres diff --git a/hosts/web-arm/modules/supabase/sql/realtime.sql b/hosts/web-arm/modules/supabase/sql/realtime.sql deleted file mode 100644 index 231cded..0000000 --- a/hosts/web-arm/modules/supabase/sql/realtime.sql +++ /dev/null @@ -1,3 +0,0 @@ -\set pguser `echo "$POSTGRES_USER"` -create schema if not exists _realtime; -alter schema _realtime owner to :pguser; diff --git a/hosts/web-arm/modules/supabase/sql/roles.sql b/hosts/web-arm/modules/supabase/sql/roles.sql deleted file mode 100644 index c507c29..0000000 --- a/hosts/web-arm/modules/supabase/sql/roles.sql +++ /dev/null @@ -1,6 +0,0 @@ -\set pgpass `echo "$POSTGRES_PASSWORD"` -ALTER USER authenticator WITH PASSWORD :'pgpass'; -ALTER USER pgbouncer WITH PASSWORD :'pgpass'; -ALTER USER supabase_auth_admin WITH PASSWORD :'pgpass'; -ALTER USER supabase_functions_admin WITH PASSWORD :'pgpass'; -ALTER USER supabase_storage_admin WITH PASSWORD :'pgpass'; diff --git a/hosts/web-arm/modules/supabase/sql/webhooks.sql b/hosts/web-arm/modules/supabase/sql/webhooks.sql deleted file mode 100644 index 7d5238b..0000000 --- a/hosts/web-arm/modules/supabase/sql/webhooks.sql +++ /dev/null @@ -1,153 +0,0 @@ -BEGIN; - CREATE EXTENSION IF NOT EXISTS pg_net SCHEMA extensions; - CREATE SCHEMA supabase_functions AUTHORIZATION supabase_admin; - GRANT USAGE ON SCHEMA supabase_functions TO postgres, anon, authenticated, service_role; - ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON TABLES TO postgres, anon, authenticated, service_role; - ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON FUNCTIONS TO postgres, anon, authenticated, service_role; - ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON SEQUENCES TO postgres, anon, authenticated, service_role; - CREATE TABLE supabase_functions.migrations ( - version text PRIMARY KEY, - inserted_at timestamptz NOT NULL DEFAULT NOW() - ); - INSERT INTO supabase_functions.migrations (version) VALUES ('initial'); - CREATE TABLE supabase_functions.hooks ( - id bigserial PRIMARY KEY, - hook_table_id integer NOT NULL, - hook_name text NOT NULL, - created_at timestamptz NOT NULL DEFAULT NOW(), - request_id bigint - ); - CREATE INDEX supabase_functions_hooks_request_id_idx ON supabase_functions.hooks USING btree (request_id); - CREATE INDEX supabase_functions_hooks_h_table_id_h_name_idx ON supabase_functions.hooks USING btree (hook_table_id, hook_name); - COMMENT ON TABLE supabase_functions.hooks IS 'Supabase Functions Hooks: Audit trail for triggered hooks.'; - CREATE FUNCTION supabase_functions.http_request() - RETURNS trigger - LANGUAGE plpgsql - AS $function$ - DECLARE - request_id bigint; - payload jsonb; - url text := TG_ARGV[0]::text; - method text := TG_ARGV[1]::text; - headers jsonb DEFAULT '{}'::jsonb; - params jsonb DEFAULT '{}'::jsonb; - timeout_ms integer DEFAULT 1000; - BEGIN - IF url IS NULL OR url = 'null' THEN - RAISE EXCEPTION 'url argument is missing'; - END IF; - IF method IS NULL OR method = 'null' THEN - RAISE EXCEPTION 'method argument is missing'; - END IF; - IF TG_ARGV[2] IS NULL OR TG_ARGV[2] = 'null' THEN - headers = '{"Content-Type": "application/json"}'::jsonb; - ELSE - headers = TG_ARGV[2]::jsonb; - END IF; - IF TG_ARGV[3] IS NULL OR TG_ARGV[3] = 'null' THEN - params = '{}'::jsonb; - ELSE - params = TG_ARGV[3]::jsonb; - END IF; - IF TG_ARGV[4] IS NULL OR TG_ARGV[4] = 'null' THEN - timeout_ms = 1000; - ELSE - timeout_ms = TG_ARGV[4]::integer; - END IF; - CASE - WHEN method = 'GET' THEN - SELECT http_get INTO request_id FROM net.http_get(url, params, headers, timeout_ms); - WHEN method = 'POST' THEN - payload = jsonb_build_object( - 'old_record', OLD, 'record', NEW, 'type', TG_OP, - 'table', TG_TABLE_NAME, 'schema', TG_TABLE_SCHEMA - ); - SELECT http_post INTO request_id FROM net.http_post(url, payload, params, headers, timeout_ms); - ELSE - RAISE EXCEPTION 'method argument % is invalid', method; - END CASE; - INSERT INTO supabase_functions.hooks (hook_table_id, hook_name, request_id) - VALUES (TG_RELID, TG_NAME, request_id); - RETURN NEW; - END - $function$; - DO - $$ - BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'supabase_functions_admin') THEN - CREATE USER supabase_functions_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION; - END IF; - END - $$; - GRANT ALL PRIVILEGES ON SCHEMA supabase_functions TO supabase_functions_admin; - GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA supabase_functions TO supabase_functions_admin; - GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA supabase_functions TO supabase_functions_admin; - ALTER USER supabase_functions_admin SET search_path = "supabase_functions"; - ALTER table "supabase_functions".migrations OWNER TO supabase_functions_admin; - ALTER table "supabase_functions".hooks OWNER TO supabase_functions_admin; - ALTER function "supabase_functions".http_request() OWNER TO supabase_functions_admin; - GRANT supabase_functions_admin TO postgres; - DO - $$ - BEGIN - IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'supabase_pg_net_admin') THEN - REASSIGN OWNED BY supabase_pg_net_admin TO supabase_admin; - DROP OWNED BY supabase_pg_net_admin; - DROP ROLE supabase_pg_net_admin; - END IF; - END - $$; - DO - $$ - BEGIN - IF EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'pg_net') THEN - GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role; - ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; - ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; - ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; - ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; - REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; - REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; - GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; - GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; - END IF; - END - $$; - CREATE OR REPLACE FUNCTION extensions.grant_pg_net_access() - RETURNS event_trigger - LANGUAGE plpgsql - AS $$ - BEGIN - IF EXISTS ( - SELECT 1 FROM pg_event_trigger_ddl_commands() AS ev - JOIN pg_extension AS ext ON ev.objid = ext.oid - WHERE ext.extname = 'pg_net' - ) THEN - GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role; - ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; - ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; - ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; - ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; - REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; - REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; - GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; - GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; - END IF; - END; - $$; - COMMENT ON FUNCTION extensions.grant_pg_net_access IS 'Grants access to pg_net'; - DO - $$ - BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_event_trigger WHERE evtname = 'issue_pg_net_access') THEN - CREATE EVENT TRIGGER issue_pg_net_access ON ddl_command_end WHEN TAG IN ('CREATE EXTENSION') - EXECUTE PROCEDURE extensions.grant_pg_net_access(); - END IF; - END - $$; - INSERT INTO supabase_functions.migrations (version) VALUES ('20210809183423_update_grants'); - ALTER function supabase_functions.http_request() SECURITY DEFINER; - ALTER function supabase_functions.http_request() SET search_path = supabase_functions; - REVOKE ALL ON FUNCTION supabase_functions.http_request() FROM PUBLIC; - GRANT EXECUTE ON FUNCTION supabase_functions.http_request() TO postgres, anon, authenticated, service_role; -COMMIT; diff --git a/hosts/web-arm/modules/supabase/vector.yml b/hosts/web-arm/modules/supabase/vector.yml deleted file mode 100644 index cb6ca90..0000000 --- a/hosts/web-arm/modules/supabase/vector.yml +++ /dev/null @@ -1,255 +0,0 @@ -api: - enabled: true - address: 0.0.0.0:9001 - -sources: - docker_host: - type: docker_logs - exclude_containers: - - supabase-vector - -transforms: - project_logs: - type: remap - inputs: - - docker_host - source: |- - .project = "default" - .event_message = del(.message) - .appname = del(.container_name) - del(.container_created_at) - del(.container_id) - del(.source_type) - del(.stream) - del(.label) - del(.image) - del(.host) - del(.stream) - router: - type: route - inputs: - - project_logs - route: - kong: '.appname == "supabase-kong"' - auth: '.appname == "supabase-auth"' - rest: '.appname == "supabase-rest"' - realtime: '.appname == "realtime-dev.supabase-realtime"' - storage: '.appname == "supabase-storage"' - functions: '.appname == "supabase-edge-functions"' - db: '.appname == "supabase-db"' - kong_logs: - type: remap - inputs: - - router.kong - source: |- - req, err = parse_nginx_log(.event_message, "combined") - if err == null { - .timestamp = req.timestamp - .metadata.request.headers.referer = req.referer - .metadata.request.headers.user_agent = req.agent - .metadata.request.headers.cf_connecting_ip = req.client - .metadata.response.status_code = req.status - url, split_err = split(req.request, " ") - if split_err == null { - .metadata.request.method = url[0] - .metadata.request.path = url[1] - .metadata.request.protocol = url[2] - } - } - if err != null { - abort - } - kong_err: - type: remap - inputs: - - router.kong - source: |- - .metadata.request.method = "GET" - .metadata.response.status_code = 200 - parsed, err = parse_nginx_log(.event_message, "error") - if err == null { - .timestamp = parsed.timestamp - .severity = parsed.severity - .metadata.request.host = parsed.host - .metadata.request.headers.cf_connecting_ip = parsed.client - url, err = split(parsed.request, " ") - if err == null { - .metadata.request.method = url[0] - .metadata.request.path = url[1] - .metadata.request.protocol = url[2] - } - } - if err != null { - abort - } - auth_logs: - type: remap - inputs: - - router.auth - source: |- - parsed, err = parse_json(.event_message) - if err == null { - .metadata.timestamp = parsed.time - .metadata = merge!(.metadata, parsed) - } - rest_logs: - type: remap - inputs: - - router.rest - source: |- - parsed, err = parse_regex(.event_message, r'^(?P<time>.*): (?P<msg>.*)$') - if err == null { - .event_message = parsed.msg - .timestamp = parse_timestamp!(value: parsed.time,format: "%d/%b/%Y:%H:%M:%S %z") - .metadata.host = .project - } - realtime_logs_filtered: - type: filter - inputs: - - router.realtime - condition: '!contains(string!(.event_message), "/health")' - realtime_logs: - type: remap - inputs: - - realtime_logs_filtered - source: |- - .metadata.project = del(.project) - .metadata.external_id = .metadata.project - parsed, err = parse_regex(.event_message, r'^(?P<time>\d+:\d+:\d+\.\d+) \[(?P<level>\w+)\] (?P<msg>.*)$') - if err == null { - .event_message = parsed.msg - .metadata.level = parsed.level - } - functions_logs: - type: remap - inputs: - - router.functions - source: |- - .metadata.project_ref = del(.project) - storage_logs: - type: remap - inputs: - - router.storage - source: |- - .metadata.project = del(.project) - .metadata.tenantId = .metadata.project - parsed, err = parse_json(.event_message) - if err == null { - .event_message = parsed.msg - .metadata.level = parsed.level - .metadata.timestamp = parsed.time - .metadata.context[0].host = parsed.hostname - .metadata.context[0].pid = parsed.pid - } - db_logs: - type: remap - inputs: - - router.db - source: |- - .metadata.host = "db-default" - .metadata.parsed.timestamp = .timestamp - parsed, err = parse_regex(.event_message, r'.*(?P<level>INFO|NOTICE|WARNING|ERROR|LOG|FATAL|PANIC?):.*', numeric_groups: true) - if err != null || parsed == null { - .metadata.parsed.error_severity = "info" - } - if parsed.level != null { - .metadata.parsed.error_severity = parsed.level - } - if .metadata.parsed.error_severity == "info" { - .metadata.parsed.error_severity = "log" - } - .metadata.parsed.error_severity = upcase!(.metadata.parsed.error_severity) - -sinks: - logflare_auth: - type: 'http' - inputs: - - auth_logs - encoding: - codec: 'json' - method: 'post' - request: - retry_max_duration_secs: 30 - retry_initial_backoff_secs: 1 - headers: - x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN} - uri: 'http://analytics:4000/api/logs?source_name=gotrue.logs.prod' - logflare_realtime: - type: 'http' - inputs: - - realtime_logs - encoding: - codec: 'json' - method: 'post' - request: - retry_max_duration_secs: 30 - retry_initial_backoff_secs: 1 - headers: - x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN} - uri: 'http://analytics:4000/api/logs?source_name=realtime.logs.prod' - logflare_rest: - type: 'http' - inputs: - - rest_logs - encoding: - codec: 'json' - method: 'post' - request: - retry_max_duration_secs: 30 - retry_initial_backoff_secs: 1 - headers: - x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN} - uri: 'http://analytics:4000/api/logs?source_name=postgREST.logs.prod' - logflare_db: - type: 'http' - inputs: - - db_logs - encoding: - codec: 'json' - method: 'post' - request: - retry_max_duration_secs: 30 - retry_initial_backoff_secs: 1 - headers: - x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN} - uri: 'http://analytics:4000/api/logs?source_name=postgres.logs' - logflare_functions: - type: 'http' - inputs: - - functions_logs - encoding: - codec: 'json' - method: 'post' - request: - retry_max_duration_secs: 30 - retry_initial_backoff_secs: 1 - headers: - x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN} - uri: 'http://analytics:4000/api/logs?source_name=deno-relay-logs' - logflare_storage: - type: 'http' - inputs: - - storage_logs - encoding: - codec: 'json' - method: 'post' - request: - retry_max_duration_secs: 30 - retry_initial_backoff_secs: 1 - headers: - x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN} - uri: 'http://analytics:4000/api/logs?source_name=storage.logs.prod.2' - logflare_kong: - type: 'http' - inputs: - - kong_logs - - kong_err - encoding: - codec: 'json' - method: 'post' - request: - retry_max_duration_secs: 30 - retry_initial_backoff_secs: 1 - headers: - x-api-key: ${LOGFLARE_PUBLIC_ACCESS_TOKEN} - uri: 'http://analytics:4000/api/logs?source_name=cloudflare.logs.prod' diff --git a/hosts/web-arm/secrets.yaml b/hosts/web-arm/secrets.yaml index 7917310..bc5ae05 100644 --- a/hosts/web-arm/secrets.yaml +++ b/hosts/web-arm/secrets.yaml @@ -1,80 +1,80 @@ -borg-passphrase: ENC[AES256_GCM,data:E1O37tZVfr+76hTKEzluCruTO8JUrsTwYbhtlDmWxnX2wBwcQm21ks8LYTkgjRMOAg2pseHumr3HdVGdRz+wzw==,iv:dXj4wS6FLbe2s58/kLdoxrLE6Q7IKMEkKGcKq/v+dgQ=,tag:FtBSFm7LEIbbzebhvYqrIw==,type:str] -borg-ssh-key: ENC[AES256_GCM,data:mX/lV32oU4BXTjAA5T1lQnvWF9geq4bKmf2bCyjoKARVhVrlq9TX/GQqkLPjVsA/y9BeE7yvUdCst8F+qKTGkLoLHU2DgjiDPm2voiBn/x4FO+QQMGl76UyB20La+lz+hs8hNsRzDEsAhdEzmi9yFDythUOzgYLbMpdiOk2aPau6UQhOp18DDBXpkFvqOhzO1QzNFOJzpd2kbKMkbQzIuRbwjVzQyFm4wJmPmKaaYG0C9aobn+qrgCBMjcYtPn1S8GM+nigYsvLOJzdxYC/OZUBESosvAh/KEiQYXLG6iBC6ExonUCJsBBxWDMnXPNJC7RWL45SGySwv5zq4CI44ZSvfXwbyUG80omTOdkbLaxkofNKWIK3tJ45p2MmHhh6qDqSw+liNp6ZeX17fwkCU6XQymRImdKPFJrrs3ZoR3GvzyVXK/vxcvG4cTyJxldJNYeNF0oNJsB3x9svr3vangPgyxfUn2iYoSssz4NYGUNhy6edHjlZ0phioJIarUkdLBqXVykbpEg0Lze5tMS28,iv:b43PmYxF9GJ3NX1C5Ki904lx8amjyQ8Wx1KTv+hIkPU=,tag:WzSGx37prY2dGy2s0RWUhw==,type:str] -vaultwarden-admin-token: ENC[AES256_GCM,data:A+WaZP3rOT8Sr3Fnh/aX4vSUQViNgn2KlFwkjnV9mIK/3m2hQBnMvY2YtSFgLkBEkMomAxmRyIAw+PpWU4+TlA==,iv:QwLtekgMaBaAKeZBb2wvPZEuPYwpP17xOVZOkmOjzFM=,tag:625ybIGd3Wr2pLsnZy9pdQ==,type:str] -vaultwarden-ldap-password: ENC[AES256_GCM,data:Db5TKSQEmpZMLp9mLqV0MB8ICnf6EcgHCG6BkZrl2H9U/PAamPQa3aEgS5yQDDZRXADxnVaeLvvBH/CQlRK5mw==,iv:Ahg6ZiqJHCoJ43yq3WDw4oWRo8JhrQ0dC3w9+b8o4+k=,tag:xetBoKe7aw65nNXD2cVASw==,type:str] -vaultwarden-env: ENC[AES256_GCM,data:761VT3rj6WltBrjEspTRdbOCKcQOt06R2m5TOTRFG2BRHwsSCZP+V3XxGe51xFwB4LMUD4zPjl5z8FR25Z7GdRY6i1DGBlcCSJjJAeMPBY2v+pP2/8FmV8zcgAfOJxu6yjkfg23+q6bUxFxSwMkBUYmr0UnSNdQU9dpB9O2r5vfNv+JkjOZzqgfvN99YBfV5o+9H5wQYTnW+TpV+lsIOeN/Ja8l+tMa8+I4AH1kkNASD6LQ3TEFBuc8IRmUfztEsuCR0Mf7kEcqhDzWac2SC1EA1jhLJGMgCQtRqeZ++VcoR1obgwnMdjC1G783ffXttMJ/Ut8kLjQ==,iv:fjbGcULFd5fSZLL1l04fIzDvlcKvlnlCXsVWMJma4Zo=,tag:qFKfixayRWeV+D5i6Dr+9A==,type:str] -authelia-jwt-secret: ENC[AES256_GCM,data:StT9SXs9pkB75G2XdGVSlVYAJOnDjZFifGETVLkJ3C3tThEKybV/ibhMRZj9z2sE3A126v1xbX7SI7broNxlPg==,iv:bLhYu9vHh2n/nT88Yg7ejXWr1xvJK9Du2fAe8zn+8NI=,tag:cDX7iAC4Vrp9HIf0ZTIPSg==,type:str] -authelia-backend-ldap-password: ENC[AES256_GCM,data:d73smm/wTl2uUR3Z2RMf/AvFcDJvKZDxezrs6DJ7qFLkDWAu/0t8nB/l5CiLn4DQrAKQm0bi7C8mbGmKYTskag==,iv:X7KXpbRwcAMATzTNGmUlDLNvZJXjMqLwAkebsH50uiI=,tag:X0n+mhK5LT4rj5oEsZqZ0g==,type:str] -authelia-storage-encryption-key: ENC[AES256_GCM,data:NdiBiq0uI60VrqUlAB7B9Q2BLYyMNfBoQGL+obb8WO4ThOVFLsx061KjdzPtQ7tlvvhbL2JXpPXxfKnMRpyb+Q==,iv:M5gbiE8iDrPTxwETV3UfZoi3UDwXREhVcnyysdlD8Kk=,tag:aeuTT4FPPnJZGaROOxdHQA==,type:str] -authelia-session-secret: ENC[AES256_GCM,data:S8WkCSF7wbfb1ZOjuKSBDUxcr3Wsqs8m8ZIzTyScU1qt41gdGzAs7wBfTbTdLw+IpcUoC8iJv1cMLZRPrPz2QQ==,iv:/amZglU0DoYN9KWfaYeoW+FfppKNmlOt67HEu3tv5jM=,tag:yw9h1pEhdPGCThj3HLuMyQ==,type:str] -authelia-identity-providers-oidc-hmac-secret: ENC[AES256_GCM,data:qUUohOQMJrBChpub0Wo/oburQBybRCbDToFLziubhttcMqzEzfc0t5958Rd9GVwM3YKqbAfc85omagkh15xNwbAwKpW2CaQ7ExDnd800YkTWS/U5AGDoV61JDb7sl0kpEHhY+DjcqY/1Joy2ZO78cdq1OlDo9X2MyVBJeuLSC38=,iv:K8SNO6385+QLlbRg38hj4eHmqSw7RncFPKy+8blD+Ps=,tag:7pY3ibRYPA+zHrkWgcIjKw==,type:str] -authelia-identity-providers-oidc-issuer-certificate-chain: ENC[AES256_GCM,data:pQ2JmNy7kDLW5hktGUO2Ubxjs1bkifLT5anFdOE4AujJFMAktw4wkpjzDbQwrWAvjGiORG6NryXPg3N51ocRjAi8Stli4HuUT2bpSrmeQHfOP53TEB2CiTSrnp+8vRlwaflPCjH2zXldGRYAwMfKjiJcZODuIicB6Y6BqDJ9a4aSgSTlbVO2/eu4SUnwmXPtZKHkG/3o93qp3Mola9h9b6ZWiKhOD/BZRx9svA1NW4vkgy4wwmLR6kgVbkVDv8Ga/vJr8kKwkwmX9ocT2A4un0Uyzok0bISk4kOcnOEPxvlyiMbYc+dyfNo/czNN6LTsKZU58FRAuuYrz3zSh+5CxMbBDGPgW1m1iStSi+1ahZ1+OOi6Ay/tOs6jy1267qFoTlSm1Nz74dodlOEuXU9ezZRN/oakhWCwiEoADm4yQzUSKTahnsauap7vZoXsEjSTtwrWOlhUxSUIAej3Pl4e5uBYJCgqg9uGJu24U4qaWVnM2hn3bFeTI1vRW17K4WK8JQSvUHpENitz79/VwaNpoRYXNk4/S3rLWkRsRUfI3MyoeCYNflduFjBHExY6JG+DQvtMLGaR5Ih9VkGfbhmRLKVnuE03HMpaB53cja9kEeF8uFqigardBPIRanTvEXyNtz1oA5NdUhClkuOTjaUkI55zZgzYurJkWxsxfQtvSs1Um/VFkdHLTIzyTkE5y9QyZNuwitWYG6eHSjhfvCLlRYp+AUsL1C7CYM9/3RizQnHaXsyyKqoTbjpdk6qhAgg8sE4lssCADM3GwpUzfSnM3wDoOL1TozUnpcpb7Dy+IJIl15V3bJwzi4PF4OGpaWQ1WLPu0g+LZ9sFWtjc8eOqYUQ+Q845I+JfC7nE5MgxGeUQsLcA4beAOXlyfzBvUpHXFlfk3aM3Gzraev6p5f/bKZQM2ZQeiw+mGKh5s5ifIGUSHwjUlTca92ohOSR/HoDbtZGtLsKFjZUseWqu1JHLN02Xh5D9lMrWAHRnTvl5k1rmyUSHCMZNZO1L3a9qSdW0Brx5sX7/lw==,iv:SmXQArwrm7eufINusZdYOBm89FefJia+BYZiZS438ZI=,tag:4QUYxECPo2+RUWY7fD/peQ==,type:str] -authelia-identity-providers-oidc-issuer-private-key: ENC[AES256_GCM,data:GTSvXcCLT8LdMWhAjxG6qYR4hKBh64lF8ZYoY6nkbSIg4/mGIQc5XWYC0Gy6sjKXViLtCDoWx0UPGTxY4VEIA3N47CfQQjCmKOIQjr2R4xfE+F6SpR1kt3DZy8fj4zwwxT822mShZ13qOPXvp8uVzpO1y1ymlopCHuZtAVbljeJLrLniXwHXKMd43N62KnKTCdszGKxY7MdbjzEitVJJo2970TT8jz62PJKMEfK2gklFISCqvMpo9JWbX+0KjJqq3hOklGH9+LbAd4viV5ngTA7dMYWR0nPh0LVyZj+nT0A+6rsG2hLDTnYrYNJX7rlW+DR9h56ZC9JUuEDVLRsUdmz6w6iZmMt6GJW1xu+lcxOeXd/HK/yUnxWKTYfa55nDUZ+GhBPy2oQfw6+28GxnE8exYhhhsSn2KmkkGpBVMrtBuIQkwr8E4wpn3Y9w0eRaWWsd5crvuT2HLa4T49TVwxM93/zxyT7QFvsQhIOzaAhTavJMfRtbCvi92I3Z2WpDtWlxvPQIvFARzHunbAm/2UCl0jykVyoKOL6cu+jyKX0y6koX5UbVQGSJy3y1UyBKZRrthUbhRpTufujvT/uVtO0mbE2yDqnqn0rWHah6wJCuMk3UQR+AJcSgMkdYdLlZsuuYfF6uFsPoBlY5c93yeqjSCqRqJUiTUpVzVJVjdZd4kPIvC1W5Xzd5gqqnCMav//xCwCk+7ByYnWOM6ykSNWniQkGocW4+vDZSgozGpOcYVOTdzdMGwzgnu58cdmP7CxM4o2nLtfemLU/wAcNLaVtPlaPydkXVYkSu5tCi6L7v+KXBbi3q1PKQXSvvBKJCZQmwLNX3I/s9lDgVx3H82VefQR6WHz0oQz8LhHOQai3p9HrFBluzMKCmSngN985ccbRzlXpnxOGZz9n24wXk3GkVyhSIlbuSUX58JwLS5rQOn7g8OLo48HtHxUY5wxFxoK2kyxtgEuZb4d+zRr/JI9D17GS+Yy58fzYEGoE4faHjHTFwu/IQNJyg5fTzx4CuUM+ddgQBe7uKjb3VtHqRIpIVQPXj5fuRyGvoRujgONqmlNpJDFxFLcapH+nagFQzlQ5TJ+ljroxHy63HtdLP+cbn4u5KkJIyfHAMv9gkJf+1lqXBgRa+RxlF05jNF9JZHqjTtl5MtS3zzDZOdYs/EYiULx+oyN8Hfmy9JaFFNMmyTJtIQqodibL1dJ09EPolo2r8gwmLJIvMMHmfpGoGAx4y+BnBw4LC52gGacGqfvTk9pG5tMCsM86d2lYbklXpup4KkUXdA+9w+QLBB1SSwDD9bpLB9ZXC/XHw5iVUL1RsnX179Tzca6t+qUGSlIcl6YHL5Hzzaf77PM87ZGnBV+/UrA8XmzZfCA3BxiIouF2ItadRGuz32vbPQjN76ple+hyWKXhv8L2Z4HmqBK4WExPY5ZX1NbCNMLTD0omr9s/YuOvQxxQraUuLsSrzSOhuno6gMMOws2fvP3mgpsi5382NDAr3xPG7j/bWATJ1MYxdXNLDyYL/jP1PM1chbwcvPP7Ej2IH4NkxeD1bKu9CFBZy2ZjZGHxXho9WBr5+MeuFqbIADnneLzG/xfXohpcreumDIGHBl/sn4GdcQFLg/8jvwPY3VNym2G3LSONSPPwnEVsI4k6WaySTxnrzF3tSMckXKxw5HzvMU2YRQUoIag2Z2ZK+WQpL75r5+KBJW/hRsEkkMqRT+ztBw3fD9V0Ma++HRSdr7kq1//SX1WSkdXl4tW+A5yvsCdJ4kEn5gpqeENYlSpiLabdd7ASCRAB8GkBAx5o+OGPr8D0ntCtHwArpqs6P8wXvSFCpuAEL8WTgLYB76l1RHb+zp4J0C7my1MbBxVl2Xn8WhIWNvPvoXag4ukpUYL+9+SJ5hKDueh+YyM9iTw4pW2kiuxprshlYglPLaGl/DsqqEZxyGc4gdk4z01pXsZcRu1M3Ea6R4aTIBiwCvPZ0Hp0fbMlH8LZnOq6O1WO079kd1PBXjh9jzr20UvK5F3AcJfK6HbTmH+CD2wSwr0s7oJnJ6KMWECSKi+qejSO5qIvpy/59LtDlHhYOI/lBsCjdqiyci9oVevNRFGGaLo8iNf3fWpLrmGfIFkP1VgOVnTm9W4zhuKp6EwazCMTsvKGw+rrVjj0gNtDzb66uzMW/5RV8d//fjaDvDWLNef29sOHwj9Ng4A+udZpRDxcgC5cnV6P3vunFhiFHJz02Y8ZY1zDNMxcbc2NFuDfKKu+ANEj5+gcatYTtsAWFH3HuSSxYvbwUIAj+tMsITYfvrzL0gpuiIgeqDq7DoPUCdMLbGYNznAe6TEHenZ+KeLLJs2+lgZkLmXQgVFh6WV3sm1mTpgxfcL3wwvxI2YrUJg6kRRmWEfL1Tn06XwqH31C+/SWQCl1a394CMNus6/t8aFkYg/YTEHO/O1c9WDBRVWNKQuVTiC2kCJe6tIA7HShbP2ZC5sNYh6lWqIQATM/oCGth3K/GNi85/wjgrSBstBEgtW1h8YshxelDE7xguRpP6gVC75Q+upFaVHTnpw5bwzlkN25y3KuMaktOQBJaoQ6jgNbCuZXCa7kCB2Wh2qApebkUaBVCWgLqDmX2u8F/dF6M/C8+1UpJTZGj7pRR6GMZmMRt27zuipClzSoLAJP1LmjpIHdg68M5epLs0WW3E6I9SRbFeERQ4JCM/abq3+w4xgsOjHi0A3CR4jVNiDaFujEJI6QpR+AETegWDSlKs6Mf2kSksH880k3yBcsTbbKi2YqbzpGXqiNl18GbfHU8hNLfF7dDYtlyeoIvWWrXx1sG9AyPgKbqC1rYhEoZs5CTpdMeaUQyAdnXzxJmCiR16qUP+YAQawTnEjlSmwOAFQxfSnMAHy+cCLnjk6Cc0VoLPlpeNh+HTHKm6etgGX7wbjeL0wS1AW7ZA6bNyZT0CvR8nn5fURpOa8t58l6DDyWhyJwFZP8GUZ0MAbMJg7j6bjkj9B+luRJ7dKsant6kfluH7UR7Ps+Jrfrdhdj/KDexWcgffG74fHYN8TdFBF7OKXD+kXdjjAt1Nx9rIw4FnlENurbw2RkkwMaQjm2Kl1Y3ATNsN6emH0541nnMfbVkGQSmHWMcE0aW0aXSYJw+qjMj89S0rxjonlylf7vsTIm453T8tHRmuRO/UzOpSDSEIbCxBnQcNrJebmKTjkvxqwbJbEfq0LB4t5F+wdqAPACU8oSLtu/hBZBgaIarHBBWYibJKhEnymMJ1WuhzZ+t+ejy6WRbwWQ9YQC5ZMYaNF1A38CIu/5+xp/7SSdbLO6sPq+VpLiOf3kE+rTTYzgZUqVN9NgkBj49RZTyUYVj0qwXGV9td2DRD2iPLSIsq9MSo2Px1iPSpHKkpT3tJNtC/Khe44kzgS9zHRC973paU8R544n0XpS/bJkBp6jx2dQhUuR7VCsZGX34sDlHraxr31a324p3gToNUbrzxfdyR077F6nrGcVUZJKDngoSCsUHTyG10JVySjmvJuPVDM+1eYKOBvY///4bSnVZ25930Hi5KTiI0Y4V1qJk1stZTsAdorxX2zBSQLMt3b1qTAzzm4ClXjrWBJ3HrTL6g7TGMZ2XWblB5jR6yYHA9RVY5BQq1iQoGA4WCkwXxunZBJp690oHEAWQNu3PB8l5Vi6Y1xFJyAoqpM7SZJmqPi3J/A+kYFqRTmjke6US8EFoZS1Cq0u5BdE/AjH3xQAu32ElUfamMdgtJ7jbAevDIzyKC+fH+vhmDkmmUT0IsQRF2IOufA0Vv3ehkQkMtZU4v39itA9H8HXXA/V5JMRNQSLQd91G0dfEZen83KDharOEZPuou3EBoEhh1ohXOlO+gMt35JnpUjobcdNXKm3bZa1VK8Z+oEFDfmbUcR/xrM4S6h4R2sg/U+E4fBDkhJfh456Ebq0ZEUqJZU945qgcWj+4zHkwt5h7XdpnkkKRk0rKQ/VzSU0xoHApMO7aK0YjBQHnF9Kd2j2pK6rizqovexUeVB/Wk0g1g7cY72W/a225/YfoZYpBZFS7/2+AiPNhI8FIey8Sj25fhPbzOZyInsc400gMt0/lHpsBB1ZHML+f7OSFWZgh9z/6OlaBfngw/QAhi7g9S4bM7SJY7Ouo58LoqnMhXxE8tMzvzGrJ1kVvLLi8znYbqZI4Uzo7oiXQI1Kyo6IfSEjL3LUGUfdsagek63WqteQ+gv1j23udXYxz5Fa8IIsS205GiDYNYWmS1RJdcw70maoD3lW1YGLhU6H0hYLnwLpxqGVkTKxVn/2gijSU4mUklNeMZIFS9mLIC5FFA5Nfl2/whOXHOW405gb4Hrf85L1fy6a8,iv:0+CqN0JedhUvs4AWh35OW/cDIfqvE0rtib7ZLlE23Tk=,tag:0Q6+Ee6kQig8FlSNFoCzrg==,type:str] -gitea-ssh-key: ENC[AES256_GCM,data:jCe+/CpRfn5dv5neQ1yzL7nI7D6cwjMohDjDQmUJxHkQaJMUYG0977rYEcZhPhFUCMDNW28J60g/kfrfRjSIzX895LaD25ZZrSbkeLpKywt9zhUqaXnpaPcT9SfQyn+jgGGsgQd3xvi/1fyu6+lwDfQ/nbbF33E/Wo5D2j7o8yL8LbvDjQZkDZlaO4QXTRlhxtTzlkZk3zVmIMF62+PMYImyCdH+bAQ2+12YhO30iETiz1EcXSkz+EtVZj1+pI7RlJeQK2qp5HUJT7+h+hfzNfslqd4pvTKFwUvM33VSoFUR8NRuh4wAu5pthSp4JPZLuKGucvAVC9g+F2wVfcS+ntHKSBW3fWDYCbafB0USSow28ZhUn8eZRhBkhfisxgp1Hh+uD2sgBZUEPJo3AhnEOKC0X4MgWHU2qEi8BiMkplE6j8tVWtZja+le7kroklZ15jwuEls/ZZqWDYjnef6KxfRRBRxu5SrZcHXO/aG3qeZ0qArPcyO2ZzJvU/f42+TOlkzgjG4OSY4lJV3mo/Hf,iv:mBlZOuBvd23enZ1LwiLVIcuzDdaXBMdMrtw4Zu/ZIPA=,tag:hK5UQWZThjkWBf/BKXqMDg==,type:str] -grafana-ldap-password: ENC[AES256_GCM,data:9F/gYXzxzkS/vq3UE1vYF/woYs0Leyzroeqh5F7YV1r2Dnsomxm1AQ01N71wtAqW2aTda0pwDFv94N3qH/CJZ6FBk9wZrbtY5wt63PjvkaQD2T/7rC/BmvSWtddSlU+eSJ/rTilHHEBpFb+4czrRcyZmy8x5vuR+h3nz+n5BGgU=,iv:kFVlGQZF+ins5IPRwOlrT38hpp6M69x/hxZ9lDWZb2Y=,tag:VUh1GVmlzy8vnmPqyWnaKA==,type:str] -grafana-admin-password: ENC[AES256_GCM,data:1eHCZpqjmQKMaD7PdlWZ784shYQw9lSa3L59uE57yr+GRIxpDYgWSh748tcpicMfQE8RlFpq5SZ45BeqtUodM5lxEHG8JIwu0f0X9xvBbm4C4ZoyMKg5zB9DY/39VzV+KPtPffjy3tCpFjNzfoBmw5bVc1aLrhsKtqOreKg4njA=,iv:XAM2leioNVsOLt/EC48iuOx+YJEugdarCZBV+/ybdko=,tag:64MDI6nWc3XMkQSA2/qGxg==,type:str] -grafana-oauth-secret: ENC[AES256_GCM,data:MRrb9+JqQZksdVdKDZJ0GJsBDQUwkfboVXL/xp7gMfRF+LNsIdxjSTeLyXAjAlVGAp9arb2zvVGNfgS0B8Lng3fbx46UC/s6,iv:blgyt4cLP49K384yp4HlL76AogEewwk7bqCIbwB9AuM=,tag:MSYoH8Fcr5qQdHhBLjbRkw==,type:str] -linuxbind-password: ENC[AES256_GCM,data:TY7UBM5yDvUvUTIGjshRT0GtiVrBufpf5g/wJP2CTz1X/pliZTSJ/RRR7hc5TuUPs6nivGnQUNm/1EXD56uIAA==,iv:8cOr4WrkjTsGW5XDAjQaOwbXJrH4D98yO9jJRTn5dDk=,tag:Eu6N31m3sfzN14tzPvVq8A==,type:str] -sssd-environment: ENC[AES256_GCM,data:0up0tN6r80Z7uBgUFHTgd1IWhQE0EeM8DNrngplSjHnx/dMqBxH06liFalfiAB92KKtHr//iBjgMHJ0jtmW8hu2xFSE/QAZ9VZ5BQCyhwn9sSX6NH0SL65aGrg==,iv:3Fs0AxtUdsei7cw0M85XT1eraNIvwONmAS4mE7ns768=,tag:5BWFnOWE+V8C2gFx1JVEVQ==,type:str] -promtail-nginx-password: ENC[AES256_GCM,data:Sp6KjAUz2y+CPwaWb1k75Ca2SX81dGdlcfJJ0tLKyqPzeVQz7arpuC3/0TPNg/zRG4jHchS6NJ2hEA==,iv:1FYRFk5eevTwMzNMkpC9kPDivf+Z4kRa66EhI0NXXKc=,tag:4Wg6OFE/XolDq//I8hh3gA==,type:str] -victoria-nginx-password: ENC[AES256_GCM,data:QIjz+/l7a91No+9EUMDUYsyRpNqHWGn2Ll65EV9rSF+1G4ubiRBVzysYYetZRUrgZxsDu5Q=,iv:eRMYYoMYg+xD+HwPs4muIM3GQ2oC4FzYKMnnXpHp1XQ=,tag:WPwPjFC2v/N1sAXkmMCJ2A==,type:str] -nextcloud-adminpass: ENC[AES256_GCM,data:ORkyUFw7kxJWw45PjIiebBwoLLwGdjxumn9L7627nyAHIUZm2PYLeKnHc2hZsqP/dEs59pkttiindXGePrQa3s0fVZSKrh5g2eGnX5GfhaZgcMe/Gus5P1YMs775mRgxHUfdPkJdzs5A+KmKWa5BLUATarO/dZvLSlfF2suhJK0=,iv:KNIbcDqVGVPv2klixeKEhQxB1/V8KRXl3rtbbPmTcK0=,tag:wRk1kN/5aSUFB4qLfu+Ytg==,type:str] -nextcloud-secrets: ENC[AES256_GCM,data:z6jPujXeek+q5er0hlJXqAHHcKSEPHNuQ3g9O7uGDODqttXX+iXL8N+k2EsTk3baAncR8OQsXdWrKmyR68coNGZZTQ6V6gPIfDK58a3Z0lErBy2oW03apCIVqAt4a7V0w4KUMUisU+ufQWEwIA==,iv:pdMlTt9w2lTt5XSaohGxOhsqaCLcoWFc3WGdV/RvpWg=,tag:okguzCm2iCRxjyKmFmyQAw==,type:str] -nextcloud-smb-credentials: ENC[AES256_GCM,data:2AobSnB8bracurDscSHt/4j8fY2uvU3zZ8f4j6VN0M1Y6i7A8ivSsGNG4t1LOu2b,iv:ogRwat1FWmiihe5xPaxduzNxcHhBGSBG3oM0I1nr7JE=,tag:Tsza9rKn44irm04Hj6XUrQ==,type:str] -atticd: ENC[AES256_GCM,data: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,iv:E2R6CnmzHHO9qOGFROaQc18jyiGXKFH9eDFtWoTRNbw=,tag:IKXiF6hF+FcrLRsQ0ADdtg==,type:str] -atticd-smb-credentials: ENC[AES256_GCM,data:mj+49EsyWKfWPns+8iLmng6uPm9LjPdqyw7D0c6jipV1+FyYZblNCsh/IWZqwklIKnBm8Bb7Whreu7W4t0SdC2hyJfb9WBvrHm8ZSw==,iv:MFpPvXnmAlc3fnPihPlCQE2vZx5v1IHfI9N/AuXp2c0=,tag:hBUKKn9cu7FIC2W70mRjJQ==,type:str] -ocis-admin-password: ENC[AES256_GCM,data:dhrQI4ody6o9IowmlhKG91Ps1T7FQ4bVLLgR1WEuDubB1j//7myLIvaINQ3G9w==,iv:q8ywceZ5ky1O3TQVsx+oMHkIh2o/qYiR9EDvwTqq4PY=,tag:d1N8lq+rVAq2YsI7Ex3yrw==,type:str] -openclaw-mysql-password: ENC[AES256_GCM,data:flTJzVaCc0/KFdoC8F1drrl3xC99I7ZBfR2ARZoC3gJi2YZb2KthJuiRCQwvyg==,iv:PRBtD/xe2jEs9fA2mx2FpPctX5zZ/7ss5W0MlENOL3A=,tag:HToJLKPwo7Jd9eRYMwsapw==,type:str] -pushover-api-token: ENC[AES256_GCM,data:0EneqOqEQAx0UvN9oofUW7wShjzW9RsTBhkyqV9H,iv:/InwtiShoLifQMhkalUjESfiMMidWzYxXdtC2MtHnhY=,tag:j+/X1SbtRLs7yCl4jBn+mA==,type:str] -pushover-user-key: ENC[AES256_GCM,data:iGrwNi9aan36u4qC+/nodAtOg2gEkcWTd6asf7tw,iv:jVUKcU7F7t7aMtimoXPYtHqSyeOTVm7I6XegMNGtibw=,tag:O+1jFqcqMBe2pM2IS6Schw==,type:str] -sa-core-mailpw: ENC[AES256_GCM,data:YMZnEkAAPt1dp5CAZvs+/7jlPRTFKrfZSrnN,iv:W/sbU8FDcLiwTGRvdWtCwKxlZtxVuhtYm0XxhMzzFgg=,tag:OeNtMRzlYf3EniFoJrxzJA==,type:str] -zammad-db-password: ENC[AES256_GCM,data:e9KjHWlZBwaarUS24IvPropjBxxODEkxMVSfrOF3yCwS1Zjwb1Kus+42LHSaXT9PvHHepa3ov2lENBkEAEWfbQ==,iv:RGGm+P2ZldF+51zWZEaeyAypqFbIBwqL9OgXttXlNhA=,tag:Fp/tfeOEm/p/vN8779JaUg==,type:str] -zammad-key-base: ENC[AES256_GCM,data:9I4h5zdDQCvdmfEWiowqfoL5BY7GkPtW58JFO/J/xKKzlC7kVhmKQKaoK0uIcuuuNKbd2kZ0PGsM7x0f/Sk4rgH+nSXpriD7DbsfDF9Cmg/uz2bMgfWBJe5SCFNt5rx5/Cpt6buRjzOxndioNhqH3+K3z/KWr0HuWtpUC4sYXVQ=,iv:Fxl42oTd5lP9aJGgx74qfhNtELVY4UVnLszbIlv8XVQ=,tag:w2S2xYYVPJbHqfyTRWZu5w==,type:str] -updns-token: ENC[AES256_GCM,data:CsCoGIyHCdmzXeaRBsvFAdqmZPAX7U3A2H0ztFywyYU=,iv:tLRqZLqPB9RuxXrc/wcZ5W4nbubta/HEOJjU6wpCILs=,tag:8vv2O9GcPqORltZnlXZcgQ==,type:str] -wg_cloonar_key: ENC[AES256_GCM,data:kQS1G+2XQHzTPQmaZYlkmktVuhwDoPNjdM7yPRkL9bheqbRBaxrBIzFsrPI=,iv:rU4E/yDazQ43MBRaC8ZLkXo0gNf10PIGrjEYRfBpUZU=,tag:39MLYrGOC0eWrU3h3b3jag==,type:str] -piped-db-password: ENC[AES256_GCM,data:OLpltypEEFiUlunYD8KWavycPALJ4ADVorwMCZGXZw+vjO4G6+TDIWKFv58=,iv:QAbJEqgJjnVrKGuKybA9SNxq8D/Nuihcc6Rv8qf9kH0=,tag:NQ7W1qDJeRqe1VAU4h4kMQ==,type:str] -piped-http-auth: ENC[AES256_GCM,data:EO+MN0X62dNEbc4iPHNRQYvcvukTsMIdGKgk+WUNGpQxuupPjGvFOsJoJxjD,iv:cHYqo+iKHPUF5PzPpE0xEFPVbruLM0cfG5CFsnzkFOs=,tag:6f58D+xWsTlzsKd/guxmuw==,type:str] -fueltide-lego-credentials: ENC[AES256_GCM,data:dvZ0bn4cQXuNqemIOBOznK68V67KlUF9yKr+pMrB/9R97A3/HVpvBcW7l97IKaiXvxvU/5LbF14zKAAUGc2tycRlVy5yMSWUWNz904O4m3L2xw==,iv:2XTJ6pilUXm07EazAhQGX1yncqxcTCTmwWjJrwA2A6E=,tag:gzgdcA+l/6HQYKwBnV8D4Q==,type:str] -supabase-env: ENC[AES256_GCM,data:sK29tW/X5+89sKWd4eeq9yVoUXRco438Kc4Ph+r9RMUV3RZF33V2wrZqbCSICEGofhb0e1vOcinrpwCZPcdN0zHfSj0tTsB0lJU+wPozTbSCoA5W5UHPD7uqnXKh7w4nxZapaRTwJOTXJ0+qZWS6dvNQmVue/cq13DXtvTduQ4WyFZ9vapbHamr8ItE+EhRZ+LilppbIK0vOEjwv16tyR9VyUuEvhyx+sjxK7c5O6FDbWiDrGxYV3kKdD+DQLQG+j1GLk5WzSHY46fPOWM+2aK5+6CowdFnGzzmk5FQCythP7rkH4xAFcaVpBddzq0Bwp5A697yedXuhJQhR4D8Tom1/KGbOwHjIp0BQf5HksAndVB816IVh2ijmhznYguVoLXHNUnaJ+c7TIIbhhalvBMuBrSM4AahF+a1/yXFMQICFcbnmCJfPOExoiplCowqsqTU8uwm3QWEfB92vgVoA8vn+LmqlG7lVL41Lyu0HfQGsj/qLTf2K9kPae687xyKhHCbTbw5JP9O/btNoi2Y6qo7npSTympTb4YaIBkhTkynA4HWtFmH9pKkvMx3IUgBHh57EPs46aBCntHorhoBQl6d82XYW8TtdWKKh98LSxcUgj4qD0oV4vK4qd00cf4DjW7uTUGHsAw+Ti06EuWYY4XO5qhe11dKqMHsBO1zsHkhJX4dRiZrMca/3PniT0c+XmEQUCbLSR5m2hZ2R11v0DkADZ2s3cm2rHOFAH/Lm0VClOIqnvQ2hZ6jxzYlSPLTTu5H6OxI20allCaqTuuUlhkZGV5c4mAw7UmrrsJIcw3N7Ra53rJybxxAcr8lCFc1Xat+Ayfm9b1RaDyPwRsysn/msk6z9JKkiDWYCbunmJ3rNLTt4obUXax47E9lW5xY/Vh0Omd27eiOh6uGzBUxDdNEh8tb9vNs3EQe4cgx8ODYJ9t/+zFQUd3lL1zzNNUg06RcZQrAQPLOldsSjEsRzCne6HOydu0cL04s88mpERmUA8Mg5lmrS2D32yrxSRJ6Z7WlnyP1i/yQWy1x3aOP8wmtiqcSbscpYt8Gj71SXXyB07EgKUT5SDRIl4awaEGw6M8hcCA4b6rTdHnMcohXh+axik91zW1UI8xvjvbYO9faE+J1+SWn0UX84HIhrVUUDaCS/CJHQGKmcChKqSj+KRB+XjXWwTdWM3V/fmcYQ85LMiAW/1XoNQLWNtp1uRY1YIpyMIvEVRk1nBwrPiP3gIt2HkD9Zr5NR3gvPDuBnpoPCzFUdiB2rg6TcCk7goEoTMMPhQ3dFug0VswAvFd7nlFVIAdaG4gzsUNFSbmGd/8IG1j6JOJY5baVgA4cYhZFn9Ox+dPJGRN5Ol6RraPr2K04zUfp679dv4Zg9mss+5cVrcNBlzzhWsuZN0Qa1K7czxKKgJQVfEC/cdLIoHPkOZKnBQGwcDGOD+bWRWVVbXpdnC/d1+VdWAD+hiZR4Kzcoe82BTtY2KbNoa+fVJCZM,iv:7pWYLa06a7lsM/fEGXMS5sSfKtbTKs9NCJ1bHe5+UPc=,tag:9mPaObLKBG2bSfNczB887w==,type:str] +borg-passphrase: ENC[AES256_GCM,data:tdqB4ipAqF+gRBYeukt9q4+o+8mec8lHQ17KV1u4rNWPxSgD+Px+aqPI5Qz8uNmIy467LlLfXOLsYMZNN0Z8Xw==,iv:8sBE3Ynz/Fk1Zt+gdDGoYh/udmdLSjtBQnWm9o1WR68=,tag:mmV5OE6uRNNIaW/UDB5QzQ==,type:str] +borg-ssh-key: ENC[AES256_GCM,data:1pz5NDNI3RpaVDPaQR5+nBZyKoZVeox5WZxu4FiRJ5zraDvA8IuS0PG+rib0J/FniXU9Lqxux8etvCmpnHp8jA2rGGrK9UCPIhhYixPu+XIEh0ilgGO6F/ory8D5jlLfjcpK9AlOToXXgPxraFUsr3xW712SQZ1fMMCl2Zh8z/qpduD7idr8nDYvIdVzGiWnwRaYLaoHCS+Tj56QdsIM+mMR4Gs4i/GLjaTS1AepKyCxnV4hDzjPnS0LpvKR5wEUwGbV4RUGWJVEsMScCo1CWy9VnZCmN587sOS2fqVQEMXh7PCVZ010X61ynUebd3MwAPRySdxpNZfQuqlidCVUPmsxpa39PbeHBFzXAVWkbiB6sRQsMo0k43JP+qvQDUAhNVVRvibhtExRM2J7ONolIdHOB6O1dieosnPCD0dUCj1bIimJHTkQy6bXxErQYDW/5DnMtY8mNJTVJh1V65+FIT4luKxRxJZzWZz/hcz43baTcA1ExditgaRDrdLySDiGs4BkD9i8wSvkdbmloOOe,iv:fDjsfXl9SXdS7pPOVP0cJ+DDUImJlTBsOTiwXTge6HU=,tag:avzEFeFEH2WZ4pNkYHiVrQ==,type:str] +vaultwarden-admin-token: ENC[AES256_GCM,data:sQ76TnXNSbrSU+Hf3axCG2v9bKXJ8jY135eKQ0D6wPTTAdl+L7Oi0VhubPcO9xuud5+DM1t3AIA9pETDkrMLew==,iv:IQLURBw82K5f+E+6VBTjWmNQbk1mNiYk0g+Qvn7KLEk=,tag:dTr5o8VEcwUbljE4uZiS9w==,type:str] +vaultwarden-ldap-password: ENC[AES256_GCM,data:hyu+YJJeZSWEGqfoEi9Il2mHGvDbzN1rJgib99jkVXx3FBI/cHh+3Pxc2QB7ipjB3Vtz4aHuiVEYMvwlaO+Ejw==,iv:tWiNkgFooz1KfGiB9M7QajirPem/z5YeDFNVVl1DMZo=,tag:pUuRCRJVfSWdt0btiuhq8w==,type:str] +vaultwarden-env: ENC[AES256_GCM,data:zE8PRD/2FQAgBPj5nxZHC7A4uC2c7lgBEHjmgeahexWI8tTiE5arpogTyArdRsWJ2ma7OqhngXbSR2FyiZVFX9yPbmNHSrr3+RnX+RzvlcuvcA5GLA+QMZr9aDUN9+IvlY6L4sQupvqYBLiMjy51oWywe8QundxYnt8UW31haVjuCtANiSQBxOWAFikIaSwCTFXb9taKUqviZ+WBacMJx16GhnXBMtBegQ0/VQtXLEKaZ00PDVhZ8xf9thoMaKdJdZookBWZw6Er3A863vuTJqQxPC6Jw+6A0+myLtNgHBn94lUWUmh6cipfwaFWGQAvmCf8B2Fzgw==,iv:2EWG/4G/+L3IZSMOeK/7hT30jexXDccvz0uu7Galtx4=,tag:m59TE0Hufjv7x9MZaZxyAw==,type:str] +authelia-jwt-secret: ENC[AES256_GCM,data:kbLosJfjNJYxpP+nOF4pOoJMguJdlNy0YFpFebUuh/gJLwBaJdGAtkOrnYxn+tD7Vy5jAjSrla91x0q4zGqaMw==,iv:byILGt+YZZKZq4S1hl91RKV2F4LM8d0XIM3NptPADl4=,tag:qURHQGytgJZOwJEmX+52mg==,type:str] +authelia-backend-ldap-password: ENC[AES256_GCM,data:8Y+tjUIfDJDBdwiZbQojXDvT15F8PQmdGiXvukCjbAFBzzHWb4uzHzfpRhSlP6l7pPEScoAktF0xmh1+8Pczgw==,iv:21oQPsiVuaXrxInwO0muPQ76KoeHrnv61qNBKydoVD4=,tag:aJH+jIGAe70hjvQe5a+wXw==,type:str] +authelia-storage-encryption-key: ENC[AES256_GCM,data:wbo27JJ0GOE9rqWb4DhDmETusk2ApaTpoEd62CtvnrcY0OpTl8CrbkUrtKXImO5ZU9L1j1YjHOslVdJbQPeAvA==,iv:TYqE1yrT3L1odhmxE3f50FRxD2O8257XOij7ZA3wMbY=,tag:RFzNTTGyTbb0Kmz9ACqW5w==,type:str] +authelia-session-secret: ENC[AES256_GCM,data:qxvO9q94MJvRxS+ymf4XT4yU5U6rLpid+6n+3gBIWFEB/wokKVuwqhCmvcF1Euz8rVjQ0ypgGMjRQVBXvmmhhA==,iv:zKPtNJUBzZLFB3DnRV0n+9YBN+PNVHZdQhCC9k1G38Y=,tag:b4WPiqwzFvHIzVb5azv2Vw==,type:str] +authelia-identity-providers-oidc-hmac-secret: ENC[AES256_GCM,data:0ilRneTzMbESwiU4irhYGVkYCrzZFoNzAcsUSFueofI3UIav194OV2+Ut2QWAUZIJM7EBxw30HhykrfcPg5Ehtxwva+/cN/Am9JJjvTwuyPDEkW2/l7wubyhW5tEPulQgokdh91YsSLXWuHc9zgSlMdbKonulGo5dr4P1wfhJ6c=,iv:9BVVdB7/uSB4wyr4G/yXTngMmcqaJ/gm7bZBev3SSA0=,tag:kRkZgTCnQWDgzhUb28KNGw==,type:str] +authelia-identity-providers-oidc-issuer-certificate-chain: ENC[AES256_GCM,data:zskH55WXXCUVOZhfewPf1PRTkD1cZIZv0nRdHTepR5hPXAWcClRdi6jytnlpWGL8xaJQ/Sc8/dKe7r919ejlP74YPkscPqPuL7fNh54/AlDKmkFPblUE66aZcF9kJaawPb//QcdNOgwQzCUihlcR3Isctt8qnjRdleprvqQAmpmQfQltgdGVlWwZbzy8QzhuF83BsEC9rdJvgZzBNkA05F6CGu0JeVw/YqV8ZrO5snEQAebNFY/n8mygdMB0bh3RlrFtDcqB5VGwa1lCZpEIlbZz70v5Sdwpv150ns9zP2YHgRDcK91k/4BI1IEmHpDjXp1zQmoktJzjcpUH/AS1gZ4AAuuXeH9cCGepCf8Yzc2jKqVGq1nMiQTKUAKfct1RkV5r2OQgjlrDwPy7FyBdeoJB1IEzsfjaS+/N4k4dY4V3vWJZkkREvAzoNnHj3lg/YomQ+G8tCzX3X2Qpv09NtEjPPTWyHgl0xuO+V89HpcdEkh7m/zG8ByTPSzsWWcdiLXmONZt4E7xvDa3kY/TtJzoXQ+UfnuNyzz6/E96VpJj3tndudV6FAw1Pw3lWkYzO6Xm1mMx30UvbkIBszzLCfSJYkeEna+Sc3goDWUIVB7f2Dd+16ThJRnYso8xO1DEvvnPB8lvb67HbY32EL9fy4bMazMAmRa376LCXHwHZ4m1m1rE+mDxk1sB3Lau4OWp10aIIK2GDOw7Z6BmvsLT36v7iueP/iTJB6KFaHmHClMM1fGktjTxCrvNbl0v2nPsf5HL1GnUK3O02q/z0Ok6CQMTtYSghC5Sx5I4r21BjJkgleKl+Zo7gQWVkuSsG+09n22RDlOR2yHTnVPzzHiylykBfI9B01D+feAwzM6Om+WPLCkL09qg/oYBI4HF9IXTlSJ9nMzzDnLzlyIavmAVSvWarqdPE5ygnQiLQY98XbQAYOnvxzU9WRiq9aGWSGxqQUgvJGeoQ9YBwXuz8JOEXS6Ajl1SCX2nWhH5dK+JxsTVd6HEhk31mkJ2TB31ZaK+QGnZoBwyhFg==,iv:c4FHCn5W4qKLKdf/7ukTVw9HW6KiYPde1I61gWSBED4=,tag:FH/B2CkcOQoXjqpiA5Z+Jw==,type:str] +authelia-identity-providers-oidc-issuer-private-key: ENC[AES256_GCM,data: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,iv:6sZT9L4js0G3Gqb6zoFhAEOxjjPK6klZElHVdpJ83uo=,tag:UBAhUBMwlQ3tNCiWlzzP7g==,type:str] +gitea-ssh-key: ENC[AES256_GCM,data:8iBhuTg4GLslB+6nXh1RRWLIFsFOpcW/vvGltsXpG7Sz8Bmau1i2IAJM03AauSm6PeTHVpIqVbX+VnHGs4SO1Ld1D+2n57RrA8PVvSRyNo34Z1nwA9Zk4Y2GVEYAyFIJhFv3aUFL2YX7Y2yr01kiNp+YR8nBxNwSuIKUgIL+vFyTfLp56c0zKeAKD3B1krMPnfD/Jw+cfgQFmAZoKAOddB+P2QilPN31813Cdg++lXYm837Uu7IhlHNdXWycpF4tw+QMaIML+FS1Q2KbmhfuaUIqgK1EZ30VZMsUlclRy9PegKo2veaAdhQhizW0+0sixVYIrsAzhy7oaeMg/iHGv2MGCFogT0bSbV1bNM2+D1O1IVyHA1Hc2OdEBC2OPyBf8938VRJUf/1kFYcTf/RQR5hhcz0kZq7sQW+FcFdyljhpUPdggluryj7WeR4yjbyDYCVIQf5FMu3Yz04UM14Jh5Wegd0CHEYNOmh0Es12pgzUC/l2oo5vxdwcMGOIPrUkqm4V7u1psrlDb+nrPhOx,iv:Mk5+HEUUe+h4XeMpVhzV3+ntTESD+S/Z7iOc2vpkIJ8=,tag:87HTy4/rzuvjYUBy7vowZg==,type:str] +grafana-ldap-password: ENC[AES256_GCM,data:OqqdEMpq8/GvnBncfbp5ZZZKgpWtWYAqvxlkaQHdssP34bUhMYHhclr7vp6vb6WQedlnxdfhAIsCUysGQW3YWSOb1+e5Z6igPpasyTWhrDPRsGgpkSRrkg1gTjQAY9MGp1r6a1zRsij3VCS8mImhqiXDusnrkVJOx1riilJ/74s=,iv:EgWzKPailuyx+ciXMzu4KLo6W+QMHxTbABhZHJbQ6+U=,tag:ezW3fvitEoM9yN0EqwThkw==,type:str] +grafana-admin-password: ENC[AES256_GCM,data:FPT69Bd1GhaLzJfT4SkljkcaVDB/joi9F2hsostVjNdWxAg4iqnMN6bPYeyvaQN6tELsn797wO/nIr2LrZLordX108La9i5Y3JOaKc52nGPmTytcFjg6I2K1lWl/V1nQP4WqDXpJstD+AHUUbo378IybhWPUmqNWkg8+xH78KG0=,iv:n6Uu0SDEta5ZoEc/Mf31VGSviRntUBvIz0QE8A9nvHU=,tag:/lZZUrOs6Q6AtnR+fsXwXQ==,type:str] +grafana-oauth-secret: ENC[AES256_GCM,data:GDrAi5y1+bwA7kpg04M3xxL1GDZUGfkSnWipLaZG0xPT5sJKlzizZznHuKVvnKuv/+RhvrqOoOlkqJU1S8cnGWE7ZBesMIDV,iv:dNkhDjitrZQIN2yxtr4BemNwJOvXhvxMFNznJzakZhU=,tag:zt+gNH6w4IPwAyYmhqlilQ==,type:str] +linuxbind-password: ENC[AES256_GCM,data:FYYID2pX4j+p2wGvA8C/d9pI2HjflIorHttsjqNpsqfIskCt8uuYVgxxT1KE3eFJZ44TwbO/Bn9m3sqd4Afcig==,iv:JhsbAhqWV2H/SYmDEMWj2gotJ0pMQU/XJmAYkW3TlxI=,tag:JbeH7JOUZ/+OPa6aKgtWBw==,type:str] +sssd-environment: ENC[AES256_GCM,data:jTli4rpUIJfvlkyTAlLxbSNnkGnRt61Jh7geUPY5YGUVLWOeqZWmIcUHNuxiSTHzkEbUUffYdzf/WcTAM3ASt7rC3+r+iEZyQtiVseCUfNOZmYkyVtvxiC/uIw==,iv:Zn0Iski8AmowJxY21xhuMvDEre1wQyEJWoc4qFbB+xo=,tag:QKzamd1wLNw2QXDqFl4+Yw==,type:str] +promtail-nginx-password: ENC[AES256_GCM,data:Gr9pkbRWoOtWhIe0k8jKQT7JxiApy0qPEB9AtPNuhFivixk11S98J23Go4Y7ewSKd+Uh9neOVil+mg==,iv:MK/53+xLWShQAnru94Q8GWOlUn8gNFoR/ai3ULadK/0=,tag:J+Peq/Fx4NERC4jYh71rhw==,type:str] +victoria-nginx-password: ENC[AES256_GCM,data:GrZlgcVuzSO/+FwZoewBEgnBrMmd0gfGn7MvlnTsiVPJVsg73XfyrABhrKhuBvaxET0G3dU=,iv:HJ2vyM3bL0lnIRxSBW/mooEfof74GXgvwlrRvrZGIRQ=,tag:wOwIKy1D2j/mEA/yMHQ1hA==,type:str] +nextcloud-adminpass: ENC[AES256_GCM,data:7SOBoH4Gd0SubsNuUQ5T0EDRhjiZU2ZmDa8cM6WSeU6KFNOdKq6I5nLtr/k0Cmds4XItj+ikDG7c/0AfoD0XiIyF6zvVn1/ObTQmALHXzAoKZlPJAKy+zrYJR2fpwuOLcZ6hwkwlTSJ2LPASPM2XOveXlXp9iemHNybe3yUlxk0=,iv:JNit7fGK7iumZDySI27jFFsJwSlQ37zwOJkPozRbuZY=,tag:qHzf8sl2N3qzvuc/h4X7Zw==,type:str] +nextcloud-secrets: ENC[AES256_GCM,data:huaByUaJp7lzhlLxklMd9L68+L/zUrcButs/B3RIROreJEGIfL5HoTernA41q/ILrnN+VdxqnmhWFfWBAH9jIdMvzaX2W7+OVaqVobKGptcS4OEA3Ae8hQqYWUyHNQ9wb9OsKqbUOqNurfacaw==,iv:HflKiZO+LwQvkoGgacJOOyH8nDxOAlbZgBjkMnsLgy4=,tag:9Rj8s4i28n5XUBPgiVBf3w==,type:str] +nextcloud-smb-credentials: ENC[AES256_GCM,data:Uh4Q0Xn0vlqn4MdQ2aDxRmqXHlRvJJErfp2FV8k/kGckU6XMfdywYLgzzHemddVR,iv:BVh3nMUvC1lntcdMd9ehGIm1WNHOle7CoMlnfqhj3n4=,tag:Ue3igBcj3rUw8eKPuhUnwg==,type:str] +atticd: ENC[AES256_GCM,data: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,iv:l1jz+NiqmD8xrrIZ1F30u2hGzU0Z/zccLYB9VN9ZFaU=,tag:q6vdceAjnvEYbQYggOh4zQ==,type:str] +atticd-smb-credentials: ENC[AES256_GCM,data:U4JHFUIB6s/5igOWWv4NQYNr5sNCv1zUHLiHl62vb47mf34ZtX/YKtlip7fewtKYfifmkIuegRVPf2tz4S3O/3F6CpALLIzY2LYB+g==,iv:N1PezIom3Jqctkh0ZNuI0XfExUxTYX6hm03+r+MrTOk=,tag:cR2bPpaN6pLFvIcR+kCV1w==,type:str] +ocis-admin-password: ENC[AES256_GCM,data:44qcM8qMUGaGlnffoILF2wC0wpYFNyqml+t+o59TfM0I1tBRya1ID1yL/rd4aQ==,iv:/44TQUkpT009MqXp+o+Cl7GbC4FDftlt9fGVIEqgvEk=,tag:oXP8LZeWfhlYDQVGb6d9qA==,type:str] +openclaw-mysql-password: ENC[AES256_GCM,data:q1pWusf1KZuIiW6hP98ZOSepdQ0auiGfsyxAzWM1eCyVg8L+EOnOml7BLBnOrg==,iv:gMP6durtZrPmHkvyY//Xc32XFMjrLGOgdjt+b3R7IIQ=,tag:I/bYET+bcDo4flwjI+xKyQ==,type:str] +pushover-api-token: ENC[AES256_GCM,data:SzegegBvjTVZoSPZlE6+AajWQpuhsxscEgd8UN2Q,iv:oHZiT/LNjfL7rIdhw9J9wOi4oM/O4qtQiXBrkYJ4AZA=,tag:i+c4UacnwKXjqvXjDoaN+w==,type:str] +pushover-user-key: ENC[AES256_GCM,data:SAUzz1twmSSZwQ3FBNun1DSfsE2gmb+JcfoSRGkX,iv:Ei8MXq/Y0YfOGnODwsJNd1ie1AusNhldqylf1MrVj5M=,tag:Wzk4fy5SbwcxgvzmZ93PAw==,type:str] +sa-core-mailpw: ENC[AES256_GCM,data:6SRPg8no5EgQHFskZWVPX/9+OSDrI0jCE+oI,iv:Difm9K2f3UfJ/6ZvrOMA9vdeY3Cqh/MN1OJ3dFktxmE=,tag:1JhxMU+eE43xmKwY2KX7oA==,type:str] +zammad-db-password: ENC[AES256_GCM,data:FlCUVlIW9mIxNdTApXZ/C4AihH2dx7vNcG4HxRJ/dhgQ1MQWuCoG4JxNbqVtySsZywhRFjxZI9rhlo0U8nuRbg==,iv:OP6+rA+n7MIQHH9Ip3GOr/bdbmBu/tTKX+EWrtdOkZc=,tag:MLab9QtuHFMjWVy/+sC4rQ==,type:str] +zammad-key-base: ENC[AES256_GCM,data:UwXUoxBUJbvQxk7gqIp0bVu5dOKhGQcl3ngFMLfFXBsUOXMgQEE6YEolX5XIsFyC2DqgCC2DNABt1D7/0NRUL5KGOvnA/P/2SjnwYTeaonZ+oO9WQEk8ZIP2y/QMRjv19AhXtnnUfuSsXlUgPfvbROzo6Si27o5KLbe8Mgdy21A=,iv:iJ9wqIvEEXmBrbxkIroccaECXl5YzEdL7/S9UowyaNs=,tag:N7w5PvuZGnT1mbA++ulh/A==,type:str] +updns-token: ENC[AES256_GCM,data:k/X52K1L1Fm8Drti08sVbIDwuGLwhEUHVRvSlmPp4t0=,iv:4vxz/YduOZ7shs+eIutTITcs58TCC+FebvFZ2T5I0Fw=,tag:bU71WgglybMOMctv+kokGA==,type:str] +wg_cloonar_key: ENC[AES256_GCM,data:t8avIo0y1548SGuJhrctM/A2o03ZZ2TC5QVlKKoyRIDs9nMF6vxI8LkaO2o=,iv:Gr4452tl/MIbp2u2BGvAY/cV4FhYuZI8FBpJOdVZSlM=,tag:Oc6qVqPh6Mjgch42bh/fyA==,type:str] +piped-db-password: ENC[AES256_GCM,data:7tAJHnZWExOJNDxjqWAcLQlu1JfzA2Yqr1djDD9O/esrWczsOaS4ylClHQo=,iv:zSrd367s9TcicCJ+T3T4gPXvZ0uL4IA81AHWDEw+RJ4=,tag:juCd74d1c/qGtP6qwEfTqw==,type:str] +piped-http-auth: ENC[AES256_GCM,data:0bcLfpsuWXFJEbXmzpvUpO7pQgt0HDAGioAvUwkAkwnReCRVY1Xk320YjL8G,iv:4SgDFfeviPyLRkQE9cjo6ommeVwPrirV+u8To+2L9UI=,tag:VkcwKWSh2ILiTz5ZNF7Wpw==,type:str] +fueltide-lego-credentials: ENC[AES256_GCM,data:UrHRbxAuzghXwTqvfbxueuA7QZbzHvUJMOU9hGMcpFDBIuXnXMBEyV9DBh0hi8K5jlAFVvo8bYA6KYrPGUGcjQ9WN+2ytZybrNFiQm9jghzxjw==,iv:A2qpq5uodE32pZkm5kUktZBcr1cyL1Crp79Tjqg5geM=,tag:NsFMEwQyW0Q0yYi06sFzhA==,type:str] +supabase-env: ENC[AES256_GCM,data:hp0i+yDutgZgaSHP+KLTXH8SnfqGQ72WNRVHZMk2BFKU2w5kLZ8VaMaG35FOX6PW8L4TKABBzStekdLAFrCCyQ06a9D/3XT0GwzcJV2goMXm2ZYd7hs=,iv:jU3JnUyCTWzfzz3H3ih5Mx970iQ9K5BWyUZYW5zhz4U=,tag:on3C6Gsob2TUd+yTDM5FlA==,type:str] sops: age: - recipient: age14grjcxaq4h55yfnjxvnqhtswxhj9sfdcvyas4lwvpa8py27pjy2sv3g6v7 enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhTWszRnZUVWI3VGJsVFVG - VW1sdTU3K3hnems1bi9TeGI4RHlLanlVN2xNCktQZzRsaTlwSGFlakI5NzhTL2Jl - c2VUeGdDY0lTRjBmSWJuS0hNSnRMK0kKLS0tIExKTDBpOW45MGhNRGhjTVA0R2Ez - cmRkMTVuOEdSK0NxcVVUSWZnZXJnaUkKCpyj5em3HIfpPciF6+PCda64C7fYJ5xB - dgTTbcJ7HXm+bn57dd12FOMlLZn3xYjV6/JK/xAm3AaXQIWhi8NHsQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxYzFWaStyMFVsSk9TRkp0 + eExNL1AvUGl4Skp0N0ZrcTFWc1NaWkNrQmtrCjAwOEMrZW94S2sxcVE2SnRHeWc3 + NEZZTjg2ZVZ4dVhvZ2xUWjlmTjA1QkEKLS0tIG1YdWtBYmlHY1ZnZHFZcFFQRXdq + TGgxZkp1bEEvdGd3VFdxYXF0eCtHeUUKFei/CwLwc9spgzwExzaKAG1/p4SFNdUc + i7tG8ZdW4d0DSNtxiHJT4x8M17z69U7kmTj17ioRsd5hV+JuIYmhQA== -----END AGE ENCRYPTED FILE----- - recipient: age1exny8unxynaw03yu8ppahu5z28uermghr8ag34e7kdqnaduq9stsyettzz enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2Y1BBZWxNL0ZjR3dBVWk3 - TlpRTkJnWFJCSXo2RlhYQjVueWplNW1qbFNJClUwU3U1aDRWUG15OGxnUkNmQ0Z6 - aDI1TVltOE1qWXMybW0veitnZWQ3TGMKLS0tIDc0cWFpenFkM1k5MTk0d1p4SDFY - MFNxRTAyUkpRb2RWdWJvZHBQMGtoeU0K3hfwA3jT9eidPeN6LgD4Un70CzfK+OA7 - WEq98tdYF0I65y11oMKW0wt+CWq05ygA+Wgxb2zeAX4xejTuXA4wjA== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaNXRaOVBKUFZld3VUVGJt + NTF3YTEvOWVFZzI2YW14M2ZYV3ByUHA3OWlZCnZZbVhNTkFpYVAvaHFpVDkxT3BS + dFFLdDFFVEo2cnFyTk1CMXMvcWt2T3MKLS0tIDlJSlo5bG1ZRjFQaEpybjRCZkh1 + bzMwMHZMVWxobHIrMHZBeDZMSkwrVlEKQbAMCacyIllIC0lZakWB2J2iVTdK5qdM + rNObc3rq8PZkvJMxeTDt1mVvLIOJU4fUn8UCMx1pa0Wz+NTkKkkUUw== -----END AGE ENCRYPTED FILE----- - recipient: age1v6p8dan2t3w9h94fz4flldl32082j3s9x6zqq7u5j66keth9aphsd6pvch enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtVUZQbEtxZ3RXQmowOUY1 - VTRmZTRoZ2dKbzdEU3dKV1ByaDIzRUVTR25ZCnoxUHlrcDdiREFKTllZMThRbEFr - empRV1JxQmcwQVBBWEFFUUNsRnZyMFEKLS0tIEJxTUlybTF0YlVmK3h3Tkt5a0Yx - TjQvZEJBKzlyNDhaNTBMWmJ4N3drWHMKr5MZlIdKupzG/s2snMGABdj4FJ8zAZMz - Egy1ifZNNQd/JgtghEQlMa0kQGYYOa9tsII92MR/WReD0ICCy/Q24A== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQZUR2cFVxUW9TNjBLNFVP + cThwVFF0OGpvNnJ5VGhST3ZkM2c5Y1VUY0Y4CnJ0ZFhOYWZ2c1doUmdJZVJRU0Nm + YlI1TlRkVUJyc1dHenRVZGwwN3YyWDgKLS0tIC9PN1c1QWJ5c1NtSnV5TFl6NXlR + aGVLUzIwWjdwWDBNSVdzSlFsZjE3MjQKyX1pyL3Lf/Epfqp4UJWmySMJps/1IZxb + levsN+2CvhQNiFDaknVRQ7l1JpHfg1GyhqerjlGNKJQyA0KoBBZOzw== -----END AGE ENCRYPTED FILE----- - recipient: age1ylrpaytkm0k5kcecsxvyv5xd9ts4md0uap48g6wsmj9pwm4lf5esffu0gw enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiNDVtYWJrc0pqS2FIdkRi - RjRsSFN4LzZicUJ5c21Gc1BoQnRxU2JIeEZrCm5xQTE3YzlrY1FzeW15S3N2bmR6 - L1c5enRESmY2SDlyTXQ3dmJBTFovc0UKLS0tIDJTMXdlZFF3ZHZGOVVabHZ4ZXdD - MWdMYitOVlREenB3Qi8yUHBGRVcyZk0KAIfJnuCiwVF1J3EE27BaXMOW4x3lI33C - A8TSnLkRc0/bMYDuBXelcy/KOf/WSGQQyzYh4DpzTTkvxu3i2m7Gyg== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWeUo1Y0d5RjduWDloRVZH + NUFIamg3bVlYZkI3WGJqVDVLTENoYTZpVUhBCmdzYm5qUTVXM2hWYVN2aGRKM0Ra + TUtGWjJZSHExRlRTOTRJNGZSU2ZibU0KLS0tIHE1MUZYOVFNK3FudnYzd25NZTFp + MDdacW00M2wwRUtsMUpwRWxHOFJ1TkEKmBULK5JZYwVJAoKgcM8GPXXto6QogDA9 + dTlGnMiDxmfNWFbA+Fl1gb6vw8rC/ufs+Binf1TibD413ezK4JNE+w== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-04-24T16:56:29Z" - mac: ENC[AES256_GCM,data:lE/HKsa0qP7ngt+7zGZ6NHLiQuP4TvZhUsF5cGZ9AfaV2g7EFzH8WW9oMRDvcWmUsuD81MjIDqjrpP/NpEYkjBlTYP/k0WmoCNS7WQeZ3+buyGXzk2iwqQ2WzW3uiNJmZF2iFOBWp8wtu+4NxgNq/5GCCXlfmqGT9w9K8q0BXmg=,iv:iAgWtEIv/+nFTqu3oj9b9oLvPDY/fgpmVjPJ+IXFrYI=,tag:RW8czu/R+tmnjePib0QY1w==,type:str] + lastmodified: "2026-04-24T19:14:56Z" + mac: ENC[AES256_GCM,data:JvzlrUYskscZJuRQezku0FegWl5wL3q9BmxwMchqKyKkfr/I+ujZTKogn4iQMiYgy5B/zHIgJhHwtgSR3/CCVXF1M/PLqRoIdhBYgMGoVVx9e7xt+TGd47cL/9LHVHe7y3gJsP2ZkGJBHEMy8cPF8dXYFKUkZWR9AxY438vqYuw=,iv:VMN+Qc/DvudTnKI2x/CbS5UWOEShDVdOl95K9Zccfv0=,tag:it/nLuWMpUhDrxi25m8vtA==,type:str] unencrypted_suffix: _unencrypted version: 3.12.1