16
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

株式会社日立システムズAdvent Calendar 2021

Day 14

RDS ProxyとIAM認証を使ってLambdaからRDSにアクセスする

Last updated at Posted at 2021-12-13

ポイントまとめ

  • RDSProxyを利用する際は、RDSはパスワード認証に設定する。
  • RDSProxyのIAM認証を利用するLambdaでは、RDS generate-auth-db-tokenを利用して認証トークンを取得する。

概要

ワークロードでLambdaとRDSを組み合わせる場合、LambdaがRDSのコネクションを食いつぶしてしまうという理由から長らくアンチパターンとされてきました。
しかし、RDS Proxyができてからはその弱点も解消され、採用されているユースケースも増えているのではないかと思います。
この記事ではLambda(Python)からIAM認証を使ってRDSProxy経由でRDSにアクセスできるように、RDSその他を設定する方法を紹介します。
ハンズオン的に利用してもらえると幸いです。

また、今回は長くなりすぎないようにネットワークの設定や踏み台用インスタンスの作成、RDSサブネットグループの作成については省略し、下図赤枠で囲われている部分の設定方法のみを紹介します。
001.png

実践

1. RDSの作成

なにはともあれRDSがないと始まりません。
RDSを作成していきましょう。
RDSのマネジメントコンソールから「データベースの作成」をクリックします。
007.png
今回はMySQLでハンズオンを進めるので、「MySQL」を選択します。
ちなみに、現時点(2021年12月時点)でRDS ProxyがサポートしているのはPostgreSQL及びMySQLのみです。
詳細は、Amazon RDS Proxyの制約事項をご確認ください。
008.png
通常のRDSを作成する時と同じように、
DBインスタンス識別子やマスターユーザー名、パスワードを入力します。
010.png
VPCやサブネットグループは概要に記載した図の通り、NATGWにルーティングされてインターネットへのアウトバウンド接続が可能なプライベートサブネット上に配置しましょう。
また、セキュリティグループはこの後少し設定を変更するので、とりあえずここでは「新規作成」を選択します。
011.png
その他は特にデフォルトのままで問題ないのですが、一点だけ、今回RDS ProxyでIAM認証を使用するからといって、データベース認証を「パスワード認証」から変更しないようにしましょう。
RDS Proxyを挟む場合は、
Client⇒(IAM認証)⇒RDS Proxy⇒(パスワード認証)⇒RDS
という形にする必要があるので、RDSではIAM認証を有効にしません。
012.png
数分待つとRDSが作成できると思います。
013.png
一つだけ、追加で設定変更をします。
先ほど新規作成した、RDSにアタッチされているセキュリティグループのインバウンドグループで、

タイプ プロトコル ポート番号 ソース
MySQL/Aurora TCP 3306 (編集しているセキュリティグループ自体のID)
を追加します。
今回の記事では、このあと作成するRDS ProxyやLambdaなどに同じセキュリティグループをアタッチしていくので、セキュリティグループ内へのRDSアクセスを許可するためのものです。
014.png

2. データベースユーザの作成

次に、RDS ProxyやLambdaからアクセスするために使うMySQL上のユーザを作成します。
MySQLクライアントがインストールされている踏み台サーバにログインします。
踏み台サーバからRDSに対して、3306番のポートでアクセスできるようにセキュリティグループは設定しておくようにしましょう。
今回は、Amazon Linux 2 のEC2インスタンスを起動してMySQLクライアントを導入しました。
027.png

下記コマンドを実行して、RDSに接続します。
コマンド実行後にはパスワードの入力を求められますので、RDS作成時に入力したパスワードを入力してください。

mysql -h <rdsのエンドポイント名> -P 3306 -u admin -p

RDSに接続できたら、下記コマンドを入力して、「proxy_user」という名前のMySQL上のユーザを作成します。
パスワードは、後でSecret Managerのローテーションを実行するので、覚えることができるものならなんでも構いません。

CREATE USER proxy_user@'%' IDENTIFIED BY 'password';

