seekrit
Docs/seekrit-run launcher

The seekrit-run launcher

seekrit-run is a compiled, single-file version of seekrit run built for machines. It authenticates with a service token, fetches the bound environment's encrypted secrets, decrypts them locally, layers them under any .env files and the live process environment, and then execs your command. That's all it does — no config files, no caching, no daemon.

SEEKRIT_TOKEN=skt_… seekrit-run -- ./start-server
note

Use the Node seekrit CLI for human workflows (login, key setup, managing secrets). seekrit-run is service-token only and read-only at runtime: the smallest thing that can turn a token into an environment and hand off to your process.

Degrades gracefully

Fetching seekrit secrets is best-effort. If the token is missing or malformed, or the API can't be reached, seekrit-run logs a warning to stderr and still runs your command with just the .env overlay and the live environment:

seekrit-run: continuing without seekrit-managed secrets: could not reach the seekrit API: …

This means the same launcher works whether or not seekrit is reachable — locally without a token, in CI, or in an offline sandbox — so you can wire it into an image's entrypoint unconditionally. Only genuinely local problems stop it: a usage error, an explicit --env-file that can't be read, or a command that can't be started. The seekrit run subcommand of the Node CLI behaves the same way.

Note what that degraded start actually gives you: the command runs, but without its managed secrets. If your app needs them, it will fail somewhere further in — usually deeper and less obviously than a failure at startup. Add --cache when you would rather it keep running on the last secrets it saw.

Surviving an outage with --cache

Off by default. With --cache, each successful resolve is written to disk and a later run falls back to it when the API cannot be reached:

seekrit-run --cache -- ./start-server
seekrit-run: could not reach the seekrit API: … — using cached secrets fetched 6m ago

Only the encrypted response is stored — the same ciphertext and wrapped data keys the API serves. Decrypting it still needs this token, so the file is no more sensitive than the token beside it (it is written 0600 in a 0700 directory). Live resolve is always tried first, and a refused resolve (401/403) deletes the entry rather than falling back to it, so revoking a token still takes effect on the next run. Entries expire after --cache-max-age (default 24h).

In a container, point it at a mounted volume so it survives a restart:

seekrit-run --cache --cache-dir /var/cache/seekrit -- ./start-server

Full behavior, including the two trade-offs it makes, is in the CLI reference.

Why use it instead of the CLI?

  • Tiny & static. One ~1–2 MB file with no runtime dependencies — no Node, no OpenSSL, no system CA bundle. TLS roots are compiled in, so it runs unchanged in distroless, alpine, and scratch images.
  • Same behavior as seekrit run. Identical layer precedence, .env parsing, and ${OTHER_SECRET} reference expansion; its decryption is verified bit-for-bit against the browser/CLI crypto.
  • Clean process model. On Unix it replaces itself with your command (execvp), so signals and exit codes pass through exactly. On Windows it spawns, waits, and forwards the exit code.

Install

The install script detects your OS and architecture, downloads the matching binary from run.seekrit.dev, verifies its SHA-256 checksum, and drops it on your PATH:

curl -fsSL https://run.seekrit.dev/install.sh | sh

It installs to /usr/local/bin if that's writable, otherwise ~/.local/bin. Override the destination, pin a version, or force a target with environment variables:

# Pin a version and install somewhere specific.
curl -fsSL https://run.seekrit.dev/install.sh \
  | SEEKRIT_RUN_VERSION=0.2.0 SEEKRIT_RUN_INSTALL_DIR="$HOME/bin" sh
VariableDefaultDescription
SEEKRIT_RUN_VERSIONlatestVersion to install, e.g. 0.2.0.
SEEKRIT_RUN_INSTALL_DIR/usr/local/bin or ~/.local/binWhere to put the binary.
SEEKRIT_RUN_TARGETauto-detectedForce a Rust target triple.

Manual download

Prefer to fetch it yourself? Every release is published under a versioned and a latest/ path, each with a .sha256 alongside. On Linux the fully static musl build runs anywhere (glibc, alpine, distroless, scratch):

# Pick your target: {x86_64,aarch64}-{unknown-linux-musl,unknown-linux-gnu,apple-darwin}
curl -fsSL -O https://run.seekrit.dev/latest/seekrit-run-aarch64-apple-darwin.tar.gz
curl -fsSL -O https://run.seekrit.dev/latest/seekrit-run-aarch64-apple-darwin.sha256
shasum -a 256 -c seekrit-run-aarch64-apple-darwin.sha256
tar xzf seekrit-run-aarch64-apple-darwin.tar.gz
install -m 0755 seekrit-run /usr/local/bin/

