Skip to main content

Component Configuration and Secrets

Wasm components running on Cosmonic Control receive configuration and secrets through fields on the HTTPTrigger or WorkloadDeployment manifest. Values are delivered to the component via the wasi:config interface and read at runtime.

This page covers all configuration mechanisms available to a component: inline key-value pairs, references to Kubernetes ConfigMaps and Secrets, outbound network allowlisting, and private OCI registries for component images.

Inline configuration

Pass static key-value pairs directly in the manifest using localResources.environment.config:

apiVersion: control.cosmonic.io/v1alpha1
kind: HTTPTrigger
metadata:
  name: my-app
  namespace: default
spec:
  replicas: 1
  ingress:
    host: my-app.localhost.cosmonic.sh
    paths:
      - path: /
        pathType: Prefix
  template:
    spec:
      components:
        - name: app
          image: ghcr.io/my-org/my-app:1.0.0
          localResources:
            environment:
              config:
                LOG_LEVEL: info
                CACHE_TTL: "300"
                FEATURE_FLAG_DARK_MODE: "true"

Keys and values are arbitrary strings. The component reads them at runtime via wasi:config/runtime.

Configuration from a ConfigMap

Reference a Kubernetes ConfigMap to supply configuration without embedding it in the manifest. All keys in the ConfigMap are merged into the component's configuration:

kubectl create configmap my-app-config \
  --from-literal=LOG_LEVEL=info \
  --from-literal=CACHE_TTL=300 \
  -n default
spec:
  template:
    spec:
      components:
        - name: app
          image: ghcr.io/my-org/my-app:1.0.0
          localResources:
            environment:
              configFrom:
                - name: my-app-config

Multiple ConfigMaps may be listed. If the same key appears in more than one, the last entry in the list wins.

You can combine configFrom with inline config. Inline values are merged alongside the referenced ConfigMaps. In case of key conflicts, the last source in declaration order wins:

localResources:
  environment:
    config:
      FEATURE_FLAG_DARK_MODE: "true"   # inline override
    configFrom:
      - name: my-app-config            # base config from ConfigMap
      - name: my-app-config-overrides  # additional overrides

Secrets

Reference a Kubernetes Secret to inject sensitive values. Secret values are base64-decoded and UTF-8 decoded before being delivered to the component:

kubectl create secret generic my-app-secrets \
  --from-literal=DATABASE_URL=postgres://user:password@db.internal:5432/mydb \
  --from-literal=API_KEY=supersecretkey \
  -n default
spec:
  template:
    spec:
      components:
        - name: app
          image: ghcr.io/my-org/my-app:1.0.0
          localResources:
            environment:
              secretFrom:
                - name: my-app-secrets

Multiple Secrets may be listed. If the same key appears in more than one, the last entry takes precedence.

configFrom and secretFrom may be combined freely. All referenced ConfigMaps and Secrets are merged into a single flat key-value map delivered to the component:

localResources:
  environment:
    config:
      LOG_LEVEL: info
    configFrom:
      - name: my-app-config
    secretFrom:
      - name: my-app-secrets
note

The operator service account has get, list, and watch access to Secrets cluster-wide by default (see Kubernetes RBAC). Ensure your namespace RBAC restricts which tenants can create or read Secrets in each namespace.

Host interface configuration

Some host interfaces require their own configuration — for example, an outbound HTTP interface that needs a base URL, or a blobstore interface that needs a bucket name. These are separate from component configuration and are passed to the capability layer via hostInterfaces[].config:

spec:
  template:
    spec:
      components:
        - name: app
          image: ghcr.io/my-org/my-app:1.0.0
      hostInterfaces:
        - namespace: wasi
          package: blobstore
          version: 0.2.0-draft
          interfaces:
            - blobstore
          config:
            bucket: my-bucket
          secretFrom:
            - name: blobstore-credentials

hostInterfaces supports the same config, configFrom, and secretFrom fields as component localResources.

Outbound network access

By default, Wasm components have no outbound network access. Use allowedHosts to explicitly permit outbound HTTP calls to specific hosts:

localResources:
  allowedHosts:
    - https://api.example.com
    - https://auth.example.com

