EC2 + RDS 環境へインストールした WordPress 上で AWS Secrets Manager Agent 経由で DB 接続情報のシークレットを取得してみた

EC2 + RDS 環境へインストールした WordPress 上で AWS Secrets Manager Agent 経由で DB 接続情報のシークレットを取得してみた

Clock Icon2024.07.15

いわさです。

3 年近く前になりますが WordPress の DB 接続情報を AWS Secrets Manager から取得する方法を試したことがあります。

https://dev.classmethod.jp/articles/wordpress-db-secretsmanager/

その際は取得出来なくはないのですが、wp-config.php モジュールがロードされる度に Secrets Manager API を呼び出す形となってしまい、AWS Secrets Manager のベストプラクティスから外れた状態となっていました。
解決策としては環境変数やストレージなど一時的な領域にシークレットを格納する方法が考えられますが、シークレットのローテーションに追従する仕組みなども考える必要があり、自前で色々考えるのはちょっと面倒だなぁと思っていました。

そんな中、先日 AWS Secrets Manager Agent というものが登場しました。
このエージェントは取得したシークレットをキャッシュし、TTL を自由に設定が出来るのでシークレットのローテーションにも追従しやすいです。

https://dev.classmethod.jp/articles/aws-secrets-manager-agent-amazon-linux-2023/

これを使うと冒頭の課題を解決出来るのではと思い、WordPress 側で取得して設定してみました。

WordPress をセットアップ

上記 WordPress の記事を参考にまずは検証環境を用意します。
CloudFormation テンプレートが用意されていましたのでこちらを使いましょう。WordPress のインストールまで行ってくれるので、すぐに WordPress のセットアップ画面から開始することが出来ます。3 年前の自分、えらい。

ただ、3 年前ということもあって Amazon Linux 2 + MariaDB 10.5.12 というちょっと古いバージョンが使われていました。

https://github.com/Tak1wa/aws-cfn-wordpress-secretrds

MariaDB 10.5.12 は、現在はもうデプロイ出来ないようなので、エンジンバージョンを 10.11.6 にだけアップデートしておきました。

ブログに従って MariaDB 側で Create Database だけすると次のようにセットアップを開始することが出来ました。DB 接続情報が Secrets Manager に格納されているのでコンソールからマニュアルで取得して WordPress 上へまずはポチポチと入力していきます。

8A5296B2-9F6D-40AC-B36B-9F8FF1733464

セットアップが完了しました。デフォルトのサイトにアクセスすることも出来ました。
なお、この時点での WordPress 構成ファイルには次のように接続情報などがハードコーディングされています。

/var/www/html/wp-config.php
<?php
/**
 * The base configuration for WordPress
 *
 * The wp-config.php creation script uses this file during the installation.
 * You don't have to use the website, you can copy this file to "wp-config.php"
 * and fill in the values.
 *
 * This file contains the following configurations:
 *
 * * Database settings
 * * Secret keys
 * * Database table prefix
 * * ABSPATH
 *
 * @link https://wordpress.org/documentation/article/editing-wp-config-php/
 *
 * @package WordPress
 */

// ** Database settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'wordpress' );

/** Database username */
define( 'DB_USER', 'hoge' );

/** Database password */
define( 'DB_PASSWORD', '6XUK-9}fxO%E(e)f' );

/** Database hostname */
define( 'DB_HOST', 'hoge-rds.cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com' );

/** Database charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8mb4' );

/** The database collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );

:

Secrets Manager Agent 経由で取得するように変更

では、Secrets Manager Agent 経由で取得するように変更していきたいと思います。

Secrets Manager Agent のインストール

まずは EC2 上に Secretes Manager Agent をセットアップする必要がありますが、それは先日の記事と手順が同じなので省略します。dnf が yum になるくらいで、後は同じ感じです。

この時点でローカルホストへ HTTP リクエストを送信してみると...

[root@ip-10-0-0-86 html]# curl -H "X-Aws-Parameters-Secrets-Token: $(</var/run/awssmatoken)" 'http://localhost:2773/secretsmanager/get?secretId=hoge-secret' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current                                 Dload  Upload   Total   Spent    Left  Speed100   438  100   438    0     0   389k      0 --:--:-- --:--:-- --:--:--  427k{
  "ARN": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:hoge-secret-IKn9tn",
  "Name": "hoge-secret",
  "VersionId": "624cbc68-d1fb-437b-95b6-fb642f675db5",
  "SecretString": "{\"password\":\"6XUK-9}fxO%E(e)f\",\"engine\":\"mariadb\",\"port\":3306,\"dbInstanceIdentifier\":\"hoge-rds\",\"host\":\"hoge-rds.cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com\",\"username\":\"hoge\"}",
  "VersionStages": [
    "AWSCURRENT"
  ],  "CreatedDate": "1720908102.569"
}

良いですね。取得出来ています。

wp-config.php の修正

ではこの仕組みを WordPress 上で使ってみます。
具体的には wp-config.php で Secrets Manager Agent に対してシークレット取得リクエストを送信してみます。

/var/www/html/wp-config.php
<?php
/**
 * The base configuration for WordPress
 *
 * The wp-config.php creation script uses this file during the installation.
 * You don't have to use the website, you can copy this file to "wp-config.php"
 * and fill in the values.
 *
 * This file contains the following configurations:
 *
 * * Database settings
 * * Secret keys
 * * Database table prefix
 * * ABSPATH
 *
 * @link https://wordpress.org/documentation/article/editing-wp-config-php/
 *
 * @package WordPress
 */

// ** Database settings - You can get this info from your web host ** //
$token = file_get_contents('/var/run/awssmatoken');
$response = file_get_contents('http://localhost:2773/secretsmanager/get?secretId=hoge-secret', false, stream_context_create([
    'http' => [
        'header' => "X-Aws-Parameters-Secrets-Token: $token"
    ]
]));
$secrets = json_decode($response, true);
$dbSettings = json_decode($secrets['SecretString'], true);
/** The name of the database for WordPress */
define( 'DB_NAME', 'wordpress' );

/** Database username */
//define( 'DB_USER', 'hoge' );
define( 'DB_USER', $dbSettings['username'] );

/** Database password */
//define( 'DB_PASSWORD', '6XUK-9}fxO%E(e)f' );
define( 'DB_PASSWORD', $dbSettings['password'] );

/** Database hostname */
//define( 'DB_HOST', 'hoge-rds.cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com' );
define( 'DB_HOST', $dbSettings['host'] );

/** Database charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8mb4' );

/** The database collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );

:

WordPress 画面にアクセスしてみると、無事表示することが出来ました。

04EDD668-826F-43C8-99ED-13AA4D2FA917_1_105_c

ちなみにシークレットをローテーションした直後は次のようにデータベース接続エラーが発生しました。
TTL 値の調整やローテーションのタイミングは考える必要がありますね。

FCDD89C8-02DB-40EB-A768-ED3943FF9B80

さいごに

本日は EC2 + RDS 環境へインストールした WordPress に対して AWS Secrets Manager Agent 経由でシークレットを取得してみました。

エージェント構成ファイルをあまりカスタマイズしていないので適切な設定にはまだなっていないですが、冒頭の記事のように直接シークレットを取得するよりも改善されていそうな気がしますね。負荷テストして評価してみたいところです。

SSRF 対策用のトークンをストレージから毎回取得してしまっているのでストレージ I/O が発生すると思いますが、これはどうなのだろうとちょっと思っています。これもインメモリに出来ないものか。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.