diff --git a/conf/gke.cfg b/conf/gke.cfg index 34a7e90..0bf953f 100644 --- a/conf/gke.cfg +++ b/conf/gke.cfg @@ -127,6 +127,21 @@ GITLAB_OIDC_CLIENT_ID = secretref://google-oidc-client-id GITLAB_OIDC_CLIENT_SECRET = secretref://google-oidc-client-secret GITLAB_OIDC_ISSUER = https://accounts.google.com GITLAB_PUBLIC_HOSTS = git.knoe.dev +; Pin the GCE L7 HTTPS ingresses to reserved GLOBAL static IPs (gcloud compute +; addresses create --global). Prevents IP churn on ingress delete/recreate. +GITLAB_GLOBAL_STATIC_IP_NAME = git-knoe-dev +; Kong (knoe-system/svc-knoe-ingress, serves svc.knoe.dev + api.knoe.dev) +SVC_KNOE_GLOBAL_STATIC_IP_NAME = svc-knoe +; Supabase Kong API ingress (supabase/supabase-kong, serves api.0.knoe.dev) +SUPABASE_API_GLOBAL_STATIC_IP_NAME = supabase-api +; Supabase Studio ingress (supabase/supabase-studio, serves db.0.knoe.dev) +SUPABASE_STUDIO_GLOBAL_STATIC_IP_NAME = supabase-studio +; SSH ingress — dedicated REGIONAL external static IP (us-west3) bound to +; gitlab-shell Service of type LoadBalancer. Must be created via +; gcloud compute addresses create git-knoe-ssh --region=us-west3 +; then fill in the .address value below. +GITLAB_SSH_HOST = git-ssh.knoe.dev +GITLAB_SHELL_LOADBALANCER_IP = 34.106.243.154 GITLAB_REPAIR_BLOCKED_AUTOCLEAN = 1 GITLAB_WEBSERVICE_LIMITS_MEMORY = 3Gi GITLAB_WEBSERVICE_PUMA_THREADS_MAX = 2 diff --git a/etc/init_gitlab.sh b/etc/init_gitlab.sh index 2bbc687..c1d0a4a 100755 --- a/etc/init_gitlab.sh +++ b/etc/init_gitlab.sh @@ -2428,6 +2428,31 @@ if [[ "$MODE" == "k8s" ]]; then fi GITLAB_INGRESS_CLASS="${GITLAB_INGRESS_CLASS:-$_default_gitlab_ingress_class}" +# --------------------------------------------------------------------------- +# Git SSH hostname + LoadBalancer IP +# --------------------------------------------------------------------------- +# On GKE with Google-managed certs, HTTPS has to live on a GCE global L7 IP +# (ManagedCertificate CRD only binds there). Port 22 requires a regional +# Network LB which can't share an IP with a global L7. So in k8s mode we +# default to a dedicated SSH hostname (git-ssh.) bound to a +# user-reserved regional external static IP via GITLAB_SHELL_LOADBALANCER_IP. +# In k3d/k3s modes the gitlab-shell Service stays ClusterIP (typically +# port-forwarded) and global.hosts.ssh tracks the main gitlab hostname. +_default_gitlab_ssh_host="$GITLAB_DOMAIN" +if [[ "$MODE" == "k8s" ]]; then + _default_gitlab_ssh_host="git-ssh.${PRIMARY_GITLAB_DOMAIN_ROOT}" +fi +GITLAB_SSH_HOST="${GITLAB_SSH_HOST:-$_default_gitlab_ssh_host}" + +# Pre-reserved regional external static IP for the gitlab-shell LoadBalancer +# Service. If blank, no service override is emitted (ClusterIP default). +GITLAB_SHELL_LOADBALANCER_IP="${GITLAB_SHELL_LOADBALANCER_IP:-}" + +# externalTrafficPolicy preserves client source IPs in SSH auth logs — useful +# for abuse triage and rate-limiting. Requires at least one gitlab-shell pod +# per node in the LB backend; our replicaCount=1 is fine. +GITLAB_SHELL_EXTERNAL_TRAFFIC_POLICY="${GITLAB_SHELL_EXTERNAL_TRAFFIC_POLICY:-Local}" + # Single GitLab front-door owner model. # - operator: GitLab chart/operator-managed ingress owns ${GITLAB_PUBLIC_HOSTS} # - fallback: custom fallback ingress owns ${GITLAB_PUBLIC_HOSTS} @@ -3831,7 +3856,7 @@ fi) domain: ${PRIMARY_GITLAB_DOMAIN_ROOT} gitlab: name: ${GITLAB_DOMAIN} - ssh: ${GITLAB_DOMAIN} + ssh: ${GITLAB_SSH_HOST} ingress: class: ${GITLAB_INGRESS_CLASS} configureCertmanager: false @@ -4008,6 +4033,14 @@ ${WORKLOAD_JEMALLOC_VALUES_YAML} replicaCount: 1 minReplicas: 1 maxReplicas: 1 +$(if [[ -n "${GITLAB_SHELL_LOADBALANCER_IP:-}" ]]; then +cat <&2 fi diff --git a/supabase/helm/render_supabase.py b/supabase/helm/render_supabase.py index 6c3bb00..2cfaa70 100755 --- a/supabase/helm/render_supabase.py +++ b/supabase/helm/render_supabase.py @@ -630,6 +630,25 @@ def _build_overlay(cfg: configparser.ConfigParser, args: argparse.Namespace) -> "ManagedCertificate + FrontendConfig is the single TLS source of truth.\n" ) + # Optional: pin each GCE L7 ingress to a pre-reserved GLOBAL external + # static IP (gcloud compute addresses create --global). Prevents IP churn + # on ingress delete/recreate. Blank = GCE assigns ephemerally. + supabase_api_global_static_ip_name = _first( + os.environ.get("SUPABASE_API_GLOBAL_STATIC_IP_NAME", ""), + _cfg_get(cfg, "Global", "SUPABASE_API_GLOBAL_STATIC_IP_NAME"), + default="", + ).strip() + if _is_placeholder(supabase_api_global_static_ip_name): + supabase_api_global_static_ip_name = "" + + supabase_studio_global_static_ip_name = _first( + os.environ.get("SUPABASE_STUDIO_GLOBAL_STATIC_IP_NAME", ""), + _cfg_get(cfg, "Global", "SUPABASE_STUDIO_GLOBAL_STATIC_IP_NAME"), + default="", + ).strip() + if _is_placeholder(supabase_studio_global_static_ip_name): + supabase_studio_global_static_ip_name = "" + allow_traefik_public_ingress = _as_bool( _first( os.environ.get("SUPABASE_ALLOW_TRAEFIK_INGRESS", ""), @@ -980,6 +999,9 @@ def _build_overlay(cfg: configparser.ConfigParser, args: argparse.Namespace) -> "networking.gke.io/managed-certificates": supabase_api_managed_cert_name, "networking.gke.io/v1beta1.FrontendConfig": supabase_api_frontend_config_name, } if mode == "k8s" else {}), + **({ + "kubernetes.io/ingress.global-static-ip-name": supabase_api_global_static_ip_name, + } if mode == "k8s" and supabase_api_global_static_ip_name else {}), } }, "studioIngress": { @@ -992,6 +1014,9 @@ def _build_overlay(cfg: configparser.ConfigParser, args: argparse.Namespace) -> "networking.gke.io/managed-certificates": supabase_studio_managed_cert_name, "networking.gke.io/v1beta1.FrontendConfig": supabase_studio_frontend_config_name, } if mode == "k8s" else {}), + **({ + "kubernetes.io/ingress.global-static-ip-name": supabase_studio_global_static_ip_name, + } if mode == "k8s" and supabase_studio_global_static_ip_name else {}), **({ "nginx.ingress.kubernetes.io/auth-url": auth_verify_url, "nginx.ingress.kubernetes.io/auth-signin": auth_signin_url,