Techfirm Cloud Architect Blog

テックファーム株式会社クラウドインフラグループのブログ

DBメンテでのIAMデータベース認証の利用

Aurora MySQLの管理用ユーザをIAM認証にしたので紹介します。
RDS MySQLでも可能ですし、PostgreSQLにもIAM認証は存在します。

※ 構築にはTerraformを利用していますので、設定方法はTerraform利用を前提としています

構成概要

Aurora MySQLへのアクセス経路は踏み台サーバ経由のみとし、その踏み台サーバもSessionManager経由でのアクセスとしていました。 アクセスは踏み台を経由すればポートフォワーディングでもmysqlコマンドでも可能です。
その上で、管理用ユーザが固定パスワードにならないようIAM認証を導入しました。 DBメンテ構成

認証・認可がIAMに集約されるので不要ユーザの削除漏れ対策にもなります。

管理ユーザへのIAM認証導入のメリット

IAMで権限を集中管理

各ユーザやロールに設定するIAMポリシーでどのDBのどのユーザに接続可能か設定できます。
さらに踏み台サーバへの接続制限もSessionManager経由のみとなるため、すべてIAMユーザ/ロールを利用したアクセスにする事ができました。

パスワードが固定化されない

IAM認証では、コマンドにより毎回パスワードを発行する形になります。そのパスワードも15分間の制限付きです。(最初の認証に利用するだけなので時間を過ぎても接続済みのセッションが切断される事はありません)
DBパスワードが固定化されないので、共通ユーザになっている場合でも『退職者がパスワードを知ってる』ような事にはなりません。(誰がアクセスしたか管理するためにDB側も個人ユーザにすべきかとは思いますが)

MFAが必要にできる

今回の案件ではロールに対して権限を割り当て、各ユーザのロールへのスイッチを制限して権限管理を行っています。
ロールへのスイッチにMFA認証の必須化とIPアドレス制限を行う事で、DB接続にMFAも必須にする事ができます。

管理ユーザへのIAM認証導入のデメリット

パスワード生成が必須で面倒

利用時に毎回パスワード生成が必要になるため、接続のためのステップが少し増えます。そのため、場合によっては利用者へのフォローが必要です。
私は、AWS CLIに慣れていない開発者のために、Windowsバッチを作成して配布しました。

導入方法・利用方法

参考: https://aws.amazon.com/jp/premiumsupport/knowledge-center/users-connect-rds-iam/

導入

IAM認証の準備は以下のようになります。

  1. RDSインスタンス/ClusterでIAM認証を有効化しておく
  2. MySQLにユーザを作成する
  3. IAMユーザ/ロールに権限を設定する

IAM認証を有効化

TerraformでAuroraならaws_rds_clusterリソースに、RDS MySQL等ならaws_db_instanceリソースに以下の設定を入れます。

iam_database_authentication_enabled = true

対応バージョンの制限があるので、古い環境に導入する場合は事前に対応しているか調べておく必要があります。
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html#UsingWithRDS.IAMDBAuth.Availability

MySQLにユーザを作成

MySQLの場合はAWSAuthenticationPluginを利用して認証するユーザを作成します。(前述の設定でIAM認証が有効化されていないとエラーになります)

CREATE USER 'adminuser'@'10.1.0.0/255.255.255.0' IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS';

ユーザに対する権限設定(GRANT文)は通常通り実施します。

IAMユーザ/ロールに権限を設定

対象のIAMユーザやロールのポリシーにrds-db:connect権限を追加します。以下は追加する行の例です。

{
    "Sid": "DBConnect",
    "Effect": "Allow",
    "Action": [
        "rds-db:connect"
    ],
    "Resource": [
        "arn:aws:rds-db:ap-northeast-1:123456789012:dbuser:cluster-KITB2ZNFNV3MVJYGOAAPGUP2UE/adminuser"
    ]
}

Resourceは、どのDBのどのユーザへ接続可能かを指定でき、ワイルドカードも利用できます。 上記で『cluster-KITB2ZNFNV3MVJYGOAAPGUP2UE』はAuroraクラスタまたはRDSインスタンスのリソースIDにあたります。
Terraformの場合は、aws_rds_clusterリソースのcluster_resource_idか、aws_db_instanceリソースのresource_id属性値で取得可能です。
『adminuser』は先に作成したMySQLユーザのユーザ名にあります。

利用

作成したユーザの利用方法は以下のようになります。

  1. パスワードを生成する(トークンの発行)
  2. ユーザ/パスワードでログインする

パスワードの生成

