Slide 1

Slide 1 text

データベースパスワードローテーションの自動化と PHP Swoole を用いたCache戦略について

Slide 2

Slide 2 text

はじめに ローテーションを行うにあたり、意識すべきは下記の2点です。 1. ダウンタイムが最小であること 2. 自動化されていること データベースのパスワード、ローテーションしてますか? データベースはPrivateなネットワーク上で稼働していることが多いため、パスワードが漏洩したとしても外部から 直接接続されることは稀でしょう。 しかし、退職者のアクセス権限が残存していたり、多層防御の一環として実装することは大切です。 もしくはコンプライアンス要件でローテーションが強制されている場合もあるかもしれません。 ? なぜ必要か まずは、MySQLを用いた基本的なパスワードローテーションについて考えてみます。

Slide 3

Slide 3 text

MySQL を用いたローテーションについて 結論: デュアルパスワードを使います。 デュアルパスワードとは? “こちらはMySQL 8.0.14から追加された機能で、名前の通り、2つのパスワードが設定できるようになり ます。それぞれ、プライマリーとセカンダリーと呼びます。2つのパスワードが設定されている時には、プ ライマリーでもセカンダリーでもどちらでもログインが可能になります。” 引用: デュアルパスワード機能でパスワードを便利に変更する ALTER USER 'appuser1'@'host1.example.com' IDENTIFIED BY 'password_b' RETAIN CURRENT PASSWORD; 構文 単純な ALTER USER との違いとしては、RETAIN CURRENT PASSWORD句 が 追加されていること。現在のプライマリーパスワードはセカンダリーに、新しく登録したパ スワードがプライマリーとして登録されます。

Slide 4

Slide 4 text

MySQL を用いたローテーションについて ・primary - password1 ・secondary - MySQL パスワード MySQL サーバー Application サーバー ②プライマリーパスワード が作成される ①MySQLユーザーを作成 ③ MySQLユーザー/パスワード を設定 ・primary - password2 ・secondary - password1 ②’ 新しいパスワードがプライマリに、既 存のプライマリがセカンダリに設定される ①' パスワードの更新 (RETAIN CURRENT PASSWORD;) ・primary - password2 ・secondary - ⑤’セカンダリの破棄 ④' セカンダリの破棄 (DISCARD OLD PASSWORD;) ③’ MySQLパスワードを更新

Slide 5

Slide 5 text

MySQL を用いたローテーションについて 課題 基本的にはこの戦略がうまくいきそうですが、いくつか課題があります。 1. アプリケーション側の複雑性  アプリケーション側でどちらのパスワードを使うか管理する必要があり、更新の際には環境変数 の切り替え等が発生します。 また、Laravelでconfig:cacheとOPcacheを有効化している場合、キャッシュ破棄のため phpfpmの再起動が必要かもしれません。 2. 手動介入が必要  人間が、アプリケーション側でのパスワードの切り替えを判断し、セカンダリパスワードを無効化 する必要があります。 クラウドを利用しているのであれば、この複雑性の責任を押し付けます。

Slide 6

Slide 6 text

AWS Secrets Managerを利用したローテーションについて AWS Secrets Managerとは? “AWS Secrets Manager は、データベース認証情報、アプリケーション認証情報、OAuth トークン、API キー、 およびその他のシークレットをライフサイクル全体で管理、取得、ローテーションするのに役立ちます。多くの AWS サービスは、Secrets Manager でシークレットを保存して使用します。” 引用: What is AWS Secrets Manager? 様々な機能がありますが、今回利用するのはローテーションのみ。 さらにローテーションの中でも、 ● 1人のユーザーのパスワードを更新し続ける「シングルユーザー戦略」 ● 2人のユーザーのパスワードを交互に更新し続ける「交代ユーザー戦略」 があります。 可用性を考慮し、後者の戦略を採用します。

Slide 7

Slide 7 text

AWS Secrets Managerを利用したローテーションについて Application サーバー MySQL サーバー CURRENT PENDING PREVIOUS ①ランダムなパスワードを作成 ・user ・rand1 ② ①で作成したパスワードをもとにMySQLユー ザーを作成 ③ CURRENTラベル付与 ・user ・rand1 ④ アプリケーションは常にCURRENラベルが付与された認証情報を取得 ・user ・rand1 ⑤ ローテーション時、新しいユーザーとパスワー ドを作成 ・user_clone ・rand2 ⑤ user_cloneの MySQLユーザーを作成 ・user_clone ・rand2 ・user ・rand1 ⑤ CURRENTラベル付与 ・user_clone ・rand2 ・user_clone ・rand2 ・user ・rand1 意識しなくてよい

