Terraformを用いてRDSで作成したsecret managerのARNを参照する方法
こんにちは、ソーシャルデータバンク株式会社、日吉事業部のkevin-nambaです。普段は複数プロダクトの横断SREとして活動しています。
検証環境などを含めると環境構築回数が多い一方でインフラを触ることができる人が少ないので管理が煩雑になってしまうという問題がありました。そこで、日吉事業部では、TerraformコマンドでALB、RDS、ECSのサービスが一発で立ち上がるTerreformのテンプレートを作成しています。
今回は、ワンコマンドでRDSのパスワードを作成でき、かつECSからも参照できるという方法を試したので、共有させていただきます。
Terraformのパスワード管理について
TerraformでRDSを作成する際はパスワードを指定することができます。
resource "aws_db_instance" "default" {
allocated_storage = 10
db_name = "mydb"
engine = "mysql"
engine_version = "5.7"
instance_class = "db.t3.micro"
username = "foo"
password = "foobarbaz"
parameter_group_name = "default.mysql5.7"
skip_final_snapshot = true
}
また、シークレットも同様にTerraformで作成することができます。
resource "aws_secretsmanager_secret" "example" {
name = "example"
}
envファイルなどからパスワードを読み取るようにして、Terraformのファイルに機密情報が乗らないようにすれば、Gitなどに機密情報が共有することを防ぐことはできますが、tfstateにパスワードが乗ってしまう、という問題があります。また、envファイルのパスワード管理を個人に任せてしまうことになり、紛失や流出のリスクが上がる、といった問題もあります。
そこでしばらくは
- とりあえず初期パスワードをTerraformで設定する
- GUI上でシークレットマネージャーのシークレットを作成
- GUI上でデータベースのパスワードを2のパスワードに変更する
- ECSのsecretsからシークレットマネージャーのarnを参照
という運用をしていました。
しかし、Terraformコマンド1個でデプロイされるのが利点だったはずが、RDSのパスワードのために何個も作業が必要になってしまいました。また、ECSのタスクにシークレットマネージャーのシークレット変更を反映させる必要があるため、サービスを再起動する必要がある、という問題がありました。
RDSのシークレットマネージャー連携機能について
RDSにはシークレットマネージャーにシークレットを自動で作成して、そのシークレットをDBのパスワードで用いるという機能があり、Terraformでもサポートされています。
resource "aws_db_instance" "default" {
allocated_storage = 10
db_name = "mydb"
engine = "mysql"
engine_version = "5.7"
instance_class = "db.t3.micro"
username = "foo"
// password = "foobarbaz"
//シークレットマネージャーで作成したシークレットを使う
manage_master_user_password = true
parameter_group_name = "default.mysql5.7"
skip_final_snapshot = true
}
ECSからシークレットマネージャーにアクセスする際はarnを指定する必要がありますが、このシークレットは、Terraformのリソースとしては存在しないので、後から指定し直すという必要がありました。
また、そのシークレット名はデータベースと関係ないuuidで作成されており、後から指定することを自動化することも難しそうです。
作成したsecret managerのarnを参照する方法
そこでTerraformのrdsで作成したsecret managerのarnはrdsリソースから作成することができることを見つけました!
公式ドキュメントにほのめかされてはいるのですが、実際にどう使うかは書いていなかったand調べても出てこなかったので、この記事が誰かの役に立てば幸いです。
output "aws_rds_db_password_arn" {
value = aws_db_instance.default.master_user_secret[0].secret_arn
}
なぜaws_db_instance.default.master_user_secret
配列なのかは謎ですが(誰かご教授いただけると嬉しいです)、この値をECSのタスク定義に渡してあげることで、Terraformコマンド一発でRDSのシークレットを作成してECSから呼び出すことができ、その情報はtfstateにもローカルにも残らない、という仕組みを作ることができました
Discussion