Terraformでmodule分けしてHashiCorp製以外のプロバイダを使うときにつまづいたこと

2024.02.07

こんにちは、ゲームソリューション部のsoraです。
今回は、Terraformでmodule分けしてHashiCorp製以外のプロバイダを使うときにつまづいたことについて書いていきます。

発生したエラー

Terraformでプロバイダとして、hashicorp/awstidbcloud/tidbcloudを指定したコードを実行しようとしたところ、以下のエラーが発生しました。

$ terraform init
│ Error: Failed to query available provider packages
│
│ Could not retrieve the list of available versions for provider hashicorp/tidbcloud: provider registry   
│ registry.terraform.io does not have a provider named registry.terraform.io/hashicorp/tidbcloud
│
│ Did you intend to use tidbcloud/tidbcloud? If so, you must specify that source address in each module   
│ which requires that provider. To see which modules are currently depending on hashicorp/tidbcloud, run  
│ the following command:
│     terraform providers
# ⇒hashicorp/tidbcloudなんて記述はしておらず、tidbcloud/tidbcloudをちゃんと指定している。

Terraformのソースコードは以下です。
ちなみに、module分けせずに、main.tfにまとめれば正常に動作します。

main.tf

terraform {
    required_providers {
        aws = {
            source  = "hashicorp/aws"
            version = "~> 5.35.0"
        }
        # TiDB Cloudプロバイダー
        tidbcloud = {
            source = "tidbcloud/tidbcloud"
            version = "~> 0.2.3"
        }
    }
    backend s3 {
        bucket = "{bucket_name}"
        region = "ap-northeast-1"
        key    = "tmp.tfstate"
    }
}
provider aws {
    region = "ap-northeast-1"
}
# TiDB Cloud APIキー
provider tidbcloud {
    public_key  = "{public_key}"
    private_key = "{private_key}"
}

# TiDB
module tidb_cluster_create {
    source = "./tidb"
}

tidb/main.tf

# TiDB CloudのServerless Tierクラスタの構築
resource tidbcloud_cluster serverless_tier_cluster {
    project_id     = "{project_id}"
    name           = "ClusterServerless"
    cluster_type   = "DEVELOPER"
    cloud_provider = "AWS"
    region         = "ap-northeast-1"
    config = {
        root_password = "root_password"
    }
}

修正版のソースコード

先に、module分けした上でエラー解消した修正版のソースコードを以下に記載します。
次項で原因について記載します。

main.tf

terraform {
    required_providers {
        aws = {
            source  = "hashicorp/aws"
            version = "~> 5.35.0"
        }
    }
    backend s3 {
        bucket = "{bucket_name}"
        region = "ap-northeast-1"
        key    = "tmp.tfstate"
    }
}
provider aws {
    region = "ap-northeast-1"
}

# TiDB
module tidb_cluster_create {
    source = "./tidb"
}

tidb/main.tf

terraform {
    required_providers {
        # TiDB Cloudプロバイダー
        tidbcloud = {
            source = "tidbcloud/tidbcloud"
            version = "~> 0.2.3"
        }
    }
}
# TiDB Cloud APIキー
provider tidbcloud {
    public_key  = "{public_key}"
    private_key = "{private_key}"
}

# TiDB CloudのServerless Tierクラスタの構築
resource tidbcloud_cluster serverless_tier_cluster {
    project_id     = "{project_id}"
    name           = "ClusterServerless"
    cluster_type   = "DEVELOPER"
    cloud_provider = "AWS"
    region         = "ap-northeast-1"
    config = {
        root_password = "root_password"
    }
}

原因

Terraformの公式ドキュメントを見てみると、以下記載がありました。

Note: Only provider configurations are inherited by child modules, not provider source or version requirements. Each module must declare its own provider requirements. This is especially important for non-HashiCorp providers.

Terraform公式ドキュメントから引用

プロバイダの構成のみが子モジュールに継承されて、プロバイダのソースが継承されないため、子モジュールと親モジュールが異なる場合は、明示的に指定する必要があります。
HashiCorp製のプロバイダであるhashicorp/awsは暗黙の継承で動作するものの、HashiCorp製以外のプロバイダだとhashicorp/で補完されて上手くいかないのだと思います。

そのため、moduleディレクトリ側のmain.tfでプロバイダを明示的に指定することで、解消できました。

参考

Providers Within Modules
Terraform の required_providers はモジュールごとに定義しようねというお話
Terraform: Failed to query available provider packages (Azapi)

最後に

今回は、Terraformでmodule分けしてHashiCorp製以外のプロバイダを使うときにつまづいたことを記事にしました。
どなたかの参考になると幸いです。