IAMデータベース認証でRDS PostgreSQLに接続してみた

Amazon RDS の PostgreSQL 系サービス

  • Amazon RDS for PostgreSQL
  • Amazon Aurora PostgreSQL

は IAM データベース認証を使用して、DB インスタンスを認証できます。

アプリケーションから DB にアクセスする際、クレデンシャルは

  • アプリケーション内にべた書き
  • メタデータ(タグ、環境変数)で管理
  • AWS Systems Manager パラメータストア で管理
  • AWS Secrets Manager で管理
  • Hashicorp Vault のようなミドルウェア

などで管理します。これらはすべて永続的な認証情報を利用します。

一方で、IAM データベース認証は一時的な認証情報を利用します。さらに、この認証情報を取得する API をインスタンスプロファイルが有効な EC2 から呼び出すと、その API 呼び出し時も一時的な認証情報を利用するため、認証情報の管理がよりセキュアになります。

また、複数の DB インスタンスに対して、同じ IAM ユーザー/ロールで認証できるため、DB アクセスを一元管理しやすくなります。

それでは、この認証方式を試してみます。

作業の流れ

以下の流れで作業します。

  1. IAM データベース認証を有効にした DB インスタンスの作成
  2. IAM データベース認証用 PostgreSQL ユーザーを作成
  3. IAM データベース認証用ポリシーを作成
  4. RDS が発行する認証トークンを取得して DB 接続

手順は Aurora と 非 Aurora で実質的に同じです。 今回は Amazon Aurora PostgreSQL 9.6.9 を利用します。

1. IAM データベース認証を有効にした DB インスタンスの作成

Amazon Aurora PostgreSQL 9.6.9 のインスタンスを作成します。

"Step 3:Configure advanced settings" で IAM データベース認証を有効にします("Enable IAM DB authentication")。

Amazon Aurora PostgreSQL 9.6.8 のように、データベース認証に対応していないバージョンでは、この選択肢は表示されません。

2. IAM データベース認証用 PostgreSQL ユーザーを作成

PostgreSQL に接続し、IAM データベース認証用ユーザー(jane_doe) を作成し、rds_iam ロールを GRANT します。

dbname=> CREATE USER jane_doe WITH LOGIN;
CREATE ROLE
dbname=> GRANT rds_iam to jane_doe;
GRANT ROLE

3. IAM データベース認証用ポリシーを作成

IAM データベース認証を利用する ポリシーを作成し、IAM ユーザー/ロールにアタッチします。

ポリシーテンプレート

{
   "Version": "2012-10-17",
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
             "rds-db:connect"
         ],
         "Resource": [
             "arn:aws:rds-db:region:account-id:dbuser:dbi-resource-id/database-user-name"
         ]
      }
   ]
}

環境に合わせて以下の値を変更してください。

  • region
  • account-id
  • dbi-resource-id(DB インスタンス ID または DB クラスター ID)
  • database-user-name(IAMデータベース認証に利用するユーザー名)

例)DBインスタンスをまるっと指定

まるっと許可したいときは「*」 を利用します。

次の例では、任意の DB インスタンスの jane_doe ユーザーに対して IAM データベース認証を許可します。

{
   "Version": "2012-10-17",
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
             "rds-db:connect"
         ],
         "Resource": [
             "arn:aws:rds-db:us-west-2:123456789012:dbuser:*/jane_doe"
         ]
      }
   ]
}

例)DBインスタンとユーザー名を明示的に指定

次の例では、DB インスタンス db-12ABC34DEFG5HIJ6KLMNOP78QRのユーザー(jane_doeまたはmary_roe)に対して IAM データベース認証を許可します。

{
   "Version": "2012-10-17",
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
             "rds-db:connect"
         ],
         "Resource": [
             "arn:aws:rds-db:us-west-2:123456789012:dbuser:db-12ABC34DEFG5HIJ6KLMNOP78QR/jane_doe",
             "arn:aws:rds-db:us-west-2:123456789012:dbuser:db-12ABC34DEFG5HIJ6KLMNOP78QR/mary_roe"
         ]
      }
   ]
}

dbi-resource-id に設定する値

dbi-resource-id

  • DB インスタンスリソース ID
  • (Aurora の場合)DB クラスターリソース ID

のどちらかを指定できます。

管理コンソールから確認

管理コンソールでは

  • DB インスタンス
  • クラスター

それぞれの詳細ページから確認可能です。

DB インスタンスリソースIDを確認

DB クラスターリソースIDを確認

AWS CLI から確認

DB インスタンスリソースIDを取得

$ aws rds describe-db-instances \
 --query "DBInstances[*].[DBInstanceIdentifier,DbiResourceId]"
[
    [
        "test",
        "db-XXX"
    ]
]

DB クラスターリソースIDを取得

