# ── Soma — AI Inference Gateway — Cloud Run ─────────────────────────────────── # Soma is a Rust/Axum inference proxy that speaks OpenAI-compatible API. # Single region (us-central1) — inference latency matters, no need for global # multi-region replication at this stage. # # Public endpoint: https://ai.neurontechnologies.ai/v1/chat/completions # Auth: Bearer token (svc-* prefix) via require_api_key middleware. locals { soma_labels = { "managed-by" = "terraform" "service" = "neuron-soma" } soma_image = "us-central1-docker.pkg.dev/${var.project_id}/neuron-soma/soma:latest" } # ── Artifact Registry ───────────────────────────────────────────────────────── resource "google_artifact_registry_repository" "soma" { location = "us-central1" repository_id = "neuron-soma" description = "Soma AI inference gateway (Rust) Docker images" format = "DOCKER" project = var.project_id cleanup_policies { id = "keep-last-10" action = "KEEP" most_recent_versions { keep_count = 10 } } } # ── CI pusher access to soma repo ───────────────────────────────────────────── resource "google_artifact_registry_repository_iam_member" "ci_soma" { project = var.project_id location = "us-central1" repository = google_artifact_registry_repository.soma.name role = "roles/artifactregistry.writer" member = "serviceAccount:${google_service_account.ci_pusher.email}" } resource "google_service_account_iam_member" "ci_pusher_act_as_soma" { service_account_id = google_service_account.soma.name role = "roles/iam.serviceAccountUser" member = "serviceAccount:${google_service_account.ci_pusher.email}" } # ── Service Account ─────────────────────────────────────────────────────────── resource "google_service_account" "soma" { account_id = "neuron-soma-sa" display_name = "Neuron Soma Cloud Run SA" description = "Service account for the Soma AI inference gateway on Cloud Run" project = var.project_id } resource "google_project_iam_member" "soma_secret_accessor" { project = var.project_id role = "roles/secretmanager.secretAccessor" member = "serviceAccount:${google_service_account.soma.email}" } # soma needs to create/terminate GCE GPU instances for inference resource "google_project_iam_member" "soma_compute_admin" { project = var.project_id role = "roles/compute.instanceAdmin.v1" member = "serviceAccount:${google_service_account.soma.email}" } # Allow soma to use the default Compute Engine SA for the instances it creates resource "google_project_iam_member" "soma_service_account_user" { project = var.project_id role = "roles/iam.serviceAccountUser" member = "serviceAccount:${google_service_account.soma.email}" } # Firewall: allow inbound TCP 8000 (vLLM) to inference nodes from anywhere. # Tighten later to Cloud Run egress IP ranges. resource "google_compute_firewall" "allow_vllm_from_soma" { name = "allow-vllm-from-soma" project = var.project_id network = "default" allow { protocol = "tcp" ports = ["8000"] } source_ranges = ["0.0.0.0/0"] target_tags = ["soma-inference-node"] } # ── Secrets ─────────────────────────────────────────────────────────────────── resource "google_secret_manager_secret" "soma_hf_token" { secret_id = "soma-hf-token" project = var.project_id replication { auto {} } } resource "google_secret_manager_secret_version" "soma_hf_token" { secret = google_secret_manager_secret.soma_hf_token.id secret_data = "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" } resource "google_secret_manager_secret" "soma_operator_key" { secret_id = "soma-operator-key" project = var.project_id replication { auto {} } } resource "google_secret_manager_secret_version" "soma_operator_key" { secret = google_secret_manager_secret.soma_operator_key.id secret_data = "svc-will-1ab07c23ab5112aa14378f2941f7cd3f" } resource "google_secret_manager_secret" "soma_node_secret" { secret_id = "soma-node-secret" project = var.project_id replication { auto {} } } resource "google_secret_manager_secret_version" "soma_node_secret" { secret = google_secret_manager_secret.soma_node_secret.id # 32-char hex secret for GCE startup script authentication secret_data = "a3f8d2e1c4b5a6978f0e3d2c1b4a5978f" } resource "google_secret_manager_secret" "soma_key_secret" { secret_id = "soma-key-secret" project = var.project_id replication { auto {} } } resource "google_secret_manager_secret_version" "soma_key_secret" { secret = google_secret_manager_secret.soma_key_secret.id # HMAC signing secret for stateless API keys — rotate after first deploy secret_data = "neuron-soma-key-secret-2026-change-me" } resource "google_secret_manager_secret" "soma_anthropic_api_key" { secret_id = "soma-anthropic-api-key" project = var.project_id replication { auto {} } } resource "google_secret_manager_secret_version" "soma_anthropic_api_key" { secret = google_secret_manager_secret.soma_anthropic_api_key.id secret_data = "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" } # ── Together.ai backend — cord-cut inference path ───────────────────────────── # When TOGETHER_API_KEY is set, soma can route chat completions to Together's # inference API as an alternative to the Anthropic backend. # Secret value is populated out-of-band (contains live API key). resource "google_secret_manager_secret" "soma_together_api_key" { secret_id = "soma-together-api-key" project = var.project_id replication { auto {} } } # ── Cloud Run Service — us-central1 ────────────────────────────────────────── resource "google_cloud_run_v2_service" "soma_us" { name = "soma-prod-us" location = "us-central1" project = var.project_id ingress = "INGRESS_TRAFFIC_ALL" labels = local.soma_labels template { service_account = google_service_account.soma.email scaling { # min=1: always warm — inference latency is unacceptable on cold start min_instance_count = 1 max_instance_count = 10 } containers { image = local.soma_image resources { limits = { cpu = "2" memory = "2Gi" } # cpu_idle=false: keep CPU allocated — inference proxy needs fast response cpu_idle = false } env { name = "SOMA_CONFIG_PATH" value = "/etc/soma/soma.toml" } env { name = "HF_TOKEN" value_source { secret_key_ref { secret = google_secret_manager_secret.soma_hf_token.secret_id version = "latest" } } } env { name = "SOMA_OPERATOR_KEY" value_source { secret_key_ref { secret = google_secret_manager_secret.soma_operator_key.secret_id version = "latest" } } } env { name = "SOMA_NODE_SECRET" value_source { secret_key_ref { secret = google_secret_manager_secret.soma_node_secret.secret_id version = "latest" } } } env { name = "SOMA_BASE_DOMAIN" value = "neurontechnologies.ai" } env { name = "SOMA_KEY_SECRET" value_source { secret_key_ref { secret = google_secret_manager_secret.soma_key_secret.secret_id version = "latest" } } } env { name = "GCP_PROJECT_ID" value = var.project_id } env { name = "GCP_ZONE" value = "us-central1-a" } env { name = "SOMA_PUBLIC_URL" value = "https://ai.neurontechnologies.ai" } env { # vLLM backend — RunPod pod Neuron-R1 (DeepSeek-R1-Distill-Llama-70B). # Update to a new pod ID when the RunPod pod is cycled. name = "LLM_BACKEND_URL" value = "https://08axh3kk1oatu2-19123.proxy.runpod.net" } env { # Anthropic API key — when set, soma routes chat completions to Anthropic # instead of trying to provision a GCE GPU node. name = "ANTHROPIC_API_KEY" value_source { secret_key_ref { secret = google_secret_manager_secret.soma_anthropic_api_key.secret_id version = "latest" } } } env { # Anthropic model to use for the "neuron" model alias. name = "ANTHROPIC_MODEL" value = "claude-sonnet-4-5" } env { # Together.ai API key — cord-cut inference path. When set, soma can # route chat completions to Together's API as an Anthropic alternative. name = "TOGETHER_API_KEY" value_source { secret_key_ref { secret = google_secret_manager_secret.soma_together_api_key.secret_id version = "latest" } } } # ── Stripe billing ──────────────────────────────────────────────────────── env { name = "STRIPE_SECRET_KEY" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_secret_key.secret_id version = "latest" } } } env { name = "STRIPE_WEBHOOK_SECRET" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_webhook_secret.secret_id version = "latest" } } } env { name = "STRIPE_PRICE_FREE_PLAN" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_price_free_plan.secret_id version = "latest" } } } env { name = "STRIPE_PRICE_PROFESSIONAL_PLAN" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_price_professional_plan.secret_id version = "latest" } } } env { name = "STRIPE_PRICE_FOUNDING_PLAN" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_price_founding_plan.secret_id version = "latest" } } } env { name = "STRIPE_METER_ID_INPUT_TOKENS" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_meter_id_input_tokens.secret_id version = "latest" } } } env { name = "STRIPE_METER_ID_OUTPUT_TOKENS" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_meter_id_output_tokens.secret_id version = "latest" } } } env { name = "STRIPE_PRICE_FREE_INPUT_OVERAGE" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_price_free_input_overage.secret_id version = "latest" } } } env { name = "STRIPE_PRICE_FREE_OUTPUT_OVERAGE" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_price_free_output_overage.secret_id version = "latest" } } } env { name = "STRIPE_PRICE_PROFESSIONAL_INPUT_OVERAGE" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_price_professional_input_overage.secret_id version = "latest" } } } env { name = "STRIPE_PRICE_PROFESSIONAL_OUTPUT_OVERAGE" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_price_professional_output_overage.secret_id version = "latest" } } } env { name = "STRIPE_PRICE_FOUNDING_INPUT_OVERAGE" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_price_founding_input_overage.secret_id version = "latest" } } } env { name = "STRIPE_PRICE_FOUNDING_OUTPUT_OVERAGE" value_source { secret_key_ref { secret = google_secret_manager_secret.stripe_price_founding_output_overage.secret_id version = "latest" } } } ports { container_port = 8080 name = "http1" } startup_probe { http_get { path = "/health" port = 8080 } initial_delay_seconds = 2 timeout_seconds = 5 period_seconds = 5 failure_threshold = 10 } liveness_probe { http_get { path = "/health" port = 8080 } timeout_seconds = 5 period_seconds = 30 failure_threshold = 3 } } max_instance_request_concurrency = 100 } traffic { type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST" percent = 100 } depends_on = [ google_project_iam_member.soma_secret_accessor, google_project_iam_member.soma_compute_admin, google_project_iam_member.soma_service_account_user, google_secret_manager_secret_version.soma_hf_token, google_secret_manager_secret_version.soma_operator_key, google_secret_manager_secret_version.soma_node_secret, google_secret_manager_secret_version.soma_key_secret, google_secret_manager_secret_version.soma_anthropic_api_key, google_secret_manager_secret.soma_together_api_key, # Stripe billing secrets — must exist before Cloud Run deploy. # Versions are populated by provision_stripe_billing.py. google_secret_manager_secret.stripe_secret_key, google_secret_manager_secret.stripe_webhook_secret, google_secret_manager_secret.stripe_price_free_plan, google_secret_manager_secret.stripe_price_professional_plan, google_secret_manager_secret.stripe_price_founding_plan, google_secret_manager_secret.stripe_meter_id_input_tokens, google_secret_manager_secret.stripe_meter_id_output_tokens, google_secret_manager_secret.stripe_price_free_input_overage, google_secret_manager_secret.stripe_price_free_output_overage, google_secret_manager_secret.stripe_price_professional_input_overage, google_secret_manager_secret.stripe_price_professional_output_overage, google_secret_manager_secret.stripe_price_founding_input_overage, google_secret_manager_secret.stripe_price_founding_output_overage, ] } # ── Public Invoker IAM ──────────────────────────────────────────────────────── resource "google_cloud_run_v2_service_iam_member" "soma_us_public" { project = var.project_id location = "us-central1" name = google_cloud_run_v2_service.soma_us.name role = "roles/run.invoker" member = "allUsers" } # ── Serverless NEG ──────────────────────────────────────────────────────────── resource "google_compute_region_network_endpoint_group" "soma_us" { name = "soma-neg-us" network_endpoint_type = "SERVERLESS" region = "us-central1" project = var.project_id cloud_run { service = google_cloud_run_v2_service.soma_us.name } } # ── Backend Service ─────────────────────────────────────────────────────────── resource "google_compute_backend_service" "soma" { name = "soma-backend-prod" project = var.project_id load_balancing_scheme = "EXTERNAL_MANAGED" protocol = "HTTPS" # Cloud Armor — same policy as other services (SQLi/XSS/rate-limit) security_policy = google_compute_security_policy.marketing.self_link # No CDN — inference responses are always unique enable_cdn = false backend { group = google_compute_region_network_endpoint_group.soma_us.self_link } log_config { enable = true sample_rate = 1.0 } } # ── SSL Certificate ─────────────────────────────────────────────────────────── resource "google_compute_managed_ssl_certificate" "soma" { name = "soma-cert-prod-v2" project = var.project_id managed { domains = ["neuron.neurontechnologies.ai"] } lifecycle { create_before_destroy = true } }