How do I handle secrets and environment configuration?
← Security and Sanitization · Ref: Q271
EK9 handles secrets through the EnvVars type, which provides auto-sanitized access to environment variables. This aligns with the 12-factor app methodology and container practices.
ENVVARS API
The EnvVars type provides:
env <- EnvVars() env.get(name) Auto-sanitized: blocks SQL, XSS, command injection but allows system paths env.unsanitizedGet(name) Raw value with no sanitization env contains name Check if variable exists env.keys() Iterate all variable names
AUTO-SANITIZATION
The get() method runs InputSanitizer automatically. This blocks injection patterns in environment variable values while allowing legitimate system paths like /usr/bin. Use unsanitizedGet() only when you specifically need raw values.
GUARD PATTERN
Combine EnvVars with declaration guards for safe access:
env <- EnvVars() if apiKey <- env.get("API_KEY") processWithKey(apiKey) else stderr.println("API_KEY not configured")
The guard handles both missing variables and sanitization failures in one line.
SANITIZED FORWARDING
A function that takes a sanitized parameter cleans its own copy on entry, so a value carrying an injection threat arrives unset:
connectToService()
-> apiKey as sanitized String
<- result as String: apiKey
This is run-time threat cleaning by the receiving function. It does not stop a value being logged and it tracks nothing through the call chain.
KEEPING SECRETS OUT OF LOGS
For a real credential use env.sensitiveGet(name), which returns a Sensitive. Its '$' always gives ***REDACTED*** and reveal() is gated by the Privileged trait. See Q701.
WHAT NOT TO DO
Never embed secrets in source code. Never log secret values (keep them in a Sensitive, whose '$' is redacted). Never store secrets in the .ek9 build directory. Never use unsanitizedGet without a specific reason.
INDUSTRY ALIGNMENT
Environment variables are the industry standard for secrets. Docker and Kubernetes inject secrets as env vars. Vault and AWS Secrets Manager ultimately deliver values through env vars. The 12-factor app methodology specifies env vars for configuration. EK9's EnvVars type with auto-sanitization goes beyond what most languages provide.
See Q215 for sanitized parameters. See Q29 for unset variables and guard patterns. See Q74 for declaration guards. See Q268 for OWASP vulnerability prevention. See Q272 for defense in depth.
Example
defines module qa.security.secrets defines function // Accept sanitized secret for processing connectToService() as pure -> apiKey as sanitized String <- result as String: "No key provided" // Copy constructor for defensive copy safeKey <- String(apiKey) if safeKey? result: "Connected with key length: " + $length safeKey defines program SecretsAndEnvDemo() stdout <- Stdout() stderr <- Stderr() // === READ ENVIRONMENT VARIABLES === env <- EnvVars() // Auto-sanitized access with guard if path <- env.get("PATH") stdout.println("PATH available, length: " + $length path) else stdout.println("PATH not available") // === CHECK EXISTENCE === if env contains "HOME" stdout.println("HOME is configured") // === GUARD PATTERN FOR SECRETS === if apiKey <- env.get("API_KEY") // connectToService cleans its own sanitized parameter on entry result <- connectToService(apiKey) if result? stdout.println(result) else stderr.println("API_KEY not configured") // === ITERATE AVAILABLE KEYS === stdout.println("Environment variable access patterns:") stdout.println(" get() — auto-sanitized") stdout.println(" unsanitizedGet() — raw value") stdout.println(" contains — check existence") stdout.println(" keys() — iterate names")
Common mistakes
E50001 — The type is EnvVars. A misspelt type name cannot be resolved, so E50001 is reported on that line. See ek9 -h E50001 for details.
Incorrect:
env <- EnvVar()
Correct:
env <- EnvVars()
E50001 — A misspelt function name cannot be resolved, so E50001 is reported on that line. Spell the declared function name exactly. See ek9 -h E50001 for details.
Incorrect:
result <- connectToServic(apiKey)
Correct:
result <- connectToService(apiKey)
Other ways to ask this
- How do I read environment variables in EK9?
- How does EK9 handle API keys and credentials?
- What is the best way to manage secrets in EK9?
Coming from another language?
Java: System.getenv() returns raw String, no sanitization. Python: os.environ with no safety. Go: os.Getenv returns raw string. Rust: std::env::var returns raw string. Kotlin: System.getenv() with no sanitization. EK9: EnvVars.get() auto-sanitizes blocking injection patterns, unsanitizedGet() for raw access, guard pattern for missing variables.
Keywords: api, password, config, protect, secret, sensitive, variable, env, key, safe, environment, security, token, credential