MySQL8 以降の新しい機能に一部対応した terraform-provider-mysql を開発しました
開発したもの
経緯
勤めている会社で MySQL のユーザーを目的別に作成してそれぞれ使い分けましょう、という話がありました。単純に CREATE USER
してパスワード共有したら管理しきれなくなりそうな予感がしたので、いい感じに管理する方法を検討しました。
Terraform で管理するか Vault by HashiCorp で短寿命のアカウントを払い出すようにするくらいしか自分たちでできそうな方法は見つけられませんでした。Vault は SassS を使わなければ自分でサーバーをたてて運用しないといけないので、見送って Terraform で管理することにしました。
MySQL の管理ができる Terraform Provider を探したのですが Terraform Registry で検索したら10件以上ヒットしました。その中から比較的メンテナンスされていそうな https://registry.terraform.io/providers/petoju/mysql/latest を使ってみることにしました。他もいくつか見てみましたが、機能的には大差ありませんでした。
管理したいものは以下の通りで、ついでにパスワードローテーションしやすい仕組みを作れるとよいな、と考えていました。
- MySQL のユーザー
- MySQL のロール
- ロールに付与した権限
- ユーザーに付与した権限
- デフォルトロール
ざっくりと terraform module を作ってユーザーやロールを作り、権限を付与したりはできたのですが、やりたかったことが完全には実現できませんでした。
任意の SQL を実行する mysql_sql
というリソースを使えば何でもできそうではあったのですが、あまりうまくいきませんでした。
ソースコードを読んだりもしたのですが、既存の MySQL provider だと実現できなさそうなことがわかりました。
既存の MySQL provider の問題点
既存の MySQL provider は全て https://github.com/hashicorp/terraform-provider-mysql を fork して各々が欲しい機能を少しずつ追加していったものでした。もちろん fork の fork もあったりしました。
いくつかあった問題点なのですが、概ね以下の通りです。
- デフォルトロールをサポートしていない
- カラム単位の権限管理をサポートしていない
- アカウントロックをサポートしていない
-
terraform import
をサポートしていないリソースがある - terraform-plugin-sdk/v2 を使っている
- SQL の組立て方が文字列連結のみで行なわれており、つらい
- MySQL5.7 以前と MySQL8 以降をサポートしようとしていてバージョン分岐がつらい
- ドキュメントが微妙に抜けている
このうちデフォルトロールをサポートしていないこととアカウントロックをサポートしていないことが、自分のやりたいことができない原因だったので既存の terraform-provider-mysql に機能を追加するべくコードをさわってみたのですが、上に書いたような問題があってそのまま機能だけ追加してもダメな感じがしたので新しく作ることにしました。
新しく作った terraform-provider-mysql の特徴
- terraform-plugin-framework を使っている
- SQL の実行になるべくストアドプロシージャを使っている
-
SHOW GRANTS
の結果をパースするのに tidb の SQL parser を使っている - アカウントのロックに対応している
- カラム単位の権限設定に対応している
- デフォルトロールをサポートしている
-
terraform import
をサポートしている - 既存の terraform-provider-mysql とは互換性がない
- 全ての resource/data source のドキュメントが揃っている
-
mysql_user
で tfstate 上のパスワードをハッシュ化していない- MySQL8 で追加された
caching_sha2_password
のハッシュ化をサポートするのが難しかったのと terraform-plugin-framework でハッシュ化したパスワードを tfstate に書き込む方法がわからなかったため
- MySQL8 で追加された
既存の terraform-provider-mysql からの移行方法
terraform state rm
して設定ファイルを修正してから、一つずつ terraform import
すればよいです。
たぶん tfmigrate を使えばいい感じに移行できると思います。
既存の MySQL provider での書き方。
resource "mysql_user" "test" {
user = "test"
}
新しい MySQL provider での書き方。
resource "mysql_user" "test" {
name = "test"
}
ユーザー名を指定する attribute の名前が異なるので互換性はありません。
まとめ
そんな感じで terraform-provider-mysql を作って公開しました。
既に本番環境の provider を今回作ったものに置き換えています。
Discussion