メインコンテンツまでスキップ

Queryable Encryption

Queryable Encryption を使うと、元の値を database に見せることなく、アプリケーションから暗号化されたデータを検索できます。フィールドは、cluster 上で保存され検索されるときも含め、アプリケーションの外では常に暗号化されたままです。アプリケーションは値を MongoDB に送る前に暗号化し、返ってきたときに復号します。これにより、機微なデータを保護したまま暗号化フィールドを検索できます。

ほかの暗号化方式との比較​

各方式は、データの生涯のうち異なる段階を保護します。

方式保護する場面サーバーが平文を見るか
SSL/TLSネットワーク転送中見る
ディスク暗号化 (TDE)ディスク保存時見る。処理のためサーバー自身が復号する
Queryable Encryption転送中、保存時、処理中見ない

3 つは競合するものではなく補い合う関係にあります。読み取り権限を持つ人に何が見えるかを変えるのは、最後の列だけです。

仕組み​

アプリケーションのコードの書き方は変わりません。{ssn: "123-45-6789"} と書き、同じ形で読み戻せます。送信時の暗号化と受信時の復号は、driver と crypt_shared というライブラリが担います。

アプリケーションと cluster の間で暗号化された insert と find の流れ

中央の行が、これを通常のクライアントサイド暗号化以上のものにしています。driver は検索 filter も暗号化するため、サーバーは ciphertext どうしを照合して正しいドキュメントを返しますが、何を検索したのかを知ることはありません。

どのクエリが使えるか​

照合が効くのは collection 作成時に宣言した query type に対してだけで、その選択は collection の生涯にわたって変更できません。

Query type用途状態
equality$eq、$in、$neMongoDB 7.0 から production で利用可能
range$lt、$lte、$gt、$gteMongoDB 8.0 から production で利用可能
prefix、suffix、substring前方一致、後方一致、部分一致検索MongoDB 9.0 から production で利用可能
noneクエリせず暗号化のみ常に利用可能
FPT Cloud での意味

バージョン 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 の作成から、暗号化を有効にした client での読み書きまでの 5 つの設定手順

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 は BinData subtype 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: falsereturnDocument: 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 の入手と設定を説明しています。

次のステップ​