Skip to content
Browse the docs

Command line

crunu run

Run a program with the variables of Crunu environments in a clean process environment, with signal forwarding and an optional restart when values change.

Last updated

On this page

crunu run starts a program with the variables of the environments you choose. Values are decrypted in memory and passed to the program through its process environment. Nothing is written to disk.

Shell
crunu run [--env PROJECT/ENVIRONMENT]... [--env-file FILE]... [--restart on-change] [--inherit-env] [--stop-timeout 30s] [--poll-interval 10s] -- COMMAND [ARGS]

A typical service on a server:

Shell
crunu run --env payments-api/production --restart on-change -- /opt/payments/bin/server

Which variables the program gets

crunu run reads only files marked Load as environment variables (crunu run) in the environment editor. Other files, such as ~/.aws/credentials, are not turned into variables. Use crunu pull to place those on disk.

  • --env names an environment as project/environment or by its ID. Repeat it to combine several environments. Later environments and files override earlier ones.
  • Without --env, crunu uses the environment in CRUNU_ENV. If that is empty too, it uses every environment granted to it.
  • --env-file reads variables from a local env file instead of the server. It can't be combined with --env.

A clean process environment

By default the program gets a short allowlist from the environment of crunu itself, plus the variables of the chosen environments:

Text
PATH HOME USER LOGNAME LANG LC_ALL TERM TZ SHELL TMPDIR

--inherit-env passes the whole environment of crunu instead. Either way, the program never receives the credentials of crunu: CRUNU_TOKEN, CRUNU_OIDC_TOKEN, CRUNU_ID_TOKEN and CRUNU_ENROLL_CODE. The only exception is a variable with one of these names that the environment itself contains, because that is environment data.

On Linux, crunu run also closes its own process to other processes of the same user before it reads any variables, including the program it starts. Its environment in /proc, its memory and debugging are unavailable to them. This does not stop root or processes with CAP_SYS_PTRACE. On GitHub-hosted runners every process of the job can use sudo without a password. macOS has no equivalent protection.

Signals, exit codes and restarts

crunu forwards INT, TERM, HUP, QUIT, USR1 and USR2 to the program and exits with the program's exit code. A program killed by a signal gives 128 plus the signal number. 127 means the command wasn't found and 126 that it couldn't be started. When crunu itself fails before starting the program, it exits with one of its own codes, listed in Environment variables and exit codes.

With --restart on-change, crunu watches for new values. After a change and 2 seconds without further changes, it sends SIGTERM to the program, waits --stop-timeout (30 seconds by default), sends SIGKILL if the program is still running, and starts it again with the new variables. Only the names of changed variables are logged. The machine service reports changes itself. With a person's session or a service token, crunu checks again every --poll-interval, 10 seconds by default. --restart never is the default.

Where the variables come from

crunu run uses the first source that is set up:

  1. CRUNU_TOKEN: service token mode. Sign-in, checks and decryption happen inside the crunu process, with no state files. This is the mode for CI.
  2. CRUNU_SOCKET: the service listening on that socket.
  3. Your session, if you signed in with crunu login and your keys are still in memory.
  4. The machine service, on the socket from agent.json or /run/crunu/agent.sock.

If you signed in but your keys are locked, crunu exits with code 3 and suggests crunu unlock. If you named an environment and there is no sign-in and no enrolled machine, the exit code is also 3. If you named nothing and no source is set up, the exit code is 2.

Environments it can't serve right now

An environment can be granted but not available at the moment. When you name it with --env or CRUNU_ENV, crunu run refuses with a reason and an exit code:

  • 7: the server doesn't serve this environment to your address because of a network restriction. The message includes the address the server sees.
  • 6: the data didn't pass signature checks.
  • 1: the key or the files haven't been delivered yet.

When you don't name environments, such environments are skipped. The program gets the rest, and crunu prints one line per skipped environment to stderr, for example that payments-api/production was skipped because the server sees the address 198.51.100.7 outside its allowed networks. The line repeats only when the set of skipped environments changes.

The server decides network restrictions. crunu explains the decision but never works around it. See Network rules.

Running a service under systemd

On a server, run your application through the agent so its variables come from the service's memory:

INI
# /etc/systemd/system/payments-api.service
[Service]
User=payments
ExecStart=/usr/local/bin/crunu run --env payments-api/production --restart on-change -- /opt/payments/bin/server

The payments user must be a member of the crunu group to reach the service socket. Your deploy pipeline then only ships code and restarts the service. It never sees the production secrets.