FLINTERSでエンジニアをしています。
現在、FLINTERSでは会社設立10周年を記念して、全社員で133日間ブログを更新し続けるという企画を実施中です。こちらのブログはその19日目です。
はじめに
Terraformで同じ設定を全リージョンに行おうとして少し苦戦したので記事にしました。1
ちなみに全リージョン設定しましょうという推奨は、セキュリティ関係のサービスで見ますね。例えば、GuardDutyなんかです。
GuardDuty の開始方法
GuardDuty を使用してモニタリングするリージョンごとに繰り返す必要があります。
AWS は、サポートされているすべてのリージョンで GuardDuty を有効にすることを強くお勧めします。
リージョン毎に繰り返してくださいですって😢
Terraformを全リージョンに実行するときの課題
Terraformはfor_eachでProviderを参照する事ができず、動的にProviderを生成することもできないようです。
- Issue: Instantiating Multiple Providers with a loop
- Issue: Ability to pass providers to modules in for_each
- Issue: Dynamic provider configuration assignment
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 }) }
- localsブロックはTerragruntが参照できる変数を定義できます。
- run_cmdでコマンドを実行できるので、AWS CLIで全リージョンの一覧を取得して渡してあげます。
- jsondecodeはTerraformの関数ですね。Terragruntの定義ファイルではTerraformの関数が使えます。
- generateブロックでファイルを生成する事が可能です。
- Terraformのtemplatefile関数を使用して
.tf
ファイルを生成しています。
- Terraformのtemplatefile関数を使用して
生成する対象は以下の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
initやplanをしたときに、generate_providers.tf
、generate_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" ] } # 有効化されていないと空欄になる
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
- CloudFormation StackSetsなどでも良いと思うが、すでにTerraformを使っていたのでなるべくそちらに寄せたかった。↩