4. Provider配置与多环境认证

Terraform 本身并不直接调用云厂商 API,它通过 Provider 插件把 HCL 资源声明翻译成各云平台的 REST 调用。因此,Provider 配置是混合云编排的“入口层”:声明用哪个厂商、以什么身份、访问哪个区域或账号。本节围绕 Provider 声明、多账号多区域认证、环境变量与凭据管理、Provider 别名与多实例配置四条主线展开。

一、Provider 声明与版本约束

每个 Provider 都需要在 required_providers 中声明来源和版本约束,再在 provider 块中给出认证与区域参数。版本约束建议使用悲观约束 ~>,避免次版本升级引入破坏性变更。

terraform {
  required_version = ">= 1.6.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.40"
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.95"
    }
    alicloud = {
      source  = "aliyun/alicloud"
      version = "~> 1.220"
    }
  }
}

provider "aws" {
  region = var.aws_region
}

provider "azurerm" {
  features {}
  subscription_id = var.azure_subscription_id
}

注意 azurerm 的 features {} 块是必填项,即使为空也必须保留;alicloud 的 source 是 aliyun/alicloud,而非 hashicorp 命名空间,写错会导致 terraform init 拉取失败。

二、多账号与多区域认证

混合云场景下,同一厂商往往存在多个账号(如生产账号、测试账号)和多个区域。Terraform 通过 Provider 别名(alias)实现“同一 Provider 多实例”。每个实例拥有独立的认证身份和区域,资源通过 provider = aws.prod 显式绑定。

provider "aws" {
  alias  = "prod"
  region = "cn-north-1"
  assume_role {
    role_arn = "arn:aws-cn:iam::111122223333:role/TerraformDeploy"
  }
}

provider "aws" {
  alias  = "test"
  region = "cn-northwest-1"
  assume_role {
    role_arn = "arn:aws-cn:iam::444455556666:role/TerraformDeploy"
  }
}

resource "aws_s3_bucket" "logs" {
  provider = aws.prod
  bucket   = "corp-prod-logs"
}

未指定 provider 的资源会落到默认 Provider(无 alias 的那个)。因此建议:默认 Provider 只用于单一环境,多环境一律显式绑定别名,避免“资源建错账号”这类高风险事故。跨账号访问通常配合 assume_role,由主账号角色切换到目标账号角色,凭据不落地。

三、环境变量与凭据管理

Provider 认证参数有明确的优先级:显式写在 provider 块中的值 > 环境变量 > 共享凭据文件。生产实践中应遵循“凭据不进代码”原则:HCL 中只保留区域、角色 ARN 等非敏感参数,密钥通过环境变量或外部凭据链注入。

云厂商常用环境变量凭据文件
AWSAWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_PROFILE~/.aws/credentials
AzureARM_CLIENT_ID / ARM_CLIENT_SECRET / ARM_TENANT_ID / ARM_SUBSCRIPTION_IDaz login 缓存
GCPGOOGLE_APPLICATION_CREDENTIALS / GOOGLE_PROJECT服务账号 JSON
阿里云ALICLOUD_ACCESS_KEY / ALICLOUD_SECRET_KEY / ALICLOUD_REGION~/.aliyun/config.json
CI/CD 中优先使用 OIDC 联合身份(如 AWS IAM Roles Anywhere、Azure Workload Identity),让流水线临时换取短期凭据,避免长期 AK/SK 写入 Secret 存储。

四、Provider 别名与多实例配置

别名不仅用于多账号,也用于同一账号下的多区域、多订阅。模块化时,Provider 需要通过 providers 参数显式传递给子模块,否则子模块会使用自己的默认 Provider,导致配置失效。

module "network_prod" {
  source    = "./modules/network"
  providers = {
    aws = aws.prod
  }
  vpc_cidr = "10.10.0.0/16"
}

子模块内部则用 configuration_aliases 声明它期望接收的别名:

terraform {
  required_providers {
    aws = {
      source                = "hashicorp/aws"
      configuration_aliases = [aws.prod, aws.test]
    }
  }
}

下面这张图展示了多环境认证的整体数据流:凭据从环境变量或凭据文件进入 Provider 实例,经别名绑定后驱动不同账号/区域的资源,最终由 Terraform 状态文件统一记录。

多环境 Provider 认证与资源绑定数据流 凭据来源 环境变量 ~/.aws/credentials OIDC 临时令牌 assume_role 角色链 Provider 实例(别名) aws.prod cn-north-1 aws.test cn-northwest-1 azurerm / alicloud 目标账号 / 区域 生产账号 111122223333 测试账号 444455556666 Azure 订阅 / 资源组 阿里云 Region 资源绑定 resource "aws_s3_bucket" provider = aws.prod Terraform State 记录 provider 别名与资源映射 远程后端 + 状态锁 子模块传递 providers = { aws = aws.prod }

五、常见排障要点

  • 资源建到默认账号:检查资源是否遗漏 provider 参数,或子模块未通过 providers 接收别名。
  • init 拉取失败:核对 source 命名空间,如阿里云为 aliyun/alicloud。
  • 凭据不生效:按“显式参数 > 环境变量 > 凭据文件”顺序排查,确认环境变量名拼写正确。
  • 跨账号权限不足:检查 assume_role 的信任策略是否允许当前身份扮演目标角色。

把 Provider 配置当作基础设施代码的“身份层”来治理:版本锁定、别名显式、凭据外置、模块透传,四者齐备后,混合云多环境编排才能稳定可复现。