跳转到内容

Secrets

Greentic treats secrets as runtime data, not pack data. Packs and components declare the credentials they need, but secret values are supplied during setup and resolved through a configured secrets backend at runtime.

This separation matters because the same digital worker can run for many tenants and teams. Each tenant can use the same application pack while receiving different Slack tokens, OpenAI keys, webhook signing secrets, OAuth client credentials, database credentials, or API keys.

The model has four parts:

LayerResponsibility
Component or packDeclares required secret keys, formats, descriptions, and optional scope hints.
gtc setup / greentic-secretsCollects, validates, imports, and writes secret values.
Secrets backend or extensionStores and resolves secret material.
Runtime hostEnforces tenant scope, capability grants, redaction, and audit/telemetry metadata.

Components and packs declare secret requirements using the canonical Greentic secret types from greentic-types and greentic-interfaces.

The current shared shape is:

pub struct SecretRequirement {
pub key: SecretKey,
pub required: bool,
pub description: Option<String>,
pub scope: Option<SecretScope>,
pub format: Option<SecretFormat>,
pub schema: Option<serde_json::Value>,
pub examples: Vec<String>,
}

The matching WIT package is greentic:secrets-types@1.0.0. Its secret-requirement record contains the logical key, whether it is required, an optional operator-facing description, optional environment/tenant/team scope, optional format, optional schema, and examples.

Secret keys are validated. They must be non-empty, use only ASCII letters, digits, ., _, -, and /, must not start with /, and must not contain a .. path segment.

Example component manifest excerpt:

{
"secret_requirements": [
{
"key": "openai/api_key",
"required": true,
"description": "API key used by the research analyst component",
"scope": {
"env": "prod",
"tenant": "acme",
"team": "research"
},
"format": "text"
}
],
"capabilities": {
"host": {
"secrets": {
"required": [
{
"key": "openai/api_key",
"required": true,
"format": "text"
}
]
}
}
}
}

Greentic component tooling writes secret_requirements and mirrors the same requirements into capabilities.host.secrets.required. The runtime uses those declarations to deny undeclared secret access.

Secrets are accessed through the secrets host capability. They are not injected into JSON operation payloads and should not be templated into flow definitions.

The current WIT host surfaces are:

InterfacePurpose
greentic:secrets-store@1.0.0Read-only get(key) interface.
greentic:secrets-store@1.1.0Read/write interface with get(key) and put(key, value).
greentic:secrets-types@1.0.0Shared metadata types for secret requirements, scopes, and formats.

The component receives a tenant-aware invocation context from the host. The host combines that context with the declared requirement and the configured backend. A component should ask for a logical key such as openai/api_key; it should not build raw vault paths or encode tenant ids into ad hoc strings.

Secret resolution is scoped by TenantCtx. The canonical scope is:

env + tenant + optional team + logical key

Setup flows and demos use tenant-aware secret URIs such as:

secrets://{env}/{tenant}/{team}/{provider}/{key}

Examples:

secrets://prod/acme/_/slack/bot_token
secrets://prod/acme/research/openai/api_key
secrets://dev/demo/_/telegram/bot_token

The _ segment is commonly used when no team is selected. The important rule is that tenant and team are part of the lookup boundary. A secret for tenant acme must not satisfy a request for tenant globex, even when both tenants use the same app pack and the same logical key.

For platform-level services, use a clearly separate scope and key namespace. For example, repo infrastructure can use paths such as:

repo/{env}/{tenant}/{team_or_underscore}/signing/build
repo/{env}/{tenant}/{team_or_underscore}/http/runner/bearer

That keeps platform credentials distinct from application and messaging credentials.

Greentic configuration stores only the backend selector and reference:

[secrets]
kind = "none"
reference = "..."

The default kind is none, which is appropriate only when the active workload has no runtime secret needs. Production deployments should use a real secrets manager through the runtime, deployer, or a secrets extension pack.

Common backend choices include:

