













The value of using multiple providers in Terraform becomes clear when you hit real production infrastructure, where you suddenly need to deploy resources to two or more AWS regions, multiple cloud providers, or apply changes across a dev and a prod account in the same run.
There are two ways of using multiple providers in Terraform. One is combining completely different providers, and the other is running several configurations of the same provider.
They solve different problems, and you will end up using both when working with infrastructure at scale.
In this article, we will cover:
A provider is a plugin that lets Terraform interact with an API. The AWS provider talks to AWS, the Kubernetes provider talks to your cluster’s API server, and the random provider doesn’t talk to anything external at all; it just generates values locally.
You can use different Terraform providers in the same configuration. This can be useful for multi-cloud scenarios or when you simply want to leverage a particular service from a cloud provider, combining it with that provider’s offering. For example, leveraging the AWS provider to create an EKS cluster, then using the Kubernetes provider to deploy workloads into the same cluster, all in a single run, sharing the same state.
At the same time, you can use multiple instances of the same provider. When you need to declare the same provider more than once, each with different settings, use the alias meta-argument. In this case, you deploy to multiple regions or accounts within a single configuration.
Both cases live in the same place, in your root module, and they are very common on real infrastructure. Let’s explore each one of them with working examples.
In this case, you want to use two or more distinct providers in the same configuration because your infrastructure spans multiple platforms or services.
While this is optional, it’s good practice to declare every provider you need in the required_providers block within the terraform block. If you do this, Terraform will know which plugins to download and which version constraints to enforce.
After you add the providers in the required_providers block, you still need to declare them using a “provider” block. Each provider has its own arguments, so ensure you review the docs to understand how to configure them.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.30"
}
}
}
provider "aws" {
region = "eu-west-1"
}
data "aws_eks_cluster" "this" {
name = "eks"
}
data "aws_eks_cluster_auth" "this" {
name = "eks"
}
provider "kubernetes" {
host = data.aws_eks_cluster.this.endpoint
cluster_ca_certificate = base64decode(data.aws_eks_cluster.this.certificate_authority[0].data)
token = data.aws_eks_cluster_auth.this.token
}In this example, you are using two providers: one for AWS to manage the cloud infrastructure and another for Kubernetes to manage what runs in the cluster.
I used data sources from the AWS provider to point to an existing EKS cluster instead of creating one in the same config. You could’ve generated the provider from a resource as well, but the problem is that the provider might need its configuration values known at plan time, and those attributes aren’t known until the cluster is actually created.
This is why Terraform tends to break, and pointing a data source at an existing cluster avoids this, since the attributes are known up front. You could’ve, of course, done a terraform plan -target and include only the AWS resources for the first run as a workaround.
By specifying other resources, like in the example below, Terraform will know exactly to which provider to attribute them:
resource "aws_s3_bucket" "app_data" {
bucket = "my-app-data-bucket"
}
resource "kubernetes_namespace" "app" {
metadata {
name = "production"
}
}Using multiple instances of the same provider can help you manage resources in different cloud regions. By default, Terraform allows only one configuration per provider type. If you write two provider “aws” blocks with no distinction, Terraform throws an error, because it can’t figure out which configuration a given resource belongs to.
The solution for the above case is to use the alias meta-argument. An alias is a named, secondary configuration of the same provider. You keep one default provider block without an alias, then add as many aliased blocks as you need.
Here is an example of how a multi-region AWS setup looks:
provider "aws" {
region = "us-east-1"
}
provider "aws" {
alias = "west"
region = "us-west-2"
}
provider "aws" {
alias = "eu"
region = "eu-west-1"
}So, now you have three AWS providers. The default one in us-east-1, aws.west, and aws.eu. In case you want to use the non-default configuration on a resource, you should set the provider meta-argument explicitly in the resource configuration:
resource "aws_vpc" "primary" {
cidr_block = "10.0.0.0/16"
}
resource "aws_vpc" "west" {
provider = aws.west
cidr_block = "10.1.0.0/16"
}
resource "aws_vpc" "europe" {
provider = aws.eu
cidr_block = "10.2.0.0/16"
}The first VPC has no provider argument, so it is using the default configuration and will be deployed in us-east-1. For the last two, the alias meta-argument was used, and they will be deployed in their respective regions. All three are managed by a single configuration, a single state file, and a single apply.
The exact same approach also works for multiple AWS accounts. You configure each aliased provider with different credentials or a different assume_role block, and you can deploy across accounts in a single run.
provider "aws" {
region = "us-east-1"
}
provider "aws" {
alias = "prod"
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::3333333333333:role/terraform"
}
}As a best practice, you should always keep a default provider configuration, the one without an alias, even when you rely heavily on aliases. Resources and modules that don’t have a specified provider argument fall back to the default, and Terraform will complain if no provider is available.
When talking about modules, the rule to remember is that child modules automatically inherit the default provider configuration, but they never inherit alias providers automatically. You need to explicitly pass an aliased provider.
For example, you have a module that needs to create resources in two regions. So it will set up VPC peering between the primary and secondary regions. Inside this module, you need to declare which provider configurations it expects using configuration_aliases in the required_providers block.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 6.0"
configuration_aliases = [aws.primary, aws.secondary]
}
}
}Within the module, resources refer to these configurations by their aliases, exactly as you would in the root module.
resource "aws_vpc" "primary" {
provider = aws.primary
cidr_block = "10.0.0.0/16"
}
resource "aws_vpc" "secondary" {
provider = aws.secondary
cidr_block = "10.1.0.0/16"
}When calling the module, you map your real provider configurations to the names the module expects using the providers argument inside the module block.
provider "aws" {
alias = "use1"
region = "us-east-1"
}
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
module "network" {
source = "./modules/network"
providers = {
aws.primary = aws.use1
aws.secondary = aws.usw2
}
}In this way, the module stays portable, and you should never hardcode a region or account. The parent module becomes the single place where all environment wiring lives, making the module reusable across dev, staging, and prod.
There are several real constraints that you need to know about using multiple Terraform providers before you build something that cannot be applied:
alias argument: Provider blocks are resolved before Terraform evaluates most of the configuration. This means the alias value must be a static string. You cannot dynamically generate provider configurations based on a variable or a listcount.index, each.key, or each.value, so you cannot span a single resource block across multiple provider instances. So, if you need the same resource in three regions, you either write three resource blocks or call a module three times, each with a different provider mapped in.configuration_aliases and then pass it explicitly.Knowing these limits will help you save a lot of time before you start designing a configuration that looks clean on paper but cannot be applied in practice.
Terraform is powerful, but a secure GitOps workflow needs more than a CLI. You need a platform that orchestrates your infrastructure workflows with the guardrails, visibility, and control to match.
Spacelift takes Terraform further with purpose-built infrastructure orchestration, including:
Keep IaC and GitOps as the system of record for production, and use Intent for fast, governed provisioning of tests, demos, and POCs.
Spacelift also lets you run private workers inside your own infrastructure, so you can execute workflows within your security perimeter. Read the documentation to learn more about configuring private workers.
Try Spacelift by creating a trial account or booking a demo. Spacelift supports teams that want developer self-service without giving up governance, auditability, or control.
Multiple providers in Terraform will help you solve two different problems. By using different providers together, you will orchestrate infrastructure across platforms like AWS and Kubernetes in a single run, with Terraform handling the dependencies between them. Using multiple configurations of the same provider through aliases lets you deploy across regions and accounts without duplicating your code.
Modules are usually the part that trips people up. While default providers are automatically passed down to child modules, aliased providers are not. You have to declare configuration_aliases inside the module and explicitly pass them through the providers map in the parent module.
You need to keep the constraints in mind as you build. Don’t use aliased providers with count or for_each on a resource to spread it across providers, no expressions in alias names, and a hard limit on how many aliases you should reasonably maintain before splitting things up. If you respect those boundaries, multiple providers give you a clean, single-configuration way to manage complex multi-region, multi-account, multi-platform infrastructure.
If you need help in managing your Terraform configurations across multiple providers by creating dependencies, taking advantage of governance, or implementing self-service infrastructure, learn more about Spacelift by booking a demo with one of our engineers.
Declare each provider in the root module’s required_providers block, then add a provider block to configure each one. Resources map to a provider by the type prefix (for example, aws_ maps to aws), or you can set the provider meta-argument explicitly.
A provider alias is a named secondary configuration of the same provider, defined with the alias argument, that lets you run multiple instances side by side (different regions, accounts, or credentials). Resources target it with a reference like provider = aws.west.
Yes. A single configuration can declare AWS, Azure, Google Cloud, and others together, so Terraform plans and applies changes across all of them in one run, with outputs from one provider passed as inputs to another.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。