Local generated secrets

Let fed create development passwords, signing keys, and other values that should be stable on one checkout without being committed to Git.

Generate a secret

Declare a type: secret parameter. With no source and no generate command, fed creates a cryptographically random 32-character alphanumeric value:

parameters:
  DB_PASSWORD:
    type: secret

services:
  database:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: '{{DB_PASSWORD}}'

The first fed start that needs the value generates it. In an interactive terminal, fed shows the names it will generate and asks for confirmation. In CI and other non-interactive contexts it proceeds without prompting.

Where values are stored

Generated values are written to .fed/secrets.generated.env and reused on later starts. Fed creates .fed/ when needed and manages .fed/.gitignore so the generated file is ignored by Git. Secret files are written atomically with mode 0600.

A value already present in the generated file is not replaced merely because fed starts again. To intentionally create a new value, remove that variable's line and run fed start.

Do not commit .fed/secrets.generated.env. If .fed/.gitignore is changed so the file is commit-eligible, fed refuses to write generated secrets there.

Custom generation

Use generate when a value needs a particular format. The command runs through sh -c; its trimmed stdout becomes the value. Stderr is hidden on success and included in the error if the command fails. When the command interpolates {{...}} values, the resolved command and its stderr are suppressed so a failure can't leak another secret.

parameters:
  SESSION_SECRET:
    type: secret
    generate: "openssl rand -hex 32"

Because this parameter is also type: secret, the command runs only when a value needs to be created. Its result is persisted. By contrast, a parameter with generate but without type: secret is a computed parameter: fed reruns it on every start and does not persist it.

Derived secrets

References in a generator create dependencies. Fed orders the commands and rejects dependency cycles:

parameters:
  SIGNING_PRIVATE_KEY:
    type: secret
    generate: "openssl genpkey -algorithm ED25519"

  SIGNING_PUBLIC_KEY:
    type: secret
    generate: "printf '%s' '{{SIGNING_PRIVATE_KEY}}' | openssl pkey -pubout"

If fed creates a missing input secret, it also regenerates persisted secrets that depend on that input during the same run. This prevents a derived public key, certificate, or token from getting out of sync with newly generated source material.

Generators are shell commands. Treat interpolated values as untrusted shell input when they can come from outside your config, and choose commands available on every development platform your team supports.

Local overrides

The generated secrets file is loaded before files in env_file, so a normal environment file can override a generated value for one machine:

env_file:
  - .env
  - .env.local

If one of those files already supplies the secret, fed uses that value instead of generating a new one. Keep every file containing secrets out of Git.

Generated or manual?

Use generated secrets for values whose actual contents do not matter and which fed can safely create: local database passwords, session secrets, encryption keys, and test signing keys.

Use source: manual when the value comes from an external system, such as an API key or OAuth client secret:

parameters:
  STRIPE_SECRET_KEY:
    type: secret
    source: manual
    description: "From https://dashboard.stripe.com/apikeys"

Fed never generates a manual secret. Supply it through an env_file, or use Team secrets to share development credentials through Service Federation Cloud.

Constraints

Secret parameters cannot declare default or either constraints. Put secret material outside the committed config.

Next: Commands →