$ aws rds describe-db-clusters --query "DBClusters[*].[DBClusterIdentifier,DbClusterResourceId]"
[
    [
        "test-cluster-id",
        "cluster-XXX"
    ]
]

4. RDS が発行する認証トークンを取得して DB 接続

aws rds generate-db-auth-token API で一時認証トークンを取得します。 この値をパスワードとして環境変数 PGPASSWORD に渡し、PostgreSQL と認証します。

認証トークンの有効期間は15分です。

$ RDSHOST=CLUSTER-ID.XXX.eu-central-1.rds.amazonaws.com
$ export PGPASSWORD="$( aws rds generate-db-auth-token --hostname $RDSHOST --port 5432 --username jane_doe )"
$ psql "host=$RDSHOST dbname=dbname user=jane_doe"
psql (9.5.0, server 9.6.9)
WARNING: psql major version 9.5, server major version 9.6.
        Some psql features might not work.
SSL connection (protocol: TLSv1, cipher: DHE-RSA-AES256-SHA, bits: 256, compression: off)
Type "help" for help.

dbname=> select version();
                                  version
------------------------------------------------------------------------------
PostgreSQL 9.6.9 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.9.3, 64-bit
(1 row)

無事接続できました。

なお、psql コマンドはデフォルトで SSL 通信します。

Amazon RDS PostgreSQLにpsqlからSSL接続する

PAM authentication failed が発生したら?

残念ながら、IAM ロールを利用して aws rds generate-db-auth-token API を呼び出すと、以下の様な PAM authentication failed エラーが発生し、認証に失敗します。

$ psql ...
psql: FATAL:  PAM authentication failed for user "jane_doe"
FATAL:  pg_hba.conf rejects connection for host "172.31.19.116", user "jane_doe", database "dbname", SSL off

ドキュメントを読むと、IAM ロールには対応していない旨が記載されています。

Role-based authentication is currently not supported.

PostgreSQL Limitations for IAM Database Authentication

Lambda/EC2 などで IAM ロールを利用しているユーザーは頭を抱えてしまいますが、回避策もあります。

RDS フォーラムに投稿されているようにaws sts assume-role API でロールを明示的に assume したあとで、aws rds generate-db-auth-token API を呼び出せば回避できます(2018/11/09 確認)。

具体的には次の Bash スクリプトのような手順になります。

#!/bin/bash

USERNAME=jane_doe
RDSHOST=CLUSTER-ID.XXX.eu-central-1.rds.amazonaws.com
ROLE=RDS_IAM_AUTH_ROLE
DBNAME=dbname

# 明示的に IAM Auth 用ロールを assume

result="$(aws sts assume-role --role-arn arn:aws:iam::1234567890:role/$ROLE --role-session-name dummy_session_name --duration-seconds 900)"

export AWS_ACCESS_KEY_ID=`echo ${result} | jq -r '.Credentials.AccessKeyId'`
export AWS_SECRET_ACCESS_KEY=`echo ${result} | jq -r '.Credentials.SecretAccessKey'`
export AWS_SESSION_TOKEN=`echo ${result} | jq -r '.Credentials.SessionToken'`

# IAM DB Auth 用トークンで接続

export PGPASSWORD="$(aws rds generate-db-auth-token --hostname $RDSHOST --port 5432 --username $USERNAME)"
psql "host=$RDSHOST dbname=$DBNAME user=$USERNAME"

なお MySQL 向け IAM データベース認証にはこのような制約は存在しません。

フォーラムを読む限り、開発チームも issue として認識しているようなので、将来的にはIAM ロールからもシームレスに利用できるようになるはずです。

IAM データベース認証を利用可能な PostgreSQL のバージョン

  • Amazon RDS for PostgreSQL
    • 9.5.13 以上
    • 9.6.9 以上
    • 10.4 以上
  • Amazon Aurora PostgreSQL
    • 9.6.9 以上

※ Aurora PostgreSQL 9.6.8 は対応していません。

MySQL 系の IAM データベース認証方法

MySQL 向け IAM データベース認証方法は以下を参照ください。

最後に

AWS 公式ドキュメントにあるIAM データベース認証の利点を列挙します。

  • データベースに出入りするネットワークトラフィックは、Secure Sockets Layer (SSL) を使用して暗号化されます。
  • IAM を使用して各 DB インスタンスで個別に管理するのではなく、データベースリソースへのアクセスを一元的に管理できます。
  • Amazon EC2 で実行するアプリケーションの場合、セキュリティを高めるため、EC2 インスタンスプロファイルの認証情報を使用して、パスワードの代わりにデータベースにアクセスできます。

特に、後ろ2つは IAM データベース認証の大きな利点です。 これらのメリットに大きな魅力を感じる場合は、IM データベース認証の利用を一度検討してみてはいかがでしょうか。

参考