hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.
https://www.terraform.io/
Other
42.65k stars 9.55k forks source link

Can't find provider with alias #26354

Closed steeef closed 3 years ago

steeef commented 4 years ago

Terraform Version

Terraform v0.13.3

Terraform Configuration Files

versions.tf:

terraform {
  required_version = ">= 0.13"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.7.0"
    }
    external = {
      source  = "hashicorp/external"
      version = "~> 1.2.0"
    }
  }
}

main.tf:

provider "aws" {
  alias  = "master_va"
  region = "us-east-1"
}

module "master_route53" {
  providers = {
    aws  = aws.master_va
    apex = aws.master_va
  }

  source             = "./modules/organization_route53"
  org                = var.org
  account            = "master"
  public_domain_name = "example.com"
  delegate           = false

  default_tags = merge(
    local.default_tags,
    {
      "account" = "master"
    },
  )
}

module "dev_route53" {
  providers = {
    aws  = aws.dev_va
    apex = aws.master_va
  }

  source             = "./modules/organization_route53"
  org                = var.org
  account            = "dev"
  public_domain_name = "dev.example.com"
  delegate           = true
  apex_zone_id       = module.master_route53.public_zone_id

  default_tags = merge(
    local.default_tags,
    {
      "account" = "dev"
    },
  )
}

modules/organization_route53/main.tf:

provider "aws" {
  alias = "apex"
}

resource "aws_route53_zone" "public" {
  name = var.public_domain_name

  tags = merge(
    var.default_tags,
    {
      "Name" = "${var.account} public"
    },
  )
}

resource "aws_route53_record" "ns_record" {
  provider = aws.apex

  count = var.delegate ? 1 : 0

  type    = "NS"
  zone_id = var.apex_zone_id
  name    = var.account
  ttl     = "172800"
  records = aws_route53_zone.public.name_servers
}

Debug Output

https://gist.github.com/steeef/6a432c498862ef3ded498522b23a3c75

Crash Output

Expected Behavior

Terraform should use the default aws provider to create an AWS Route 53 zone, and then the provider with alias apex to create the DNS records to delegate entries for the subdomain in the aws provider.

Actual Behavior

I recieved the error:

Error: missing provider provider["registry.terraform.io/hashicorp/apex"].master_va

Steps to Reproduce

  1. terraform init
  2. terraform plan

    Additional Context

    I'm upgrading an existing Terraform configuration from v0.12.29 to v0.13.3. This is a complicated configuration since it manages an entire AWS Organizations organization including AWS account-specific resources in multiple accounts. The intent here is to manage AWS Route53 zones for both the master account (referenced by the provider with alias apex) and any member accounts (referenced by the default aws provider). Each account in the AWS Organization has a copy of the route53 module, including the master account, where both providers (aws and apex) point to the same master_va provider. I can't determine from the error message which one of these entries caused the error. I can paste more if necessary.

I find it odd that it's trying to find a provider with type apex when it's really a provider with type aws and alias apex.

References

steeef commented 4 years ago

I managed to solve my own issue:

I changed the providers block to:

  providers = {
    aws  = aws.dev_va
    aws.apex = aws.master_va
  }

Apparently this is required when passing providers with aliases. In general, you have to list <type>.<alias> to get Terraform to recognize it properly.

If there's a better way to do this (like using required_providers in the module's terraform configuration block), let me know. I didn't see any explicit documentation on this in either the existing reference documentation or the "Upgrading to Terraform 0.13" page.

apparentlymart commented 4 years ago

Hi @steeef! I just wanted to note here some more of what we talked about in chat earlier:

It seems like this would've been much clearer had Terraform been able to recognize that:

That seems like a strong enough heuristic for the error message to potentially include "Did you mean aws.apex?" as a hint for how to address it.

Since Terraform was working as designed here but there is an opportunity for improving the error message, I'm going to relabel this as an enhancement.

The Passing Providers Explicitly section in the docs includes an example of passing aliased providers between modules:

module "tunnel" {
  source    = "./tunnel"
  providers = {
    aws.src = aws.usw1
    aws.dst = aws.usw2
  }
}

While working on this, we can also consider if there's a better place to document this that would be more discoverable, though we must trade that against the fact that this sort of pattern is relatively unusual (compared to other patterns around passing providers) and so we likely wouldn't want to make it so prominent that it overwhelms other information that'd be more relevant.

steeef commented 4 years ago

Sounds fair. I appreciate your help!

ghost commented 3 years ago

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.