WEB+DB PRESSの「実践!先進的インフラ運用」という連載の最後として、Hashicorp Vaultの記事をVol.104に寄稿しました。記事には、Hashicorp Vault(以下、Vault)を用いた「秘密情報の一括管理」として、秘密情報の管理の必要性をはじめ、秘密情報の管理の大変さ、そしてVaultは何を解決して何ができるのか を書きました。
WEB+DB PRESS Vol.104: 嬉しいことに表紙に見出し
Vaultは、インフラを自動化するソフトウェアを作ってきたHashicorpならではの、セキュリティ対策や技術またはアイデアがたくさん詰まっているので、ちゃんと理解するには、必要な前提知識や連携するソフトウェアの説明が必要なんですが、今回は残念ながら記事でそれらを省いています。なので、読者によってはわかりにくいかもしれません。それでも、初稿で予定の1.5倍の分量になってしまい、文字数を削るのに苦労しました。
WEB+DB PRESS Vol.104の当該記事を読んでいただけるとわかりますが、Vaultには、秘密情報を管理するたくさんの機能があります。私は、今回記事を書くにあたって、オフィシャルサイトのドキュメントをくまなく読みました。そこで、Vaultの全体像が見えた時、そのたくさんの機能がVaultの本質を見えにくくしているような印象を感じました。以下の3点がVaultのポリシーとしてソフトウェアの中心にあって、その前提のもと、様々な秘密管理としての機能を持っているということに気がつきました。
- 秘密情報のアクセス権限をバージョン管理できる
- できるだけ短いサイクルで秘密情報へのアクセス権限を更新する
- 秘密情報へのアクセスをすべて記録する
Vaultは、オフィシャルサイトで秘密情報管理ツールと定義されていますが、私は「セキュリティ対策をシステム全体でいい感じにする君」だと捉えていいのではないかと思っています。上述の3点は、堅牢さと柔軟さと使いやすさを実現していて、よく考えられていると感心します。
また、Vaultが備えるたくさんの機能においても、便利だけでなく学ぶことが多いです。セキュリティ対応は、適切なタイミングで適切な対応を行うことが効率よく効果を発揮する
と私は考えています。例えば、水を溜めるバケツがあって、「バケツに穴が空いたらどうやって水の漏洩を最小限に防ぐか(これはこれで必要な議論ではありますが)」よりもまず「そもそもバケツに穴が空かない方法」を考えることがべきです。なので、そのようなセキュリティ対応として効率の良さまたは正しさを、Vaultの機能を使うことによって、考えさせられるというのもメリットがある気がしています。
記事中にも書きましたが、コストのかかる秘密情報管理やセキュリティ対応は何かと後回しにされがちです。覆水盆に返らず。Vaultを使って、今一度、システムのセキュリティを見直しても良いのではないでしょうか。各位、意識高めて、やっていきましょう。
Sequelize Vault
RailsのActiveRecordで扱うカラムを透過的にVaultで暗号化/復号をする vault-rails を使ったハンズオンを記事中で紹介しました。最近では、WebアプリケーションをSPA+SSRで作るケースが多く、バックエンドもJavaScriptで実装することが増えてきました。そこで、Node.jsの代表的なO/R Mapperである Sequlizeで vault-rails 同等の機能をもつパッケージを作ってみましたのでご紹介します。
- Hashicorp製のActiveRecord拡張https://github.com/hashicorp/vault-rails
- 今回作ったSequelize拡張https://github.com/linyows/sequelize-vault
使い方は、リポジトリのREADMEにあるように、定義したModelオブジェクトを呼び出したSequelize
Vault関数の引数に渡すだけです。そうすると、BeforeSaveやAfterFindなどのSequelize
Hookが登録され、暗号化/復号が行われていることを感じさせないように使えます。vault-railsと異なり、sequelize-vaultが1つ便利な点は、暗号化前の生データで検索が行える点 です。
const Sequelize = require('sequelize')
const SequelizeVault = require('sequelize-vault')
const s = new Sequelize({
username: 'root',
password: '',
dialect: 'sqlite',
database: 'test',
})
const User = s.define('user', {
ssn_encrypted: Sequelize.STRING,
ssn: Sequelize.VIRTUAL,
})
SequelizeVault.Vault.app = 'fooapp'
SequelizeVault.Vault.address = 'http://master-vault'
SequelizeVault.default(User)
const u = await User.create({ ssn: '123-45-6789' })
console.log(u.ssn_encrypted)
// vault:v0:EE3EV8P5hyo9h...
Many Thanks
執筆にあたって、スムーズなスケジューリングや適切な編集をしていただき、@inaoさんありがとうございました!
また、なんども記事のレビューをしていただいた@monochromeganeさんをはじめ、GMOペパボのみなさん、ありがとうございました。
あと、記事のフィードバックはとても嬉しいですね。@r_takaishiさんありがとうございます。