Terraformにある既存のリソースのインポート機能を試してみたかった。ちょうど完全に手で(AWSコンソールで)管理しているS3バケット群に新しいバケットを追加したくなったので、ちょうどいいからTerraform Cloudともども試してみた。
この手のIaC管理に既存のリソースを持ってくる体験はいい体験をしたことがない(対応リソースが全然足らなかったり、不完全なインポートだったり)のだけれど、なぜかTerraformには期待していた。
案の定、すんなりはいかなくて(S3バケットインポートするだけなのに!)かなりイライラしながら作業していた。せっかくなのでどんなことにイライラしていたのか備忘しておこうと思う。
tarraform import すると tfstate は出来上がるが tf ファイルは手で修正する。本当か? ダルすぎるんだが。もっとこう、一撃で全部やってくれよ。
— 光電/7474 (@koudenpa) 2020年12月12日
追記: 後から読み返すと『インポート後のplanで差分が出たらその項目の期待値を宣言しろ』『関連するプロバイダのドキュメントはちゃんと読め』という教訓を得ただけだった。この記事にはその教訓を得るまでの流れが書かれている。
対象リソース
以下のようなS3バケットを terraform import
した。
- プライベートなバケット
- 数年前に(多分)デフォルトの設定で作っただけ
- パブリックな静的Webサイトにしているバケット
- (多分)ドキュメント通りに設定しただけ
- 静的ウェブサイトホスティング用に S3 バケットを設定する方法 - Amazon Simple Storage Service
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すると適用もされる。
最終的には acl
と force_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するのは大変だとの思いが強まった。