今日では、企業や医療機関、自治体などの組織において、情報セキュリティ対策は慎重に取り扱うべき問題です。個人情報を収める場合もあるデータベースは、特に気を配る必要があります。
PostgreSQL は、クライアント認証とデータベースオブジェクトのアクセス制御によって、不正なユーザからデータベースのデータを保護しています。しかしながら、OS ファイルレベルでの暗号化はされておらず、ファイルやディスクの物理的な盗難に対しては対策が立てられていません。
そこで、第 3 回では、PostgreSQL の pgcrypto や、PowerGres Plus の独自機能である透過的データ暗号化を用いて、データベースの暗号化を行い、よりセキュアにデータベースを管理していく方法をご紹介します。
まずは PowerGres のベースとなっている PostgreSQL の機能を用いてデータの暗号化を行います。
PostgreSQL 自体にもデータの暗号化を行う仕組みは用意されており、contrib モジュールの pgcrypto を利用します。pgcrypto はデーターベースをテーブルのカラム単位で暗号化 / 復号する、PostgreSQL 用の関数群です
まずは pgcrypto が使えるようにします。ここでは、データベースの所有者を testuser とした、cryptodb を作成し、pgcrypto を使っていくことにします。第 1 回の記事を参考にデータベースのセットアップを行い、データベースユーザ testuser の作成と、データベース cryptodb の作成を完了しておいてください。
psql で cryptodb に接続し、CREATE EXTENSION コマンドを実行します。CREATE EXTENSION コマンドはデータベースのスーパーユーザでなければいけません。
\c cryptodb CREATE EXTENTION pgcrypto;
暗号化で利用する鍵を、GnuPG を用いて作成します。新しい鍵ペアを作成しましょう。鍵の種類は DSA と Elgamal を指定します。
[postgres@node1 ~]$ gpg --gen-key : : ご希望の鍵の種類を選択してください: (1) DSAとElgamal (既定) (2) DSA (署名のみ) (5) RSA (署名のみ) 選択は? 1 # デフォルトを指定 DSA keypair will have 1024 bits. ELG-E keys may be between 1024 and 4096 bits long. What keysize do you want? (2048) 2048 # デフォルトを指定 要求された鍵長は2048ビット 鍵の有効期限を指定してください。 0 = 鍵は無期限 <n> = 鍵は n 日間で満了 <n>w = 鍵は n 週間で満了 <n>m = 鍵は n か月間で満了 <n>y = 鍵は n 年間で満了 鍵の有効期間は? (0)0 # 無期限を指定 Key does not expire at all これで正しいですか? (y/N) y : : 本名: postgres 電子メール・アドレス: postgres@node1 コメント: # コメントは省略 : : 名前(N)、コメント(C)、電子メール(E)の変更、またはOK(O)か終了(Q)? O 秘密鍵を保護するためにパスフレーズがいります。 # パスフレーズは省略 : : 公開鍵と秘密鍵を作成し、署名しました。
ASCII アーマー形式で公開鍵と秘密鍵をエクスポートします。鍵ペアが複数ある場合は、–export オプションと –export-secret-keys オプションの後に使用する 鍵 ID を指定してください。
[postgres@node1 ~]$ gpg -a -o public.key --export [postgres@node1 ~]$ gpg -a -o secret.key --export-secret-keys
鍵ペアの値を格納する gpgkey テーブルを作成します。psql で cryptodb に接続し、 testuser に変わります。鍵ペアの値は psql の変数に読み込ませて、INSERT 文で挿入します。
SET ROLE testuser; CREATE TABLE gpgkey(public text, secret text); \set PUBLIC `cat /var/lib/pgsql/public.key` \set SECRET `cat /var/lib/pgsql/secret.key` INSERT INTO gpgkey VALUES (:'PUBLIC', :'SECRET');
ID と氏名から構成される usertbl テーブルを作成します。暗号化するカラムのデータ型は bytea 型にする必要があります。name カラムを bytea 型にしましょう。
CREATE TABLE usertbl( id int, --ID name bytea -- 氏名 );
usertbl テーブルに、name カラムのデータを暗号化して挿入します。暗号化には pgp_pub_encrypt() 関数を使います。pgp_pub_encrypt() 関数は、第一引数に暗号化したいカラム名、第二引数に公開鍵を指定します。第三引数には使用する暗号アルゴリズムや圧縮アルゴリズムなどを指定できますが、ここではデフォルトのままとします。公開鍵の値は ASCII アーマー形式の文字列になっているので、dearmor() 関数を使ってバイナリ形式に戻す必要があります。
INSERT 文を使って、データを挿入してみましょう。
INSERT INTO usertbl VALUES ( 1501, pgp_pub_encrypt('TOKUGAWA Ieyasu', dearmor((SELECT public FROM gpgkey))) ); INSERT INTO usertbl VALUES ( 1502, pgp_pub_encrypt('TOKUGAWA Hidetada', dearmor((SELECT public FROM gpgkey))) ); INSERT INTO usertbl VALUES ( 1503, pgp_pub_encrypt('TOKUGAWA Iemitsu', dearmor((SELECT public FROM gpgkey))) );
usertbl テーブルの中身を確認してみましょう。投入したデータが暗号化されています。
\x SELECT name FROM usertbl;
usertbl テーブルのデータを復号して取り出します。復号には pgp_pub_decrypt() 関数を使います。pgp_pub_decrypt() 関数は、第一引数に復号したいカラム名、第二引数に秘密鍵を指定します。第三引数は、鍵ペアを作成したときにパスフレーズを指定します。パスフレーズを指定しなかった場合は空文字を指定します。秘密鍵の値も ASCII アーマー形式の文字列になっているので、dearmor() 関数を使ってバイナリ形式に戻す必要があります
usertbl テーブルを検索してみましょう。
\x SELECT id, pgp_pub_decrypt(name, dearmor((SELECT secret FROM gpgkey)), '') AS name FROM usertbl;
データを取得することができました。
続いては、PowerGres Plus の独自機能による透過的データ暗号化によって、データの暗号化を行っていきます。
透過的データ暗号化は PostgreSQL の 暗号化したい列を指定する pgcypto とは異なり、指定したテーブル空間内の全てのユーザデータを暗号化します。暗号化されたテーブルやインデックスに対する操作によって出力されるトランザクションログや一時ファイルも自動的に暗号化されます。したがって、クライアント側は暗号化キーの管理や暗号化 / 復号の処理を気にする必要はありません。また、物理コピーによるバックアップデータも、暗号化されたデータは暗号化されたままとなっています。
透過的データ暗号化では、二層のキーストアファイルによってデータを保護しています。暗号化されたテーブル空間には、その中の全てのデータを暗号化 / 復号するキーストアファイルがあります。このキーストアファイルはデータベースクラスタに 1 つだけ作成されるマスター暗号化キーによって暗号化されています。マスター暗号化キーは DB 管理者が指定したパスフレーズに基づいて暗号化され、キーストアファイルに保存されます。
それでは透過的データ暗号化を設定してみましょう。
はじめに、マスター暗号化キーの設定を行います。管理ツールを起動し、「データ暗号化」の「キーストア格納ディレクトリ」にキーストアファイルを格納するディレクトリを指定し、「適用(A)」ボタンをクリックします。サービスの再起動を促されるのでサービスを再起動します。
サービスを再起動したら、「マスター暗号化キーを作成」ボタンをクリックしてキーストアファイルをオープンする際に使用するパスフレーズを入力してください。マスター暗号化キーはこのパスフレーズで保護されるので、単純で推測されやすい文字列は指定しないようにしてください。また、ここで指定したパスフレーズを忘れてしまうと、暗号化されたデータには二度とアクセスできなくなります。パスフレーズは忘れないようにしてください。
透過的データ暗号化を利用する際は、作成したキーストアファイルをオープンしておく必要があります。サービスの起動に合わせて自動的にキーストアがオープンされるようにしておきましょう。「キーストアの自動オープンを有効にする」をクリックしてパスフレーズを入力します。
暗号化用のテーブル空間を作成します。「オブジェクト」の「テーブルスペース」の「テーブルスペースを作成」ボタンをクリックします。
以下の設定を入力します。
設定項目 | 設定値 |
---|---|
テーブルスペース名 | tde-space |
テーブルスペースの場所 | /var/lib/pgsql/tde |
テーブルスペースの所有者 | postgres |
データ暗号化アルゴリズム | AES128 |
暗号化したテーブル空間にデータベースを作成し、データを挿入していきます。これらの手順は、透過的データ暗号化を利用しない場合と何も変わりはありません。
「オブジェクト」の「データベース」にある「データベースを作成」ボタンをクリックし、以下の設定でデータベースを作成します。
設定項目 | 設定値 |
---|---|
データベース名 | tdedb |
データベース所有者 | testuser |
文字エンコーディング | UTF8 |
テーブルスペース | tde-space |
psql で tdedb に接続し、testuser に代わって pgcrypto と同様のテーブルを作成します。INSERT 文でデータを挿入し、SELECT 文で確認します。SQL 文やテーブル定義を書き換えることなく暗号化 / 復号は行われます。
\c tdedb SET ROLE testuser; CREATE TABLE usertbl( id int, name text ); INSERT INTO usertbl VALUES (1504, 'TOKUGAWA Ietsuna'); INSERT INTO usertbl VALUES (1505, 'TOKUGAWA Tsunayoshi'); INSERT INTO usertbl VALUES (1506, 'TOKUGAWA Ienobu'); SELECT * FROM usertbl;
テーブルデータが格納されているファイルを確認してみましょう。PostgreSQL の組み込み関数である pg_relation_filepath() でテーブルデータが格納されているファイルパスを特定し、ファイルを読み込みます。
SELECT pg_relation_filepath('usertbl');
usertbl の中身です。入力した氏名は暗号化されており、特定することができません。
こちらは、usertbl テーブルと同一のデータを暗号化せずに挿入したテーブルの中身です。氏名が特定できてしまっています。
透過的データ暗号化の特徴的な利点は、クライアント側が暗号化キーの管理や、暗号化 / 復号の処理を意識する必要がないだけではありません。
透過的データ暗号化は、ディスク I/O が発生するときのみ、暗号化 / 復号が行われます。バッファ・キャッシュ内のデータアクセスの際は暗号化を行わないのでオーバーヘッドはありません。また、Intel Xeon プロセッサの 5600 番台以降に搭載された AES-NI を用いた場合、暗号化 / 復号のオーバヘッドは極消化されます。
具体的な暗号化、非暗号化時の性能比較結果を以下に掲載します。
以下の条件で OLTP、バッチ処理、ロードの性能を測定しました。
ハードウェア | FUJITSU PRIMERGY RX300 S7 CPU: Intel Xeon E5-2690 2.90GHz(8コア)×2 DRAM: 160GB ストレージ: SSD(PCI Express) |
---|---|
ソフトウェア | OS: Red Hat Enterprise Linux 6.2(64ビット) RDBMS: PowerGres Plus V9.1(64ビット) |
それぞれの結果をグラフに示します。
はじめは pgbench の実行結果です。1 秒あたりのトランザクション数 (TPS) は暗号化、非暗号化の間に差はありません。また、暗号化した場合であっても、暗号化強度、AES-NIの有無による TPS の差はありません。
バッチ処理およびロード処理性能の測定結果は同様の傾向が示されました。どちらの測定結果も、処理時間は暗号化したほうが増加しています。しかし、AES-NI を有効にした場合は増加量は抑えられています。
以上の結果から、ディスクアクセスが少ない OLTP では暗号化のオーバヘッドはほとんどなく、ディスクアクセスの多いバッチ処理やロードにおいても、AES-NI が有効であれば暗号化のオーバーヘッドはほぼ抑えられており、透過的データ暗号化のオーバヘッドは非常に小さいと言えます。
今回は PowerGres Plus の透過的データ暗号化機能についての解説でした。透過的データ暗号化は、クライアント側が暗号化 / 復号を意識することなく手軽に使えるメリットがあります。また、オーバヘッドもほとんどありません。PowerGres Plus を使って、手軽な GUI でセキュアな DB 管理をぜひともお試しください。