Skip to content

Commit 78b5799

Browse files
committed
Create key vault index in key management scripts and remove setup code elsewhere
This replaces the setup code with a top-of-script comment to avoid repetition. ExamplesTest now prepares the cleans up the necessary collections. Add a note about creating the partial, unique index on keyAltNames.
1 parent b4bfd0e commit 78b5799

10 files changed

+97
-60
lines changed

docs/examples/create_data_key.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@
1414
// Create a client with no encryption options
1515
$client = new Client($uri);
1616

17+
/* Prepare the database for this script. Drop the key vault collection and
18+
* ensure it has a unique index for keyAltNames. This would typically be done
19+
* during application deployment. */
20+
$client->selectCollection('encryption', '__keyVault')->drop();
21+
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], [
22+
'unique' => true,
23+
'partialFilterExpression' => ['keyAltNames' => ['$exists' => true]],
24+
]);
25+
1726
// Create a ClientEncryption object to manage data encryption keys
1827
$clientEncryption = $client->createClientEncryption([
1928
'keyVaultNamespace' => 'encryption.__keyVault',
@@ -22,11 +31,6 @@
2231
],
2332
]);
2433

25-
/* Create a new key vault collection for this script. The application must also
26-
* ensure that a unique index exists for keyAltNames. */
27-
$client->selectCollection('encryption', '__keyVault')->drop();
28-
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);
29-
3034
/* Create a data encryption key. To store the key ID for later use, you can use
3135
* serialize(), var_export(), etc. */
3236
$keyId = $clientEncryption->createDataKey('local');

docs/examples/csfle-automatic_encryption-local_schema.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99

1010
$uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/';
1111

12+
/* Note: this script assumes that the test database is empty and that the key
13+
* vault collection exists and has a partial, unique index on keyAltNames (as
14+
* demonstrated in the encryption key management scripts). */
15+
1216
// Generate a secure local key to use for this script
1317
$localKey = new Binary(random_bytes(96));
1418

@@ -23,10 +27,8 @@
2327
],
2428
]);
2529

26-
/* Create a new key vault collection and data encryption key for this script.
27-
* Alternatively, this key ID could be read from a configuration file. */
28-
$client->selectCollection('encryption', '__keyVault')->drop();
29-
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);
30+
/* Create a data encryption key. Alternatively, this key ID could be read from a
31+
* configuration file. */
3032
$keyId = $clientEncryption->createDataKey('local');
3133

3234
/* Define a JSON schema for the encrypted collection. Since this only utilizes
@@ -61,7 +63,6 @@
6163
* Note: without a server-side schema, another client could potentially insert
6264
* unencrypted data into the collection. Therefore, a local schema should always
6365
* be used in conjunction with a server-side schema. */
64-
$encryptedClient->selectDatabase('test')->dropCollection('coll');
6566
$encryptedClient->selectDatabase('test')->createCollection('coll', ['validator' => ['$jsonSchema' => $schema]]);
6667
$encryptedCollection = $encryptedClient->selectCollection('test', 'coll');
6768

docs/examples/csfle-automatic_encryption-server_side_schema.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99

1010
$uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/';
1111

12+
/* Note: this script assumes that the test database is empty and that the key
13+
* vault collection exists and has a partial, unique index on keyAltNames (as
14+
* demonstrated in the encryption key management scripts). */
15+
1216
// Generate a secure local key to use for this script
1317
$localKey = new Binary(random_bytes(96));
1418

@@ -23,10 +27,8 @@
2327
],
2428
]);
2529

26-
/* Create a new key vault collection and data encryption key for this script.
27-
* Alternatively, this key ID could be read from a configuration file. */
28-
$client->selectCollection('encryption', '__keyVault')->drop();
29-
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);
30+
/* Create a data encryption key. Alternatively, this key ID could be read from a
31+
* configuration file. */
3032
$keyId = $clientEncryption->createDataKey('local');
3133

3234
// Create another client with automatic encryption enabled
@@ -53,7 +55,6 @@
5355

5456
/* Create a new collection for this script. Configure a server-side schema by
5557
* explicitly creating the collection with a "validator" option. */
56-
$encryptedClient->selectDatabase('test')->dropCollection('coll');
5758
$encryptedClient->selectDatabase('test')->createCollection('coll', ['validator' => ['$jsonSchema' => $schema]]);
5859
$encryptedCollection = $encryptedClient->selectCollection('test', 'coll');
5960

docs/examples/csfle-explicit_encryption.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
$uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/';
1010

11+
/* Note: this script assumes that the test database is empty and that the key
12+
* vault collection exists and has a partial, unique index on keyAltNames (as
13+
* demonstrated in the encryption key management scripts). */
14+
1115
// Generate a secure local key to use for this script
1216
$localKey = new Binary(random_bytes(96));
1317

@@ -22,22 +26,17 @@
2226
],
2327
]);
2428

25-
/* Create a new key vault collection and data encryption key for this script.
26-
* Alternatively, this key ID could be read from a configuration file. */
27-
$client->selectCollection('encryption', '__keyVault')->drop();
28-
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);
29+
/* Create a data encryption key. Alternatively, this key ID could be read from a
30+
* configuration file. */
2931
$keyId = $clientEncryption->createDataKey('local');
3032

