mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
improvement(auth): added ability to inject secrets to kubernetes, server-side ff to disable email registration (#2728)
* improvement(auth): added ability to inject secrets to kubernetes, server-side ff to disable email registration * consolidated telemetry events * comments cleanup * ack PR comment * refactor to use createEnvMock helper instead of local mocks
This commit is contained in:
@@ -39,6 +39,8 @@ The chart includes several pre-configured values files for different scenarios:
|
||||
| `values-azure.yaml` | Azure AKS optimized | Azure Kubernetes Service |
|
||||
| `values-aws.yaml` | AWS EKS optimized | Amazon Elastic Kubernetes Service |
|
||||
| `values-gcp.yaml` | GCP GKE optimized | Google Kubernetes Engine |
|
||||
| `values-external-secrets.yaml` | External Secrets Operator integration | Using Azure Key Vault, AWS Secrets Manager, Vault |
|
||||
| `values-existing-secret.yaml` | Pre-existing Kubernetes secrets | GitOps, Sealed Secrets, manual secret management |
|
||||
|
||||
### Development Environment
|
||||
|
||||
@@ -623,6 +625,111 @@ To uninstall/delete the release:
|
||||
helm uninstall sim
|
||||
```
|
||||
|
||||
## External Secret Management
|
||||
|
||||
The chart supports integration with external secret management systems for production-grade secret handling. This enables you to store secrets in secure vaults and have them automatically synced to Kubernetes.
|
||||
|
||||
### Option 1: External Secrets Operator (Recommended)
|
||||
|
||||
[External Secrets Operator](https://external-secrets.io/) is the industry-standard solution for syncing secrets from external stores like Azure Key Vault, AWS Secrets Manager, HashiCorp Vault, and GCP Secret Manager.
|
||||
|
||||
**Prerequisites:**
|
||||
```bash
|
||||
# Install External Secrets Operator
|
||||
helm repo add external-secrets https://charts.external-secrets.io
|
||||
helm install external-secrets external-secrets/external-secrets \
|
||||
-n external-secrets --create-namespace
|
||||
```
|
||||
|
||||
**Configuration:**
|
||||
```yaml
|
||||
externalSecrets:
|
||||
enabled: true
|
||||
refreshInterval: "1h"
|
||||
secretStoreRef:
|
||||
name: "my-secret-store"
|
||||
kind: "ClusterSecretStore"
|
||||
remoteRefs:
|
||||
app:
|
||||
BETTER_AUTH_SECRET: "sim/app/better-auth-secret"
|
||||
ENCRYPTION_KEY: "sim/app/encryption-key"
|
||||
INTERNAL_API_SECRET: "sim/app/internal-api-secret"
|
||||
postgresql:
|
||||
password: "sim/postgresql/password"
|
||||
```
|
||||
|
||||
See `examples/values-external-secrets.yaml` for complete examples including SecretStore configurations for Azure, AWS, GCP, and Vault.
|
||||
|
||||
### Option 2: Pre-Existing Kubernetes Secrets
|
||||
|
||||
Reference secrets you've created manually, via GitOps (Sealed Secrets, SOPS), or through other automation.
|
||||
|
||||
**Configuration:**
|
||||
```yaml
|
||||
app:
|
||||
secrets:
|
||||
existingSecret:
|
||||
enabled: true
|
||||
name: "my-app-secrets"
|
||||
|
||||
postgresql:
|
||||
auth:
|
||||
existingSecret:
|
||||
enabled: true
|
||||
name: "my-postgresql-secret"
|
||||
passwordKey: "POSTGRES_PASSWORD"
|
||||
|
||||
externalDatabase:
|
||||
existingSecret:
|
||||
enabled: true
|
||||
name: "my-external-db-secret"
|
||||
passwordKey: "password"
|
||||
```
|
||||
|
||||
**Create secrets manually:**
|
||||
```bash
|
||||
# Generate secure values
|
||||
BETTER_AUTH_SECRET=$(openssl rand -hex 32)
|
||||
ENCRYPTION_KEY=$(openssl rand -hex 32)
|
||||
INTERNAL_API_SECRET=$(openssl rand -hex 32)
|
||||
POSTGRES_PASSWORD=$(openssl rand -base64 16 | tr -d '/+=')
|
||||
|
||||
# Create app secrets
|
||||
kubectl create secret generic my-app-secrets \
|
||||
--namespace sim \
|
||||
--from-literal=BETTER_AUTH_SECRET="$BETTER_AUTH_SECRET" \
|
||||
--from-literal=ENCRYPTION_KEY="$ENCRYPTION_KEY" \
|
||||
--from-literal=INTERNAL_API_SECRET="$INTERNAL_API_SECRET"
|
||||
|
||||
# Create PostgreSQL secret
|
||||
kubectl create secret generic my-postgresql-secret \
|
||||
--namespace sim \
|
||||
--from-literal=POSTGRES_PASSWORD="$POSTGRES_PASSWORD"
|
||||
```
|
||||
|
||||
See `examples/values-existing-secret.yaml` for more details.
|
||||
|
||||
### External Secrets Parameters
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `app.secrets.existingSecret.enabled` | Use existing secret for app credentials | `false` |
|
||||
| `app.secrets.existingSecret.name` | Name of existing secret | `""` |
|
||||
| `app.secrets.existingSecret.keys` | Key name mappings | See values.yaml |
|
||||
| `postgresql.auth.existingSecret.enabled` | Use existing secret for PostgreSQL | `false` |
|
||||
| `postgresql.auth.existingSecret.name` | Name of existing secret | `""` |
|
||||
| `postgresql.auth.existingSecret.passwordKey` | Key containing password | `"POSTGRES_PASSWORD"` |
|
||||
| `externalDatabase.existingSecret.enabled` | Use existing secret for external DB | `false` |
|
||||
| `externalDatabase.existingSecret.name` | Name of existing secret | `""` |
|
||||
| `externalDatabase.existingSecret.passwordKey` | Key containing password | `"EXTERNAL_DB_PASSWORD"` |
|
||||
| `externalSecrets.enabled` | Enable External Secrets Operator integration | `false` |
|
||||
| `externalSecrets.refreshInterval` | How often to sync secrets | `"1h"` |
|
||||
| `externalSecrets.secretStoreRef.name` | Name of SecretStore/ClusterSecretStore | `""` |
|
||||
| `externalSecrets.secretStoreRef.kind` | Kind of store | `"ClusterSecretStore"` |
|
||||
| `externalSecrets.remoteRefs.app.*` | Remote paths for app secrets | See values.yaml |
|
||||
| `externalSecrets.remoteRefs.postgresql.password` | Remote path for PostgreSQL password | `""` |
|
||||
| `externalSecrets.remoteRefs.externalDatabase.password` | Remote path for external DB password | `""` |
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Production Secrets
|
||||
|
||||
54
helm/sim/examples/values-existing-secret.yaml
Normal file
54
helm/sim/examples/values-existing-secret.yaml
Normal file
@@ -0,0 +1,54 @@
|
||||
# Using pre-existing Kubernetes secrets for Sim
|
||||
# For GitOps, Sealed Secrets, or manual secret management
|
||||
|
||||
# Prerequisites:
|
||||
# Create your secrets before installing (see examples at bottom of file)
|
||||
|
||||
app:
|
||||
enabled: true
|
||||
replicaCount: 2
|
||||
secrets:
|
||||
existingSecret:
|
||||
enabled: true
|
||||
name: "sim-app-secrets"
|
||||
env:
|
||||
NEXT_PUBLIC_APP_URL: "https://sim.example.com"
|
||||
BETTER_AUTH_URL: "https://sim.example.com"
|
||||
NEXT_PUBLIC_SOCKET_URL: "wss://sim-ws.example.com"
|
||||
NODE_ENV: "production"
|
||||
|
||||
realtime:
|
||||
enabled: true
|
||||
replicaCount: 2
|
||||
env:
|
||||
NEXT_PUBLIC_APP_URL: "https://sim.example.com"
|
||||
BETTER_AUTH_URL: "https://sim.example.com"
|
||||
NEXT_PUBLIC_SOCKET_URL: "wss://sim-ws.example.com"
|
||||
ALLOWED_ORIGINS: "https://sim.example.com"
|
||||
NODE_ENV: "production"
|
||||
|
||||
postgresql:
|
||||
enabled: true
|
||||
auth:
|
||||
username: postgres
|
||||
database: sim
|
||||
existingSecret:
|
||||
enabled: true
|
||||
name: "sim-postgresql-secret"
|
||||
passwordKey: "POSTGRES_PASSWORD"
|
||||
|
||||
# ---
|
||||
# Create secrets before installing:
|
||||
# ---
|
||||
|
||||
# kubectl create secret generic sim-app-secrets \
|
||||
# --namespace sim \
|
||||
# --from-literal=BETTER_AUTH_SECRET="$(openssl rand -hex 32)" \
|
||||
# --from-literal=ENCRYPTION_KEY="$(openssl rand -hex 32)" \
|
||||
# --from-literal=INTERNAL_API_SECRET="$(openssl rand -hex 32)" \
|
||||
# --from-literal=CRON_SECRET="$(openssl rand -hex 32)" \
|
||||
# --from-literal=API_ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
||||
|
||||
# kubectl create secret generic sim-postgresql-secret \
|
||||
# --namespace sim \
|
||||
# --from-literal=POSTGRES_PASSWORD="$(openssl rand -base64 16 | tr -d '/+=')"
|
||||
94
helm/sim/examples/values-external-secrets.yaml
Normal file
94
helm/sim/examples/values-external-secrets.yaml
Normal file
@@ -0,0 +1,94 @@
|
||||
# External Secrets Operator integration for Sim
|
||||
# Syncs secrets from Azure Key Vault, AWS Secrets Manager, HashiCorp Vault, etc.
|
||||
|
||||
# Prerequisites:
|
||||
# 1. Install ESO: helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespace
|
||||
# 2. Create a SecretStore/ClusterSecretStore for your provider (see examples at bottom of file)
|
||||
|
||||
externalSecrets:
|
||||
enabled: true
|
||||
apiVersion: "v1"
|
||||
refreshInterval: "1h"
|
||||
secretStoreRef:
|
||||
name: "sim-secret-store"
|
||||
kind: "ClusterSecretStore"
|
||||
remoteRefs:
|
||||
app:
|
||||
BETTER_AUTH_SECRET: "sim/app/better-auth-secret"
|
||||
ENCRYPTION_KEY: "sim/app/encryption-key"
|
||||
INTERNAL_API_SECRET: "sim/app/internal-api-secret"
|
||||
CRON_SECRET: "sim/app/cron-secret"
|
||||
API_ENCRYPTION_KEY: "sim/app/api-encryption-key"
|
||||
postgresql:
|
||||
password: "sim/postgresql/password"
|
||||
|
||||
app:
|
||||
enabled: true
|
||||
replicaCount: 2
|
||||
env:
|
||||
NEXT_PUBLIC_APP_URL: "https://sim.example.com"
|
||||
BETTER_AUTH_URL: "https://sim.example.com"
|
||||
NEXT_PUBLIC_SOCKET_URL: "wss://sim-ws.example.com"
|
||||
NODE_ENV: "production"
|
||||
|
||||
realtime:
|
||||
enabled: true
|
||||
replicaCount: 2
|
||||
env:
|
||||
NEXT_PUBLIC_APP_URL: "https://sim.example.com"
|
||||
BETTER_AUTH_URL: "https://sim.example.com"
|
||||
NEXT_PUBLIC_SOCKET_URL: "wss://sim-ws.example.com"
|
||||
ALLOWED_ORIGINS: "https://sim.example.com"
|
||||
NODE_ENV: "production"
|
||||
|
||||
postgresql:
|
||||
enabled: true
|
||||
auth:
|
||||
username: postgres
|
||||
database: sim
|
||||
|
||||
# ---
|
||||
# SecretStore Examples (apply one of these to your cluster before installing)
|
||||
# ---
|
||||
|
||||
# Azure Key Vault (Workload Identity):
|
||||
# apiVersion: external-secrets.io/v1beta1
|
||||
# kind: ClusterSecretStore
|
||||
# metadata:
|
||||
# name: sim-secret-store
|
||||
# spec:
|
||||
# provider:
|
||||
# azurekv:
|
||||
# authType: WorkloadIdentity
|
||||
# vaultUrl: "https://your-keyvault.vault.azure.net"
|
||||
# serviceAccountRef:
|
||||
# name: external-secrets-sa
|
||||
# namespace: external-secrets
|
||||
|
||||
# AWS Secrets Manager (IRSA):
|
||||
# apiVersion: external-secrets.io/v1beta1
|
||||
# kind: ClusterSecretStore
|
||||
# metadata:
|
||||
# name: sim-secret-store
|
||||
# spec:
|
||||
# provider:
|
||||
# aws:
|
||||
# service: SecretsManager
|
||||
# region: us-east-1
|
||||
# role: arn:aws:iam::123456789012:role/external-secrets-role
|
||||
|
||||
# HashiCorp Vault (Kubernetes Auth):
|
||||
# apiVersion: external-secrets.io/v1beta1
|
||||
# kind: ClusterSecretStore
|
||||
# metadata:
|
||||
# name: sim-secret-store
|
||||
# spec:
|
||||
# provider:
|
||||
# vault:
|
||||
# server: "https://vault.example.com"
|
||||
# path: "secret"
|
||||
# version: "v2"
|
||||
# auth:
|
||||
# kubernetes:
|
||||
# mountPath: "kubernetes"
|
||||
# role: "external-secrets"
|
||||
@@ -181,8 +181,15 @@ Database URL for internal PostgreSQL
|
||||
|
||||
{{/*
|
||||
Validate required secrets and reject default placeholder values
|
||||
Skip validation when using existing secrets or External Secrets Operator
|
||||
*/}}
|
||||
{{- define "sim.validateSecrets" -}}
|
||||
{{- $useExistingAppSecret := and .Values.app.secrets .Values.app.secrets.existingSecret .Values.app.secrets.existingSecret.enabled }}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled }}
|
||||
{{- $useExistingPostgresSecret := and .Values.postgresql.auth.existingSecret .Values.postgresql.auth.existingSecret.enabled }}
|
||||
{{- $useExistingExternalDbSecret := and .Values.externalDatabase.existingSecret .Values.externalDatabase.existingSecret.enabled }}
|
||||
{{- /* App secrets validation - skip if using existing secret or ESO */ -}}
|
||||
{{- if not (or $useExistingAppSecret $useExternalSecrets) }}
|
||||
{{- if and .Values.app.enabled (not .Values.app.env.BETTER_AUTH_SECRET) }}
|
||||
{{- fail "app.env.BETTER_AUTH_SECRET is required for production deployment" }}
|
||||
{{- end }}
|
||||
@@ -198,15 +205,21 @@ Validate required secrets and reject default placeholder values
|
||||
{{- if and .Values.realtime.enabled (eq .Values.realtime.env.BETTER_AUTH_SECRET "CHANGE-ME-32-CHAR-SECRET-FOR-PRODUCTION-USE") }}
|
||||
{{- fail "realtime.env.BETTER_AUTH_SECRET must not use the default placeholder value. Generate a secure secret with: openssl rand -hex 32" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- /* PostgreSQL password validation - skip if using existing secret or ESO */ -}}
|
||||
{{- if not (or $useExistingPostgresSecret $useExternalSecrets) }}
|
||||
{{- if and .Values.postgresql.enabled (not .Values.postgresql.auth.password) }}
|
||||
{{- fail "postgresql.auth.password is required when using internal PostgreSQL" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.postgresql.enabled (eq .Values.postgresql.auth.password "CHANGE-ME-SECURE-PASSWORD") }}
|
||||
{{- fail "postgresql.auth.password must not use the default placeholder value. Set a secure password for production" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.postgresql.enabled (not (regexMatch "^[a-zA-Z0-9._-]+$" .Values.postgresql.auth.password)) }}
|
||||
{{- if and .Values.postgresql.enabled .Values.postgresql.auth.password (not (regexMatch "^[a-zA-Z0-9._-]+$" .Values.postgresql.auth.password)) }}
|
||||
{{- fail "postgresql.auth.password must only contain alphanumeric characters, hyphens, underscores, or periods to ensure DATABASE_URL compatibility. Generate with: openssl rand -base64 16 | tr -d '/+='" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- /* External database password validation - skip if using existing secret or ESO */ -}}
|
||||
{{- if not (or $useExistingExternalDbSecret $useExternalSecrets) }}
|
||||
{{- if and .Values.externalDatabase.enabled (not .Values.externalDatabase.password) }}
|
||||
{{- fail "externalDatabase.password is required when using external database" }}
|
||||
{{- end }}
|
||||
@@ -214,6 +227,103 @@ Validate required secrets and reject default placeholder values
|
||||
{{- fail "externalDatabase.password must only contain alphanumeric characters, hyphens, underscores, or periods to ensure DATABASE_URL compatibility." }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the app secrets name
|
||||
Returns the name of the secret containing app credentials (auth, encryption keys)
|
||||
*/}}
|
||||
{{- define "sim.appSecretName" -}}
|
||||
{{- if and .Values.app.secrets .Values.app.secrets.existingSecret .Values.app.secrets.existingSecret.enabled -}}
|
||||
{{- .Values.app.secrets.existingSecret.name -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-app-secrets" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the PostgreSQL secret name
|
||||
Returns the name of the secret containing PostgreSQL password
|
||||
*/}}
|
||||
{{- define "sim.postgresqlSecretName" -}}
|
||||
{{- if and .Values.postgresql.auth.existingSecret .Values.postgresql.auth.existingSecret.enabled -}}
|
||||
{{- .Values.postgresql.auth.existingSecret.name -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-postgresql-secret" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the PostgreSQL password key name
|
||||
Returns the key name in the secret that contains the password
|
||||
*/}}
|
||||
{{- define "sim.postgresqlPasswordKey" -}}
|
||||
{{- if and .Values.postgresql.auth.existingSecret .Values.postgresql.auth.existingSecret.enabled -}}
|
||||
{{- .Values.postgresql.auth.existingSecret.passwordKey | default "POSTGRES_PASSWORD" -}}
|
||||
{{- else -}}
|
||||
{{- print "POSTGRES_PASSWORD" -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the external database secret name
|
||||
Returns the name of the secret containing external database password
|
||||
*/}}
|
||||
{{- define "sim.externalDbSecretName" -}}
|
||||
{{- if and .Values.externalDatabase.existingSecret .Values.externalDatabase.existingSecret.enabled -}}
|
||||
{{- .Values.externalDatabase.existingSecret.name -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-external-db-secret" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the external database password key name
|
||||
Returns the key name in the secret that contains the password
|
||||
*/}}
|
||||
{{- define "sim.externalDbPasswordKey" -}}
|
||||
{{- if and .Values.externalDatabase.existingSecret .Values.externalDatabase.existingSecret.enabled -}}
|
||||
{{- .Values.externalDatabase.existingSecret.passwordKey | default "EXTERNAL_DB_PASSWORD" -}}
|
||||
{{- else -}}
|
||||
{{- print "EXTERNAL_DB_PASSWORD" -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Check if app secrets should be created by the chart
|
||||
Returns true if we should create the app secrets (not using existing or ESO)
|
||||
*/}}
|
||||
{{- define "sim.createAppSecrets" -}}
|
||||
{{- $useExistingAppSecret := and .Values.app.secrets .Values.app.secrets.existingSecret .Values.app.secrets.existingSecret.enabled }}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled }}
|
||||
{{- if not (or $useExistingAppSecret $useExternalSecrets) -}}
|
||||
true
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Check if PostgreSQL secret should be created by the chart
|
||||
Returns true if we should create the PostgreSQL secret (not using existing or ESO)
|
||||
*/}}
|
||||
{{- define "sim.createPostgresqlSecret" -}}
|
||||
{{- $useExistingSecret := and .Values.postgresql.auth.existingSecret .Values.postgresql.auth.existingSecret.enabled }}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled }}
|
||||
{{- if not (or $useExistingSecret $useExternalSecrets) -}}
|
||||
true
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Check if external database secret should be created by the chart
|
||||
Returns true if we should create the external database secret (not using existing or ESO)
|
||||
*/}}
|
||||
{{- define "sim.createExternalDbSecret" -}}
|
||||
{{- $useExistingSecret := and .Values.externalDatabase.existingSecret .Values.externalDatabase.existingSecret.enabled }}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled }}
|
||||
{{- if not (or $useExistingSecret $useExternalSecrets) -}}
|
||||
true
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Ollama URL
|
||||
|
||||
@@ -44,15 +44,14 @@ spec:
|
||||
cd /app/packages/db
|
||||
export DATABASE_URL="{{ include "sim.databaseUrl" . }}"
|
||||
bun run db:migrate
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
envFrom:
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-secret
|
||||
{{- else if .Values.externalDatabase.enabled }}
|
||||
envFrom:
|
||||
name: {{ include "sim.postgresqlSecretName" . }}
|
||||
{{- else if .Values.externalDatabase.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.fullname" . }}-external-db-secret
|
||||
{{- end }}
|
||||
name: {{ include "sim.externalDbSecretName" . }}
|
||||
{{- end }}
|
||||
{{- include "sim.resources" .Values.migrations | nindent 10 }}
|
||||
{{- include "sim.securityContext" .Values.migrations | nindent 10 }}
|
||||
{{- end }}
|
||||
@@ -89,15 +88,18 @@ spec:
|
||||
{{- with .Values.extraEnvVars }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
envFrom:
|
||||
# App secrets (authentication, encryption keys)
|
||||
- secretRef:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-secret
|
||||
{{- else if .Values.externalDatabase.enabled }}
|
||||
envFrom:
|
||||
name: {{ include "sim.appSecretName" . }}
|
||||
# Database secrets
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.fullname" . }}-external-db-secret
|
||||
{{- end }}
|
||||
name: {{ include "sim.postgresqlSecretName" . }}
|
||||
{{- else if .Values.externalDatabase.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.externalDbSecretName" . }}
|
||||
{{- end }}
|
||||
{{- if .Values.app.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.app.livenessProbe | nindent 12 }}
|
||||
|
||||
@@ -62,15 +62,18 @@ spec:
|
||||
{{- with .Values.extraEnvVars }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
envFrom:
|
||||
# App secrets (authentication keys shared with main app)
|
||||
- secretRef:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-secret
|
||||
{{- else if .Values.externalDatabase.enabled }}
|
||||
envFrom:
|
||||
name: {{ include "sim.appSecretName" . }}
|
||||
# Database secrets
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.fullname" . }}-external-db-secret
|
||||
{{- end }}
|
||||
name: {{ include "sim.postgresqlSecretName" . }}
|
||||
{{- else if .Values.externalDatabase.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.externalDbSecretName" . }}
|
||||
{{- end }}
|
||||
{{- if .Values.realtime.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.realtime.livenessProbe | nindent 12 }}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{{- if .Values.externalDatabase.enabled }}
|
||||
{{- if and .Values.externalDatabase.enabled (include "sim.createExternalDbSecret" .) }}
|
||||
---
|
||||
# Secret for external database credentials
|
||||
apiVersion: v1
|
||||
|
||||
44
helm/sim/templates/external-secret-app.yaml
Normal file
44
helm/sim/templates/external-secret-app.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
{{- if and .Values.externalSecrets.enabled .Values.app.enabled }}
|
||||
# ExternalSecret for app credentials (syncs from external secret managers)
|
||||
apiVersion: external-secrets.io/{{ .Values.externalSecrets.apiVersion | default "v1" }}
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-app-secrets
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.app.labels" . | nindent 4 }}
|
||||
spec:
|
||||
refreshInterval: {{ .Values.externalSecrets.refreshInterval | quote }}
|
||||
secretStoreRef:
|
||||
name: {{ required "externalSecrets.secretStoreRef.name is required when externalSecrets.enabled=true" .Values.externalSecrets.secretStoreRef.name }}
|
||||
kind: {{ .Values.externalSecrets.secretStoreRef.kind | default "ClusterSecretStore" }}
|
||||
target:
|
||||
name: {{ include "sim.fullname" . }}-app-secrets
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
{{- if .Values.externalSecrets.remoteRefs.app.BETTER_AUTH_SECRET }}
|
||||
- secretKey: BETTER_AUTH_SECRET
|
||||
remoteRef:
|
||||
key: {{ .Values.externalSecrets.remoteRefs.app.BETTER_AUTH_SECRET }}
|
||||
{{- end }}
|
||||
{{- if .Values.externalSecrets.remoteRefs.app.ENCRYPTION_KEY }}
|
||||
- secretKey: ENCRYPTION_KEY
|
||||
remoteRef:
|
||||
key: {{ .Values.externalSecrets.remoteRefs.app.ENCRYPTION_KEY }}
|
||||
{{- end }}
|
||||
{{- if .Values.externalSecrets.remoteRefs.app.INTERNAL_API_SECRET }}
|
||||
- secretKey: INTERNAL_API_SECRET
|
||||
remoteRef:
|
||||
key: {{ .Values.externalSecrets.remoteRefs.app.INTERNAL_API_SECRET }}
|
||||
{{- end }}
|
||||
{{- if .Values.externalSecrets.remoteRefs.app.CRON_SECRET }}
|
||||
- secretKey: CRON_SECRET
|
||||
remoteRef:
|
||||
key: {{ .Values.externalSecrets.remoteRefs.app.CRON_SECRET }}
|
||||
{{- end }}
|
||||
{{- if .Values.externalSecrets.remoteRefs.app.API_ENCRYPTION_KEY }}
|
||||
- secretKey: API_ENCRYPTION_KEY
|
||||
remoteRef:
|
||||
key: {{ .Values.externalSecrets.remoteRefs.app.API_ENCRYPTION_KEY }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
23
helm/sim/templates/external-secret-external-db.yaml
Normal file
23
helm/sim/templates/external-secret-external-db.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
{{- if and .Values.externalSecrets.enabled .Values.externalDatabase.enabled .Values.externalSecrets.remoteRefs.externalDatabase.password }}
|
||||
# ExternalSecret for external database password (syncs from external secret managers)
|
||||
apiVersion: external-secrets.io/{{ .Values.externalSecrets.apiVersion | default "v1" }}
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-external-db-secret
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: external-database
|
||||
spec:
|
||||
refreshInterval: {{ .Values.externalSecrets.refreshInterval | quote }}
|
||||
secretStoreRef:
|
||||
name: {{ required "externalSecrets.secretStoreRef.name is required when externalSecrets.enabled=true" .Values.externalSecrets.secretStoreRef.name }}
|
||||
kind: {{ .Values.externalSecrets.secretStoreRef.kind | default "ClusterSecretStore" }}
|
||||
target:
|
||||
name: {{ include "sim.fullname" . }}-external-db-secret
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
- secretKey: EXTERNAL_DB_PASSWORD
|
||||
remoteRef:
|
||||
key: {{ .Values.externalSecrets.remoteRefs.externalDatabase.password }}
|
||||
{{- end }}
|
||||
22
helm/sim/templates/external-secret-postgresql.yaml
Normal file
22
helm/sim/templates/external-secret-postgresql.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
{{- if and .Values.externalSecrets.enabled .Values.postgresql.enabled .Values.externalSecrets.remoteRefs.postgresql.password }}
|
||||
# ExternalSecret for PostgreSQL password (syncs from external secret managers)
|
||||
apiVersion: external-secrets.io/{{ .Values.externalSecrets.apiVersion | default "v1" }}
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-secret
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.postgresql.labels" . | nindent 4 }}
|
||||
spec:
|
||||
refreshInterval: {{ .Values.externalSecrets.refreshInterval | quote }}
|
||||
secretStoreRef:
|
||||
name: {{ required "externalSecrets.secretStoreRef.name is required when externalSecrets.enabled=true" .Values.externalSecrets.secretStoreRef.name }}
|
||||
kind: {{ .Values.externalSecrets.secretStoreRef.kind | default "ClusterSecretStore" }}
|
||||
target:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-secret
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
- secretKey: POSTGRES_PASSWORD
|
||||
remoteRef:
|
||||
key: {{ .Values.externalSecrets.remoteRefs.postgresql.password }}
|
||||
{{- end }}
|
||||
27
helm/sim/templates/secrets-app.yaml
Normal file
27
helm/sim/templates/secrets-app.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
{{- if and .Values.app.enabled (include "sim.createAppSecrets" .) }}
|
||||
# Secret for app credentials (authentication, encryption keys)
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-app-secrets
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.app.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
{{- if .Values.app.env.BETTER_AUTH_SECRET }}
|
||||
BETTER_AUTH_SECRET: {{ .Values.app.env.BETTER_AUTH_SECRET | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.app.env.ENCRYPTION_KEY }}
|
||||
ENCRYPTION_KEY: {{ .Values.app.env.ENCRYPTION_KEY | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.app.env.INTERNAL_API_SECRET }}
|
||||
INTERNAL_API_SECRET: {{ .Values.app.env.INTERNAL_API_SECRET | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.app.env.CRON_SECRET }}
|
||||
CRON_SECRET: {{ .Values.app.env.CRON_SECRET | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.app.env.API_ENCRYPTION_KEY }}
|
||||
API_ENCRYPTION_KEY: {{ .Values.app.env.API_ENCRYPTION_KEY | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -65,6 +65,7 @@ data:
|
||||
POSTGRES_USER: {{ .Values.postgresql.auth.username | quote }}
|
||||
PGDATA: "/var/lib/postgresql/data/pgdata"
|
||||
|
||||
{{- if (include "sim.createPostgresqlSecret" .) }}
|
||||
---
|
||||
# Secret for PostgreSQL password
|
||||
apiVersion: v1
|
||||
@@ -77,6 +78,7 @@ metadata:
|
||||
type: Opaque
|
||||
data:
|
||||
POSTGRES_PASSWORD: {{ .Values.postgresql.auth.password | b64enc }}
|
||||
{{- end }}
|
||||
|
||||
---
|
||||
# StatefulSet for PostgreSQL
|
||||
@@ -128,7 +130,7 @@ spec:
|
||||
- configMapRef:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-env
|
||||
- secretRef:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-secret
|
||||
name: {{ include "sim.postgresqlSecretName" . }}
|
||||
{{- if .Values.postgresql.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.postgresql.livenessProbe | nindent 12 }}
|
||||
|
||||
@@ -81,18 +81,39 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"secrets": {
|
||||
"type": "object",
|
||||
"description": "Secret management configuration",
|
||||
"properties": {
|
||||
"existingSecret": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Use an existing secret instead of creating one"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the existing Kubernetes secret"
|
||||
},
|
||||
"keys": {
|
||||
"type": "object",
|
||||
"description": "Key name mappings in the existing secret"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"BETTER_AUTH_SECRET": {
|
||||
"type": "string",
|
||||
"minLength": 32,
|
||||
"description": "Auth secret (minimum 32 characters required)"
|
||||
"description": "Auth secret (minimum 32 characters required when not using existingSecret)"
|
||||
},
|
||||
"ENCRYPTION_KEY": {
|
||||
"type": "string",
|
||||
"minLength": 32,
|
||||
"description": "Encryption key (minimum 32 characters required)"
|
||||
"description": "Encryption key (minimum 32 characters required when not using existingSecret)"
|
||||
},
|
||||
"NEXT_PUBLIC_APP_URL": {
|
||||
"type": "string",
|
||||
@@ -329,8 +350,7 @@
|
||||
"properties": {
|
||||
"BETTER_AUTH_SECRET": {
|
||||
"type": "string",
|
||||
"minLength": 32,
|
||||
"description": "Auth secret (minimum 32 characters required)"
|
||||
"description": "Auth secret (minimum 32 characters required when not using existingSecret)"
|
||||
},
|
||||
"NEXT_PUBLIC_APP_URL": {
|
||||
"type": "string",
|
||||
@@ -431,11 +451,25 @@
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"minLength": 8,
|
||||
"not": {
|
||||
"const": "CHANGE-ME-SECURE-PASSWORD"
|
||||
},
|
||||
"description": "PostgreSQL password (minimum 8 characters, must not be default placeholder)"
|
||||
"description": "PostgreSQL password (minimum 8 characters when not using existingSecret)"
|
||||
},
|
||||
"existingSecret": {
|
||||
"type": "object",
|
||||
"description": "Use an existing secret for PostgreSQL credentials",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Use an existing secret instead of creating one"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the existing Kubernetes secret"
|
||||
},
|
||||
"passwordKey": {
|
||||
"type": "string",
|
||||
"description": "Key in the secret containing the password"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -475,6 +509,24 @@
|
||||
"type": "string",
|
||||
"enum": ["disable", "allow", "prefer", "require", "verify-ca", "verify-full"],
|
||||
"description": "SSL mode for database connection"
|
||||
},
|
||||
"existingSecret": {
|
||||
"type": "object",
|
||||
"description": "Use an existing secret for external database credentials",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Use an existing secret instead of creating one"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the existing Kubernetes secret"
|
||||
},
|
||||
"passwordKey": {
|
||||
"type": "string",
|
||||
"description": "Key in the secret containing the password"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"if": {
|
||||
@@ -821,6 +873,61 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"externalSecrets": {
|
||||
"type": "object",
|
||||
"description": "External Secrets Operator integration",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Enable External Secrets Operator integration"
|
||||
},
|
||||
"apiVersion": {
|
||||
"type": "string",
|
||||
"enum": ["v1", "v1beta1"],
|
||||
"description": "ESO API version - use v1 for ESO v0.17+ (recommended), v1beta1 for older versions"
|
||||
},
|
||||
"refreshInterval": {
|
||||
"type": "string",
|
||||
"description": "How often to sync secrets from external store"
|
||||
},
|
||||
"secretStoreRef": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the SecretStore or ClusterSecretStore"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": ["SecretStore", "ClusterSecretStore"],
|
||||
"description": "Kind of the store"
|
||||
}
|
||||
}
|
||||
},
|
||||
"remoteRefs": {
|
||||
"type": "object",
|
||||
"description": "Remote key paths in external secret store",
|
||||
"properties": {
|
||||
"app": {
|
||||
"type": "object",
|
||||
"additionalProperties": { "type": "string" }
|
||||
},
|
||||
"postgresql": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"password": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"externalDatabase": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"password": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ingress": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -16,16 +16,16 @@ global:
|
||||
app:
|
||||
# Enable/disable the main application
|
||||
enabled: true
|
||||
|
||||
|
||||
# Image configuration
|
||||
image:
|
||||
repository: simstudioai/simstudio
|
||||
tag: latest
|
||||
pullPolicy: Always
|
||||
|
||||
|
||||
# Number of replicas
|
||||
replicaCount: 1
|
||||
|
||||
|
||||
# Resource limits and requests
|
||||
resources:
|
||||
limits:
|
||||
@@ -34,19 +34,37 @@ app:
|
||||
requests:
|
||||
memory: "2Gi"
|
||||
cpu: "1000m"
|
||||
|
||||
|
||||
# Node selector for pod scheduling (leave empty to allow scheduling on any node)
|
||||
nodeSelector: {}
|
||||
|
||||
|
||||
# Pod security context
|
||||
podSecurityContext:
|
||||
fsGroup: 1001
|
||||
|
||||
|
||||
# Container security context
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
|
||||
|
||||
# Secret management configuration
|
||||
# Use this to reference pre-existing Kubernetes secrets instead of defining values directly
|
||||
# This enables integration with External Secrets Operator, HashiCorp Vault, Azure Key Vault, etc.
|
||||
secrets:
|
||||
existingSecret:
|
||||
# Set to true to use an existing secret instead of creating one from values
|
||||
enabled: false
|
||||
# Name of the existing Kubernetes secret containing app credentials
|
||||
name: ""
|
||||
# Key mappings - specify the key names in your existing secret
|
||||
# Only needed if your secret uses different key names than the defaults
|
||||
keys:
|
||||
BETTER_AUTH_SECRET: "BETTER_AUTH_SECRET"
|
||||
ENCRYPTION_KEY: "ENCRYPTION_KEY"
|
||||
INTERNAL_API_SECRET: "INTERNAL_API_SECRET"
|
||||
CRON_SECRET: "CRON_SECRET"
|
||||
API_ENCRYPTION_KEY: "API_ENCRYPTION_KEY"
|
||||
|
||||
# Environment variables
|
||||
env:
|
||||
# Application URLs
|
||||
@@ -118,7 +136,9 @@ app:
|
||||
|
||||
# Registration Control
|
||||
DISABLE_REGISTRATION: "" # Set to "true" to disable new user signups
|
||||
|
||||
EMAIL_PASSWORD_SIGNUP_ENABLED: "" # Set to "false" to disable email/password login (SSO-only mode, server-side enforcement)
|
||||
NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED: "" # Set to "false" to hide email/password login form (UI-side)
|
||||
|
||||
# Access Control (leave empty if not restricting login)
|
||||
ALLOWED_LOGIN_EMAILS: "" # Comma-separated list of allowed email addresses for login
|
||||
ALLOWED_LOGIN_DOMAINS: "" # Comma-separated list of allowed email domains for login
|
||||
@@ -305,6 +325,12 @@ postgresql:
|
||||
username: postgres
|
||||
password: "" # REQUIRED - set via --set flag or external secret manager
|
||||
database: sim
|
||||
# Use an existing secret for PostgreSQL credentials
|
||||
# This enables integration with External Secrets Operator, HashiCorp Vault, etc.
|
||||
existingSecret:
|
||||
enabled: false
|
||||
name: "" # Name of existing Kubernetes secret
|
||||
passwordKey: "POSTGRES_PASSWORD" # Key in the secret containing the password
|
||||
|
||||
# Node selector for database pod scheduling (leave empty to allow scheduling on any node)
|
||||
nodeSelector: {}
|
||||
@@ -387,17 +413,24 @@ postgresql:
|
||||
externalDatabase:
|
||||
# Enable to use an external database instead of the internal PostgreSQL instance
|
||||
enabled: false
|
||||
|
||||
|
||||
# Database connection details
|
||||
host: "external-db.example.com"
|
||||
port: 5432
|
||||
username: postgres
|
||||
password: ""
|
||||
database: sim
|
||||
|
||||
|
||||
# SSL configuration
|
||||
sslMode: require
|
||||
|
||||
# Use an existing secret for external database credentials
|
||||
# This enables integration with External Secrets Operator, HashiCorp Vault, etc.
|
||||
existingSecret:
|
||||
enabled: false
|
||||
name: "" # Name of existing Kubernetes secret
|
||||
passwordKey: "EXTERNAL_DB_PASSWORD" # Key in the secret containing the password
|
||||
|
||||
# Ollama local AI models configuration
|
||||
ollama:
|
||||
# Enable/disable Ollama deployment
|
||||
@@ -1013,4 +1046,51 @@ copilot:
|
||||
|
||||
# Job configuration
|
||||
backoffLimit: 3
|
||||
restartPolicy: OnFailure
|
||||
restartPolicy: OnFailure
|
||||
|
||||
# External Secrets Operator integration
|
||||
# Use this to automatically sync secrets from external secret managers (Azure Key Vault, AWS Secrets Manager, etc.)
|
||||
# Prerequisites: Install External Secrets Operator in your cluster first
|
||||
# See: https://external-secrets.io/latest/introduction/getting-started/
|
||||
externalSecrets:
|
||||
# Enable External Secrets Operator integration
|
||||
enabled: false
|
||||
|
||||
# ESO API version - use "v1" for ESO v0.17+ (recommended), "v1beta1" for older versions
|
||||
apiVersion: "v1"
|
||||
|
||||
# How often to sync secrets from the external store
|
||||
refreshInterval: "1h"
|
||||
|
||||
# Reference to the SecretStore or ClusterSecretStore
|
||||
secretStoreRef:
|
||||
# Name of the SecretStore or ClusterSecretStore resource
|
||||
name: ""
|
||||
# Kind of the store: "SecretStore" (namespaced) or "ClusterSecretStore" (cluster-wide)
|
||||
kind: "ClusterSecretStore"
|
||||
|
||||
# Remote references - paths/keys in your external secret store
|
||||
# These map to the secrets that will be created in Kubernetes
|
||||
remoteRefs:
|
||||
# App secrets (authentication, encryption keys)
|
||||
app:
|
||||
# Path to BETTER_AUTH_SECRET in external store (e.g., "sim/app/better-auth-secret")
|
||||
BETTER_AUTH_SECRET: ""
|
||||
# Path to ENCRYPTION_KEY in external store
|
||||
ENCRYPTION_KEY: ""
|
||||
# Path to INTERNAL_API_SECRET in external store
|
||||
INTERNAL_API_SECRET: ""
|
||||
# Path to CRON_SECRET in external store (optional)
|
||||
CRON_SECRET: ""
|
||||
# Path to API_ENCRYPTION_KEY in external store (optional)
|
||||
API_ENCRYPTION_KEY: ""
|
||||
|
||||
# PostgreSQL password (for internal PostgreSQL)
|
||||
postgresql:
|
||||
# Path to PostgreSQL password in external store (e.g., "sim/postgresql/password")
|
||||
password: ""
|
||||
|
||||
# External database password (when using managed database services)
|
||||
externalDatabase:
|
||||
# Path to external database password in external store
|
||||
password: ""
|
||||
Reference in New Issue
Block a user