Files
infrastructure/servers/gcp/k8s/gitea/external-secrets.yaml
T
Will Anderson 9330107fcc migrate Vault and Gitea to GKE Autopilot cluster
Implements Option A: move Vault (3x GCE e2-small) and Gitea (Legion k8s)
onto a new GKE Autopilot cluster (neuron-platform, us-central1) managed
through Legion Argo CD.

Terraform (servers/gcp/):
- gke.tf: GKE Autopilot cluster, Workload Identity bindings for Vault (KMS)
  and Gitea (Cloud SQL)
- cloud-sql.tf: gitea database + user on neuron-prod-pg15, gitea GCP SA,
  gitea-database-url and gitea-db-password Secret Manager secrets
- vault-nodes.tf: PENDING DECOMMISSION comment with migration checklist

k8s manifests (servers/gcp/k8s/):
- vault/: namespace.yaml
- gitea/: namespace, serviceaccount (Workload Identity annotation), pvc (50Gi
  standard-rwo), deployment (Gitea + Cloud SQL Auth Proxy sidecar), service,
  configmap (custom CSS carried from Legion), external-secrets (GCP SM provider)
- argocd-apps/: vault-gke.yaml, vault-helm-gke.yaml (Helm chart, HA Raft 3
  replicas, GCP KMS auto-unseal, topologySpread across zones, 10Gi premium-rwo),
  gitea-gke.yaml — all target GKE_CLUSTER_ENDPOINT placeholder

Legion (servers/legion/):
- apps/gke-apps.yaml: App-of-Apps entry point on Legion Argo CD that syncs the
  GKE Application manifests
- k8s/gitea-runner/Dockerfile: add system-level git insteadOf so GKE CI runners
  resolve Gitea in-cluster without Cloudflare Access headers
2026-05-04 20:40:48 -05:00

69 lines
2.8 KiB
YAML

---
# SecretStore for GKE — uses GCP Secret Manager directly via Workload Identity.
# On GKE we use the GCP provider instead of a Vault-backed store, since
# Vault itself may be in the process of being migrated.
# The Gitea GCP SA has secretmanager.secretAccessor on its own secret (see cloud-sql.tf).
#
# Pre-requisite: install ESO on GKE before applying this:
# helm install external-secrets external-secrets/external-secrets \
# --namespace external-secrets --create-namespace
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: gcp-secretmanager
namespace: gitea
spec:
provider:
gcpsm:
projectID: neuron-785695
# Workload Identity is used automatically — no explicit auth needed
# when the pod's ServiceAccount has the iam.gke.io/gcp-service-account annotation.
---
# gitea-db — Gitea database password, pulled from GCP Secret Manager.
# The Secret Manager secret "gitea-database-url" stores the full DSN, but we
# extract just the password field for use in GITEA__database__PASSWD.
#
# The full DSN format from Terraform:
# host=/cloudsql/<conn> user=gitea password=<pw> dbname=gitea sslmode=disable
#
# ESO extracts the raw secret value. Since GCP Secret Manager stores the full
# DSN as a single string, we store the password separately as "gitea-db-password"
# so Gitea can receive it as a discrete env var.
#
# Bootstrap: after `terraform apply`, run:
# PASSWORD=$(gcloud secrets versions access latest --secret=gitea-database-url \
# | grep -oP '(?<=password=)\S+')
# echo -n "$PASSWORD" | gcloud secrets create gitea-db-password \
# --data-file=- --project=neuron-785695
#
# Or simpler — let Terraform write it directly. The gitea-db-password secret
# is managed by the gitea-database-url secret version output. Use the full DSN
# secret and parse in-pod, or store password separately.
#
# For simplicity: pull the full DSN and use it as GITEA__database__PASSWD
# is wrong (it's a DSN, not a password). Instead, use the Cloud SQL proxy
# unix socket and no password — configure Gitea to use peer auth.
#
# ACTUAL APPROACH: ExternalSecret pulls the full DSN string into a k8s Secret
# key "dsn". A separate gitea-db secret provides just the password field.
# Terraform outputs both; add a gitea-db-password Secret Manager secret in cloud-sql.tf.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: gitea-db
namespace: gitea
spec:
refreshInterval: 1h
secretStoreRef:
name: gcp-secretmanager
kind: SecretStore
target:
name: gitea-db
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
# This secret is populated by Terraform (gitea-db-password in cloud-sql.tf)
# It contains just the raw database password (no DSN prefix).
key: gitea-db-password