> ## Documentation Index
> Fetch the complete documentation index at: https://www.checklyhq.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy Checkly secrets from HashiCorp Vault

> Use GitHub OIDC to fetch HashiCorp Vault values and deploy them as scoped Checkly secrets.

Use GitHub OpenID Connect (OIDC) to authenticate a trusted deployment job to HashiCorp Vault without storing a Vault token in GitHub. The job reads only the values required by one Checkly CLI project and exposes them to the Checkly deploy step.

For guidance on choosing account, group, or check scope, see [Manage secrets at scale](/docs/platform/manage-secrets-at-scale).

<Accordion title="Prerequisites">
  * A Checkly Monitoring as Code project with its dependencies and lockfile committed.
  * A GitHub repository with Actions enabled and a protected environment named `checkly-production`.
  * A Vault server reachable from the GitHub Actions runner, with the required values stored in a KV secrets engine.
  * Permission to configure a Vault JWT auth method, policy, and role.
  * `VAULT_ADDR` and `CHECKLY_ACCOUNT_ID` configured as GitHub Actions variables.
  * The Checkly API key stored in Vault alongside the secrets required by this CLI project.
</Accordion>

<Info>
  This guide uses a fictional payments service; replace its names, paths, and
  URL with your own application values. Checkly requires `CHECKLY_API_KEY` and
  `CHECKLY_ACCOUNT_ID`; `VAULT_ADDR` configures this workflow.
</Info>

## Configure Vault access

Configure Vault's JWT authentication for GitHub Actions and create a role for this deployment by following HashiCorp's [`vault-action` JWT guide](https://github.com/hashicorp/vault-action#jwt-with-github-oidc-tokens). The workflow below assumes that role is named `checkly-payments-deploy`.

Restrict the role to the repository, branch, and GitHub environment that deploy Checkly. Its policy should grant read-only access only to the Vault paths referenced by this project. The role's audience must match `jwtGithubAudience` in the workflow. See HashiCorp's [JWT role reference](https://developer.hashicorp.com/vault/api-docs/auth/jwt#createupdate-role) for the Vault configuration options.

## Scope secrets in your constructs

Read each value with `secret()` and mark it as secret on the group or check that needs it:

```typescript __checks__/payments.check.ts theme={null}
import { ApiCheck, CheckGroupV2 } from "checkly/constructs";
import { secret } from "checkly/util";

const paymentsGroup = new CheckGroupV2("payments", {
  name: "Payments",
  environmentVariables: [
    {
      key: "PAYMENTS_API_KEY",
      value: secret("PAYMENTS_API_KEY"),
      secret: true,
    },
  ],
});

new ApiCheck("payments-admin", {
  name: "Payments admin",
  group: paymentsGroup,
  environmentVariables: [
    {
      key: "PAYMENTS_ADMIN_TOKEN",
      value: secret("PAYMENTS_ADMIN_TOKEN"),
      secret: true,
    },
  ],
  request: {
    method: "GET",
    url: "https://payments.example.com/admin",
    headers: [
      { key: "Authorization", value: "Bearer {{PAYMENTS_ADMIN_TOKEN}}" },
    ],
  },
});
```

The helper reads `CHECKLY_SECRET_PAYMENTS_API_KEY` and `CHECKLY_SECRET_PAYMENTS_ADMIN_TOKEN` when the CLI loads the project. If a required value is missing, `secret()` stops the deployment instead of deploying an empty value.

## Fetch and deploy from GitHub Actions

The official HashiCorp action authenticates with GitHub's OIDC token and returns masked step outputs. Set `exportEnv: false`, then map the outputs to `CHECKLY_SECRET_*` variables only on the deploy step:

```yaml .github/workflows/deploy-checkly.yml theme={null}
name: Deploy Checkly

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  deploy:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: checkly-production
    permissions:
      contents: read
      id-token: write

    steps:
      - uses: actions/checkout@v7

      - uses: actions/setup-node@v7
        with:
          node-version: 22
          cache: npm

      - name: Install dependencies
        run: npm ci

      - id: vault-secrets
        name: Fetch deployment secrets
        uses: hashicorp/vault-action@v4
        with:
          url: ${{ vars.VAULT_ADDR }}
          method: jwt
          role: checkly-payments-deploy
          jwtGithubAudience: https://github.com/YOUR_ORG
          exportEnv: false
          secrets: |
            secret/data/checkly/production/payments/checkly checkly_api_key | CHECKLY_API_KEY ;
            secret/data/checkly/production/payments/group payments_api_key | CHECKLY_SECRET_PAYMENTS_API_KEY ;
            secret/data/checkly/production/payments/admin-check admin_token | CHECKLY_SECRET_PAYMENTS_ADMIN_TOKEN

      - name: Deploy Checkly
        env:
          CHECKLY_API_KEY: ${{ steps.vault-secrets.outputs.CHECKLY_API_KEY }}
          CHECKLY_ACCOUNT_ID: ${{ vars.CHECKLY_ACCOUNT_ID }}
          CHECKLY_SECRET_PAYMENTS_API_KEY: ${{ steps.vault-secrets.outputs.CHECKLY_SECRET_PAYMENTS_API_KEY }}
          CHECKLY_SECRET_PAYMENTS_ADMIN_TOKEN: ${{ steps.vault-secrets.outputs.CHECKLY_SECRET_PAYMENTS_ADMIN_TOKEN }}
        run: npx checkly deploy --force
```

The job needs `id-token: write` to request the GitHub OIDC token and `contents: read` for checkout. The Vault role and policy determine which values the job can read.

<Warning>
  Do not print or persist fetched values. Install dependencies before fetching
  secrets and expose the outputs only to the Checkly deployment step.
</Warning>

## Rotate a secret

Rotating a value in Vault does not automatically update the encrypted copy stored by Checkly. Run this trusted deployment workflow again after rotation. The action reads the current KV value and `checkly deploy` updates the secret at its declared group or check scope.

When the workflow no longer needs a value, remove it from the construct, workflow mapping, and Vault policy or path.
