DMM.comの、一番深くておもしろいトコロ。

terraformでどこまでやる?運用を見据えた部分的な管理アプローチ

terraformでどこまでやる?運用を見据えた部分的な管理アプローチ

  • このエントリーをはてなブックマークに追加

こんにちは。

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)

f:id:dmmadcale2021:20211125193056p:plain
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で作るけど、あえて更新を含めない選択肢について紹介をしました。解決したいことを見失わずに、上手に付き合っていく一助になれば幸いです。

明日の記事もお楽しみに。