Terraform

Terraform Provider Authentication Patterns: Env Vars, Shared Profiles, and OIDC

2026-04-19
NicheeLab Editorial Team

Authentication in Terraform is implemented per Provider, and the precedence rules and supported variables differ from one Provider to the next. Exams test whether you can match the right pattern to the right scenario and pick a design that automates safely.

This article focuses on AWS, Azure, and GCP, comparing three families of patterns — environment variables, shared profiles, and OIDC (federation) — and lays out guidelines for running them reliably in both CI/CD and local development.

Provider Auth Principles and Precedence

Terraform core has no authentication of its own. Each Provider implements its own credential search order (precedence). Most official Providers look in roughly this order — explicit config → environment variables → shared profile / CLI auth → instance metadata — but the exact order and supported keys vary by Provider.

For the exam, anchor on four points: explicit provider-block configuration wins, environment variables fit CI/CD, shared profiles / CLIs are easiest for local development, and production automation should lean on OIDC/federation with short-lived credentials. Check each Provider's official documentation for the fine print on precedence.

  • Explicit config takes precedence (e.g., client_id / role_arn in the provider block)
  • Environment variables work well in non-interactive / container environments (CI/CD-friendly)
  • Shared profiles / CLIs are convenient for local development (e.g., ~/.aws/credentials, gcloud ADC, az login)
  • Metadata / IMDS is the fallback when the runtime itself sits inside the cloud
  • Precedence varies by Provider, so verify it before locking in your design

Minimal configuration (delegating to the existing auth chain)

terraform {
  required_providers {
    aws = { source = "hashicorp/aws" }
  }
}

provider "aws" {
  # Resolved via credentials / profile / env / IMDS
  region = var.region
}

Environment Variable Pattern (Works for Local and CI)

Environment variables are the go-to for non-interactive environments and play nicely with CI/CD. Use access keys or temporary tokens on AWS, ARM_* variables on Azure, and ADC on GCP (with GOOGLE_APPLICATION_CREDENTIALS pointing at the credentials JSON, including external account files). Avoid dropping long-lived keys in raw, and prefer short-lived credentials (session tokens) when you can.

Keep the provider block minimal on the Terraform side and let environment variables fill in the rest — that's the standard playbook. Missing variables surface as auth errors during init, so manage masking, permission scope, and expiry together in your CI.

  • AWS: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_REGION
  • AzureRM: ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_TENANT_ID, ARM_SUBSCRIPTION_ID
  • GCP: GOOGLE_APPLICATION_CREDENTIALS (path to a JSON file; external-account JSON also supports WIF)
  • Avoid long-lived keys; design around short-lived, rotating credentials

Environment variable examples (macOS/Linux) and minimal provider blocks

# AWS (short-lived session example)
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...
export AWS_REGION=ap-northeast-1

# Azure
export ARM_CLIENT_ID=00000000-....
export ARM_TENANT_ID=11111111-....
export ARM_SUBSCRIPTION_ID=22222222-....
export ARM_CLIENT_SECRET=...   # Migrate to OIDC if possible

# GCP (ADC)
export GOOGLE_APPLICATION_CREDENTIALS=$HOME/.config/gcloud/application_default_credentials.json
# Or a path to an external-account JSON (WIF)

# Keep Terraform-side provider blocks minimal
provider "aws" { region = "ap-northeast-1" }
provider "azurerm" { features {} }
provider "google" { project = var.project region = var.region }

Shared Profile / CLI Pattern (Best for Local, Easy to Learn)

For local development, shared profiles and CLI logins are practical. AWS leans on profiles in ~/.aws/credentials and ~/.aws/config, Azure on tokens from az login (device code / browser), and GCP on ADC created by gcloud auth application-default login.

Do not carry these straight into CI — switch to OIDC / short-lived credentials there instead. Exams frequently ask whether you can split responsibilities along the same line: profiles for local, OIDC for CI.

  • AWS: provider "aws" { profile = "dev" } reads from shared credentials
  • GCP: ADC is consulted in priority order (GOOGLE_APPLICATION_CREDENTIALS → gcloud ADC → metadata)
  • Azure: once az login has run, Managed Identity / CLI auth can act as a fallback

