ご挨拶と記事概要
こんにちは株式会社ヤポドゥ・技術部所属、インフラエンジニア見習いのkojiroです。 今回はAWS Secrets Managerを使用する際に自動で生成されるシークレット名をカスタム可能かについて投稿します。 尚、こちらの投稿はAWS RDS系DBの環境変数をSecrets Manager管理にする場合にフォーカスしています。 DBを使わないケースのプロジェクトは昨今、稀ではありますがそれ以外のケースを割愛しておりますことをお断りしておきます。
目次
TerraformでSecrets Managerを使ってみた
TerrafromでSecret Managerを有効にするコマンドは以下の様に構成します。
resource "aws_rds_cluster" "main" { cluster_identifier = "myapp-db" engine = "aurora-postgresql" manage_master_user_password = true }
上記コマンドで大事な箇所はmanage_master_user_password = true
であり
このコマンドがあることでSecrets Managerが起動し、DBの環境変数を自動生成、自動管理、自動連携してくれます。
Secrets Managerがシークレット名( 環境変数データの識別子 )を生成します。
rds!cluster-myapp-db-a1b2c3d4e5.....
このシークレット名を使ってTerraformに環境変数が渡されます。この時Terraformがシークレット名を管理していない事も重要なポイントです。 シークレット名の確認コマンドは以下になります。
aws secretsmanager list-secrets \ --query "SecretList[?starts_with(Name, 'rds!cluster-')].Name" \ --output text
シークレット名を使いたくない理由
このセクションではSecrets Managerで生成されたシークレット名を使いたくない理由を列挙していこうと思います。まるで恨み節のように。
➀シークレット名は長くてかっこ悪い使いづらい。
➁Terraformでせっかく決めた命名規則と足並みがそろわない。
➂シークレット名だけ他の変数名と比べて浮いてしまう。セキュアなはずなのに目立つからなんだか不安。
④とにかく使いたくない。コントロールしたい。
技術的な側面はそっちのけで感情論をぶつけて、無理やり広げてみました。
たったの4つでした。でも共感してほしい。
シークレット名を分解してみた
Secret Managerで生成されたシークレット名を分解し、それがどのような内容なのか調べてみるとなんとなく見えてくる大事なポイントがあります。
シークレット名( 見本 )
rds!cluster-myapp-db-a1b2c3d4e5.....
構成分解
rds!cluster : AWSが予約している接頭辞( プレフィックス )
myapp : インフラコードcluster_identifierの箇所で指定した名前が使われる。唯一任意に決められる命名箇所。
a1b2c3d4e5.... : AWSが自動生成したランダムID識別子 そしてこのシークレット名に紐づけられて呼び出される中身が以下のようなjson形式の内容になります。これがシークレット名の実体であり、環境変数として渡されます。
{ "engine": "aurora-postgresql", "host": "example.cluster-abcdefghij.us-west-2.rds.amazonaws.com", "username": "master", "password": "5L8*kswJdK!zqT2h", "dbname": "postgres", "port": 5432 }
こちらの内容もAWS側で自動生成され、RDSとSecrets Managerが話し合って決定します。 内容をカスタムすることは当然できません。 シークレット名に紐づいて呼び出す内容(json)を使って、それぞれの項目に合わせて名前と値で呼び出す、キーとバリューの関係でマッピングしていくRDSとSecrets Managerの連携システムです。
それを踏まえて見えてきそうなこと、
- シークレット名って大事そう。
- 予約しているプレフィックスと長いランダムIDで出来てるんだ!
- シークレット名の中身ってjsonなんだ。
- それってRDSとSecrets Managerが話し合って決めているんだ!
結論
- シークレット名はカスタム不可能な大事な識別子です。
- Terraformの命名規則にあわせてresource構文を使い、変数名を再定義( rds!cluster-myapp-db-a1b2c3d4e5..... = secrets_myapp_db )しようものなら即座にRDSとの連携が壊れます。AWS側で認識されなくなります。( Terraformが管理していない理由 )
自己管理 VS AWS管理
結論を踏まえてそれでも自分で決めた命名規則で環境変数を運用したい場合
manage_master_user_password = true
をTerraformで指定せず、自前で
resource "aws_secretsmanager_secret" "myapp_db" { name = "secrets_myapp_db" } resource "aws_secretsmanager_secret_version" "myapp_db_version" { secret_id = aws_secretsmanager_secret.myapp_db.id secret_string = jsonencode({ username = "admin" password = "your-secure-password" engine = "aurora-postgresql" host = "myapp-db.cluster-xxxxxx.ap-northeast-1.rds.amazonaws.com" port = 5432 }) }
などとして定義してしまいましょう。
そうすればTerraform管理で他のリソースとの命名に足並みをそろえた実装を可能にします。
Terraformの命名規則を使い慣れている人ならその管理コストはSecrets Managerを使うよりコスパがいいと判断する見方もあるかもしれません。
セキュリティーの強度に少しの優劣があるものの、やっている事の本質に大きな違いはありません。 ただ重要なのはこの後です。
AWSが環境変数の運用にあたってSecrets Managerを使う事を推奨している点に有無を言わさぬ、正義があります。
推奨理由として以下があげられるでしょう。
- AWSが環境変数をすべて自動で管理してくれる
- AWSが強力なランダムパスワードを自動生成してくる
- パスワードを自動でローテーションをしてくれる
- 設定ミスのリスクがほとんどない
- AWSベストプラクティスに準拠出来る
- AWS他サービスとネイティブに連動する
以上の理由から自己管理で使いやすい名前を取るか、AWS管理でコントロールできない長い名前を使うか、天秤にかけ決断してください。
以上で" あなたの正義はどっち?命名規則とシークレット名 "を終わります。
参考資料 : AWS公式ページURL https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-secrets-manager.html?utm_source=chatgpt.com
RDSとsecrets managerが密に連携してパスワードが生成されているようでそこにterraformの変数名の定義が入り込む余地はない解釈です。
仮に動作してもAWSは推奨していない為、誤動作があっても責任を取らないというスタンスだと思います。