Skip to content

Commit 49be637

Browse files
committed
Remove PyMongo's create_encrypted_collection
- `showfieldsmap` needs to be renamed to `createfieldsmap` and we need another management command called `showfieldsmap` to retrieve the keys from the key vault (either from server side or client side generation.) - In order to retrieve keys from the vault they need to have a keyVaultName and PyMongo's `create_data_keys` does not provide this. - If `encrypted_fields_map` is present, use it to create the collection, else create the collection with `create_collection` and our `encrypted_fields_map`. - We may consider requiring users to provide an empty dictionary to initiate server side encryption rather than relying on the absence of `encrypted_fields_map`. PyMongo uses this convention in its KMS code and in this case it emphasizes the need for a map and when and how the map is created.
1 parent 0e6e469 commit 49be637

File tree

2 files changed

+33
-31
lines changed

2 files changed

+33
-31
lines changed

django_mongodb_backend/management/commands/showfieldsmap.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,34 @@ def add_arguments(self, parser):
1919
help="Specify the database to use for generating the encrypted"
2020
"fields map. Defaults to the 'default' database.",
2121
)
22-
parser.add_argument(
23-
"--kms-provider",
24-
default="local",
25-
help="Specify the KMS provider to use for encryption. Defaults to 'local'.",
26-
)
2722

2823
def handle(self, *args, **options):
2924
db = options["database"]
3025
connection = connections[db]
3126
encrypted_fields_map = {}
3227
for app_config in apps.get_app_configs():
3328
for model in app_config.get_models():
29+
db_table = model._meta.db_table
3430
if has_encrypted_fields(model):
3531
fields = connection.schema_editor()._get_encrypted_fields_map(model)
3632
client = connection.connection
37-
options = client._options.auto_encryption_opts
33+
ae = client._options.auto_encryption_opts
3834
ce = ClientEncryption(
39-
options._kms_providers,
40-
options._key_vault_namespace,
35+
ae._kms_providers,
36+
ae._key_vault_namespace,
4137
client,
4238
client.codec_options,
4339
)
4440
kms_provider = router.kms_provider(model)
4541
master_key = connection.settings_dict.get("KMS_CREDENTIALS").get(kms_provider)
4642
for field in fields["fields"]:
43+
key_alt_name = f"{db_table}_{field['path']}"
4744
data_key = ce.create_data_key(
4845
kms_provider=kms_provider,
4946
master_key=master_key,
47+
key_alt_names=[key_alt_name],
5048
)
5149
field["keyId"] = data_key
52-
encrypted_fields_map[model._meta.db_table] = fields
50+
field["keyAltName"] = key_alt_name
51+
encrypted_fields_map[db_table] = fields
5352
self.stdout.write(json_util.dumps(encrypted_fields_map, indent=2))

django_mongodb_backend/schema.py

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -432,33 +432,36 @@ def _create_collection(self, model):
432432
db_table = model._meta.db_table
433433
if has_encrypted_fields(model):
434434
client = self.connection.connection
435-
options = getattr(client._options, "auto_encryption_opts", None)
436-
if options is not None:
437-
if encrypted_fields_map := getattr(options, "_encrypted_fields_map", None):
438-
db.create_collection(db_table, encryptedFields=encrypted_fields_map[db_table])
439-
else:
440-
ce = ClientEncryption(
441-
options._kms_providers,
442-
options._key_vault_namespace,
443-
client,
444-
client.codec_options,
445-
)
446-
encrypted_fields_map = self._get_encrypted_fields_map(model)
447-
provider = router.kms_provider(model)
448-
credentials = self.connection.settings_dict.get("KMS_CREDENTIALS").get(provider)
449-
ce.create_encrypted_collection(
450-
db,
451-
db_table,
452-
encrypted_fields_map,
453-
provider,
454-
credentials,
455-
)
456-
else:
435+
options = client._options
436+
ae = getattr(options, "auto_encryption_opts", None)
437+
if not ae:
457438
raise ImproperlyConfigured(
458439
"Encrypted fields found but the connection does not have "
459440
"auto encryption options set. Please set `auto_encryption_opts` "
460441
"in the connection settings."
461442
)
443+
encrypted_fields_map = getattr(ae, "_encrypted_fields_map", None)
444+
if not encrypted_fields_map:
445+
encrypted_fields_map = {}
446+
ce = ClientEncryption(
447+
ae._kms_providers,
448+
ae._key_vault_namespace,
449+
client,
450+
client.codec_options,
451+
)
452+
fields = self._get_encrypted_fields_map(model)
453+
kms_provider = router.kms_provider(model)
454+
master_key = self.connection.settings_dict.get("KMS_CREDENTIALS").get(kms_provider)
455+
for field in fields["fields"]:
456+
key_alt_name = f"{db_table}_{field['path']}"
457+
data_key = ce.create_data_key(
458+
kms_provider=kms_provider,
459+
master_key=master_key,
460+
key_alt_names=[key_alt_name],
461+
)
462+
field["keyId"] = data_key
463+
encrypted_fields_map[db_table] = fields
464+
db.create_collection(db_table, encryptedFields=encrypted_fields_map[db_table])
462465
else:
463466
db.create_collection(db_table)
464467

0 commit comments

Comments
 (0)