Queryable Encryption with Symfony and Doctrine ODM

For the complete MongoDB documentation index, see www.mongodb.com/docs/llms.txt

Queryable Encryption with Symfony and Doctrine ODM

Overview

In this guide, you can learn how to create a Symfony application that uses Doctrine MongoDB ODM to implement MongoDB's Queryable Encryption feature.

Queryable Encryption allows you to automatically encrypt and decrypt document fields. You can use Queryable Encryption to encrypt sensitive data in your application, store data fields as randomized encrypted data on the server, and query the encrypted fields. This tutorial shows you how to set up Queryable Encryption by using Doctrine MongoDB ODM, which provides an Object Document Mapper (ODM) for PHP applications.

Tip:

To learn more about integrating Symfony and Doctrine with the MongoDB PHP Library, see the [Symfony MongoDB Integration](https://www.mongodb.com/docs/drivers/php-frameworks/symfony.md#std-label-php-symfony-integration tutorial.

Prerequisites

Before you begin this tutorial, complete the following prerequisite tasks:

  • Create a MongoDB Atlas account and configure a cluster. Ensure that your cluster runs on MongoDB Server version 7.0 or later. To learn more, see the MongoDB Get Started guide.

  • Download the Automatic Encryption Shared Library. To view instructions, see the [Install and Configure a Query Analysis Component](https://www.mongodb.com/docs/manual/core/queryable-encryption/install-library/?encryption-component=crypt_shared#procedure guide.

  • Download the PHP extension. To learn more, see Installation in the extension documentation.

  • Install PHP 8.1 or later.

  • Install Composer 2.0 or later.

  • Install the Symfony CLI. To learn more, see the Symfony CLI documentation.

Tutorial

This tutorial shows how to create a Queryable Encryption application that uses Symfony and Doctrine MongoDB ODM. The application encrypts and decrypts patient medical records and queries encrypted medical data.

Set Up Your Project

Follow the steps in this section to install the project dependencies, configure your environment, and create the application structure.

  1. Set up your environment.

Run the following commands in your terminal to create a new Symfony application and install the necessary dependencies:

bash symfony new qe-symfony-app cd qe-symfony-app composer require doctrine/mongodb-odm-bundle mongodb/mongodb

These commands create a qe-symfony-app project directory and install the following dependencies:

  • Doctrine MongoDB ODM Bundle, the Symfony integration for Doctrine MongoDB ODM

  • MongoDB PHP Library, the official MongoDB driver for PHP

  • Specify your environment variables.

In your project directory, open the .env file and add or modify the following variables:

bash MONGODB_URI=<connection URI> CRYPT_SHARED_LIB_PATH=<Automatic Encryption Shared Library path>

Replace the <connection URI> placeholder with the connection URI that connects to your cluster, and replace <Automatic Encryption Shared Library path> with the full path to your Automatic Encryption Shared Library. Ensure the path points to lib/mongo_crypt_v1.dylib inside your downloaded package.

  1. Create your application files.

In your project's src/ directory, create the following subdirectories and files to define the document structure and application logic:

  • src/Document/Patient.php

  • src/Document/PatientRecord.php

  • src/Document/Billing.php

  • src/Command/QueryableEncryptionCommand.php

Future steps in this tutorial instruct you to add code to each file.

  1. Define your document classes.

This tutorial uses Patient, PatientRecord, and Billing classes to represent patient medical records.

Paste the following code into the src/Document/Patient.php file:

```php <?php

namespace App\Document;

use Doctrine\ODM\MongoDB\Mapping\Attribute as ODM;

#[ODM\Document(collection: 'patients')] class Patient { #[ODM\Id] public string $id;

   #[ODM\Field]
   public string $patientName;

   #[ODM\Field]
   public int $patientId;

   #[ODM\EmbedOne(targetDocument: PatientRecord::class)]
   public PatientRecord $patientRecord;

} ```

Then, paste the following code into the src/Document/PatientRecord.php file:

```php 'local', 'key' => new Binary( $masterKeyBytes, Binary::TYPE_GENERIC, ), ]; ``` This code creates or loads a 96-byte local Customer Master Key file. The `$kmsProvider` array configures the local KMS provider used for encryption. **Warning: Local CMK Storage** This tutorial stores your Customer Master Key in a local file. Do not use this approach in production. Without a remote KMS, you risk unauthorized access to the encryption key or loss of the key needed to decrypt your data. **Tip: Key Management Systems** To learn more about KMS, see the [Key Management](https://en.wikipedia.org/wiki/w/index.php?title=Key_management\&oldid=1320428824) Wikipedia entry. 3. Configure your auto-encryption options. Add the following code directly under the KMS provider configuration from the previous step: ```php $autoEncryptionOptions = [ 'keyVaultNamespace' => $keyVaultNamespace, ]; $cryptSharedLibPath = $_ENV['CRYPT_SHARED_LIB_PATH'] ?? ''; if ($cryptSharedLibPath) { $autoEncryptionOptions['extraOptions'] = [ 'cryptSharedLibPath' => $cryptSharedLibPath, ]; } ``` This code sets the key vault namespace and configures the path to the Automatic Encryption Shared Library. 4. Configure your `DocumentManager`. Add the following code under the `// Paste connection and configuration below` comment: ```php // Paste connection and configuration below $cacheDir = __DIR__ . '/../../var/cache/doctrine'; $config = new Configuration(); $config->setAutoEncryption($autoEncryptionOptions); $config->setKmsProvider($kmsProvider); $config->setProxyDir($cacheDir . '/Proxies'); $config->setProxyNamespace('Proxies'); $config->setHydratorDir($cacheDir . '/Hydrators'); $config->setHydratorNamespace('Hydrators'); $config->setDefaultDB($encryptedDatabase); $config->setMetadataDriverImpl( new AttributeDriver([__DIR__ . '/../Document']) ); $client = new Client( uri: $_ENV['MONGODB_URI'], uriOptions: [], driverOptions: $config->getDriverOptions(), ); $dm = DocumentManager::create($client, $config); ``` This code configures a Doctrine `Configuration` object with your encryption settings, creates a MongoDB client that passes encryption driver options, and initializes a `DocumentManager` for encrypted operations. 5. Create your encrypted collection. Add the following code under the `// Paste collection setup below` comment: ```php // Paste collection setup below $schemaManager = $dm->getSchemaManager(); $schemaManager->dropDocumentCollection(Patient::class); $schemaManager->createDocumentCollection(Patient::class); ``` This code drops any existing collection and creates a new `patients` collection with the encryption metadata required for Queryable Encryption. Each call to `createDocumentCollection()` generates new Data Encryption Keys for the encrypted fields. ### Perform Encrypted Operations After configuring your application and database connection, follow the steps in this section to insert and query encrypted documents. 1. Insert encrypted data. In your `src/Command/QueryableEncryptionCommand.php` file, add the following code under the `// Paste insert operation below` comment: ```php // Paste insert operation below $billing = new Billing(); $billing->type = 'Visa'; $billing->number = '4111111111111111'; $record = new PatientRecord(); $record->ssn = '987-65-4320'; $record->billing = $billing; $record->billAmount = 1500; $patient = new Patient(); $patient->patientName = 'Jon Doe'; $patient->patientId = 12345678; $patient->patientRecord = $record; $dm->persist($patient); $dm->flush(); $dm->clear(); $output->writeln( 'Successfully inserted the patient document.' ); ``` Queryable Encryption automatically encrypts the `patientRecord.ssn` and `patientRecord.billing` fields before storing the document in MongoDB. 2. Query encrypted data. Add the following code under the `// Paste encrypted query below` comment: ```php // Paste encrypted query below $found = $dm ->getRepository(Patient::class) ->findOneBy(['patientRecord.ssn' => '987-65-4320']); if ($found instanceof Patient) { $output->writeln('Found patient:'); $output->writeln( ' Name: ' . $found->patientName ); $output->writeln( ' SSN: ' . $found->patientRecord->ssn ); $output->writeln( ' Billing type: ' . $found->patientRecord->billing->type ); $output->writeln( ' Billing number: ' . $found->patientRecord->billing->number ); $output->writeln( ' Bill amount: ' . $found->patientRecord->billAmount ); } $output->writeln('Connection closed.'); ``` This code performs an equality query on the encrypted `patientRecord.ssn` field. 3. Run your application. To start your application, run the following command from your `qe-symfony-app` project directory: ```bash php bin/console app:queryable-encryption ``` If successful, your command output resembles the following example: ```none Successfully inserted the patient document. Found patient: Name: Jon Doe SSN: 987-65-4320 Billing type: Visa Billing number: 4111111111111111 Bill amount: 1500 Connection closed. ``` In the database, the document is encrypted. MongoDB stores fields marked with the `#[ODM\Encrypt]` attribute as BSON binary data and includes a `__safeContent__` field for metadata tags. The stored document resembles the following: ```json { "_id": { "$oid": "..." }, "patientName": "Jon Doe", "patientId": 12345678, "patientRecord": { "ssn": { "$binary": { ... } }, "billing": { "$binary": { ... } }, "billAmount": 1500 }, "__safeContent__": [ { "$binary": { ... } } ] } ``` ## Next Steps Congratulations on completing the Doctrine ODM Queryable Encryption tutorial! You now have a sample Symfony application that uses Queryable Encryption to automatically encrypt and decrypt document fields. Your application encrypts sensitive data on the server side and queries the data on the client side. To learn more about Queryable Encryption and Doctrine MongoDB ODM, visit the following resources: - View more driver Queryable Encryption tutorials in the [MongoDB Server manual.](https://www.mongodb.com/docs/manual/core/queryable-encryption/tutorials.md#std-label-qe-tutorials - Learn more about Doctrine MongoDB ODM in the [Doctrine MongoDB ODM](https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/index.html) documentation. - Learn more about integrating Doctrine MongoDB ODM with Symfony in the [Symfony MongoDB Integration](https://www.mongodb.com/docs/drivers/php-frameworks/symfony.md#std-label-php-symfony-integration tutorial. ?>