Config and Secrets
Openlane uses a layered configuration system built on koanf. Configuration values are resolved through a three-stage hierarchy where each stage can override the previous one.
Loading Hierarchy
- Struct defaults -- the
defaultstruct tags on the Go config type provide baseline values - YAML config file -- loaded from
./config/.config.yamlby default. If the file is missing, the system logs a warning and continues with defaults - Environment variables -- override everything. Prefixed with
CORE_and mapped to nested fields via underscore-to-dot transformation
Environment Variable Mapping
Environment variables follow the pattern CORE_<SECTION>_<FIELD>:
| Environment Variable | Config Path | Example Value |
|---|---|---|
CORE_SERVER_LISTEN | server.listen | :17608 |
CORE_DB_PRIMARYDBSOURCE | db.primarydbsource | postgres://user:pass@localhost/openlane |
CORE_AUTH_TOKEN_ACCESSDURATION | auth.token.accessduration | 15m |
CORE_REDIS_ADDRESS | redis.address | localhost:6379 |
CORE_ENTITLEMENTS_ENABLED | entitlements.enabled | true |
The transformation strips the CORE_ prefix, lowercases the remainder, and converts underscores to dots for nesting.
Config Structure
The root config struct in config/config.go contains all server configuration organized by concern:
| Section | Key Fields | Purpose |
|---|---|---|
Server | listen, debug, tls, cors, csrf, timeouts | HTTP server behavior |
DB | primarydbsource, secondarydbsource | Database connections |
Auth | enabled, token, supportedproviders, providers | Authentication settings |
Authz | OpenFGA configuration | Authorization service |
Redis | address | Cache and session store |
Email | Provider config, template paths | Email delivery |
Sessions | Cookie config, expiry | User session management |
ObjectStorage | Provider config (S3, R2, Disk, Database) | File storage |
Entitlements | Stripe keys, webhook secrets | Billing and subscription |
Workflows | Engine configuration | Workflow execution |
Slack | Webhook URL, message templates | Slack notifications |
Keywatcher | Key directory, secret manager integration | JWT signing key management |
Domain Inheritance
A convenience feature for deployment: setting the top-level Domain field automatically propagates to all config fields tagged with domain:"inherit".
domain: example.com
Fields tagged with domainPrefix or domainSuffix get the domain with a prefix or suffix applied:
domainPrefix:"api"resolves toapi.example.comdomainPrefix:"auth"resolves toauth.example.com
This means you can configure a single domain value and have API URLs, auth URLs, and CDN URLs all derive from it automatically.
Sensitive Fields
Fields tagged with sensitive:"true" receive special handling:
WebhookURL string `json:"webhookurl" koanf:"webhookurl" sensitive:"true"`
Sensitive fields are:
- Excluded from generated example configs and logged output
- Mapped to Kubernetes secrets via External Secrets Operator in production
- Sourced from GCP Secret Manager (or equivalent) rather than config files or plain environment variables
Current sensitive fields include Stripe webhook secrets, Slack webhook URLs, and GCP Secret Manager secret names.
Secret Management in Production
- Secret values are stored in an external secret manager (GCP Secret Manager)
- The External Secrets Operator syncs them into Kubernetes secrets
- Kubernetes injects them as environment variables
- The application's koanf loader picks them up through the standard
CORE_prefix mapping
Generated Artifacts
The configuration system generates deployment artifacts automatically:
| Artifact | Purpose |
|---|---|
helm-values.yaml | Helm chart values derived from config struct |
config.example.yaml | Example configuration with defaults (sensitive fields omitted) |
| ConfigMap templates | Kubernetes ConfigMap manifests for non-sensitive config |
| External Secrets templates | ExternalSecret manifests for sensitive fields |
Build Automation
CI workflows detect changes to the config struct and automatically:
- Regenerate Helm values and External Secrets templates
- Create a draft PR against the infrastructure repository
- Notify via Slack that config changes need review
This prevents drift between the application's config expectations and the deployed infrastructure.