Amazon Web Services ブログ

サーバーレスアプリケーションから Amazon Aurora への IAM ロールベース認証



ユーザー名とパスワードをアプリケーションに直接保存することはベストプラクティスではありません。セキュリティで保護されたアプリケーションでは、資格情報をプレーンテキストとして保存しないでください。ソリューションとして、AWS Identity and Access Management (IAM) ポリシーは、Amazon Aurora リソースを管理できるユーザーを決定するアクセス許可を割り当てることができます。たとえば、IAM を使用して、DB クラスター、タグリソース、またはセキュリティグループを作成、記述、変更、削除できるユーザーを決定できます。Amazon Aurora では、データベースユーザーを IAM ユーザーとロールに関連付けることができます。

この記事では、AWS Lambda 関数を使用して IAM を使用して Amazon Aurora データベースにアクセスする方法を説明します。

概要

IAM データベース認証を使用して、DB クラスターに接続できます。この方法を使用すると、パスワードを設定ファイルに保存する代わりに、生成された認証トークンでデータベースにアクセスできます。Amazon Aurora は、アプリケーションから接続を作成するために 15 分間有効な AWS Signature Version 4 認証トークンを生成します。認証は IAM によって外部で完全に管理されるため、データベースに認証情報を作成する必要はありません。

チュートリアル

次の図は、ワークフローを示しています。

Lambda は、サーバーのプロビジョニングまたは管理を行うことなく、コードを実行するコンピューティングサービスです。Lambda は、必要な場合にのみコードを実行し、1 日あたり数回のリクエストから毎秒数千ものリクエストにまで自動的にスケールします。Lambda を使用するときは、コードに対してのみ責任があります。Lambda は、メモリ、CPU、ネットワークや他のリソースのバランスを提供するコンピュートフリートを管理します。Lambda は Lambda 関数を実行し、結果を返します。

コンソールで Lambda 関数を作成する方法は次のとおりです。

  • [AWS Lambda コンソール] を開きます。
  • [関数の作成] を選択します。
  • 関数名には、demo-function と入力します。
  • 優先言語ランタイムを選択します。この記事では、Python 3.7 を選択します。
  • 権限については、[基本的な Lambda 権限で新しいロールを作成] を選択します。これにより、ログを Amazon CloudWatch にアップロードする権限を持つ実行ロール (たとえば、demo-function-role-ipqlab4h) が作成されます。
  • [関数を作成] を選択すると、次のスクリーンショットに示すオプションが表示されます。

Designer では、トリガーを設定して権限を表示できます。

次のスクリーンショットに示すように、AWS Lambda コンソールエディタを使用して関数を作成できます。

Lambda には、成功応答を返すサンプルコードが含まれています。Lambda コンソールのコードエディタを使用すると、Lambda 関数コードの実行結果を記述、テスト、表示できます。

ソースコードが 3 MB の制限を超えない限り、組み込みの AWS Cloud9 エディタで関数コードを編集できます。AWS SDK 以外のライブラリと依存関係を含める必要がある場合は、デプロイパッケージを作成する必要があります。50 MB を超えない場合、パッケージを直接アップロードできます。それ以外の場合は、Amazon S3 にアップロードしてから Lambda にアップロードできます。

次のスクリーンショットは、Lambda 環境変数を設定できるダイアログボックスを示しています。

Lambda 関数の環境変数により、コードを変更せずに、設定を関数コードとライブラリに動的に渡すことができます。

次のスクリーンショットは、Lambda 実行ロールを設定できるダイアログを示しています。

Lambda 関数の実行ロールは、AWS のサービスとリソースへのアクセス権限を付与します。

次のスクリーンショットは、ネットワークを選択できるダイアログボックスを示しています。

デフォルトでは、Lambda 関数はパブリックインターネットアドレスとパブリック AWS API にアクセスできます。プライベートサブネットにある Amazon RDS などのプライベートリソースにアクセスするには、VPC の Lambda 関数を有効にする必要があります。データベースインスタンスが存在する同じ VPC で Lambda 関数を設定することをお勧めします。さらに、プライベートサブネットのルートテーブルに NAT ゲートウェイが追加され、Lambda 関数にインターネットアクセスが許可されているようにしてください。