Windows ships as a .zip (seekrit-run-x86_64-pc-windows-msvc.zip).

Usage

# Token from the environment (or a .env file); resolves org/app/env from it.
SEEKRIT_TOKEN=skt_… seekrit-run -- pnpm start

# Token via flag; everything after -- is the command, verbatim.
seekrit-run --token skt_… -- node --enable-source-maps server.js

# Swap one composed group's slice for this run.
seekrit-run --with auth-providers=staging -- ./app

# See where each variable resolved from (stderr; names only, never values).
seekrit-run --explain -- true

Precedence

Highest wins — identical to seekrit run:

process env  >  .env files  >  app-environment secrets  >  group secrets

The live process environment always wins, so a value exported in the shell (or by your orchestrator) overrides anything seekrit resolves.

Options

FlagDefaultDescription
-t, --token <skt_…>SEEKRIT_TOKEN (env or .env)Service token.
--api-url <url>SEEKRIT_API_URL or https://api.seekrit.devAPI base URL.
-e, --env-file <path>.envA .env file to overlay (repeatable).
--no-env-fileDo not load the default .env.
--with <group=env>Override one composed group's slice (repeatable).
--explainPrint each variable's source to stderr.
--no-interpolateLeave ${OTHER_SECRET} references as literal text.
--cacheoffFall back to the last-known-good encrypted response when the API is unreachable. Also SEEKRIT_CACHE=1.
--no-cacheOverride SEEKRIT_CACHE=1 for this run.
--cache-dir <path>SEEKRIT_CACHE_DIR, else $XDG_CACHE_HOME/seekritWhere cached responses live.
--cache-max-age <d>24hHow stale a cached response may be and still be used.

HTTPS_PROXY / ALL_PROXY are honored for egress-proxied networks.

In a container

Keep Node out of your runtime image entirely. The simplest way is to copy the binary out of the published image — seekritdev/run is multi-arch and is just the static binary on scratch (~2 MB) — into a minimal runtime, and make it the entrypoint:

FROM seekritdev/run:latest AS seekrit
FROM gcr.io/distroless/static
COPY --from=seekrit /seekrit-run /usr/local/bin/seekrit-run
ENTRYPOINT ["seekrit-run", "--"]
CMD ["./start-server"]

Pin a release tag (e.g. seekritdev/run:0.3.0) for reproducibility, or :edge for the latest main.

Prefer not to depend on Docker Hub? Fetch the static binary in a build stage instead — pin the version and verify the checksum for reproducible images:

# --- fetch seekrit-run: pinned + checksum-verified --------------------------
FROM alpine:3 AS seekrit
ARG SEEKRIT_RUN_VERSION=0.2.0
ARG TARGET=x86_64-unknown-linux-musl
RUN apk add --no-cache curl && cd /tmp \
 && curl -fsSL -O https://run.seekrit.dev/v${SEEKRIT_RUN_VERSION}/seekrit-run-${TARGET}.tar.gz \
 && curl -fsSL -O https://run.seekrit.dev/v${SEEKRIT_RUN_VERSION}/seekrit-run-${TARGET}.sha256 \
 && sha256sum -c seekrit-run-${TARGET}.sha256 \
 && tar xzf seekrit-run-${TARGET}.tar.gz -C /usr/local/bin

# --- your runtime image: fully static, so distroless/static is enough -------
FROM gcr.io/distroless/static
COPY --from=seekrit /usr/local/bin/seekrit-run /usr/local/bin/seekrit-run
ENTRYPOINT ["seekrit-run", "--"]
CMD ["./start-server"]
docker run --rm \
  -e SEEKRIT_TOKEN="$SEEKRIT_TOKEN" \
  your-image ./start-server
caution

Inject at runtime, never at build time. Secrets fetched during docker build can be baked into an image layer. seekrit-run only ever puts values into the child process's environment — nothing touches disk.

Exit codes

CodeMeaning
2Usage error (unknown flag, no command).
1An explicitly named --env-file could not be read.
127The command could not be started.
childOtherwise, the command's own exit code.

A missing/malformed token, a revoked token or missing key grant, and network failures are not fatal — seekrit-run warns and runs the command without the managed secrets (see Degrades gracefully).

See the CLI reference for the condensed version, and Service tokens for how to mint the token this binary needs.