[Terraform] Multi Providerで特定のリソースだけ別リージョンに作成したい
ユースケース
他のリソースは、東京リージョンで構築したいがCloudFront用のSSL証明書は、us-east-1(バージニア)リージョンのものしか使えないので、ACM Certificate関連のリソースだけバージニアリージョンでTerraformで作成したい
ディレクトリ構成
ひとまず説明用にルートディレクトリにルートモジュール用のmain.tfだけあるようなシンプルな構成。
※実際は、ステージング用本番用にそれぞれモジュールを分けて、各環境用のモジュール内の main.tf
でTerraformを実行するのがよくある方法かと思われます。
.
├── main.tf
└── modules
└── certificates
├── main.tf
├── output.tf
└── variables.tf
ユースケースを実現するためのアプローチ方針
- ルートモジュールに複数リージョンのawsプロバイダーを定義
- ルートモジュール内のACMのモジュール呼び出し部分でプロバイダーを指定?
- ACMモジュール内でリソース定義部分でプロバイダーを指定
ベースとなるTerraform実装
ここから、Multi Providerで別リージョンでCloudFront用のSSL証明書をバージニアリージョンに作れるようにする
main.tf
ルートモジュールの terraform {
required_version = ">= 1.0.9"
backend "s3" {
bucket = "sample-bucket-2022-01-04"
key = "terraform.tfstate"
region = "ap-northeast-1"
}
required_providers {
aws = {
source = "hashicorp/aws"
}
}
}
provider "aws" {
region = var.region.name
}
provider "aws" {
region = "us-east-1"
alias = "virginia"
}
module "certificate" {
source = "./modules/certificates"
}
ACMのモジュール
resource "aws_acm_certificate" "acm_for_cloudfront" {
provider = aws.virginia
domain_name = "*.test.com"
validation_method = "DNS"
lifecycle {
create_before_destroy = true
}
}
resource "aws_route53_record" "cert_validation" {
depends_on = [
aws_acm_certificate.acm_for_cloudfront
]
for_each = {
for dvo in aws_acm_certificate.acm_for_cloudfront.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}
allow_overwrite = true
name = each.value.name
records = [each.value.record]
ttl = 60
type = each.value.type
zone_id = var.route53_hosted_zone_id
}
resource "aws_acm_certificate_validation" "acm_for_cloudfront" {
provider = aws.virginia
certificate_arn = aws_acm_certificate.acm_for_cloudfront.arn
validation_record_fqdns = [for record in aws_route53_record.cert_validation : record.fqdn]
}
terraform init
, terraform plan
ここまでのTerraform実装で、terraform init は成功
$ terraform init
Initializing modules...
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v3.57.0
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
terraform plan は失敗
$ terraform plan
╷
│ Error: Provider configuration not present
│
│ To work with module.acm_certificate.aws_acm_certificate_validation.collet_com_for_cloudfront its original provider configuration at
│ module.acm_certificate.provider["registry.terraform.io/hashicorp/aws"].virginia is required, but it has been removed. This occurs when a provider configuration is removed
│ while objects created by that provider still exist in the state. Re-add the provider configuration to destroy
│ module.acm_certificate.aws_acm_certificate_validation.collet_com_for_cloudfront, after which you can remove the provider configuration again.
╵
╷
│ Error: Provider configuration not present
│
│ To work with module.acm_certificate.aws_acm_certificate.acm_for_cloudfront its original provider configuration at
│ module.acm_certificate.provider["registry.terraform.io/hashicorp/aws"].virginia is required, but it has been removed. This occurs when a provider configuration is removed
│ while objects created by that provider still exist in the state. Re-add the provider configuration to destroy
│ module.acm_certificate.aws_acm_certificate.collet_com_for_cloudfront, after which you can remove the provider configuration again.
╵
ルートモジュールを以下のように修正して、init, planを再実行
provider "aws" {
region = var.region.name
}
provider "aws" {
region = "us-east-1"
alias = "virginia"
}
module "certificate" {
source = "../../modules/certificates"
+ providers = {
+ aws = aws
+ aws.virginia = aws.virginia
+ }
+}
terraform init
Warningが発生
$ terraform init
Initializing modules...
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v3.57.0
╷
│ Warning: Provider aws is undefined
│
│ on main.tf line 58, in module "acm_certificate":
│ 58: aws = aws
│
│ Module module.acm_certificate does not declare a provider named aws.
│ If you wish to specify a provider configuration for the module, add an entry for aws in the required_providers block within the module.
╵
╷
│ Warning: Provider aws.virginia is undefined
│
│ on main.tf line 59, in module "acm_certificate":
│ 59: aws.virginia = aws.virginia
│
│ Module module.acm_certificate does not declare a provider named aws.virginia.
│ If you wish to specify a provider configuration for the module, add an entry for aws.virginia in the required_providers block within the module.
╵
Terraform has been successfully initialized!
terraform plan
失敗した
$ terraform plan
╷
│ Warning: Provider aws is undefined
│
│ on main.tf line 58, in module "acm_certificate":
│ 58: aws = aws
│
│ Module module.acm_certificate does not declare a provider named aws.
│ If you wish to specify a provider configuration for the module, add an entry for aws in the required_providers block within the module.
╵
╷
│ Warning: Provider aws.virginia is undefined
│
│ on main.tf line 59, in module "acm_certificate":
│ 59: aws.virginia = aws.virginia
│
│ Module module.acm_certificate does not declare a provider named aws.virginia.
│ If you wish to specify a provider configuration for the module, add an entry for aws.virginia in the required_providers block within the module.
╵
╷
│ Error: Provider configuration not present
│
│ To work with module.maintenance.aws_acm_certificate.maintenance (orphan) its original provider configuration at
│ module.maintenance.provider["registry.terraform.io/hashicorp/aws"].virginia is required, but it has been removed. This occurs when a provider configuration is removed while
│ objects created by that provider still exist in the state. Re-add the provider configuration to destroy module.maintenance.aws_acm_certificate.maintenance (orphan), after
│ which you can remove the provider configuration again.
╵
╷
│ Error: Provider configuration not present
│
│ To work with module.maintenance.aws_acm_certificate_validation.maintenance (orphan) its original provider configuration at
│ module.maintenance.provider["registry.terraform.io/hashicorp/aws"].virginia is required, but it has been removed. This occurs when a provider configuration is removed while
│ objects created by that provider still exist in the state. Re-add the provider configuration to destroy module.maintenance.aws_acm_certificate_validation.maintenance (orphan),
│ after which you can remove the provider configuration again.
╵
ちなみにルートモジュールではなく、子モジュールである ./modules/certificates/main.tf
にバージニアリージョンのprivder定義をするのは、アンチパターンらしい
基本的には、ルートモジュールでproviderを定義するのが良いとのこと
子モジュールに別でprovider指定すると、子モジュールをリファクタリングで分解したときにterraform planが失敗する
こうなると、子モジュールのprovider定義をルートモジュールに移動させて再度terraform applyする必要があった
ルートモジュールで別リージョン用のproviderを定義しつつ、子モジュールの方では terraform init
でWarningが出るので、required_providersを追加する必要がある
terraform {
required_version = ">= 1.0.9"
required_providers {
aws = {
source = "hashicorp/aws"
configuration_aliases = [ aws, aws.virginia ]
}
}
}
このスクラップはそもそも子モジュールにすでにproviderが定義されていたという前提が抜け落ちていた。。。
ということで一旦Close