IAM 認証を使用して Lambda 関数から Amazon Aurora にアクセスする方法は次のとおりです

  • 次の手順に進む前に、マシンに AWS Command Line Interface (AWS CLI) をインストールして設定する必要があります。
  • 次のように AWS CLI を使用して、DB クラスターで IAM データベース認証を有効にしますAWS マネジメントコンソールまたは Amazon RDS API を使用することもできます。
    aws rds modify-db-cluster --db-cluster-identifier <cluster-identifier> --enable-iam-database-authentication --apply-immediately
    • cluster-identifier: DB クラスターの名前。
      例:

      aws rds modify-db-cluster --db-cluster-identifier mysql-demo  --enable-iam-database-authentication --apply-immediately
  • DB クラスターに接続し、次のようにログイン特権を持つユーザーを作成し、そのユーザーに IAM ロールへのアクセスを許可します。
    • PostgreSQL: ユーザーに rds_iam 特権を付与します。
      CREATE USER <db_user_name> WITH LOGIN; 
      GRANT rds_iam TO <db_user_name>;

      例:

      CREATE USER  demouser WITH LOGIN; 
      GRANT rds_iam TO demouser;
    • MySQL: 次のように特権を付与します。
      CREATE USER < db_user_name> IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS';
      GRANT ALL PRIVILEGES ON <dbname>.* TO '<db_user_name>’ @'%';

      例:

      CREATE USER demouser IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS';
      GRANT ALL PRIVILEGES ON demodb.* TO 'demouser’ @'%';
      FLUSH PRIVILEGES;
  • 次に、前の手順で作成したユーザーが IAM データベース認証を使用してデータベースにアクセスできるようにするポリシーを作成します。詳細については、「IAM ポリシーと IAM データベースアクセス」を参照してください。
    ポリシー文書:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "rds-db:connect"
                ],
                "Resource": [
                    "arn:aws:rds-db:<region>:<account-id>:dbuser:<DbiResourceId>/<db_user_name>"
                ]
            }
        ]
    }

    次の設定を使用します。

    • リージョン: データベースインスタンスのリージョン。
    • account-id: データベースインスタンスの AWS アカウント番号。
    • DbiResourceId: DB インスタンス識別子、またはアカウントのリージョン内のすべてのデータベースインスタンスを許可する「*」。
    • db_user_name: データベースに作成されたユーザー。データベース内のすべてのユーザーに IAM 認証を許可するには、特定のユーザー、または「*」に言及します。

    AWS CLI を使用してポリシーを作成するには、次の例に従ってください。

    aws iam create-policy --policy-name my-policy --policy-document '{
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "rds-db:connect"
                ],
                "Resource": [
                    "arn:aws:rds-db:us-east-1:123456789012:dbuser:*/demouser"
                ]
            }
        ]
    }'
  • 次に、以下のようにこのポリシーを Lambda 関数に関連付けられた IAM ロールにアタッチします。
    aws iam attach-role-policy --role-name <role_name> --policy-arn <policy_arn>
    • role_name: Lambda 関数に関連付けられた IAM ロール (たとえば、demo-function-role-ipqlab4h)。
    • policy_arn: IAM データベース認証用に作成された IAM ポリシーの ARN (たとえば、「arn:aws:iam::123456789012:policy/my-policy」)。
  • Lambda で次の環境変数を設定します。
    • DBEndPoint: DB インスタンスのエンドポイント (たとえば、ab9c3efgh31k.us-east-1.rds.amazonaws.com)。
    • DatabaseName: データベースの名前。
    • DBUserName: 前の手順で作成したユーザー名 (たとえば、demouser)。

ネットワークトラフィックを暗号化するには、この例など、RDS 指定のルート SSL 証明書を使用します。この SSL 証明書をデプロイパッケージに含める必要があります。

Lambda 関数から Amazon Aurora PostgreSQL データベースにアクセスするには、デプロイパッケージの一部として pg8000 (PostgreSQL Driver) ライブラリを含める必要があります。

Amazon Aurora PostgreSQL の Lambda 関数は次のとおりです。

import boto3
import pg8000
       
