🎃

Cloud Armor の terraform plan 差分が少し分かりづらい

2022/09/30に公開

Cloud Armor の細切れルールによる課金を節約することに成功したクラウドエースの吉崎です。

今回は Cloud Armor のリソースを terraform plan したときの少し分かりづらい差分を分かりやすくする方法を紹介します。

見にくい差分

まずは terraform のコードです。
Cloud Armor の許可ルールに IP アドレスを 3 つ追加する変更を加えています。

armor.tf
resource "google_compute_security_policy" "minikui" {
  name = "minikui"

  rule {
    description = "company"
    action      = "allow"
    priority    = 100

    match {
      versioned_expr = "SRC_IPS_V1"
      config {
        src_ip_ranges = [
          "100.156.122.201/32", "73.56.89.242/32", "101.194.133.22/32",
          "7.224.207.99/32", "247.141.94.110/32", "178.196.243.110/32",
+         "105.236.0.67/32", "239.240.165.214/32", "216.141.24.125/32",
        ]
      }
    }
  }

  rule {
    action   = "allow"
    priority = "2147483647"
    match {
      versioned_expr = "SRC_IPS_V1"
      config {
        src_ip_ranges = ["*"]
      }
    }
    description = "default rule"
  }
}

以下が terraform plan 結果です。

