LoginSignup
5
1

More than 3 years have passed since last update.

HashiCorp Vaultを利用してPostgreSQLのデータを暗号化する

Last updated at Posted at 2020-12-11

概要

HashiCorp VaultのTransit Secrets Engineを利用して、
PostgreSQLに格納するデータを暗号化して保存するユーザ定義型(Cipher型)を学習のため実装してみました。

・pg_vault_encrypt
https://github.com/ssl-oyamata/pg_vault_encrypt
→ Cipher型を実装してみたGithubレポジトリです(途中です)

HashiCorp Vault概要

Vaultは機密情報(シークレット)の管理を行うソフトウェアです。
データベースの接続パスワード、クラウドサービスのシークレットキー、証明書などの動的な払い出しとシークレットのライフサイクル管理を行います。
Vaulthへの認証にはトークンやユーザ・パスワードの他にLDAP,GitHubなどの多くのソフトウェアやサービスを利用可能です。
また、アクセスポリシーで要件に合わせた権限制御も可能です。

Transit Secrets Engine概要

VaultのTransit Secrets Engineはクライアントから送付されたデータの暗号化・復号を行う機能です。
暗号化するデータをクライアントからVaultに送信するとVaultが暗号化し、暗号化データをクライアントに返却します。
暗号化されたデータをVaultに送付するとVaultが復号しクライアントに返却します。

暗号化キーはVaultでセキュアに管理されており、暗号化キーのローテーションやバージョン管理が容易に実現可能になっています。

Transit Secrets Engineを使ってみる

手元のCentOS Linux release 7.8.2003 (Core)の環境で試してみます。

Vaultインストール

# wget https://releases.hashicorp.com/vault/1.6.0/vault_1.6.0_linux_amd64.zip
# unzip vault_1.6.0_linux_amd64.zip -d /usr/local/bin/
# vault version
Vault v1.6.0 (7ce0bd9691998e0443bc77e98b1e2a4ab1e965d4)

Vault起動

Vaultをdevモードで起動します。devモードではVaultのデータはメモリ上に保持され、
Vault停止時にデータは失われますので注意して下さい。

# export VAULT_ADDR="http://127.0.0.1:8200"
# vault server -dev
[省略]
Root Token: s.j0NkNK4zRglchBwvkTuTRVxt

Root TokenはVaultにログインする際に利用するので、メモしておきます。

Vaultへのログイン

# export VAULT_ADDR="http://127.0.0.1:8200"
# vault login
Token (will be hidden): [Root Tokenを入力]

Transit Secrets Engineの有効化

Transit Secrets Engineを有効化します。

# vault secrets enable transit

暗号化キーリングの作成

testという名前で暗号化キーリングを作成します。

# vault write -f transit/keys/test

データ暗号化

Transit Secrets Engineで暗号化するためにはデータをbase64にエンコードする必要があります。

# vault write transit/encrypt/test \
    plaintext=$(base64 <<< "宇宙人になりたい")
Key            Value
---            -----
ciphertext     vault:v1:HYS1O0IEnf+IiI3WsSGULYXmDrGSxjmaMEKehLJvcSbejve9w58XhWJXHH7MXMAo559DtUc=
key_version    1

データ復号化

Vaultから返却された暗号化データを復号します。
Base64で返却されるため、デコードします。

# vault write transit/decrypt/test \
    ciphertext="vault:v1:HYS1O0IEnf+IiI3WsSGULYXmDrGSxjmaMEKehLJvcSbejve9w58XhWJXHH7MXMAo559DtUc="
Key          Value
---          -----
plaintext    5a6H5a6Z5Lq644Gr44Gq44KK44Gf44GECg==
# base64 --decode <<< "5a6H5a6Z5Lq644Gr44Gq44KK44Gf44GECg=="
宇宙人になりたい

キーのローテート

容易にキーのローテートも可能です。

# vault write -f transit/keys/test/rotate

キーのローテートを行うと暗号化データの接頭語がvault:v2になりました。

# vault write transit/encrypt/test \
     plaintext=$(base64 <<< "宇宙人になりたい2")
