Terraform

Terraform AWS Provider: Key Patterns for the Associate Exam

2026-04-19
NicheeLab Editorial Team

The AWS Provider is by far the most-used Terraform provider. Whether you are preparing for the exam or building real infrastructure, credential precedence, assume_role, and region splitting via aliases are must-know fundamentals.

This article follows the behavior documented by HashiCorp and walks through the Associate-level talking points with minimal code and concrete examples.

AWS Provider Basics and Version Pinning

Declare the AWS Provider in required_providers and pin its version per project. Major upgrades can introduce breaking changes, so using the ~> operator to track minor and patch versions safely is the standard pattern.

Region resolves in this order: provider argument, then environment variables (AWS_REGION / AWS_DEFAULT_REGION), then the shared config file (~/.aws/config). Setting it explicitly on the provider removes ambiguity. default_tags has been stable since v5 and is a clean way to attach common tags across every resource (when a resource defines the same key in its own tags, the resource-level value wins).

  • Pin the version with ~> (e.g. ~> 5.0). Commit .terraform.lock.hcl to VCS as well.
  • The provider argument always wins for region. When in doubt, set it explicitly on the provider.
  • Use default_tags as the baseline policy for every resource and express exceptions by splitting providers.

Minimal configuration (version pin + common tags)

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"

  default_tags {
    tags = {
      Project     = "nicheelab"
      Environment = "dev"
    }
  }
}

Authentication Methods and Precedence (a Common Exam Trap)

The AWS Provider resolves credentials using the AWS SDK default credential chain. When multiple methods are configured at once, explicit provider settings come first, followed by environment variables, then shared profiles, and finally runtime roles (EC2 / ECS). If Web Identity (OIDC) environment variables are present, they take precedence as environment-variable credentials.

The exam frequently asks which method actually gets used. The classic gotcha: even if you set profile on the provider, environment variables set in CI take precedence over it.

  • Explicit static credentials have the highest priority but are discouraged in production.
  • Environment variables are easy to use in CI/CD and have high precedence.
  • Profiles pair well with manual runs and SSO. They become active after aws sso login.
  • Runtime roles (EC2 / ECS) are the last fallback and resolve automatically.
MethodDeclaration / SettingPriority (high → low)Typical use case and notes
Explicit static credentialsprovider aws { access_key/secret_key/token }1For testing only. Never commit secrets to code.
Environment variables (static / session)AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN2Common in CI/CD. Takes precedence over profile settings.
Environment variables (Web Identity / OIDC)AWS_ROLE_ARN / AWS_WEB_IDENTITY_TOKEN_FILE2EKS ServiceAccount and similar setups. No assume_role block required.
Shared profileprovider aws { profile = "xxx" } + ~/.aws/{config,credentials}3Developer machines and SSO. credential_process and source_profile are also resolved.
Runtime roleEC2 Instance Profile / ECS Task Role4Used automatically when nothing else is configured. Stick to least privilege.

Examples for environment variables and profiles

# 環境変数で認証(推奨: CI/CD)
# export AWS_ACCESS_KEY_ID=AKIA...
# export AWS_SECRET_ACCESS_KEY=...
# export AWS_REGION=ap-northeast-1
provider "aws" {}

# 共有プロファイルで認証(ローカル/SSO)
provider "aws" {
  profile = "sandbox"
  region  = "ap-northeast-1"
}

Multi-Account and Role Assumption (assume_role)

In a multi-account setup, the standard pattern is to start from a source credential (profile or environment variables) and assume a role in the target account via assume_role. Configure external_id and session_name to match your audit and integration requirements.

assume_role is specified as a block inside the provider. The deeper the chain gets, the harder it is to debug, so stick to a single hop whenever possible and keep the trust policy and required permissions clearly scoped to the minimum.

  • Use long-lived credentials or SSO on the source side, and a least-privilege role on the target side.
  • Handle external_id according to your security requirements.
  • Keep session duration as short as practical.

Typical assume_role flow (cross-account)

Account ASource / User / Profile / SSOAccount BTarget / IAM Role: TerraformRole1) sts:AssumeRole2) Issue temporary credentials3) Call AWS APISource → Target AssumeRole, then call the AWS API with the temporary credentials

assume_role configuration on the provider

provider "aws" {
  profile = "platform"   # source資格情報(共有プロファイル)
  region  = "ap-northeast-1"

  assume_role {
    role_arn     = "arn:aws:iam::222222222222:role/TerraformRole"
    session_name = "tf-apply"
    external_id  = "nicheelab-ci"
    duration     = "3600s"
  }
}

# 以降のリソースは上記ロール経由で作成される

