Terraform・terraformer で Gmail の filter を管理する
published_at: 2020-09-13
[2021/5/9 変更]
- Terraform 0.13 以上での
terraform init
を行う際の調整事項を末尾に追記
( terraform-provider-gmailfilter 1.0.1 で確認 ) - 問い合わせ先を Twitter へのリプライからこの記事への Discussion コメントに変更
すこし前に、 gmailfilters というツールがあるのを知ってはいました。
が、おそろしいことにこれまで設定したフィルタがふっとんで(消えて)しまうことがありえるとわかっていたので、継続採用は見送ってました。 [1]
そんなときに、ふと Gmailのフィルタを管理するためのTerraformプロバイダーを作った - febc技術メモ というブログを発見。Terraform であれば既存のものに影響なく管理できそうと予想して、使ってみました。
Key Takeaways
- Terraform・terraformer で Gmail の filter は、管理できる
- そこに至るまでには Google ( GCP + G Suite ) のちょっとした壁があり、作成したサービスアカウントへAPI アクセスの委任を管理画面で行うのが良さそう
- 今のところ、設定には以下の制約がありそう
- 一度設定したフィルタを再度設定しようとするとエラーになる(コメントアウトしておく等で回避できる)
- 1つのフィルタで付けられるラベルは1つずつの模様
今回試した流れの概要
- 参考情報の参照
- GCP にサービスアカウントの作成と G Suite 管理画面でAPIアクセス権の調整
- 既存 label , filter の保存(バックアップ)を terraformer で
- 新しい label , filter の設定を terraform-provider-gmailfilter で
参考情報の参照
サンプルコード https://github.com/sogaoh/TerraformPractice/tree/master/Community/GmailFilter の refs にだいたいまとめてはあるのですが、@yamamoto_febc さんのブログを大いに参考にしました。苦戦中に相談もさせてもらって心強かったです。
大いに参考にしたブログ2つ
苦戦中の相談の様子
(Twitter埋め込みではなく画像なのでご注意を。
キャプションをリンクにしていますので適宜ご利用ください)
https://twitter.com/yamamoto_febc/status/1304212390217543682
https://twitter.com/yamamoto_febc/status/1304389099944509440
ここまででの気付きは、2つありました。
- G Suite への API での操作に先立っての認証方法に
Default Application Credentials
というのもある - この機構を実現するベースになっているのは、Gmail API
Default Application Credentials を諦めてサービスアカウントでの認証を探る
Default Application Credentials
にだいぶとらわれてしまっていたのですが、何度かエラーを見ているうちに、自分のこの MacBook Air の環境ではこれは使えないのでは、予想しました。
たしかに、.zshrc で GOOGLE_CREDENTIALS
も GOOGLE_APPLICATION_CREDENTIALS
も仕込んでしまっていて、それが「勝って」しまっていたんだろうな、と。。 [2]
エラーメッセージが一貫して private key should be a PEM or plain PKCS1 or PKCS8; parse error: asn1: syntax error: sequence truncated
と言っていたので、たぶん、サービスアカウントでの認証がベターなんだろう、というのは感じてはいたものの、なかなかわからなかったのはどうサービスアカウントの権限を設定するのか。。
失敗を繰り返す terraform apply のエラーメッセージが変化したときに検索してみたところ見つけた CloudGate HelpCenter の 【Q&A】G Suite:ユーザー操作(作成・更新・削除)の際にプロビジョニングエラーが発生する という文書で、「APIスコープ」の設定が必要なことを掴みました。
GCP にサービスアカウントの作成と G Suite 管理画面でAPIアクセス権の調整
APIスコープの設定をして、ついに terraform apply が成功したときの叫びがこちら。
所要時間、実に 9/11 21:11 - 9/12 0:53 の約4時間ほど・・・(間に家事してたけど)
(こちらもTwitter埋め込みではなく画像です。キャプションをリンクにしています)
整理して振り返ると、ポイントは以下になると思います。
1. GCP 管理コンソールで作成したサービスアカウントに、Domain wide deligation(G Suite ドメイン全体の委任を有効に) する -> クライアントID が発生するのでそれを控える
※ 以下 G Suite 管理画面での設定にはAdmin権限が必要なのでシステム管理者との調整が必要なことをご留意ください
2. G Suite 管理画面で Google Cloud Platform サービスへのアクセスコントロールがオンになっているか確認する
-
https://admin.google.com/ -> アプリ -> その他のGoogleサービス (->
Google Cloud Platform
のサービスステータス オン を確認)
3. G Suite管理画面でアプリのアクセス制御に1.で委任したAPIクライアントに必要なAPIのスコープを設定
-
https://admin.google.com/ -> セキュリティ -> アプリのアクセス制御(いちばん下 ?)
- -> ドメイン全体の委任(いちばん下)の ドメイン全体の委任を管理 で APIクライアントを [新しく追加]
- クライアントID に 1. のクライアントIDを設定し、以下をスコープに含める
- -> ドメイン全体の委任(いちばん下)の ドメイン全体の委任を管理 で APIクライアントを [新しく追加]
terraformer で
既存 label , filter の保存(バックアップ)をここまで設定ができていれば、既存 label・filter の保存(バックアップ) はコマンド一発です。
❯ terraformer import gmailfilter -r=filter,label
コマンド実行前に行ったのは以下環境変数の設定のみです。(インストールは サンプルコードの README に記載した事項が必要 )
- GOOGLE_CREDENTIALS
- IMPERSONATED_USER_EMAIL
今回の自分のケースでは、以下のような .envrc ファイルを用意して、 direnv で局所的に作業ディレクトリだけの環境変数を設定しました。
export GOOGLE_CREDENTIALS=/path/to/domain-wide-deligated_service-account_credentials.json
export IMPERSONATED_USER_EMAIL="xxx@xxx.xxx"
terraformer 実行時の console log (一部)
~/ghq/github.com/sogaoh/TerraformPractice/Community/GmailFilter master*
❯ direnv allow
direnv: loading ~/ghq/github.com/sogaoh/TerraformPractice/Community/GmailFilter/.envrc
direnv: export +IMPERSONATED_USER_EMAIL ~GOOGLE_CREDENTIALS
~/ghq/github.com/sogaoh/TerraformPractice/Community/GmailFilter master*
❯ terraformer import gmailfilter -r=filter,label
2020/09/12 19:59:07 gmailfilter importing... filter
2020/09/12 19:59:09 Refreshing state... gmailfilter_filter.tfer--ANe1BmgPoKSrujLtHzJbg3eOLZCso7JO1UzAVALXRR6n6NY4qI2o0bN5LUnHKsMtaoHBjbXJsA
・・・
2020/09/12 19:59:10 Refreshing state... gmailfilter_filter.tfer--ANe1BmiNYMH21_Y4OxnjFxCJEwOZkR7Dwd9kT58bmnPJITNFajsEPi8FcMtVWiQSOuPMOG6cbQ
・・・
2020/09/12 19:59:10 gmailfilter importing... label
・・・
2020/09/12 19:59:17 Refreshing state... gmailfilter_label.tfer--_Work
・・・
2020/09/12 19:59:17 gmailfilter Connecting....
2020/09/12 19:59:17 gmailfilter save filter
2020/09/12 19:59:17 gmailfilter save tfstate for filter
2020/09/12 19:59:17 gmailfilter save label
2020/09/12 19:59:17 gmailfilter save tfstate for label
~/ghq/github.com/sogaoh/TerraformPractice/Community/GmailFilter master* 11s
作業ディレクトリの generated
ディレクトリに設定が保存されていればOKです。
万が一、設定がふっとんでしまっても、これらを元手に terraform apply
すれば label, filter がすっかり元に戻るはずです。
terraform-provider-gmailfilter で
新しい label , filter の設定を約4時間の格闘の末に確立できた .tf ファイルは以下のような4つです [3]
variable "credentials" {
type = string
default = ""
}
variable "user_email" {}
provider gmailfilter {
credentials = var.credentials
impersonated_user_email = var.user_email
}
resource "gmailfilter_label" "label_techbookfest9" {
background_color = "#c2c2c2"
label_list_visibility = "labelShow"
message_list_visibility = "show"
name = "2020/09/techbookfest9"
text_color = "#ffffff"
}
resource gmailfilter_filter "bought_techbookfest9" {
criteria {
from = "info@techbookfest.org"
query = "[技術書典] 書籍のご購入ありがとうございます"
}
action {
add_label_ids = [
gmailfilter_label.label_techbookfest9.id,
]
remove_label_ids = [
]
}
}
これを terraform init
-> terraform plan
-> terraform apply
と実行していくと、
Gmail API に抵触する点がなければ、指定した label, filter が作られます。
terraform apply 時の console log (少し加工してあります)
~/ghq/github.com/sogaoh/TerraformPractice/Community/GmailFilter master*
❯ terraform apply
gmailfilter_label.label_techbookfest9: Refreshing state... [id=Label_1]
gmailfilter_filter.bought_techbookfest9: Refreshing state... [id=ANe1BmjSrnJdB29oqZz6c70GonyV86RhG2DnYw]
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# gmailfilter_filter.bought_techbookfest9 will be created
+ resource "gmailfilter_filter" "bought_techbookfest9" {
+ id = (known after apply)
+ action {
+ add_label_ids = (known after apply)
+ remove_label_ids = []
}
+ criteria {
+ from = "info@techbookfest.org"
+ query = "[技術書典] 書籍のご購入ありがとうございます"
}
}
# gmailfilter_label.label_techbookfest9 will be created
+ resource "gmailfilter_label" "label_techbookfest9" {
+ background_color = "#c2c2c2"
+ id = (known after apply)
+ label_list_visibility = "labelShow"
+ message_list_visibility = "show"
+ messages_total = (known after apply)
+ messages_unread = (known after apply)
+ name = "2020/09/techbookfest9"
+ text_color = "#ffffff"
+ threads_total = (known after apply)
+ threads_unread = (known after apply)
+ type = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
gmailfilter_label.label_techbookfest9: Creating...
gmailfilter_label.label_techbookfest9: Creation complete after 2s [id=Label_2]
gmailfilter_filter.bought_techbookfest9: Creating...
gmailfilter_filter.bought_techbookfest9: Creation complete after 2s [id=ANe1BmisWaXJ2Aapql6GU1eDOEaOmFHMuT0bHA]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
~/ghq/github.com/sogaoh/TerraformPractice/Community/GmailFilter master*
Gmail の設定画面を一度リロードして、ラベルとフィルタが意図通り作成されていればOKです。
そして、期待通りにフィルタが作用することを可能であれば試すと良いでしょう。
それでは、素敵な Gmail filter 管理を。
質問等は Twitter で↓へのリプライ この記事へ Discussion コメントでいただければ、と思っています。
https://twitter.com/sogaoh/status/1305074553593327617
Terraform 0.13 以上で利用する場合の調整事項
(2021/5/9追記)
https://github.com/sogaoh/TerraformPractice/tree/master/Community/GmailFilter#setup-terraform-provider-gmailfilter の README に加筆したのですが、以下2点の調整が必要でした。[4]
- バイナリの置き場所を仕様に従った状態にする
-
terraform init
時に-plugin-dir
を指定する
Footnotes
-
最高すぎる!Gmail のフィルタ設定をデプロイできる CLI「gmailfilters」 - kakakakakku blog で、ちゃんとバックアップとっておいてください、と言及されています。 ↩︎
-
苦戦中の相談の後に terraformer で採取に成功したのは、direnv での
GOOGLE_APPLICATION_CREDENTIALS
環境変数の上書きが局所的に効いた、からであろうと考えています。 ↩︎ -
https://github.com/sogaoh/TerraformPractice/tree/master/Community/GmailFilter ↩︎
-
https://www.terraform.io/docs/cli/config/config-file.html#provider-installation https://www.terraform.io/upgrade-guides/0-13.html#in-house-providers https://www.terraform.io/upgrade-guides/0-14.html#in-house-providers-and-internal-mirrors ↩︎
Discussion