Example: AWS shared profile and GCP ADC

# ~/.aws/credentials
[dev]
aws_access_key_id=AKIA...
aws_secret_access_key=...

# ~/.aws/config
[profile dev]
region=ap-northeast-1

# On the Terraform side
provider "aws" {
  profile = "dev"
  region  = "ap-northeast-1"
}

# GCP (ADC) setup command (local development)
# gcloud auth application-default login
# → provider "google" auto-detects ADC

OIDC / Federation (The CI/CD Standard — Zero Long-Lived Secrets)

OIDC / federation is the baseline for safe authentication from CI/CD. You hold no long-lived secrets — the workflow mints an OIDC token at run time, and the cloud-side trust relationship promotes it to temporary credentials. AWS uses sts:AssumeRoleWithWebIdentity, Azure uses Entra ID Federated Identity Credentials, and GCP uses Workload Identity Federation (external_account JSON).

The Terraform provider block can stay minimal — environment variables plus cloud-side role / identity configuration usually cover it. The classic failure modes are mismatched trust-policy conditions (audience, issuer, sub) and expired tokens.

  • AWS: AWS_ROLE_ARN plus AWS_WEB_IDENTITY_TOKEN_FILE (or SDK auto-detection)
  • Azure: create a Federated Identity in Entra ID; authenticate with client ID / tenant ID and the OIDC token
  • GCP: point GOOGLE_APPLICATION_CREDENTIALS at the external_account JSON (or rely on the ADC chain)
  • OIDC assumes least-privilege roles backed by conditional trust

OIDC flow from CI (conceptual)

 [CI/CD Job]
      |
      | 1. Request (aud, sub, repo info)
      v
 [OIDC Provider] ---- 2. Issues OIDC token ---->
      |
      | 3. Presents token (Assume / Exchange)
      v
 [Cloud STS/Identity] -- 4. Issues short-lived creds --> [Provider SDK]
      |
      v
 [Terraform Apply]

Minimal AWS example (GitHub Actions OIDC)

# Sketch of the key parts in GitHub Actions. Prefer the official action in real use.
# permissions: id-token: write is required

# Set env inside the job (the token is provided as a file path)
# AWS_ROLE_ARN=arn:aws:iam::123456789012:role/gha-oidc-role
# AWS_WEB_IDENTITY_TOKEN_FILE=/path/to/gha/oidc-token
# AWS_REGION=ap-northeast-1

provider "aws" {
  region = "ap-northeast-1"  # Auth is fully handled via env vars
}

Practical Selection Criteria for CI/CD Design

OIDC / federation is the first choice when measured against security (no long-lived secrets), least privilege, automatic rotation of short-lived credentials, and easy re-runs on failure. The exception is when the target cloud or runtime does not yet support OIDC — only then should you fall back to short-lived keys passed as environment variables as a stopgap.

Even on Terraform Cloud / Enterprise, inject variables safely as environment variables from the VCS / workspace side and flag secrets as Sensitive.

  • Rule of thumb: OIDC in CI, profiles / CLIs locally, short-lived keys only in emergencies
  • Trace issues through the Provider's DEBUG logs (TF_LOG=DEBUG)
  • Swapping region / project / tenant IDs is the classic rookie mistake
PatternSecurityExpiry / RotationLocal Fit
Env vars (long-lived keys)Low (leak risk, weak rotation)Fixed (manual rotation)OK (simple)
Shared profile / CLIMedium (depends on host hygiene)Medium (CLI refresh)High (easy to use)
OIDC / federationHigh (zero long-lived secrets)Short-lived (auto-issued)Medium (reproducing locally takes effort)

Typical environment variables on Terraform Cloud (example)

