-
Notifications
You must be signed in to change notification settings - Fork 265
PHPLIB-1176: Various improvements for In-Use Encryption tutorial #1122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
jmikola
merged 6 commits into
mongodb:master
from
jmikola:phplib-1176-encryption-tutorial
Jul 10, 2023
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
4a1e55d
PHPLIB-1176: Various improvements for In-Use Encryption tutorial
jmikola c2ca7b0
Code review feedback
jmikola e81560a
Create key vault index in key management scripts and remove setup cod…
jmikola e05aa7d
Fix variable typo
jmikola af018f1
Update baseline
jmikola 847023d
PHP 7.2 doesn't allow indenting nowdoc closing identifiers
jmikola File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php | ||
|
||
use MongoDB\BSON\Binary; | ||
use MongoDB\Client; | ||
use MongoDB\Driver\ClientEncryption; | ||
|
||
require __DIR__ . '/../../vendor/autoload.php'; | ||
|
||
$uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; | ||
|
||
// Generate a secure local key to use for this script | ||
$localKey = new Binary(random_bytes(96)); | ||
|
||
// Create a client with no encryption options | ||
$client = new Client($uri); | ||
|
||
/* Prepare the database for this script. Drop the key vault collection and | ||
* ensure it has a unique index for keyAltNames. This would typically be done | ||
* during application deployment. */ | ||
$client->selectCollection('encryption', '__keyVault')->drop(); | ||
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], [ | ||
'unique' => true, | ||
'partialFilterExpression' => ['keyAltNames' => ['$exists' => true]], | ||
]); | ||
|
||
// Create a ClientEncryption object to manage data encryption keys | ||
$clientEncryption = $client->createClientEncryption([ | ||
'keyVaultNamespace' => 'encryption.__keyVault', | ||
'kmsProviders' => [ | ||
'local' => ['key' => $localKey], | ||
], | ||
]); | ||
|
||
/* Create a data encryption key. To store the key ID for later use, you can use | ||
* serialize(), var_export(), etc. */ | ||
$keyId = $clientEncryption->createDataKey('local'); | ||
|
||
print_r($keyId); | ||
|
||
// Encrypt a value using the key that was just created | ||
$encryptedValue = $clientEncryption->encrypt('mySecret', [ | ||
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, | ||
'keyId' => $keyId, | ||
]); | ||
|
||
print_r($encryptedValue); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?php | ||
|
||
use MongoDB\BSON\Binary; | ||
use MongoDB\Client; | ||
use MongoDB\Driver\ClientEncryption; | ||
use MongoDB\Driver\Exception\ServerException; | ||
|
||
require __DIR__ . '/../../vendor/autoload.php'; | ||
|
||
$uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; | ||
|
||
/* Note: this script assumes that the test database is empty and that the key | ||
* vault collection exists and has a partial, unique index on keyAltNames (as | ||
* demonstrated in the encryption key management scripts). */ | ||
|
||
// Generate a secure local key to use for this script | ||
$localKey = new Binary(random_bytes(96)); | ||
|
||
// Create a client with no encryption options | ||
$client = new Client($uri); | ||
|
||
// Create a ClientEncryption object to manage data encryption keys | ||
$clientEncryption = $client->createClientEncryption([ | ||
'keyVaultNamespace' => 'encryption.__keyVault', | ||
'kmsProviders' => [ | ||
'local' => ['key' => $localKey], | ||
], | ||
]); | ||
|
||
/* Create a data encryption key. Alternatively, this key ID could be read from a | ||
* configuration file. */ | ||
$keyId = $clientEncryption->createDataKey('local'); | ||
|
||
/* Define a JSON schema for the encrypted collection. Since this only utilizes | ||
* encryption schema syntax, it can be used for both the server-side and local | ||
* schema. */ | ||
$schema = [ | ||
'bsonType' => 'object', | ||
'properties' => [ | ||
'encryptedField' => [ | ||
'encrypt' => [ | ||
'keyId' => [$keyId], | ||
'bsonType' => 'string', | ||
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, | ||
], | ||
], | ||
], | ||
]; | ||
|
||
/* Create another client with automatic encryption enabled. Configure a local | ||
* schema for the encrypted collection using the "schemaMap" option. */ | ||
$encryptedClient = new Client($uri, [], [ | ||
'autoEncryption' => [ | ||
'keyVaultNamespace' => 'encryption.__keyVault', | ||
'kmsProviders' => ['local' => ['key' => $localKey]], | ||
'schemaMap' => ['test.coll' => $schema], | ||
], | ||
]); | ||
|
||
/* Create a new collection for this script. Configure a server-side schema by | ||
* explicitly creating the collection with a "validator" option. | ||
* | ||
* Note: without a server-side schema, another client could potentially insert | ||
* unencrypted data into the collection. Therefore, a local schema should always | ||
* be used in conjunction with a server-side schema. */ | ||
$encryptedClient->selectDatabase('test')->createCollection('coll', ['validator' => ['$jsonSchema' => $schema]]); | ||
$encryptedCollection = $encryptedClient->selectCollection('test', 'coll'); | ||
|
||
/* Using the encrypted client, insert and find a document to demonstrate that | ||
* the encrypted field is automatically encrypted and decrypted. */ | ||
$encryptedCollection->insertOne(['_id' => 1, 'encryptedField' => 'mySecret']); | ||
|
||
print_r($encryptedCollection->findOne(['_id' => 1])); | ||
|
||
/* Using the client configured without encryption, find the same document and | ||
* observe that the field is not automatically decrypted. */ | ||
$unencryptedCollection = $client->selectCollection('test', 'coll'); | ||
|
||
print_r($unencryptedCollection->findOne(['_id' => 1])); | ||
|
||
/* Attempt to insert another document with an unencrypted field value to | ||
* demonstrate that the server-side schema is enforced. */ | ||
try { | ||
$unencryptedCollection->insertOne(['_id' => 2, 'encryptedField' => 'myOtherSecret']); | ||
} catch (ServerException $e) { | ||
printf("Error inserting document: %s\n", $e->getMessage()); | ||
} |
79 changes: 79 additions & 0 deletions
79
docs/examples/csfle-automatic_encryption-server_side_schema.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
<?php | ||
|
||
use MongoDB\BSON\Binary; | ||
use MongoDB\Client; | ||
use MongoDB\Driver\ClientEncryption; | ||
use MongoDB\Driver\Exception\ServerException; | ||
|
||
require __DIR__ . '/../../vendor/autoload.php'; | ||
|
||
$uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; | ||
|
||
/* Note: this script assumes that the test database is empty and that the key | ||
* vault collection exists and has a partial, unique index on keyAltNames (as | ||
* demonstrated in the encryption key management scripts). */ | ||
|
||
// Generate a secure local key to use for this script | ||
$localKey = new Binary(random_bytes(96)); | ||
|
||
// Create a client with no encryption options | ||
$client = new Client($uri); | ||
|
||
// Create a ClientEncryption object to manage data encryption keys | ||
$clientEncryption = $client->createClientEncryption([ | ||
'keyVaultNamespace' => 'encryption.__keyVault', | ||
'kmsProviders' => [ | ||
'local' => ['key' => $localKey], | ||
], | ||
]); | ||
|
||
/* Create a data encryption key. Alternatively, this key ID could be read from a | ||
* configuration file. */ | ||
$keyId = $clientEncryption->createDataKey('local'); | ||
|
||
// Create another client with automatic encryption enabled | ||
$encryptedClient = new Client($uri, [], [ | ||
'autoEncryption' => [ | ||
'keyVaultNamespace' => 'encryption.__keyVault', | ||
'kmsProviders' => ['local' => ['key' => $localKey]], | ||
], | ||
]); | ||
|
||
// Define a JSON schema for the encrypted collection | ||
$schema = [ | ||
'bsonType' => 'object', | ||
'properties' => [ | ||
'encryptedField' => [ | ||
'encrypt' => [ | ||
'keyId' => [$keyId], | ||
'bsonType' => 'string', | ||
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, | ||
], | ||
], | ||
], | ||
]; | ||
|
||
/* Create a new collection for this script. Configure a server-side schema by | ||
* explicitly creating the collection with a "validator" option. */ | ||
$encryptedClient->selectDatabase('test')->createCollection('coll', ['validator' => ['$jsonSchema' => $schema]]); | ||
$encryptedCollection = $encryptedClient->selectCollection('test', 'coll'); | ||
|
||
/* Using the encrypted client, insert and find a document to demonstrate that | ||
* the encrypted field is automatically encrypted and decrypted. */ | ||
$encryptedCollection->insertOne(['_id' => 1, 'encryptedField' => 'mySecret']); | ||
|
||
print_r($encryptedCollection->findOne(['_id' => 1])); | ||
|
||
/* Using the client configured without encryption, find the same document and | ||
* observe that the field is not automatically decrypted. */ | ||
$unencryptedCollection = $client->selectCollection('test', 'coll'); | ||
|
||
print_r($unencryptedCollection->findOne(['_id' => 1])); | ||
|
||
/* Attempt to insert another document with an unencrypted field value to | ||
* demonstrate that the server-side schema is enforced. */ | ||
try { | ||
$unencryptedCollection->insertOne(['_id' => 2, 'encryptedField' => 'myOtherSecret']); | ||
} catch (ServerException $e) { | ||
printf("Error inserting document: %s\n", $e->getMessage()); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
|
||
use MongoDB\BSON\Binary; | ||
use MongoDB\Client; | ||
use MongoDB\Driver\ClientEncryption; | ||
|
||
require __DIR__ . '/../../vendor/autoload.php'; | ||
|
||
$uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; | ||
|
||
/* Note: this script assumes that the test database is empty and that the key | ||
* vault collection exists and has a partial, unique index on keyAltNames (as | ||
* demonstrated in the encryption key management scripts). */ | ||
|
||
// Generate a secure local key to use for this script | ||
$localKey = new Binary(random_bytes(96)); | ||
|
||
// Create a client with no encryption options | ||
$client = new Client($uri); | ||
|
||
// Create a ClientEncryption object to manage data encryption keys | ||
$clientEncryption = $client->createClientEncryption([ | ||
'keyVaultNamespace' => 'encryption.__keyVault', | ||
'kmsProviders' => [ | ||
'local' => ['key' => $localKey], | ||
], | ||
]); | ||
|
||
/* Create a data encryption key. Alternatively, this key ID could be read from a | ||
* configuration file. */ | ||
$keyId = $clientEncryption->createDataKey('local'); | ||
|
||
// Insert a document with a manually encrypted field | ||
$encryptedValue = $clientEncryption->encrypt('mySecret', [ | ||
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, | ||
'keyId' => $keyId, | ||
]); | ||
|
||
$collection = $client->selectCollection('test', 'coll'); | ||
$collection->insertOne(['_id' => 1, 'encryptedField' => $encryptedValue]); | ||
|
||
/* Using the client configured without encryption, find the document and observe | ||
* that the field is not automatically decrypted. */ | ||
$document = $collection->findOne(); | ||
|
||
print_r($document); | ||
|
||
// Manually decrypt the field | ||
printf("Decrypted: %s\n", $clientEncryption->decrypt($document->encryptedField)); |
52 changes: 52 additions & 0 deletions
52
docs/examples/csfle-explicit_encryption_automatic_decryption.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
<?php | ||
|
||
use MongoDB\BSON\Binary; | ||
use MongoDB\Client; | ||
use MongoDB\Driver\ClientEncryption; | ||
|
||
require __DIR__ . '/../../vendor/autoload.php'; | ||
|
||
$uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; | ||
|
||
/* Note: this script assumes that the test database is empty and that the key | ||
* vault collection exists and has a partial, unique index on keyAltNames (as | ||
* demonstrated in the encryption key management scripts). */ | ||
|
||
// Generate a secure local key to use for this script | ||
$localKey = new Binary(random_bytes(96)); | ||
|
||
// Create a client with automatic encryption disabled | ||
$client = new Client($uri, [], [ | ||
'autoEncryption' => [ | ||
'keyVaultNamespace' => 'encryption.__keyVault', | ||
'kmsProviders' => ['local' => ['key' => $localKey]], | ||
'bypassAutoEncryption' => true, | ||
], | ||
]); | ||
|
||
// Create a ClientEncryption object to manage data encryption keys | ||
$clientEncryption = $client->createClientEncryption([ | ||
'keyVaultNamespace' => 'encryption.__keyVault', | ||
'kmsProviders' => [ | ||
'local' => ['key' => $localKey], | ||
], | ||
]); | ||
|
||
/* Create a data encryption key. Alternatively, this key ID could be read from a | ||
* configuration file. */ | ||
$keyId = $clientEncryption->createDataKey('local'); | ||
|
||
// Insert a document with a manually encrypted field | ||
$encryptedValue = $clientEncryption->encrypt('mySecret', [ | ||
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, | ||
'keyId' => $keyId, | ||
]); | ||
|
||
$collection = $client->selectCollection('test', 'coll'); | ||
$collection->insertOne(['_id' => 1, 'encryptedField' => $encryptedValue]); | ||
|
||
/* Using the client configured with encryption (but not automatic encryption), | ||
* find the document and observe that the field is automatically decrypted. */ | ||
$document = $collection->findOne(); | ||
|
||
print_r($document); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
<?php | ||
|
||
use MongoDB\BSON\Binary; | ||
use MongoDB\Client; | ||
use MongoDB\Driver\ClientEncryption; | ||
use MongoDB\Driver\Exception\ServerException; | ||
|
||
require __DIR__ . '/../../vendor/autoload.php'; | ||
|
||
$uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'; | ||
|
||
// Generate a secure local key to use for this script | ||
$localKey = new Binary(random_bytes(96)); | ||
|
||
// Create a client with no encryption options | ||
$client = new Client($uri); | ||
|
||
/* Prepare the database for this script. Drop the key vault collection and | ||
* ensure it has a unique index for keyAltNames. This would typically be done | ||
* during application deployment. */ | ||
$client->selectCollection('encryption', '__keyVault')->drop(); | ||
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], [ | ||
'unique' => true, | ||
'partialFilterExpression' => ['keyAltNames' => ['$exists' => true]], | ||
]); | ||
|
||
// Create a ClientEncryption object to manage data encryption keys | ||
$clientEncryption = $client->createClientEncryption([ | ||
'keyVaultNamespace' => 'encryption.__keyVault', | ||
'kmsProviders' => [ | ||
'local' => ['key' => $localKey], | ||
], | ||
]); | ||
|
||
// Create a data encryption key with an alternate name | ||
$clientEncryption->createDataKey('local', ['keyAltNames' => ['myDataKey']]); | ||
|
||
/* Attempt to create a second key with the same name to demonstrate that the | ||
* unique index is enforced. */ | ||
try { | ||
$clientEncryption->createDataKey('local', ['keyAltNames' => ['myDataKey']]); | ||
} catch (ServerException $e) { | ||
printf("Error creating key: %s\n", $e->getMessage()); | ||
} | ||
|
||
// Encrypt a value, using the "keyAltName" option instead of "keyId" | ||
$encryptedValue = $clientEncryption->encrypt('mySecret', [ | ||
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, | ||
'keyAltName' => 'myDataKey', | ||
]); | ||
|
||
print_r($encryptedValue); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This note is included in scripts other than
create_data_key.php
andkey_alt_name.php
, which demonstrate creation of the unique index on the key vault. I'm reasonably happy with this, as it avoids repetition, and also goes along with the note I added in the RST prose above thekey_alt_name.php
example.This means all
drop()
calls are removed andcreateCollection()
only exists in the QE example scripts, since it's necessary to handleencryptedFields
. I've revised the comments to remind users aboutencryptedFields
when dropping collections.ExamplesTest was also updated to ensure a clean test environment going into each script, and create the necessary key vault index.