An HCP Terraform organisation can change every cloud account it is connected to, so its tokens, workspace permissions, state files and stored provider credentials are as sensitive as cloud administrator access itself. Terraform Cloud was renamed HCP Terraform on 22 April 2024 with the same features; Terraform Enterprise is its self-hosted distribution, and HashiCorp has been part of IBM since February 2025. This guide covers the permission model, the five token types, OIDC dynamic provider credentials, agents, state access, policy enforcement with Sentinel and OPA, and audit trails. It is for platform and cloud security engineers who run or review an HCP Terraform or Terraform Enterprise estate. Terraform releases since August 2023 use the Business Source License 1.1; OpenTofu, a Linux Foundation fork, shares the language but not the HCP Terraform control plane described here.
Key takeaways
- Remove static cloud keys from workspaces. Dynamic provider credentials issue a per-run OIDC token that AWS, Azure, Google Cloud, Vault and Kubernetes exchange for temporary credentials, discarded when the run ends.
- Trust policies must name your organisation. The workload identity token's
subincludes organisation, project, workspace and run phase; a trust policy that does not check at leastaudand the organisation name can be satisfied by any HCP Terraform customer. - State is a secrets store. Full state read access exposes resource attributes, often including generated passwords and keys, so most consumers should get "Read outputs only" or no access.
- Permissions are additive across scopes. A team's effective access is the union of organisation, project and workspace grants, so "Manage all workspaces" at organisation level silently overrides a Read role on one workspace.
- VCS access is apply access. Anyone who can merge to a VCS-connected workspace's branch can trigger runs, and with auto apply those runs change infrastructure without a human approval.
How identity and access work in HCP Terraform
HCP Terraform has users, teams and organisations. Users sign in with HCP Terraform or HCP credentials or through SAML single sign-on; teams receive permissions; organisations hold projects, workspaces, Stacks, variable sets, policy sets, agent pools and the private registry. HCP Europe organisations manage access through HCP groups and roles instead of teams.
Single sign-on and team mapping
- Supported identity providers: Microsoft Entra ID, Okta and generic SAML. The SAML NameID must be an email address.
- Enforcement: once SSO is on, non-owner members must authenticate through the IdP before reaching projects, workspaces and managed resources. Account settings are not covered by SSO, so enable two-factor authentication for HCP Terraform credentials as well.
- Team management: HCP Terraform reads the SAML attribute
MemberOf(configurable), adds users to teams with exactly matching, case-sensitive names, and removes them from teams absent from the assertion. It cannot place users in theownersteam, which stays manually managed. - Owner bypass: owners can still sign in with HCP Terraform or HCP credentials if the IdP fails. HashiCorp recommends creating two break-glass owner accounts before enabling SSO; protect them as you would cloud root accounts. See the Break-Glass Account Guide.
Scopes and workspace roles
Permissions can be granted at organisation, project and workspace level and combine additively. Workspace fixed roles are:
| Role | Runs | Variables | State | Other |
|---|---|---|---|---|
| Read | View runs and logs | Read | Read | View configuration |
| Plan | Queue plans; applies need approval | Read | Read | Comment on runs |
| Write | Plan and apply | Read and write | Read and write | Lock and unlock, download Sentinel mocks |
| Admin | Plan and apply | Read and write | Read and write | Workspace settings, team access, deletion |
Custom workspace roles combine any non-admin permission. The state permission has four levels: No access; Read outputs only (enough for terraform output, the state outputs API and terraform_remote_state); Read (the full state file, which can contain sensitive data); and Read and write (create state versions, needed for local execution mode and terraform import or terraform state commands). Even the Read role sees full state, so build custom roles for reviewers who only need run logs. Sensitive variables are write-only and cannot be viewed by anyone after saving, but Sentinel mock data can contain unredacted sensitive values, so treat "Download Sentinel mocks" as a sensitive permission.
Admin roles and privileged access
The owners team holds admin rights on every project, workspace and Stack, and is the only team that can manage organisation settings, IP allowlists, billing and deletion of the organisation. Below it, organisation-level permissions create a set of quasi-admin roles that are easy to over-grant:
| Organisation permission | What it really allows | Risk if over-granted |
|---|---|---|
| Manage all workspaces | Admin on every workspace, manage variable sets | Read every state file and change credentials organisation-wide |
| Manage all projects | Create, edit and delete projects and team access to them | Grant itself or others access to any project |
| Manage teams / Manage membership | Create teams, generate team tokens, add users | Mint tokens for privileged teams |
| Manage policies | Edit policy sets | Weaken or remove guardrails before a malicious apply |
| Manage policy overrides | Override failed policy checks in all workspaces | Bypass soft-mandatory and mandatory controls |
| Manage version control settings | VCS providers and SSH keys | Point workspaces at a different repository or key |
| Manage agent pools | Create and delete pools | Route runs into a network segment they should not reach |
| Manage modules / providers (private registry) | Publish and delete registry artefacts | Supply chain tampering of shared modules |
- Keep owners small: two named break-glass accounts plus a very small platform group; day-to-day work belongs in scoped teams.
- Prefer project scope: grant teams project-level access and project-owned variable sets instead of organisation-wide permissions; organisation-owned variable sets apply across projects and need higher privilege.
- Separate policy authors from appliers: the team that can apply production should not also hold Manage policies or Manage policy overrides.
- Secret teams: the "Include secret teams" permission reveals teams hidden from normal members; grant it only to administrators who manage those teams.
- Member token management: "Allow member token management" is enabled by default, which lets team members create team tokens; disable it for privileged teams so tokens are created only by administrators.
Integrations, API tokens and service accounts
Token types
| Token | Scope | Can start runs | Limits and notes |
|---|---|---|---|
| User | The user's own permissions | Yes, if the user can | Tied to a person; required to connect a repository through the GitHub App; can be disabled per organisation |
| Team | The team's permissions; an owners team token carries owner rights | Yes, if the team can apply | Multiple tokens per team with descriptions; the preferred identity for CI/CD automation |
| Organisation | Create and configure workspaces and teams | No | One valid token per organisation, owners only; use for bootstrap, then delegate to team tokens |
| Audit trail | Read audit trail events | No | One per organisation; for SIEM integrations |
| Agent | Connect agents to one agent pool | No (not valid for the API) | Shown once; revoking makes connected agents exit |
- Lifetimes: user, team and organisation tokens have an expiry that cannot be changed after creation; owners can set a maximum token lifetime in organisation settings. HCP Terraform emails 30 and 7 days before expiry. Create tokens with the shortest practical lifetime and delete them when unused.
- Storage: tokens are shown once. Keep them in a secrets manager, never in repository files or
.terraformrcon shared hosts; the CLI credentials file (credentials.tfrc.json) written byterraform loginholds a user token in plain text. - Integration tokens: run task access tokens last 10 minutes. Bots and VCS integrations act with the access they were granted, so review the scopes of the VCS OAuth connection or GitHub App installation.
Dynamic provider credentials
For each plan and apply, HCP Terraform signs an OIDC workload identity token, the cloud verifies it against HCP Terraform's public signing key and returns temporary credentials, and the credentials are discarded with the run environment. Supported targets include AWS, Azure, Google Cloud, Vault, Kubernetes, HCP and Tencent Cloud; Vault can in turn broker AWS, Azure or Google Cloud credentials through its secrets engines.
- Token claims:
issis the instance URL (https://app.terraform.iofor HCP Terraform).subfollowsorganization:<org>:project:<project>:workspace:<workspace>:run_phase:<plan|apply>. Extra claims includeterraform_run_phase,terraform_workspace_id,terraform_organization_nameandterraform_project_name. Names can change; IDs are more stable. - AWS setup: create an IAM OIDC provider for
https://app.terraform.iowith audienceaws.workload.identity(or yourTFC_AWS_WORKLOAD_IDENTITY_AUDIENCE), then setTFC_AWS_PROVIDER_AUTH=trueandTFC_AWS_RUN_ROLE_ARNin the workspace or a variable set. The trust policy should checkapp.terraform.io:audwithStringEqualsandapp.terraform.io:subwith the full organisation, project and workspace path. - Separate plan and apply: use
TFC_AWS_PLAN_ROLE_ARNfor a read-only role andTFC_AWS_APPLY_ROLE_ARNfor the write role, withrun_phase:planandrun_phase:applyin the respective trust policies. A speculative plan from a pull request then cannot obtain write credentials. Equivalent variables exist for other targets, for exampleTFC_AZURE_PLAN_CLIENT_ID,TFC_GCP_PLAN_SERVICE_ACCOUNT_EMAILandTFC_VAULT_PLAN_ROLE. - Do not mix: remove static
AWS_ACCESS_KEY_IDstyle variables when dynamic credentials are on; they interfere and leave a long-lived key behind. Self-hosted agents need version 1.7.0 or later (1.12.0 for multiple provider configurations).
See the Workload Identity Federation Guide and the HashiCorp Vault Guide for the receiving side of this trust.
Agents and state sharing
- Agents: agents run in your network and need only outbound connectivity to HCP Terraform. Scope each agent pool to the workspaces, projects or Stacks that need it (with exclusions where useful), because by default any workspace allowed to use a pool runs code inside that network segment. Rotate agent tokens by issuing a new token, moving agents, then revoking the old one; token details show last use. Any credentials on the agent host (instance roles, mounted files) are available to every run on that pool. See the Network Segmentation Guide.
- Remote state sharing: new workspaces share state with no other workspace by default. Share with specific named workspaces rather than "all workspaces in the organisation". The
tfe_outputsdata source ignores remote state sharing controls and relies on the token's own permissions. - Variable sets: global variable sets apply to every current and future workspace and Stack; priority variable sets override more specific values but do not stop a configuration hard-coding a value, so enforce critical settings with policy checks or run tasks.
Logging and detection
The audit trails API (GET /organization/audit-trail) returns organisation events with actor, authentication type, impersonator, request ID and resource action. It accepts only an organisation or audit trail token, supports a since timestamp and paging with page[size] (default page of 1,000 events), and retains events for 14 days, so poll it continuously into a SIEM. It is available in HCP Terraform Standard and Premium editions, not in Terraform Enterprise, which has its own logging.
| Event or signal | Why it matters |
|---|---|
| Token creation for owners or privileged teams; new organisation token | Persistence through a long-lived automation credential |
| Changes to team membership, team organisation access or SSO settings | Privilege escalation or bypass of IdP control |
| Policy set edits, enforcement level downgrades, policy overrides | Guardrails weakened before or during a malicious change |
| Changes to VCS provider, workspace VCS branch, auto apply or execution mode | Redirecting runs or removing human approval |
| State version downloads or new state versions outside runs | Secret harvesting or tampering with recorded infrastructure |
| Variable or variable set changes on production workspaces | Credential swap or injection of a static key |
Cloud-side logs (for example AWS CloudTrail AssumeRoleWithWebIdentity) with unexpected sub values | Trust policy too broad, or misuse of a workspace identity |
Relevant ATT&CK techniques include T1552.001 Credentials In Files (state and CLI credentials files), T1078.004 Cloud Accounts, T1098.001 Additional Cloud Credentials and T1195.002 Compromise Software Supply Chain (poisoned modules or providers).
Metrics:
- Dynamic credential coverage: share of workspaces with cloud access that use dynamic provider credentials and hold no static cloud keys.
- Token hygiene: number of user, team and organisation tokens older than the maximum lifetime, or unused for 90 days.
- State exposure: count of teams with full state Read on production workspaces, and workspaces sharing state organisation-wide.
- Policy coverage: share of production workspaces under at least one mandatory policy set, and number of overrides per month.
- Owner count: members of the owners team (target: break-glass accounts plus a handful of named administrators).
Hardening baseline
- Identity: enable SAML SSO with team management, create two break-glass owner accounts first, require two-factor authentication, and configure IP allowlists where your edition offers them.
- Structure: one project per trust boundary (for example per environment or business unit), with teams granted at project level and organisation-wide permissions limited to the platform team.
- Credentials: move every workspace to dynamic provider credentials with separate plan and apply roles; delete static keys from workspace variables and variable sets; set a maximum token lifetime.
- Runs: disable auto apply on production; require apply approval from a different team than the authors; restrict VCS trigger patterns (for example
/**/*.tf) and protect the tracked branch in the VCS with required reviews. - Policy: attach Sentinel (advisory, soft mandatory, hard mandatory) or OPA (advisory, mandatory) policy sets stored in version control; use hard mandatory or mandatory for controls such as no public storage, required encryption and approved regions; set policy overrides to "No policy overrides" or delegate them to a small team.
- State: grant "Read outputs only" for cross-workspace consumption; share state only with named workspaces; mark sensitive outputs and prefer data sources over remote state. See the Infrastructure as Code Security Guide.
- Agents: scope pools, run agents on ephemeral hosts with no standing cloud credentials beyond what dynamic credentials provide, and rotate agent tokens.
- Supply chain: publish internal modules through the private registry, restrict who can publish, pin provider and module versions, and commit the dependency lock file.
- Logging: stream audit trails to the SIEM every few minutes given the 14-day retention, and correlate with cloud-side role assumption logs.
Rollout and rollback: pilot dynamic credentials on one non-production workspace with the static keys still present but unused, confirm in cloud logs that runs assume the new role, then remove the static keys. Enable new policy sets as advisory for two to four weeks, review failures, then raise them to mandatory. Rolling back is setting the level back to advisory or restoring the previous variable set; never roll back state versions without understanding the diff, since replacing state can orphan or duplicate resources.
Small versus large organisations: a small team on the Free or Standard edition can rely on SSO, project scoping, team tokens and dynamic credentials, with OPA or Sentinel where available. Large estates add Premium features such as policy evaluation inside self-managed agent pools, many scoped agent pools, separate organisations for regulated environments, or Terraform Enterprise where the control plane must be self-hosted.
Common misconfigurations
- Trust policy without the organisation. An IAM role trusting
app.terraform.iowith a wildcardsubcan be assumed from any HCP Terraform organisation. - One role for plan and apply. Speculative plans on pull requests then receive write credentials, so an untrusted change can run provider or external data source code with production rights.
- Static cloud keys in global variable sets. A single long-lived key reaches every workspace, current and future, and every person with Write on any of them. The Codecov breach showed how CI environment variables holding cloud keys and tokens are harvested in bulk once one step in the pipeline is compromised.
- Full state read for everyone. Read and Plan roles both include full state; reviewers and downstream workspaces usually need outputs only.
- Owners team as the working team. Large owners teams and owners team tokens in CI mean one leaked token controls the organisation, including policies and SSO.
- Auto apply on a weakly protected branch. Anyone who can merge changes production without review, which defeats approval and policy override controls.
Framework mapping
| Control area | NIST SP 800-53 Rev. 5 | NIST CSF 2.0 | ISO/IEC 27001:2022 Annex A |
|---|---|---|---|
| SSO, tokens, dynamic credentials | IA-5, IA-5(7) | PR.AA-01 | A.5.17 |
| Teams, scopes, owners | AC-6 | PR.AA-05 | A.8.2 |
| Policy sets, approvals, VCS protection | CM-3, CM-6 | PR.PS-01 | A.8.9, A.8.32 |
| State access and sensitive values | SC-28 | PR.DS-01 | A.8.24 |
| Audit trails and SIEM | AU-2 | PR.PS-04, DE.CM-09 | A.8.15 |
Practitioner checklist
- Confirm SSO with team management is on, the owners team is minimal, and two break-glass owners exist.
- Inventory all user, team and organisation tokens; set a maximum lifetime and revoke unused tokens.
- Move every cloud-connected workspace to dynamic provider credentials with separate plan and apply roles.
- Check every cloud trust policy for exact
audand an organisation-anchoredsub. - Remove static keys from workspace variables and global variable sets.
- Replace full state Read with "Read outputs only" where possible and restrict remote state sharing to named workspaces.
- Attach mandatory policy sets to production and restrict policy override permissions.
- Disable auto apply on production and protect the tracked VCS branch.
- Scope agent pools and rotate agent tokens.
- Stream audit trails to the SIEM and alert on token, team, policy and VCS changes.
Standards and references
- HashiCorp: Dynamic provider credentials
- HashiCorp: Workload identity tokens
- HashiCorp: HCP Terraform API tokens
- HashiCorp: Workspace permissions
- HashiCorp: Manage policy sets
- HashiCorp: Audit trails API
- HashiCorp: HCP Terraform single sign-on
- NIST: SP 800-53 Rev. 5
Related NHI Mgmt Group resources: Infrastructure as Code Security Guide · HashiCorp Vault Guide · Secrets Management Guide · CI/CD Security Guide · Okta Security Hardening Guide