Overview
このガイドでは、 Mongooseを使用して MongoDB のQueryable Encryption機能を実装するアプリケーションを作成する方法を学習できます。
Queryable Encryption を使用すると、ドキュメントフィールドを自動的に暗号化および復号化できます。 Queryable Encryption を使用して、アプリケーション内の 機密データ を暗号化し、データフィールドをサーバーに保存し、暗号化されたフィールドをクエリします。このチュートリアルでは、データ処理用の ODM(Object Document Mapper、オブジェクト ドキュメント マッパー)ライブラリを提供するMongooseを使用して、 Queryable Encryption を設定する方法を説明します。
前提条件
このチュートリアルを開始する前に、次の前提条件タスクを完了してください。
Tutorial
このチュートリアルでは、 Mongooseを使用するQueryable Encryptionアプリケーションを作成する方法を説明します。アプリケーションは、医療レコードを暗号化および復号化し、暗号化された医療データをクエリします。
プロジェクトを設定する
このセクションの手順に従って、プロジェクトの依存関係のインストール、環境を構成し、アプリケーション構造を作成します。
環境を設定します。
プロジェクトを初期化し、必要な依存関係をインストールするには、ターミナルで次のコマンドを実行します。
mkdir mongoose-qe-app cd mongoose-qe-app npm init -y npm pkg set main="queryable-encryption-tutorial.js" npm pkg set type="module" npm pkg set scripts.start="node queryable-encryption-tutorial.js" npm i mongoose mongodb dotenv mongodb-client-encryption
これらのコマンドは mongoose-qe-appプロジェクトディレクトリを作成し、次の依存関係をインストールします。
Mongoose、 Node.js ODM
Node.jsドライバー
環境変数をロードするためのモジュールである Dotenv
環境変数を指定します。
プロジェクトルートで、.envファイルを作成し、次のコードを貼り付けます。
# MongoDB Connection URI and Shared Library Path MONGODB_URI="<connection URI>" SHARED_LIB_PATH="<Automatic Encryption Shared Library path>" # AWS Credentials AWS_ACCESS_KEY_ID="<Your AWS access key ID>" AWS_SECRET_ACCESS_KEY="<Your AWS secret access key>" AWS_KEY_REGION="<Your AWS key region>" AWS_KEY_ARN="<Your AWS key ARN>" # Azure Credentials AZURE_TENANT_ID="<Your Azure tenant ID>" AZURE_CLIENT_ID="<Your Azure client ID>" AZURE_CLIENT_SECRET="<Your Azure client secret>" AZURE_KEY_NAME="<Your Azure key name>" AZURE_KEY_VERSION="<Your Azure key version>" AZURE_KEY_VAULT_ENDPOINT="<Your Azure key vault endpoint>" # GCP Credentials GCP_EMAIL="<Your GCP email>" GCP_PRIVATE_KEY="<Your GCP private key>" GCP_PROJECT_ID="<Your GCP project ID>" GCP_LOCATION="<Your GCP location>" GCP_KEY_RING="<Your GCP key ring>" GCP_KEY_NAME="<Your GCP key name>" GCP_KEY_VERSION="<Your GCP key version>" # KMIP Credentials KMIP_KMS_ENDPOINT="<Endpoint for your KMIP KMS>" KMIP_TLS_CA_FILE="<Full path to your KMIP certificate authority file>" KMIP_TLS_CERT_FILE="<Full path to your client certificate file>"
<connection URI> プレースホルダーをクラスターに接続する接続 URI に置き換え、<Automatic Encryption Shared Library path> を自動暗号化共有ライブラリへの完全パスに置き換えます。ダウンロードしたパッケージ内で、パスが lib/mongo_crypt_v1.dylib にあることを確認します。
.env テンプレートにリストされている KMS(Key Management System)のいずれかを使用する場合は、対応するプレースホルダー値を置き換えます。それ以外の場合は、これらの値を割り当てずに、カスタマー マスター キーをローカルに保存できます。このアプリケーションは、ローカルの CMKファイルを作成します。
警告
ローカル CMK ストレージ
カスタマー マスター キーをローカルに保存する場合は、このアプリケーションを本番環境では使用しないでください。リモート KMS を使用しないと、暗号化のキーへの不正アクセスや、データの復号に必要なキーが失われるリスクがあります。
アプリケーションファイルを作成します。
mongoose-qe-appディレクトリに移動し、アプリケーションロジックを保存する queryable-encryption-tutorial.js という名前のファイルを作成します。次のコードをこのファイルに貼り付けます。
import 'dotenv/config'; import mongoose from 'mongoose'; import * as qeHelper from './queryable-encryption-helpers.js'; import { MongoClient, ClientEncryption } from 'mongodb'; async function runExample() { // Paste initial application variables below // Paste credential and options variables below // Paste connection and client configuration below // Paste data key creation code below // Paste encryption schema below // Paste the model below // Paste connection code below // Paste the insertion operation below // Paste the encrypted query below await connection.close(); console.log('Connection closed.'); } runExample().catch(console.dir);
次に、queryable-encryption-helpers.js という名前のファイルを作成し、次のコードを貼り付けます。
import 'dotenv/config'; import { writeFileSync, readFileSync, existsSync } from 'fs'; import { randomBytes } from 'crypto'; export async function dropExistingDatabase(client, databaseName) { const database = client.db(databaseName); await database.dropDatabase(); } // Paste helper methods below
このファイルには、アプリケーション用の dropExistingDatabase()ヘルパー関数が含まれています。このチュートリアルの今後のステップでは、ヘルパー関数を追加するように指示されます。
アプリケーション変数を割り当てます。
初期データベースと暗号化変数を指定するには、queryable-encryption-tutorial.jsファイルの runExample() 関数に次のコードを貼り付けます。
const kmsProviderName = '<KMS provider>'; const uri = process.env.MONGODB_URI; // Your connection URI const keyVaultDatabaseName = 'encryption'; const keyVaultCollectionName = '__keyVault'; const keyVaultNamespace = `${keyVaultDatabaseName}.${keyVaultCollectionName}`; const encryptedDatabaseName = 'medicalRecords'; const encryptedCollectionName = 'patients';
'<KMS provider>' プレースホルダーをキープロバイダーに置き換えます: 'aws'、'azure'、'gcp'、または 'kmip'カスタマー マスター キーをローカルに保存するには、この値を 'local' に設定します。
コードでは、次の変数に事前にデータが入力されています。
keyVaultDatabaseName - データ暗号化キー(DEK)を保存するMongoDBのデータベース。このチュートリアルでは、
encryptionデータベースを使用します。keyVaultCollectionName - DEK を保存するMongoDBのコレクション。コードでは、この変数を
__keyVaultに設定し、 ユーザーコレクションと区別するためにアンダースコアを先頭に付けます。keyVaultNamespace - DEK を保存するMongoDB内の名前空間。この変数は、
keyVaultDatabaseName変数とkeyVaultCollectionName変数をピリオドで区切った構成で構成されています。encryptionDatabaseName - 暗号化されたデータを保存するMongoDBのデータベース。このチュートリアルでは、
medicalRecordsデータベースを使用します。encryptedCollectionName - 暗号化されたデータを保存するMongoDBのコレクション。このチュートリアルでは、
patientsコレクションを使用します。
暗号化の認証情報の設定
プロジェクト構造を設定したら、このセクションの手順に従って、KMS プロバイダーの認証情報と暗号化オプションを設定します。
KMS プロバイダーの認証情報を取得します。
getKMSProviderCredentials() 関数を queryable-encryption-helpers.jsファイルに追加します。この関数は、キー管理システム プロバイダーの認証情報を検索します。または、KMS プロバイダーを使用しない場合はローカルの CMKファイルを作成します。
dropExistingDatabase() 関数の後に次のコードを貼り付けます。
export function getKMSProviderCredentials(kmsProviderName) { let kmsProviders; switch (kmsProviderName) { case 'aws': kmsProviders = { aws: { accessKeyId: process.env.AWS_ACCESS_KEY_ID, // Your AWS access key ID secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, // Your AWS secret access key }, }; return kmsProviders; case 'azure': kmsProviders = { azure: { tenantId: process.env.AZURE_TENANT_ID, // Your Azure tenant ID clientId: process.env.AZURE_CLIENT_ID, // Your Azure client ID clientSecret: process.env.AZURE_CLIENT_SECRET, // Your Azure client secret }, }; return kmsProviders; case 'gcp': kmsProviders = { gcp: { email: process.env.GCP_EMAIL, // Your GCP email privateKey: process.env.GCP_PRIVATE_KEY, // Your GCP private key }, }; return kmsProviders; case 'kmip': kmsProviders = { kmip: { endpoint: process.env.KMIP_KMS_ENDPOINT, // Your KMIP KMS endpoint }, }; return kmsProviders; case 'local': (function () { if (!existsSync('./customer-master-key.txt')) { try { writeFileSync('customer-master-key.txt', randomBytes(96)); } catch (err) { throw new Error( `Unable to write Customer Master Key to file due to the following error: ${err}` ); } } })(); try { // WARNING: Do not use a local key file in a production application const localMasterKey = readFileSync('./customer-master-key.txt'); if (localMasterKey.length !== 96) { throw new Error( 'Expected the customer master key file to be 96 bytes.' ); } kmsProviders = { local: { key: localMasterKey, }, }; } catch (err) { throw new Error( `Unable to read the Customer Master Key due to the following error: ${err}` ); } return kmsProviders; default: throw new Error( `Unrecognized value for KMS provider name \'${kmsProviderName}\' encountered while retrieving KMS credentials.` ); } }
この getKMSProviderCredentials() 関数は、 AWS、 Azure、 GCP、 KMIP 、 ローカルキーストレージなどの複数の KMS プロバイダーをサポートしています。
CMK の認証情報を取得します。
getCustomerMasterKeyCredentials() 関数を queryable-encryption-helpers.jsファイルに追加します。この関数は、KMS プロバイダーに基づいてカスタマー マスター キーの認証情報を検索します。
getKMSProviderCredentials() 関数の後に次のコードを貼り付けます。
export function getCustomerMasterKeyCredentials(kmsProviderName) { let customerMasterKeyCredentials; switch (kmsProviderName) { case 'aws': customerMasterKeyCredentials = { key: process.env.AWS_KEY_ARN, // Your AWS Key ARN region: process.env.AWS_KEY_REGION, // Your AWS Key Region }; return customerMasterKeyCredentials; case 'azure': customerMasterKeyCredentials = { keyVaultEndpoint: process.env.AZURE_KEY_VAULT_ENDPOINT, // Your Azure Key Vault Endpoint keyName: process.env.AZURE_KEY_NAME, // Your Azure Key Name }; return customerMasterKeyCredentials; case 'gcp': customerMasterKeyCredentials = { projectId: process.env.GCP_PROJECT_ID, // Your GCP Project ID location: process.env.GCP_LOCATION, // Your GCP Key Location keyRing: process.env.GCP_KEY_RING, // Your GCP Key Ring keyName: process.env.GCP_KEY_NAME, // Your GCP Key Name }; return customerMasterKeyCredentials; case 'kmip': case 'local': customerMasterKeyCredentials = {}; return customerMasterKeyCredentials; default: throw new Error( `Unrecognized value for KMS provider name \'${kmsProviderName}\' encountered while retrieving Customer Master Key credentials.` ); } }
この関数は、選択した KMS プロバイダーに対応するカスタマー マスター キー認証情報を構成します。
自動暗号化オプションを取得します。
getAutoEncryptionOptions() 関数を queryable-encryption-helpers.jsファイルに追加します。この関数は、アプリケーションの自動暗号化オプションを構成します。
getCustomerMasterKeyCredentials() 関数の後に次のコードを貼り付けます。
export async function getAutoEncryptionOptions( kmsProviderName, keyVaultNamespace, kmsProviders ) { if (kmsProviderName === 'kmip') { const tlsOptions = { kmip: { tlsCAFile: process.env.KMIP_TLS_CA_FILE, // Path to your TLS CA file tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE, // Path to your TLS certificate key file }, }; const extraOptions = { cryptSharedLibPath: process.env.SHARED_LIB_PATH, // Path to your Automatic Encryption Shared Library }; const autoEncryptionOptions = { keyVaultNamespace, kmsProviders, extraOptions, tlsOptions, }; return autoEncryptionOptions; } else { const extraOptions = { cryptSharedLibPath: process.env.SHARED_LIB_PATH, // Path to your Automatic Encryption Shared Library }; const autoEncryptionOptions = { keyVaultNamespace, kmsProviders, extraOptions, }; return autoEncryptionOptions; } }
認証情報変数を割り当てます。
ヘルパー関数を定義したので、それらを使用してメインのアプリケーションファイルから認証情報にアクセスできるようになります。
queryable-encryption-tutorial.jsファイルに移動し、// Paste credential and options variables below コードコメントの後に次のコードを貼り付けます。
const kmsProviderCredentials = qeHelper.getKMSProviderCredentials(kmsProviderName); const customerMasterKeyCredentials = qeHelper.getCustomerMasterKeyCredentials(kmsProviderName); const autoEncryptionOptions = await qeHelper.getAutoEncryptionOptions( kmsProviderName, keyVaultNamespace, kmsProviderCredentials );
このコードでは、 Queryable Encryptionの構成に使用される KMS プロバイダー認証情報、カスタマー マスター キー認証情報、自動暗号化オプションを取得するためにヘルパー関数を呼び出します。
MongoDBの暗号化と接続
暗号化設定を構成した後、このセクションの手順に従って、 MongoDB接続を設定し、データキーを作成し、 暗号化されたスキーマの定義 を行います。
MongoDB接続とクライアントを構成します。
MongoDB接続とクライアントを設定するには、queryable-encryption-tutorial.jsファイルに移動し、// Paste connection and client configuration below コードコメントの後に次のコードを貼り付けます。
const connection = mongoose.createConnection(); const client = new MongoClient(uri); const clientEncryption = new ClientEncryption( client, autoEncryptionOptions ); await qeHelper.dropExistingDatabase(client, encryptedDatabaseName); await qeHelper.dropExistingDatabase(client, keyVaultDatabaseName);
このコードでは、暗号化操作用のMongoose接続、キー管理用のMongoDBクライアント、データキーを作成するための ClientEncryptionインスタンスを作成します。また、既存のデータベースもすべて削除され、チュートリアルのクリーンな設定が維持されます。
データキーを作成します。
必要なデータキーを作成するには、// Paste data key creation code below コードコメントの後に次のコードを貼り付けます。
const keyId1 = await clientEncryption.createDataKey( kmsProviderName, { masterKey: customerMasterKeyCredentials, }); const keyId2 = await clientEncryption.createDataKey( kmsProviderName, { masterKey: customerMasterKeyCredentials, }); const keyId3 = await clientEncryption.createDataKey( kmsProviderName, { masterKey: customerMasterKeyCredentials, });
このコードでは、クライアントドキュメントのさまざまなフィールドを暗号化するために使用される 3 つのデータ暗号化キーが作成されます。各暗号化されたフィールドには独自のデータキーが必要です。
暗号化スキーマを定義します。
暗号化されたスキーマ定義を作成するには、// Paste encryption schema below コードコメントの後に次のコードを貼り付けます。
const patientSchema = new mongoose.Schema({ patientName: { type: String, required: true }, patientId: { type: Number, required: true }, patientRecord: { ssn: { type: String, encrypt: { keyId: keyId1, queries: { queryType: 'equality' } } }, billing: { type: { type: String, encrypt: { keyId: keyId2, } }, number: { type: String, encrypt: { keyId: keyId3 } } }, billAmount: Number } }, { encryptionType: 'queryableEncryption', collection: encryptedCollectionName });
このスキーマは、patientsコレクション内のドキュメントの構造を定義し、次の暗号化されたフィールドを指定します。
patientRecord.ssn: 暗号化と等価クエリ用の構成patientRecord.billing.type: 暗号化されていますが、クエリはできませんpatientRecord.billing.number: 暗号化されていますが、クエリはできません
暗号化された操作の実行
アプリケーションとデータベースの接続を構成したら、このセクションの手順に従って暗号化されたドキュメントの挿入とクエリを行います。
暗号化された データを挿入します。
暗号化されたフィールドを持つドキュメントを挿入するには、queryable-encryption-tutorial.jsファイルに移動し、// Paste the insertion operation below コードコメントの後に次のコードを貼り付けます。
const patientDocument = { patientName: 'Jon Doe', patientId: 12345678, patientRecord: { ssn: '987-65-4320', billing: { type: 'Visa', number: '4111111111111111', }, billAmount: 1500, }, }; const result = await Patient.create(patientDocument); if (result) { console.log('Successfully inserted the patient document.'); console.log('Document ID:', result._id); }
Queryable Encryption は、ドキュメントをMongoDBに保存する前に、patientRecord.ssn フィールドと patientRecord.billing フィールドを自動的に暗号化します。
アプリケーションを実行します。
最後に、mongoose-qe-appディレクトリから次のコマンドを実行中と、前の手順で定義された暗号化操作を実行できます。
npm start
成功した場合、コマンド出力は次の例のようになります。
Successfully inserted the patient document. Document ID: new ObjectId('...') Found patient: { patientRecord: { billing: { type: 'Visa', number: '4111111111111111' }, ssn: '987-65-4320', billAmount: 1500 }, _id: new ObjectId('...'), patientName: 'Jon Doe', patientId: 12345678, __v: 0, __safeContent__: [ Binary.createFromBase64('EGzhQwBpf1B6W9udskSxJ8kwEEnF5P+SJPZ6ygQ9Ft8=', 0) ] } Connection closed.
次のステップ
Mongoose Queryable Encryption のチュートリアルが完了しました。これで、 Queryable Encryptionを使用してドキュメントフィールドを自動的に暗号化および復号化するサンプルMongooseアプリケーションができました。アプリケーションはサーバー側で機密データを暗号化し、クライアント側でデータをクエリします。
Queryable EncryptionとMongooseの詳細については、次のリソースを参照してください。
MongoDB Serverマニュアルで、ドライバーQueryable Encryption のチュートリアルをさらに見る
Mongooseを使い始める チュートリアルで、 Queryable EncryptionなしでMongooseを使用するアプリケーションを作成する方法を学びます。
Mongooseの詳細については、 Mongooseドキュメント を参照してください。