Skip to content

How to Add Vault Secrets with obs

Your app's secrets (API keys, passwords, connection strings, certificates) are stored in HashiCorp Vault at vault.rit.services. You don't work in Vault directly: you request secrets through the observability platform, obs (obs.rit.services), and obs sets everything up in Vault for you.

Every change to a secret needs approval. A change only runs once key holders approve it with their Vault unseal keys: 3 keys in total, from at least 2 different people. No single person, including whoever made the request, can change, read or delete a secret alone.

Who What they do
You (the person who needs the secret) Request a new secret, a change, a deletion, or to see the current values
Key holders (currently Hammad, Matthias and Sven) Approve or reject requests with their unseal keys

Info

This is not the same as Vaultwarden, our password manager for personal logins. Vault (this guide) holds the secrets your apps use when they run in Kubernetes.

Before you start

  • You need an obs account with operator access to your app's namespace. Without it you won't see the Vault secrets card described below. Ask a platform administrator to give you access.
  • Your app should already be deployed, or about to be, through ArgoCD. See How to Setup ArgoCD with your project.

1. Request a new secret

  1. Sign in to obs.rit.services.
  2. Open your namespace:
    • Namespace users: click My Namespaces in the sidebar, then your namespace.
    • Administrators: click Clusters, then the cluster, then Namespaces, then the namespace.
  3. Find the Vault secrets card and click Add secret.
  4. Fill in the form:
    • Secret name: lowercase letters, numbers and hyphens, e.g. orderservice. The secret is stored in Vault at secret/<namespace>/<name>. You can't rename it later.
    • How your app gets the secret: pick one.
      • Vault Secrets Operator (recommended, and what most of our projects use). The secret becomes a normal Kubernetes Secret, which your app reads as environment variables. No code changes are needed.
      • Agent Injector (file). The secret is written as files inside your pod. Use this for config files, certificates or keys your app reads from disk.
    • Secret data: one row per value. The key is the variable name your app reads, e.g. DATABASE_URL, and the value is the secret itself. Use Agent Injector if you need to upload files instead.
    • Advanced (optional): leave it closed unless you know you need it. By default obs names the ServiceAccount <name>-vault, names the Kubernetes Secret <name>-secret, re-reads the secret every 30s, and gives your app read-only access.
  5. Click Request approval.

You'll see Sent to the key holders. The key holders are emailed straight away. The request expires after 24 hours if it isn't approved; if that happens, simply request it again.

Warning

Never paste secrets into Slack, email or tickets to "help" the key holders. They don't need to see your values to approve: they only approve that the change may run.

2. Wait for approval

Follow your request in Vault approvals (sidebar) → My requests.

Status Meaning
Waiting for approvals No key holder has approved yet.
Collecting keys Some keys are in; more are needed.
Done Approved and carried out. You're also emailed.
Rejected A key holder rejected it; the reason is shown on the request.
Expired Not approved within 24 hours. Request it again.
Failed Approved, but Vault reported an error. The error is shown on the request.

You can withdraw a request that's still waiting with Cancel request.

Tip

If it's urgent, let a key holder know a request is waiting. Two of them need to approve it.

3. Connect your app to the secret

Once the request is Done, the secret appears on your namespace's Vault secrets card.

  1. Click View guide next to the secret.
  2. Copy the manifests it shows into your project's Kubernetes folder (usually k8s/), and commit them:
    • Vault Secrets Operator: the manifests (a ServiceAccount, VaultConnection, VaultAuth and VaultStaticSecret) plus a short envFrom snippet to add to your Deployment. Your app then sees every key as an environment variable.
    • Agent Injector: the annotations to add to your pod template. Your app then finds the files at the path shown.
  3. ArgoCD deploys the change as usual.

You only need to do this once per secret. Later changes to the values reach your app automatically. With the Vault Secrets Operator, the Kubernetes Secret is updated within the refresh interval (30 seconds by default). Restart your pods if your app only reads its environment at startup.

Change a secret

  1. On the Vault secrets card, click the pencil icon next to the secret.
  2. Enter the values and click Request approval.

An approved change replaces the whole secret

The form starts empty, because obs can't read the current values without approval. Enter the complete set of keys and values, including the ones that aren't changing. Any key you leave out is deleted when the change is approved.

If you don't have the current values, request to see them first (next section), then request the change.

See the current values

  1. On the Vault secrets card, click the eye icon next to the secret, then Request reveal.
  2. Once it's approved, open Vault approvals → My requests, and click View values on the request.
  3. Click Show values once and copy what you need.

Warning

The values can be viewed once, within 15 minutes of approval. After you close the window they're gone from obs. If you miss it, request again.

Delete a secret

Click the bin icon next to the secret, then Request deletion. Once it's approved, the secret, its access policy and its Kubernetes login role are removed from Vault for good.

Danger

Remove the secret from your app's manifests first. Any workload still using it will fail to authenticate on its next sync.

For key holders: approving requests

You're emailed when a request needs approval.

  1. Open Vault approvals → Awaiting approval.
  2. Check what's being asked: who asked, which namespace and secret, and whether it's a create, change, reveal or delete. If you didn't expect it, ask the requester before approving.
  3. Click Approve with my keys, then either:
    • tick your saved keys and enter your obs passphrase for them, or
    • paste a key from your password manager.
  4. Click Approve with N keys (it shows how many you picked).

How the keys add up:

  • A request needs 3 keys from at least 2 different people, so one person can't approve a request alone, even with 2 keys.
  • You can give several of your keys in one go. The dialog shows how many more are needed and how many you can add.
  • The requester can contribute their own keys too, if they're a key holder.
  • Vault collects keys for one request at a time. Others wait until it finishes or is cancelled, so don't leave a half-approved request sitting.

To refuse a request, click Reject and give a reason. The requester sees it.

Setting up your keys (once): in Vault approvals → My keys, enroll each of your unseal keys separately. Keep "Save it so I can pick it when approving" ticked to approve with a passphrase instead of pasting the key each time. The passphrase is at least 12 characters and never leaves your browser. An administrator must first mark you as a key holder in Admin → Vault.

Troubleshooting

Problem What to do
I don't see a Vault secrets card on my namespace You don't have operator access to that namespace. Ask a platform administrator.
The card says Vault isn't connected yet Ask a platform administrator to connect Vault in Admin → Vault.
The button says Create secret, not Request approval Key-holder approval is switched off, so changes run straight away. Ask a platform administrator if that's expected.
My request Expired Nobody approved it within 24 hours. Request it again and let a key holder know.
A key holder sees You are not a Vault key holder An administrator must mark them as a key holder in Admin → Vault.
A key is refused when approving Only keys enrolled under your account in My keys are accepted. Enroll it first.
My app doesn't see a changed value With the Vault Secrets Operator, wait for the refresh interval, then restart the pods if the app reads its environment only at startup.