Queryable Encryption
Queryable Encryption を使うと、元の値を database に見せることなく、アプリケーションから暗号化されたデータを検索できます。フィールドは、cluster 上で保存され検索されるときも含め、アプリケーションの外では常に暗号化されたままです。アプリケーションは値を MongoDB に送る前に暗号化し、返ってきたときに復号します。これにより、機微なデータを保護したまま暗号化フィールドを検索できます。
ほかの暗号化方式との比較
各方式は、データの生涯のうち異なる段階を保護します。
| 方式 | 保護する場面 | サーバーが平文を見るか |
|---|---|---|
| SSL/TLS | ネットワーク転送中 | 見る |
| ディスク暗号化 (TDE) | ディスク保存時 | 見る。処理のためサーバー自身が復号する |
| Queryable Encryption | 転送中、保存時、処理中 | 見ない |
3 つは競合するものではなく補い合う関係にあります。読み取り権限を持つ人に何が見えるかを変えるのは、最後の列だけです。
仕組み
アプリケーションのコードの書き方は変わりません。{ssn: "123-45-6789"} と書き、同じ形で読み戻せます。送信時の暗号化と受信時の復号は、driver と crypt_shared というライブラリが担います。

中央の行が、これを通常のクライアントサイド暗号化以上のものにしています。driver は検索 filter も暗号化するため、サーバーは ciphertext どうしを照合して正しいドキュメントを返しますが、何を検索したのかを知ることはありません。
どのクエリが使えるか
照合が効くのは collection 作成時に宣言した query type に対してだけで、その選択は collection の生涯にわたって変更できません。
| Query type | 用途 | 状態 |
|---|---|---|
equality | $eq、$in、$ne | MongoDB 7.0 から production で利用可能 |
range | $lt、$lte、$gt、$gte | MongoDB 8.0 から production で利用可能 |
prefix、suffix、substring | 前方一致、後方一致、部分一致検索 | MongoDB 9.0 から production で利用可能 |
none | クエリせず暗号化のみ | 常に利用可能 |
バージョン 8.0.20 では equality と range が、7.0.30 では equality のみが使えます。6.0.27 は、MongoDB 6.0 が public preview しか提供せず、その preview のサポートもすでに終了しているため利用できません。
設計前に織り込むべき制限
フィールドを暗号化すると、そのフィールドでできることが狭まります。schema を確定する前に、アプリケーションの実際のクエリと照らし合わせてください。
最初の 1 つが他のすべてを左右します。Queryable Encryption を有効にできるのは 新規かつ空の collection だけで、暗号化するフィールドを後から変えることもできません。選択を誤れば、新しい collection を作ってデータを移行することになります。
残りは暗号化フィールド自体に関する制限です。
- 同一 collection で Queryable Encryption と CSFLE を併用できません。
collationはサポートされません。updateManyとdeleteManyはサポートされず、bulkWriteは 1 つの namespace に限定されます。- 暗号化フィールドへの update は
$setと$unsetのみで、$incや$pushは使えません。 findOneAndUpdateとfindOneAndReplaceは変更前のドキュメントを返す必要があり (returnDocument: before)、projection は使えません。- 暗号化フィールドを
null、正規表現、または別の暗号化フィールドと比較するクエリは失敗します。 - aggregation では
$outと$mergeが使えず、$groupは暗号化されていないフィールドでのみ動作します。 distinctは利用できません。- collection の削除は Queryable Encryption を有効にした client で行ってください。そうしないと metadata collection が残ります。
完全な一覧は MongoDB の Supported Operations for Queryable Encryption にあります。
設定の手順
手順はどの言語でも同じで、続く 2 ページでコードを 1 行ずつ追っていきます。

