こんにちは。
DMMグループ Advent Calendar 2021 3日目はVPoEグループの飯田 涼太が担当します!
趣旨を理解の上、お楽しみください。
はじめに
インフラ構成をコードで書く、いわゆるIaCもそう珍しいものではなくなったと感じています。
とくに私の周りでは、クラウドインフラの管理としてCloudFormationやterraformなどを利用しているケースをよく耳にするようになりました。
本記事では、すべてを闇雲にコード化するのではなく、運用を考慮して部分的にコード化するアプローチについて紹介していきます。
※terraform分は少なめで、どちらかというと設計めいた話であるのをご理解し、お読みください
TL;DR;
すべてをコード管理するのではなく、構成管理の要素が少ないものを意図的に外してみるアプローチも一考の価値がありそうなので、お試しいただきたいです。 たとえば、WAFとそれに利用するIPリストであれば、IPリストを作る部分はコード化しつつ、構成管理の要素が少ないリスト内容の更新は別管理にします。そうすると、「構成の更新」と「IPリストの更新」のそれぞれがバッティングしないため、運用懸念が減ります。
やりがちなこと
金槌を持つと出っ張りがすべて釘に見えるようなもので、なまじコードで表現できると手当たり次第コードで表現したくなりますよね。
ただ、これはこれで良い面もあり、100%な悪手ではないです。 すべてがそこに書かれているというのも、思った以上に安心感があります。
では、どういうときに困るのでしょうか。 具体的なケースについて紹介していきます。
例 IPリストとアクセス制限の構成を管理する
私が直近で対応した、AWS上に構築されたアプリケーションのアクセス制限の事例がまさにそれだったので、こちらを例に紹介します。
すでに構築済みのwebアプリケーション(ELB → ECS)に、IPリストで許可されたIPからのみ、アクセスを受け付ける(AWS WAFの導入)という事例です。
要件の概要は次の通りです。
- 環境ごとにアクセスできるIPリストは異なる
- 既存クラウドインフラの構成管理に利用しているterraformに含めたい
- IPリストの更新は度々あり、要請があってからなるべく早めに適応したい
新たに構成する必要があるリソースはこれらを想定しました。
- 適用したいルールセット(AWS WAFのWebACL)
- 接続を許可するIPリスト(AWS WAFのIPSet)
AWS WAFの追加イメージ
作成・更新・削除、すべてをコードで管理する
あちこち確認しなくても、すべてがここに書いてあるのは分かりやすいですね。 コードの該当部分を抜粋すると、こんなイメージです。
##################################
# WAFV2 aws_wafv2_ip_set
##################################
resource "aws_wafv2_ip_set" "access_white_list" {
name = "${var.env}_access_white_list"
description = "IP white list for http access"
scope = "REGIONAL"
ip_address_version = "IPV4"
addresses = []
}
##################################
# WAFV2 aws_wafv2_web_acl
##################################
resource "aws_wafv2_web_acl" "cf_web_acl" {
depends_on = [aws_wafv2_ip_set.access_white_list]
name = "${var.env}_cf_web_acl"
description = "web acl for private http access."
scope = "REGIONAL"
default_action {
block {}
}
rule {
name = "access_white_list"
priority = 1
action {
allow {}
}
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.access_white_list.arn
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${var.env}_web_acl_rule_watch"
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${var.env}_web_acl_watch"
sampled_requests_enabled = true
}
}
何か変更があれば、コードを変更して更新分を適用する運用となります。
しかし、私はこのやり方を採用しませんでした。
なぜ全コード管理を選ばなかったのか
その理由を説明します。
一見すると、すべて構成管理として一括りにできそうです。
アクセスできるIPリストは構成管理すべきだと考えましたが、その中身はどうでしょうか? これは構成という観点には含まれない、と私は判断しました。
なぜならIPリストの中身がどれだけ変更されても、ルールセットとルールという構成自体に変化がないからです。
2つの目的が混在している時に、懸念になりうること
- 構成を管理したい(便宜的にAとする)
- IPリストを管理したい(便宜的にBとする)
この2つのユースケースを1つのコードで表現していることが懸念として挙げられました。
実際の運用中を想像してみると、Aの変更とBの変更が同時期に提出されることがあり得ます。
Bだけ適用したい場合、工夫なしにAの変更を含めざるを得ないです(その逆もまた然り)。
実際の解決策
IPリストを作るところまでは、構成管理に含めましたが、リスト自体の更新は含めませんでした。(terraform上はIPSetのリソース定義のlifecycleにignore_changesを指定する)
私もこちらの方法を選択しました。
ただ、IPリストはコード管理していないかというと、そうではありません。
あくまで構成管理のterraformからは除外しましたが、IPリストの管理は別のコード管理としました。 ※本題からずれるため、こちらは割愛します
構成の更新とIPリストの更新を並行して行うこともできますし、terraformの知識がなくてもIPリストの更新ができるのは、運用として扱いやすい形に仕上げられたと感じています。
おわりに
本記事では、運用も見据えてterraformで作るけど、あえて更新を含めない選択肢について紹介をしました。解決したいことを見失わずに、上手に付き合っていく一助になれば幸いです。
明日の記事もお楽しみに。