Backend styleTypical use
Local/dev storeFast local demos, tests, and isolated development.
greentic-secrets broker/storeGreentic-managed setup/import flow and tenant-aware secret writing.
AWS Secrets ManagerAWS deployments and AWS-native credential policy.
Azure Key VaultAzure deployments and Azure-native identity/policy.
Google Secret ManagerGoogle Cloud deployments and GCP-native IAM.
HashiCorp VaultSelf-managed or cross-cloud vault operations.
Kubernetes or container secretsRuntime injection for custom deployers where the deployer maps Greentic requirements into cluster/container-native secrets.

The bundle wizard catalog currently includes AWS Secrets Manager entries for Greentic secrets extension packs. Other managers should be wired through the same extension/backend pattern: the pack advertises the capability and setup requirements, while the deployment/runtime chooses the actual backend implementation.

Use setup tooling to populate secrets instead of editing files by hand.

Terminal window
gtc setup --bundle ./bundle

gtc setup detects the bundle tenant from tenants/, asks for required credentials, writes values into the configured secrets store, and validates required capabilities across the bundle.

For lower-level secret workflows, use greentic-secrets:

Terminal window
greentic-secrets scaffold --pack ./my-pack.gtpack --out ./secrets.answers.json
greentic-secrets wizard --input ./secrets.answers.json --output ./secrets.filled.json
greentic-secrets apply --file ./secrets.filled.json

Useful greentic-secrets commands include:

CommandPurpose
greentic-secrets scaffoldCreate an answer document from pack secret requirements.
greentic-secrets wizardFill or import secret answers, including from .env for local workflows.
greentic-secrets applyWrite filled answers into the selected store/broker.
greentic-secrets initScaffold and apply secrets for a pack in one flow.
greentic-secrets config showInspect the effective secrets configuration.
greentic-secrets config explainExplain where the CLI is reading its configuration from.

When creating a component, use the wizard or CLI flags to declare secret requirements:

Terminal window
greentic-component wizard apply --mode create \
--answers ./component-create-answers.json

For local testing, greentic-component test can load declared secrets from:

Terminal window
greentic-component test ./component.wasm \
--secrets ./secrets.env

It also supports JSON maps and repeated inline values:

Terminal window
greentic-component test ./component.wasm \
--secrets-json ./secrets.json \
--secret openai/api_key=sk-local-test

The local harness denies access to secrets that are not declared in the component manifest. That behavior is intentional: it catches missing capability declarations before the component reaches a shared runtime.

Secret rotation should be handled by updating the backend value and rerunning setup or deployment validation. gtc setup is idempotent: rerunning it can overwrite existing values in place and rerun provider-specific setup flows.

For operations, prefer fail-fast checks. Selected packs should aggregate their secret_requirements before execution and report missing secrets with a remediation path, such as:

Terminal window
greentic-secrets init --pack ./my-pack.gtpack

Secret operations should be observable without exposing secret values. Telemetry may record metadata such as:

AttributeMeaning
secrets.opget, put, delete, or list.
secrets.keyLogical secret key. Never the value.
secrets.scope.envEnvironment scope.
secrets.scope.tenantTenant scope.
secrets.scope.teamOptional team scope.
secrets.resultok, not_found, denied, invalid, or error.

Logs, traces, and inspector output must redact values with names such as secret, token, api_key, authorization, password, client_secret, access_token, refresh_token, bearer, and x-api-key.

Secrets-related events should carry metadata only. Events such as greentic.secrets.put, greentic.secrets.delete, greentic.secrets.rotate.requested, greentic.secrets.rotate.completed, and greentic.secrets.missing.detected must never include secret bytes, even if encoded.

  • Declare every required credential as a SecretRequirement.
  • Keep secret values out of packs, bundles, flows, cards, source code, and committed setup answers.
  • Choose a real backend for production instead of kind = "none".
  • Scope secrets by environment, tenant, and team.
  • Use gtc setup or greentic-secrets to populate values.
  • Validate missing secrets before starting runtime traffic.
  • Configure redaction before exporting logs or traces.
  • Rotate backend values and rerun setup/deployment validation after rotation.