Skip to content

Commit 2f305ca

Browse files
committed
Create QE tutorial in PHP
1 parent eb91fa4 commit 2f305ca

File tree

5 files changed

+366
-0
lines changed

5 files changed

+366
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# MongoDB connection uri and automatic encryption shared library path
2+
3+
MONGODB_URI="<Your MongoDB URI>"
4+
SHARED_LIB_PATH="<Full path to your Automatic Encryption Shared Library>"
5+
6+
# AWS Credentials
7+
8+
AWS_ACCESS_KEY_ID="<Your AWS access key ID>"
9+
AWS_SECRET_ACCESS_KEY="<Your AWS secret access key>"
10+
AWS_KEY_REGION="<Your AWS key region>"
11+
AWS_KEY_ARN="<Your AWS key ARN>"
12+
13+
# Azure Credentials
14+
15+
AZURE_TENANT_ID="<Your Azure tenant ID>"
16+
AZURE_CLIENT_ID="<Your Azure client ID>"
17+
AZURE_CLIENT_SECRET="<Your Azure client secret>"
18+
AZURE_KEY_NAME="<Your Azure key name>"
19+
AZURE_KEY_VERSION="<Your Azure key version>"
20+
AZURE_KEY_VAULT_ENDPOINT="<Your Azure key vault endpoint>"
21+
22+
# GCP Credentials
23+
24+
GCP_EMAIL="<Your GCP email>"
25+
GCP_PRIVATE_KEY="<Your GCP private key>"
26+
27+
GCP_PROJECT_ID="<Your GCP project ID>"
28+
GCP_LOCATION="<Your GCP location>"
29+
GCP_KEY_RING="<Your GCP key ring>"
30+
GCP_KEY_NAME="<Your GCP key name>"
31+
GCP_KEY_VERSION="<Your GCP key version>"
32+
33+
# KMIP Credentials
34+
35+
KMIP_KMS_ENDPOINT="<Endpoint for your KMIP KMS>"
36+
KMIP_TLS_CA_FILE="<Full path to your KMIP certificate authority file>"
37+
KMIP_TLS_CERT_FILE="<Full path to your client certificate file>"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.env
2+
composer.lock
3+
customer-master-key.txt
4+
vendor
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "mongodb/qe-tutorial",
3+
"type": "project",
4+
"require": {
5+
"php": ">=8.1",
6+
"ext-mongodb": "^1.21|^2",
7+
"mongodb/mongodb": "^1.21|^2",
8+
"symfony/dotenv": "^6.4|^7"
9+
}
10+
}
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
<?php
2+
3+
namespace MongoDB\Tutorials\QueryableEncryption;
4+
5+
use InvalidArgumentException;
6+
use MongoDB\Client;
7+
use MongoDB\Driver\ClientEncryption;
8+
use MongoDB\Driver\Exception\Exception;
9+
use RuntimeException;
10+
11+
function dropExistingCollection(Client $client, string $databaseName): void
12+
{
13+
$database = $client->getDatabase($databaseName);
14+
$database->drop();
15+
}
16+
17+
function getKMSProviderCredentials(string $kmsProviderName): array
18+
{
19+
switch ($kmsProviderName) {
20+
case 'aws':
21+
// start-aws-kms-credentials
22+
$kmsProviders = [
23+
'aws' => [
24+
'accessKeyId' => getenv('AWS_ACCESS_KEY_ID'), // Your AWS access key ID
25+
'secretAccessKey' => getenv('AWS_SECRET_ACCESS_KEY'), // Your AWS secret access key
26+
],
27+
];
28+
// end-aws-kms-credentials
29+
return $kmsProviders;
30+
case 'azure':
31+
// start-azure-kms-credentials
32+
$kmsProviders = [
33+
'azure' => [
34+
'tenantId' => getenv('AZURE_TENANT_ID'), // Your Azure tenant ID
35+
'clientId' => getenv('AZURE_CLIENT_ID'), // Your Azure client ID
36+
'clientSecret' => getenv('AZURE_CLIENT_SECRET'), // Your Azure client secret
37+
],
38+
];
39+
// end-azure-kms-credentials
40+
return $kmsProviders;
41+
case 'gcp':
42+
// start-gcp-kms-credentials
43+
$kmsProviders = [
44+
'gcp' => [
45+
'email' => getenv('GCP_EMAIL'), // Your GCP email
46+
'privateKey' => getenv('GCP_PRIVATE_KEY'), // Your GCP private key
47+
],
48+
];
49+
// end-gcp-kms-credentials
50+
return $kmsProviders;
51+
case 'kmip':
52+
// start-kmip-kms-credentials
53+
$kmsProviders = [
54+
'kmip' => [
55+
'endpoint' => getenv('KMIP_ENDPOINT'), // Your KMIP endpoint
56+
],
57+
];
58+
// end-kmip-kms-credentials
59+
return $kmsProviders;
60+
case 'local':
61+
// start-generate-local-key
62+
if (!file_exists('./customer-master-key.txt')) {
63+
file_put_contents('./customer-master-key.txt', base64_encode(random_bytes(96)));
64+
}
65+
// end-generate-local-key
66+
67+
// start-get-local-key
68+
$localMasterKey = file_get_contents('./customer-master-key.txt');
69+
$kmsProviders = [
70+
'local' => [
71+
'key' => $localMasterKey,
72+
],
73+
];
74+
// end-get-local-key
75+
return $kmsProviders;
76+
default:
77+
throw new InvalidArgumentException(sprintf('Unrecognized value for KMS provider name. Must be one of: aws, gcp, azure, kmip, or local. Got "%s".', $kmsProviderName));
78+
}
79+
}
80+
81+
function getCustomerMasterKeyCredentials(string $kmsProviderName): array
82+
{
83+
switch ($kmsProviderName) {
84+
case 'aws':
85+
// start-aws-cmk-credentials
86+
$customerMasterKeyCredentials = [
87+
'key' => getenv('AWS_KEY_ARN'), // Your AWS key ID
88+
'region' => getenv('AWS_REGION'), // Your AWS region
89+
];
90+
// end-aws-cmk-credentials
91+
return $customerMasterKeyCredentials;
92+
case "azure":
93+
// start-azure-cmk-credentials
94+
$customerMasterKeyCredentials = [
95+
'keyVaultEndpoint' => getenv('AZURE_KEY_VAULT_ENDPOINT'), // Your Azure Key Vault Endpoint
96+
'keyName' => getenv('AZURE_KEY_NAME'), // Your Azure Key Name
97+
];
98+
// end-azure-cmk-credentials
99+
return $customerMasterKeyCredentials;
100+
case "gcp":
101+
// start-gcp-cmk-credentials
102+
$customerMasterKeyCredentials = [
103+
'projectId' => getenv('GCP_PROJECT_ID'), // Your GCP Project ID
104+
'location' => getenv('GCP_LOCATION'), // Your GCP Key Location
105+
'keyRing' => getenv('GCP_KEY_RING'), // Your GCP Key Ring
106+
'keyName' => getenv('GCP_KEY_NAME'), // Your GCP Key Name
107+
];
108+
// end-gcp-cmk-credentials
109+
return $customerMasterKeyCredentials;
110+
case "kmip":
111+
case "local":
112+
// start-kmip-local-cmk-credentials
113+
$customerMasterKeyCredentials = [];
114+
// end-kmip-local-cmk-credentials
115+
return $customerMasterKeyCredentials;
116+
default:
117+
throw new InvalidArgumentException(sprintf('Unrecognized value for KMS provider name. Must be one of: aws, gcp, azure, kmip, or local. Got "%s".', $kmsProviderName));
118+
}
119+
}
120+
121+
function getAutoEncryptionOptions(
122+
string $kmsProviderName,
123+
string $keyVaultNamespace,
124+
array $kmsProviders,
125+
): array
126+
{
127+
if ($kmsProviderName === 'kmip') {
128+
$tlsOptions = getKmipTlsOptions();
129+
130+
// start-kmip-encryption-options
131+
$sharedLibraryPathOptions = [
132+
'cryptSharedLibPath' => getenv('SHARED_LIB_PATH'), // Path to your Automatic Encryption Shared Library
133+
];
134+
135+
$autoEncryptionOptions = [
136+
'keyVaultNamespace' => $keyVaultNamespace,
137+
'kmsProviders' => $kmsProviders,
138+
'sharedLibraryPathOptions' => $sharedLibraryPathOptions,
139+
'tlsOptions' => $tlsOptions,
140+
];
141+
// end-kmip-encryption-options
142+
return $autoEncryptionOptions;
143+
} else {
144+
// start-auto-encryption-options
145+
$sharedLibraryPathOptions = [
146+
'cryptSharedLibPath' => getenv('SHARED_LIB_PATH'), // Path to your Automatic Encryption Shared Library
147+
];
148+
149+
$autoEncryptionOptions = [
150+
'keyVaultNamespace' => $keyVaultNamespace,
151+
'kmsProviders' => $kmsProviders,
152+
'sharedLibraryPathOptions' => $sharedLibraryPathOptions,
153+
];
154+
// end-auto-encryption-options
155+
156+
return $autoEncryptionOptions;
157+
}
158+
}
159+
160+
function getKmipTlsOptions(): array
161+
{
162+
// start-tls-options
163+
$tlsOptions = [
164+
'kmip' => [
165+
'tlsCAFile' => getenv('KMIP_TLS_CA_FILE'), // Path to your TLS CA file
166+
'tlsCertificateKeyFile' => getenv('KMIP_TLS_CERT_FILE'), // Path to your TLS certificate key file
167+
],
168+
];
169+
// end-tls-options
170+
return $tlsOptions;
171+
}
172+
173+
function getClientEncryption(Client $encryptedClient, array $autoEncryptionOptions): ClientEncryption
174+
{
175+
// start-create-client-encryption
176+
$clientEncryption = $encryptedClient->createClientEncryption($autoEncryptionOptions);
177+
// end-create-client-encryption
178+
179+
return $clientEncryption;
180+
}
181+
182+
function createEncryptedCollection(
183+
Client $client,
184+
ClientEncryption $clientEncryption,
185+
string $encryptedDatabase,
186+
string $encryptedCollectionName,
187+
string $kmsProviderName,
188+
array $encryptedFieldsMap,
189+
?array $customerMasterKeyCredentials,
190+
): void
191+
{
192+
try {
193+
// start-create-encrypted-collection
194+
$client->getDatabase($encryptedDatabase)->createEncryptedCollection(
195+
$encryptedCollectionName,
196+
$clientEncryption,
197+
$kmsProviderName,
198+
$customerMasterKeyCredentials,
199+
$encryptedFieldsMap,
200+
);
201+
// end-create-encrypted-collection
202+
} catch (Exception $e) {
203+
throw new RuntimeException(sprintf('Unable to create encrypted collection: %s', $e->getMessage()), 0, $e);
204+
}
205+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?php
2+
3+
namespace MongoDB\Tutorials\QueryableEncryption;
4+
5+
use MongoDB\Exception\RuntimeException;
6+
use Symfony\Component\Dotenv\Dotenv;
7+
8+
require __DIR__.'/vendor/autoload.php';
9+
require __DIR__.'/queryable-encryption-helpers.php';
10+
11+
(new Dotenv())->usePutenv()->loadEnv(__DIR__.'/.env');
12+
13+
// start-setup-application-variables
14+
// KMS provider name should be one of the following: "aws", "gcp", "azure", "kmip" or "local"
15+
$kmsProviderName = '<KMS provider name>';
16+
17+
$uri = getenv('MONGODB_URI'); // Your connection URI
18+
19+
$keyVaultDatabaseName = 'encryption';
20+
$keyVaultCollectionName = '__keyVault';
21+
$keyVaultNamespace = $keyVaultDatabaseName . '.' . $keyVaultCollectionName;
22+
$encryptedDatabaseName = 'medicalRecords';
23+
$encryptedCollectionName = 'patients';
24+
// end-setup-application-variables
25+
26+
// Override the KMS provider name with the environment variable if set
27+
$kmsProviderName = getenv('KMS_PROVIDER') ?: throw new RuntimeException('Variable KMS_PROVIDER not set.');
28+
29+
$kmsProviderCredentials = getKMSProviderCredentials($kmsProviderName);
30+
$customerMasterKeyCredentials = getCustomerMasterKeyCredentials($kmsProviderName);
31+
32+
$autoEncryptionOptions = getAutoEncryptionOptions(
33+
$kmsProviderName,
34+
$keyVaultNamespace,
35+
$kmsProviderCredentials
36+
);
37+
38+
// start-create-client
39+
$encryptedClient = new \MongoDB\Client($uri, [], [
40+
'autoEncryption' => $autoEncryptionOptions,
41+
]);
42+
// end-create-client
43+
44+
dropExistingCollection($encryptedClient, $encryptedDatabaseName);
45+
dropExistingCollection($encryptedClient, $keyVaultDatabaseName);
46+
47+
// start-encrypted-fields-map
48+
$encryptedFieldsMap = [
49+
'encryptedFields' => [
50+
'fields' => [
51+
[
52+
'path' => 'patientRecord.ssn',
53+
'bsonType' => 'string',
54+
'queries' => ['queryType' => 'equality'],
55+
],
56+
[
57+
'path' => 'patientRecord.billing',
58+
'bsonType' => 'object',
59+
],
60+
],
61+
],
62+
];
63+
// end-encrypted-fields-map
64+
65+
$clientEncryption = getClientEncryption(
66+
$encryptedClient,
67+
$autoEncryptionOptions
68+
);
69+
70+
createEncryptedCollection(
71+
$encryptedClient,
72+
$clientEncryption,
73+
$encryptedDatabaseName,
74+
$encryptedCollectionName,
75+
$kmsProviderName,
76+
$encryptedFieldsMap,
77+
$customerMasterKeyCredentials
78+
);
79+
80+
// start-insert-document
81+
$patientDocument = [
82+
'patientName' => 'Jon Doe',
83+
'patientId' => 12345678,
84+
'patientRecord' => [
85+
'ssn' => '987-65-4320',
86+
'billing' => [
87+
'type' => 'Visa',
88+
'number' => '4111111111111111',
89+
],
90+
],
91+
];
92+
93+
$encryptedCollection = $encryptedClient
94+
->getDatabase($encryptedDatabaseName)
95+
->getCollection($encryptedCollectionName);
96+
97+
$result = $encryptedCollection->insertOne($patientDocument);
98+
// end-insert-document
99+
100+
if ($result->isAcknowledged()) {
101+
echo "Successfully inserted the patient document.\n";
102+
}
103+
104+
// start-find-document
105+
$findResult = $encryptedCollection->findOne([
106+
'patientRecord.ssn' => '987-65-4320',
107+
]);
108+
109+
print_r($findResult);
110+
// end-find-document

0 commit comments

Comments
 (0)