VI Shipping

Supply Secrets

The database has a password and the email service an API key. Neither may be written in the Context, which is in version control. The Context only names secrets; you supply their values yourself, once per environment: in the cluster for a deployment, in the .env file for a local run.

§What is a secret

Credentials of infrastructure. An address in the Context must not contain a user name or a password. One that does is refused:

Pointer URI 'mongodb://user:pass@mongo.example.com' must not contain credentials.

They are supplied as a secret with username and password keys.

Secret configuration values. A configuration value written as $NAME is a reference to a secret, not a value. The Context toa create wrote has one, the key of identity tokens; a component that sends email adds its API key:

# context.toa.yaml
configuration:
  identity.tokens:
    keys:
      - id: key0
        key: $IDENTITY_TOKENS_ENCRYPTION_KEY0
  notifications:
    sender: orders@example.com
    apiKey: $EMAIL_API_KEY

Configuration covers this in full, with the component that declares such a value. Other extensions have secrets of their own, such as a storage provider’s keys or the keys of identity tokens.

You do not work out the list. Ask for it.

§What a deployment needs

$ npx toa export secrets production
toa-amqp-context.default:
  username
  password
toa-configuration:
  EMAIL_API_KEY
  IDENTITY_TOKENS_ENCRYPTION_KEY0
toa-mongodb.default:
  username
  password
toa-storages-pictures:
  ACCESS_KEY_ID (optional)
  SECRET_ACCESS_KEY (optional)

Each block is one Kubernetes secret and the keys it must hold. A key marked (optional) may be absent; the workload starts without it.

Run the command again after changing addresses, configuration or storages in the Context.

§Putting secrets in the cluster

$ npx toa conceal mongodb.default username=store password=s3cret

toa conceal <secret> <key=value>... creates the secret, or adds the keys to it if it exists. Keys you do not mention are left as they are.

  • The name is given without the toa- prefix; toa conceal adds it.
  • --namespace chooses the Kubernetes namespace. Use the one you deploy into.

To be asked for every secret of an environment in turn, instead of naming them:

$ npx toa conceal --interactive --environment production

To read one back:

$ npx toa reveal mongodb.default
username: store
password: s3cret

Secrets can be created by other means: kubectl, an operator, a sealed-secrets workflow. They then carry the toa- prefix themselves, exactly as toa export secrets prints the names.

§A deploy checks first

toa deploy refuses before building anything if a required key is missing, naming all of them:

Secrets are not deployed: toa-mongodb.default/username, toa-mongodb.default/password

Required are the keys toa export secrets lists, except the optional ones, plus the image pull secret named by registry.credentials. Only presence is checked. An empty value counts as present, and a wrong password is found by the process that uses it.

§Changing a value

Changing a secret does not restart anything. Pods read their secrets when they start, so restart the workloads that use it:

$ npx toa conceal mongodb.default password=n3w -n store
$ kubectl rollout restart deployment/composition-core -n store

§Secrets for a local run

Locally, secrets are lines of the .env file. toa env writes them with empty values and offers two ways to fill them:

$ npx toa env local --dev           # fill what has a known local default
$ npx toa env local --interactive   # ask for each one
$ npx toa env local -d -i           # fill what can be filled, ask for the rest

npm run env, and so npm run restart, runs the first. --dev fills:

  • developer / secret as the credentials of the default broker and database, which is what the generated docker-compose.yaml gives the ones npm run dock starts;
  • freshly generated keys for identity tokens;
  • any secret whose key is set in your shell’s environment. With EMAIL_API_KEY=... toa env -d, the $EMAIL_API_KEY configuration secret takes that value.

Whatever is left is written empty. A component should treat an empty secret as “not configured” where that is meaningful locally — for example, by not sending real email.

A value already in the file is kept. Fill a secret in by hand once, and later runs of toa env, with any options and for any environment written to the same file, preserve it.

Keep .env* out of version control.

Do not read these variables from process.env in an operation. A secret reaches an operation through what declares it: a configuration value through context.configuration, a storage’s keys through the storage. The other lines of .env are written by toa env for the runtime; change the Context and run toa env again instead of editing them.

§Credentials

The address of the database is an ordinary Context value (Addresses); its user name and password are a secret. Which secret follows from the key of the address map the component resolves to: the connector’s name, then the key, with dots turned into dashes. The . key is .default:

Key in mongodbSecret
., or a single addresstoa-mongodb.default
storetoa-mongodb-store
store.catalogtoa-mongodb-store-catalog
$ npx toa conceal mongodb-store-catalog username=catalog password=s3cret

Every component that resolves to a key shares its secret, and so does every address under that key.

For the broker the name is amqp-context, so the default secret is toa-amqp-context.default, and a source’s is toa-amqp-sources-<source>.

Each such secret holds username and password. An address on a protocol without credentials — redis, http, https — has no secret.

toa export secrets prints the exact names; the rule is here so that the output is not a surprise. Addresses and Credentials has more.

§The same names in every environment

Addresses vary by environment with the usual suffix:

mongodb@local: mongodb://localhost
mongodb@production: mongodb://mongo.internal.example.com

Secret names do not vary: toa-mongodb.default is the same name everywhere. The values differ because each environment is a different namespace or cluster, or a different .env file, holding its own.

A deployed pod is given only the secrets and addresses of the components it runs. The database password of store.catalog is not in a pod that does not run store.catalog.

§Checklist for a new environment

  1. Add the environment’s suffixed keys to the Context.
  2. toa export secrets <environment> — see what it needs.
  3. toa conceal ... for each secret, in the target namespace.
  4. Create the image pull secret, if the registry is private.
  5. toa deploy <environment>.
Search
Search the documentation