Secrets in Environments
Overview
Section titled “Overview”The Secrets concept page covers how packs and components declare the credentials they need, how the runtime resolves and isolates them, and how redaction works. This page focuses on the operator side: supplying secret values to a deployed environment, choosing a backend, and scoping credentials by tenant and team.
Secret addressing
Section titled “Secret addressing”Greentic uses two URI forms for secrets. The distinction matters when you write manifests and endpoint configurations.
Store URI — the full five-segment address used internally by the secrets store:
secrets://<env>/<tenant>/<team>/<category>/<name>The category segment is typically the provider or pack identifier, such as messaging-telegram or openai. An optional @version suffix pins a specific version of the secret.
Reference form — the shorter form used in manifests and endpoint secret_refs:
secret://<env>/<tenant>/<team>/<category>/<name>The reference form converts to the store URI internally. You will encounter the secret:// form in environment manifests and messaging endpoint configurations.
Team segment normalization: the values _, empty, and default all normalize to _, meaning tenant-scoped. A secret stored at the tenant level (with _ as the team) serves all teams under that tenant unless a team-specific secret overrides it.
Fallback behavior: when the runtime looks up a secret with a specific team scope and finds nothing, it automatically retries with the tenant-level (_) URI. This lets you store a credential once at the tenant level while still allowing per-team overrides where needed.
Allowed characters: all segments use [a-z0-9-_.]. Names are normalized to lowercase with separators converted to underscores.
Environment-variable projection: a store URI can also be satisfied from a process environment variable. The derived variable name follows the pattern GREENTIC_SECRET__<ENV>__<TENANT>__<TEAM>__<CATEGORY>__<NAME>. A read-only env backend variant uses the pattern GTSEC_<ENV>_<TENANT>_<TEAM>_<CATEGORY>_<NAME>.
Supplying secrets
Section titled “Supplying secrets”There are three ways to get secret values into an environment. In all cases, the values themselves never appear in committed files.
Environment manifest
Section titled “Environment manifest”The secrets[] section of an environment manifest lists secrets by path. Each entry names the secret’s store path and optionally the environment variable to read the value from at apply time:
"secrets": [ { "path": "default/_/messaging-telegram/telegram_bot_token", "from_env": "TELEGRAM_BOT_TOKEN" }, { "path": "default/_/openai/api_key" }]When from_env is present, gtc op env apply reads the value from that environment variable at apply time. When from_env is absent, the operator is prompted for a masked interactive paste.
Interactive environment wizard
Section titled “Interactive environment wizard”Running gtc setup --env <name> walks you through each required secret. For each secret, you choose whether to supply an environment variable name or paste the value directly (input is masked).
Direct operator commands
Section titled “Direct operator commands”For ad-hoc secret management outside of manifest applies or wizard runs:
gtc op secrets listgtc op secrets put --answers secrets-payload.jsongtc op secrets get --answers query-payload.jsongtc op secrets rotate --answers rotate-payload.jsonThese commands accept payloads through the --answers flag.
Development store vs production backends
Section titled “Development store vs production backends”The development store is a plaintext, file-backed store located under the environment or bundle directory. It requires no configuration and is the default when no backend is bound to the environment. It is appropriate for local development and demos only. For production, bind a real secrets backend through the environment’s secrets capability slot.
Backends
Section titled “Backends”| Backend | Provider ID | Main config knobs | Notes |
|---|---|---|---|
| Dev store | greentic.secrets.dev-store | None | Local plaintext; default when nothing is configured |
| Env vars (read-only) | env | GTSEC_* variables | Read-only; requires GREENTIC_ALLOW_ENV_SECRETS=1 |
| AWS Secrets Manager | greentic.secrets.aws-sm | GREENTIC_AWS_KMS_KEY_ID (required), GREENTIC_AWS_REGION, GREENTIC_AWS_SECRET_PREFIX | Default prefix gtsec; names are slash paths |
| Azure Key Vault | greentic.secrets.azure-kv | Vault URL + Azure identity | 127-char name limit; names folded with hash suffix |
| GCP Secret Manager | greentic.secrets.gcp-sm | GCP project + identity | 255-char name limit; names folded with hash suffix |
| HashiCorp Vault | greentic.secrets.vault-kv | VAULT_ADDR (required); token or K8s workload identity auth | KV v2 + Transit; TLS verification cannot be disabled |
| Kubernetes Secrets | greentic.secrets.k8s | In-cluster identity | Preview — early-stage |
AWS Secrets Manager
Section titled “AWS Secrets Manager”Requires a KMS key (GREENTIC_AWS_KMS_KEY_ID). Secret names are stored as slash-separated paths under a configurable prefix: <prefix>/<env>/<tenant>/<team>/<category>/<name>, where the default prefix is gtsec. Configure the region with GREENTIC_AWS_REGION and override the prefix with GREENTIC_AWS_SECRET_PREFIX.
HashiCorp Vault
Section titled “HashiCorp Vault”Requires VAULT_ADDR. Authenticate with either a VAULT_TOKEN or Kubernetes workload identity (VAULT_K8S_ROLE, VAULT_K8S_JWT_PATH, VAULT_K8S_MOUNT). Secrets are stored as slash paths under the KV v2 mount (VAULT_KV_MOUNT, default secret) with a configurable prefix (VAULT_KV_PREFIX, default greentic). Transit encryption is available via VAULT_TRANSIT_MOUNT and VAULT_TRANSIT_KEY. Namespace isolation uses VAULT_NAMESPACE. A custom CA bundle can be set with VAULT_CA_BUNDLE, but TLS verification cannot be disabled.
Azure Key Vault and GCP Secret Manager
Section titled “Azure Key Vault and GCP Secret Manager”Both backends fold secret names to comply with their respective character restrictions. Azure Key Vault limits names to [0-9a-z-] and 127 characters. GCP Secret Manager allows [a-zA-Z0-9_-] up to 255 characters. Both append a 16-character hex hash suffix to preserve uniqueness when names are folded. The readable portion of a long name is truncated to make room for the suffix.
Binding a backend to an environment
Section titled “Binding a backend to an environment”The secrets backend for an environment is set through a JSON binding document:
{ "schema_version": "greentic.secrets.binding.v1", "provider_id": "greentic.secrets.aws-sm", "pack": "providers/secrets/aws-sm.gtpack", "config": { "namespace_prefix": "greentic", "region": "eu-north-1", "environment": "prod" }}This binding lives in the environment’s platform configuration. At the environment manifest level, the same concept is expressed as an entry in the packs[] section with "slot": "secrets":
"packs": [ { "slot": "secrets", "kind": "greentic.secrets.aws-sm@1.0.0", "pack_ref": "builtin" }]Both forms select which secrets backend the environment uses. Swapping the backend does not require redeploying application bundles — bundles reference secrets by logical name, and the runtime resolves them through whatever backend is bound.
Per-tenant and per-team secrets managers
Section titled “Per-tenant and per-team secrets managers”The runtime selects a secrets-manager pack by searching in this order:
GREENTIC_SECRETS_MANAGER_PACKenvironment variable (absolute or bundle-relative path) — unconditional override.<bundle_root>/providers/secrets/<tenant>/<team>/*.gtpack— team-specific pack.<bundle_root>/providers/secrets/<tenant>/*.gtpack— tenant-specific pack.<bundle_root>/providers/secrets/*.gtpack— bundle default.- Nothing found — falls back to the dev store.
Naming rules across backends
Section titled “Naming rules across backends”Stick to lowercase letters, digits, hyphens, and underscores in tenant, team, category, and secret name segments. This keeps names portable across all backends.
| Backend | Character set | Max length | Behavior |
|---|---|---|---|
| AWS Secrets Manager | Slash paths round-trip exactly | Liberal | Names stored as-is under the prefix |
| HashiCorp Vault | Slash paths round-trip exactly | Liberal | Names stored as-is under the KV mount |
| Azure Key Vault | [0-9a-z-] | 127 chars | Folded + hash suffix; long names truncated |
| GCP Secret Manager | [a-zA-Z0-9_-] | 255 chars | Folded + hash suffix; long names truncated |
| Kubernetes | Label-safe | Namespace-scoped | Preview |
Azure Key Vault’s 127-character limit is the tightest constraint. If you use long tenant names or deeply nested categories, the readable portion of the secret name will be truncated to make room for the uniqueness hash. Prefer short, descriptive names.
Related Pages
Section titled “Related Pages”- Secrets — declaration, runtime access, WIT interfaces, component development, redaction
- Multi-Tenancy — runtime model and
TenantCtx - Tenants & Teams in Environments — tenant onboarding, access maps, deploy-time selectors
- Cloud Deploy Environments — the admin-console managed deploy surface