AWS CLI等でトークン(パスワード)を生成可能です。トークン生成には、接続先エンドポイント、接続先ポート番号、接続ユーザ名が必要です。

aws rds generate-db-auth-token --hostname dev-db01.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com --port 3306 --username apadmin

実際には、AWS CLIの設定や上記コマンドはスクリプト化しておいて事前設定や利用の手間が少なくなるようにしていました。
面倒なので、なるべく手間が少なくなるよう工夫は必要かと思われます。

ここで生成される文字列は以下のような長いものですが、すべてをパスワードとして利用します。

dev-db01.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com:3306/?Action=connect&DBUser=adminuser&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAVPNIT0A0A0A0A0AD%2F20220630%2Fap-northeast-1%2Frds-db%2Faws4_request&X-Amz-Date=20220630T042734Z&X-Amz-Expires=900&X-Amz-SignedHeaders=host&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEND%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaBcDeFgHiJkLmNoPqIkcwRQIgLxSeOCR01vNKreBs39r4UPS5H9Auzy7Zz3RG%2BtrY%2BQsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%2BXrdTaJ%2Bq6zQvluCqUAwjp%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAEaDDM3NjcwMDEzOTYwMCIMuDznae6TybD967SgKugCwRJjX7SW5ShYfGYzrZWDi5LBmrLISYTiEe9O6cbzeqVuVpLLit0y0Kvp2u5wFk36sOIVpmoB%2FNmxbL%2BMXPA3vAKD%2FtAK9rkpKavfSv04os2XbElDAphhBOYPs3ZUO0kT3KCfnsU97Kd0tfubpD9hD9vGLKm%2BrF0pynsEH%2BqF78CWCUkdqCEX%2Bzlg6V3uhnay98Jb5M22wjSWMcLmij1SkhCTAlWLOkKhoXEUgRydmFNiq4MzBEQEax317zxhg11rgPetSmqNPktR3VhkU2UlNw14C5OECXjCl08CTrAi7TAQkh4zb%2FCidGdYMFCglcYZ4TyEfySDaMwFpkmVqOTXy8jlGs0KlUNUF%2Bx1vbuknJQ9Ozdy5Q3pL2Q%2Fh7LyfJNZDcbSSgjxEH6w9LVjuh9zUk7n9w5TR3PvrvPgb6yiBD5TtcE9DPU%2F24vTyLzT5OnmOToJRrEqcGSadfdB%2FieOaQeoJOmQu58tMMHi6pUGOqYBLGL6hOzLRzEyujoSr5qQ%2B%2Byr5rUg14ICyGKB8hPXVAmqFYOkh6d8i7z%2Bn3oxmg0C9Nq0Dx5Ks9FWM%2B9B96r0%2B%2Fzkwma4Q1pSVVxXkwdEhyRFj%2BY25GKCJ4rttvowMtSneRoH%2FAtlM9yTOBAEwPqtOfTV7jdW6LlvOoxHZVpZPx4hYbef2dyY9r518ZaJqG2s%2BpVEIf03rXTgFEwtMIZcwzFTcbxp6w%3D%3D&X-Amz-Signature=c094677xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5e7561414bafdb5698e507cd4b9

最初の『dev-db01……』から最後の『……d4b9』までの文字列すべてがパスワード文字列になります。パスワードに見えないので、最初は戸惑うところです。
また、権限がない場合でも接続先のホスト名を誤っている場合でもコマンドは成功し、トークンが生成されます。権限の評価はDBでの認証時に実施されるようです。

ユーザ/パスワードでログイン

通常通りmysqlコマンドやDB接続ツールで接続します。
この時、接続先はパスワード生成に利用したホストやポート番号、ユーザ名を利用します。
パスワードにはパスワード生成で生成した文字列をすべて入力します。前述したように、パスワードに見えなくても文字列すべてをパスワードとして入力します。

注意点

接続権限やクレデンシャルの有効性検証

『aws rds generate-db-auth-token』は、接続先の指定が間違っていようとAWS認証情報が期限切れになっていようと成功します。
トークンが生成されたからと言って、それが正しいかどうかは分かりません。 実際にDB接続して認証してみないと分かりません。

出力されたトークン全体がパスワード

『aws rds generate-db-auth-token』で生成される文字列は、まるでURLの一部のようになっています。
最初の接続先ホスト名も含めて、出力された文字列をパスワードとして入力する必要があります。文字列は長い上に『&』等の文字列も含むのでスクリプト等で利用する場合は注意してください。

CloudTrailには出てこない

『rds-db:connect』がCloudTrailに出ることを期待しましたが、出てきませんでした。