Provider Configuration and Aliases
A provider block configures how Terraform talks to a platform. For AWS that means the region it operates in, where it gets credentials, and the tags it stamps on everything it creates. One block is enough for a single-region, single-account project — but real estates are neither.
Aliases are how one configuration uses the same provider several ways at once: two regions, or two accounts, in a single apply. Every multi-region disaster-recovery setup and every cross-account Terraform run is built on this one mechanism. Get aliases right and the rest of multi-target Terraform is just plumbing.
The Basic Provider Block
The default provider block names the platform and sets its region. The interesting argument is default_tags: every resource this provider creates inherits these tags automatically, so you stamp ownership, cost center, and environment once instead of repeating a tag map on a hundred resources. The credentials are deliberately absent — they come from the environment, a named profile, or an assumed role, never from the block itself.
provider "aws" { region = "us-east-1" default_tags { tags = { Environment = "prod" ManagedBy = "terraform" Team = "platform" } } }
Aliased Providers
Give a second provider block an alias and you have a named, independent configuration of the same provider. A resource opts into it with the provider meta-argument; without that line, the resource lands on the default provider. The bucket below is created in us-west-2 only because it points at aws.us_west — drop that one line and it silently goes to us-east-1 instead.
provider "aws" { region = "us-east-1" } provider "aws" { alias = "us_west" region = "us-west-2" } resource "aws_s3_bucket" "dr_logs" { provider = aws.us_west bucket = "my-app-dr-logs-7f3a" }
Passing Providers Into Modules
A module uses the default provider unless you hand it a different one. The providers argument in the module block maps the module's provider name to the aliased configuration you want it to use, so a single module call can deploy into a specific region or account. This is how a reusable "regional stack" module gets pointed at us-west-2 without the module itself knowing which region it runs in.
module "dr_stack" { source = "./modules/regional-stack" providers = { aws = aws.us_west } }
Default Tags and assume_role
Two provider-level settings carry most of the operational weight. default_tags applies a tag map to every resource, which is how a whole organization gets consistent cost and ownership tags without trusting each author to remember them. assume_role tells the provider to assume an IAM role before doing anything, which is the foundation of cross-account management: a provider in your tooling account assumes a role in a workload account and manages its resources from there.
provider "aws" { alias = "workload" region = "us-east-1" assume_role { role_arn = "arn:aws:iam::222233334444:role/TerraformExec" session_name = "terraform-prod" } }
One caveat on tags: default_tags covers tags Terraform sets, but if a resource sets the same tag key directly, the resource's value cleanly overrides the provider default for that key (it shows up in tags_all) — there is no perpetual diff. The genuine trap is a tag an outside system mutates out of band, which surfaces as drift, so decide where each tag comes from and keep it in one place.
One Version, Many Configurations
A common misconception is that aliases let you run two different versions of the AWS provider side by side. They do not. A configuration resolves exactly one version of the AWS provider for the whole run; aliases give you multiple configurations of that one version — different regions, accounts, or assumed roles — not different binaries. If you genuinely need two provider versions, that is a state-splitting problem, not an alias problem.
- Defining an aliased provider but forgetting
provider = aws.aliason the resource — it silently uses the default provider, so the resource lands in the wrong region or account with no error. - Putting
access_keyandsecret_keydirectly in the provider block, committing permanent credentials to git instead of using the environment, a profile, or an assumed role. - Calling a module that operates in a specific region without passing the aliased provider, so the module uses the default provider and deploys into the wrong place.
- Assuming a resource cannot override a default tag — in fact a tag set on the resource wins over
default_tagsfor the same key, so the override is silent, not a conflict. - Assuming an alias can pin a second provider version side by side — one configuration resolves a single AWS provider version, and aliases only vary its configuration.
- Set
default_tagsat the provider level for consistent org-wide tagging, so ownership and cost tags exist on every resource without per-resource effort. - Keep credentials out of the provider block entirely; rely on the environment, named profiles, or
assume_roleso nothing secret reaches version control. - Pass aliased providers explicitly with the
providersargument into any module that must run in a specific region or account. - Name aliases for their purpose —
us_west,audit_account— so everyprovider = aws.audit_accountline reads as documentation. - Use one
assume_roleprovider per target account rather than juggling multiple credential profiles, keeping cross-account intent visible in the config.
Knowledge Check
What does a provider alias let you do?
- Use the same provider in multiple configurations — two regions or accounts — within one apply
- Run two different versions of the AWS provider side by side in one configuration
- Cache the provider's downloaded plugin binaries across configurations so that a subsequent init runs faster
- Encrypt the static credentials stored directly in the provider block
You define an aliased aws.us_west provider but a resource has no provider argument. What happens?
- It uses the default provider, landing in the default region rather than us-west-2
- Terraform halts with an error because the provider alias is ambiguous
- It is created in both the default and aliased regions to be safe
- Terraform picks one alias at random from among all the provider blocks defined in the configuration
How does a module use a non-default provider configuration?
- The caller passes it with the
providersargument in the module block - The module declares its own credentials in a nested provider block
- It silently inherits whichever provider alias was defined last in the file
- Modules always run on the default provider and cannot be retargeted
What is the effect of default_tags on the provider?
- Every resource the provider creates inherits the tag map automatically
- It records the tags only in the state file, not on the real resources themselves
- It overrides any tag a resource sets directly, with no conflict possible
- It applies tags only to resources that omit their own tags block
You got correct