provisioning/schemas/examples/deployment-with-secrets.ncl

240 lines
5.8 KiB
Text
Raw Permalink Normal View History

# Example: Complete Deployment Configuration with Nickel + SOPS Integration
#
# This example shows the hybrid pattern:
# 1. Infrastructure config in .ncl (readable, version-controlled)
# 2. Secrets in YAML (encrypted with SOPS)
# 3. Merged at deployment time
let sops = import "schemas/security/sops/main.ncl" in
let secrets_loader = import "schemas/security/secrets-loader.ncl" in
let config_merger = import "schemas/security/config-merger.ncl" in
{
# ============================================
# STEP 1: Default Configuration
# ============================================
defaults = {
environment = "dev",
deployment_mode = "solo",
database = {
type = "postgresql",
host = "localhost",
port = 5432,
name = "myapp",
user = "app_user",
# Password placeholder - will be replaced by secrets
password = "${secret:database.password}",
ssl = false,
pool_size = 10,
},
redis = {
host = "localhost",
port = 6379,
# Password placeholder - will be replaced by secrets
password = "${secret:redis.password}",
db = 0,
ttl = 3600,
},
api = {
host = "0.0.0.0",
port = 8080,
# API key placeholder - will be replaced by secrets
api_key = "${secret:api.api_key}",
timeout = 30,
max_connections = 100,
},
tls = {
enabled = false,
# Certificate placeholders - will be replaced by secrets
certificate = "${secret:tls.certificate}",
private_key = "${secret:tls.private_key}",
},
},
# ============================================
# STEP 2: Environment-Specific Overrides
# ============================================
environments = {
# All environments inherit these
all = {
logging = {
level = "info",
format = "json",
},
},
# Development overrides
dev = {
database = {
host = "postgres-dev.local",
ssl = false,
},
redis = {
host = "redis-dev.local",
},
api = {
port = 8080,
},
logging = {
level = "debug",
},
},
# Staging overrides
staging = {
database = {
host = "postgres-staging.example.com",
ssl = true,
},
redis = {
host = "redis-staging.example.com",
},
api = {
port = 443,
},
tls = {
enabled = true,
},
logging = {
level = "info",
},
},
# Production overrides
prod = {
database = {
host = "postgres-prod-cluster.example.com",
port = 5432,
ssl = true,
pool_size = 50,
},
redis = {
host = "redis-prod-cluster.example.com",
},
api = {
port = 443,
max_connections = 1000,
},
tls = {
enabled = true,
},
logging = {
level = "warn",
},
},
},
# ============================================
# STEP 3: Deployment Modes
# ============================================
deployment_modes = {
solo = {
replicas = 1,
resources = {
cpu = "1",
memory = "512Mi",
},
},
ha = {
replicas = 3,
resources = {
cpu = "2",
memory = "2Gi",
},
},
enterprise = {
replicas = 5,
resources = {
cpu = "4",
memory = "4Gi",
},
},
},
# ============================================
# STEP 4: SOPS Configuration
# ============================================
sops_config = {
dev = (sops.generate_sops_yaml "dev"),
staging = (sops.generate_sops_yaml "staging"),
prod = (sops.generate_sops_yaml "prod"),
},
# ============================================
# STEP 5: Build Final Configuration
# ============================================
# This function is called at deployment time with:
# - environment: "dev" | "staging" | "prod"
# - secrets: loaded from config/secrets/{env}.yaml (SOPS-encrypted)
# - deployment_mode: "solo" | "ha" | "enterprise"
build_config = fun environment deployment_mode secrets =>
let env_config = config_merger.by_environment @ { defaults = $.defaults, environments = $.environments } environment in
let mode_config = ($.deployment_modes | std.record.get deployment_mode | default {}) in
let base = config_merger.compose_config $.defaults env_config {} in
let with_mode = config_merger.compose_config base mode_config {} in
let final = config_merger.compose_config with_mode secrets {} in
# Merge secrets into placeholders
secrets_loader.merge final secrets,
# ============================================
# Export Configuration for Different Scenarios
# ============================================
# Development configuration (for local testing)
config_dev = {
environment = "dev",
deployment_mode = "solo",
config = (
config_merger.compose_config
$.defaults
($.environments | std.record.get "dev")
{}
),
},
# Staging configuration (requires secrets)
config_staging = {
environment = "staging",
deployment_mode = "ha",
config = (
config_merger.compose_config
$.defaults
($.environments | std.record.get "staging")
{}
),
},
# Production configuration (requires secrets)
config_prod = {
environment = "prod",
deployment_mode = "enterprise",
config = (
config_merger.compose_config
$.defaults
($.environments | std.record.get "prod")
{}
),
},
# ============================================
# Validation
# ============================================
validate = fun configuration =>
let required_paths = [
"database.host",
"database.user",
"redis.host",
"api.port",
] in
config_merger.validate_complete configuration required_paths,
}