Skip to main content

Secrets & Network Policy

Security architecture for secret management, network isolation, and data protection across all phases of GospeLib's infrastructure.

Secret Management

Architecture

AWS Secrets Manager
└── gospelib/staging/
│ ├── database (PG URL, FalkorDB URL, Redis URL)
│ ├── auth (Clerk keys)
│ ├── billing (Stripe keys)
│ ├── ai (Anthropic, OpenAI keys)
│ ├── notifications (Resend, FCM, APNS keys)
│ └── search (Typesense API key)
└── gospelib/production/
├── database
├── auth
├── billing
├── ai
├── notifications
└── search

Phase Progression

PhaseStrategyDetails
Phase 1AWS Secrets ManagerOne secret per service per environment
Phase 2+ External Secrets OperatorK8s CRDs auto-sync from AWS Secrets Manager → K8s Secrets
Phase 3+ HashiCorp VaultDynamic DB credentials (lease-based), PKI for mTLS, audit trail

Env Var Naming

All environment variables follow the convention: GOSPELIB_{SERVICE}_{KEY}

SecretEnv VarService
FalkorDB URLGOSPELIB_FALKORDB_URLContent
PostgreSQL URLGOSPELIB_PG_URLAuth, Billing
Redis URLGOSPELIB_REDIS_URLAll
Clerk secret keyCLERK_SECRET_KEYAuth
Clerk webhook secretCLERK_WEBHOOK_SECRETAuth
Stripe secret keySTRIPE_SECRET_KEYBilling
Stripe webhook secretSTRIPE_WEBHOOK_SECRETBilling
Anthropic API keyANTHROPIC_API_KEYAI
OpenAI API keyOPENAI_API_KEYAI
Resend API keyRESEND_API_KEYNotifications

Kubernetes Secret Sync (Phase 2+)

External Secrets Operator syncs AWS Secrets Manager into Kubernetes Secrets:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: gospelib-database
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: gospelib-secrets
creationPolicy: Owner
data:
- secretKey: pg-url
remoteRef:
key: gospelib/production/database
property: PG_URL

Secret Rotation

  1. Update the secret in AWS Secrets Manager
  2. External Secrets Operator picks up the change within refreshInterval (1h default)
  3. Kubernetes Secrets are updated automatically
  4. Restart affected deployments to pick up new values

No secrets in git, ever. The .env.example file documents all variables with placeholder values. .env.local (git-ignored) holds actual local development values.

Network Security

Network Topology

graph TB
Internet["Public Internet"]
ALB["ALB<br/>(TLS termination)"]
Ingress["Nginx Ingress"]
GW["Gateway"]

subgraph internal["Internal Only"]
Content["Content"]
Auth["Auth"]
Billing["Billing"]
AI["AI"]
Notif["Notifications"]
end

subgraph data["Data Tier (no public endpoint)"]
FDB["FalkorDB"]
PG["PostgreSQL"]
Redis["Redis"]
end

Internet --> ALB --> Ingress --> GW
GW --> Content & Auth & Billing & AI & Notif
Content & Auth & Billing & AI & Notif --> FDB & PG & Redis

Key Rules

  • Gateway is the only public endpoint — all other services are internal-only
  • Data stores have no public endpoints — only reachable from within the cluster
  • TLS everywhere — TLS 1.3 for external traffic, internal HTTP within the cluster
  • Phase 3 adds mTLS via service mesh (Istio or Linkerd) for inter-service encryption

CORS Policy

The gateway configures CORS to allow only known origins:

OriginEnvironment
https://gospelib.comProduction
https://admin.gospelib.comProduction
https://staging.gospelib.comStaging
http://localhost:3000-3002Development

Webhook Signature Verification

All incoming webhooks are verified before processing:

Stripe Webhooks

// Verify Stripe webhook signature
event, err := stripe.ConstructEvent(payload, sigHeader, cfg.WebhookSecret)

Clerk Webhooks

// Verify Clerk webhook signature
if !clerk.VerifySignature(r, cfg.ClerkWebhookSecret) {
// reject
}

Both handlers also check idempotency keys before processing to prevent duplicate event handling.

Data Security

MeasureDetails
Encryption at restAWS managed keys (Phase 1-2), CMK (Phase 3)
Encryption in transitTLS 1.3 for all external traffic
User data ownershipStudy data (highlights, notes) is private by default
GDPR complianceUser data export (GET /api/v1/users/me/export) and deletion
PII in logsAutomatically redacted by structured logging middleware

GitHub Actions Secrets

Required secrets for CI/CD:

SecretEnvironmentDescription
AWS_ROLE_ARNstaging, productionIAM OIDC role for GitHub Actions
ECR_URLstaging, productionECR registry URL
CLERK_SECRET_KEYstaging, productionClerk API key (per env)
STRIPE_SECRET_KEYstaging, productionStripe API key (per env)
ANTHROPIC_API_KEYstaging, productionAnthropic API key
OPENAI_API_KEYstaging, productionOpenAI API key
RESEND_API_KEYstaging, productionResend API key
EXPO_TOKENstaging, productionExpo/EAS access token
NX_CLOUD_ACCESS_TOKENallNx Cloud cache token

GitHub Actions authenticates to AWS using OIDC (no long-lived credentials), configured during the AWS account bootstrap. See the Operations > Infrastructure page for details.