Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
077e1df
Add `autoEncryption` configuration to the client (#889)
GromNaN Jun 17, 2025
9a43b4f
[Encryption] Update required version of mongodb driver and odm (#899)
GromNaN Jun 19, 2025
12b1559
[Encryption] Inject auto encryption options into ODM configuration (#…
GromNaN Jun 23, 2025
76e9684
[Encryption] Improve diagnostic command (#898)
GromNaN Jul 2, 2025
af57fa0
[Encryption] Fix format of `encryptedFieldsMaps` in the `autoEncrypti…
GromNaN Aug 1, 2025
8a8bdd4
Add link to encryption page from config docs
GromNaN Aug 8, 2025
61a8118
Escape mongocryptd path before calling it
GromNaN Aug 11, 2025
823dd72
[Encryption] Fix XML configuration (#910)
GromNaN Aug 13, 2025
f21d4ee
Remove invalid tlsOptions from the config doc
GromNaN Aug 18, 2025
23737b3
Remove unecessary attributes from the XSD (default values)
GromNaN Aug 18, 2025
953613d
Cast KMS provider to object to support AWS empty config
GromNaN Aug 18, 2025
ea8ac92
Add "fields" property to encryptedFieldsMap config (#912)
GromNaN Aug 20, 2025
59bea27
Validate extraOptions configuration (#913)
GromNaN Aug 20, 2025
7028b0e
Convert extra-options to sub-elements to allow multiple mongocryptdSp…
GromNaN Aug 21, 2025
cf11f81
Revert extraOptions config to attributes for string and boolean options
GromNaN Aug 21, 2025
c49d20d
Update diagnostic criteria
GromNaN Aug 21, 2025
e28616a
Add comment on encryptedFieldsMap JSON decoding
GromNaN Aug 21, 2025
887b319
Rename encryption commands (#914)
GromNaN Aug 22, 2025
37c0f03
Update docs
GromNaN Aug 22, 2025
28b8e68
Return dumped encrypted fields map even in quiet mode
GromNaN Aug 26, 2025
235b64d
[Encryption] Fix query option min/max type for exported encrypted fie…
GromNaN Aug 26, 2025
6d74e79
Revert mongodb-odm branch in composer.json
GromNaN Aug 28, 2025
e1e82e6
Add attributes for all master key formats
GromNaN Aug 28, 2025
90ad0b1
Change random string
GromNaN Aug 28, 2025
93ddd8a
Throw exception in JSON decode from toCanonicalExtendedJSON + support…
GromNaN Aug 28, 2025
7183f33
Move the commands to the Encryption namespace
GromNaN Aug 28, 2025
f13fde6
Fix compatibility with mongodb-odm < 1.12
GromNaN Aug 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/coding-standards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
pull_request:
branches:
- "*.x"
- "feature/*"
push:
branches:
- "*.x"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/composer-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ on:
pull_request:
branches:
- "*.x"
- "feature/*"
paths:
- "composer.json"
push:
branches:
- "*.x"
- "feature/*"
paths:
- "composer.json"

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
pull_request:
branches:
- "*.x"
- "master"
- "feature/*"
push:

env:
Expand Down Expand Up @@ -41,7 +41,7 @@ jobs:
- dependencies: "lowest"
os: "ubuntu-24.04"
php-version: "8.1"
driver-version: "1.16.0"
driver-version: "1.21.0"
stability: "stable"
symfony-version: "6.4.*"
- dependencies: "highest"
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
pull_request:
branches:
- "*.x"
- "feature/*"
paths:
- .github/workflows/static-analysis.yml
- composer.*
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
"homepage": "http://www.doctrine-project.org",
"require": {
"php": "^8.1",
"ext-mongodb": "^1.16 || ^2",
"ext-mongodb": "^1.21 || ^2",
"composer-runtime-api": "^2.0",
"doctrine/mongodb-odm": "^2.6",
"doctrine/mongodb-odm": "dev-feature/queryable-encryption as 2.12.x-dev",
"doctrine/persistence": "^3.0 || ^4.0",
"psr/log": "^1.0 || ^2.0 || ^3.0",
"symfony/config": "^6.4 || ^7.0",
Expand Down
11 changes: 11 additions & 0 deletions config/command.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use Doctrine\Bundle\MongoDBBundle\Command\ClearMetadataCacheDoctrineODMCommand;
use Doctrine\Bundle\MongoDBBundle\Command\CreateSchemaDoctrineODMCommand;
use Doctrine\Bundle\MongoDBBundle\Command\DropSchemaDoctrineODMCommand;
use Doctrine\Bundle\MongoDBBundle\Command\EncryptionDiagnosticCommand;
use Doctrine\Bundle\MongoDBBundle\Command\EncryptionDumpFieldsMapCommand;
use Doctrine\Bundle\MongoDBBundle\Command\GenerateHydratorsDoctrineODMCommand;
use Doctrine\Bundle\MongoDBBundle\Command\GenerateProxiesDoctrineODMCommand;
use Doctrine\Bundle\MongoDBBundle\Command\InfoDoctrineODMCommand;
Expand All @@ -15,12 +17,21 @@
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

use function Symfony\Component\DependencyInjection\Loader\Configurator\service;
use function Symfony\Component\DependencyInjection\Loader\Configurator\tagged_locator;

return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->services()
->set('doctrine_mongodb.odm.command.clear_metadata_cache', ClearMetadataCacheDoctrineODMCommand::class)
->tag('console.command', ['command' => 'doctrine:mongodb:cache:clear-metadata'])

->set('doctrine_mongodb.odm.command.connection_diagnostic', EncryptionDiagnosticCommand::class)
->tag('console.command', ['command' => 'doctrine:mongodb:encryption:diagnostic'])
->args([tagged_locator('doctrine_mongodb.connection_diagnostic', 'name')])

->set('doctrine_mongodb.odm.command.dump_encrypted_fields_map', EncryptionDumpFieldsMapCommand::class)
->tag('console.command', ['command' => 'doctrine:mongodb:encryption:dump-fields-map'])
->args([tagged_locator('doctrine_mongodb.odm.document_manager', 'name')])

->set('doctrine_mongodb.odm.command.create_schema', CreateSchemaDoctrineODMCommand::class)
->tag('console.command', ['command' => 'doctrine:mongodb:schema:create'])

Expand Down
100 changes: 91 additions & 9 deletions config/schema/mongodb-1.0.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<xsd:complexType name="config">
<xsd:sequence>
<xsd:element name="default-commit-options" type="default-commit-options" minOccurs="0" maxOccurs="1" />
<xsd:element name="default-commit-options" type="default-commit-options" minOccurs="0" />
<xsd:element name="connection" type="connection" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="document-manager" type="document-manager" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="resolve-target-document" type="resolve_target_document" minOccurs="0" maxOccurs="unbounded" />
Expand Down Expand Up @@ -46,8 +46,9 @@

<xsd:complexType name="connection">
<xsd:sequence>
<xsd:element name="options" type="connection-options" minOccurs="0" maxOccurs="1" />
<xsd:element name="driver-options" type="connection-driver-options" minOccurs="0" maxOccurs="1" />
<xsd:element name="options" type="connection-options" minOccurs="0" />
<xsd:element name="driver-options" type="connection-driver-options" minOccurs="0" />
<xsd:element name="autoEncryption" type="auto-encryption" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" use="required" />
<xsd:attribute name="server" type="xsd:string" />
Expand Down Expand Up @@ -84,6 +85,9 @@
</xsd:complexType>

<xsd:complexType name="connection-driver-options">
<xsd:all>
<xsd:element name="autoEncryption" type="auto-encryption" minOccurs="0"/>
</xsd:all>
<xsd:attribute name="context" type="xsd:string" />
</xsd:complexType>

Expand Down Expand Up @@ -119,12 +123,90 @@
<xsd:attribute name="value" type="xsd:string" use="required" />
</xsd:complexType>

<xsd:complexType name="auto-encryption">
<xsd:sequence>
<xsd:element name="kmsProvider" type="kms-provider" />
<xsd:element name="masterKey" type="master-key" minOccurs="0" />
<xsd:element name="keyVaultClient" type="xsd:string" minOccurs="0" />
<xsd:element name="keyVaultNamespace" type="xsd:string" minOccurs="0" />
<xsd:element name="tlsOptions" type="tls-options" minOccurs="0" />
<xsd:element name="encryptedFieldsMap" type="encrypted-fields-map" minOccurs="0" />
<xsd:element name="extraOptions" type="extra-options" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="bypassAutoEncryption" type="xsd:boolean" />
<xsd:attribute name="bypassQueryAnalysis" type="xsd:boolean" />
</xsd:complexType>

<xsd:complexType name="kms-provider">
<xsd:attribute name="type" type="xsd:string" use="required" />
<!-- AWS -->
<xsd:attribute name="accessKeyId" type="xsd:string" />
<xsd:attribute name="secretAccessKey" type="xsd:string" />
<xsd:attribute name="sessionToken" type="xsd:string" />
<!-- Azure -->
<xsd:attribute name="tenantId" type="xsd:string" />
<xsd:attribute name="clientId" type="xsd:string" />
<xsd:attribute name="clientSecret" type="xsd:string" />
<xsd:attribute name="keyVaultEndpoint" type="xsd:string" />
<xsd:attribute name="identityPlatformEndpoint" type="xsd:string" />
<xsd:attribute name="keyName" type="xsd:string" />
<xsd:attribute name="keyVersion" type="xsd:string" />
<!-- GCP -->
<xsd:attribute name="email" type="xsd:string" />
<xsd:attribute name="privateKey" type="xsd:string" />
<xsd:attribute name="endpoint" type="xsd:string" />
<xsd:attribute name="projectId" type="xsd:string" />
<xsd:attribute name="location" type="xsd:string" />
<xsd:attribute name="keyRing" type="xsd:string" />
<!-- Attribute already present for another KMS type -->
<!-- <xsd:attribute name="keyName" type="xsd:string" /> -->
<!-- <xsd:attribute name="keyVersion" type="xsd:string" /> -->
<!-- KMIP -->
<!-- <xsd:attribute name="endpoint" type="xsd:string" /> -->
<!-- Local -->
<xsd:attribute name="key" type="xsd:string" />
</xsd:complexType>

<xsd:complexType name="master-key">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this warrant its own complex type? Why not just allow the master key to be specified as an attribute on the parent masterKey XML element?

That would be consistent with the other string options at that level, such as keyVaultClient and keyVaultNamespace.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on this XSD,

There are various struct formats (by provider) for the masterKey option, as documented in ClientEncryption::createDataKey().

The XSD defines the master-key complex type as:

<xsd:attribute name="key" type="xsd:string" use="required" />

Unless I'm mistaken (and my XSD is rusty), that's going to allow a single key string option to be specified within masterKey. And that's just one of several sub-options for the "aws" provider.

Should this be changed to allow any number of <string-option> and <bool-option> values? (names there are for example purposes, but maybe there is a general need for since this is a recurring problem for complex configs in XML).

<xsd:attribute name="key" type="xsd:string" use="required" />
</xsd:complexType>

<xsd:complexType name="tls-options">
<xsd:attribute name="tlsCAFile" type="xsd:string" />
<xsd:attribute name="tlsCertificateKeyFile" type="xsd:string" />
<xsd:attribute name="tlsCertificateKeyFilePassword" type="xsd:string" />
<xsd:attribute name="tlsDisableOCSPEndpointCheck" type="xsd:boolean" />
</xsd:complexType>

<xsd:simpleType name="encrypted-fields-map">
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>

<xsd:complexType name="encrypted-queries">
<xsd:attribute name="queryType" type="xsd:string" use="required" />
<xsd:attribute name="min" type="xsd:string" />
<xsd:attribute name="max" type="xsd:string" />
<xsd:attribute name="sparsity" type="xsd:string" />
<xsd:attribute name="trimFactor" type="xsd:string" />
</xsd:complexType>

<xsd:complexType name="extra-options">
<xsd:sequence>
<xsd:element name="mongocryptdSpawnArgs" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="mongocryptdURI" type="xsd:string" />
<xsd:attribute name="mongocryptdBypassSpawn" type="xsd:boolean" />
<xsd:attribute name="mongocryptdSpawnPath" type="xsd:string" />
<xsd:attribute name="cryptSharedLibPath" type="xsd:string" />
<xsd:attribute name="cryptSharedLibRequired" type="xsd:boolean" />
</xsd:complexType>

<xsd:complexType name="document-manager">
<xsd:choice maxOccurs="unbounded">
<xsd:element name="filter" type="filter" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="mapping" type="mapping" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="metadata-cache-driver" type="metadata-cache-driver" minOccurs="0" maxOccurs="1" />
<xsd:element name="profiler" type="profiler" minOccurs="0" maxOccurs="1" />
<xsd:element name="metadata-cache-driver" type="metadata-cache-driver" minOccurs="0" />
<xsd:element name="profiler" type="profiler" minOccurs="0" />
</xsd:choice>
<xsd:attribute name="id" type="xsd:string" use="required" />
<xsd:attribute name="auto-mapping" type="xsd:boolean" />
Expand Down Expand Up @@ -167,10 +249,10 @@

<xsd:complexType name="metadata-cache-driver">
<xsd:all>
<xsd:element name="class" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="host" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="instance-class" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="port" type="xsd:integer" minOccurs="0" maxOccurs="1" />
<xsd:element name="class" type="xsd:string" minOccurs="0" />
<xsd:element name="host" type="xsd:string" minOccurs="0" />
<xsd:element name="instance-class" type="xsd:string" minOccurs="0" />
<xsd:element name="port" type="xsd:integer" minOccurs="0" />
</xsd:all>
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
Expand Down
50 changes: 48 additions & 2 deletions docs/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,10 @@ Otherwise you will get a *auth failed* exception.
]);
};

Using Queryable Encryption
--------------------------

For details on configuring Queryable Encryption (QE) and Client-Side Field-Level Encryption (CSFLE), see :doc:`encryption`.

Full Default Configuration
--------------------------
Expand Down Expand Up @@ -699,6 +703,29 @@ Full Default Configuration
wTimeoutMS: ~
driver_options:
context: ~ # stream context to use for connection
autoEncryption: # Options for client-side field-level encryption
keyVaultClient: null # Service ID of a MongoDB\Driver\Manager for the key vault
keyVaultNamespace: null # The namespace for the key vault collection (e.g., "encryption.__keyVault")
kmsProvider: {} # Configuration for Key Management System provider (see specific examples above)
# e.g., { type: "local", key: "YOUR_BASE64_KEY" }
# e.g., { type: "aws", accessKeyId: "...", secretAccessKey: "..." }
masterKey: ~ # Default master key to use when creating a new encrypted collection
schemaMap: [] # Document schemas for explicit encryption
encryptedFieldsMap: [] # Map of collections to their encrypted fields configuration
extraOptions: [] # Extra options for mongocryptd
# mongocryptdURI: "mongodb://localhost:27020"
# mongocryptdBypassSpawn: false
# mongocryptdSpawnPath: "/usr/local/bin/mongocryptd"
# mongocryptdSpawnArgs: ["--idleShutdownTimeoutSecs=60"]
# cryptSharedLibPath: null # Path to the crypt_shared library
# cryptSharedLibRequired: false # If true, fails if the crypt_shared library cannot be loaded
bypassQueryAnalysis: false # Disables automatic analysis of read and write operations for encryption
bypassAutoEncryption: false # Disables auto-encryption
tlsOptions: # TLS options for the Key Vault client (if keyVaultClient is not specified)
tlsCAFile: null # Path to CA file, e.g., /path/to/key-vault-ca.pem
tlsCertificateKeyFile: null # Path to client cert/key file, e.g., /path/to/key-vault-client.pem
tlsCertificateKeyFilePassword: null # Password for client cert/key file
tlsDisableOCSPEndpointCheck: false # Disable OCSP checks

proxy_namespace: MongoDBODMProxies
proxy_dir: "%kernel.cache_dir%/doctrine/odm/mongodb/Proxies"
Expand Down Expand Up @@ -825,8 +852,27 @@ Full Default Configuration

$config->connection('id')
->server('mongodb://localhost')
->driverOptions([
'context' => null, // stream context to use for connection
->autoEncryption([ // Options for client-side field-level encryption
'bypassAutoEncryption' => false, // Disables auto-encryption
'keyVaultClient' => null, // Service ID of a MongoDB\Driver\Manager for the key vault
'keyVaultNamespace' => null, // The namespace for the key vault collection (e.g., "encryption.__keyVault")
'kmsProvider' => [ // Configuration for Key Management System provider
// e.g., ['type' => 'local', 'key' => 'YOUR_BASE64_KEY']
// e.g., ['type' => 'aws', 'accessKeyId' => '...', 'secretAccessKey' => '...']
],
'schemaMap' => [], // Document schemas for explicit encryption
'encryptedFieldsMap' => [], // Map of collections to their encrypted fields configuration
'extraOptions' => [ // Extra options for mongocryptd
// 'cryptSharedLibPath' => null, // Path to the crypt_shared library
// 'cryptSharedLibRequired' => false, // If true, fails if the crypt_shared library cannot be loaded
],
'bypassQueryAnalysis' => false, // Disables automatic analysis of read and write operations for encryption
'tlsOptions' => [ // TLS options for the Key Vault client (if keyVaultClient is not specified)
// 'tlsCAFile' => null, // Path to CA file, e.g., /path/to/key-vault-ca.pem
// 'tlsCertificateKeyFile' => null, // Path to client cert/key file, e.g., /path/to/key-vault-client.pem
// 'tlsCertificateKeyFilePassword' => null, // Password for client cert/key file
// 'tlsDisableOCSPEndpointCheck' => false, // Disable OCSP checks
],
])
->options([
'authMechanism' => null,
Expand Down
Loading