Managing Secrets

Configuration guide for the MetaRouter secret store, an encrypted key-value store for
sensitive values like API credentials, access tokens, and cloud storage keys.

Managing secrets is done through the Control CLI only. There is no in-app UI for secrets at this time. See
CLI tools for installing and configuring the CLI.


How It Works

  1. Store a secret once, by ID, through the control CLI.
  2. Reference it from a configuration with a secret_ref (the secret's ID) plus
    $$secret.KEY$$ placeholders. Placeholders resolve to real values at runtime. The
    plaintext secret is never stored in the configuration.

Roles and Permissions

Secret operations require a role that carries the matching permission. create:secret covers
create, clone, and dangerous update. read:secret covers get. delete:secret covers delete.

Rolecreate:secretread:secretdelete:secret
Deployment Manageryesyesno
Integration Manageryesyesno
Adminyesyesno
🚧

Deletes are not currently available

Contact your MetaRouter dedicated support team if you need a secret deleted.


The Secret Object

  • A secret is a flat map of string keys to string values, plus identifying metadata. The id
    is what configurations point at via secret_ref.
  • Values are write-only by default. Storing a secret never echoes values back. Reading
    them requires a separate, tightly scoped permission.
FieldRequiredNotes
idyesUnique identifier. Used as the secret_ref from configurations.
descriptionyesFree-text purpose of the secret.
valuesyesMap of secret key-value pairs. Must contain at least one entry.
authornoSet automatically by the CLI. Leave it out of your file.
created_atnoStamped server-side on create. Read-only.

CLI Configuration

Create

  • Write the secret to a YAML or JSON file, then create it. The file is parsed strictly and
    unknown fields are rejected.
  • Create is collision-safe. Creating a secret whose id already exists fails. This is a
    guardrail against silently overwriting a live secret. Overwriting is always explicit.
control create secret -f <secret.yaml>   # create a new secret from a file
control create secret --example          # print the annotated example config
id: replay-source
description: AWS creds for replay bucket
values:
  AWS_ACCESS_KEY: value
  AWS_SECRET_KEY: value

Clone

  • Create a new secret from an existing one, optionally dropping or overriding keys. Merge
    order: start from the source's values, apply --remove-values, then apply the values in
    -f (file values win on conflict). The result must contain at least one value.
  • An interactive run shows a masked diff and prompts before writing.
  • --clone-from and --dangerously-update-secret cannot be combined.
control create secret -f <new-secret.yaml> --clone-from <source-id>                          # copy, then merge file values
control create secret -f <new-secret.yaml> --clone-from <source-id> --remove-values k1,k2   # copy, dropping keys

Get and Delete

  • get returns plaintext. There is no masking on this path. It requires the
    read:secret permission. Keep that permission tightly scoped.
  • Deletion is permanent and prompts for confirmation in an interactive terminal. Deleting a
    non-existent ID succeeds without error (idempotent).
  • Deletion requires delete:secret, which no role currently includes. See
    Roles and Permissions.
control get secret <id>      # returns values in plaintext, requires read:secret permission
control delete secret <id>   # permanent, prompts for confirmation

Update (dangerous)

  • To intentionally overwrite an existing secret, pass --dangerously-update-secret. An
    interactive run prints a diff with all values masked as ****** (modified keys are flagged)
    and prompts for confirmation before writing.
❗️

Prefer clone over in-place update

A dangerous update overwrites the live secret immediately. Secrets have no staged or
draft state, so anything referencing it through secret_ref, including configurations
actively serving traffic, resolves against the new values on its next resolution. The safer
path is to clone to a new ID, then point your configuration's secret_ref at the
new secret.

control create secret -f <secret.yaml> --dangerously-update-secret

Referencing Secrets in Configuration

  • Credentials are never inline. A configuration sets secret_ref to the ID of the secret
    to resolve against, and puts $$secret.KEY$$ placeholders in its string fields, where KEY
    is a key in that secret's values map.
  • Placeholders work in any string field of a configuration that supports a secret_ref,
    including nested fields, map values, and endpoint URLs.
id: replay-test
sourceConfig:
  source:
    s3:
      region: us-east-1
      bucket: mr-test-replay-us-east-1
      # here are the $$ variable references
      credentials:
        accessKey: $$secret.AWS_ACCESS_KEY$$
        secretKey: $$secret.AWS_SECRET_KEY$$
    # here is the secert id
    secretRef: replay-source
  globPattern: replay-test/**.json.gz
  scopes:
    writeKeys:
      - retl_replay
    events:
      - identify
      - page
      - order_completed

Resolution Rules

Resolution is all-or-nothing per configuration:

Configuration stateResult
$$secret.KEY$$ references but empty secret_refFails. secret_ref is required.
A referenced KEY missing from the secretFails with secret key "KEY" not found in secret "<secret_ref>".

When Resolution Happens

  • On create or update, the configuration is validated: secret_ref must point at an
    existing secret, and that secret must contain every $$secret.KEY$$ key the configuration
    references. A gap is rejected with a fix hint. Resolved values are never persisted into the
    stored configuration.
  • At runtime, placeholders resolve into the running configuration just before use. Runtime
    views that return resolved configurations expose plaintext and are gated behind elevated
    permissions.

FAQs

Can I list all secrets?
No. Secrets are fetched individually by ID with control get secret <id>, which requires the
read:secret permission.

How do I rotate a credential?
Prefer cloning to a new ID and re-pointing the configuration's secret_ref. Overwriting in
place with --dangerously-update-secret also works, but it changes what every referencing
configuration resolves to on its next resolution. Both paths show a masked diff before
writing.

What happens if a configuration references a key the secret doesn't have?
Validation fails on create or update with secret key "KEY" not found in secret "<secret_ref>". Resolution is all-or-nothing. A configuration never runs with a partially
resolved value.

Can one secret be shared by multiple configurations?
Yes. Any number of configurations can set the same secret_ref. Remember that an in-place
update changes what all of them resolve to on their next resolution.

Can I update just one key in a secret?
Yes, with clone. --clone-from starts from the source's values and merges your file's values
over them. A file containing only the changed key produces a full copy with that one key
replaced. To change it in place instead, pass the full desired state with
--dangerously-update-secret.