テックメモ

技術的に気になったことをメモしていきます

terraform planで意図せず差分が検出される件と向き合ってみた

はじめに

良く terraformを利用するのですが、定義変更がない状態でplanを実行した際差分が検出される(ことがある)事象に悩まされていました。遭遇頻度がそこまで高くなかったために、しばらく放置していたのですがterraformもCI/CDをまわしたい欲に駆られてしっかりと向き合ってみました。

どんな事象が起きるのか

たとえば、Datadogと連携するためのiAM Roleを以下のように定義してみます。

resource "aws_iam_role" "dd" {
    name = "dd"
    description = "dd"
    assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "123451234512"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
}

おもむろにapplyします。

$ terraform apply
<snip>
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

無事にIAM Roleが作成されました。それでは、定義を変更せずにplanを実行してみます。

$ terraform plan
<snip>
  ~ aws_iam_role.dd
      assume_role_policy: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::123451234512:root\"},\"Action\":\"sts:AssumeRole\"}]}" => "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"\",\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"AWS\": \"123451234512\"\n      },\n      \"Action\": \"sts:AssumeRole\"\n    }\n  ]\n}\n"

定義の変更が無いにも関わらず、差分が検出されてしまいます。

向き合い方

それではこの差分と向き合ってみましょう。今回はterraform-landscapeを利用してplanの可読性を高めています。

github.com

使い方は簡単でplanの結果をパイプでlandscapeに渡してあげるだけです。それでは実行してみます。

$ terraform plan | landscape
<snip>
~ aws_iam_role.dd
    assume_role_policy:   "Statement": [
                               {
                                 "Action": "sts:AssumeRole",
                                 "Effect": "Allow",
                                 "Principal": {
                          -        "AWS": "arn:aws:iam::123451234512:root"
                          +        "AWS": "123451234512"
                                 },
                                 "Sid": ""
                               }
                             ],
                             "Version": "2012-10-17"

Principalの値に差分が見られますね。123451234512として定義しましたが、tfstateファイルではarn:aws:iam::123451234512:rootと記録されているようです。

一方planで表示された設定は表記方法が異なるだけで、設定としては問題がなさそうです。そのためこのままapplyしても問題はなさそう。ですがこれでは都度差分を確認することとなり、精神的にも消耗しますし、最悪planをしっかりと確認しない文化が作られる可能性があります。

このようなケースで差分として検出されないために、定義ファイルを少しだけ修正してみます。

resource "aws_iam_role" "dd" {
    name = "dd"
    description = "dd"
    assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123451234512:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
}
`

Principalの定義をtfstateファイルに合わせ修正しています。この状態でplanを実行して差分が検出されないことを確認してみます。

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

aws_iam_role.dd: Refreshing state... (ID: dd)

------------------------------------------------------------------------

No changes. Infrastructure is up-to-date.

This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.

無事に差分が検出されなくなりました。

terreformでは定義ファイルの通りにtfstateファイルへと記録されないこともあるようですね。そのため、定義ファイルで変更が無い場合でもplanの際に差分として検出されることがあります。このような差分はplanのノイズになるので排除したいところです。

この辺りはplanにヒントが多く表示されていると思われますので、やはりplanは大事です。また、planの差分としてJSONが表示されるとかなり視認性が低くツラかったのですが、terraform-landscapeの力を借りることでかなり視認性が高くなりました。

この調子で意図しない差分はどんどん排除したいと思います。