Keep the personal half of the desktop in one place, and ask before installing it
Agent instructions, skills, SSH host aliases and expansion triggers are worth having identical on every machine one person owns, and belong in none of the shared configuration. They live in user/ now, with a manifest saying where each piece goes and a link-user stage that puts it there. That stage does nothing unless the machine said yes. Somebody who clones Panama to try the desktop keeps their own ~/.claude/CLAUDE.md exactly where it was; the question names the destinations and defaults to no. Anything displaced goes to config/old rather than being deleted. ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md were byte-identical copies of one file, which is the drift this exists to prevent. Also adds the vitals toggles for the battery and Claude usage readouts, which had preferences and no way to reach them.
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: infisical-agent
|
||||
description: "Guide for configuring the Infisical Agent — a client daemon that manages token lifecycle and renders secrets via Go templates without modifying application code. Covers the full YAML config format, all 6 auth methods (Universal Auth, Kubernetes, AWS IAM, Azure, GCP ID Token, GCP IAM), sinks, template functions (listSecrets, listSecretsByProjectSlug, getSecretByName, dynamicSecret), polling, on-change commands, and caching. Use this skill when someone asks about: Infisical Agent, agent config file, agent templates, rendering secrets to files, sidecar secret injection, token renewal, infisical agent command, or 'how do I use the Infisical Agent to inject secrets'."
|
||||
---
|
||||
|
||||
# Infisical Agent Guide
|
||||
|
||||
You are a setup assistant helping users configure the Infisical Agent — a client daemon that simplifies secret management by automatically authenticating, renewing tokens, and rendering secrets to files via Go templates.
|
||||
|
||||
## How to use this skill
|
||||
|
||||
Start by understanding the user's deployment context, then guide them through:
|
||||
|
||||
1. **Auth method** — Which authentication method fits their platform
|
||||
2. **Config file** — The YAML config structure with auth, sinks, and templates
|
||||
3. **Templates** — Go template syntax with the correct template functions
|
||||
4. **Deployment** — Running the agent in their environment (Docker, K8s, ECS, etc.)
|
||||
|
||||
Read the relevant reference file(s), then walk them through building their config file step by step.
|
||||
|
||||
## Reference files
|
||||
|
||||
| File | When to read |
|
||||
|------|-------------|
|
||||
| `references/agent-config.md` | User needs the full config file format, field reference, auth methods, sinks, or caching |
|
||||
| `references/template-functions.md` | User needs to write templates — all available functions with signatures, parameters, and examples |
|
||||
| `references/deployment-examples.md` | User needs example configs for specific platforms (Docker Compose, ECS, Kubernetes, basic) |
|
||||
|
||||
## Guiding principles
|
||||
|
||||
- **Platform-native auth first.** On AWS, recommend `aws-iam`. On Kubernetes, recommend `kubernetes`. On Azure, recommend `azure`. Only fall back to `universal-auth` (client ID/secret) when platform-native auth isn't available.
|
||||
- **Templates over sinks for secrets.** Sinks deposit access tokens. Templates render actual secrets. Most users want templates, not raw access tokens.
|
||||
- **Use `listSecrets` or `listSecretsByProjectSlug` for .env files.** These are the most common template functions — they render all secrets in an environment to a key=value file.
|
||||
- **Use `dynamicSecret` for database credentials.** This function creates and auto-renews dynamic secret leases directly in templates.
|
||||
- **Polling interval matters.** Default is 5 minutes. For latency-sensitive apps, reduce it. For stable configs, increase it to reduce API calls.
|
||||
- **`exit-after-auth: true` for init containers.** In Kubernetes init containers or one-shot setups, set this so the agent renders secrets once and exits.
|
||||
- **On-change commands for reloads.** Use `execute.command` to trigger application restarts or config reloads when secrets change.
|
||||
- **Never log secret values.** The agent writes to files — ensure the destination paths have correct permissions and aren't exposed.
|
||||
@@ -0,0 +1,159 @@
|
||||
# Infisical Agent Configuration Reference
|
||||
|
||||
## Running the Agent
|
||||
|
||||
```bash
|
||||
infisical agent --config /path/to/agent-config.yaml
|
||||
```
|
||||
|
||||
Requires the Infisical CLI to be installed first.
|
||||
|
||||
## Full Config File Structure
|
||||
|
||||
```yaml
|
||||
infisical:
|
||||
address: "https://app.infisical.com" # Infisical instance URL
|
||||
exit-after-auth: false # Exit after first auth + render
|
||||
revoke-credentials-on-shutdown: false # Revoke leases/tokens on shutdown
|
||||
retry-strategy:
|
||||
max-retries: 3 # Max retry attempts
|
||||
max-delay: "5s" # Max delay between retries
|
||||
base-delay: "200ms" # Base delay (exponential backoff)
|
||||
|
||||
auth:
|
||||
type: "<auth-method>" # See Auth Methods below
|
||||
config:
|
||||
# Auth-method-specific fields
|
||||
|
||||
sinks: # Where access tokens are deposited
|
||||
- type: "file"
|
||||
config:
|
||||
path: "/path/to/access-token"
|
||||
|
||||
cache: # Optional persistent caching
|
||||
persistent:
|
||||
type: "kubernetes"
|
||||
path: "/home/infisical/cache"
|
||||
service-account-token-path: "/var/run/secrets/kubernetes.io/serviceaccount/token"
|
||||
|
||||
templates: # Secret rendering templates
|
||||
- source-path: "/path/to/template.tpl" # File-based template
|
||||
# OR
|
||||
template-content: | # Inline template
|
||||
{{- with listSecrets "project-id" "env" "/" }}
|
||||
{{- range . }}
|
||||
{{ .Key }}={{ .Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
destination-path: "/path/to/output/.env"
|
||||
config:
|
||||
polling-interval: "5m" # How often to check for changes
|
||||
execute:
|
||||
command: "./reload-app.sh" # Run on secret change
|
||||
timeout: 30 # Command timeout in seconds
|
||||
```
|
||||
|
||||
## Auth Methods
|
||||
|
||||
### Universal Auth (fallback for any environment)
|
||||
```yaml
|
||||
auth:
|
||||
type: "universal-auth"
|
||||
config:
|
||||
client-id: "./client-id" # Path to file containing client ID
|
||||
client-secret: "./client-secret" # Path to file containing client secret
|
||||
remove_client_secret_on_read: false # Delete secret file after reading
|
||||
```
|
||||
|
||||
### Kubernetes (recommended on K8s)
|
||||
```yaml
|
||||
auth:
|
||||
type: "kubernetes"
|
||||
config:
|
||||
identity-id: "./identity-id" # Path to file with machine identity ID
|
||||
service-account-token: "/var/run/secrets/kubernetes.io/serviceaccount/token" # Optional
|
||||
```
|
||||
|
||||
### AWS IAM (recommended on AWS)
|
||||
```yaml
|
||||
auth:
|
||||
type: "aws-iam"
|
||||
config:
|
||||
identity-id: "./identity-id" # Path to file with machine identity ID
|
||||
```
|
||||
Uses the instance's IAM role automatically — no access keys needed.
|
||||
|
||||
### Azure (recommended on Azure)
|
||||
```yaml
|
||||
auth:
|
||||
type: "azure"
|
||||
config:
|
||||
identity-id: "./identity-id" # Path to file with machine identity ID
|
||||
```
|
||||
|
||||
### GCP ID Token (recommended on GCP)
|
||||
```yaml
|
||||
auth:
|
||||
type: "gcp-id-token"
|
||||
config:
|
||||
identity-id: "./identity-id" # Path to file with machine identity ID
|
||||
```
|
||||
|
||||
### GCP IAM
|
||||
```yaml
|
||||
auth:
|
||||
type: "gcp-iam"
|
||||
config:
|
||||
identity-id: "./identity-id" # Path to file with machine identity ID
|
||||
service-account-key: "./key.json" # Path to GCP service account JSON key
|
||||
```
|
||||
|
||||
## Sinks
|
||||
|
||||
Sinks are where the agent deposits renewed access tokens. Currently only file sinks are supported.
|
||||
|
||||
```yaml
|
||||
sinks:
|
||||
- type: "file"
|
||||
config:
|
||||
path: "/tmp/access-token"
|
||||
```
|
||||
|
||||
**Important distinction:** Sinks deposit raw access tokens (for SDK/API use). Templates render actual secret values to files. Most users want templates, not sinks.
|
||||
|
||||
## Token Renewal Lifecycle
|
||||
|
||||
1. Agent starts → authenticates using configured auth method
|
||||
2. If auth fails → retries with exponential backoff (base-delay up to max-delay)
|
||||
3. Token obtained → written to all sinks
|
||||
4. Agent monitors token expiry → renews before expiration
|
||||
5. Each renewal → writes new token to all sinks
|
||||
6. Templates rendered → secrets fetched using the token
|
||||
7. Templates re-render on polling-interval → detects secret changes
|
||||
8. If secrets changed and `execute.command` is set → command runs
|
||||
|
||||
## Caching (Kubernetes only)
|
||||
|
||||
Persistent caching stores secrets locally so the agent can serve them even if Infisical is temporarily unavailable.
|
||||
|
||||
```yaml
|
||||
cache:
|
||||
persistent:
|
||||
type: "kubernetes"
|
||||
path: "/home/infisical/cache"
|
||||
service-account-token-path: "/var/run/secrets/kubernetes.io/serviceaccount/token"
|
||||
```
|
||||
|
||||
- Only available in Kubernetes environments
|
||||
- Stale dynamic secret leases are auto-evicted and refreshed
|
||||
- Cache GC runs every 10 minutes
|
||||
|
||||
## Key Config Options
|
||||
|
||||
| Setting | When to use |
|
||||
|---------|------------|
|
||||
| `exit-after-auth: true` | Init containers, one-shot renders (render secrets once and exit) |
|
||||
| `revoke-credentials-on-shutdown: true` | Clean up dynamic secret leases when agent stops |
|
||||
| `polling-interval: "30s"` | Latency-sensitive apps that need fast secret updates |
|
||||
| `polling-interval: "60m"` | Stable configs where secrets rarely change |
|
||||
| `execute.command` | Trigger app restarts or config reloads on secret changes |
|
||||
@@ -0,0 +1,297 @@
|
||||
# Infisical Agent Deployment Examples
|
||||
|
||||
## Basic Local Development
|
||||
|
||||
```yaml
|
||||
# agent-config.yaml
|
||||
infisical:
|
||||
address: "https://app.infisical.com"
|
||||
|
||||
auth:
|
||||
type: "universal-auth"
|
||||
config:
|
||||
client-id: "./client-id"
|
||||
client-secret: "./client-secret"
|
||||
|
||||
sinks:
|
||||
- type: "file"
|
||||
config:
|
||||
path: "/tmp/infisical-token"
|
||||
|
||||
templates:
|
||||
- template-content: |
|
||||
{{- with listSecrets "6553ccb2b7da580d7f6e7260" "dev" "/" }}
|
||||
{{- range . }}
|
||||
{{ .Key }}={{ .Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
destination-path: /app/.env
|
||||
config:
|
||||
polling-interval: 5m
|
||||
execute:
|
||||
command: ./restart-app.sh
|
||||
timeout: 30
|
||||
```
|
||||
|
||||
**Run:** `infisical agent --config agent-config.yaml`
|
||||
|
||||
---
|
||||
|
||||
## Docker Compose Sidecar
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
version: "3.8"
|
||||
services:
|
||||
infisical-agent:
|
||||
image: infisical/cli:latest
|
||||
command: agent --config /etc/infisical/agent-config.yaml
|
||||
volumes:
|
||||
- ./agent-config.yaml:/etc/infisical/agent-config.yaml:ro
|
||||
- ./client-id:/etc/infisical/client-id:ro
|
||||
- ./client-secret:/etc/infisical/client-secret:ro
|
||||
- shared-secrets:/infisical/secrets
|
||||
|
||||
app:
|
||||
image: myapp:latest
|
||||
volumes:
|
||||
- shared-secrets:/app/secrets:ro
|
||||
depends_on:
|
||||
- infisical-agent
|
||||
|
||||
volumes:
|
||||
shared-secrets:
|
||||
```
|
||||
|
||||
```yaml
|
||||
# agent-config.yaml (for Docker Compose)
|
||||
infisical:
|
||||
address: "https://app.infisical.com"
|
||||
|
||||
auth:
|
||||
type: "universal-auth"
|
||||
config:
|
||||
client-id: "/etc/infisical/client-id"
|
||||
client-secret: "/etc/infisical/client-secret"
|
||||
|
||||
sinks:
|
||||
- type: "file"
|
||||
config:
|
||||
path: "/infisical/secrets/access-token"
|
||||
|
||||
templates:
|
||||
- template-content: |
|
||||
{{- with listSecrets "<project-id>" "dev" "/" }}
|
||||
{{- range . }}
|
||||
{{ .Key }}={{ .Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
destination-path: /infisical/secrets/.env
|
||||
config:
|
||||
polling-interval: 5m
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## AWS ECS Sidecar
|
||||
|
||||
Use `aws-iam` auth so no credentials need to be stored. The agent uses the ECS task role automatically.
|
||||
|
||||
```yaml
|
||||
# agent-config.yaml (for ECS)
|
||||
infisical:
|
||||
address: "https://app.infisical.com"
|
||||
exit-after-auth: true # Render once and exit (init-style)
|
||||
|
||||
auth:
|
||||
type: "aws-iam"
|
||||
config:
|
||||
identity-id: "<machine-identity-id>" # Inline ID (no file path needed in ECS)
|
||||
|
||||
sinks:
|
||||
- type: "file"
|
||||
config:
|
||||
path: "/infisical/secrets/access-token"
|
||||
|
||||
templates:
|
||||
- template-content: |
|
||||
{{- with listSecretsByProjectSlug "my-project" "prod" "/" }}
|
||||
{{- range . }}
|
||||
{{ .Key }}={{ .Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
destination-path: /infisical/secrets/.env
|
||||
```
|
||||
|
||||
**ECS Task Definition snippet:**
|
||||
```json
|
||||
{
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "infisical-agent",
|
||||
"image": "infisical/cli:latest",
|
||||
"command": ["agent", "--config", "/etc/infisical/agent-config.yaml"],
|
||||
"essential": false,
|
||||
"mountPoints": [
|
||||
{ "sourceVolume": "secrets", "containerPath": "/infisical/secrets" }
|
||||
],
|
||||
"environment": [
|
||||
{ "name": "INFISICAL_MACHINE_IDENTITY_ID", "value": "<identity-id>" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "app",
|
||||
"image": "myapp:latest",
|
||||
"essential": true,
|
||||
"dependsOn": [
|
||||
{ "containerName": "infisical-agent", "condition": "COMPLETE" }
|
||||
],
|
||||
"mountPoints": [
|
||||
{ "sourceVolume": "secrets", "containerPath": "/app/secrets", "readOnly": true }
|
||||
]
|
||||
}
|
||||
],
|
||||
"volumes": [
|
||||
{ "name": "secrets" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Kubernetes Init Container
|
||||
|
||||
Use `exit-after-auth: true` to render secrets once and let the main container start.
|
||||
|
||||
```yaml
|
||||
# agent-config.yaml (for K8s init container)
|
||||
infisical:
|
||||
address: "https://app.infisical.com"
|
||||
exit-after-auth: true
|
||||
|
||||
auth:
|
||||
type: "kubernetes"
|
||||
config:
|
||||
identity-id: "/etc/infisical/identity-id"
|
||||
service-account-token: "/var/run/secrets/kubernetes.io/serviceaccount/token"
|
||||
|
||||
templates:
|
||||
- template-content: |
|
||||
{{- with listSecretsByProjectSlug "my-project" "prod" "/" }}
|
||||
{{- range . }}
|
||||
{{ .Key }}={{ .Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
destination-path: /infisical/secrets/.env
|
||||
```
|
||||
|
||||
```yaml
|
||||
# Kubernetes Pod spec
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: my-app
|
||||
spec:
|
||||
serviceAccountName: my-app-sa
|
||||
initContainers:
|
||||
- name: infisical-agent
|
||||
image: infisical/cli:latest
|
||||
command: ["infisical", "agent", "--config", "/etc/infisical/agent-config.yaml"]
|
||||
volumeMounts:
|
||||
- name: secrets
|
||||
mountPath: /infisical/secrets
|
||||
- name: agent-config
|
||||
mountPath: /etc/infisical
|
||||
containers:
|
||||
- name: app
|
||||
image: myapp:latest
|
||||
volumeMounts:
|
||||
- name: secrets
|
||||
mountPath: /app/secrets
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: secrets
|
||||
emptyDir: {}
|
||||
- name: agent-config
|
||||
configMap:
|
||||
name: infisical-agent-config
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Kubernetes Sidecar (continuous sync)
|
||||
|
||||
For apps that need live secret updates, run the agent as a sidecar instead of an init container.
|
||||
|
||||
```yaml
|
||||
# agent-config.yaml (sidecar mode)
|
||||
infisical:
|
||||
address: "https://app.infisical.com"
|
||||
# exit-after-auth: false (default — keep running)
|
||||
|
||||
auth:
|
||||
type: "kubernetes"
|
||||
config:
|
||||
identity-id: "/etc/infisical/identity-id"
|
||||
|
||||
cache:
|
||||
persistent:
|
||||
type: "kubernetes"
|
||||
path: "/home/infisical/cache"
|
||||
|
||||
templates:
|
||||
- template-content: |
|
||||
{{- with listSecretsByProjectSlug "my-project" "prod" "/" }}
|
||||
{{- range . }}
|
||||
{{ .Key }}={{ .Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
destination-path: /infisical/secrets/.env
|
||||
config:
|
||||
polling-interval: "1m"
|
||||
execute:
|
||||
command: "kill -HUP 1" # Signal main process to reload
|
||||
timeout: 10
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## With Dynamic Secrets (Database Credentials)
|
||||
|
||||
```yaml
|
||||
# agent-config.yaml
|
||||
infisical:
|
||||
address: "https://app.infisical.com"
|
||||
revoke-credentials-on-shutdown: true # Clean up DB users on shutdown
|
||||
|
||||
auth:
|
||||
type: "aws-iam"
|
||||
config:
|
||||
identity-id: "<machine-identity-id>"
|
||||
|
||||
templates:
|
||||
# Static secrets
|
||||
- template-content: |
|
||||
{{- with listSecretsByProjectSlug "my-project" "prod" "/" }}
|
||||
{{- range . }}
|
||||
{{ .Key }}={{ .Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
destination-path: /app/secrets/static.env
|
||||
|
||||
# Dynamic database credentials
|
||||
- template-content: |
|
||||
{{ with dynamicSecret "my-project" "prod" "/" "postgres-creds" "1h" }}
|
||||
DB_HOST=db.internal.example.com
|
||||
DB_PORT=5432
|
||||
DB_NAME=myapp
|
||||
DB_USER={{ .DB_USERNAME }}
|
||||
DB_PASS={{ .DB_PASSWORD }}
|
||||
{{ end }}
|
||||
destination-path: /app/secrets/db.env
|
||||
config:
|
||||
polling-interval: "5m"
|
||||
execute:
|
||||
command: "./reconnect-db.sh"
|
||||
timeout: 30
|
||||
```
|
||||
@@ -0,0 +1,200 @@
|
||||
# Infisical Agent Template Functions
|
||||
|
||||
Templates use Go's `text/template` syntax. All functions are available inside template blocks.
|
||||
|
||||
## listSecrets
|
||||
|
||||
Fetch all secrets from a project environment and path. **Most common function** — use for rendering .env files.
|
||||
|
||||
```
|
||||
listSecrets "<project-id>" "<environment-slug>" "<secret-path>" "<optional-modifier>"
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| project-id | string | UUID of the project |
|
||||
| environment-slug | string | `dev`, `staging`, `prod`, etc. |
|
||||
| secret-path | string | `/`, `/api`, `/database`, etc. |
|
||||
| optional-modifier | JSON string | `{"recursive": bool, "expandSecretReferences": bool}` |
|
||||
|
||||
- `recursive` (default: `false`) — Fetch secrets from subdirectories too
|
||||
- `expandSecretReferences` (default: `true`) — Resolve `${SECRET_NAME}` references
|
||||
|
||||
**Returns:** Array of objects with: `Key`, `Value`, `SecretPath`, `WorkspaceId`, `Type`, `ID`, `Comment`
|
||||
|
||||
**Example — .env file:**
|
||||
```go
|
||||
{{- with listSecrets "6553ccb2b7da580d7f6e7260" "dev" "/" `{"recursive": false, "expandSecretReferences": true}` }}
|
||||
{{- range . }}
|
||||
{{ .Key }}={{ .Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
```
|
||||
|
||||
**Example — recursive with paths:**
|
||||
```go
|
||||
{{- with listSecrets "da8056c8-01e2-4d24-b39f-cb4e004b8d44" "staging" "/" `{"recursive": true, "expandSecretReferences": true}` }}
|
||||
{{- range . }}
|
||||
{{- if eq .SecretPath "/"}}
|
||||
{{ .Key }}={{ .Value }}
|
||||
{{- else}}
|
||||
{{ .SecretPath }}/{{ .Key }}={{ .Value }}
|
||||
{{- end}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## listSecretsByProjectSlug
|
||||
|
||||
Same as `listSecrets` but uses the project slug instead of UUID. Easier to read in configs.
|
||||
|
||||
```
|
||||
listSecretsByProjectSlug "<project-slug>" "<environment-slug>" "<secret-path>" "<optional-modifier>"
|
||||
```
|
||||
|
||||
**Parameters:** Same as `listSecrets`, except first param is project slug (e.g., `"my-project"`) instead of UUID.
|
||||
|
||||
**Returns:** Same as `listSecrets`.
|
||||
|
||||
**Example:**
|
||||
```go
|
||||
{{- with listSecretsByProjectSlug "my-project" "prod" "/" `{"recursive": true}` }}
|
||||
{{- range . }}
|
||||
{{ .Key }}={{ .Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## getSecretByName
|
||||
|
||||
Fetch a single secret by name.
|
||||
|
||||
```
|
||||
getSecretByName "<project-id>" "<environment-slug>" "<secret-path>" "<secret-name>"
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| project-id | string | UUID of the project |
|
||||
| environment-slug | string | `dev`, `staging`, `prod`, etc. |
|
||||
| secret-path | string | `/`, `/api`, etc. |
|
||||
| secret-name | string | Exact secret name (e.g., `DATABASE_URL`) |
|
||||
|
||||
**Returns:** Single object with: `Key`, `Value`, `WorkspaceId`, `Type`, `ID`, `Comment`
|
||||
|
||||
**Example — config file snippet:**
|
||||
```go
|
||||
{{ with getSecretByName "d821f21d-aa90-453b-8448-8c78c1160a0e" "dev" "/" "POSTHOG_HOST" }}
|
||||
{{ if .Value }}
|
||||
analytics_host = "{{ .Value }}"
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## dynamicSecret
|
||||
|
||||
Create and auto-renew a dynamic secret lease. **Use for database credentials, cloud IAM tokens, etc.**
|
||||
|
||||
```
|
||||
dynamicSecret "<project-slug>" "<environment-slug>" "<secret-path>" "<dynamic-secret-name>" "<lease-ttl>"
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| project-slug | string | Project slug |
|
||||
| environment-slug | string | `dev`, `staging`, `prod`, etc. |
|
||||
| secret-path | string | `/`, `/database`, etc. |
|
||||
| dynamic-secret-name | string | Name of the dynamic secret (e.g., `postgres-creds`) |
|
||||
| lease-ttl | string | Lease duration (e.g., `1m`, `1h`, `24h`) |
|
||||
|
||||
**Returns:** Object with keys specific to the dynamic secret type:
|
||||
- SQL databases: `DB_USERNAME`, `DB_PASSWORD`
|
||||
- AWS IAM: `ACCESS_KEY`, `SECRET_ACCESS_KEY`, `SESSION_TOKEN` (if temporary)
|
||||
- Redis: `DB_USERNAME`, `DB_PASSWORD`
|
||||
|
||||
**Key behaviors:**
|
||||
- Automatically renews credentials before expiration
|
||||
- Deduplication: Multiple templates with identical dynamic secret configs share one lease
|
||||
- Revoked on shutdown if `revoke-credentials-on-shutdown: true`
|
||||
|
||||
**Example — PostgreSQL credentials:**
|
||||
```go
|
||||
{{ with dynamicSecret "my-project" "dev" "/" "postgres-creds" "1h" }}
|
||||
DB_HOST=db.example.com
|
||||
DB_USER={{ .DB_USERNAME }}
|
||||
DB_PASSWORD={{ .DB_PASSWORD }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
**Example — Redis credentials:**
|
||||
```go
|
||||
{{ with dynamicSecret "my-project" "prod" "/" "redis" "30m" }}
|
||||
REDIS_USER={{ .DB_USERNAME }}
|
||||
REDIS_PASS={{ .DB_PASSWORD }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Template Patterns
|
||||
|
||||
### .env file (most common)
|
||||
```go
|
||||
{{- with listSecrets "<project-id>" "dev" "/" }}
|
||||
{{- range . }}
|
||||
{{ .Key }}={{ .Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
```
|
||||
|
||||
### JSON config
|
||||
```go
|
||||
{
|
||||
{{- with listSecrets "<project-id>" "prod" "/" }}
|
||||
{{- range $i, $s := . }}
|
||||
{{- if $i }},{{ end }}
|
||||
"{{ $s.Key }}": "{{ $s.Value }}"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
}
|
||||
```
|
||||
|
||||
### YAML config
|
||||
```go
|
||||
{{- with listSecrets "<project-id>" "dev" "/" }}
|
||||
{{- range . }}
|
||||
{{ .Key }}: "{{ .Value }}"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
```
|
||||
|
||||
### Mixed static + dynamic secrets
|
||||
```go
|
||||
{{- with listSecrets "<project-id>" "prod" "/" }}
|
||||
{{- range . }}
|
||||
{{ .Key }}={{ .Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{ with dynamicSecret "my-project" "prod" "/" "postgres" "1h" }}
|
||||
DB_DYNAMIC_USER={{ .DB_USERNAME }}
|
||||
DB_DYNAMIC_PASS={{ .DB_PASSWORD }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
### Export format (for `source .env`)
|
||||
```go
|
||||
{{- with listSecrets "<project-id>" "dev" "/" }}
|
||||
{{- range . }}
|
||||
export {{ .Key }}="{{ .Value }}"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
```
|
||||
Reference in New Issue
Block a user