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

# Terraform Cloud

> Connect Terraform Cloud (HCP Terraform) to Keldyn so infrastructure change-approval and policy-gate evidence stays current automatically — without ever reading Terraform state.

The Terraform Cloud integration connects your HCP Terraform organization to Keldyn's continuous-evidence engine. Once connected, Keldyn reads workspace apply-gating settings, recent runs and applies, Sentinel/OPA policy-check results, and (optionally) who confirmed each apply. It turns that into live evidence for the related change-management controls.

Keldyn **never reads Terraform state**. State files can contain cleartext secrets. The token you create must be scoped to runs and outputs only.

<Note>
  Integrations and automated evidence are typically managed by workspace admins.
  See [Evidence & audits](/evidence-and-audits) for how automated evidence fits
  alongside manual evidence.
</Note>

## What it's used for

Keldyn uses the data it reads from Terraform Cloud to keep infrastructure change-approval evidence current. Each nightly refresh updates the evidence and the freshness status shown on the integration's **Controls covered** table.

Every workspace the connected team can see is in scope. There is no production-workspace picker.

The integration contributes evidence to these SOC 2 controls:

| Control                                | Topic                                                                     | Coverage             |
| -------------------------------------- | ------------------------------------------------------------------------- | -------------------- |
| **Software changes approved**          | Each apply went through a gated pipeline run with a recorded confirmation | Full                 |
| **Testing of changes**                 | Sentinel or OPA policy checks that ran before apply                       | Partial              |
| **Production environment restriction** | Audit-trail actors who confirmed applies                                  | Partial / supporting |

<Info>
  **Full** coverage means the data is the artifact the control asks for.
  **Partial** coverage means the data usefully contributes but does not, on its
  own, replace everything the control requires. Keldyn labels partial coverage
  in the auto-generated evidence so it isn't mistaken for complete coverage.
</Info>

<Note>
  **Testing of changes** stays Partial because Terraform Cloud covers the
  infrastructure policy gate only. Application-code test results still come from
  your [code platform](/integrations/github). **Production environment
  restriction** stays Partial: audit-trail actors support who confirmed each
  apply, but your cloud platform's access listing remains the source of record
  for who can reach production.
</Note>

## Before you begin

<Steps>
  <Step title="Use a Terraform Cloud organization owner or teams admin">
    You need permission to create a team, assign a custom workspace role, and
    generate a team token in the organization you want to evidence.
  </Step>

  <Step title="Create a dedicated team — do not use the built-in Read role">
    The built-in workspace **Read** role can read full state files. Org-level
    "View all workspaces" is too broad for the same reason. Create a dedicated
    team (for example `KeldynEvidence`) and grant it a **custom** role instead.
  </Step>

  <Step title="Decide whether you need apply-approver identity">
    Recording **who confirmed each apply** needs HCP Terraform **Standard or
    Premium** plus a separate organization or audit-trail token. On the Free
    plan, or without that token, Keldyn still evidences that applies were
    gated and confirmed; approver identity comes from the code platform
    instead. Terraform Enterprise does not expose the organization audit-trail
    API.
  </Step>

  <Step title="Keldyn only ever reads">
    The connector uses a runs-and-outputs-only team token. Keldyn never
    applies runs, overrides policies, locks workspaces, or reads state or
    variable values.
  </Step>
</Steps>

## Set up the integration

Do the Terraform Cloud work first, then paste the results into Keldyn.

### 1. Create the team and custom role in Terraform Cloud