Key            Value
---            -----
ciphertext     vault:v2:n9krlq4iPxoAlKD894isR7qUbAdiQ/mynJFvEBVxQSUha4f8UHiDp321FuzgMN7AwpaUgTjV
key_version    2

デフォルトでは暗号化はaes256-gcm96に設定されていました。

# vault read transit/keys/test
[省略]
type                      aes256-gcm96

容易に高度なデータ暗号化とキーのローテートが実現できました。

PostgreSQLのデータ暗号化・復号

VaultのTransit Secrets Engineを利用し、PostgreSQLに格納するテーブルのデータの一部を暗号化したいと考えました。
既存のアプリケーションを修正せずに、PostgreSQLのデータを暗号化したいと考え、ユーザ定義型(cipher型)を作成しました。
cipher型は下記のように動作します。

・データ保存時(入力) : Transit Secrets Engineでデータを暗号化し保存
・データ参照時(出力) : Transit Secrets Engineで暗号化データを復号し返却

インストール

インストール方法は下記をご参照いただけると幸いです。
https://github.com/ssl-oyamata/pg_vault_encrypt

Cipher型の動作

Cipher型を利用する場合、pg_vault_encrypt.vault_tokenパラメータなどを設定する必要があります。

$ psql -d cipherdb
=# SET pg_vault_encrypt.vault_token = 's.v8AYIpHOXGvNSKSpEfcsL1Dk';
SET
=# CREATE TABLE test(id int , data cipher);
=# INSERT INTO test values(1, 'secret data1'); # 暗号化したデータが保存されています。
=# INSERT INTO test values(2, 'secret data2'); # 暗号化したデータが保存されています。
=# SELECT * FROM test;
 id |     data
----+--------------
  1 | secret data1
  2 | secret data2
(2 行)


=# SELECT * FROM test where data = 'secret data2';
 id |     data
----+--------------
  2 | secret data2
(1 行)

cipher型ではpg_vault_encrypt.vault_tokenパラメータに指定したVaultのトークンが誤っていた場合にはエラーになり、データが参照できません。

=# SET pg_vault_encrypt.vault_token = 'dummy';
=# SELECT * FROM test where data = 'secret data2';
ERROR:  Cannot decrypt data (vault:v1:tA85X0C42FxEFVhX4VLXG49rfrTpHU4WoXl4fux9/5uJPET3iohAUA==): Error making API request.

URL: PUT https://192.168.0.30:8200/v1/encryption/decrypt/pgtest
Code: 403. Errors:

* permission denied

暗号化の確認

PostgreSQLのテーブルを構成するデータファイルが暗号化されていることを確認します。

データベースのOIDを確認

pg_stat_databaseビューのdatid(データベースのOID)列で、確認します。

# psql -d cipherdb
=# SELECT datid, datname FROM pg_stat_database WHERE datname='cipherdb';

  datid  | datname
---------+----------
 1411807 | cipherdb
(1 行)

テスト用に用意したデータベース(cipherdb)は、$PGDATA/base/1411807ディレクトリに格納されています。

テーブルのファイル名を確認

pg_classカタログのrelfilenode(リレーションのディスク上のファイルの名前)列で、確認します。

=# SELECT relname, relfilenode from pg_class WHERE relname='test';
 relname | relfilenode
---------+-------------
 test    |     1411946
(1 行)

テスト用に用意したデータベース(cipherdb)の、
testテーブルはファイル($PGDATA/base/1411807/1411946)に保存されていることを確認できました。

暗号化の確認

testテーブルが保存されているファイル($PGDATA/base/1411807/1411946)をstringsコマンドで参照してみます。

$ strings $PGDATA/base/1411807/1411946
vault:v1:41AB/8k2yiuth9rHdUAaiqOrqwpngg7CbuC3etKu195yCe3Bo/tOaA==
vault:v1:tA85X0C42FxEFVhX4VLXG49rfrTpHU4WoXl4fux9/5uJPET3iohAUA==

データが暗号化されていることを確認できました。

補足.
暗号化していないテーブルの場合、以下のように表示されます。

$ strings $PGDATA/base/1411807/1411949
secret data1
secret data2

以上です、間違いなどあればコメントください!

参考.

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1