17. Dynamic Command Configuration

Commands often require access to runtime variables, particularly when interacting with external services, ranging from mundane values (like the URL of a downstream resource) to highly sensitive information (like database passwords or access tokens).

One (terrible) way of providing these values to a command might be baking them into the bundle’s container image, but that has two problems:

  1. It limits command reusability by requiring all users to use the same configuration.

  2. It creates a security risk by making potentially sensitive values accessible to anybody who with access to the image.

Dynamic command configuration solves this problem by making it possible to securely store configuration information so that it can be injected into worker containers at runtime as specifically-named environment variables or files.

Note

Dynamic command configuration shouldn’t be confused with the config.yaml file that defines the commands, rules, and permissions present in each command bundle. That configuration is effectively static. The configuration we are concerned with is for the execution of individual commands.

It’s also dynamic in the sense that it can be changed on-the-fly by Gort administrators, with the changes taking effect nearly instantaneously without restarting any applications.

Warning

Currently dynamic configurations can only be stored in plain text in the Gort database. While a secure backend is currently in development, it is currently recommended that dynamic configuration not be used to inject highly sensitive values.

17.1. Core Concepts

Dynamic configuration allows users to define one or more key-value pairs that are injected as variables into the execution environment of a command. The key is usually a simple name, like “url” or “email”.

Note

All configurations belong to a specific bundle. Dynamic configurations cannot be assigned to multiple bundles.

The actual environment variable name is constructed by converting this key into an all-caps name using the pattern BUNDLE_KEY. Dashes are also converted into underscores.

For example, a dynamic configuration named “user-email” that belongs to the “testing” bundle will be injected into the command environment as TESTING_USER_EMAIL.

A command can then access it as an environment variable (e.g. ENV['TESTING_USER_EMAIL'] in Ruby, os.environ['TESTING_USER_EMAIL'] in Python, etc.)

Warning

Each command in a bundle will receive the same dynamic configuration environment. There is not currently a way to allow one command to receive one set of variables while another receives a different set.

17.2. Layers

There are four layers:

bundle

Configurations at the bundle layer are applied to all of the commands in its respective command bundle. This layer can be overridden by any other layer.

channel

Configurations made at the channel layer are applied to all commands in its bundle executed in a specific channel. This layer can override bundle layer configurations, and can in turn be overridden by group or user layer configurations.

group

Configurations made at the group layer are applied to all commands in its bundle executed by a given group. This layer can override bundle and channel layer configurations, and can be overridden by user layer.

user

Configurations made at the user layer are applied to all commands in its bundle executed by a particular user. This layer can be override any other layer.

17.2.1. Layer Overriding

For any given bundle, the same configuration can be defined in multiple layers. In this case, the layer with the highest precedence is the one that’s used.

The layer precedence order is as follows:

  1. User

  2. Group

  3. Channel

  4. Bundle

This allows you to, for example, define a default set of user credentials at the bundle level while allowing a specific group and even specific users to define their own credentials for more specialized purposes.

17.3. Managing Dynamic Configuration Values

Dynamic configurations can be managed using the gort config commands. There are three:

  1. gort config get: Used to retrieve one or more non-secret configuration values.

  2. gort config set: Used to create or update a configuration value.

  3. gort config delete: Used to delete a configuration value.

The flags accepted by each of these commands are as follows

Flags

Get

Set

Delete

Description

--bundle

R

R

R

The name of the bundle to configure.

--layer

O

O

O

One of: bundle, channel, group, user.
Default: bundle.

--owner

R

R

R

The owning channel, group, or user.

--key

R

R

R

The name of the configuration.

--secret

n/a

O

n/a

Makes a configuration value secret. Secret values
cannot be read using gort config get.

R=Required. O=Optional.

17.4. Future Steps

This feature is in a state of minimal viability, and many new features are planned for it. Including:

  1. The development of an optional secure backend. Initially this will support Hashicorp Vault.

  2. Allowing configuration value to be defined as code.

  3. Allowing configuration values to be injected as files (and not just environment variables).