31-
// Create a new collection for this script
32-
$collection = $client->selectCollection('test', 'coll');
33-
$collection->drop();
34-
3533
// Insert a document with a manually encrypted field
3634
$encryptedValue = $clientEncryption->encrypt('mySecret', [
3735
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
3836
'keyId' => $keyId,
3937
]);
4038

39+
$collection = $client->selectCollection('test', 'coll');
4140
$collection->insertOne(['_id' => 1, 'encryptedField' => $encryptedValue]);
4241

4342
/* Using the client configured without encryption, find the document and observe

docs/examples/csfle-explicit_encryption_automatic_decryption.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
$uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/';
1010

11+
/* Note: this script assumes that the test database is empty and that the key
12+
* vault collection exists and has a partial, unique index on keyAltNames (as
13+
* demonstrated in the encryption key management scripts). */
14+
1115
// Generate a secure local key to use for this script
1216
$localKey = new Binary(random_bytes(96));
1317

@@ -28,22 +32,17 @@
2832
],
2933
]);
3034

31-
/* Create a new key vault collection and data encryption key for this script.
32-
* Alternatively, this key ID could be read from a configuration file. */
33-
$client->selectCollection('encryption', '__keyVault')->drop();
34-
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);
35+
/* Create a data encryption key. Alternatively, this key ID could be read from a
36+
* configuration file. */
3537
$keyId = $clientEncryption->createDataKey('local');
3638

37-
// Create a new collection for this script
38-
$collection = $client->selectCollection('test', 'coll');
39-
$collection->drop();
40-
4139
// Insert a document with a manually encrypted field
4240
$encryptedValue = $clientEncryption->encrypt('mySecret', [
4341
'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC,
4442
'keyId' => $keyId,
4543
]);
4644

45+
$collection = $client->selectCollection('test', 'coll');
4746
$collection->insertOne(['_id' => 1, 'encryptedField' => $encryptedValue]);
4847

4948
/* Using the client configured with encryption (but not automatic encryption),

docs/examples/key_alt_name.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515
// Create a client with no encryption options
1616
$client = new Client($uri);
1717

18+
/* Prepare the database for this script. Drop the key vault collection and
19+
* ensure it has a unique index for keyAltNames. This would typically be done
20+
* during application deployment. */
21+
$client->selectCollection('encryption', '__keyVault')->drop();
22+
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], [
23+
'unique' => true,
24+
'partialFilterExpression' => ['keyAltNames' => ['$exists' => true]],
25+
]);
26+
1827
// Create a ClientEncryption object to manage data encryption keys
1928
$clientEncryption = $client->createClientEncryption([
2029
'keyVaultNamespace' => 'encryption.__keyVault',
@@ -23,11 +32,6 @@
2332
],
2433
]);
2534

26-
/* Create a new key vault collection for this script. The application must also
27-
* ensure that a unique index exists for keyAltNames. */
28-
$client->selectCollection('encryption', '__keyVault')->drop();
29-
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);
30-
3135
// Create a data encryption key with an alternate name
3236
$clientEncryption->createDataKey('local', ['keyAltNames' => ['myDataKey']]);
3337

docs/examples/queryable_encryption-automatic.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
$uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/';
1010

11+
/* Note: this script assumes that the test database is empty and that the key
12+
* vault collection exists and has a partial, unique index on keyAltNames (as
13+
* demonstrated in the encryption key management scripts). */
14+
1115
// Generate a secure local key to use for this script
1216
$localKey = new Binary(random_bytes(96));
1317

@@ -20,10 +24,8 @@
2024
'kmsProviders' => ['local' => ['key' => $localKey]],
2125
]);
2226

23-
/* Create a new key vault collection and data encryption keys for this script.
24-
* Alternatively, the key IDs could be read from a configuration file. */
25-
$client->selectCollection('encryption', '__keyVault')->drop();
26-
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);
27+
/* Create the data encryption keys for this script. Alternatively, the key IDs
28+
* could be read from a configuration file. */
2729
$keyId1 = $clientEncryption->createDataKey('local');
2830
$keyId2 = $clientEncryption->createDataKey('local');
2931

@@ -53,10 +55,10 @@
5355
],
5456
]);
5557

56-
/* Create a new collection for this script. The drop and create helpers will
57-
* infer encryptedFields from the client and manage internal encryption
58-
* collections automatically. */
59-
$encryptedClient->selectDatabase('test')->dropCollection('coll');
58+
/* Create the data collection for this script. The create and drop helpers will
59+
* infer encryptedFields from the client configuration and manage internal
60+
* encryption collections automatically. Alternatively, the "encryptedFields"
61+
* option can also be passed explicitly. */
6062
$encryptedClient->selectDatabase('test')->createCollection('coll');
6163
$encryptedCollection = $encryptedClient->selectCollection('test', 'coll');
6264

docs/examples/queryable_encryption-explicit.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
$uri = getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/';
1010

