diff --git a/apps/groombook/overlays/uat/auth-sealed-secret.yaml b/apps/groombook/overlays/uat/auth-sealed-secret.yaml new file mode 100644 index 0000000..9417ae5 --- /dev/null +++ b/apps/groombook/overlays/uat/auth-sealed-secret.yaml @@ -0,0 +1,29 @@ +# ============================================================================= +# GroomBook Auth Credentials — SealedSecret (groombook-uat namespace) +# ============================================================================= +# Fresh credentials generated 2026-04-04. Encrypted with UAT cluster sealing +# certificate via kubeseal --scope namespace-wide. +# ============================================================================= + +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + annotations: + sealedsecrets.bitnami.com/namespace-wide: "true" + name: groombook-auth-uat + namespace: groombook-uat +spec: + encryptedData: + BETTER_AUTH_SECRET: AgBQ3AtxX/LXMeIDlppSaxO4uC8J6wm8vvyv6XMX5129A1kupcog0a//w5n0/R6JKPdg12egipBysoza9O3SXNjWyVEOs6+q5Vs3y0oDNsc1a45o4lTrPPsn1m8LW7nvk8B7lZOSCUgsUfQa9djaIjb5eKoHZvngET7fpQbPt4qQpjHYIR/WVgr5gVkLTHZi2OBVfv5QoX6KIONdoBUb0hJBh4W8j7r+3Usm+GE0W4TDZu+JN1+YYDwmsschTrFuqK2DlVVw9/I7vpX2H25miT/Sv1nEJ8k6mSd0aXACPUrXvJ/E+bkbs1/deSgOvfykRoAURvE00+4aJnbhsyvujyy9Wb/iFowrcmCxQTmu2B19cunBqTMiMlBEGemUpj4QbDXt4GS8C2tsYmHGhYW40ERf7Q6/b4ijlsKE8/gXzEKgZO7nqU1Xn67LWAiHIzNRkT4vnHYv/Xunchq5YoC6AYJb6UIVdX8C5BMQA3l6xlGUWhTSwLYXTJEZ/+LwkXIG3wJxR5pZ2T4q6Q8IGADECfSJjOVC2L0Hs1+CU13xahepikX6Xqp8clBE78ypusSuFioF4Mog0Bv5fvoHQl3g+0zwtKxjQu+1xBqO8KnOpy1PM17xehkr0j5/eh9HXr7psabwqRSjP23It/MxZVPY0FdWdOBy44PPnOavAz4Btr5C8CXyutyZ+vCxxwu6zUB360KGqRaLGetNa25uDVTdkpQ8znv40J0JQ2VprMoWCFcLGnpOqMYZHrSW5XuSeLyiTBmdZ5WhbGgnvCGyiFfV7x7Z + BETTER_AUTH_URL: AgBs+/Ju9T/36zpOdoPAZx7nPXGvxoMzXbElQ2M3rPPioOsPRWiHGNefENGnJS43Rozn5tnCdKzepAHL8kShqKqZKRVThhYVwj2/LCNT8J+I5jW4XkvnokFCUoP6GHoWZXa7Woe1w5bH6oGjrrHfPv2MN4oriO8bYI/hwNbHmSWmAXVv8lE9tbAz1eJDMG/E5VyrHrc9wC7Cw5ITP1/LCb7UrFGHiR97D5zx0XQRTwFfqSFv8oZp+vkUEhLwloe/j2l5RObUN4qtTcGtmpM2B28wiU1TQG2H2sgq3XQY2cotjcJZ80/RQxp/YZgcpOKet/geatLQzAbKnKbLcmM+8NIfpqadwnEbZyDdGvyHENmDWn6xthK77iQFyv6akNIAPjGdWWX4HwGs/rU7pqb1rJMtTWbOsjA+5ocRPQelrpinGugBc3MMquKdMv5PxKHeXqZtUVEN/oEIluKg3LWzbtIRTBh21muZGrsuQHGbpV7G2ct8qga2F6SNCZrfj85w0LKhwky9fysiJ8y1b8wdvsooMYQWmOOJxqIFt/4ajbeAaf4MCU/p395d96ozhx7Ql93FZjZpCRcQFy0IppqYrlR/IkBLg0pBKvzm7dDkya5jg+v6pJv75PDLY6QgflWnsqD3hVbQ8+/k1eVpZsTlVUN/g57C7PTKbeyRBw5iMeXGuE2GDh/37R2mUsnWDLvFouK3c1WDgxFG2bG1tfVPtIK18J5KKoSQ0Tg/HWdu80vGyMxvYfQKU8w= + OIDC_AUDIENCE: AgCJqWqHDMI/Rv8aOPe0dtW/4MKjWSs1s6Nx8TAXl9Y5DzgJFRfewBAnW0yZipCoiLNoYzXPy1lMzjd0SXLv6bNhZ1RKW2TIT8kwP9jFNht+4U4302bSkM6Ud5NlGSb5TxPK7fx327etKg4/9g8Gvk1hI0TB438j0RP66U/nt71d8PSmfJorUvWkMnFgnQ4U2ulcqvj23mb1YU06AVoRvm2hLcPxx/oFMfuN5q9vU4k5pSoXeohlBiy9RCLkjeYc9GKkArsgHI22KMCvE+/1xEA+wfyJEykYjfpi5tlHhB/aA8wElLa93DbfNHy+uT7e/uGJ7x3/I/0lzKaxktEt6E8076bZEch5QkeSRdkEwjx/rRZC4HFMsbTnnagn4YpYsEDisC1kDmj04069PJI0ccwzyIybTkOLWcTb3C6DU26TsBgwD8ktWgrmN/vVR6FODfjArdZacZsZY2zg1hjx35fujl/JYOMWfKSzGPBYC3jbhC5z3yExu8cHQuz2Ayeval3dH1+yzZChvNYjErn2fFEMK79SUmugH4heTgWOhz/JuwiLKMwwYwTkUJwJog8N8LI0IYWul+gRRsiT4Z9bvfcQS+aPKIcFh1jyd+7flKNdoNhvW8ER6L9T7miOWjZZp5NEdFMpcEm++oEnNZTBoub5RVVlHQ71JrpoFUGCfcgYHdSd2h2GZs+Nlt+zlfVQYc+srKY8UCuGBRDx8Pp8WKOIKaXFdPrQH0657gfarkS8qjAbtpLmemCv + OIDC_CLIENT_ID: AgBywUiMkID9wfQwYRxrgzwh6ryLrbQ3mPocvCVywLRuuU8KT8OP7cUVaLcWHaRW7bdDIlzfk8xwNvJoSPsbHLdrpgXugCsbD8oXJy0ZFBxmJT9xNnZtOI0jldEjKze68DW0G4wVvV01IrJPwTIjta7LfOXSuc5rDpYQMDP3fSPdb/HnD5gieOnfsMx6/BdwIgWXQ2ovwklF+0JU2EDPzpkeyiuwJUZjz4UyZj6YWSsHTwod4IN/vMKnD78bD+P48Zn1cQnE8rjDjUQHPJQ414IHoPGebC7eXrICxFWuFJr+GFRhDmrEYQEx+y2SP89MyCOR3pEX+OX0WCOyyRg7PP/D6W/oFB2Z9lEa6+eXm+f37OM7AV/aD4W1IoAIe44dHM2FFnWOiTy8Tx/LdqYyvbg1oISb13dpDle58Za/58ChHyfbf+jP+iAK2dCFJlVonYK3/A7eVihT+Hd8+t3Y/O+84QfmR2bv+she1RpMH2PSjnaULMRKvSf6B6Y5Hvt264wYFbfm+H0WIcNfpZ6OUOlclkMp5CY+UHyQCI6AiivtUmE8s1R6eBuvm3s1uzIdEJMWay80rtNjQors3nbrL/BvWSKoTse4T4Biox9NdfCyKgc59PM/nQ7OpaHSYoCf6lV8gWqe8ps9/JEffujGo9qRHQhRhZU28nKc/pVpgYZIgyqCS6Kg+PmtRRuPKGAblbeYF31EqeB/KBIbsYAfGESE2i7Tuwz2AvAhy48vmKqCsKik7+Lv6eMM + OIDC_CLIENT_SECRET: AgAgEVL+T1VbtIC0ZFDCZsAMfkfaYiwXlDZOpwa/03EPASGwW1bhb2OJBOHV2+/kRwQMD5hyt4BZ5gxDwUxdaD3o9/xe7LYakVglayV3edDkuKqHTg9+87khiWTi/4x2xUTh7/FIu+sVGQyZkGnLQOr8yQ1wh7IT9PD2rwwAVFWYKhrmlIa1IIX0gikiX28lKzrqIGro2MwVQmjnn122OrIkPJHPhOfmxqpljkf1WPr3lIQl5U0V5Z0sl1Ji26/FQiq3332gl++bXw0ecI07+ZZNC+JNZyhLj3dff+dhhI7oIEn0CJ8w39HdRomBHqA3LXa/UtGaJPW6ybaT1QMUUvWHPfMS6jzkjLKRUhF8nC6bgYn411RmTY2z+sPDLMY3QD7BVPhoXe2A+xl02R8Elmz3VnBzwaLt0IWrayb9WxYlRz0ottY+gb1cjWKMAeF/2UocYWWhIGxvN4M/f6QrFzcwQNnmROG3ltZZR8tQZDYnfJsilSZRlWE6iifxHhXHKFz+jni3ntipFFXZYU/+KcYbopYZQY/AJ0FG61f80fzO3SnHVXj3IPHXUy1NO+iupqmw9OivY+0pxjxvzCPc9sWjtLKL4w0Pqp2fYWWvp/YPOLzVMPg0VbbmFeRpjeyZP1hWT7Ejq7whqf3N7Tu9hKAkAD27C20dgzOsi5gRz50PekzBH8CZVaTQRkGRw9C5nwyePtDcwrbGoBzNAuep7V5+l+XA2spivgeSNcxttbfeDhfOdMKH3N5RyNFXS2pWy330zYoa8q5sV4mX04HI78nBXzTvACojze4hui21EzawChcU/5cLPLaVeA0X22YhnH7RrZInwVOYF3fep2fHlRVh0A== + OIDC_INTERNAL_BASE: AgCYH+f1sZJCLqoR0ZYWrhpNx7R/9xEWDjeiFDyFlDvV+OKon6ZmIzzgQw4WZY67/Pbio0PxQ530+z/cFBo9+7n8TvSrauaBi/a6KjGn4/ayYGSMTGKK4ItzV0rAdgKM47/yx/TTbk0d2DwMaqTGp7+vOGg2HVq0bqsu0LG//QrLPxbx5Jc4qFEW7oiRrhA9JpUhVKkcqpDtT9qKBDOmjtegAEIM0WZncr1d/apcPjJu+2ugS65p0ILr/rAuCBDQDLsNJ7IdNH/YLdvFAOWOZ0VP1TJY7DLUzq2ToYbA71QLVnVaA8XhOm8rzjSrWZccCYe6V7fqGc96uRM76i1vhdWNZ5ViFaoj37F1DXLw/x51jHCoDPRAl8LUVGzoYHnxzOwUW6wh6O5Zo4tw1AKt4RgqFldqGUvnrhQPT2tIpnBYdeEkyLod/qA0lLNThPr6LP3X5LgVfe64zPB00J3UajfrL1Xb9Xhc903lSnt4oszcm1n5sVIHlr8q8ioSVTimksDf/be/CzgisnHpJQ/7YocucV47DN7l5X/O63j5IMFhKaJuukcJK3bMMWqkJGfRHDqCiqT0uTOGpdsn01smC4MidqEmBNQFgk5ehH1Vs3xAJZ08qSWBkPUS9c7pzAlsIJC48V8pwQXPgDGBsbPIkqM6vYp8obZFdHm6tH4ITEmDPQbeFl3sZm46tKXTPU3vZ4wZwXsIBeqEaAd9tMmTb02O3G6qrxgqojR7LX1wQy8wGh5Q101ILjBxcAEJw8bf + OIDC_ISSUER: AgAyv5SDPr1j5AM86jlnby72v8ZRtTQA6k4VTsyp4OS6Z1lhN2j6GU7w9iuSGtqT3TlX//CR8e1BQoB3hb2luzcEbxi+LAvRH+ZiB32cSCWUXx74fE1qLFc75Ri3FY4u70WoLwGSJuHoFmFMEI3TDrSxMIpDdjJa+adJZdW9+ERp1FdT3L6bqAnx/yAbaBjGvdBFVcd4Qu1aMgR7I1Pk/3e8W7B+U6GRc4IdkeIbNyxsVUsKWxPBMji5rgYhMqU5dl2/b0DfNM9z1iDKTqRdFsBIUJ6ynTcx9uZ6UIBGRdB5oI937eVJPVodwAr5RbOPEZsvcdyYtofjdDy1ZleO06saaXb3+SgWiej8kzWhf+53FexdIDdl6/sGa41NE4KSH4tdr8UcujxvwmfFL4/nrpE3I9YftLw7wvsrUvxaVAn7bcdtgFpgQTHokhSWzcddEcmEUZTCJHp21wTtrYiOFAw40LAzyMBkbD7gaK9w9I7oNRX6GF6dtA4ppn3z+jTwGHjWM3jJnTxFeJQxH/S6sgFsRHBrDrGIz5o1qnWvxjNVBhFaVc9ev7qb6jNNqYrUOfGMxpDOuQe0C+54vBCY5Bo7cimde4eBLIo6HmGsLd4ISUxtr3oiBpYShGBRSu3al5rGUWXk9S+sGO7wVHsqrzDb9OnxHJClARxlimxrdoH0FA2UY1hmeQdnzSA7d4mNnyOv+AS9E6PmCPcXrCzK+qmsGcvgjY0fpbpw+SbAzEcAp1VcTEekrm/4ZIWsp8io94oc0g== + template: + metadata: + annotations: + sealedsecrets.bitnami.com/namespace-wide: "true" + name: groombook-auth-uat + namespace: groombook-uat diff --git a/apps/groombook/overlays/uat/kustomization.yaml b/apps/groombook/overlays/uat/kustomization.yaml new file mode 100644 index 0000000..d9e78af --- /dev/null +++ b/apps/groombook/overlays/uat/kustomization.yaml @@ -0,0 +1,112 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: groombook-uat +images: + - name: ghcr.io/groombook/api + newTag: "2026.04.03-90be1be" + - name: ghcr.io/groombook/web + newTag: "2026.04.03-90be1be" + - name: ghcr.io/groombook/migrate + newTag: "2026.04.03-90be1be" + - name: ghcr.io/groombook/seed + newTag: "2026.04.03-90be1be" +resources: + - ../../base + - postgres-sealed-secret.yaml + - auth-sealed-secret.yaml +patches: + # UAT: delete the base postgres-credentials SealedSecret (scoped to groombook namespace, not groombook-uat) + # The base component ../components/postgres-credentials creates a namespace-scoped (not namespace-wide) + # SealedSecret that the namespace transformer cannot fix. Remove it to avoid noise. + - target: + kind: SealedSecret + name: groombook-postgres-credentials + patch: | + - op: remove + path: /metadata + # UAT: inject auth env vars from groombook-auth-uat sealed secret into API + - target: + kind: Deployment + name: api + patch: | + - op: add + path: /spec/template/spec/containers/0/env + value: + - name: NODE_ENV + value: production + - name: AUTH_DISABLED + value: "false" + - name: BETTER_AUTH_URL + valueFrom: + secretKeyRef: + name: groombook-auth-uat + key: BETTER_AUTH_URL + - name: BETTER_AUTH_SECRET + valueFrom: + secretKeyRef: + name: groombook-auth-uat + key: BETTER_AUTH_SECRET + - name: OIDC_ISSUER + valueFrom: + secretKeyRef: + name: groombook-auth-uat + key: OIDC_ISSUER + - name: OIDC_CLIENT_ID + valueFrom: + secretKeyRef: + name: groombook-auth-uat + key: OIDC_CLIENT_ID + - name: OIDC_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: groombook-auth-uat + key: OIDC_CLIENT_SECRET + - name: OIDC_AUDIENCE + valueFrom: + secretKeyRef: + name: groombook-auth-uat + key: OIDC_AUDIENCE + - name: OIDC_INTERNAL_BASE + valueFrom: + secretKeyRef: + name: groombook-auth-uat + key: OIDC_INTERNAL_BASE + # UAT: single Postgres instance instead of 3 + - target: + kind: Cluster + name: groombook-postgres + patch: | + - op: replace + path: /spec/instances + value: 1 + - op: replace + path: /spec/storage/size + value: 5Gi + - op: replace + path: /spec/bootstrap/initdb/secret/name + value: groombook-postgres-credentials-uat + # UAT: use uat hostname for HTTPRoute + - target: + kind: HTTPRoute + name: groombook + patch: | + - op: replace + path: /spec/hostnames + value: + - groombook.uat.farh.net + # UAT: point migrate job at UAT postgres credentials + - target: + kind: Job + labelSelector: "app.kubernetes.io/name=migrate" + patch: | + - op: replace + path: /spec/template/spec/containers/0/env/0/valueFrom/secretKeyRef/name + value: groombook-postgres-credentials-uat + # UAT: point seed job at UAT postgres credentials + - target: + kind: Job + labelSelector: "app.kubernetes.io/name=seed" + patch: | + - op: replace + path: /spec/template/spec/containers/0/env/0/valueFrom/secretKeyRef/name + value: groombook-postgres-credentials-uat diff --git a/apps/groombook/overlays/uat/postgres-sealed-secret.yaml b/apps/groombook/overlays/uat/postgres-sealed-secret.yaml new file mode 100644 index 0000000..16e73d7 --- /dev/null +++ b/apps/groombook/overlays/uat/postgres-sealed-secret.yaml @@ -0,0 +1,33 @@ +# ============================================================================= +# GroomBook Postgres Credentials — SealedSecret (groombook-uat namespace) +# ============================================================================= +# Fresh credentials generated 2026-04-04. Encrypted with UAT cluster sealing +# certificate via kubeseal --scope namespace-wide. +# CloudNativePG reads this secret at bootstrap time (postgres-cluster.yaml +# bootstrap.initdb.secret). +# ============================================================================= + +apiVersion: bitnami.com/v1alpha1 +kind: SealedSecret +metadata: + annotations: + sealedsecrets.bitnami.com/namespace-wide: "true" + name: groombook-postgres-credentials-uat + namespace: groombook-uat + labels: + app.kubernetes.io/name: postgres + app.kubernetes.io/part-of: groombook +spec: + encryptedData: + # yamllint disable rule:line-length + password: AgB6lhWPCCCKvlxbQyupxhidg2rgPv1McRm3c2VPVhpyw9S0vdGL2VJhlhyr01ya2tOFJZOqhgYPi2Q0kTmd8bfMy83ygCBcvk0D1XfMXazVq1VOJmu7zBMWyRLjjDHQfV0ASKqk07wRP6TiY37BQwKtdHj+e0oHoh9D08oo3SuZXs+DkjuoP8tgU2MAMLj3PxXp5nDrOY/BYh9MEsUVC37PduGZXsTKCD/7uOHZRMj3NrheSc9ZyVSGLGsfW6dHeULFblW93NSQM03G9I/G8NhoGrZy3SaLfajZrm1TB7X+4qI4yCYTk0QqBxIBpEfR29TdSaYX1NNbgKgI1ebRVTQBQ9Kq1fYXL9saFVwcMmHT8zKjPSFYXDAJvRMqSOPCgntp/w8nnhVoFNaQLkwRI/unSFLgZ3yu+9eV6bixN3gUIrLvzJNjF5uV6mAyFJ8phLEFJJ50la+tdKu8QEMT00//PFqidNNe43inxKTSNtFUcfeC6dKKDzHkj99DMTVHbMSUe0TzwX/aDw8YsxN147Q8vuANm5PuaX8DZFkMcL92tppulZwdclER9+tLfcRWFfd52WX+u5Me0WbF9qAVcS1CJI7CMjKvNS5uYm7ZIKwmHHTHROZAHL4RsFZeUoE4Asuep4b+EjU9V/LDYYJdo9kW+RkKUVdtrurY6SL/NhtqyzHLtbvSWFBRsLT+UADpoFXa3z38tJLQD+kFbA/8ifHRKcEfzF3SflodLiAlNjRTMfLjWCU5a/bipR3U + uri: AgBM/6mX5eUTTok8dYECF7zR3aKuPHcloWMAfSVESnyNdZnEO1TgPCpcgp47dCy5C2bLPshxyMCZlwiQux2336qHHQyXv08rlF6duiUr26zJC92/Izvaj2YNmWYAnUA8bC/3N9Dk5+/tKbDwVwYSH+s4hAN1V+B2fH7k9/hFYv38Iih38fMqbQG4XZpYsNrJLthds/ox3DdJNLh4mjrDKLYHkWlGfg8qUxDqgVnFGozTuSrAMIqTvpxLFnM87GO9mILyP+ccFo53ikGLqQ0fniZSl9s+xF1b3jaqQZSL5gYf77Yt0uKFBurmBaw6Vpe56q2WDeFJJBYUd0PqyOK41RX6NnoPJF8KbmDC7qJYxgZMP2ghWh3xP+zpBozuoS1qMu470InaZNIBetnhxtFWF42tKv9UbZ2H6GQbnMWBaPeVra3foRqUn9oCvAWMThPSicaNJMLK0pGfjoAR9lurFa9aAMGqcWVJPuEbKJ5LfC6oHWTqMe2NnCaDg7RG787ntF/KK1VUnWVPQKn9sff/vQPi0pftq7bVQaMELMy0vclFOtxvVfsuKDyvEFUzJKuegPjiTZ3uISW5s6m/68bgTchSPjXKY40oFKnAu/l18DGX/LX7QkTfBEo7wlUrYhF3gwjWJoNk0KCydNodRyglPkyrbvc44fCCofmA1x/YRj0RerxhL+tUzp+pMNO+lsKTvocuewMNfWuDUsUZCxYJAPh3FtC2dYqjFECsdzpBurAeLLopEgK5XyKSyjhW60rDp5SEhd46Pcui5Pf4xgf0YfaZcHYUu72yikIf26EMZjIDjRGOZB25l/TAtcQNAlwYdZu51AOS7DEjfw8RhZNhQSEn6L+ieRew+17i + username: AgCxwdyCROIRBHmewuxmWlcPe3Ngj1EvXRi7xyZMw6iHO7YQGcX5IQbXSsWvy/hcPcRj3rGpj0O9qn602QEcgeSeNlTye4NmTU8ExWEC6ObvMRP2j+rPdWdGUp2eIGA846rE9/OUiCb3GkoRwKWbYI9QISBAc4IzoaBSvi/pscCeKWuWqx/EJQqasUcaTeA+HcvKUB3eo7gMMBYDC+cds50iiDD4UmG8ZM9m6t9yfYFKdjgoiU47REUancrJHDs1umR3zuYFAKVVr84xGSplAIHk0Cc1iuxmzXMR/o4dBqZJzJUseBHCS2KLptNqIM02yIKQtMT0QgQzXUY3Ox+8fhDLWABxDmDKw6a6dUVuBACG4FkLFx5gksmXXsmsc0882L6q3k1AcZPakemD3j2ESPxVkcxbRNxjLf2bt8V1pUbOh5TgCwhM4YOu0MiXRWr5VhVJZ0hKTiW6JUEuW8zjEzHQp48PM6THNiWyxK89pMdeqPo4vaQfeJxeFs6y/xWyDnNNTJ/95fYCMG69I5cP5pA8XcUwu5p+mUuspmpfx/O5jFz2ksRxzUWP0vBdJXE4bg0lmqhL/8/OMGMX/MGFFY9wRD8hnEJeDQ5R27mEmqUKB0IlbMvhIrWS3Ro3KEetdndOFzN2ALOEUQIhgUEM7uH1vrDivcMX/W89oDlz0fFeqBRK8q69dygY+PXKS8qyhoaO2ER++Xw55tU= + # yamllint enable rule:line-length + template: + metadata: + annotations: + sealedsecrets.bitnami.com/namespace-wide: "true" + name: groombook-postgres-credentials-uat + namespace: groombook-uat + type: kubernetes.io/basic-auth