# Set as workspace variables (mark as Sensitive)
# AWS OIDC example (in practice these come from the VCS / runtime)
AWS_ROLE_ARN=arn:aws:iam::123456789012:role/tfc-oidc-role
AWS_WEB_IDENTITY_TOKEN_FILE=/workspace/oidc/token
AWS_REGION=ap-northeast-1

Exam Focus and Troubleshooting

Common exam topics: understanding the credential search order, the exact environment-variable names, switching the design between local and CI, matching OIDC trust conditions (issuer, audience, subject), and refreshing short-lived credentials. On multiple-choice, any option that says 'store the long-lived secret' is almost always wrong.

In practice, the first move is to run the provider with minimal config and check which credential the DEBUG log selects. Then move to CI and shape the cloud-side role and trust so OIDC produces the same behavior.

  • Use TF_LOG=DEBUG to inspect the SDK's credential resolution
  • On AWS, audit the sts:AssumeRoleWithWebIdentity policy conditions
  • On Azure, create Federated Identity Credentials in Entra ID scoped correctly
  • On GCP, double-check audience / subject_token_type in the external_account JSON
  • ExpiredToken, AccessDenied, and 'configuration not found' are the first clues

Example: AWS shared profile + AssumeRole (privilege elevation from local)

provider "aws" {
  profile = "dev"
  region  = "ap-northeast-1"
  assume_role {
    role_arn     = "arn:aws:iam::123456789012:role/admin"
    session_name = "tf-local-dev"
  }
}

Check Your Understanding

Associate / Pro

問題 1

You run Terraform against AWS from GitHub Actions. You want to avoid long-lived access keys and grant least-privilege, short-lived credentials per run. Which configuration is most appropriate?

  1. Use OIDC so GitHub calls sts:AssumeRoleWithWebIdentity, and pass AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE via env vars
  2. Store AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY in repo Secrets and reuse them across every job
  3. Issue custom tokens from a self-built auth server and feed them to Terraform
  4. Run apply by hand from a machine where az login has already succeeded

正解: A

OIDC / federation is the recommended way to obtain least-privilege, short-lived credentials from CI/CD without storing long-lived secrets. On AWS, use AssumeRoleWithWebIdentity and pass the role ARN and the OIDC token file via environment variables. Storing long-lived keys or running by hand is not appropriate.

Frequently Asked Questions

What information do I need to use OIDC with AzureRM?

Configure Federated Identity Credentials on Entra ID and prepare the workload's client ID (app registration), tenant ID, and subscription ID. The CI hands over an OIDC token, and the Provider authenticates via environment variables (e.g., ARM_CLIENT_ID, ARM_TENANT_ID, ARM_SUBSCRIPTION_ID together with the OIDC token). Follow the documentation that matches your Provider version for exact details.

How do I use GCP OIDC (Workload Identity Federation) with Terraform?

Create an external_account-style credentials JSON file and point GOOGLE_APPLICATION_CREDENTIALS at its path. The Terraform Google Provider picks up that external account through the ADC chain and impersonates a service account when needed.

How do I diagnose auth failures caused by credential precedence?

Run with TF_LOG=DEBUG and inspect which credential source (explicit config, environment variable, shared profile, metadata) was actually picked. In parallel, work through the usual suspects: swapped environment variables (region/project/tenant ID), expired credentials, and mismatched trust conditions.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
Terraform

HCL Syntax: Terraform's Configuration Language (2026)

HCL2 fundamentals for Terraform — blocks, attributes, expres...

Terraform

Terraform Authoring & Operations Pro: Complete Guide (2026)

Tactics for the Terraform Pro exam — module authoring, works...

Terraform

Terraform Providers: Plugin Management Fundamentals (2026)

Provider mechanics — required_providers, versions, mirrors, ...

Terraform

Terraform Resource Blocks: Declarative Infra Units (2026)

Resource block fundamentals — addresses, references, common ...

Terraform

Terraform Data Sources: Read-Only External Data (2026)

Data source basics — declaration, refresh behavior, dependen...

Browse all Terraform articles (102)
© 2026 NicheeLab All rights reserved.