TerraformでALBの高度なリスナールールがより簡潔に書けるようになった話

こんにちは、ななです。
皆さんはTerraformを使っていますか？ちなみに私は最近、Terraformを触り始めました。
今回はTerraformのAWSプロバイダに関して本日2019年12月14日にアップデートがあったため、早速試してみた話を書いてみます。

# はじめに
[Terraform](https://www.terraform.io/)とは、HashiCorpにより作成されたInfrastructure as a Codeを実現するためのオープンソースなツールを指します。

# Application Load Balancer (ALB) とは
AWSが提供するElastic Load Balancing (ELB) というサービスにおいてサポートされ、かつOSI参照モデルの第7層 (アプリケーション層) で機能するものです。
![component_architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144887/9f49d3c9-205f-fa57-79d1-32871a9e56b7.png)
(図引用元： https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/introduction.html)

## リスナールールについて
ALBではリスナールールに従って、ユーザーからのトラフィックを制御しています。

そして2019年3月27日には、AWSがリスナールールを拡張しました。詳しくは、

* [Application Load Balancer で高度なリクエストルーティングのサポートを開始](
https://aws.amazon.com/jp/about-aws/whats-new/2019/03/application-load-balancers-now-support-advanced-request-routing/)
* [[新機能] HTTPヘッダーやクエリ文字列などなどでルーティングができちゃう!!AWS ALBで高度なリクエストルーティングが可能になりました! ｜ Developers.IO](https://dev.classmethod.jp/cloud/aws/advanced-request-routing-for-alb/)

に書いてありますが、リクエストヘッダ内のユーザーエージェントの値などで、より柔軟なルーティングができるようになりました。

# Terraformで書く際に
[AWSプロバイダ](https://github.com/terraform-providers/terraform-provider-aws)経由で、各種AWSリソースを管理していくことになりますが、上記の拡張については以下のように書いても、

```terraform:elb.tf
resource "aws_lb_listener_rule" "http_header_based_routing" {
  listener_arn = aws_lb_listener.front_end.arn
  priority = 10

  action {
    type = "forward"
    target_group_arn = aws_lb_target_group.tg.arn
  }

  condition {
    http_header {
      http_header_name = "User-Agent"
      values           = [
        "*Chrome*",
        "*Safari*",
      ]
    }
  }
}
```

terraform planやterraform applyを入力した際に以下のエラーが出ました。

```
Error: Unsupported block type

  on elb.tf line xx, in resource "aws_lb_listener_rule" "http_header_based_routing":
  xx:     http_header {

Blocks of type "http_header" are not expected here.
```

そこで、上手く書く方法が無いか、AWSプロバイダのリポジトリを確認してみました。そうすると[当該関連のプルリク](https://github.com/terraform-providers/terraform-provider-aws/issues/8126)を見つけましたが、Open (現在はClose) の状態でした。要するにまだのようでした。

そして、月日は経ち、2019年12月7日にmasterブランチにマージされました。そして2019年12月14日に2.42.0としてリリースされました。

ちなみにTerraformでより簡潔に書けるようになる前は、TerraformでCloudFormationスタックを作成するなどして管理する必要がありました。忘れていなければ詳細はどこかの記事で書こうかと思います。もしかしたらすでに書いている人がいて、二番煎じになるかもしれませんが……

## Terraformで実際にALBの高度なリスナールールを書いてみる
①[こちら](https://www.terraform.io/docs/providers/aws/index.html)を参考にAWSプロバイダーの2.42.0のバイナリを持ってきます。

```
$ terraform init

Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "aws" (hashicorp/aws) 2.42.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.
```


②今回はChromeやSafariブラウザを判定するリスナールールを実現してみます。他のパターンについては、[こちら](https://www.terraform.io/docs/providers/aws/r/lb_listener_rule.html)を確認してください。

```terraform:elb.tf
resource "aws_lb_listener_rule" "http_header_based_routing" {
  listener_arn = aws_lb_listener.front_end.arn
  priority = 10

  action {
    type = "forward"
    target_group_arn = aws_lb_target_group.tg.arn
  }

  condition {
    http_header {
      http_header_name = "User-Agent"
      values           = [
        "*Chrome*",
        "*Safari*",
      ]
    }
  }
}
```

③terraform planやterraform applyを用いて、内容を確認した上でデプロイします。

④AWSマネジメントコンソールで確認します。ちゃんと設定されていますね。
<img width="1251" alt="スクリーンショット 2019-12-14 11.21.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144887/aca89d4d-9f77-b4b2-408b-194e5b87c032.png">

以上です。

# おわりに
マージされるまでに8ヶ月以上掛かりましたが、ALBの高度なリスナールールがTerraformでより簡潔に書けるようになりました。皆さんもぜひ使ってみましょう。