Trajectory keeps Datadog credential values out of configuration and session data. Configuration names a credential by reference; the credential layer resolves that reference at runtime from an environment variable, an external provider, or the OS keychain. The resolved value is held only as long as the active process or its bounded credential cache needs it.
This document describes the Datadog API and application key lifecycle in the
Trajectory binary. Provider credentials such as
ANTHROPIC_API_KEY, OPENAI_API_KEY, and GEMINI_API_KEY are separate from
the Datadog publish path.
| Credential | What Trajectory uses it for | When it is required |
|---|---|---|
| Datadog API key | LLM Observability, metrics, logs, and AI Usage intake; Datadog API-key validation; optional AI Guard evaluation | Direct datadog_agentless publishing, agentless Datadog OTLP forwarding, and the enabled AI Guard evaluator |
| Datadog application key | Datadog Metrics query readback, log-based metric configuration, and optional AI Guard evaluation | Explicit readback, trajectory publish sync, and the enabled AI Guard evaluator; not routine capture or publish |
| No Trajectory-managed key | Egress owned by another component | datadog_agent destinations and generic otlp collectors |
An application key does not replace an API key. Commands that call a Datadog configuration or query API generally use both: the API key identifies the organization, and the application key authorizes the operation.
- YAML contains
api_key_ref,app_key_ref, and command configuration, never a credential value. - The default durable store is the current user's OS keychain under service
trajectory. - Session JSONL, local-ui data, publish ledgers, and publish outboxes never persist API or application keys.
- Runtime logs and validation output report the policy, source, wrapper shape, normalized length, and format validity, but never the value.
- A missing credential does not stop local capture. Remote publishing fails closed, records a credential-health error, and leaves retryable publish work in its normal durable queue where applicable.
- Publish keys are sent only to the destination selected by the effective
trusted configuration. Datadog requests use
DD-API-KEY,dd-api-key, and, only where required,DD-APPLICATION-KEYheaders over HTTPS.
setup / config / managed provisioning
|
+--> config.yaml or config.defaults.yaml: refs and source policy only
|
+--> environment, credential provider, or OS keychain: secret value
|
v
credentials.ConfigurePolicy
|
+-------------+--------------+
| |
v v
credentials.Resolve ResolveDatadogApplicationKey
per destination only for readback/sync
| |
v v
API key in memory app key in memory
| |
+-------------+--------------+
v
publish or Datadog API client
trajectory setup prompts for a Datadog API key with terminal echo disabled,
validates it against the selected Datadog site, and stores it as dd_api_key
in the OS keychain. It does not request an application key because normal
publishing does not need one. Setup snapshots an existing keychain value before
replacement and attempts to restore that value if the write fails.
Keys can also be stored directly:
trajectory config set-secret dd_api_key
trajectory config set-secret dd_app_key --stdin
trajectory config set-secret dd-payments-api-key
trajectory config secretsInteractive set-secret input is hidden. --stdin is appropriate for
automation that can provide a protected pipe. Avoid --value=... for real
credentials because the value becomes a command-line argument. config secrets reports only whether known keychain entries exist; it does not print
values or enumerate arbitrary custom entries.
A standard multi-destination configuration can name separate credentials:
auth:
credential_source: auto
key_command: ""
required_destinations:
- name: primary
type: datadog_agentless
site: datadoghq.com
api_key_ref: dd-primary-api-key
app_key_ref: dd-primary-app-key
level: standardapi_key_ref selects the API credential for all direct Datadog signals on that
destination. app_key_ref is consulted only by a command that needs Datadog
readback or configuration access; its presence does not cause the normal
publish engine to resolve or transmit an application key.
Custom intake and forwarder destinations can use bearer_token_ref instead of
api_key_ref when the default-off bearer_destination_auth feature is enabled.
The fields are mutually exclusive. Bearer references use the configured source
policy but resolve only the named environment variable, keychain account, or
destination command; they never fall back to DD_API_KEY, DATADOG_API_KEY,
or the default Datadog key provider. Trajectory sends the result as
Authorization: Bearer <token> across the explicitly configured direct and
OTLP publish requests. Bearer endpoints must use HTTPS; loopback HTTP is
accepted only for local development and tests, and authenticated redirects are
not followed.
Managed direct-Datadog entries use the rollback-safe type: datadog_bearer
shape with level: off and the active level in bearer_level. Project publish
files use version: 2 for bearer destinations. Bearer configuration must set
explicit intake, OTLP trace, active metrics transport, and logs URLs; enabled
evaluations and AI Usage also require their explicit endpoints.
Managed bearer destinations use only the rollback-safe datadog_bearer shape;
project schema version 2 also supports bearer-authenticated otlp collectors.
For the implicit _config_datadog destination created from export.*, the API
key ref defaults to dd-api-key. In standard mode, dd-api-key and
dd_api_key are aliases for the same normalized keychain account. This is why
setup can store dd_api_key while the publish layer uses dd-api-key.
For a direct Datadog destination, auth.credential_source: auto checks the
following sources in order:
| Order | Source | Behavior |
|---|---|---|
| 1 | Environment | The uppercased api_key_ref with hyphens changed to underscores, then DD_API_KEY, then DATADOG_API_KEY |
| 2 | Default key provider | auth.key_command, available only to the default dd-api-key / dd_api_key ref |
| 3 | OS keychain | Service trajectory, account api_key_ref with hyphens normalized to underscores |
| 4 | Destination command | The destination's api_key_command, if configured |
For example, api_key_ref: dd-payments-api-key first checks
DD_PAYMENTS_API_KEY, then the two global API-key environment aliases. It
skips the default key provider because it is a non-default ref, then checks the
normalized keychain account dd_payments_api_key, and finally its configured
destination command.
Set auth.credential_source to env, key_provider, keychain, or
api_key_command to select exactly one source. A pinned source fails closed; it
does not continue through the auto chain. A managed credential_source value
wins over the user value.
Trajectory normalizes common credential-provider wrappers before use,
including quoted values, DD_API_KEY=..., supported JSON objects, and
go-keyring-base64: keychain values. Real Datadog endpoints require a final
API key shape of 32 alphanumeric characters. In auto mode, a malformed
environment override is diagnosed and a real Datadog destination may continue
to the later sources. A pinned env policy rejects the value without fallback.
datadog_agent and generic otlp destinations bypass this chain because the
Agent or collector owns authentication. Agentless Datadog OTLP is still a
direct Datadog path and uses the resolved API key in a dd-api-key header.
There are two command-backed API-key paths:
auth.key_commandis the process-wide default key provider. It supports short-lived credentials, refreshes on demand, and is used only for the default API-key ref. Its shared~/.trajectory/.auth-cachehas a 40-minute validity window, while lock and failure-sentinel files prevent concurrent refreshes and repeated provider prompts across processes.- A destination
api_key_commandis the last step in the standard auto chain, or the only step whencredential_source: api_key_commandis pinned. Its configuredttlcontrols reuse and defaults to five minutes. Results from recognized credential tools can be shared through~/.trajectory/.credential-command-cache/; other explicitly allowed commands remain process-local.
Destination commands are executed directly, not through a shell, with a
30-second timeout. A bounded allowlist covers recognized credential helpers.
Setting TRAJECTORY_ALLOW_API_KEY_COMMAND=1 permits a non-allowlisted command
and should be limited to a trusted environment and trusted configuration.
Shared cache files and directories are user-only (0600 files under 0700
directories). Cached key material is XOR-obfuscated with a machine/user-derived
mask so the raw key does not appear to pattern-matching scanners. This is
obfuscation, not encryption; file permissions, short validity, and host access
control are the security boundary. Application keys resolved by the shared app
key resolver are not written to these command caches.
Managed deployments can set:
auth:
mode: managed_keychain
required_destinations:
- name: primary
type: datadog_agentless
api_key_ref: managed-primary-api-key
app_key_ref: managed-primary-app-keyManaged keychain mode is intentionally not an extension of the standard fallback chain. It:
- requires an explicit
api_key_reffor each direct Datadog managed destination; - reads the exact keychain account name under service
trajectorywithout hyphen/underscore aliasing; - ignores API and application key environment variables;
- skips the default key provider and destination
api_key_command; - coalesces concurrent reads, caches successful values in memory, and caches failures briefly to avoid repeatedly prompting or hammering the keychain.
Provision exact managed account names with the fleet's keychain tooling or, for a manual recovery, with:
trajectory config set-secret managed-primary-api-key --exact-name
trajectory config set-secret managed-primary-app-key --exact-name--exact-name is for managed provisioning. Standard set-secret deliberately
normalizes hyphens to underscores.
The shared publish/CLI application key path is smaller than the API-key path. It first selects a reference, then reads that secret:
- An explicit command flag such as
--readback-app-key-ref. - The selected destination's
app_key_ref. - The default
dd_app_keyref.
In standard mode, the default ref checks these environment aliases in order:
DD_APP_KEY, DD_APPLICATION_KEY, DATADOG_APP_KEY, and
DATADOG_APPLICATION_KEY, then the normalized OS keychain account. A custom
application-key ref is keychain-backed; it does not derive a custom environment
variable. Use the default ref for environment-driven automation, or store a
custom ref in the keychain.
In managed keychain mode, the selected ref is always an exact keychain account and no environment alias is read.
Application-key consumers state the permission they need:
| Consumer | Application-key permission |
|---|---|
trajectory metrics verify --readback, metrics audit, and backfill readback |
Metrics query (timeseries_query) |
trajectory publish sync |
Log configuration write |
Optional agent-security AI Guard evaluator |
AI Guard API access defined by the service's application-key policy |
Without an application key, routine capture and publish still work.
trajectory metrics verify normally falls back to submit-only evidence; an
explicit --readback makes missing readback credentials a hard failure.
trajectory publish validate validates destination API keys but does not prove
application-key permissions.
The default-disabled AI Guard evaluator is a separate module request path. Its
auth_headers configuration maps DD-API-KEY and DD-APPLICATION-KEY to
environment variable names, defaulting to DD_API_KEY and DD_APP_KEY. The
module reads those variables directly when building an evaluation request; it
does not use destination api_key_ref / app_key_ref or the shared publish
credential caches. Rotating those module credentials therefore requires the
same process-environment refresh as any other environment-backed key.
Environment variables are copied into a process when it starts. Exporting or
changing DD_API_KEY in a shell does not update an already-running
trajectory serve. The background server also disables unbounded generic
keychain reads so macOS cannot block it on an authorization dialog. The default
dd_api_key remains available through a bounded key-provider fallback;
non-default background credentials should use a managed exact ref, an external
provider, or an environment supplied when the process starts.
Use this rotation sequence:
- Create or obtain the replacement credential in the secret authority.
- Update the environment, provider, or keychain entry without changing the configured ref when possible.
- Reload configuration and restart long-running Trajectory processes through the supported process lifecycle when their source is process-bound or memory-cached.
- Run
trajectory publish validatefor API keys. For application keys, run the exact readback or sync command that exercises the required permission. - Revoke the old credential after the new path is healthy.
Command-backed API keys naturally refresh at their TTL. Environment-backed and keychain-backed credentials can remain in a long-running process, so process refresh is part of their rotation procedure. Managed exact-ref successes are also cached in memory.
Use the narrowest command that proves the required path:
trajectory config secrets
trajectory doctor
trajectory publish status
trajectory publish validate
trajectory metrics verify --destination <name> --readback
trajectory publish syncconfig secretsconfirms known keychain presence without resolving or printing values.doctorreports the effective credential policy and live serve credential health.publish statusshows effective destinations and publish modes.publish validateresolves each destination API key, reports non-secret source/shape metadata, and validates real Datadog keys against that site.metrics verify --readbackproves API-key submission plus application-key Metrics query access.publish syncproves the application key has log configuration write access.
Do not print a key to debug it. Check the named keychain account, source policy, destination ref, site, and non-secret shape diagnostics. If a real value was printed, committed, attached to a support bundle, or pasted into a ticket, rotate it rather than trying to redact every copy.