Calls to any host not in allowedHosts will be denied at the runtime level. Use the most specific URLs you can — preferring https://api.example.com over https://*.

note

allowedHosts controls outbound HTTP access from within the component (via wasi:http/outgoing-handler). It does not affect inbound traffic, which is controlled by the HTTPTrigger ingress configuration.

Private component registries

If your component image is in a private OCI registry, create a docker-registry pull secret and reference it on the component spec:

kubectl create secret docker-registry component-pull-secret \
  --docker-server=my-registry.corp.com \
  --docker-username=<username> \
  --docker-password=<password> \
  -n default
spec:
  template:
    spec:
      components:
        - name: app
          image: my-registry.corp.com/my-org/my-app:1.0.0
          imagePullSecret:
            name: component-pull-secret

Each component in a workload can reference a different pull secret if images come from different registries.

note

This secret is per-component, not per-HostGroup pod. The HostGroup itself does not need access to your application component registries — only the operator does, to resolve and distribute the component image.

Volumes and volume mounts

Workloads can request a volume on the host pod and mount it into one or more components. The most common use is sharing data between a long-running service and the per-request components colocated with it on the same host (see Service-plus-component workloads).

Declare the volume once on template.spec.volumes, then mount it on each side via localResources.volumeMounts:

spec:
  template:
    spec:
      volumes:
        - name: data
          ephemeral: {}
      service:
        image: ghcr.io/example/index-service:0.1.0
        localResources:
          volumeMounts:
            - name: data
              mountPath: /data
      components:
        - name: api
          image: ghcr.io/example/api:0.1.0
          localResources:
            volumeMounts:
              - name: data
                mountPath: /data

Volumes default to read-write. Set readOnly: true on a volumeMount to mount it read-only on that side; omit the field for the default read-write behavior.

ephemeral: {} requests a per-host scratch volume that is created with the host pod and destroyed when the pod terminates — its lifetime matches the workload's. Persistent volumes mounted in this way are not part of the v0.4.x surface.

NATS messaging subscriptions

Components that export wasmcloud:messaging/handler@0.2.0 receive inbound messages from NATS subjects subscribed by the host on their behalf. Configure the subjects via the config.subscriptions field on the messaging entry under hostInterfaces:

spec:
  template:
    spec:
      hostInterfaces:
        - namespace: wasmcloud
          package: messaging
          version: '0.2.0'
          interfaces:
            - handler
            - consumer
            - types
          config:
            subscriptions: tasks.worker
      components:
        - name: task-worker
          image: ghcr.io/example/task-worker:0.1.0

Inbound messages on tasks.worker invoke the component's handle_message export. To reply, the handler reads msg.reply_to and publishes a response on it via wasmcloud:messaging/consumer.publish. If the handler returns Err without publishing, no reply is sent and the requester sees its own client-side timeout.

The hostgroup chart's nexus.requestTimeoutSeconds value (default 300 since chart 0.4.1) bounds how long any single wasmcloud:messaging/consumer.request call will wait for a reply. Lower it explicitly to fall back to a tighter ceiling, or set it to null to use the async-nats client default of 10 seconds.

Reference

All configuration fields are available under spec.template.spec.components[].localResources on both HTTPTrigger and WorkloadDeployment:

FieldTypeDescription
localResources.environment.configmap[string]stringInline key-value configuration delivered to the component
localResources.environment.configFrom[]LocalObjectReferenceReferences to ConfigMaps; all keys are merged
localResources.environment.secretFrom[]LocalObjectReferenceReferences to Secrets; values are base64+UTF-8 decoded
localResources.allowedHosts[]stringAllowlist of outbound HTTP hosts
localResources.volumeMounts[]VolumeMountMounts a volume declared in template.spec.volumes into the component or service
imagePullSecretLocalObjectReferencePull secret for the component's OCI image
hostInterfaces[].configmap[string]stringInline config for a host interface (e.g. subscriptions for wasmcloud:messaging/handler@0.2.0)
hostInterfaces[].configFrom[]LocalObjectReferenceConfigMap references for a host interface
hostInterfaces[].secretFrom[]LocalObjectReferenceSecret references for a host interface