koudenpaのブログ

趣味のブログです。株式会社はてなでWebアプリケーションエンジニアをやっています。職業柄IT関連の記事が多いと思います。

terraform import でS3バケットをインポートした時の備忘

Terraformにある既存のリソースのインポート機能を試してみたかった。ちょうど完全に手で(AWSコンソールで)管理しているS3バケット群に新しいバケットを追加したくなったので、ちょうどいいからTerraform Cloudともども試してみた。

この手のIaC管理に既存のリソースを持ってくる体験はいい体験をしたことがない(対応リソースが全然足らなかったり、不完全なインポートだったり)のだけれど、なぜかTerraformには期待していた。

案の定、すんなりはいかなくて(S3バケットインポートするだけなのに!)かなりイライラしながら作業していた。せっかくなのでどんなことにイライラしていたのか備忘しておこうと思う。

追記: 後から読み返すと『インポート後のplanで差分が出たらその項目の期待値を宣言しろ』『関連するプロバイダのドキュメントはちゃんと読め』という教訓を得ただけだった。この記事にはその教訓を得るまでの流れが書かれている。

対象リソース

以下のようなS3バケットterraform importした。

terraform import の実行

インポート自体は1リソースずつ実行するのや手でインポート結果を転記するのが面倒くさかったことを除けば特に問題なかった。素直に動作した。

バックエンドにTerraform Cloudを指定しておけばTerraform Cloud上のStateにインポートされたリソースの状態が記録された。

留意点としてはクラウド上に設定している認証情報は適用されず、ローカルで自前で設定するが必要な点がある。

これについては import コマンドのヘルプに記載がある。terraform import は apply とは異なりTerraform Cloud上ではなくローカルマシンで事項されるためそうなるらしい。

Import - Terraform by HashiCorp

クラウド上で認証情報を管理できるメリットが死ぬのでそういうのやめてほしい。

今回は面倒くさかったので変数を参照している個所を手元で一時的に書き換えてしまった。

# こういうこと。
 provider "aws" {
   region     = "ap-northeast-1"
   access_key = var.access_key
-  secret_key = var.secret_key
+  secret_key = "SECRET_KEY!!!"
 }

インポート状況

S3バケットs3_bucket のバージョン3.21.0)のインポートでは値が null でインポートされて plan 時に差分が出る引数がある。

  • force_destroy
  • acl

同じことに戸惑っている人もいるようだった。

また、プロバイダのドキュメントに記載があるのだけれど policy もインポート対象外だった。(プロバイダのバージョン4で削除される引数らしいのでリンク先に行っても消えてるかも)

既存のリソースにはバケットポリシーが指定されていて、policy引数がnullな状態でplanしても差分は出ない様子で、これをそのまま適用しても大丈夫なものか測りかねて困った。

試していた時にはドキュメントを見ていなくて、バケットポリシーあるはずなのに宣言なしでplanして何で差分でないんだ??? と混乱していた。

ダミーのリソースを作ってインポート、そのままplan, applyを試した時の振る舞いはこんな感じだった。ドキュメントの記載と矛盾はないし、stateでnullと宣言でnullを比較して差分がないのはそういうもんだろう。

  • もともとバケットポリシーが設定されているS3バケットをterrarorm importしてもバケットポリシーはインポートされない。
  • リソースの宣言にバケットポリシー(policy)が指定されていない場合、planしても差分は出ない。applyしても変更されない。
    • 多分tfstate上でnull、適用しようとしているポリシーもnullなので差分がないという判断になっている。
  • 明にpolicy引数を指定した場合は差分が発生してapplyすると適用もされる。

最終的には aclforce_destroy の差分は無視(正確には規定値が適用されて問題ないことを確認)して、policyに関してはもともと設定されていたものと同じ内容を宣言して適用した。

# 静的Webサイトにしてるバケットはこんな感じの宣言になった。最小限の指定で済むのが良い。
resource "aws_s3_bucket" "xxx-public-resource" {
  website {
    error_document = "error.html"
    index_document = "index.html"
  }
  policy = <<POLICY
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::xxx-public-resource/*"
        }
    ]
}
POLICY
}

その後他の項目を変更して plan したり apply しても変な差分が出ることはなかったのでインポートできたのだろうと思う。

感想

よく分かっていないリソースをインポートして上書きの適用はしたくないと思った。

今回インポートしたS3バケットはどういう設定をしてあるか把握しているので、この項目がインポートされないのがおかしいと分かったり、適用して何かしらの破壊が起きたとしてもどうにかリカバリができるだろうと思っていたりしたけれど、そうした勘所がない状態でインポートしても正しくインポートされているか判断できない。

S3というどう考えてもメジャーなリソースでもいい感じのインポートはできないとなると、そうでもないマイナーなリソースの対応状況はあんまり考えたくない。

全般に怖い機能だと思った。

ドキュメントに書いてあるだろ? ってことかもしれないけれど、隅から隅まで読んで把握できるわけないし、暗黙に期待している動作から外れていると怖い。

既存のリソースをIaCするのは大変だとの思いが強まった。