- Storage, Config & Secrets
- Secrets Management
Secrets Management
Ironflow provides environment-scoped secrets management with AES-256-GCM encryption backed by NATS KV. Secrets are write-only—values can be set but never retrieved through the API, CLI, or Dashboard.
Event-Driven by Design
Every secret operation (create, update, delete) is a JetStream message. This ensures that secret state inherits the same durability and replication guarantees as your workflows.
- Atomic: Secret updates use native JetStream revision tracking.
- Observable: Every rotation emits a system event (e.g.,
system.secret.STRIPE_KEY.updated). - Declarative: Functions declare exactly which secrets they need; the engine resolves and injects them only at runtime.
Secure by Default
The architecture enforces a strict “Management vs. Runtime” separation:
- Write-Only API: The CLI and Dashboard only expose metadata (revision, name). Plaintext values are never returned.
- Runtime Injection: Values are only decrypted when a worker receives a job.
- Master Key: Encryption is controlled by the
IRONFLOW_MASTER_KEYenvironment variable, or byspec.auth.masterKeyin the config file. The value must be a hex-encoded 32 bytes (generate withopenssl rand -hex 32).
When you start with ironflow serve -f ironflow.yaml, the file is the only source of truth and IRONFLOW_MASTER_KEY is not read — set spec.auth.masterKey, or reference the variable from the file as masterKey: ${IRONFLOW_MASTER_KEY}. serve and validate print a warning for each env var set but ignored.
Dev mode — no encryption. If IRONFLOW_MASTER_KEY is unset or empty, Ironflow runs in development mode and stores secrets in plaintext on disk. The engine logs a warning at startup. Always set a master key in production.
Turning encryption on later does not encrypt what is already stored. There is no
rekey command: a value written before the master key was set stays plaintext, and
reading it after the key is set fails with “secret was stored unencrypted … re-run
ironflow secret set”. Re-run ironflow secret set for every secret after
setting IRONFLOW_MASTER_KEY for the first time. Rotating to a different master
key has the same requirement, and values sealed with the old key are unreadable
without it.
Quick Start (Node.js)
1. Set a secret via CLI:
ironflow secret set STRIPE_KEY sk_live_123 --env default --description "Stripe live key"The --env / -e flag targets a specific environment (defaults to default). All ironflow secret subcommands (set, get, list, delete) accept --env. set also accepts --description / -d.
2. Declare and use in a function:
import { ironflow } from "@ironflow/node";
export const payout = ironflow.createFunction( { id: "payout", triggers: [{ event: "payout.requested" }], secrets: ["STRIPE_KEY"], // Declare dependency }, async ({ event, secrets, step }) => { // Access the decrypted value const apiKey = secrets.get("STRIPE_KEY");
await step.run("charge", () => stripe(apiKey).charge(...)); });When to Use Secrets
| Feature | Use For |
|---|---|
| Secrets | API Keys, DB Passwords, Certificates. |
| Config | Rollout percentages, Theme settings, Timeouts. |
| KV Store | Sessions, Caching, Counters. |
Subscribing to Rotations
You can subscribe to secret lifecycle events to audit rotations or trigger security workflows.
import { ironflow } from "@ironflow/browser";
await ironflow.subscribe("system.secret.*.updated", { onEvent: (e) => console.log(`Secret ${e.data.name} was rotated!`),});