master key を作成する
試用時は 96 バイトの乱数を保持するローカルファイルで、アプリケーションの起動時に一度だけ読み込みます。production では KMS (AWS、Azure、GCP、KMIP) に置き換えます。
フィールドを宣言する
暗号化する各フィールドには path、bsonType、queryType が必要です。queryType はそのフィールドで使える演算子を決めるもので、collection の作成後は変更できません。
collection を作成する
1 回の呼び出しで 3 つのことが起こります。driver がフィールドごとに Data Encryption Key を生成し、サーバーが collection を作成し、さらに metadata collection enxcol_.<COLLECTION>.esc と enxcol_.<COLLECTION>.ecoc を隣に追加します。collection は未作成である必要があります。
暗号化する client を作成する
これは collection を作成した通常の client とは別の、2 つ目の client です。手順 3 が返したフィールドマップを受け取り、この時点で driver が生成した keyId が入っています。フィールドマップに keyId が入るのは collection ができた後なので、手順 3 と 4 はこの順序でなければなりません。
読み書きする
ここから先、collection はほかの collection と同じように動作します。driver は宣言されたフィールドをプロセスから出る前に暗号化し、ドキュメントが戻ってきたときに復号します。
master key を失うと、そのデータは復元できません。鍵ファイルはデータベースとは別の場所にバックアップし、実データを預ける前に KMS へ移行してください。
正しく動いているかの確認
スクリプトを実行し終えると、同じドキュメントがどの client で読むかによってまったく違って見えます。
- 暗号化を有効にした client では、
ssnは平文で読み取れます。 - 通常の client、または鍵を持たない
mongoshでは、ssnはBinDatasubtype 6 となり、ドキュメントに__safeContent__フィールドが追加されます。 - 通常の client から平文で検索しても、何も返りません。
よくあるエラー
下表は各メッセージとその原因の対応です。
| エラー | 原因と対処 |
|---|---|
mongo_crypt_v1.so が見つからない | パスが誤っているか、アプリケーション実行ホストに crypt_shared が未導入です |
crypt_shared のバージョンエラー | crypt_shared はサーバーと同じか新しいバージョンである必要があります |
Multi-document updates are not allowed with Queryable Encryption | コードが updateMany を呼んでいます。updateOne を使用してください |
Invalid match expression operator on encrypted field | そのフィールドの query type でサポートされない演算子です。equality フィールドへの正規表現や $gt などが該当します |
findAndModify with encryption only supports new: false | returnDocument: after を使用しています。before に変更してください |
| collection がすでに存在する | Queryable Encryption には新規かつ空の collection が必要です。暗号化を有効にした client で先に削除してください |
| 接続時に認証が失敗する | password に URL エンコードされていない文字が含まれています |
production 向けの推奨事項
例ではローカル鍵ファイルを使っています。最初の実行を簡単にするためです。実データを入れる前に、次の点を変えてください。
- ローカル鍵ではなく KMS (AWS、Azure、GCP、KMIP) を使用してください。ローカル鍵はファイルに置かれるため、そのファイルを入手した人は保護対象をすべて復号できます。
- password をソースコードに書かないでください。環境変数または secret manager から読み込みます。
- 本当に必要なフィールドだけを暗号化してください。暗号化フィールドはクエリの自由度と、
enxcol_.*metadata collection や__safeContent__による容量を消費します。 - どのフィールドをクエリ対象にするかは collection 作成前に決めてください。その選択は後から変更できません。
- 配備前に、アプリケーションの実際のクエリをサポート演算子一覧と照らし合わせてテストしてください。後からでは遅すぎます。
参考資料
以下は MongoDB 自身のドキュメントで、本ガイドより踏み込んだ内容を扱っています。
- Queryable Encryption は MongoDB マニュアルにおけるこの機能のトップページです。
- Compatibility は、対応するサーバーバージョン、driver、エディション、cluster 構成を一覧にしています。
- Limitations には、このページで触れていないものを含む制限の全一覧があります。
- Supported operations は、暗号化フィールドで使えるすべてのコマンドと演算子を扱います。
- Quick start は MongoDB 自身によるチュートリアルで、複数の言語版があります。
- Automatic Encryption Shared Library は
crypt_sharedの入手と設定を説明しています。