既存のRDS for PostgreSQLにKMSサーバサイド暗号化を追加する
こんにちは、虎塚です。
これまで暗号化せずに使ってきたRDSに、KMSによるサーバサイド暗号化を後から追加したくなることがあります。すでに本番環境でDBを動かしているところに、「サーバサイドでのデータ暗号化が必須」といったセキュリティポリシーが追加された場合などですね。
今回は、RDS for PostgreSQL (9.4.4) を対象に、上記を実現するための手順と注意事項をまとめます。
おさらい: 暗号化を有効にできるタイミング
RDS for PostgreSQLで暗号化を有効にできるのは、DBインスタンスを起動するタイミングだけです。RDSは一度起動したら停止できませんので、DBインスタンスの新規作成時だけ暗号化を有効にできる、といってもいいでしょう。
残念ながら、暗号化されていないDBインスタンスのSnapshotから、暗号化されたDBインスタンスを新規に作成することは、サポートされていません。
それではどのようにしてKMSによる暗号化を有効にするかというと、新規にRDSのインスタンスを作成して、既存のデータベースの内容を手動でリストアします。
既存RDSに暗号化機能を追加する手順
手順は、おおむね次のようになります。
- 既存インスタンスを手動でバックアップする
- 既存インスタンスのSnapshotを取得する
- 既存インスタンスを削除する
- 新規インスタンスを作成する(暗号化を有効にする)
- 新規インスタンスにグローバルオブジェクトを作成する
- 1で取得したバックアップを新規インスタンスにリストアする
各ステップの詳細をみていきましょう。
ステップ1. 既存インスタンスを手動でバックアップする
バックアップには、pg_dumpコマンドを使います。
まず、作業環境にPostgreSQLクライアントをインストールします。この時、pg_dumpも同時にインストールされます。
$ sudo yum install postgresql94 [...] $ which pg_dump /usr/bin/pg_dump
次に、pg_dumpコマンドを既存のRDSインスタンスに対して実行します。
$ pg_dump DATABASE_NAME -h instance-name.abcdef0123456.ap-northeast-1.rds.amazonaws.com -U USER_NAME > OUTPUT_FILE Password: # DBログインユーザのパスワードを入力
OUTPUT_FILEは、SQLクエリが羅列されたテキストファイルです。ステップ6でリストアに使いますので、大事に保管しておきましょう。
ワンポイント: pg_dumpallの使用はNG
PostgreSQLには、ロールなどのグローバルオブジェクトを含むバックアップを取ることができるpg_dumpallコマンドがありますが、このコマンドを実行するにはsuperuser権限が必要です。RDSでは、ユーザがsuperuser権限を持つことができないため、pg_dumpallは利用できません。
pg_dumpallでバックアップを取ろうとすると、次のようなエラーになります。
$ which pg_dumpall /usr/bin/pg_dumpall $ pg_dumpall -h instance-name.abcdef0123456.ap-northeast-1.rds.amazonaws.com -U USER_NAME > OUTPUT_FILE Password: # DBログインユーザのパスワードを入力 pg_dumpall: query failed: ERROR: permission denied for relation pg_authid pg_dumpall: query was: SELECT oid, rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, rolcanlogin, rolconnlimit, rolpassword, rolvaliduntil, rolreplication, pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, rolname = current_user AS is_current_user FROM pg_authid ORDER BY 2
そのため、コマンドでグローバルオブジェクトを移行することはできません。pg_dumpで取得したバックアップを新規インスタンスにリストアする前に、作成したロールなどをもう一度作成する必要があります(ステップ5)。
ステップ2. 既存インスタンスのSnapshotを取得する
Amazon Management Consoleから、もしくはAWS CLIを使って、既存インスタンスのSnapshotを取得しましょう。
これは保険のようなものです。手動リストアがうまくいかなかった場合、Snapshotからインスタンスを再作成して、切り戻しをおこないます。
ステップ3. 既存インスタンスを削除する
Amazon Management Consoleから、もしくはAWS CLIを使って、既存インスタンスを削除します。ステップ2でSnapshotを取得しているので、安心して削除してください。
ワンポイント: RDSのDNS名の引き継ぎ
このステップで既存インスタンスを削除する理由は、ステップ4で同じ名前のインスタンスを新規に作成するためです。つまり、そうしたいのでなければ、このタイミングでインスタンスを削除することは必須ではありません。
アプリケーションからDBへ接続するための設定には、通常RDSのエンドポイントを使用します。エンドポイントとは、次のような文字列です。
- instance-name.abcdef0123456.ap-northeast-1.rds.amazonaws.com
RDSにサーバサイド暗号化の機能を追加する際、できればアプリケーション側の設定を変えずに済ませたいものです。そんなとき、同じインスタンス名でRDSインスタンスを作り直すと、新旧のRDSでDNS名(=エンドポイント)を引き継ぐことができます。ただし、同時に同じ名前のインスタンスは存在できないため、一旦削除する必要があります。
なお、インスタンス名が同一の場合、AWS Management Consoleから確認できるイベント一覧も引き継がれます。
ステップ4. 新規インスタンスを作成する(暗号化を有効にする)
Amazon Management Consoleから、もしくはAWS CLIを使って、新規にRDSのインスタンスを作成します。このとき、オプションの設定で暗号化を有効にしましょう。
暗号化に利用する鍵として、KMSのRDS用デフォルトマスターキーか、ユーザが作成したカスタマーマスターキーのいずれかを選択できます。
ワンポイント: インスタンスクラスの選択
KMSによる暗号化がサポートされるのは、一部のインスタンスクラスだけです。
既存のRDSが上記以外のインスタンスクラスだった場合は、新規にDBインスタンスを起動するタイミングで、KMSによる暗号化がサポートされるインスタンスクラスを選択してください。
ストレージの種類(Magnetic, SSDなど)は、すべてのタイプがKMS暗号化に対応しています。
ステップ5. 新規インスタンスにグローバルオブジェクトを作成する
新規インスタンスにログインして、既存インスタンスに存在したグローバルオブジェクトを作成します。
ステップ6に進む前に、かならずこの作業をしてください。
ステップ6. 1で取得したバックアップを新規インスタンスにリストアする
ステップ1のバックアップファイルを指定して、新規インスタンスにリストアします。
$ psql -d DATABASE_NAME -h instance-name.abcdef0123456.ap-northeast-1.rds.amazonaws.com -U USER_NAME < OUTPUT_FILE Password for user USER_NAME: # DBログインユーザのパスワードを入力
ステップ5でも書きましたが、必要なグローバルオブジェクトの再作成をかならず先に済ませておいてください。もし、それをスキップしてバックアップファイルをいきなりリストアすると、たとえば、次のようなエラーになるでしょう。
[...] CREATE EXTENSION ERROR: must be owner of extension plpgsql [...]
(pg_catalogスキーマを触るあたりでエラーになるのだと思います)
もしエラーが発生しても、リストアは進行してしまいます(そうしないためのオプションを使わないかぎり、エラーが出てもリストアは止まりません)。その結果、中途半端にリストアされたデータベースができてしまうので、注意しましょう。
おわりに
暗号化していないRDSに、後から暗号化機能を加えるための手順を紹介しました。もし失敗してもSnapshotから復元できるので、やはりAWSは便利ですね。
もっとも、システム要件の一部であるセキュリティポリシーを要件定義段階で念入りに確認して、最初にRDSインスタンスを作成する段階から暗号化を設定しておくことが、一番よいかと思います。
それでは、また。