Skip to content

Secrets & Environment Variables

Skipper separates non-sensitive configuration (environment variables) from sensitive credentials (secrets). They are stored and displayed differently.

Environment variables

For non-sensitive config like log levels, feature flags, and base URLs.

bash
# Set one or more variables
kip app env set api LOG_LEVEL=debug API_URL=https://api.example.com

# Load from a file
kip app env set api --from-file .env.production

# List all variables (values visible)
kip app env list api

# Delete a variable
kip app env delete api LOG_LEVEL

Values are displayed in plain text in both the CLI and the console UI.

Secrets

For sensitive values like database passwords, API keys, and tokens.

bash
# Interactive prompt (value hidden, not in shell history)
kip app secret set api DATABASE_URL

# Inline (warns about shell history)
kip app secret set api DATABASE_URL=postgres://user:pass@host/db

# Load from a file
kip app secret set api --from-file .secrets

# List keys only (values always masked)
kip app secret list api

# Reveal a single value
kip app secret reveal api DATABASE_URL

# Delete a secret
kip app secret delete api DATABASE_URL

# Rollback to the previous value
kip app secret rollback api DATABASE_URL

Automatic previous version

Every time you update a secret, Skipper automatically preserves the previous value (inspired by AWS Secrets Manager). The list command shows which keys have a previous version available:

$ kip app secret list api

  KEY                            PREVIOUS     VALUE
  DATABASE_URL                   yes          ••••••••
  STRIPE_KEY                                  ••••••••

If you accidentally set a wrong value, rollback instantly:

bash
kip app secret rollback api DATABASE_URL

JSON secrets

If a secret value is valid JSON, kip app secret reveal displays it as formatted JSON. This is useful for structured config like database credentials:

$ kip app secret reveal api DB_CONFIG
  DB_CONFIG=
  {
    "host": "db.example.com",
    "port": 5432,
    "user": "api",
    "password": "secret",
    "database": "production"
  }

Why the separation?

Environment variablesSecrets
list outputKeys and valuesKeys only (masked)
set behaviourInline KEY=VALUEInteractive hidden prompt
Console UIPlain textMasked with reveal button
Shell historyVisibleNot recorded (interactive mode)

How it works internally

Both env vars and secrets are stored as Kubernetes Secrets (encrypted at rest by k3s). They are kept in separate Secret objects:

  • <app>-env: environment variables
  • <app>-secrets: secrets

Both are injected into the pod via EnvFrom. From the application's perspective, they are all standard environment variables. There is no difference at runtime.

Updating either env vars or secrets triggers an automatic rolling restart so the application picks up the new values.

Released under the Apache 2.0 License.