Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/content/cre/guides/workflow/secrets/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ date: Last Modified
metadata:
description: "Secure your API keys and credentials: learn how to manage secrets safely in CRE for both simulated and deployed workflows."
datePublished: "2025-11-04"
lastModified: "2026-10-01"
lastModified: "2026-10-29"
---

import { Aside, CodeHighlightBlockMulti } from "@components"
Expand Down Expand Up @@ -90,6 +90,8 @@ apiKey := secret.Value`,

The CRE runtime automatically handles retrieving the secret from the appropriate source based on your environment.

To fetch several secrets in one call, use the batch API (`runtime.getSecrets()` in TypeScript, `runtime.GetSecrets()` in Go). Limits apply to how many secrets a batch can contain and how many fetch calls one execution can make, and they are separate from the limits on uploading secrets. See [Fetching multiple secrets](/cre/guides/workflow/secrets/using-secrets-deployed#fetching-multiple-secrets) and the [secrets quotas](/cre/service-quotas#secrets-quotas).

{/* prettier-ignore */}
<Aside type="note" title="Fetch secrets only inside trigger handlers">
When your workflow starts, the DON first runs your top-level code to register (subscribe) trigger handlers. During this trigger subscription phase, all capability calls and secret retrieval (Go: `runtime.GetSecrets()` / TS: `runtime.getSecret()`) are blocked. A `GetSecrets()` call made while registering handlers fails. Call it from inside a trigger handler instead — secrets are fetched on each execution, after the trigger fires.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ date: Last Modified
metadata:
description: "Secure your deployed workflows: learn to store and manage secrets in the Vault DON for deployed workflows running on DONs."
datePublished: "2025-11-04"
lastModified: "2026-10-26"
lastModified: "2026-10-29"
---

import { Aside, CodeHighlightBlockMulti } from "@components"
Expand Down Expand Up @@ -58,6 +58,17 @@ The workflow is similar to local development, but with a critical difference in
- **Local simulation**: Secrets read from your environment variables or `.env` file on your machine
- **Deployed workflows**: Secrets retrieved from Vault DON by the workflow

## Secrets limits

Secrets are subject to several limits that apply at different times. A value that is allowed by one can still be rejected by another:

- **Secrets stored in total:** a cap on how many secrets you can keep in the Vault for one owner.
- **Secrets per upload:** a cap on how many secrets one `cre secrets create`, `update`, or `delete` file can contain. To store more, upload several files.
- **Secrets per batch fetch:** a cap on how many secrets one `getSecrets()` / `GetSecrets()` call can request.
- **Fetch calls per execution:** a cap on how many times one workflow execution can fetch secrets. A single-secret call and a batch call each count as one.

See [Secrets quotas](/cre/service-quotas#secrets-quotas) for the current values and for the secret size limits.

## Step-by-step guide

### Step 1: Create a secrets YAML file
Expand All @@ -82,6 +93,11 @@ secretsNames:
- **Key** (e.g., `API_KEY`) — The identifier your workflow code will use
- **Value** — An array containing the environment variable name that holds the actual value

{/* prettier-ignore */}
<Aside type="note" title="Limit on secrets per file">
A single file can only contain a limited number of secrets. The CLI rejects larger files with `cannot have more than N items in a single payload; check your secrets YAML`. Split larger sets across multiple files. This limit applies to one upload only. It is separate from the limit on the total number of stored secrets and from the limit on secrets per batch fetch (see [Secrets limits](#secrets-limits) and [Secrets quotas](/cre/service-quotas#secrets-quotas)).
</Aside>

{/* prettier-ignore */}
<Aside type="caution" title="Don't commit secrets files">
Add your production secrets YAML files to `.gitignore`. Never commit them to version control.
Expand Down Expand Up @@ -234,6 +250,44 @@ Secret identifier: secret_id=DATABASE_URL, owner=<your-owner-address>, namespace
The `list` command only shows secret identifiers, never the actual secret values. Secret values are only accessible to your deployed workflows at runtime.
</Aside>

## Fetching multiple secrets

Use the batch API to fetch several secrets in one call. A batch call counts as a single fetch call against your [service quotas](/cre/service-quotas#secrets-quotas).

<CodeHighlightBlockMulti
languages={{
ts: {
code: `const secrets = runtime.getSecrets([{ id: "API_KEY" }, { id: "DATABASE_URL" }]).result()

const apiKey = secrets["API_KEY"].value
const databaseUrl = secrets["DATABASE_URL"].value`,
title: "Fetching Multiple Secrets (TypeScript)",
},
go: {
code: `secrets, err := runtime.GetSecrets([]\*protos.SecretRequest{
{Id: "API_KEY"},
{Id: "DATABASE_URL"},
}).Await()
if err != nil {
return nil, err
}

