Expand GCP infra: accounts + API services, Cloud SQL, Artifact Registry
Architecture: intelligence stays on Legion; only compiled artifacts cross to GCP. Source code and Neuron's knowledge base never leave the system. Artifact Registry: - neuron-marketing, neuron-accounts, neuron-api repos in us-central1 - Keep-last-10 cleanup policy; ci-pusher SA with writer access - Legion CI runners authenticate via GCP_SA_KEY Gitea secret Cloud SQL (cloud-sql.tf): - postgres-15 on db-g1-small, us-central1 (scale up to REGIONAL HA at 1k users) - Point-in-time recovery, 14-day backup retention - Accounts DB + user; password generated and stored in Secret Manager - JWT signing key in Secret Manager (shared by accounts + api) - Cloud Run connects via built-in Auth Proxy (Unix socket volume mount) Accounts Cloud Run (cloud-run-accounts.tf): - 3 regions (us-central1, europe-west1, asia-northeast1), min:1 max:50 - Cloud SQL proxy volume mount; secrets via Secret Manager - Stripe + JWT env vars; health probe on /health API Cloud Run (cloud-run-api.tf): - 3 regions, min:1 max:100, cpu_idle=false (always-hot) - Validates JWTs from accounts service; no direct DB connection - License admin token from Secret Manager Load balancer (host-based routing): - Same global anycast IP for all three services - URL map routes by Host: neurontechnologies.ai→marketing, api.neurontechnologies.ai→api, accounts.neurontechnologies.ai→accounts - New managed SSL certs for api.* and accounts.* added to HTTPS proxy - Cloud Armor (WAF + rate limit) applied to all backends Service accounts + IAM: - neuron-accounts-sa: secretmanager.secretAccessor + cloudsql.client - neuron-api-sa: secretmanager.secretAccessor - allUsers invoker on all prod Cloud Run services (LB health checks) bootstrap.sh: - One-shot setup: pulls Stripe secrets from Vault → Secret Manager, creates CI SA JSON key, prints DNS + next-step instructions
This commit is contained in:
Executable
+97
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
# ── GCP Bootstrap — run once after terraform apply ────────────────────────────
|
||||
# Sets up secrets and credentials that Terraform can't create automatically.
|
||||
#
|
||||
# Prerequisites:
|
||||
# - GOOGLE_APPLICATION_CREDENTIALS or `gcloud auth application-default login`
|
||||
# - GCP project access
|
||||
# - Vault running (for reading existing secrets)
|
||||
# - terraform apply has run successfully (creates SA, secrets)
|
||||
#
|
||||
# Usage:
|
||||
# cd servers/gcp
|
||||
# terraform apply
|
||||
# bash bootstrap.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT="neuron-785695"
|
||||
VAULT_ADDR="${VAULT_ADDR:-https://vault.neuralplatform.ai}"
|
||||
|
||||
echo "==> Bootstrapping GCP secrets and CI credentials"
|
||||
|
||||
# ── 1. Populate Stripe secrets in GCP Secret Manager ─────────────────────────
|
||||
echo "--> Pulling Stripe secrets from Vault..."
|
||||
MARKETING_SECRETS=$(curl -sf \
|
||||
-H "X-Vault-Token: ${VAULT_TOKEN}" \
|
||||
"${VAULT_ADDR}/v1/secret/data/neuron-technologies/marketing")
|
||||
|
||||
populate_secret() {
|
||||
local secret_id="$1"
|
||||
local vault_key="$2"
|
||||
local value
|
||||
value=$(echo "${MARKETING_SECRETS}" | python3 -c "
|
||||
import json,sys; d=json.load(sys.stdin)['data']['data']; print(d.get('${vault_key}',''))
|
||||
")
|
||||
if [ -z "${value}" ]; then
|
||||
echo " WARN: vault key '${vault_key}' not found — skipping ${secret_id}"
|
||||
return
|
||||
fi
|
||||
# Check if secret already has a version
|
||||
if gcloud secrets versions list "${secret_id}" --project="${PROJECT}" \
|
||||
--format="value(name)" 2>/dev/null | grep -q .; then
|
||||
echo " SKIP: ${secret_id} already has a version"
|
||||
else
|
||||
echo "${value}" | gcloud secrets versions add "${secret_id}" \
|
||||
--project="${PROJECT}" \
|
||||
--data-file=-
|
||||
echo " OK: ${secret_id}"
|
||||
fi
|
||||
}
|
||||
|
||||
populate_secret "stripe-secret-key" "stripe_secret_key"
|
||||
populate_secret "stripe-webhook-secret" "stripe_webhook_secret"
|
||||
populate_secret "stripe-price-professional" "stripe_price_professional"
|
||||
populate_secret "stripe-price-founding" "stripe_price_founding"
|
||||
|
||||
# ── 2. License admin token ────────────────────────────────────────────────────
|
||||
echo "--> Populating license-admin-token..."
|
||||
LICENSE_TOKEN=$(curl -sf \
|
||||
-H "X-Vault-Token: ${VAULT_TOKEN}" \
|
||||
"${VAULT_ADDR}/v1/secret/data/neuron-technologies/marketing" \
|
||||
| python3 -c "import json,sys; print(json.load(sys.stdin)['data']['data'].get('license_admin_token',''))")
|
||||
if [ -n "${LICENSE_TOKEN}" ]; then
|
||||
echo "${LICENSE_TOKEN}" | gcloud secrets versions add "license-admin-token" \
|
||||
--project="${PROJECT}" --data-file=- 2>/dev/null || echo " SKIP: already exists"
|
||||
echo " OK: license-admin-token"
|
||||
fi
|
||||
|
||||
# ── 3. Create CI service account JSON key ────────────────────────────────────
|
||||
CI_SA_EMAIL=$(terraform output -raw ci_pusher_email)
|
||||
echo "--> Creating CI SA key for: ${CI_SA_EMAIL}"
|
||||
KEY_FILE="/tmp/neuron-ci-pusher.json"
|
||||
gcloud iam service-accounts keys create "${KEY_FILE}" \
|
||||
--iam-account="${CI_SA_EMAIL}" \
|
||||
--project="${PROJECT}"
|
||||
echo " SA key written to: ${KEY_FILE}"
|
||||
echo ""
|
||||
echo " !! Add this as a Gitea secret GCP_SA_KEY in the neuron-technologies/neuron repo:"
|
||||
echo " tea secret set --repo neuron-technologies/neuron GCP_SA_KEY < ${KEY_FILE}"
|
||||
echo " Then delete the key file:"
|
||||
echo " rm ${KEY_FILE}"
|
||||
echo ""
|
||||
|
||||
# ── 4. Summary ────────────────────────────────────────────────────────────────
|
||||
echo "==> Bootstrap complete"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Set Gitea secret: tea secret set --repo neuron-technologies/neuron GCP_SA_KEY < /tmp/neuron-ci-pusher.json"
|
||||
echo " 2. Delete key file: rm /tmp/neuron-ci-pusher.json"
|
||||
echo " 3. Point DNS at: $(terraform output -raw prod_lb_ip)"
|
||||
echo " A records (proxied=true in Cloudflare):"
|
||||
echo " neurontechnologies.ai → prod_lb_ip"
|
||||
echo " www.neurontechnologies.ai → prod_lb_ip"
|
||||
echo " api.neurontechnologies.ai → prod_lb_ip"
|
||||
echo " accounts.neurontechnologies.ai → prod_lb_ip"
|
||||
echo " 4. Run a marketing CI build on main to push first image to GCP AR"
|
||||
echo " 5. Check SSL cert provisioning: gcloud compute ssl-certificates list --project=${PROJECT}"
|
||||
Reference in New Issue
Block a user