015.png

また、ついでにテストで参照する用のデータベースも作っておきましょう。

CREATE DATABASE testdb;
CREATE TABLE testdb.testtable (id int, name varchar(10));
INSERT INTO testdb.testtable VALUES (1, 'Suzuki');
INSERT INTO testdb.testtable VALUES (33, 'Kikuchi');
INSERT INTO testdb.testtable VALUES (63, 'Nishikawa');
SELECT * FROM testdb.testtable;

add_001.png
add_002.png

最後に、テスト用のデータベースに対してユーザに権限を付与します。
今回は、データベースに対する全権限を付与しています。

GRANT ALL ON testdb.* TO proxy_user;

016.png

3. シークレットの作成

RDS Proxyを使ってRDSに接続するためには、接続ユーザのパスワードをSecrets Managerで管理している必要があります。
Secrets Managerのマネジメントコンソールを開いて、「新しいシークレットを保存する」をクリックします。
017.png
シークレットのタイプは「Amazon RDS データベースの認証情報」を選択して、
「2.データベースユーザの作成」で作成したユーザ名、パスワードを入力しましょう。
また、データベースでは、「1.RDSの作成」で作成したインスタンスを指定します。
018.png
シークレットの名前を入力します。
019.png
次に、シークレットのローテーションで、「自動ローテーションを有効にする」を選択します。
Lambdaローテーション関数の名前を入力して、「次へ」をクリックします。
※今回は、ローテーションを有効にしていますが、ここは有効化しなくても利用はできます。
020.png
「保存」をクリックします。
020_1.png

4. RDS Proxyの作成

では、いよいよRDS Proxyを作成していきます。
RDSのマネジメントコンソールの左側に、「プロキシ」という項目があるのでそれをクリックして、「プロキシを作成」をクリックすると、RDS Proxyの作成画面に進みます。
プロキシ識別子を入力して、エンジンの互換性で「MySQL」を選択します。
また、Transport Layer Securityが必要のチェックを忘れずにオンにします。
RDS ProxyでIAM認証を利用する場合、TLSの有効化が前提となっています。
021.png
ターゲットグループの設定では、作成したRDSインスタンスを指定します。
022.png
サブネットは、RDSインスタンスが所属するVPCのサブネットがすべて選択されるのでそのままでOKですが、
セキュリティグループはRDSインスタンス作成時に新規作成したセキュリティグループを指定しましょう。
設定できたら、「プロキシを作成」で作成します。
024.png
ここまで問題なければ、プロキシが作成されます。
プロキシエンドポイントの二つのエンドポイントと、ターゲットグループのステータスが「利用可能」となるまで待ちましょう。
※私の場合は10分程度かかりました。
026.png

5. Lambdaの作成

proxyが作成できたので、接続するためのLamdbaを作成していきましょう。
Lambdaを作成するにあたって、必要となるIAM Policyを作成します。
まずは、RDS ProxyのプロキシURLの中の、prx-XXXXXXXXXXXXXXXXXとなっている部分をメモします。
032.png

IAM Policyを作成します。
ポリシーの内容には、下記JSONステートメントを追加してください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "rds-db:connect"
            ],
            "Resource": [
                "arn:aws:rds-db:ap-northeast-1:<アカウントID>:dbuser:<RDSProxyのARNの末尾>/proxy_user"
            ]
        }
    ]
}

