Terraform 0.15.1 多提供程序问题 - 参数 "region" 是必需的,但未设置

Terraform 0.15.1 Multiple Provider Issue - The argument "region" is required, but was not set

下面是我的项目文件结构:

├── main.tf
├── tunnel
│   ├── main.tf
│   └── variables.tf
└── variables.tf

我正尝试按照此处所述在 Terraform 0.15.1 中使用多个提供程序 -> https://www.terraform.io/docs/language/modules/develop/providers.html

按照示例进行操作后,我无法使其正常工作。我现在已经将我的代码简化为只使用一个提供者别名(尽可能简单)。我得到的错误是:

╷
│ Error: Missing required argument
│ 
│ The argument "region" is required, but was not set.
╵

我的main.tf根目录下的文件:

module "tunnel" {
  source    = "./tunnel"
  providers = {
    aws.r = aws.requester
  }
}

我的variables.tf在根目录:

provider "aws" {
  alias  = "requester"
  region = "ap-southeast-2"
  profile = "benchmark"
}

我的 tunnel/variables.tf 文件:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 2.7.0"
      configuration_aliases = [ aws.r ]
    }
  }
}

data "aws_region" "current" {}

data "aws_caller_identity" "current" {}

我的 tunnel/main.tf 文件:

# Requester's side of the connection.
resource "aws_vpc_peering_connection" "peer" {
  vpc_id        = "vpc-xxxxxxxxxxxxxxxxx"
  peer_vpc_id   = "vpc-xxxxxxxxxxxxxxxxx"
  peer_owner_id = data.aws_caller_identity.current.account_id
  peer_region   = data.aws_region.current.name
  auto_accept   = false

  tags = {
    Side = "Requester"
  }
}

我不明白为什么会出现此错误?这段代码的最终目标是自动化 vpc 对等的两端,如此处所示 -> https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_peering_connection_accepter 。但我目前坚持让两个 aws 提供者使用不同的凭据(上面示例中的一个提供者来简化事情)。

当我从根 main.tf 中删除 alias = "requester" 时:

provider "aws" {
//  alias  = "requester"
  region = "ap-southeast-2"
  profile = "benchmark"
}

和根路径中 main.tf 的提供程序配置:

module "tunnel" {
  source    = "./tunnel"
//  providers = {
//    aws.r = aws.requester
//  }
}

和来自 tunnel/variables.tf:

的别名配置
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 2.7.0"
//      configuration_aliases = [ aws.r ]
    }
  }
}