<Steps>
  <Step title="Create a team">
    In [HCP Terraform](https://app.terraform.io), open **Organization
    settings → Teams** (or use [Teams](https://app.terraform.io/app/settings/teams))
    and create a team named something stable, such as `KeldynEvidence`.
  </Step>

  <Step title="Grant a custom workspace role">
    On each workspace you want evidenced — or on a project that covers those
    workspaces — open **Settings → Team access**, add `KeldynEvidence`, and
    choose **Custom** permissions:

    | Permission      | Setting               |
    | --------------- | --------------------- |
    | Run access      | **Read**              |
    | State access    | **Read outputs only** |
    | Variable access | **No access**         |

    Leave policy-override, lock/unlock, and admin permissions off. See
    HashiCorp's [custom workspace
    permissions](https://developer.hashicorp.com/terraform/cloud-docs/users-teams-organizations/permissions/workspace)
    for the official definitions.
  </Step>

  <Step title="Create a team token">
    Open the same team → **API tokens → Create a team token**. Copy the token
    immediately — you will not see it again. That is **Team token** in Keldyn.

    Do not paste a **user token**. User tokens inherit that person's full
    access and are the wrong identity for a connector.
  </Step>
</Steps>

<Warning>
  If you accidentally create a token that can read state (the built-in Read
  role, or a user token), revoke it in Terraform Cloud and start again with
  the custom role above. Keldyn will not call state endpoints, but a leaked
  over-privileged token still could.
</Warning>

### 2. Optional: create an audit-trail token

Skip this if you are on the Free plan or do not need apply-approver identity
from Terraform Cloud.

<Steps>
  <Step title="Confirm the plan">
    The organization must be on HCP Terraform **Standard or Premium**. Free
    does not keep an organization audit trail.
  </Step>

  <Step title="Create the token">
    Open **Organization settings → API tokens**. Create either an
    **organization token** or a purpose-built **audit trail token**. Team
    tokens and user tokens cannot call the audit-trail API.
  </Step>
</Steps>

Terraform retains **fourteen days** of audit events. Keldyn accumulates those
events across nightly refreshes so a longer audit period can still be shown.

### 3. Connect in Keldyn

<Steps>
  <Step title="Open Integrations">
    In the Keldyn web app, go to **Integrations** and select **Terraform
    Cloud**.
  </Step>

  <Step title="Paste the connection details">
    Enter:

    1. **Organization name** — the HCP Terraform organization slug (for
       example `acme-corp`), not the display name.
    2. **Team token** — the runs-and-outputs-only token from step 1.
    3. **Audit-trail token (optional)** — the organization or audit-trail
       token from step 2, if you have one.
  </Step>

  <Step title="Connect">
    Select **Connect**. Keldyn checks that the team token can read the
    organization. Tokens are stored encrypted and never shown again.
  </Step>

  <Step title="Run the first sync">
    Select **Sync now** to pull evidence immediately, or wait for the
    scheduled refresh. The **Controls covered** and **Evidence sources**
    tables then show what was collected and how fresh it is.
  </Step>
</Steps>

<Tip>
  From the integration detail page, **Controls covered** shows whether
  Terraform Cloud is actively feeding each control and whether the control is
  satisfied. **Evidence sources** shows each data fetch, the controls it
  covers, and its freshness.
</Tip>

## What data Keldyn collects and why

Keldyn requests **read-only** access and collects only the data needed to build control evidence. State files, variable values, and plan JSON are never read.

| Data collected               | What it contains                                                                                                       | Why Keldyn collects it                                                                                                                                             | Refresh |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
| **Workspace apply gating**   | Each workspace's auto-apply setting, execution mode, and VCS connection                                                | Shows whether applies require a confirmation instead of applying automatically                                                                                     | Daily   |
| **Run and apply history**    | Recent runs and applies: status, planned/confirmed/applied timestamps, who created the run, and resource-change counts | Evidences that infrastructure changes went through a gated pipeline run before apply                                                                               | Daily   |
| **Policy-check results**     | Sentinel and OPA policy-check / policy-evaluation results on applied runs (pass, soft-fail, hard-fail, or override)    | Evidences that infrastructure changes were tested against policy before apply                                                                                      | Daily   |
| **Organization audit trail** | Who confirmed each apply, when, and which run (Standard or Premium only)                                               | Supporting evidence for who authorized the change. Without this token, the source is marked **Access required** and approver identity comes from the code platform | Daily   |

<Note>
  A workspace with auto-apply enabled, an apply with no confirmation
  timestamp, or an applied run with no policy check is recorded as real
  (unfavorable) evidence rather than a sync failure — that is what surfaces
  as a gap on the matching control.
</Note>

### Authentication

Keldyn authenticates with the **team token** you paste (and, optionally, a
separate audit-trail token). Both are stored encrypted. The UI only ever
shows `[redacted]`.

| Token                             | Required | Used for                                                   |
| --------------------------------- | -------- | ---------------------------------------------------------- |
| Team token                        | Yes      | Organization, workspaces, runs, applies, and policy checks |
| Organization or audit-trail token | No       | Organization audit trail only                              |

Disconnecting in Keldyn does not revoke the tokens. Rotate or delete them in
Terraform Cloud yourself.

## Troubleshooting "Access required"

A control or evidence source shows **Access required** when Keldyn cannot
read the matching data. Common causes include:

* The team token cannot see the organization, or was revoked.
* The custom role is not assigned on any workspace, so there is nothing to
  evidence.
* The **audit-trail** source is blocked because no organization / audit-trail
  token was provided, the organization is on the Free plan, or that token
  cannot read the trail. Workspace and policy evidence still refresh.
* A newly pasted audit-trail token was a user or team token (`401`). Create
  an organization or audit-trail token instead.

Controls not affected by the gap keep refreshing normally. After you fix
access, run **Sync now** again.

If the **team** token is rejected (`401`), Keldyn marks the connection
**Reauth required**. Create a new team token on the same team and use
**Update credentials**. Leave the audit-trail field blank so the stored
audit-trail token is kept — Keldyn never echoes it back.

<Tip>
  Connecting on the Free plan with an audit-trail token still succeeds. That
  source stays **Access required** until you upgrade to Standard or Premium
  (or remove the unused token). The rest of the evidence is unaffected.
</Tip>

## Keeping evidence current

Keldyn refreshes Terraform Cloud evidence automatically each day. Evidence
that hasn't refreshed within its expected cadence is marked **stale**, and
failed pulls are marked **failed** so you can spot gaps. You can also trigger
an immediate refresh at any time with **Sync now**.

<Note>
  Terraform Cloud ages out run history, and the audit trail only retains
  fourteen days. Keldyn **accumulates** run, apply, policy-check, and
  audit-trail records rather than replacing them on each refresh, so a record
  captured while it was live stays available for an audit period longer than
  Terraform's own retention window. The first sync after connecting shows
  only what Terraform still holds.
</Note>

## Rotate tokens

| What changed                                       | What to do in Keldyn                                                                                                                                                              |
| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Team token expired, leaked, or rotated             | **Update credentials** with the organization name and the new team token. Leave **Audit-trail token** blank to keep the stored one. Revoke the old team token in Terraform Cloud. |
| Audit-trail token rotated                          | **Update credentials** and paste the new organization or audit-trail token.                                                                                                       |
| Token with state-read access was pasted by mistake | Revoke it in Terraform Cloud immediately, then reconnect with a runs-and-outputs-only team token.                                                                                 |

## Next steps

<CardGroup cols={2}>
  <Card title="Evidence & audits" icon="clipboard-check" href="/evidence-and-audits" arrow={true}>
    Learn how automated integration evidence works alongside manual evidence
    and audits.
  </Card>

  <Card title="GitHub" icon="github" href="/integrations/github" arrow={true}>
    Connect the code platform for pull-request approvals and application-code
    test results that complete the change-management picture.
  </Card>
</CardGroup>