033.png
IAM Policyができました。
このポリシーは、後ほどLambdaを構築する際に自動作成されるIAM Roleにアタッチします。
034.png
Lambdaコンソールから、「関数」-「関数の作成」と進みます。
035.png
「一から作成」を選択し、任意の関数名を入力します。
ランタイムは、今回はPython3.8を選択しましょう。
実行ロールについては、「実行するLambdaアクセス権限で新しロールを作成」にします。
036.png
ここで通常のLambda関数であれば作成を押してしまいがちですが、今回はRDSというVPC上のリソースにアクセスをしないといけないので、「詳細設定」の欄を展開して、ネットワークを有効化にチェックを入れます。
RDSインスタンスが置いてあるVPCを選択し、
サブネットではプライベートサブネットを選択します。
セキュリティグループではRDSインスタンスやRDS Proxyと同じセキュリティグループを指定しましょう。
ここまで設定出来たら、「関数の作成」をクリックします。
037.png
Lambda関数が作成されます。
038.png
今回はpythonを利用してMySQLにアクセスするために、PyMySQLというパッケージを利用します。
ただ、LambdaでPythonのパッケージを追加するのは少し面倒な手順を実施しなくてはいけません。
今回は検証なので、既にPyMySQLをインストール済みの関数をレイヤとして提供してくださっている先人の方々の恩恵にあやかることにします。
下記を利用させていただきました。
https://github.com/keithrozario/Klayers
画面を下のほうにスクロールして、「レイヤーの追加」をクリックします。
039.png

レイヤーソースで、「arnを指定」を選択して、下記をコピペしてください。
「検証」を押したあと、「追加」をクリックして、レイヤを追加します。
これでPyMySQLが利用できるようになりました。
arn:aws:lambda:ap-northeast-1:770693421928:layer:Klayers-python38-PyMySQL:4
040.png
次に、RDS ProxyにIAM認証でアクセスするためには、SSL通信を行う必要があります。
RDS Proxy作成時にもそのような設定を入れました。
SSL通信を実行するために、証明書としてAmazonが提供している証明書を指定する必要があります。
コードソースの中の「File」から新規ファイルを作成し、AmazonRootCA1.pemというファイル名でSaveします。
041.png
証明書の内容は下記にアクセスして、内容をそのまま先ほどのファイルにコピペしましょう。
https://www.amazontrust.com/repository/AmazonRootCA1.pem
042.png

ここまでで、LamdbaからRDS Proxyにアクセスするための事前準備がほぼ完了しています。
下記サンプルコードを「Lambda_function.py」の中にコピペしましょう。
その上で、6行目 HOST = "XXXXXXXXXXXXXXXXXXXX"
のXXXの部分を、ご自身のRDS Proxyのエンドポイント名に置き換えてみてください。

import json
import sys
import boto3
import pymysql

HOST = "rds-proxy-kensyo001.proxy-chxhfnz5l2b1.ap-northeast-1.rds.amazonaws.com"
USER = "proxy_user"
PORT = 3306
REGION = "ap-northeast-1"

def lambda_handler(event, context):
    # TODO implement
    print ("start!!")
    client = boto3.client('rds')
    token = client.generate_db_auth_token(DBHostname=HOST, Port=PORT, DBUsername=USER, Region=REGION)
    
    print (token)

    try:
        conn = pymysql.connect(host=HOST, user=USER, passwd=token, db="testdb", connect_timeout=5, ssl={'ca': 'AmazonRootCA1.pem'})
    except Exception as e:
        print("error")
        print(e)

    with conn.cursor() as cur:
        cur.execute("SELECT * FROM testtable")
        for row in cur:
            print(row)

    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

043.png
ctrl+s で保存し、「Deploy」でLambdaをデプロイします。
044.png

ここまででほぼ終わりなのですが、もう少しだけ設定が必要になる部分があります。
Lamdbaの「設定」タブから、「アクセス権限」を選んで、実行ロールのロール名をクリックしましょう。
045.png
「ポリシーをアタッチします」をクリックします。
046.png
この章「5. Lamdbaの作成」の最初に作成したIAM Policyをアタッチします。
047.png
やっと準備ができました。
Lambdaの画面に戻って、「Test」をクリックしましょう。
Testパターンはなんでもよいので、適当に任意の名前を付けて実行します。
すると、実行時のログが表示されますが、中身を見てみると作成したテーブルのアイテムが表示されていることがわかります。
048.png

Lambdaで RDS Proxy経由で IAM認証を使ってRDSへアクセスすることができました!
この記事が、皆様のAWSライフに少しでもお役に立てば幸いです。

16
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?