// Secrets are returned in the same order as the requests.
apiKey := secrets[0].Value
databaseUrl := secrets[1].Value`,
title: "Fetching Multiple Secrets (Go)",
},
}}
/>

{/* prettier-ignore */}
<Aside type="note" title="Secrets fetch limits">
- Each execution has a limit on the number of fetch calls. A single-secret call and a batch call each count as one, so combine fetches into batch calls.
- A batch has a limit on the number of secrets it can contain. This is separate from the limits on uploading secrets.
- Batches are all-or-nothing: if any secret in the batch fails to fetch, the call returns an error that lists every failure.
- See [Secrets quotas](/cre/service-quotas#secrets-quotas) for the values.
</Aside>

## Managing secrets lifecycle

### Updating secrets
Expand Down Expand Up @@ -321,6 +375,45 @@ For complete multi-sig setup and usage, see [Using Multi-sig Wallets](/cre/guide
1. Check that the secret ID in your code matches exactly
1. Recreate the secret if necessary: `cre secrets create ...`

### "Secret not found" but the secret exists in `cre secrets list`

**Problem:** `cre secrets list` shows the secret, but the workflow can't find it.

**Solution:**
`cre secrets create`, `update`, and `delete` always use the `"main"` namespace, and `GetSecret` / `getSecret` default to `"main"` when you don't pass one. If your workflow code requests a different namespace (for example `"default"`), the lookup fails with an error such as `vault error for secret default/API_KEY: key does not exist`. Remove the `Namespace` field or set it to `"main"`.

### "request batch size exceeds maximum"

**Problem:** A batch fetch, or a `cre secrets` request, contains more secrets than a single request allows.

**Solution:**
Split the request into smaller batches. For `cre secrets create`, `update`, and `delete`, split the YAML file. The CLI reports this as `cannot have more than N items in a single payload; check your secrets YAML`. A workflow that fetches too many secrets in one batch gets `request batch size exceeds maximum of N: VaultRequestBatchSizeLimit limited: ...`. See `VaultRequestBatchSizeLimit` in [Secrets quotas](/cre/service-quotas#secrets-quotas) for the value.

### One missing secret fails the whole batch

**Problem:** A batch fetch fails, even though most of the secrets in it exist.

**Solution:**
Batches are all-or-nothing. If any secret in the batch doesn't exist (or isn't in the namespace you requested), the whole call fails, and the error names the secret, for example `vault error for secret main/MISSING_KEY: key does not exist`. Check that every ID in the batch appears in `cre secrets list`.

### Secrets fetch call limit exceeded

**Problem:** A workflow execution fails when it fetches secrets, and it makes many separate fetch calls.

**Solution:**
Each execution has a limit on secret fetch calls (`PerWorkflow.Secrets.CallLimit`, see [Secrets quotas](/cre/service-quotas#secrets-quotas)), and a batch call counts as one. Combine your fetches into batch calls. See [Fetching multiple secrets](#fetching-multiple-secrets).

In a regular workflow, the call that goes over the limit fails with `PerWorkflow.Secrets.CallLimit limited for workflow[...]: cannot use N, limit is M`.

In a Confidential Workflow, the same limit currently surfaces as `relay quorum unreachable: 0 signed responses, ...` instead of naming the limit. If you see that error and your workflow makes several fetch calls in one execution, reduce the number of fetch calls first.

### Secrets errors end with "Verify the secret name is correct..."

**Problem:** A secrets error ends with `Verify the secret name is correct and that the secret has been configured for this workflow` (or `Verify the host response is complete...`), but the secret name is fine.

**Solution:**
Those closing hints are generic and are added to every secrets error. The text before them names the actual cause, such as a limit being exceeded or a key that doesn't exist. Read that part of the message first.

### "Timeout expired" error

**Problem:** The CLI returns a timeout error when creating/updating secrets.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pageId: "guides-workflow-confidential-workflows-making-workflow-confidential"
metadata:
description: "Run workflow logic inside a secure enclave in Go: register a TEE handler, fetch secrets dynamically, and cross back to the DON for consensus."
datePublished: "2026-07-21"
lastModified: "2026-07-28"
lastModified: "2026-10-29"
---

import { Aside } from "@components"
Expand Down Expand Up @@ -108,6 +108,11 @@ if err != nil {
[`GetSecret()`](/cre/reference/sdk/confidential-workflows-client-go#runtimegetsecret) runs.
</Aside>

<Aside type="note" title="Secrets fetch limits">
Secret fetches from inside the enclave count against the same limits as fetches from a regular workflow, including the
limit on fetch calls per execution. See [Service Quotas](/cre/service-quotas#secrets-quotas).
</Aside>

### Step 3: Make a capability call from inside the enclave

Capabilities that support Confidential Workflows expose a TEE-flavored method. For the HTTP capability, that's
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pageId: "guides-workflow-confidential-workflows-making-workflow-confidential"
metadata:
description: "Run workflow logic inside a secure enclave in TypeScript: register a TEE handler, fetch secrets dynamically, and cross back to the DON for consensus."
datePublished: "2026-07-21"
lastModified: "2026-07-28"
lastModified: "2026-10-29"
---

import { Aside } from "@components"
Expand Down Expand Up @@ -84,6 +84,11 @@ const secret = runtime.getSecret({ id: "MY_API_KEY" }).result()
[`getSecret()`](/cre/reference/sdk/confidential-workflows-client-ts#runtimegetsecret) runs.
</Aside>

<Aside type="note" title="Secrets fetch limits">
Secret fetches from inside the enclave count against the same limits as fetches from a regular workflow, including the
limit on fetch calls per execution. See [Service Quotas](/cre/service-quotas#secrets-quotas).
</Aside>

### Step 3: Make a capability call from inside the enclave

Capabilities that support Confidential Workflows expose a `TeeRuntime`-accepting overload of their regular method.
Expand Down
Loading
Loading