def lambda_handler(event, context):
     try:
         # rds のサービス名で低レベルクライアントを作成する
         client = boto3.client("rds")
         # 環境変数を読み取り、DB EndPoint を取得する
         DBEndPoint = os.environ.get("DBEndPoint") 
         # 環境変数を読み取り、データベース名を取得する 
         DatabaseName = os.environ.get("DatabaseName")
         # 環境変数を読み取り、データベースにアクセスできるデータベースユーザー名を取得します。
         DBUserName = os.environ.get("DBUserName")
         # IAM 認証情報を使用してデータベースに接続するために使用する認証トークンを生成します。
         password = client.generate_db_auth_token(
             DBHostname=DBEndPoint, Port=5432, DBUsername=DBUserName
         )
         # パスワードとして生成されたトークンを使用してサーバーとの接続を確立する 
         conn = pg8000.connect(
             host=DBEndPoint,
             user=DBUserName,
             database=DatabaseName,
             password=password,
             ssl={"sslmode": "verify-full", "sslrootcert": "rds-ca-2015-root.pem"},
         )
         # カーソルオブジェクトのインスタンス化
         cursor = conn.cursor()
         # 実行されるクエリ
         query = "SELECT CURRENT_DATABASE()"
         # 接続されたデータベースでクエリ/コマンドを実行する
         cursor.execute(query)
         # 列名を取得する
         columns = [str(desc[0].decode("utf-8")) for desc in cursor.description]
         results = []
         # 結果セットから dict の行を作成します。
         for res in cursor:
             result.append(dict(zip(columns, res)))
         # 結果を返す
         return {"status": “Success”, “results”: results}
     except Exception as e:
         return {"status”:”Error”,”message”:str(e)}

Lambda 関数から Amazon Aurora MySQL データベースにアクセスするには、デプロイパッケージの一部として mysql-connector-python (MySQL Driver) ライブラリを含める必要があります。

Amazon Aurora MySQL の Lambda 関数は次のとおりです。

import boto3
from mysql import connector
from mysql.connector import Error

def lambda_handler(event, context):
    try:
        # rds のサービス名で低レベルクライアントを作成する
        client = boto3.client("rds")
        # 環境変数を読み取り、DB EndPoint を取得する
        DBEndPoint = os.environ.get("DBEndPoint") 
        # 環境変数を読み取り、データベース名を取得する 
        DatabaseName = os.environ.get("DatabaseName")
        # 環境変数を読み取り、データベースにアクセスできるデータベースユーザー名を取得します。
        DBUserName = os.environ.get("DBUserName")
        # IAM 認証情報を使用してデータベースに接続するために使用する認証トークンを生成します。
        password = client.generate_db_auth_token(
            DBHostname=DBEndPoint, Port=5432, DBUsername=DBUserName
        )
        # パスワードとして生成されたトークンを使用してサーバーとの接続を確立する
        connection = connector.connect(
            host=DBEndPoint, database=DatabaseName, user=DBUserName, password=password
        )
        # カーソルオブジェクトをインスタンス化し、辞書を true にして、行を辞書として返す
        cursor = connection.cursor(dictionary=True)
        # 接続されたデータベースでクエリ/コマンドを実行する
        cursor.execute("select database();")
        # クエリ結果セットの次の行を取得します。
        record = cursor.fetchone()
        # 結果を返す
        return {"status": “Success”, “results”: record }
    except Exception as e:
        return {"status”:”Error”,”message”:str(e)}

結論

多くのアプリケーションは、データベースの資格情報をプレーンテキストファイルに保存します。このファイルは暗号化されておらず、資格情報をユーザーに公開するため、潜在的なリスクがあります。各データベースインスタンスで個別にアクセスを管理する代わりに、IAM を使用してデータベースリソースへのアクセスを一元管理できます。IAM ユーザーまたはロールにデータベースへのアクセス許可がある限り、データベースにアクセスするための認証トークンを生成できます。

 


著者について

Mahesh Balumuri は、AWS プロフェッショナルサービスのコンサルタントです。 彼は、AWS のお客様と協力して、データベースプロジェクトに関するガイダンスと技術支援を提供し、クラウドでのインフラストラクチャとアプリケーションの構築を支援しています。また、クラウド環境でのオートメーション、オーケストレーション、DevOps についても十分な知識を持っています。