11+
/* Note: this script assumes that the test database is empty and that the key
12+
* vault collection exists and has a partial, unique index on keyAltNames (as
13+
* demonstrated in the encryption key management scripts). */
14+
1115
// Generate a secure local key to use for this script
1216
$localKey = new Binary(random_bytes(96));
1317

@@ -20,10 +24,8 @@
2024
'kmsProviders' => ['local' => ['key' => $localKey]],
2125
]);
2226

23-
/* Create a new key vault collection and data encryption keys for this script.
24-
* Alternatively, the key IDs could be read from a configuration file. */
25-
$client->selectCollection('encryption', '__keyVault')->drop();
26-
$client->selectCollection('encryption', '__keyVault')->createIndex(['keyAltNames' => 1], ['unique' => true]);
27+
/* Create the data encryption keys. Alternatively, the key IDs could be read
28+
* from a configuration file. */
2729
$keyId1 = $clientEncryption->createDataKey('local');
2830
$keyId2 = $clientEncryption->createDataKey('local');
2931

@@ -53,9 +55,10 @@
5355
],
5456
];
5557

56-
/* Create a new collection for this script. Pass encryptedFields to the drop and
57-
* create helpers to ensure that internal encryption collections are managed. */
58-
$encryptedClient->selectDatabase('test')->dropCollection('coll', ['encryptedFields' => $encryptedFields]);
58+
/* Create the data collection for this script. Specify the "encryptedFields"
59+
* option to ensure that internal encryption collections are also created. The
60+
* "encryptedFields" option should also be specified when dropping the
61+
* collection to ensure that internal encryption collections are dropped. */
5962
$encryptedClient->selectDatabase('test')->createCollection('coll', ['encryptedFields' => $encryptedFields]);
6063
$encryptedCollection = $encryptedClient->selectCollection('test', 'coll');
6164

docs/tutorial/encryption.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,13 @@ To reference keys in your application, you can use the ``keyAltName``
115115
attribute specified when creating the key. The following example creates an
116116
encryption key with an alternative name, which could be done when deploying the
117117
application. The script then encrypts data by referencing the key by its
118-
alternative name.
118+
alternative name using the ``keyAltName`` option instead of ``keyId``.
119119

120-
To use an alternate name when referencing an encryption key, use the
121-
``keyAltName`` option instead of ``keyId``.
120+
.. note::
121+
122+
Prior to adding a new key alternate name, you must create a partial, unique
123+
index on the ``keyAltNames`` field. Client-Side Field Level Encryption
124+
depends on server-enforced uniqueness of key alternate names.
122125

123126
.. literalinclude:: /examples/key_alt_name.php
124127
:language: php

tests/ExamplesTest.php

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,17 @@ public function testEncryptionExamples(string $file, string $expectedOutput): vo
201201
{
202202
$this->skipIfClientSideEncryptionIsNotSupported();
203203

204-
$this->assertExampleOutput($file, $expectedOutput);
205-
206-
// Clean up metadata and key vault collections
204+
/* Ensure that the key vault, collection under test, and any metadata
205+
* collections are cleaned up before and after the example is run. */
207206
$this->dropCollection('test', 'coll', ['encryptedFields' => []]);
208207
$this->dropCollection('encryption', '__keyVault');
208+
209+
/* Ensure the key vault has a partial, unique index for keyAltNames. The
210+
* key management examples already do this, so this is mainly for the
211+
* benefit of other scripts. */
212+
$this->setUpKeyVaultIndex();
213+
214+
$this->assertExampleOutput($file, $expectedOutput);
209215
}
210216

211217
public static function provideEncryptionExamples(): Generator
@@ -342,11 +348,15 @@ public function testQueryableEncryptionExamples(string $file, string $expectedOu
342348

343349
$this->skipIfServerVersion('<', '7.0.0', 'Queryable encryption tests require MongoDB 7.0 or later');
344350

345-
$this->assertExampleOutput($file, $expectedOutput);
346-
347-
// Clean up metadata and key vault collections
351+
/* Ensure that the key vault, collection under test, and any metadata
352+
* collections are cleaned up before and after the example is run. */
348353
$this->dropCollection('test', 'coll', ['encryptedFields' => []]);
349354
$this->dropCollection('encryption', '__keyVault');
355+
356+
// Ensure the key vault has a partial, unique index for keyAltNames
357+
$this->setUpKeyVaultIndex();
358+
359+
$this->assertExampleOutput($file, $expectedOutput);
350360
}
351361

352362
public static function provideQueryableEncryptionExamples(): Generator
@@ -452,4 +462,15 @@ private function assertExampleOutput(string $file, string $expectedOutput): void
452462

453463
$this->assertStringMatchesFormat($expectedOutput, $this->getActualOutputForAssertion());
454464
}
465+
466+
private function setUpKeyVaultIndex(): void
467+
{
468+
self::createTestClient()->selectCollection('encryption', '__keyVault')->createIndex(
469+
['keyAltNames' => 1],
470+
[
471+
'unique' => true,
472+
'partialFilterExpression' => ['keyAltNames' => ['$exists' => true]],
473+
]
474+
);
475+
}
455476
}

0 commit comments

Comments
 (0)