From ca94282552f11bd813e42cbbd7a94f9558335bd0 Mon Sep 17 00:00:00 2001 From: Scooby Husky Date: Sat, 22 Aug 2026 13:08:22 -0500 Subject: [PATCH] GitLab cross-site replication Phase 1b: secret material sync PushSecret (home) + ExternalSecret (VPS) pairs for the four chart-generated secrets whose values must match before Phase 1c's Postgres replication goes live: gitlab-rails-secret (secret_key_base/ db_key_base/otp_key_base/openid_connect_signing_key, all in one secrets.yml key - confirmed live, not four separate keys as first assumed), gitlab-gitlab-shell-secret, gitlab-gitaly-secret, gitlab-praefect-secret (the latter two also needed for Phase 2's cross-site gRPC auth). Same pattern as infrastructure/authentik/manifests/ha-postgres-app-pushsecret.yaml. Co-Authored-By: Claude Sonnet 5 --- .../ha-gitlab-secrets-pushsecret.yaml | 99 +++++++++++++++++++ .../ha-gitlab-secrets-externalsecret.yaml | 87 ++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 apps/gitlab/manifests/ha-gitlab-secrets-pushsecret.yaml create mode 100644 infrastructure/vps-standby/gitlab/manifests/ha-gitlab-secrets-externalsecret.yaml diff --git a/apps/gitlab/manifests/ha-gitlab-secrets-pushsecret.yaml b/apps/gitlab/manifests/ha-gitlab-secrets-pushsecret.yaml new file mode 100644 index 0000000..4964572 --- /dev/null +++ b/apps/gitlab/manifests/ha-gitlab-secrets-pushsecret.yaml @@ -0,0 +1,99 @@ +# GitLab cross-site replication Phase 1b (see +# /home/scooby/.claude/plans/jiggly-snacking-iverson.md) - pushes home's +# chart-generated secrets into Vault so the VPS's ESO can pull them back +# down BEFORE the VPS's Postgres becomes a real replica of home's. +# +# Why this matters: the GitLab chart generates these per-release, at +# random, on first install. Home's and the VPS's values are currently +# different. Once the VPS's Postgres is byte-for-byte replicating home's +# rows, the VPS Rails app will be reading home's encrypted-at-rest data +# (2FA secrets, CI/CD variables, integration tokens, PAT digests, +# application_settings encrypted columns) with the WRONG key unless these +# match - Rails raises OpenSSL::Cipher::CipherError on boot otherwise. +# +# gitlab-gitaly-secret/gitlab-praefect-secret are also needed for +# Phase 2's cross-site gRPC auth (the VPS's Gitaly/Praefect need the same +# tokens home's do, to be trusted as nodes of the same virtual storage). +# +# Same pattern as infrastructure/authentik/manifests/ha-postgres-app-pushsecret.yaml. +# Each of these secrets happens to have exactly one key (confirmed live), +# so one PushSecret + one ExternalSecret per secret, no enumeration needed. +apiVersion: external-secrets.io/v1alpha1 +kind: PushSecret +metadata: + name: gitlab-rails-secret-to-vps + namespace: gitlab +spec: + refreshInterval: 5m + secretStoreRefs: + - name: vault-backend + kind: ClusterSecretStore + selector: + secret: + name: gitlab-rails-secret + data: + - match: + secretKey: secrets.yml + remoteRef: + remoteKey: vps/gitlab-rails-secret + property: secrets.yml +--- +apiVersion: external-secrets.io/v1alpha1 +kind: PushSecret +metadata: + name: gitlab-shell-secret-to-vps + namespace: gitlab +spec: + refreshInterval: 5m + secretStoreRefs: + - name: vault-backend + kind: ClusterSecretStore + selector: + secret: + name: gitlab-gitlab-shell-secret + data: + - match: + secretKey: secret + remoteRef: + remoteKey: vps/gitlab-gitlab-shell-secret + property: secret +--- +apiVersion: external-secrets.io/v1alpha1 +kind: PushSecret +metadata: + name: gitlab-gitaly-secret-to-vps + namespace: gitlab +spec: + refreshInterval: 5m + secretStoreRefs: + - name: vault-backend + kind: ClusterSecretStore + selector: + secret: + name: gitlab-gitaly-secret + data: + - match: + secretKey: token + remoteRef: + remoteKey: vps/gitlab-gitaly-secret + property: token +--- +apiVersion: external-secrets.io/v1alpha1 +kind: PushSecret +metadata: + name: gitlab-praefect-secret-to-vps + namespace: gitlab +spec: + refreshInterval: 5m + secretStoreRefs: + - name: vault-backend + kind: ClusterSecretStore + selector: + secret: + name: gitlab-praefect-secret + data: + - match: + secretKey: token + remoteRef: + remoteKey: vps/gitlab-praefect-secret + property: token diff --git a/infrastructure/vps-standby/gitlab/manifests/ha-gitlab-secrets-externalsecret.yaml b/infrastructure/vps-standby/gitlab/manifests/ha-gitlab-secrets-externalsecret.yaml new file mode 100644 index 0000000..3b0fcd5 --- /dev/null +++ b/infrastructure/vps-standby/gitlab/manifests/ha-gitlab-secrets-externalsecret.yaml @@ -0,0 +1,87 @@ +# GitLab cross-site replication Phase 1b - VPS's half of the Vault +# pipeline (apps/gitlab/manifests/ha-gitlab-secrets-pushsecret.yaml has +# home's half, which pushes the authoritative values into Vault at +# secret/vps/gitlab-{rails,gitlab-shell,gitaly,praefect}-secret). Pulls +# them back down here, BEFORE Phase 1c's Postgres replication goes live. +# +# creationPolicy: Owner (not Merge) - each of these secrets has exactly +# one key with nothing else to preserve, unlike pg-authentik-app which +# has CNPG-local host/dbname/username fields alongside the shared +# password. The chart's shared-secrets job skips creating a key that +# already exists, so having ESO own these outright is sufficient to stop +# the VPS from ever generating its own divergent values. +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: gitlab-rails-secret + namespace: gitlab +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: gitlab-rails-secret + creationPolicy: Owner + data: + - secretKey: secrets.yml + remoteRef: + key: vps/gitlab-rails-secret + property: secrets.yml +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: gitlab-gitlab-shell-secret + namespace: gitlab +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: gitlab-gitlab-shell-secret + creationPolicy: Owner + data: + - secretKey: secret + remoteRef: + key: vps/gitlab-gitlab-shell-secret + property: secret +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: gitlab-gitaly-secret + namespace: gitlab +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: gitlab-gitaly-secret + creationPolicy: Owner + data: + - secretKey: token + remoteRef: + key: vps/gitlab-gitaly-secret + property: token +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: gitlab-praefect-secret + namespace: gitlab +spec: + refreshInterval: 5m + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: gitlab-praefect-secret + creationPolicy: Owner + data: + - secretKey: token + remoteRef: + key: vps/gitlab-praefect-secret + property: token