Last updated 2026-09-04Development preview

Read secrets

Separate a secret resource from its value, grant read access, and handle versions and rotation in application code.


An API key is a value your backend needs but your source repository and browser should not receive. A secret resource gives that value a managed home. Your runtime asks for a version of the secret when it needs to authenticate to the external service.

Declaring the resource, allowing a runtime to read it, and supplying its value are three separate steps. A deployment can successfully create a secret resource that does not yet contain a usable version.

#Understand secret versions

A secret is the named resource. A version contains a particular value. Rotation adds or selects a newer value while your application continues referring to the same declared resource.

ReadLatest asks for the current latest version on each call. It does not push a rotated value into a variable your program already holds. ReadVersion asks for an exact version when a workflow needs stable input. Your application decides whether to read for each operation or cache the result for a bounded time.

The read grant generates both methods. The separate list grant generates ListVersions; being able to enumerate versions does not allow their values to be read.

#A missing version is not missing permission

StateConsequence
Runtime has no secret grantNo generated secret client for that runtime
Runtime has read access, but no version is availableA read can return NotFound
Runtime reads a version with an empty valueDecide whether an empty value is valid for the integration
A new version is suppliedA subsequent latest read can see it; cached bytes do not update themselves
A user calls your HTTP handlerYour handler uses the secret internally; it does not return the value to that user

How access works explains the same declaration/grant boundary with an interactive bucket example.

#Configure secret access

#Declare the secret and permission

Add a secret named api-key to fluffy-chainsaw.yaml and grant an existing API runtime read access:

yaml
secrets:
  api-key: {}
runtimes:
  api:
    uses:
      secrets:
        - name: api-key
          actions: [read]

Keep the runtime's artifact and other fields. Workspace policy selects Secret Manager for a configured GCP environment:

yaml
resourceTypes:
  secrets:
    secret-manager:
      product: gcp.secret-manager
environments:
  prod:
    secrets:
      defaults:
        type: secret-manager
        provider: application

The application provider must already specify the intended project and region. This snippet chooses the product; it does not contain the secret value.

#Supply a secret version

After deploying the resource, an authorized operator supplies a version to the exact Secret Manager resource using the provider's workflow. Keep the value out of application YAML, logs, source control, and command output that might be recorded.

Fluffy's public runtime API offers read/list access. It does not provide a method for authoring new versions. That separation lets the runtime consume a credential without also granting it permission to rotate or replace the credential.

For local development, the local secret service stores its own versions. A fresh resource may have no version. The current public CLI and local manifest do not provide a secret-value population command or field. Use a provisioned development version for successful reads; use an empty local resource to check missing-secret handling. Keep production secrets out of local fixtures.

#Read from your runtime

Generate the runtime's SDK. For an application named example-app:

fluffy-chainsaw generate --application example-app --runtime api --language typescript

Use the sidecar setup for your selected language. These examples use example-app and module example.com/app; adjust the imports to your application. TypeScript uses address and transport; Python uses channel. Go passes its connection and a deadline-bearing context to the function:

import { Metadata } from '@grpc/grpc-js'
import * as runtimev1 from './.fluffy/generated/runtimes/api/typescript/fluffy/runtime/example-app/api.js'
import * as secretsv1 from './.fluffy/generated/runtimes/api/typescript/fluffy/secrets/v1/secrets.js'

const client = new runtimev1.SecretsApiKeyClient(address, transport)
const latest = await new Promise<secretsv1.ReadLatestResponse>((resolve, reject) => {
  client.readLatest(
    secretsv1.ReadLatestRequest.fromPartial({}),
    new Metadata(),
    { deadline: Date.now() + 5000 },
    (error, value) => {
      if (error) reject(error)
      else resolve(value)
    },
  )
})
const apiKey = latest.value
if (apiKey.length === 0) throw new Error('api-key is empty')

Pass apiKey directly to the server-side integration. If your application logs an authentication failure, record the operation and safe error context, not the key. Use a deadline for the read and decide whether a temporary read failure should stop startup or fail that integration request.

#Verify rotation and failure behavior

With a development version available, confirm the integration authenticates successfully and that logs and HTTP responses omit the value. Supply a new development version, let the application's refresh policy run, and verify the integration uses it.

Also test a missing version. The application should report a controlled unavailable integration or startup failure instead of continuing with an accidental empty credential. A valid empty value and a NotFound response are different states.

#Reference: permitted operations and limits

GrantGenerated operationPurpose
readReadLatest, ReadVersionRead a latest or exact version's value
listListVersionsEnumerate version metadata

An unknown action, empty action list, unresolved secret name, or duplicate edge is rejected. There is no write or rotate runtime secret grant. Version listing uses a page limit from 1 to 100; preserve the returned cursor rather than inventing or reusing one for another resource.

#Native access

The client also includes Unwrap and Credential. Their native behavior depends on the product. In GCP, a Secret Manager native credential is the runtime service account's ordinary OAuth token, whose authority includes that identity's IAM grants; it is not necessarily limited to this one secret's read action. See Generated SDKs.

#Diagnose the failing boundary

A missing client points to the grant or generation target. NotFound can mean the secret has no available version. A cloud permission error needs the runtime identity and resource policy checked; copying a service-account key into YAML does not fix the declaration model. A downstream API rejecting the value may indicate the external credential is invalid even though the secret read itself succeeded.

Continue with Cache for values that can be recomputed, or Authentication for identifying the user behind a request.