#!/usr/bin/env nu # Generate .sops.yaml configuration files # Fetches Age public keys from vault-service and creates environment-specific SOPS rules # Usage: sops-init [--environment dev|staging|prod] [--output-dir ] [--validate] use std log def get-vault-url [] { $env.VAULT_SERVICE_URL? // "http://localhost:9094" } def get-vault-token [] { $env.VAULT_SERVICE_TOKEN? // "" } def fetch-age-public-key [environment: string] { let url = $"(get-vault-url)/api/v1/age/get-public?env=($environment)" let token = (get-vault-token) let headers = if ($token | is-empty) { {} } else { {"X-Vault-Token": $token} } let response = (http get -H $headers $url | complete) if $response.exit_code != 0 { error make { msg: "Cannot connect to vault-service" label: { text: $"Check VAULT_SERVICE_URL (set to: (get-vault-url))" span: (metadata $environment).span } } } let json = ($response.stdout | from json) $json.public_key } def generate-sops-yaml [environment: string, public_key: string] { let encrypted_regex = match $environment { "dev" => "^(password|token|key|secret|api_key)$", "staging" => "^(password|token|key|secret|api_key|database_url)$", "prod" => "^(password|token|key|secret|api_key|database_url|tls_cert|tls_key)$", _ => "^(password|token|key|secret|api_key)$" } let extension = match $environment { "dev" => ".dev.yaml", "staging" => ".staging.yaml", "prod" => ".prod.yaml", _ => ".yaml" } let header = "# SOPS creation rules - evaluated sequentially, first match wins" let rule1 = $" - path_regex: \\($extension)$" let rule1_age = $" age: '$public_key'" let rule1_regex = $" encrypted_regex: '$encrypted_regex'" let rule2 = " -" let rule2_age = $" age: '$public_key'" let rule2_regex = $" encrypted_regex: '$encrypted_regex'" $"$header creation_rules: $rule1 $rule1_age $rule1_regex $rule2 $rule2_age $rule2_regex " } def validate-sops-yaml [yaml_content: string] { let has_creation_rules = ($yaml_content | str contains "creation_rules:") let has_age_key = ($yaml_content | str contains "age:") let has_public_key = ($yaml_content | str contains "age1") # Age keys start with "age1" if not $has_creation_rules { error make { msg: "Invalid SOPS YAML: missing creation_rules section" label: { text: "YAML must have creation_rules" } } } if not $has_age_key { error make { msg: "Invalid SOPS YAML: missing age key configuration" label: { text: "Each rule must have an age key" } } } if not $has_public_key { error make { msg: "Invalid SOPS YAML: Age public key format invalid" label: { text: "Public key should start with 'age1'" } } } true } def determine-output-path [environment: string, output_dir: string] { let dir = if ($output_dir | is-empty) { match $environment { "dev" => "config/secrets/dev", "staging" => "config/secrets/staging", "prod" => "config/secrets/prod", _ => "config/secrets" } } else { $output_dir } $"($dir)/.sops.yaml" } def main [ --environment: string = "dev" --output-dir: string = "" --validate ] { # Validate environment if $environment not-in ["dev", "staging", "prod"] { error make { msg: "Invalid environment" label: { text: "Must be: dev, staging, or prod" span: (metadata $environment).span } } } print $"🔐 Generating .sops.yaml for ($environment) environment..." # Fetch Age public key print $"Fetching Age public key from vault-service..." let public_key = (fetch-age-public-key $environment) print $"✓ Age public key retrieved: ($public_key | str substring 0..20)..." # Generate SOPS configuration print "Generating SOPS rules..." let sops_yaml = (generate-sops-yaml $environment $public_key) # Validate if requested if $validate { print "Validating SOPS YAML configuration..." let valid = (validate-sops-yaml $sops_yaml) if $valid { print "✓ SOPS configuration is valid" } } # Determine output path let output_path = (determine-output-path $environment $output_dir) let output_dir_path = ($output_path | path dirname) # Create directory if needed if not ($output_dir_path | path exists) { print $"Creating directory: ($output_dir_path)" ^mkdir -p $output_dir_path } # Write .sops.yaml file print $"Writing .sops.yaml to ($output_path)" $sops_yaml | save -f $output_path print "" print "✓ SOPS configuration generated successfully" print $"Location: ($output_path)" print $"Environment: ($environment)" print $"Age public key: ($public_key | str substring 0..30)..." { success: true environment: $environment output_path: $output_path public_key: ($public_key | str substring 0..30) message: "SOPS .yaml configuration created" } }