计划工作正常:

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.tunnel.aws_vpc_peering_connection.peer will be created
  + resource "aws_vpc_peering_connection" "peer" {
      + accept_status = (known after apply)
      + auto_accept   = false
      + id            = (known after apply)
      + peer_owner_id = "xxxxxxx"
      + peer_region   = "ap-southeast-2"
      + peer_vpc_id   = "vpc-xxxxxxxxxxxxxxxxx"
      + tags          = {
          + "Side" = "Requester"
        }
      + vpc_id        = "vpc-xxxxxxxxxxx"

      + accepter {
          + allow_classic_link_to_remote_vpc = (known after apply)
          + allow_remote_vpc_dns_resolution  = (known after apply)
          + allow_vpc_to_remote_classic_link = (known after apply)
        }

      + requester {
          + allow_classic_link_to_remote_vpc = (known after apply)
          + allow_remote_vpc_dns_resolution  = (known after apply)
          + allow_vpc_to_remote_classic_link = (known after apply)
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

此错误消息是 Terraform 必须使更简单的情况变得更简单的一些自动行为的结果,但不幸的是,这导致在像您这样的更复杂的情况下情况变得相当不清楚。

在您的子模块中,您已声明它希望在调用方中传递一个替代(别名)提供程序配置,在该模块中将称为 aws.r。但是,您之后声明的数据资源不包含 provider 参数来指定它们属于哪个提供者配置,因此 Terraform 选择 default(无别名)提供者配置.

不幸的是,您的配置实际上 没有 默认提供程序配置,因为根模块 使用备用提供程序配置aws.requester。因此,Terraform 会自动构建一个空配置,因为这对于像 http 这样不需要任何特殊配置的简单提供程序来说是一种有用的行为。但这并不能最终为 aws 提供商工作,因为它 需要设置 region

至少有两种不同的方法可以更改子模块以使其工作。其中哪一个最合适将取决于此模块如何适应您的更广泛的配置。


第一个选项是让子模块根本不声明 aws.r,而是始终使用其默认提供程序配置:

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

data "aws_region" "current" {}

data "aws_caller_identity" "current" {}

因为您的根模块没有 hashicorp/aws 的默认配置,您仍然需要在模块调用中明确指出该模块的默认提供程序是 aws.requester 提供程序,因为根模块看到它:

module "tunnel" {
  source    = "./tunnel"
  providers = {
    aws = aws.requester
  }
}

对于不需要多个 AWS 提供商配置的共享模块来说,这种方法是一个不错的选择,因为模块本身可以完全不知道其调用者中的多个配置,而只是期望给出 hashicorp/aws 使用的默认配置。

但是,如果您的子模块也需要对 hashicorp/aws 进行不止一种配置,那么它将无法工作。在这种情况下,您将需要我接下来将描述的其他选项。


当共享模块将使用多个提供者配置时,我们需要为它希望从其调用者传递的每个配置声明一个 configuration_aliases 条目。你在你的例子中只展示了一个叫做 r 的,我不知道“r”代表什么,所以为了这里的例子我将称它们为“src”(“源”)和"dst" for ("destination") 只是为了举例说明一些有意义的术语。

我们将从 configuration_aliases 配置开始:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 2.7.0"
      configuration_aliases = [ aws.src, aws.dst ]
    }
  }
}

configuration_aliases 中给出的每一项都声明了一个配置地址,在对该模块的任何调用中,providers 参数中必须有一个对应的条目,我们稍后会看到。

由于此模块不希望使用 默认(无别名)配置,我们现在需要为每个资源块告诉 Terraform 它属于哪个提供者配置。从您的数据资源开始,假设它们属于“源”端:

data "aws_region" "current" {
  provider = aws.src
}

data "aws_caller_identity" "current" {
  provider = aws.src
}

我怀疑在您的真实系统中,您显示的 aws_vpc_peering_connection 资源在逻辑上可能也属于“源”端,但由于您没有显示任何其他资源,我将任意分配它到 aws.dst 以显示它的样子:

resource "aws_vpc_peering_connection" "peer" {
  provider = aws.dst

  vpc_id        = "vpc-xxxxxxxxxxxxxxxxx"
  peer_vpc_id   = "vpc-xxxxxxxxxxxxxxxxx"
  peer_owner_id = data.aws_caller_identity.current.account_id
  peer_region   = data.aws_region.current.name
  auto_accept   = false

  tags = {
    Side = "Requester"
  }
}

该模块中的每个 dataresource 块都需要设置 provider,因为默认情况下此模块中没有 select 的默认提供程序配置.

调用模块时,需要告诉 Terraform 调用方中的哪些提供程序配置映射到被调用模块中的 srcdst 配置:

module "tunnel" {
  source    = "./tunnel"
  providers = {
    aws.src = aws.requester
    aws.dst = aws.peer
  }
}

正如我之前提到的,我们需要在 providers 中为模块中声明的每个 configuration_aliases 分配一个条目。将这些替代提供程序配置视为与输入变量有些相似可能会有所帮助,但它们具有更专业的声明和定义语法,因为提供程序是 Terraform 执行模型的基础,需要在正常表达式评估成为可能之前解决.

这里我只是任意选择“peer”作为您在根模块中声明的假定第二个配置的名称。将调用者中的默认配置分配给被调用模块中的替代配置也是有效的,例如 aws.src = aws,但这似乎不适用于您的情况,因为您在根目录中没有默认配置模块之一。