# !secret

The `!secret` YAML function resolves a **declared** secret from its configured backend (a `secret: true`
[store](/cli/configuration/stores) such as AWS SSM, AWS Secrets Manager, HashiCorp Vault, Azure Key Vault, or
GCP Secret Manager, or a SOPS-encrypted file) and substitutes its value into an Atmos stack manifest. Resolved
values are automatically registered with the I/O masker, so they are redacted in all output.

## Usage

```yaml
  !secret <NAME> [| path <yq-expression> | raw] [| default <default-value>]
```

The secret `<NAME>` must be declared under the component's [`secrets.vars`](/cli/configuration/secrets) before it
can be referenced — this keeps the registry of secrets GitOps-friendly and explicit.

Usage examples:

```yaml
  # Resolve a declared secret
  vars:
    api_key: !secret DATADOG_API_KEY

  # Provide a default when the secret is missing
  vars:
    api_key: !secret DATADOG_API_KEY | default "dev-key"

  # Extract a nested value from a structured (JSON) secret
  vars:
    db_host: !secret DATABASE_CONFIG | path ".host"
    db_password: !secret DATABASE_CONFIG | path ".credentials.password"

  # Preserve the exact backend payload when valid JSON must remain an opaque string
  vars:
    service_credentials: !secret SERVICE_CREDENTIALS | raw

  # Combine path and default
  vars:
    db_host: !secret DATABASE_CONFIG | path ".host" | default "localhost"
```

Bare `!secret` preserves the store's existing value contract, including structured maps and lists.
Use `| raw` when the original textual payload is required byte-for-byte. The `raw` and `path`
modifiers are mutually exclusive.

Some store backends detect structured values by attempting to decode the payload as JSON. Use
`| raw` whenever a secret that must remain a string might be valid JSON—including objects, arrays,
bare numbers, booleans, `null`, and JSON-quoted strings. This prevents a future secret rotation from
silently changing the resolved value's type.

`atmos secret set` writes string values verbatim, so new values round-trip through `| raw`. Secrets
written by older Atmos releases may contain JSON quote characters in the stored payload; set them
again with the current release before switching those references to `| raw`.

## Declaration

A secret must be declared before use. Declarations live in stack/component config and reference a backend by name:

**File:** `stacks/prod/api.yaml`

```yaml
components:
  terraform:
    api:
      secrets:
        vars:
          DATADOG_API_KEY:
            description: "Datadog API key for monitoring"
            store: app-secrets       # a `secret: true` store (track 1)
            required: true
          GITHUB_APP_KEY:
            sops: dev-sops           # a SOPS provider (track 2)
      vars:
        datadog_api_key: !secret DATADOG_API_KEY
```

The backend (`store:` or `sops:`) carries the provider, region, prefix, and optional auth `identity`, so the
declaration stays terse. See [Secrets configuration](/cli/configuration/secrets) for backend setup.

### Backend selected by a YAML function

`store:` and `sops:` can be a YAML function instead of a literal name, for example to read the backend
name from a CloudFormation stack's Outputs:

**File:** `stacks/prod/api.yaml`

```yaml
secrets:
  vars:
    API_KEY:
      store: !aws.cloudformation.output secret-backends prod SecretStoreName
    DB_PASSWORD:
      store: app-secrets
```

Selectors are resolved **lazily, one declaration at a time**, only when a command uses that declaration.
`!secret API_KEY` and `atmos secret get API_KEY` resolve the selector for `API_KEY` and nothing else, so
a selector that cannot be resolved (for example, its producer component is not deployed yet) fails only
that declaration. The error names the secret, component, stack and selector, and suggests deploying the
producer. Declarations with a literal backend, such as `DB_PASSWORD` above, keep working, including
`atmos secret delete`.

Three things differ from literal backends:

- [`atmos secret list`](/cli/commands/secret/list) is credential-free and never evaluates selectors. It
  shows the declaration with status `unresolved` and a reason until you pass `--verify`.
- [`atmos secret validate`](/cli/commands/secret/validate) resolves `sops:` selectors to check for SOPS file
  collisions across the stack. If a `sops:` selector cannot be resolved, validation fails instead of
  skipping it, because the file it would use is unknown.
- [`atmos describe affected`](/cli/commands/describe/affected) marks components affected when a SOPS
  file they use changes, and it normally runs without credentials, so it does not evaluate selectors. A
  `sops:` selector is never skipped: the component is treated as affected by any change under the directories
  its SOPS providers can use (`spec.path`, default `secrets`, or the static directory prefix of `spec.file`),
  and a warning names the component and the declaration. Use a literal `sops:` name when you want the
  exact file to decide.

## Masking and Inspection

`!secret` is automatically masked everywhere its value appears. In **inspection** commands —
[`atmos describe`](/cli/commands/describe/component) and the [`atmos list`](/cli/commands/list/list-values)
family — `!secret` resolves to `<MASKED>` **without contacting the backend** when masking is enabled (the
default). This means you can inspect a stack's shape with **no cloud credentials**:

```shell
# No credentials needed — the secret renders as <MASKED>
atmos describe component api --stack=prod

# Reveal the real value (requires access to the secret backend)
atmos describe component api --stack=prod --mask=false
```

In **value-producing** commands (`terraform plan`/`apply`, [`atmos secret get`](/cli/commands/secret/get)), the
value is always retrieved because it is needed to function; `--mask` only controls whether it is redacted in
display output.

## Access Rule

`!secret` is the **only** accessor for a `secret: true` store. Using [`!store`](/functions/yaml/store) against a
`secret: true` store is an error — this makes declarations mandatory-by-construction for secrets and removes any
ambiguity about whether a value is sensitive.

## See Also

- [`atmos secret` command](/cli/commands/secret/usage)
- [Secrets configuration](/cli/configuration/secrets)
- [`!store` YAML function](/functions/yaml/store)
