FLINTERS Engineer's Blog

FLINTERSのエンジニアによる技術ブログ

TerraformでAWSの全リージョン設定したい!(Terragrunt使用)

FLINTERSでエンジニアをしています。
現在、FLINTERSでは会社設立10周年を記念して、全社員で133日間ブログを更新し続けるという企画を実施中です。こちらのブログはその19日目です。

はじめに

Terraformで同じ設定を全リージョンに行おうとして少し苦戦したので記事にしました。1

ちなみに全リージョン設定しましょうという推奨は、セキュリティ関係のサービスで見ますね。例えば、GuardDutyなんかです。
GuardDuty の開始方法

GuardDuty を使用してモニタリングするリージョンごとに繰り返す必要があります。
AWS は、サポートされているすべてのリージョンで GuardDuty を有効にすることを強くお勧めします。

リージョン毎に繰り返してくださいですって😢

Terraformを全リージョンに実行するときの課題

Terraformはfor_eachでProviderを参照する事ができず、動的にProviderを生成することもできないようです。

Terraformをマルチリージョンに対して実行するには、以下のようなコードを書きます。

provider "aws" {
  region = "ap-northeast-1"
}

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

resource "aws_instance" "foo" {
  # ...
}

resource "aws_instance" "bar" {
  provider = aws.us-east-1

  # ...
}

参考

2リージョン程度なら良いですが、全リージョンともなると何行も定義することになります。

ちなみに全アカウントに実行したいときも同様の問題が発生します。
Organizationで有効化できないAWS Configとか😯、、AWS Configとか😨、、AWS Configとかですね😭😭😭
参考:AWS Configの全アカウント全リージョン有効化の良い方法を考えてみた

この記事の内容を応用すれば複数アカウント対応も可能ですが、アカウントが増える毎にStateが肥大化していくので適用するのが良いかどうかは微妙です。
アカウント毎にTerraform Workspaceを作って実行する仕組みを作った方が良いかも知れません。

Terragruntとは

Terraformを便利に使えるラッパーツールです。

利用イメージは以下の記事などを参照すると良いかと思います。
Terragrunt 導入で Terraform コードを DRY にしてみた

terragrunt.hclを書いて、terraformコマンドの代わりにterragruntコマンドを使うといい感じにやってくれるツールです。
Quick start

なお後述しますが、Terragruntを使う場合Terraformバージョンは1.5.5以下にしてください。

環境ごとにディレクトリを分けるのは良くある構成だと思うのですが、重複するコードが出てくるので生成してもらうのが主な使い方だと思われます。
初めて利用したので、あまり使いこなせてはいません。。

今回はこのツールを使って、全リージョンに実行してみましょう。

Terragruntで全リージョンに実行しよう

ディレクトリ構成はよくみる構成に、Terragrunt用の設定を追加したものです。
今回はGuardDutyを有効化してみます。

├── environments/
│   └── dev/
│       ├── backend.tf
│       ├── generate_main.tf      # 生成される
│       ├── generate_providers.tf # 生成される
│       ├── terragrunt.hcl  # 追加分
│       ├── template/       # 追加分
│       │   ├── main.tftpl
│       │   └── provider.tftpl
│       └── variables.tf
└── modules/
    └── guardduty/
        ├── backend.tf
        ├── main.tf
        └── variables.tf

記述は以下のようになります。backendなどの記述は省略します。

まずTerragruntの定義ファイルです。
environments/dev/terragrunt.hcl

locals {
  regions = jsondecode(run_cmd(
    "aws", "ec2", "describe-regions",
    "--no-all-regions",
    "--query", "sort(Regions[*].RegionName)",
    "--output", "json"
  ))
}

generate "providers" {
  path      = "generate_providers.tf"
  if_exists = "overwrite"
  contents = templatefile("template/provider.tftpl", {
    regions     = local.regions
  })
}

generate "main" {
  path      = "generate_main.tf"
  if_exists = "overwrite"
  contents = templatefile("template/main.tftpl", {
    regions     = local.regions
  })
}

生成する対象は以下の2つです。
environments/dev/terragrunt_template/provider.tftpl

%{ for region in regions ~}
provider "aws" {
  region = "${region}"
  alias  = "${region}"
}

%{~ endfor }

environments/dev/terragrunt_template/main.tftpl

%{ for region in regions ~}
module "guardduty_${region}" {
  source = "../../modules/guardduty/"

  providers = {
    aws = aws.${region}
  }
}

%{~ endfor }

実際にGuardDutyを有効化するのは以下のモジュールです。

modules/guardduty/main.tf

resource "aws_guardduty_detector" "this" {
  enable = true
}

※これは最小限の設定で、実際には色々設定箇所があります。以下などを参考にすると良いと思います。
amazon-guardduty-for-aws-organizations-with-terraform

実行は以下のコマンドです。

terragrunt init
terragrunt plan
terragrunt apply

CLI options

initやplanをしたときに、generate_providers.tfgenerate_main.tfが生成され、それを元に実行されます。

有効化できたかどうかは以下で確認できます。

$ aws ec2 describe-regions --no-all-regions --query 'Regions[*].[RegionName]' --output text | \
  xargs -I {} aws guardduty list-detectors --region {}
{
    "DetectorIds": [
        "aaa"
    ]
}
{
    "DetectorIds": [
        "bbb"
    ]
}
# 有効化されていないと空欄になる

guardduty - list-detectors

Terragruntは今後どうなる?

少し前にTerraformがライセンスを変更して話題になりましたね。
Terragruntにも影響があるようで声明が出ています。
blog.gruntwork.io Terraformの未来は開かれたものでなければならない

Terraform 1.5.5を超えるバージョンでは、Terraformがオープンソースに戻すならTerraformを、そうでないならフォークしたTerraformを使うとのこと。

私にはどちらが良いのか判断できませんが、ユーザーとして思うのは当記事に記載した課題は大分前からIssueに挙がっていて、ライセンス変えるなら変えるで公式で対応して欲しいなというのは1つ思うところです。
でも記事書いてから思いましたが、これくらいの内容であればJinjaなどで生成しても良かったかもしれませんね。
いろいろやろうとするとTerragruntが欲しくなりそうです。

いずれにしても、TerraformやTerragruntやその他のツールたちにとって良い未来になるといいなと思います。

そういえば、先日OpenTofuが発表されました。名前やアイコンが可愛いですね😊
Linux Foundation Launches OpenTofu: A New Open Source Alternative to Terraform


  1. CloudFormation StackSetsなどでも良いと思うが、すでにTerraformを使っていたのでなるべくそちらに寄せたかった。