Multiple Providers, Aliases, and Splitting by Region

Most AWS services are region-scoped. In Terraform you can attach an alias to a provider and split things explicitly by region or account, which makes plans more readable and safer. Specifying provider on each resource prevents accidental creation in the wrong place.

Some resources, like IAM and parts of Route 53, are global and largely unaffected by region settings. Check the docs for the target region or partition so you are not surprised by plan-vs-apply differences.

  • An alias is the switch you flip to change region or account.
  • Reference the alias from each resource to avoid creating things in the wrong region.
  • It is safer not to mix multiple accounts in a single State file.

Example: per-region alias usage

provider "aws" {
  alias   = "tokyo"
  region  = "ap-northeast-1"
  profile = "prod"
}

provider "aws" {
  alias   = "virginia"
  region  = "us-east-1"
  profile = "prod"
}

resource "aws_s3_bucket" "logs_tokyo" {
  provider = aws.tokyo
  bucket   = "nicheelab-logs-apne1"
}

resource "aws_s3_bucket" "logs_virginia" {
  provider = aws.virginia
  bucket   = "nicheelab-logs-use1"
}

Common AWS Data Sources and Policy Generation

aws_caller_identity and aws_partition dynamically resolve the account ID and partition (aws / aws-cn / aws-us-gov), which is great for smoothing over environment differences. They let you write EKS and S3 ARNs in an environment-agnostic way.

aws_iam_policy_document is a data source that assembles JSON policies locally without any API calls. Diffs become clearer and it prevents the kinds of mistakes you get when hand-writing JSON.

  • Use data.aws_caller_identity.current.account_id to reference the account.
  • Use data.aws_partition.current.partition to handle partition differences in ARNs.
  • Generate policy JSON safely with aws_iam_policy_document.

Generate an IAM policy with data sources

data "aws_caller_identity" "current" {}

data "aws_partition" "current" {}

data "aws_iam_policy_document" "s3_readonly" {
  statement {
    actions   = ["s3:GetObject", "s3:ListBucket"]
    resources = [
      "arn:${data.aws_partition.current.partition}:s3:::nicheelab-data",
      "arn:${data.aws_partition.current.partition}:s3:::nicheelab-data/*"
    ]
  }
}

resource "aws_iam_policy" "s3_readonly" {
  name   = "S3ReadOnly"
  policy = data.aws_iam_policy_document.s3_readonly.json
}

Best Practices that Pay Off in Both Production and the Exam

Never hardcode credentials. Use environment variables, shared profiles, or assume_role instead. Split State along account and region boundaries and switch explicitly with aliases.

To keep dependencies reproducible, pinning the provider version and tracking .terraform.lock.hcl are non-negotiable. Plan upgrades deliberately: read the breaking-change notes first, then run terraform init -upgrade.

  • Use env / profile / SSO combined with assume_role for credentials. Never hardcode static keys.
  • Split State by boundary. Workspaces are not a substitute for true boundary separation.
  • Apply common tags via default_tags and express exceptions by splitting providers.
  • Track the provider version and lock file in VCS.

Provider version pinning and lock file workflow

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.50"
    }
  }
}

# 初回: terraform init
# アップグレード時: terraform init -upgrade
# .terraform.lock.hcl はVCSで管理する

Check Your Understanding

Associate

問題 1

In CI, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are set as environment variables, while the Terraform provider "aws" block specifies profile = "sandbox". Which credentials does terraform apply actually use?

  1. The environment variable credentials win
  2. The profile specified on the provider wins
  3. Neither is used; the instance profile or task role of the runtime is used
  4. The profile and environment variables are merged

正解: A

The AWS Provider resolves credentials in this order: explicit settings > environment variables > shared profile > runtime role. Here, the provider has no explicit static credentials, and environment variables outrank the shared profile — so the environment variables are used.

Frequently Asked Questions

If default_tags and resource tags conflict, which one wins? Can I disable default_tags for a specific resource?

When the same key is set in both, the resource-level tags win. There is no explicit switch to turn off default_tags for a single resource. If you really need to exclude one, the safest pattern is to define a separate provider (with a different alias) that has no default_tags and use it for the exception.

How do I use AWS SSO with Terraform?

Configure an SSO profile in ~/.aws/config with AWS CLI v2, then run aws sso login to authenticate. On the Terraform side, you only need provider aws { profile = "your-sso-profile" } — the SSO credentials resolve from the shared config automatically.

What is the region resolution order? What if both provider.region and AWS_REGION are set?

Region is resolved in this order: provider argument > environment variables (AWS_REGION / AWS_DEFAULT_REGION) > shared config file. If both are set, the provider argument wins.

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.