「データを安全に格納すること」はデータベースの使命の一つですが、「安全に」という言葉には二通りの意味があると思っています。一つは「データを壊さないこと」、もう一つは「セキュアにデータを保管すること」で、今回は後者に特化した内容の記事となります。
セキュアにデータを保管する
たとえばユーザーやロールでアクセス権限を管理することや、DBへの接続元を制限することも「セキュアにデータを保管する」ために用いられる手法です。しかし、これらだけでは万全と言えず、データあるいはデータベース自体を暗号化することも昨今珍しくはありません。
透過的暗号化
実はPostgreSQLにはpgcryptoという暗号化モジュールが提供されているのですが、これがあまり使い勝手がよくないのです。
--暗号化
pgp_sym_encrypt()
--復号
pgp_sym_decrypt()
余談ですが「復号化」という言葉は誤りで、正しくは「復号」です。
pgcryptoは上記の関数を使ってSQL単位で暗号化・複合を行うため、アプリケーションの大幅な改修が必要になり、可読性も良くありません。これに対し「透過的暗号化」という手法は暗号化を特別意識することなくSQLを発行できるのがポイントで、暗号化の単位はデータベースとなります。
今回ご紹介するTransparent Data Encryption for PostgreSQL(以下、TDE for PG)はこの透過的暗号化機能を提供するものです。
サポート無しにはなりますが、有償版だけでなくOSSとして無償版を提供されたNECの決断には敬意と感謝しかありません。
TDE for PG のシステム要件
現在TDE for PG の最新バージョンはV1.2で、OSはRHEL系LinuxとWindowsに対応しています。
前回の記事でCentOS 8にインストールしたPostgreSQLのバージョンが10だった理由は、TDE for PG が11・12には未対応だからです。CentOSも正式に対応がアナウンスされているのは7系となります。
この辺りがサポートの無いものを自己責任で利用するリスクでもあるのですが、後続バージョンへの正式対応が強く望まれるところです!
TDE for PG のダウンロード
下準備は前回の記事で出来ていますので、TDE for PG をダウンロードしましょう。
wget https://github.com/nec-postgres/tdeforpg/releases/download/v1.2.1.0/tde_for_pg10-fe-1.2.1-0.el7.x86_64.rpm
ホームディレクトリに保存されていることを確認します。
[postgres@centos ~]$ ls -l
合計 24536
drwxrwxr-x. 7 postgres postgres 4096 8月 10 15:35 postgresql-10.13
-rw-rw-r--. 1 postgres postgres 24973924 5月 12 06:24 postgresql-10.13.tar.gz
-rw-rw-r--. 1 postgres postgres 142348 7月 11 2018 tde_for_pg10-fe-1.2.1-0.el7.x86_64.rpm
TDE for PG インストール
sudo rpm -ivh tde_for_pg10-fe-1.2.1-0.el7.x86_64.rpm
これは直ぐに終わります。
Verifying... ################################# [100%]
準備しています... ################################# [100%]
更新中 / インストール中...
1:tde_for_pg10-fe-1.2.1-0.el7 ################################# [100%]
INFO: Transparent Data Encryption for PostgreSQL 10
was installed successfully.
HINT: To complete validation of transparent data encryption feature,
please refer to "/opt/nec/tdeforpg10-fe/INSTALL-NOTE.TXT"
環境変数設定
TDE for PG の設定に必要な環境変数を設定します。ここを間違えると後の作業で必ず詰みますので慎重に行いましょう。
export PGHOME='/usr/local/pgsql' # PostgreDQLインストールディレクトリ
export TDEHOME='/opt/nec/tdeforpg10-fe' # TDE for PGインストールディレクトリ
export PGPORT='5432' # PostgreSQLの接続ポート
export PGDATA='/usr/local/pgsql/data' # データベースクラスタ
export PGDATABASE='sandambara'; # TDE for PG を有効化したいデータベース
export PGPASSWORD='postgres' # スーパーユーザーのパスワード
pgcrypto のインストール
TDE for PG はpgcryptoを利用しています。前回の記事ではpgcryptoを仕込んでいませんのでここでインストールします。
sudo su -
cd /home/postgres/postgresql-10.13/contrib/pgcrypto
make && make install
exit
リンク作成
マニュアルに従いリンクを作成します。ここのパス記述を誤ると後の作業でエラーになる場合がありますので慎重に作業しましょう。
sudo ln -s $PGHOME/lib/pgcrypto.so /usr/lib64/libpgcrypto.so
sudo ln -s $TDEHOME/SOURCES/data_encryption/10/data_encryption10.so.1.2.1.0 /usr/lib64/data_encryption.so
postgresql.conf 変更
DB起動時に読み込むライブラリを指定します。コメントを解除して下記のパスを記入してください。
nano $PGDATA/postgresql.conf
shared_preload_libraries = '/usr/local/pgsql/lib/pgcrypto.so' # (change requires restart)
保存して終了したらpostgresql.confを読み込ませるためにDBを再起動します。
pg_ctl restart
正常にDBが起動しないときはpostgresql.confのshared_preload_librariesの値をもう一度見直しましょう。
暗号化したいデータベースを作成する
透過的暗号化はデータベース単位で暗号化を行いますので、ログインし暗号化したいデータベース(先ほど環境変数で指定したデータベース)を作成します。成功したら作成したデータベースへログインしましょう。
psql postgres postgres
create database sandambara;
\c sandambara postgres
pgcrypto 作成
作成したデータベースでpgcryptoを使えるようにします。
create extension pgcrypto;
このようになっていればOKです。
select * from pg_available_extensions;
name | default_version | installed_version | comment
----------+-----------------+-------------------+------------------------------
plpgsql | 1.0 | 1.0 | PL/pgSQL procedural language
pgcrypto | 1.3 | 1.3 | cryptographic functions
(2 rows)
-- 確認出来たらDBを抜けます
\q
TDE for PG のセットアップ
TDE for PG を有効化します。
cd $TDEHOME/SOURCES
sudo sh bin/cipher_setup.sh $PGHOME
設定は対話形式で行います。
Transparent data encryption feature setup script
Please select from the setup menu below
Transparent data encryption feature setup menu
1: activate the transparent data encryption feature
2: inactivate the transparent data encryption feature
select menu [1 - 2] > 1
Please enter database server port to connect : 5432 # PostgreSQLの接続ポート
Please enter database user name to connect : postgres # スーパーユーザー
Please enter password for authentication : # スーパーユーザーのパスワード
Please enter database name to connect : sandambara # TDE for PG を有効化したいデータベース
CREATE LANGUAGE
TDE for PG が有効化されました。
TDE for PG の設定
有効化された TDE for PG の設定を行います。
sudo sh bin/cipher_key_regist.sh $PGHOME
=== Database connection information ===
Please enter database server port to connect : 5432 # PostgreSQLの接続ポート
Please enter database user name to connect : postgres # スーパーユーザー
Please enter password for authentication : # スーパーユーザーのパスワード
Please enter database name to connect : sandambara # 対象のデータベース
=== Regist new cipher key ===
Please enter the new cipher key : # 暗号鍵
Please retype the new cipher key : # 暗号鍵再入力
Please enter the algorithm for new cipher key : aes # 暗号化方式
Are you sure to register new cipher key(y/n) : y # 確認
暗号化アルゴリズムと暗号鍵の強度についてはマニュアルp.6にある通り、aes-16,24,32byteとblowfish56byteから選べます。
強度が上がればパフォーマンスがトレードオフとなりますので、お使いの環境や実現したい環境に応じて適切なものを選んでください。
設定作業は以上です。
使ってみよう! TDE for PG
それでは早速使ってみましょう!テスト用のテーブルを作ります。
追記 TDE for PG有効化後はログイン時に「–no-readline」を付けてください。付与せずログインすると.psql_historyに認証情報がプレーンテキストで残ってしまいます。
-- データベース sandambara にユーザー postgres でログインする
psql sandambara postgres --no-readline
-- テスト用にテーブルを作る
sandambara=# create table test(logtext encrypt_text);
CREATE TABLE
-- データを入れてみる
insert into test(logtext) values('hoge');
ERROR: TDE-E0016 could not encrypt data, because key was not set[01]
LINE 1: insert into test(logtext) values('hoge');
怒られました。暗号化列となるlogtext(encrypt_text型)に値を入れようとしたのですが鍵が無いと言われています。TDE for PG Free Editionでは暗号化したい列のデータ型にencrypt_textもしくはencrypt_byteaを指定できます。ちなみに有償版ではこれらに加えて下記の3つが利用可能です。
- encrypt_numeric
- encrypt_integer
- encrypt_timestamp
会計情報などを格納するデータベースではかなり魅力的ですね。
では、鍵を入力して再挑戦です。
sandambara=# select cipher_key_disable_log();
cipher_key_disable_log
------------------------
t
(1 row)
sandambara=# select pgtde_begin_session('暗号鍵');
pgtde_begin_session
---------------------
t
(1 row)
sandambara=# select cipher_key_enable_log();
cipher_key_enable_log
-----------------------
t
(1 row)
insert into test(logtext) values('hoge');
INSERT 0 1
sandambara=# select * from test;
logtext
---------
hoge
(1 row)
- cipher_key_disable_log() でログ出力を無効化
- pgtde_begin_session(‘暗号鍵’) で暗号鍵を入力
- cipher_key_enable_log() でログ出力を有効に戻す
- SQL実行
このような流れになっており、いずれのコマンドも省略することはできません。
作業が終わってDBを抜けるときは
select pgtde_end_session();
このようになります。
sandambara=# select pgtde_end_session();
pgtde_end_session
-------------------
t
(1 row)
暗号化セッションを抜けると再度アクセスするにはcipher_key_disable_log()からやり直しが必要です。試してみましょう。
sandambara=# select * from test;
ERROR: TDE-E0017 could not decrypt data, because key was not set[01]
暗号鍵が無いため中身を見ることができなくなっていますね。
ちなみに encrypt_*** 以外のデータ型列には従来通り何をせずともそのままアクセスが可能ですし、平文で保存されている列をalter tableでencrypt_textに変換することも(その逆も)可能です。
注意点は大量にデータ型変換を行うと作業中はDBのパフォーマンスが低下すること、archive_mode = on の場合は大量にwalのアーカイブが生成されることの2点です。作業のタイミングやストレージの残量には気を付けておきましょう。
今回の記事では暗号化がどのようなものか身をもってご経験頂けたのではないでしょうか?とても安心感を得られますよね。
マニュアルにも記載されていますが「鍵をどのように管理するか」は慎重に検討が必要ですし、DBが暗号化されても「クライアント~サーバー間の通信が平文のまま」では大きなリスクとなります。セキュリティーの問題は落としどころが難しいと思いますが、少しでも「安全・安心」に近寄れるようにしたいものです。
NECさま、後続バージョンへの対応、どうかよろしくお願い致します!
コメント