Inject Configuration from ConfigMaps and Secrets
This recipe walks through providing runtime configuration to a wasmCloud component from three sources: inline key-value pairs, Kubernetes ConfigMaps, and Kubernetes Secrets. All three are delivered to the component through the same interface, wasi:cli/environment, so the component reads them the same way regardless of source.
By the end, you will have a component that reads configuration values from all three sources, with a clear understanding of how precedence works when keys overlap.
Prerequisites
- A Kubernetes cluster with wasmCloud installed via the Helm chart
kubectl- A component that reads
wasi:cli/environment(see Configuration for a TypeScript walkthrough, or use the example below)
How it works
The localResources.environment field on a component accepts three sub-fields:
| Field | Source | Precedence |
|---|---|---|
config | Inline key-value pairs in the manifest | Lowest |
configFrom | References to Kubernetes ConfigMaps | Middle |
secretFrom | References to Kubernetes Secrets | Highest |
All keys from all sources are merged into a single set of environment variables. When the same key appears in more than one source, the source with higher precedence wins. Within a single source (e.g. multiple ConfigMaps in configFrom), the last entry in the list wins.
Components can read the merged values by calling getEnvironment() (a part of the wasi:cli/environment interface), which returns all key-value pairs as an array.
Step 1: Create the ConfigMap
Create a ConfigMap with non-sensitive application configuration:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: default
data:
APP_NAME: "My Service"
LOG_LEVEL: "info"
UPSTREAM_URL: "https://api.example.com"kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: default
data:
APP_NAME: "My Service"
LOG_LEVEL: "info"
UPSTREAM_URL: "https://api.example.com"
EOFStep 2: Create the Secret
Create a Secret for sensitive values:
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
namespace: default
type: Opaque
stringData:
API_KEY: "sk-example-key-12345"
DB_PASSWORD: "supersecret"kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
namespace: default
type: Opaque
stringData:
API_KEY: "sk-example-key-12345"
DB_PASSWORD: "supersecret"
EOFSecret values are delivered to the component as plain strings. No base64 decoding is required in your component code.
Step 3: Deploy the workload with all three sources
Create a WorkloadDeployment that combines inline values, the ConfigMap, and the Secret:
apiVersion: runtime.wasmcloud.dev/v1alpha1
kind: WorkloadDeployment
metadata:
name: configured-app
namespace: default
spec:
replicas: 1
template:
spec:
hostSelector:
hostgroup: default
components:
- name: http-component
image: ghcr.io/wasmcloud/components/hello-world:0.1.0
localResources:
environment:
config:
REGION: "us-east-1"
LOG_LEVEL: "debug"
configFrom:
- name: app-config
secretFrom:
- name: app-secrets
hostInterfaces:
- namespace: wasi
package: http
interfaces:
- incoming-handler
config:
host: localhostkubectl apply -f - <<EOF
apiVersion: runtime.wasmcloud.dev/v1alpha1
kind: WorkloadDeployment
metadata:
name: configured-app
namespace: default
spec:
replicas: 1
template:
spec:
hostSelector:
hostgroup: default
components:
- name: http-component
image: ghcr.io/wasmcloud/components/hello-world:0.1.0
localResources:
environment:
config:
REGION: "us-east-1"
LOG_LEVEL: "debug"
configFrom:
- name: app-config
secretFrom:
- name: app-secrets
hostInterfaces:
- namespace: wasi
package: http
interfaces:
- incoming-handler
config:
host: localhost
EOFStep 4: Understand precedence
In the manifest above, LOG_LEVEL appears in two sources:
config(inline) sets it to"debug"configFromreferencesapp-config, which sets it to"info"
Because configFrom has higher precedence than config, the component receives LOG_LEVEL=info.
The full set of values the component receives:
| Key | Value | Source | Why |
|---|---|---|---|
REGION | us-east-1 | config | Only appears in inline config |
LOG_LEVEL | info | configFrom | ConfigMap overrides inline |
APP_NAME | My Service | configFrom | Only appears in ConfigMap |
UPSTREAM_URL | https://api.example.com | configFrom | Only appears in ConfigMap |
API_KEY | sk-example-key-12345 | secretFrom | Only appears in Secret |
DB_PASSWORD | supersecret | secretFrom | Only appears in Secret |
If app-secrets also contained a LOG_LEVEL key, the Secret value would win over both the inline and ConfigMap values.
Reading configuration in component code
Rust
Use the wasi:cli/environment bindings to read environment variables:
fn get_config() -> std::collections::HashMap<String, String> {
wasi::cli::environment::get_environment()
.into_iter()
.collect()
}TypeScript
Import getEnvironment from wasi:cli/environment:
import { getEnvironment } from 'wasi:cli/environment@0.2.3';
const config = Object.fromEntries(getEnvironment());
const region = config['REGION'] ?? 'us-west-2';
const apiKey = config['API_KEY'];Call getEnvironment() inside route handlers rather than at module scope. See the Configuration guide for a full TypeScript walkthrough including Hono integration.
Multiple ConfigMaps and Secrets
You can reference multiple ConfigMaps and multiple Secrets. Within each list, the last entry wins on key conflicts:
localResources:
environment:
configFrom:
- name: base-config # loaded first
- name: override-config # wins on conflicts
secretFrom:
- name: shared-secrets # loaded first
- name: app-secrets # wins on conflictsThis is useful for layering a shared base configuration with per-application overrides.
Development workflow
During local development with wash dev, localResources.environment defaults to empty. Provide fallback defaults in your component code so the component runs correctly without configuration:
const config = Object.fromEntries(getEnvironment());
const region = config['REGION'] ?? 'us-west-2';
const logLevel = config['LOG_LEVEL'] ?? 'debug';Test configuration-dependent behavior by deploying to a Kubernetes environment with the full manifest.
Clean up
kubectl delete workloaddeployment configured-app
kubectl delete configmap app-config
kubectl delete secret app-secretsRelated documentation
- Secrets and Configuration Management for a complete reference on
localResources.environment - Configuration (TypeScript) for a full walkthrough of reading configuration in TypeScript
- Custom Resource Definitions for the full CRD field reference
- Roles and Role Bindings for RBAC considerations when referencing Secrets