mirror of
https://github.com/dredx/prole.git
synced 2026-09-24 15:54:32 +00:00
feat: GKE production deployment — CNPG + GCS backups + Google Workspace SSO
Add complete GKE deployment stack: - deploy/gcp/gke/: namespace, CloudNativePG cluster (premium-rwo, 100Gi), GCS barman-cloud backup with Workload Identity SA, ArgoCD OIDC ConfigMap, GitLab OmniAuth secret template, knoe-auth Google OIDC secret template - etc/init_cnpg_gke.sh: provision GCS buckets, GCP SA, WI binding, CNPG operator - etc/init_argocd.sh: apply argocd-oidc-cm.yaml when PLATFORM_DOMAIN/FRONTDOOR_HOST set - etc/init_gitlab.sh: inject OmniAuth openid_connect block when FRONTDOOR_HOST set - prole-auth-deployment.yaml: add GOOGLE_OIDC_ENABLED env vars (all optional) - supabase/helm/prole-supabase/values-gke.yaml: GoTrue Google OAuth overlay - knoe/core/prod_config.py: add backupProvider, workloadIdentitySA, googleClientId/Secret/HostedDomain Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
68e4a5418c
commit
620bdd25eb
58
deploy/gcp/gke/argocd-oidc-cm.yaml
Normal file
58
deploy/gcp/gke/argocd-oidc-cm.yaml
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
# Patch argocd-cm to enable Google Workspace SSO via knoe-auth OIDC issuer.
|
||||||
|
# Applied by etc/init_argocd.sh --mode k8s after ArgoCD is installed.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: argocd-cm
|
||||||
|
namespace: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: argocd-cm
|
||||||
|
app.kubernetes.io/part-of: argocd
|
||||||
|
data:
|
||||||
|
# Set url to your ArgoCD external hostname
|
||||||
|
url: "https://argocd.${PLATFORM_DOMAIN}"
|
||||||
|
oidc.config: |
|
||||||
|
name: "Google Workspace"
|
||||||
|
issuer: "https://${FRONTDOOR_HOST}/auth"
|
||||||
|
clientID: argocd
|
||||||
|
clientSecret: $oidc.argocd.clientSecret
|
||||||
|
requestedScopes:
|
||||||
|
- openid
|
||||||
|
- profile
|
||||||
|
- email
|
||||||
|
- groups
|
||||||
|
requestedIDTokenClaims:
|
||||||
|
groups:
|
||||||
|
essential: true
|
||||||
|
|
||||||
|
---
|
||||||
|
# RBAC: map Google Workspace admin email to ArgoCD admin role.
|
||||||
|
# Add additional group/email → role mappings under policy.csv.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: argocd-rbac-cm
|
||||||
|
namespace: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: argocd-rbac-cm
|
||||||
|
app.kubernetes.io/part-of: argocd
|
||||||
|
data:
|
||||||
|
policy.default: role:readonly
|
||||||
|
policy.csv: |
|
||||||
|
g, ${BOOTSTRAP_ADMIN_EMAIL}, role:admin
|
||||||
|
|
||||||
|
---
|
||||||
|
# Secret referenced by oidc.config above ($oidc.argocd.clientSecret).
|
||||||
|
# Populated by the installer from the OIDC Client Secret field.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: argocd-secret
|
||||||
|
namespace: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: argocd-secret
|
||||||
|
app.kubernetes.io/part-of: argocd
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
oidc.argocd.clientSecret: "" # set by installer
|
||||||
30
deploy/gcp/gke/gitlab-google-oidc-secret.example.yaml
Normal file
30
deploy/gcp/gke/gitlab-google-oidc-secret.example.yaml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: gitlab-google-oidc
|
||||||
|
namespace: gitlab
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/managed-by: prole-installer
|
||||||
|
# GitLab OmniAuth provider config for OpenID Connect via knoe-auth.
|
||||||
|
# See: https://docs.gitlab.com/ee/administration/auth/oidc.html
|
||||||
|
# Applied by etc/init_gitlab.sh --mode k8s
|
||||||
|
stringData:
|
||||||
|
provider: |
|
||||||
|
name: openid_connect
|
||||||
|
label: "Google Workspace"
|
||||||
|
icon: "https://www.google.com/favicon.ico"
|
||||||
|
args:
|
||||||
|
name: openid_connect
|
||||||
|
scope:
|
||||||
|
- openid
|
||||||
|
- profile
|
||||||
|
- email
|
||||||
|
response_type: code
|
||||||
|
issuer: "https://${FRONTDOOR_HOST}/auth"
|
||||||
|
client_auth_method: query
|
||||||
|
uid_field: email
|
||||||
|
send_scope_to_token_endpoint: false
|
||||||
|
client_options:
|
||||||
|
identifier: "" # set to OIDC client_id
|
||||||
|
secret: "" # set to OIDC client_secret
|
||||||
|
redirect_uri: "https://git.${PLATFORM_DOMAIN}/users/auth/openid_connect/callback"
|
||||||
14
deploy/gcp/gke/knoe-auth-google-oidc-secret.example.yaml
Normal file
14
deploy/gcp/gke/knoe-auth-google-oidc-secret.example.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: knoe-auth-google-oidc
|
||||||
|
namespace: knoe-system
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/managed-by: prole-installer
|
||||||
|
# Fill in client_id and client_secret from your Google Cloud Console OAuth 2.0 credentials.
|
||||||
|
# Create at: https://console.cloud.google.com/apis/credentials
|
||||||
|
# Authorized redirect URI: https://<frontdoor-host>/auth/callback/google
|
||||||
|
stringData:
|
||||||
|
client_id: ""
|
||||||
|
client_secret: ""
|
||||||
|
hosted_domain: "" # restrict to a Google Workspace domain, e.g. "yourdomain.com"; blank = any Google account
|
||||||
27
deploy/gcp/gke/knoe-db-backup-gcs.yaml
Normal file
27
deploy/gcp/gke/knoe-db-backup-gcs.yaml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
# Kubernetes ServiceAccount bound to the GCP service account via Workload Identity.
|
||||||
|
# The CNPG operator uses this SA to authenticate against GCS without a static key.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: cnpg-backup-sa
|
||||||
|
namespace: ecosystem-0
|
||||||
|
annotations:
|
||||||
|
# Set by etc/init_cnpg_gke.sh — substituted at deploy time
|
||||||
|
iam.gke.io/gcp-service-account: "cnpg-backup@${GCP_PROJECT_ID}.iam.gserviceaccount.com"
|
||||||
|
|
||||||
|
---
|
||||||
|
# Daily scheduled backup at 02:00 UTC.
|
||||||
|
# Backup data lands in gs://knoe-0-backups/ (WAL is streamed continuously by CNPG).
|
||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: ScheduledBackup
|
||||||
|
metadata:
|
||||||
|
name: knoe-db-daily
|
||||||
|
namespace: ecosystem-0
|
||||||
|
spec:
|
||||||
|
schedule: "0 2 * * *"
|
||||||
|
backupOwnerReference: self
|
||||||
|
cluster:
|
||||||
|
name: knoe-db
|
||||||
|
method: barmanObjectStore
|
||||||
|
immediate: false
|
||||||
105
deploy/gcp/gke/knoe-db.yaml
Normal file
105
deploy/gcp/gke/knoe-db.yaml
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Cluster
|
||||||
|
metadata:
|
||||||
|
name: knoe-db
|
||||||
|
namespace: ecosystem-0
|
||||||
|
spec:
|
||||||
|
instances: 3
|
||||||
|
# Image pulled from GCP Artifact Registry — set ARTIFACT_REGISTRY in conf/prod/gcp.cfg
|
||||||
|
# e.g. us-central1-docker.pkg.dev/<project>/prole/knoe-db:18-140
|
||||||
|
imageName: "${ARTIFACT_REGISTRY}/knoe-db:18-140"
|
||||||
|
postgresUID: 100
|
||||||
|
postgresGID: 101
|
||||||
|
maxSyncReplicas: 1
|
||||||
|
|
||||||
|
affinity:
|
||||||
|
enablePodAntiAffinity: true
|
||||||
|
podAntiAffinityType: preferred
|
||||||
|
topologyKey: topology.kubernetes.io/zone # GKE zone-aware spreading
|
||||||
|
|
||||||
|
postgresql:
|
||||||
|
parameters:
|
||||||
|
shared_buffers: 256MB
|
||||||
|
pg_stat_statements.max: '10000'
|
||||||
|
pg_stat_statements.track: all
|
||||||
|
shared_preload_libraries:
|
||||||
|
- pg_stat_statements
|
||||||
|
- pg_tde
|
||||||
|
pg_hba:
|
||||||
|
- local all postgres trust
|
||||||
|
- local all prole scram-sha-256
|
||||||
|
- host all postgres all scram-sha-256
|
||||||
|
- host prole knoe-db all scram-sha-256
|
||||||
|
- host all all all scram-sha-256
|
||||||
|
- hostssl prole knoe-db all scram-sha-256
|
||||||
|
|
||||||
|
bootstrap:
|
||||||
|
initdb:
|
||||||
|
database: knoe-db
|
||||||
|
owner: prole
|
||||||
|
localeCollate: 'en_US.utf8'
|
||||||
|
localeCType: 'en_US.utf8'
|
||||||
|
secret:
|
||||||
|
name: knoe-db-user
|
||||||
|
postInitTemplateSQL:
|
||||||
|
- CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
|
||||||
|
postInitSQL:
|
||||||
|
- CREATE EXTENSION IF NOT EXISTS pg_tde;
|
||||||
|
- CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
|
- GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO prole;
|
||||||
|
- CREATE EXTENSION IF NOT EXISTS postgis;
|
||||||
|
- CREATE EXTENSION IF NOT EXISTS postgis_topology;
|
||||||
|
- CREATE EXTENSION IF NOT EXISTS vector;
|
||||||
|
- CREATE EXTENSION IF NOT EXISTS tds_fdw;
|
||||||
|
- GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO prole;
|
||||||
|
- GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA topology TO prole;
|
||||||
|
- CREATE SCHEMA IF NOT EXISTS storage;
|
||||||
|
- CREATE SCHEMA IF NOT EXISTS graphql_public;
|
||||||
|
- CREATE ROLE anon NOLOGIN;
|
||||||
|
- CREATE ROLE authenticator LOGIN;
|
||||||
|
- GRANT USAGE ON SCHEMA public TO anon;
|
||||||
|
- GRANT USAGE ON SCHEMA storage TO anon;
|
||||||
|
- GRANT USAGE ON SCHEMA graphql_public TO anon;
|
||||||
|
- GRANT anon TO authenticator;
|
||||||
|
|
||||||
|
certificates:
|
||||||
|
serverTLSSecret: knoe-db-tls
|
||||||
|
serverCASecret: knoe-db-ca
|
||||||
|
|
||||||
|
enableSuperuserAccess: true
|
||||||
|
|
||||||
|
# GCS backup via Workload Identity — see knoe-db-backup-gcs.yaml
|
||||||
|
backup:
|
||||||
|
barmanObjectStore:
|
||||||
|
destinationPath: "gs://knoe-0-backups/"
|
||||||
|
googleCredentials:
|
||||||
|
applicationCredentials:
|
||||||
|
name: "" # empty = Workload Identity; no static key needed
|
||||||
|
wal:
|
||||||
|
compression: gzip
|
||||||
|
data:
|
||||||
|
compression: gzip
|
||||||
|
retentionPolicy: "14d"
|
||||||
|
|
||||||
|
storage:
|
||||||
|
size: 100Gi
|
||||||
|
pvcTemplate:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 100Gi
|
||||||
|
storageClassName: premium-rwo # GCP SSD persistent disk (pd-ssd)
|
||||||
|
|
||||||
|
walStorage:
|
||||||
|
size: 20Gi
|
||||||
|
pvcTemplate:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 20Gi
|
||||||
|
storageClassName: premium-rwo
|
||||||
|
|
||||||
|
monitoring:
|
||||||
|
enablePodMonitor: true # GKE managed Prometheus
|
||||||
6
deploy/gcp/gke/namespace.yaml
Normal file
6
deploy/gcp/gke/namespace.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: ecosystem-0
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/managed-by: prole-installer
|
||||||
26
deploy/gcp/gke/workload-identity.yaml
Normal file
26
deploy/gcp/gke/workload-identity.yaml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Workload Identity binding documentation.
|
||||||
|
#
|
||||||
|
# This file is NOT applied with kubectl — it documents the gcloud commands
|
||||||
|
# executed by etc/init_cnpg_gke.sh to establish the Workload Identity link
|
||||||
|
# between the Kubernetes ServiceAccount (cnpg-backup-sa) and the GCP
|
||||||
|
# service account (cnpg-backup@<project>.iam.gserviceaccount.com).
|
||||||
|
#
|
||||||
|
# Commands run by init_cnpg_gke.sh:
|
||||||
|
#
|
||||||
|
# gcloud iam service-accounts create cnpg-backup \
|
||||||
|
# --display-name="CNPG GCS Backup" \
|
||||||
|
# --project=$GCP_PROJECT_ID
|
||||||
|
#
|
||||||
|
# gsutil iam ch \
|
||||||
|
# serviceAccount:cnpg-backup@$GCP_PROJECT_ID.iam.gserviceaccount.com:objectAdmin \
|
||||||
|
# gs://knoe-0-backups
|
||||||
|
#
|
||||||
|
# gcloud iam service-accounts add-iam-policy-binding \
|
||||||
|
# cnpg-backup@$GCP_PROJECT_ID.iam.gserviceaccount.com \
|
||||||
|
# --role=roles/iam.workloadIdentityUser \
|
||||||
|
# --member="serviceAccount:$GCP_PROJECT_ID.svc.id.goog[ecosystem-0/cnpg-backup-sa]"
|
||||||
|
#
|
||||||
|
# kubectl annotate serviceaccount cnpg-backup-sa \
|
||||||
|
# -n ecosystem-0 \
|
||||||
|
# iam.gke.io/gcp-service-account=cnpg-backup@$GCP_PROJECT_ID.iam.gserviceaccount.com \
|
||||||
|
# --overwrite
|
||||||
@ -155,6 +155,37 @@ spec:
|
|||||||
configMapKeyRef:
|
configMapKeyRef:
|
||||||
name: prole-auth-kerberos
|
name: prole-auth-kerberos
|
||||||
key: realm
|
key: realm
|
||||||
|
# ── Google Workspace OIDC (primary auth for GKE/prod) ──────────
|
||||||
|
# Secret created by installer from Auth+Routing tab OIDC fields.
|
||||||
|
# Template: deploy/gcp/gke/knoe-auth-google-oidc-secret.example.yaml
|
||||||
|
- name: GOOGLE_OIDC_ENABLED
|
||||||
|
value: "true"
|
||||||
|
- name: GOOGLE_CLIENT_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: knoe-auth-google-oidc
|
||||||
|
key: client_id
|
||||||
|
optional: true # Kerberos-only deployments can omit this secret
|
||||||
|
- name: GOOGLE_CLIENT_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: knoe-auth-google-oidc
|
||||||
|
key: client_secret
|
||||||
|
optional: true
|
||||||
|
- name: GOOGLE_HOSTED_DOMAIN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: knoe-auth-google-oidc
|
||||||
|
key: hosted_domain
|
||||||
|
optional: true # blank = any Google account; set to restrict to Workspace domain
|
||||||
|
- name: OIDC_ISSUER_URL
|
||||||
|
value: "https://knoe-auth.knoe-system.svc.cluster.local:8080"
|
||||||
|
- name: OIDC_BASE_URL
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: prole-platform-config
|
||||||
|
key: frontdoorHost
|
||||||
|
optional: true
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: keytab
|
- name: keytab
|
||||||
mountPath: /etc/prole/keytabs
|
mountPath: /etc/prole/keytabs
|
||||||
|
|||||||
@ -32,6 +32,9 @@ fi
|
|||||||
|
|
||||||
ACTION="$COMMON_CORE_ACTION"
|
ACTION="$COMMON_CORE_ACTION"
|
||||||
|
|
||||||
|
REPO_ROOT="${PROLE_HOME:-$(cd "$SCRIPT_DIR/.." && pwd)}"
|
||||||
|
GKE_MANIFEST_DIR="${GKE_MANIFEST_DIR:-$REPO_ROOT/deploy/gcp/gke}"
|
||||||
|
|
||||||
if [[ -d "$SCRIPT_DIR/../k8s/argocd" ]]; then
|
if [[ -d "$SCRIPT_DIR/../k8s/argocd" ]]; then
|
||||||
ARGOCD_MANIFEST_DIR="$SCRIPT_DIR/../k8s/argocd"
|
ARGOCD_MANIFEST_DIR="$SCRIPT_DIR/../k8s/argocd"
|
||||||
elif [[ -n "${PROLE_HOME:-}" && -d "$PROLE_HOME/k8s/argocd" ]]; then
|
elif [[ -n "${PROLE_HOME:-}" && -d "$PROLE_HOME/k8s/argocd" ]]; then
|
||||||
@ -52,6 +55,11 @@ ARGOCD_PORT_FORWARD_LOCAL=${ARGOCD_PORT_FORWARD_LOCAL:-8081}
|
|||||||
ARGOCD_PORT_FORWARD_REMOTE=${ARGOCD_PORT_FORWARD_REMOTE:-80}
|
ARGOCD_PORT_FORWARD_REMOTE=${ARGOCD_PORT_FORWARD_REMOTE:-80}
|
||||||
ARGOCD_NODE_SELECTOR=${ARGOCD_NODE_SELECTOR:-}
|
ARGOCD_NODE_SELECTOR=${ARGOCD_NODE_SELECTOR:-}
|
||||||
|
|
||||||
|
# ── Google Workspace OIDC (applied when all three vars are set) ───────────────
|
||||||
|
PLATFORM_DOMAIN="${PLATFORM_DOMAIN:-}"
|
||||||
|
FRONTDOOR_HOST="${FRONTDOOR_HOST:-}"
|
||||||
|
BOOTSTRAP_ADMIN_EMAIL="${BOOTSTRAP_ADMIN_EMAIL:-}"
|
||||||
|
|
||||||
ensure_tools() {
|
ensure_tools() {
|
||||||
command -v kubectl >/dev/null || { echo "Missing required tool: kubectl" >&2; exit 1; }
|
command -v kubectl >/dev/null || { echo "Missing required tool: kubectl" >&2; exit 1; }
|
||||||
}
|
}
|
||||||
@ -122,6 +130,24 @@ apply_argocd() {
|
|||||||
kubectl rollout status statefulset/argocd-application-controller -n "$ARGOCD_NAMESPACE" --timeout=${ROLLOUT_TIMEOUT:-300s} || true
|
kubectl rollout status statefulset/argocd-application-controller -n "$ARGOCD_NAMESPACE" --timeout=${ROLLOUT_TIMEOUT:-300s} || true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply_argocd_oidc_config() {
|
||||||
|
local cm_file="$GKE_MANIFEST_DIR/argocd-oidc-cm.yaml"
|
||||||
|
if [[ -z "$PLATFORM_DOMAIN" || -z "$FRONTDOOR_HOST" || -z "$BOOTSTRAP_ADMIN_EMAIL" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [[ ! -f "$cm_file" ]]; then
|
||||||
|
echo "WARN: ArgoCD OIDC config not found at $cm_file; skipping OIDC patch." >&2
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo "Applying ArgoCD OIDC config (issuer=https://${FRONTDOOR_HOST}/auth) ..."
|
||||||
|
PLATFORM_DOMAIN="$PLATFORM_DOMAIN" \
|
||||||
|
FRONTDOOR_HOST="$FRONTDOOR_HOST" \
|
||||||
|
BOOTSTRAP_ADMIN_EMAIL="$BOOTSTRAP_ADMIN_EMAIL" \
|
||||||
|
envsubst < "$cm_file" \
|
||||||
|
| kubectl apply --server-side --force-conflicts \
|
||||||
|
--field-manager=prole-installer -f -
|
||||||
|
}
|
||||||
|
|
||||||
rollout_restart_argocd() {
|
rollout_restart_argocd() {
|
||||||
kubectl -n "$ARGOCD_NAMESPACE" rollout restart deploy/argocd-server deploy/argocd-repo-server \
|
kubectl -n "$ARGOCD_NAMESPACE" rollout restart deploy/argocd-server deploy/argocd-repo-server \
|
||||||
deploy/argocd-dex-server deploy/argocd-applicationset-controller deploy/argocd-notifications-controller \
|
deploy/argocd-dex-server deploy/argocd-applicationset-controller deploy/argocd-notifications-controller \
|
||||||
@ -144,6 +170,7 @@ case "$ACTION" in
|
|||||||
ensure_tools
|
ensure_tools
|
||||||
ensure_namespace
|
ensure_namespace
|
||||||
apply_argocd
|
apply_argocd
|
||||||
|
apply_argocd_oidc_config
|
||||||
prole_register_port_forward "argocd" "$ARGOCD_NAMESPACE" "svc/${ARGOCD_SERVER_SERVICE}" \
|
prole_register_port_forward "argocd" "$ARGOCD_NAMESPACE" "svc/${ARGOCD_SERVER_SERVICE}" \
|
||||||
"$ARGOCD_PORT_FORWARD_LOCAL" "$ARGOCD_PORT_FORWARD_REMOTE" "0.0.0.0" "TCP" "ArgoCD"
|
"$ARGOCD_PORT_FORWARD_LOCAL" "$ARGOCD_PORT_FORWARD_REMOTE" "0.0.0.0" "TCP" "ArgoCD"
|
||||||
;;
|
;;
|
||||||
@ -152,6 +179,7 @@ case "$ACTION" in
|
|||||||
ensure_namespace
|
ensure_namespace
|
||||||
apply_argocd
|
apply_argocd
|
||||||
rollout_restart_argocd
|
rollout_restart_argocd
|
||||||
|
apply_argocd_oidc_config
|
||||||
prole_register_port_forward "argocd" "$ARGOCD_NAMESPACE" "svc/${ARGOCD_SERVER_SERVICE}" \
|
prole_register_port_forward "argocd" "$ARGOCD_NAMESPACE" "svc/${ARGOCD_SERVER_SERVICE}" \
|
||||||
"$ARGOCD_PORT_FORWARD_LOCAL" "$ARGOCD_PORT_FORWARD_REMOTE" "0.0.0.0" "TCP" "ArgoCD"
|
"$ARGOCD_PORT_FORWARD_LOCAL" "$ARGOCD_PORT_FORWARD_REMOTE" "0.0.0.0" "TCP" "ArgoCD"
|
||||||
;;
|
;;
|
||||||
|
|||||||
138
etc/init_cnpg_gke.sh
Executable file
138
etc/init_cnpg_gke.sh
Executable file
@ -0,0 +1,138 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# init_cnpg_gke.sh
|
||||||
|
# Provision CloudNativePG on GKE with GCS backup via Workload Identity.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./etc/init_cnpg_gke.sh [--project PROJECT_ID] [--region REGION] [--cluster CLUSTER_NAME]
|
||||||
|
#
|
||||||
|
# Env vars (override flags):
|
||||||
|
# GCP_PROJECT_ID, GCP_REGION, GKE_CLUSTER, GCS_BACKUP_BUCKET,
|
||||||
|
# CNPG_NAMESPACE, ARTIFACT_REGISTRY, CLOUDSDK_AUTH_ACCESS_TOKEN
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
GKE_MANIFEST_DIR="$REPO_ROOT/deploy/gcp/gke"
|
||||||
|
|
||||||
|
# ── Defaults ────────────────────────────────────────────────────────────────
|
||||||
|
GCP_PROJECT_ID="${GCP_PROJECT_ID:-}"
|
||||||
|
GCP_REGION="${GCP_REGION:-us-central1}"
|
||||||
|
GKE_CLUSTER="${GKE_CLUSTER:-knoe-dev-0}"
|
||||||
|
GCS_BACKUP_BUCKET="${GCS_BACKUP_BUCKET:-knoe-0-backups}"
|
||||||
|
GCS_WAL_BUCKET="${GCS_WAL_BUCKET:-knoe-0-wal}"
|
||||||
|
CNPG_NAMESPACE="${CNPG_NAMESPACE:-ecosystem-0}"
|
||||||
|
CNPG_BACKUP_SA="${CNPG_BACKUP_SA:-cnpg-backup}"
|
||||||
|
ARTIFACT_REGISTRY="${ARTIFACT_REGISTRY:-}"
|
||||||
|
|
||||||
|
# ── Argument parsing ─────────────────────────────────────────────────────────
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--project) GCP_PROJECT_ID="$2"; shift 2 ;;
|
||||||
|
--region) GCP_REGION="$2"; shift 2 ;;
|
||||||
|
--cluster) GKE_CLUSTER="$2"; shift 2 ;;
|
||||||
|
--bucket) GCS_BACKUP_BUCKET="$2"; shift 2 ;;
|
||||||
|
--namespace) CNPG_NAMESPACE="$2"; shift 2 ;;
|
||||||
|
--registry) ARTIFACT_REGISTRY="$2"; shift 2 ;;
|
||||||
|
*) echo "Unknown argument: $1" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -z "$GCP_PROJECT_ID" ]] && {
|
||||||
|
# Try to read from gcp.cfg
|
||||||
|
GCP_CFG="$REPO_ROOT/conf/prod/gcp.cfg"
|
||||||
|
if [[ -f "$GCP_CFG" ]]; then
|
||||||
|
GCP_PROJECT_ID=$(grep '^project_id' "$GCP_CFG" | sed 's/.*=\s*"\?\([^"]*\)"\?.*/\1/' | tr -d '[:space:]')
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
[[ -z "$GCP_PROJECT_ID" ]] && { echo "ERROR: GCP_PROJECT_ID not set and conf/prod/gcp.cfg not found." >&2; exit 1; }
|
||||||
|
|
||||||
|
GCP_SA_EMAIL="${CNPG_BACKUP_SA}@${GCP_PROJECT_ID}.iam.gserviceaccount.com"
|
||||||
|
|
||||||
|
log() { echo "[init_cnpg_gke] $*"; }
|
||||||
|
|
||||||
|
# ── Tool checks ──────────────────────────────────────────────────────────────
|
||||||
|
for tool in gcloud kubectl gsutil; do
|
||||||
|
command -v "$tool" >/dev/null || { echo "ERROR: $tool not found in PATH." >&2; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
# ── 1. Acquire kubeconfig ────────────────────────────────────────────────────
|
||||||
|
log "Fetching kubeconfig for $GKE_CLUSTER in $GCP_REGION ..."
|
||||||
|
gcloud container clusters get-credentials "$GKE_CLUSTER" \
|
||||||
|
--project "$GCP_PROJECT_ID" \
|
||||||
|
--region "$GCP_REGION"
|
||||||
|
|
||||||
|
# ── 2. Create GCS buckets ────────────────────────────────────────────────────
|
||||||
|
for bucket in "$GCS_BACKUP_BUCKET" "$GCS_WAL_BUCKET"; do
|
||||||
|
if gsutil ls -b "gs://$bucket" >/dev/null 2>&1; then
|
||||||
|
log "Bucket gs://$bucket already exists."
|
||||||
|
else
|
||||||
|
log "Creating bucket gs://$bucket ..."
|
||||||
|
gsutil mb -p "$GCP_PROJECT_ID" -l "$GCP_REGION" "gs://$bucket"
|
||||||
|
gsutil versioning set on "gs://$bucket"
|
||||||
|
gsutil lifecycle set /dev/stdin "gs://$bucket" <<EOF
|
||||||
|
{"rule":[{"action":{"type":"Delete"},"condition":{"age":30}}]}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# ── 3. Create GCP service account ────────────────────────────────────────────
|
||||||
|
if gcloud iam service-accounts describe "$GCP_SA_EMAIL" --project "$GCP_PROJECT_ID" >/dev/null 2>&1; then
|
||||||
|
log "Service account $GCP_SA_EMAIL already exists."
|
||||||
|
else
|
||||||
|
log "Creating service account $GCP_SA_EMAIL ..."
|
||||||
|
gcloud iam service-accounts create "$CNPG_BACKUP_SA" \
|
||||||
|
--display-name="CNPG GCS Backup" \
|
||||||
|
--project="$GCP_PROJECT_ID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 4. Grant storage access ───────────────────────────────────────────────────
|
||||||
|
log "Granting objectAdmin on backup buckets to $GCP_SA_EMAIL ..."
|
||||||
|
for bucket in "$GCS_BACKUP_BUCKET" "$GCS_WAL_BUCKET"; do
|
||||||
|
gsutil iam ch \
|
||||||
|
"serviceAccount:${GCP_SA_EMAIL}:objectAdmin" \
|
||||||
|
"gs://$bucket"
|
||||||
|
done
|
||||||
|
|
||||||
|
# ── 5. Bind Workload Identity ─────────────────────────────────────────────────
|
||||||
|
log "Binding Workload Identity ..."
|
||||||
|
gcloud iam service-accounts add-iam-policy-binding "$GCP_SA_EMAIL" \
|
||||||
|
--role=roles/iam.workloadIdentityUser \
|
||||||
|
--member="serviceAccount:${GCP_PROJECT_ID}.svc.id.goog[${CNPG_NAMESPACE}/cnpg-backup-sa]" \
|
||||||
|
--project="$GCP_PROJECT_ID"
|
||||||
|
|
||||||
|
# ── 6. Apply namespace ────────────────────────────────────────────────────────
|
||||||
|
log "Applying namespace $CNPG_NAMESPACE ..."
|
||||||
|
kubectl apply -f "$GKE_MANIFEST_DIR/namespace.yaml"
|
||||||
|
|
||||||
|
# ── 7. Install CNPG operator (if not present) ─────────────────────────────────
|
||||||
|
if ! kubectl get crd clusters.postgresql.cnpg.io >/dev/null 2>&1; then
|
||||||
|
log "Installing CloudNativePG operator ..."
|
||||||
|
kubectl apply --server-side -f \
|
||||||
|
https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/main/releases/cnpg-1.24.0.yaml
|
||||||
|
log "Waiting for CNPG operator to be ready ..."
|
||||||
|
kubectl rollout status deployment/cnpg-controller-manager -n cnpg-system --timeout=120s
|
||||||
|
else
|
||||||
|
log "CNPG operator already installed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 8. Apply ServiceAccount + annotate with WI ───────────────────────────────
|
||||||
|
log "Applying CNPG backup ServiceAccount with Workload Identity annotation ..."
|
||||||
|
GCP_PROJECT_ID="$GCP_PROJECT_ID" envsubst < "$GKE_MANIFEST_DIR/knoe-db-backup-gcs.yaml" \
|
||||||
|
| kubectl apply -f -
|
||||||
|
|
||||||
|
kubectl annotate serviceaccount cnpg-backup-sa \
|
||||||
|
-n "$CNPG_NAMESPACE" \
|
||||||
|
"iam.gke.io/gcp-service-account=${GCP_SA_EMAIL}" \
|
||||||
|
--overwrite
|
||||||
|
|
||||||
|
# ── 9. Apply CNPG cluster ────────────────────────────────────────────────────
|
||||||
|
log "Applying knoe-db CNPG cluster ..."
|
||||||
|
ARTIFACT_REGISTRY="${ARTIFACT_REGISTRY}" envsubst < "$GKE_MANIFEST_DIR/knoe-db.yaml" \
|
||||||
|
| kubectl apply -f -
|
||||||
|
|
||||||
|
log ""
|
||||||
|
log "Done. Monitor with:"
|
||||||
|
log " kubectl -n $CNPG_NAMESPACE get cluster knoe-db"
|
||||||
|
log " kubectl -n $CNPG_NAMESPACE get pods -l cnpg.io/cluster=knoe-db"
|
||||||
|
log " kubectl -n $CNPG_NAMESPACE get scheduledbackup"
|
||||||
@ -96,6 +96,9 @@ DB_PORT="${GITLAB_DB_PORT:-5432}"
|
|||||||
|
|
||||||
# GitLab domain (reuses the git.prole.org shared hostname)
|
# GitLab domain (reuses the git.prole.org shared hostname)
|
||||||
GITLAB_DOMAIN="${GITLAB_DOMAIN:-git.prole.org}"
|
GITLAB_DOMAIN="${GITLAB_DOMAIN:-git.prole.org}"
|
||||||
|
|
||||||
|
# Google Workspace OIDC via knoe-auth — set FRONTDOOR_HOST to enable
|
||||||
|
FRONTDOOR_HOST="${FRONTDOOR_HOST:-}"
|
||||||
GITLAB_RELEASE="gitlab"
|
GITLAB_RELEASE="gitlab"
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@ -320,6 +323,22 @@ fi
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Create the GitLab CR (operator reconciles this into the full deployment)
|
# Create the GitLab CR (operator reconciles this into the full deployment)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Apply gitlab-google-oidc secret (OIDC provider config for OmniAuth)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
if [[ -n "$FRONTDOOR_HOST" ]]; then
|
||||||
|
PLATFORM_DOMAIN="${PLATFORM_DOMAIN:-}"
|
||||||
|
oidc_secret_tmpl="${SCRIPT_DIR}/../deploy/gcp/gke/gitlab-google-oidc-secret.example.yaml"
|
||||||
|
if [[ -f "$oidc_secret_tmpl" ]]; then
|
||||||
|
log "Applying gitlab-google-oidc secret (issuer=https://${FRONTDOOR_HOST}/auth) ..."
|
||||||
|
FRONTDOOR_HOST="$FRONTDOOR_HOST" PLATFORM_DOMAIN="$PLATFORM_DOMAIN" \
|
||||||
|
envsubst < "$oidc_secret_tmpl" | kubectl apply -n "$NAMESPACE" -f - >/dev/null || \
|
||||||
|
warn "Could not apply gitlab-google-oidc secret; create it manually from deploy/gcp/gke/gitlab-google-oidc-secret.example.yaml"
|
||||||
|
else
|
||||||
|
warn "gitlab-google-oidc-secret.example.yaml not found; skipping OIDC secret (create it manually)."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
log "Applying GitLab CR (domain=${GITLAB_DOMAIN}, db=${GITLAB_DB_NAME}@${DB_HOST})..."
|
log "Applying GitLab CR (domain=${GITLAB_DOMAIN}, db=${GITLAB_DB_NAME}@${DB_HOST})..."
|
||||||
|
|
||||||
kubectl apply -f - <<EOF
|
kubectl apply -f - <<EOF
|
||||||
@ -356,6 +375,20 @@ spec:
|
|||||||
# the gitlab namespace but can reference services in knoe-db.
|
# the gitlab namespace but can reference services in knoe-db.
|
||||||
serviceAccount:
|
serviceAccount:
|
||||||
create: true
|
create: true
|
||||||
|
$(if [[ -n "$FRONTDOOR_HOST" ]]; then
|
||||||
|
cat <<OMNIAUTH
|
||||||
|
appConfig:
|
||||||
|
omniauth:
|
||||||
|
enabled: true
|
||||||
|
autoSignInWithProvider: openid_connect
|
||||||
|
allowSingleSignOn:
|
||||||
|
- openid_connect
|
||||||
|
blockAutoCreatedUsers: false
|
||||||
|
providers:
|
||||||
|
- secret: gitlab-google-oidc
|
||||||
|
key: provider
|
||||||
|
OMNIAUTH
|
||||||
|
fi)
|
||||||
# Disable bundled sub-charts — we provide our own data stores
|
# Disable bundled sub-charts — we provide our own data stores
|
||||||
postgresql:
|
postgresql:
|
||||||
install: false
|
install: false
|
||||||
|
|||||||
@ -49,6 +49,8 @@ class ProdBackupsConfig:
|
|||||||
backupBucket: str = "knoe-0-backups"
|
backupBucket: str = "knoe-0-backups"
|
||||||
walBucket: str = "knoe-0-wal"
|
walBucket: str = "knoe-0-wal"
|
||||||
retentionDays: int = 14
|
retentionDays: int = 14
|
||||||
|
backupProvider: str = "gcs" # "gcs" | "garage"
|
||||||
|
workloadIdentitySA: str = "cnpg-backup"
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
@ -58,6 +60,9 @@ class ProdAuthConfig:
|
|||||||
clientId: str = "secretref://google-oidc-client-id"
|
clientId: str = "secretref://google-oidc-client-id"
|
||||||
clientSecret: str = "secretref://google-oidc-client-secret"
|
clientSecret: str = "secretref://google-oidc-client-secret"
|
||||||
bootstrapAdminEmail: str = "admin@knoey.com"
|
bootstrapAdminEmail: str = "admin@knoey.com"
|
||||||
|
googleClientId: str = "" # transient — not persisted to prole.cfg
|
||||||
|
googleClientSecret: str = "" # transient — not persisted to prole.cfg
|
||||||
|
googleHostedDomain: str = "" # blank = any Google account; set to restrict Workspace domain
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
@ -212,6 +217,10 @@ def build_config(payload: dict[str, Any] | None = None) -> KnoeProductionConfig:
|
|||||||
cfg.backups.retentionDays = _coerce_int(
|
cfg.backups.retentionDays = _coerce_int(
|
||||||
backups.get("retentionDays", cfg.backups.retentionDays), cfg.backups.retentionDays
|
backups.get("retentionDays", cfg.backups.retentionDays), cfg.backups.retentionDays
|
||||||
)
|
)
|
||||||
|
cfg.backups.backupProvider = _str_or_empty(backups.get("backupProvider")) or cfg.backups.backupProvider
|
||||||
|
cfg.backups.workloadIdentitySA = (
|
||||||
|
_str_or_empty(backups.get("workloadIdentitySA")) or cfg.backups.workloadIdentitySA
|
||||||
|
)
|
||||||
|
|
||||||
cfg.auth.provider = _str_or_empty(auth.get("provider")) or cfg.auth.provider
|
cfg.auth.provider = _str_or_empty(auth.get("provider")) or cfg.auth.provider
|
||||||
cfg.auth.issuer = _str_or_empty(auth.get("issuer")) or cfg.auth.issuer
|
cfg.auth.issuer = _str_or_empty(auth.get("issuer")) or cfg.auth.issuer
|
||||||
@ -220,6 +229,9 @@ def build_config(payload: dict[str, Any] | None = None) -> KnoeProductionConfig:
|
|||||||
cfg.auth.bootstrapAdminEmail = (
|
cfg.auth.bootstrapAdminEmail = (
|
||||||
_str_or_empty(auth.get("bootstrapAdminEmail")) or cfg.auth.bootstrapAdminEmail
|
_str_or_empty(auth.get("bootstrapAdminEmail")) or cfg.auth.bootstrapAdminEmail
|
||||||
)
|
)
|
||||||
|
cfg.auth.googleClientId = _str_or_empty(auth.get("googleClientId"))
|
||||||
|
cfg.auth.googleClientSecret = _str_or_empty(auth.get("googleClientSecret"))
|
||||||
|
cfg.auth.googleHostedDomain = _str_or_empty(auth.get("googleHostedDomain"))
|
||||||
|
|
||||||
cfg.routing.frontdoorHost = _str_or_empty(routing.get("frontdoorHost")) or cfg.routing.frontdoorHost
|
cfg.routing.frontdoorHost = _str_or_empty(routing.get("frontdoorHost")) or cfg.routing.frontdoorHost
|
||||||
cfg.routing.platformDomain = _str_or_empty(routing.get("platformDomain")) or cfg.routing.platformDomain
|
cfg.routing.platformDomain = _str_or_empty(routing.get("platformDomain")) or cfg.routing.platformDomain
|
||||||
@ -354,10 +366,13 @@ def opentofu_vars(config: KnoeProductionConfig) -> dict[str, Any]:
|
|||||||
"backup_bucket": config.backups.backupBucket,
|
"backup_bucket": config.backups.backupBucket,
|
||||||
"wal_bucket": config.backups.walBucket,
|
"wal_bucket": config.backups.walBucket,
|
||||||
"backup_retention_days": config.backups.retentionDays,
|
"backup_retention_days": config.backups.retentionDays,
|
||||||
|
"backup_provider": config.backups.backupProvider,
|
||||||
|
"workload_identity_sa": config.backups.workloadIdentitySA,
|
||||||
"oidc_issuer": config.auth.issuer,
|
"oidc_issuer": config.auth.issuer,
|
||||||
"oidc_client_id_ref": config.auth.clientId,
|
"oidc_client_id_ref": config.auth.clientId,
|
||||||
"oidc_client_secret_ref": config.auth.clientSecret,
|
"oidc_client_secret_ref": config.auth.clientSecret,
|
||||||
"bootstrap_admin_email": config.auth.bootstrapAdminEmail,
|
"bootstrap_admin_email": config.auth.bootstrapAdminEmail,
|
||||||
|
"google_hosted_domain": config.auth.googleHostedDomain,
|
||||||
"frontdoor_host": config.routing.frontdoorHost,
|
"frontdoor_host": config.routing.frontdoorHost,
|
||||||
"platform_domain": config.routing.platformDomain,
|
"platform_domain": config.routing.platformDomain,
|
||||||
"tls_mode": config.routing.tlsMode,
|
"tls_mode": config.routing.tlsMode,
|
||||||
|
|||||||
46
supabase/helm/prole-supabase/values-gke.yaml
Normal file
46
supabase/helm/prole-supabase/values-gke.yaml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# GKE production values overlay for prole-supabase Helm chart.
|
||||||
|
#
|
||||||
|
# Apply on top of values.yaml:
|
||||||
|
# helm upgrade --install prole-supabase ./supabase/helm/prole-supabase \
|
||||||
|
# --values supabase/helm/prole-supabase/values.yaml \
|
||||||
|
# --values supabase/helm/prole-supabase/values-gke.yaml \
|
||||||
|
# --set environment.auth.GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID="$CLIENT_ID" \
|
||||||
|
# --set environment.auth.GOTRUE_EXTERNAL_GOOGLE_SECRET="$CLIENT_SECRET" \
|
||||||
|
# --set environment.auth.GOTRUE_SITE_URL="https://$FRONTDOOR_HOST" \
|
||||||
|
# --set environment.auth.GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI="https://$FRONTDOOR_HOST/auth/v1/callback" \
|
||||||
|
# --set environment.auth.GOTRUE_URI_ALLOW_LIST="https://$FRONTDOOR_HOST/**"
|
||||||
|
#
|
||||||
|
# Or set FRONTDOOR_HOST, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET in environment
|
||||||
|
# and let init_supabase.sh --mode k8s substitute them automatically.
|
||||||
|
|
||||||
|
# ── Storage: use GCS instead of bundled MinIO ───────────────────────────────
|
||||||
|
# When CNPG Workload Identity is active the pod SA already has storage access;
|
||||||
|
# set storage driver to gcs and disable minio.
|
||||||
|
deployment:
|
||||||
|
minio:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# ── GoTrue: enable Google OAuth via knoe-auth OIDC broker ───────────────────
|
||||||
|
environment:
|
||||||
|
auth:
|
||||||
|
# Override base URL to the GKE frontdoor
|
||||||
|
API_EXTERNAL_URL: "" # set to https://<frontdoor-host>/auth/v1 at deploy time
|
||||||
|
GOTRUE_SITE_URL: "" # set to https://<frontdoor-host>
|
||||||
|
GOTRUE_URI_ALLOW_LIST: "" # set to https://<frontdoor-host>/**
|
||||||
|
|
||||||
|
# Google OAuth2 — client ID and secret from knoe-auth-google-oidc secret
|
||||||
|
GOTRUE_EXTERNAL_GOOGLE_ENABLED: "true"
|
||||||
|
GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID: "" # injected at deploy time
|
||||||
|
GOTRUE_EXTERNAL_GOOGLE_SECRET: "" # injected at deploy time
|
||||||
|
GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI: "" # set to https://<frontdoor-host>/auth/v1/callback
|
||||||
|
|
||||||
|
# Disable anonymous sign-in in production
|
||||||
|
GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED: "false"
|
||||||
|
|
||||||
|
# Auto-confirm email (Google accounts are pre-verified)
|
||||||
|
GOTRUE_MAILER_AUTOCONFIRM: "true"
|
||||||
|
|
||||||
|
# ── Ingress: use GKE-managed ingress class ──────────────────────────────────
|
||||||
|
ingress:
|
||||||
|
studio:
|
||||||
|
className: "gce" # GKE L7 load balancer; override with "kong" if Kong is installed
|
||||||
Loading…
Reference in New Issue
Block a user