Add staging marketing site and Cloudflare Access gate

- Deploy marketing site to neuron-stage namespace (replaces bare REST catch-all)
- Staging uses test-mode Stripe keys from Vault
- Updated stage ingress to match prod routing pattern (MCP paths + marketing at /)
- Cloudflare Access: stage.neurontechnologies.ai requires Google auth
  - @neurontechnologies.ai domain allowed
  - 1timlingo@gmail.com explicitly allowed
This commit is contained in:
Will Anderson
2026-04-24 13:43:06 -05:00
parent 477af9b673
commit e901b9a541
5 changed files with 194 additions and 2 deletions
@@ -23,10 +23,52 @@ spec:
name: neuron-mcp
port:
number: 8080
- path: /sse
pathType: Prefix
backend:
service:
name: neuron-mcp
port:
number: 8080
- path: /message
pathType: Prefix
backend:
service:
name: neuron-mcp
port:
number: 8080
- path: /.well-known
pathType: Prefix
backend:
service:
name: neuron-mcp
port:
number: 8080
- path: /oauth2
pathType: Prefix
backend:
service:
name: neuron-mcp
port:
number: 8080
- path: /login
pathType: Prefix
backend:
service:
name: neuron-mcp
port:
number: 8080
- path: /connect
pathType: Prefix
backend:
service:
name: neuron-mcp
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: neuron-rest
name: neuron-marketing
port:
number: 8081
number: 3000
@@ -4,7 +4,9 @@ resources:
- configmap.yaml
- pvc.yaml
- externalsecret.yaml
- marketing-externalsecret.yaml
- mcp-deployment.yaml
- rest-deployment.yaml
- marketing-deployment.yaml
- services.yaml
- ingress.yaml
@@ -0,0 +1,71 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: neuron-marketing
namespace: neuron-stage
labels:
app: neuron-marketing
env: stage
spec:
replicas: 1
selector:
matchLabels:
app: neuron-marketing
template:
metadata:
labels:
app: neuron-marketing
env: stage
spec:
containers:
- name: neuron-marketing
image: registry.neuralplatform.ai/neuron-technologies/marketing:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 3000
env:
- name: NODE_ENV
value: production
- name: NEURON_LICENSE_API_URL
value: http://neuron-mcp.neuron-stage.svc.cluster.local:8080
envFrom:
- secretRef:
name: neuron-marketing-secrets
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 300m
memory: 256Mi
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 15
periodSeconds: 30
failureThreshold: 3
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 3
---
apiVersion: v1
kind: Service
metadata:
name: neuron-marketing
namespace: neuron-stage
labels:
app: neuron-marketing
spec:
selector:
app: neuron-marketing
ports:
- name: http
port: 3000
targetPort: 3000
type: ClusterIP
@@ -0,0 +1,34 @@
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: neuron-marketing-secrets
namespace: neuron-stage
spec:
refreshInterval: 1h
secretStoreRef:
name: vault
kind: ClusterSecretStore
target:
name: neuron-marketing-secrets
creationPolicy: Owner
data:
- secretKey: STRIPE_SECRET_KEY
remoteRef:
key: secret/data/neuron-technologies/marketing-test
property: stripe_secret_key
- secretKey: STRIPE_WEBHOOK_SECRET
remoteRef:
key: secret/data/neuron-technologies/marketing-test
property: stripe_webhook_secret
- secretKey: STRIPE_PRICE_PROFESSIONAL
remoteRef:
key: secret/data/neuron-technologies/marketing-test
property: stripe_price_professional
- secretKey: STRIPE_PRICE_FOUNDING
remoteRef:
key: secret/data/neuron-technologies/marketing-test
property: stripe_price_founding
- secretKey: NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
remoteRef:
key: secret/data/neuron-technologies/marketing-test
property: next_public_stripe_publishable_key
+43
View File
@@ -0,0 +1,43 @@
# Cloudflare Zero Trust Access — stage.neurontechnologies.ai
# Protects the staging marketing site with Google OAuth.
# Only @neurontechnologies.ai addresses and Tim's personal Gmail are allowed in.
locals {
stage_allowed_emails = [
"1timlingo@gmail.com",
]
}
resource "cloudflare_zero_trust_access_application" "nt_stage" {
zone_id = local.zone_neurontechnologies_ai
name = "Neuron Stage"
domain = "stage.neurontechnologies.ai"
type = "self_hosted"
session_duration = "24h"
allowed_idps = ["808f1913-5a8e-4a97-9e68-8ec58e362110"] # Google
auto_redirect_to_identity = true
}
resource "cloudflare_zero_trust_access_policy" "nt_stage_allow_domain" {
application_id = cloudflare_zero_trust_access_application.nt_stage.id
account_id = var.cloudflare_account_id
name = "Allow neurontechnologies.ai domain"
precedence = 1
decision = "allow"
include {
email_domain = ["neurontechnologies.ai"]
}
}
resource "cloudflare_zero_trust_access_policy" "nt_stage_allow_tim" {
application_id = cloudflare_zero_trust_access_application.nt_stage.id
account_id = var.cloudflare_account_id
name = "Allow Tim personal Gmail"
precedence = 2
decision = "allow"
include {
email = local.stage_allowed_emails
}
}