terraform plan結果
$ terraform plan --target google_compute_security_policy.minikui
google_compute_security_policy.minikui: Refreshing state... [id=projects/xxxxxxxxxxxxxxxxxxxxxxxx/global/securityPolicies/minikui]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # google_compute_security_policy.minikui will be updated in-place
  ~ resource "google_compute_security_policy" "minikui" {
        id          = "projects/xxxxxxxxxxxxxxxxxxxxxxxx/global/securityPolicies/minikui"
        name        = "minikui"
        # (4 unchanged attributes hidden)

      + rule {
          + action      = "allow"
          + description = "company"
          + preview     = (known after apply)
          + priority    = 100

          + match {
              + versioned_expr = "SRC_IPS_V1"

              + config {
                  + src_ip_ranges = [
                      + "100.156.122.201/32",
                      + "101.194.133.22/32",
                      + "105.236.0.67/32",
                      + "178.196.243.110/32",
                      + "216.141.24.125/32",
                      + "239.240.165.214/32",
                      + "247.141.94.110/32",
                      + "7.224.207.99/32",
                      + "73.56.89.242/32",
                    ]
                }
            }
        }
      - rule {
          - action      = "allow" -> null
          - description = "company" -> null
          - preview     = false -> null
          - priority    = 100 -> null

          - match {
              - versioned_expr = "SRC_IPS_V1" -> null

              - config {
                  - src_ip_ranges = [
                      - "100.156.122.201/32",
                      - "101.194.133.22/32",
                      - "178.196.243.110/32",
                      - "247.141.94.110/32",
                      - "7.224.207.99/32",
                      - "73.56.89.242/32",
                    ] -> null
                }
            }
        }

        # (1 unchanged block hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

何が少し分かりにくいかというと、元のリストがすべて - になり、新しいリストが + で表示されており、どこに差があるのか一目では分からない点です。
これを少し分かりやすくしてみます。少しです。

少し分かりやすい差分

$ terraform plan --target google_compute_security_policy.minikui | tee 1
$ egrep '(\+|\-).*,$' 1 | sed 's/^\s*//' | awk '{print $2}' | sort | uniq -c | sort -nr
      2 "73.56.89.242/32",
      2 "7.224.207.99/32",
      2 "247.141.94.110/32",
      2 "178.196.243.110/32",
      2 "101.194.133.22/32",
      2 "100.156.122.201/32",
      1 "239.240.165.214/32",
      1 "216.141.24.125/32",
      1 "105.236.0.67/32",

いったんコマンドの解説は置いておいて、この結果は次のことを意味します。

  • 一列目の数字が偶数のものは差分がない
  • 一列目の数字が奇数のものは差分がある

なので、もし plan 結果を誰かにレビューしてもらうときは、「奇数のところが差分です」と伝えることが出来ます。
もちろん、コードの変更自体もレビューをしてもらう前提です。

ただし、以下の注意点があります。

  • terraform plan 時は target 指定をしないと結果が保証されない
  • メンバー間での暗黙知の共有が必要になるためバッドプラクティスになりえる
    →コマンドを知らない人がこの結果を見て「なにこれ?」となるのは不可避です

※コマンドの意味に関心がない場合は以下を読む必要はありません

コマンドの解説

  • 一行目

ターゲット指定をして terraform plan を実行し、その結果を tee コマンドで 1 というファイルに書き出しています。

$ terraform plan --target google_compute_security_policy.minikui | tee 1
  • 二行目

こちらが黒魔術(ただのワンライナー)です。
それぞれパイプ(|)する前後の結果を見ていくと分かりそうなのでやってみましょう。

$ egrep '(\+|\-).*,$' 1 | sed 's/^\s*//' | awk '{print $2}' | sort | uniq -c | sort -nr

まずは egrep '(\+|\-).*,$' 1 です。
拡張正規表現を使って 1 というファイルから Armor ルール内の差分のみを検索しています。

$ egrep '(\+|\-).*,$' 1
                      + "100.156.122.201/32",
                      + "101.194.133.22/32",
                      + "105.236.0.67/32",
                      + "178.196.243.110/32",
                      + "216.141.24.125/32",
                      + "239.240.165.214/32",
                      + "247.141.94.110/32",
                      + "7.224.207.99/32",
                      + "73.56.89.242/32",
                      - "100.156.122.201/32",
                      - "101.194.133.22/32",
                      - "178.196.243.110/32",
                      - "247.141.94.110/32",
                      - "7.224.207.99/32",
                      - "73.56.89.242/32",

次は sed 's/^\s*//' です。
スペース等から始まる行のスペース等を削除(置換)しています。

$ egrep '(\+|\-).*,$' 1 | sed 's/^\s*//'
+ "100.156.122.201/32",
+ "101.194.133.22/32",
+ "105.236.0.67/32",
+ "178.196.243.110/32",
+ "216.141.24.125/32",
+ "239.240.165.214/32",
+ "247.141.94.110/32",
+ "7.224.207.99/32",
+ "73.56.89.242/32",
- "100.156.122.201/32",
- "101.194.133.22/32",
- "178.196.243.110/32",
- "247.141.94.110/32",
- "7.224.207.99/32",
- "73.56.89.242/32",

次は awk '{print $2}' です。
行ごとに 2 列目の値(IP アドレス)のみを出力しています。

$ egrep '(\+|\-).*,$' 1 | sed 's/^\s*//' | awk '{print $2}'
"100.156.122.201/32",
"101.194.133.22/32",
"105.236.0.67/32",
"178.196.243.110/32",
"216.141.24.125/32",
"239.240.165.214/32",
"247.141.94.110/32",
"7.224.207.99/32",
"73.56.89.242/32",
"100.156.122.201/32",
"101.194.133.22/32",
"178.196.243.110/32",
"247.141.94.110/32",
"7.224.207.99/32",
"73.56.89.242/32",

次は sort です。
行ごとに昇順に並び替えます。次の重複排除のために必要です。

$ egrep '(\+|\-).*,$' 1 | sed 's/^\s*//' | awk '{print $2}' | sort
"100.156.122.201/32",
"100.156.122.201/32",
"101.194.133.22/32",
"101.194.133.22/32",
"105.236.0.67/32",
"178.196.243.110/32",
"178.196.243.110/32",
"216.141.24.125/32",
"239.240.165.214/32",
"247.141.94.110/32",
"247.141.94.110/32",
"7.224.207.99/32",
"7.224.207.99/32",
"73.56.89.242/32",
"73.56.89.242/32",

次は uniq -c です。
重複を排除し、重複数を出力します。

$ egrep '(\+|\-).*,$' 1 | sed 's/^\s*//' | awk '{print $2}' | sort | uniq -c
      2 "100.156.122.201/32",
      2 "101.194.133.22/32",
      1 "105.236.0.67/32",
      2 "178.196.243.110/32",
      1 "216.141.24.125/32",
      1 "239.240.165.214/32",
      2 "247.141.94.110/32",
      2 "7.224.207.99/32",
      2 "73.56.89.242/32",

最後は sort -nr です。
-n が数字の順で比較するオプション、-r が逆順にするオプションですので、数字の降順に並び替えます。

$ egrep '(\+|\-).*,$' 1 | sed 's/^\s*//' | awk '{print $2}' | sort | uniq -c | sort -nr
      2 "73.56.89.242/32",
      2 "7.224.207.99/32",
      2 "247.141.94.110/32",
      2 "178.196.243.110/32",
      2 "101.194.133.22/32",
      2 "100.156.122.201/32",
      1 "239.240.165.214/32",
      1 "216.141.24.125/32",
      1 "105.236.0.67/32",

結果、偶数行は変更がないこと、奇数行は変更があることが分かります。

おわりに

思いついたままコマンドを繋げただけですので、上手なワンライナーがあればコメントにて教えてください。
また、他に差分を上手に見る方法があれば教えてください!
terraform plan 時は target 指定することを推奨します。

Discussion