NetBSDでNECのPostgreSQL暗号化ソフト「Transparent Data Encryption for PostgreSQL Free Edition」を動かしてみる(DBから触ってみる編)

# NetBSDでNECのPostgreSQL暗号化ソフト「Transparent Data Encryption for PostgreSQL Free Edition」を動かしてみる(DBから触ってみる編)

NECのPostgreSQL暗号化ソフト「Transparent Data Encryption for PostgreSQL Free Edition」を動かしてみる話の続きです。

[前回の投稿](http://qiita.com/furandon_pig/items/9d0c8845572712da75d9)でNetBSDでTDEを利用する準備が整ったので、今回はデータベース上で透過的暗号化を使うための設定と実例を紹介したいと思います。

以降の実行例で出てくるPGHOME、PGDATAといった環境変数の値は[PostgreSQL,TDE関連の環境変数](http://qiita.com/furandon_pig/items/9d0c8845572712da75d9#postgresqltde%E9%96%A2%E9%80%A3%E3%81%AE%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0)(前回の投稿)をご参照ください。

## TDE機能のインストール

TDE機能をインストールします。以下の2つを実施します。

 * TDEの有効化
 * 鍵の登録

### TDEの有効化

データベース毎にTDEを有効/無効化します。例としてkinmosaデータベースでTDEを利用してみます。

```
$ createdb kinmosa
$
$ cd ${TDEHOME}/SOURCES
$ 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
Please enter database user name to connect : fpig
Please enter password for authentication : 
Please enter database name to connect : kinmosa
CREATE LANGUAGE
INFO: Transparent data encryption feature has been activated
```

### 鍵の登録

続いて暗号化用の鍵を登録します。"Please retype the new cipher key"で暗号鍵のキー(パスフェーズ)を入力します。今回は「kokeshi」と入力しました。暗号化アルゴリズムはAESを指定しています(AESとBrowfishのいずれかが指定できます)。

```
$ cd ${TDEHOME}/SOURCES
$ sh bin/cipher_key_regist.sh ${PGHOME}
=== Database connection information ===
Please enter database server port to connect : 5432
Please enter database user name to connect : fpig
Please enter password for authentication : 
Please enter database name to connect : kinmosa
=== Regist new cipher key ===
Please enter the new cipher key : ※「kokeshi」と入力した
Please retype the new cipher key : ※「kokeshi」と入力した
Please enter the algorithm for new cipher key : aes

Are you sure to register new cipher key(y/n) : y
 cipher_key_enable_log   
-----------------------  
 t
(1 row)

```

これでTDEを利用するための準備が整いました。

## サンプルデータを投入してみる

### テーブルの作成

まずはテーブルの作成です。きんいろモザイクの放映タイトルを入力するKinmosaテーブルを例にしてみます。

titleフィールドに暗号化データ型として「ENCRYPT_TEXT」を指定しています。[TDEのWiki](https://github.com/nec-postgres/tdeforpg/wiki/Manual(JP))によると、「テキスト型データを透過的に暗号化処理するデータ型」とのことです。

```
$ psql -d kinmosa
psql (9.3.9)
Type "help" for help.

kinmosa=# --「きんいろモザイク」テーブル作成
kinmosa=# CREATE TABLE Kinmosa(
kinmosa(#     id Integer PRIMARY KEY,
kinmosa(#     season Integer NOT NULL,
kinmosa(#     episode Integer NOT NULL,
kinmosa(#     title ENCRYPT_TEXT NOT NULL
kinmosa(# );
CREATE TABLE
```

### データの投入

暗号化データ型を含んだテーブルにレコードを追加する場合は、透過的にデータを暗号化/復号化するため、pgtde_begin_session()、pgtde_end_session()で透過的暗号化のセッションを開始/終了します。

セッション開始前にcipher_key_disable_log()を呼んでいるのは、ログの設定によっては暗号鍵情報がログに出てしまう場合があるらしく、一時的にログ出力を抑制するためのようです。

「SELECT pgtde_begin_session()」の結果がtrueであることを確認して次に進みます。

```
kinmosa=# --ログ出力無効化
kinmosa=# SELECT cipher_key_disable_log();
...中略...
kinmosa=# --セッション開始
kinmosa=# SELECT pgtde_begin_session('kokeshi');
 pgtde_begin_session
---------------------
 t
(1 row)

kinmosa=# --ログ出力有効化
kinmosa=# SELECT cipher_key_enable_log();
```

データを投入してみます。といっても、透過的暗号化なだけあって、データ投入や操作の際に暗号化を意識することはありません。

```
kinmosa=# INSERT INTO Kinmosa VALUES(1, 2, 1, '『はるがきたっ』');
kinmosa=# INSERT INTO Kinmosa VALUES(2, 2, 2, '『プレゼント・フォー・ユー』');
kinmosa=# INSERT INTO Kinmosa VALUES(3, 2, 3, '『あなたがとってもまぶしくて』');
kinmosa=# INSERT INTO Kinmosa VALUES(4, 2, 4, '『雨にもまけず』');
kinmosa=# INSERT INTO Kinmosa VALUES(5, 2, 5, '『おねえちゃんとあそぼう』');
kinmosa=# INSERT INTO Kinmosa VALUES(6, 2, 6, '『きになるあの子』');
kinmosa=# INSERT INTO Kinmosa VALUES(7, 2, 7, '『マイ・ディア・ヒーロー』');
kinmosa=# INSERT INTO Kinmosa VALUES(8, 2, 8, '『もうすぐ夏休み』');
kinmosa=# INSERT INTO Kinmosa VALUES(9, 2, 9, '『とっておきの一日』');
kinmosa=# INSERT INTO Kinmosa VALUES(10, 2, 10, '『海べのやくそく』');
kinmosa=# INSERT INTO Kinmosa VALUES(11, 2, 11, '『ほんのすこしの長いよる』');
```

普通にSELECTで問い合わせもできます。

```
kinmosa=# SELECT * FROM Kinmosa ;
 id | season | episode |             title
----+--------+---------+--------------------------------
  1 |      2 |       1 | 『はるがきたっ』
  2 |      2 |       2 | 『プレゼント・フォー・ユー』
  3 |      2 |       3 | 『あなたがとってもまぶしくて』
  4 |      2 |       4 | 『雨にもまけず』
  5 |      2 |       5 | 『おねえちゃんとあそぼう』
  6 |      2 |       6 | 『きになるあの子』
  7 |      2 |       7 | 『マイ・ディア・ヒーロー』
  8 |      2 |       8 | 『もうすぐ夏休み』
  9 |      2 |       9 | 『とっておきの一日』
 10 |      2 |      10 | 『海べのやくそく』
 11 |      2 |      11 | 『ほんのすこしの長いよる』
(11 rows)
```

データの投入ができたので、透過的暗号化のセッションを終了してみます。

```
kinmosa=# SELECT pgtde_end_session();
 pgtde_end_session 
-------------------
 t
(1 row)

```

すると新たにレコードを追加することもSELECTすることもできなくなります。テーブルを操作するには、透過的暗号化のセッションを新たに開始する必要があります。

```
kinmosa=# INSERT INTO Kinmosa VALUES(666, 2, 999, 'test');
ERROR:  TDE-E0016 could not encrypt data, because key was not set(01)
LINE 1: INSERT INTO Kinmosa VALUES(666, 2, 999, 'test');
                                                ^
kinmosa=# SELECT * FROM Kinmosa;
ERROR:  TDE-E0017 could not decrypt data, because key was not set(01)
```

というわけで、NetBSDの環境でもTDEの機能を試してみることができました。

## トラブルシューティング

cipher_key_regist.shの実行(鍵の登録)時に以下のようなエラーに遭遇しました。ハマり所のような感じがしたのでメモしておきます。

```
$ sh cipher_key_regist.sh ${PGHOME}
=== Database connection information ===
Please enter database server port to connect : 5432
Please enter database user name to connect : fpig
Please enter password for authentication : 
Please enter database name to connect : kinmosa
=== 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
ERROR:  function pgp_sym_encrypt(text, text, unknown) does not exist
LINE 1: INSERT INTO cipher_key_table VALUES(pgp_sym_encrypt(cipher_k...
                                            ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
QUERY:  INSERT INTO cipher_key_table VALUES(pgp_sym_encrypt(cipher_key, cipher_key, 'cipher-algo=aes256, s2k-mode=1'), cipher_algorithm)
CONTEXT:  PL/pgSQL function cipher_key_regist(text,text,text) line 59 at SQL statement
```

pgcryptが利用可能になっていないことが原因。データベース毎に"CREATE EXTENSION pgcrypto;"する必要があるみたいです。

```
psql -d kinmosa
kinmosa=# CREATE EXTENSION pgcrypto;
CREATE EXTENSION
kinmosa=# \q
$ sh cipher_key_regist.sh ${PGHOME}
...こんどは鍵が作成できるはず...
```

## まとめ

TDEによる透過的暗号化を試してみました。少しインストールの手順が煩雑な印象を受けますが、インストールスクリプト等で対応できるようになれば良いなと思います。TDEのテスト環境ができたため、透過的暗号化のオーバーヘッドを計測できたりするかもしれません。