Slide 8

Slide 8 text

AWS Secrets Managerを利用したローテーションについて この戦略は上手くいきそう。実装前にプラクティスを読んでみる “キャッシュを使用してシークレットを取得する シークレットを最も効率的に使用するには、サポートされている次のいずれかの Secrets Manager キャッシュコンポーネントを使用してシークレットをキャッシュ し、必要な場合にのみ更新することをお勧めします。” 引用: AWS Secrets Manager ベストプラクティス 毎秒100回 = 1分で6,000回 = 1時間で360,000回 = 1日で8,640,000回 = 1ヶ月(30日)で259,200,000回 259,200,000 ÷ 10,000 = 25,920 25,920 × $0.05 = $1,296/月 なるほど、確かに毎回 API経由でSercretを取得するのは非効率。 キャッシュと組み合わせた方が、コスト的にも◎ ※ 毎秒100回呼び出すとしたら月額 $1,296

Slide 9

Slide 9 text

AWS Secrets Managerを利用したローテーションについて PHPは・・・?

Slide 10

Slide 10 text

AWS Secrets Managerを利用したローテーションについて なぜPHP用のクライアントライブラリがないのか? Python/Javaなどの言語は: ● マルチスレッドモデル:1プロセス内でメモリを共有 ● スレッド間でキャッシュを簡単に共有できる ● ロック機構が標準で利用可能 課題は下記2点: 1. プロセス/スレッド間でキャッシュを共有したい 2. キャッシュがメモリを圧迫しないようにLRUで更新したい a. CRUD操作でロックを行う必要がありあそう ※APCuで出来そうだけど、ロック・アトミック性は独自実装。。 それ で出来ます。

Slide 11

Slide 11 text

Swoole を用いた実装 Swooleがどう解決するか $fds = array(); $server->on('connect', function ($server, $fd){ echo "connection open: {$fd}\n"; global $fds; $fds[] = $fd; var_dump($fds); }); Swooleは1つのワーカープロセスの中ではメモリを共有するため、下記のようなコードであれば $fds はシングルトン的に扱われる。 ワーカーの数を増やした場合、ワーカー間では $fdsは共有されない。 また、ロックは独自実装する必要あり。 → Swoole\Table を利用

Slide 12

Slide 12 text

Swoole を用いた実装 Swoole\Tableについて “In addition to using storage services as mentioned above, it is recommended to use shared memory to store data. Swoole\Table is a high-performance and concurrent data structure based on shared memory and locks. It is used to solve the problems of data sharing and synchronization locking between multiple processes/threads. The memory capacity of Table is not limited by PHP's memory_limit.” ● 高速:メモリ直接アクセスで非常に低レイテンシ ● プロセス間共有:ワーカー間でデータを直接共有可能 ● 行ロック incr/decr 等の原子操作を内蔵、ユーザ側で複雑なロック不要 引用: High-performance shared memory Table

Slide 13

Slide 13 text

Swoole を用いた実装 Swoole\Tableの例 - テーブルの作成 $table = new Swoole\Table(1024); $table->column('id', Swoole\Table::TYPE_INT); $table->column('name', Swoole\Table::TYPE_STRING, 64); $table->column('num', Swoole\Table::TYPE_FLOAT); $table->create(); Swoole\Tableの例 - レコードのINSERT $table->set('1', ['id' => 1, 'name' => 'test1', 'age' => 20]); $table->set('2', ['id' => 2, 'name' => 'test2', 'age' => 21]); $table->set('3', ['id' => 3, 'name' => 'test3', 'age' => 19]);

Slide 14

Slide 14 text

ライブラリとして求められるもの 最後に、AWS Secrets Manage + Swoole Tableのキャッシュクライアントライブラリ として実装したいものを記載します。 1 古いキャッシュの削除 2 PSR準拠 3 その他便利機能 LRUアルゴリズムを用いた、 古いキャッシュの削除。 連結リストどう管理するかは 要検討。 PSR-16 Simple Cache準拠 可能であればLaravelのキャッ シュファサードから呼び出せるよ うにしたい。 ・ アトリビュートでのCacheの埋め込み ・ リトライの機構 ・ Cache取得時のHook関数 等実装したい