Overview
In this tutorial, you can learn how to use Queryable Encryption (QE) in a Django application.
MongoDB's Queryable Encryption feature helps protect sensitive data by automatically encrypting it while still allowing your application to interact with the encrypted data. In this tutorial, you can learn how to use Queryable Encryption with Django MongoDB Backend by enabling encryption in your application settings and choosing model fields to encrypt.
Prerequisites
Before you begin this tutorial, complete the following prerequisite tasks:
Create a MongoDB Atlas account and configure a cluster. Ensure that your cluster runs on MongoDB Server version 7.0 or later. To learn more, see the MongoDB Get Started guide.
Download the Automatic Encryption Shared Library. To view instructions, see the Install and Configure a Query Analysis Component guide. These instructions show how to navigate to the MongoDB Download Center and fill out the form required to download the library.
Install Python 3.10 or later.
Tutorial
In this tutorial, you create a Queryable Encryption application that uses Django MongoDB Backend. The application handles medical records securely: it encrypts, decrypts, and queries sensitive medical information.
Tip
Complete Application
To view the complete sample application for this tutorial, see the django_qe folder on GitHub.
Set Up Your Project
Follow the steps in this section to install the project dependencies, configure your environment, and create the application structure.
Install Django MongoDB Backend with the QE dependencies.
Select the tab corresponding to your operating system and run the following commands to activate a virtual environment, install Django MongoDB Backend, and install the Queryable Encryption dependencies:
python -m venv venv source venv/bin/activate pip install 'django-mongodb-backend[encryption]'
python -m venv venv . venv\Scripts\activate pip install 'django-mongodb-backend[encryption]'
The pip install 'django-mongodb-backend[encryption]' command
installs Django MongoDB Backend, the latest PyMongo version, and the
required Python dependencies.
Note
Available in v6.0.1
Queryable Encryption requires Django MongoDB Backend v6.0.1 or later. The preceding command installs the required version.
Create your project directory.
From your shell, run the following command to create a
new Django project called django_qe based on a custom template:
django-admin startproject django_qe --template https://github.com/mongodb-labs/django-mongodb-project/archive/refs/heads/6.0.x.zip
This command creates a django_qe project directory and adds the
initial file scaffolding.
Create your application files.
From your django_qe directory, run the following command to create an
application called medical_records:
python manage.py startapp medical_records
This command creates a medical_records application directory in
your project and adds default app files, including files for your
models and settings.
Include your app in your project.
Navigate to the settings.py file in your django_qe directory
and edit your INSTALLED_APPS setting to resemble the following code:
INSTALLED_APPS = [ 'medical_records.apps.MedicalRecordsConfig', 'django_qe.apps.MongoAdminConfig', 'django_qe.apps.MongoAuthConfig', 'django_qe.apps.MongoContentTypesConfig', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django_mongodb_backend', ]
This setting ensures that your medical_records app is enabled
in your project.
Connect and Enable Encryption
After setting up your project, follow the steps in this section to connect to MongoDB and create models that store encrypted data.
Connect to MongoDB.
In your django_qe directory, navigate to the settings.py
file. Replace the DATABASES setting with the following code:
DATABASES = { 'default': { 'ENGINE': 'django_mongodb_backend', 'HOST': '<connection string>', 'NAME': 'db', }, }
Replace the <connection string> placeholder with the connection string that
connects to your cluster.
This code configures your Django application to connect to MongoDB
and access a database named db by default. This configuration applies
to your non-encrypted models.
Configure Queryable Encryption.
In your settings.py file, you can specify the encrypted key in
your DATABASES setting to enable Queryable Encryption and set your Key Management System
(KMS) provider. Django MongoDB Backend supports the AWS, Azure, GCP, KMIP, and local KMS
providers.
Warning
Local CMK Storage
If you store your Customer Master Key (CMK) locally, do not use this application in production. Without a remote KMS, you risk unauthorized access to the encryption key or loss of the key needed to decrypt your data.
Select the tab corresponding to your KMS and modify your DATABASES setting to resemble
the following example:
DATABASES = { 'default': { # ... Your default configuration }, 'encrypted': { 'ENGINE': 'django_mongodb_backend', 'HOST': '<connection string>', 'NAME': 'medical_records', # ... 'OPTIONS': { 'auto_encryption_opts': AutoEncryptionOpts( key_vault_namespace='medical_records.__keyVault', kms_providers={ 'local': { # Generated by os.urandom(96) 'key': ( b'-\xc3\x0c\xe3\x93\xc3\x8b\xc0\xf8\x12\xc5#b' b'\x19\xf3\xbc\xccR\xc8\xedI\xda\\ \xfb\x9cB' b'\x7f\xab5\xe7\xb5\xc9x\xb8\xd4d\xba\xdc\x9c' b'\x9a\xdb9J]\xe6\xce\x104p\x079q.=\xeb\x9dK*' b'\x97\xea\xf8\x1e\xc3\xd49K\x18\x81\xc3\x1a"' b'\xdc\x00U\xc4u"X\xe7xy\xa5\xb2\x0e\xbc\xd6+-' b'\x80\x03\xef\xc2\xc4\x9bU' ) }, }, crypt_shared_lib_path='<Automatic Encryption Shared Library path>', crypt_shared_lib_required=True, ) }, }, }
Replace the following placeholder values:
<connection string>: The same connection string you specified in thedefaultkey<Automatic Encryption Shared Library path>: The full path to your Automatic Encryption Shared Library
DATABASES = { 'default': { # ... Your default configuration }, 'encrypted': { 'ENGINE': 'django_mongodb_backend', 'HOST': '<connection string>', 'NAME': 'medical_records', # ... 'OPTIONS': { 'auto_encryption_opts': AutoEncryptionOpts( key_vault_namespace='medical_records.__keyVault', kms_providers={ 'aws': { 'accessKeyId': '<AWS Access Key ID>', 'secretAccessKey': '<AWS Secret Access Key>', }, }, crypt_shared_lib_path='<Automatic Encryption Shared Library path>', crypt_shared_lib_required=True, ) }, 'KMS_CREDENTIALS': { 'aws': { 'key': '<AWS Key ARN>', 'region': '<AWS Key Region>', }, }, }, }
Replace the following placeholder values:
<connection string>: The same connection string you specified in thedefaultkey<AWS Access Key ID>: Your AWS access key ID<AWS Secret Access Key>: Your AWS secret access key<Automatic Encryption Shared Library path>: The full path to your Automatic Encryption Shared Library<AWS Key ARN>: The Amazon Resource Name to the AWS customer.<AWS Key Region>: Your AWS region, such as'us-east-1'
DATABASES = { 'default': { # ... Your default configuration }, 'encrypted': { 'ENGINE': 'django_mongodb_backend', 'HOST': '<connection string>', 'NAME': 'medical_records', # ... 'OPTIONS': { 'auto_encryption_opts': AutoEncryptionOpts( key_vault_namespace='medical_records.__keyVault', kms_providers={ 'azure': { 'tenantId': '<Azure Tenant ID>', 'clientId': '<Azure Client ID>', 'clientSecret': '<Azure Client Secret>', }, }, crypt_shared_lib_path='<Automatic Encryption Shared Library path>', crypt_shared_lib_required=True, ) }, 'KMS_CREDENTIALS': { 'azure': { 'keyVaultEndpoint': '<Azure Key Vault Endpoint>', 'keyName': '<Azure Key Name>', # Optional: 'keyVersion': '<Azure Key Version>', }, }, }, }
Replace the following placeholder values:
<connection string>: The same connection string you specified in thedefaultkey<Azure Tenant ID>: Your Azure Active Directory tenant ID<Azure Client ID>: Your Azure application client ID<Azure Client Secret>: Your Azure application client secret<Automatic Encryption Shared Library path>: The full path to your Automatic Encryption Shared Library<Azure Key Vault Endpoint>: Your Azure Key Vault endpoint URL.<Azure Key Name>: The name of your key in Azure Key Vault<Azure Key Version>: (Optional) The version of the key to use
DATABASES = { 'default': { # ... Your default configuration }, 'encrypted': { 'ENGINE': 'django_mongodb_backend', 'HOST': '<connection string>', 'NAME': 'medical_records', # ... 'OPTIONS': { 'auto_encryption_opts': AutoEncryptionOpts( key_vault_namespace='medical_records.__keyVault', kms_providers={ 'gcp': { 'email': '<GCP Service Account Email>', 'privateKey': '<GCP Service Account Private Key>', }, }, crypt_shared_lib_path='<Automatic Encryption Shared Library path>', crypt_shared_lib_required=True, ) }, 'KMS_CREDENTIALS': { 'gcp': { 'projectId': '<GCP Project ID>', 'location': '<GCP Key Ring Location>', 'keyRing': '<GCP Key Ring Name>', 'keyName': '<GCP Key Name>', }, }, }, }
Replace the following placeholder values:
<connection string>: The same connection string you specified in thedefaultkey<GCP Service Account Email>: Your Google Cloud service account email<GCP Service Account Private Key>: Your Google Cloud service account private key<Automatic Encryption Shared Library path>: The full path to your Automatic Encryption Shared Library<GCP Project ID>: Your Google Cloud project ID<GCP Key Ring Location>: The location of your key ring, such as'global'<GCP Key Ring Name>: The name of your key ring<GCP Key Name>: The name of your key
DATABASES = { 'default': { # ... Your default configuration }, 'encrypted': { 'ENGINE': 'django_mongodb_backend', 'HOST': '<connection string>', 'NAME': 'medical_records', # ... 'OPTIONS': { 'auto_encryption_opts': AutoEncryptionOpts( key_vault_namespace='medical_records.__keyVault', kms_providers={ 'kmip': { 'endpoint': '<KMIP Server Endpoint>', }, }, crypt_shared_lib_path='<Automatic Encryption Shared Library path>', crypt_shared_lib_required=True, ) }, 'KMS_CREDENTIALS': { 'kmip': { # Optional: 'keyId': '<KMIP Key Identifier>', }, }, }, }
Replace the following placeholder values:
<connection string>: The same connection string you specified in thedefaultkey.<KMIP Server Endpoint>: Your KMIP server endpoint with its port, such as'example.com:443'.<Automatic Encryption Shared Library path>: The full path to your Automatic Encryption Shared Library.<KMIP Key Identifier>: (Optional) The KMIP Unique Identifier to a 96-byte KMIP Secret Data managed object. If you omit this value, Django MongoDB Backend creates a random 96-byte object.
This code connects to the encrypted medical_records database,
stores your data keys in the medical_records.__keyVault collection, and
configures your KMS provider.
Route operations to the encrypted database.
In your medical_records directory, create a file named routers.py
and paste the following code into it:
class EncryptedRouter: def allow_migrate(self, db, app_label, model_name=None, **hints): # Create medical_records models only in the encrypted database. if app_label == "medical_records": return db == "encrypted" # Don't create collections for other apps in the encrypted db. if db == "encrypted": return False return None def db_for_read(self, model, **hints): # All reads and writes for medical_records models go to the encrypted db. if model._meta.app_label == "medical_records": return "encrypted" return None db_for_write = db_for_read
This file routes database operations on all models in your
medical_records application to the encrypted medical_records
database.
Then, add your custom router by navigating to your settings.py file
and replacing the DATABASE_ROUTERS setting with the following code:
DATABASE_ROUTERS = [ 'django_mongodb_backend.routers.MongoRouter', 'medical_records.routers.EncryptedRouter', ]
Create models that store encrypted fields.
In your medical_records directory, navigate to the models.py
file and paste the following code:
from django.db import models from django_mongodb_backend.models import EmbeddedModel from django_mongodb_backend.fields import ( EmbeddedModelField, EncryptedCharField, EncryptedEmbeddedModelField, ) class Patient(models.Model): patient_name = models.CharField(max_length=255) patient_id = models.BigIntegerField() patient_record = EmbeddedModelField("PatientRecord") class Meta: db_table = "patients" def __str__(self): return f"{self.patient_name} ({self.patient_id})" class PatientRecord(EmbeddedModel): ssn = EncryptedCharField(max_length=11, queries={"queryType": "equality"}) billing = EncryptedEmbeddedModelField("Billing") bill_amount = models.DecimalField(max_digits=10, decimal_places=2) class Billing(EmbeddedModel): cc_type = models.CharField(max_length=50) cc_number = models.CharField(max_length=20)
This code creates a Patient model, which corresponds to
the patients collection in your medical_records database.
It also creates two embedded models, PatientRecord and
Billing, to represent nested fields in the collection.
The code configures the following encrypted fields:
patient_record.ssn: Encrypted and configured for equality queriespatient_record.billing.cc_type: Encrypted, but not queryablepatient_record.billing.cc_number: Encrypted, but not queryable
Perform Encrypted Operations
After configuring your application and database connection, follow the steps in this section to insert and query encrypted documents.
Insert encrypted data.
From your shell, run the following commands to create a Patient
instance and insert a corresponding encrypted document into the
database:
billing = Billing(cc_type="Visa", cc_number="4111111111111111") record = PatientRecord(ssn="987-65-4320", billing=billing, bill_amount=1500) patient = Patient.objects.create( name="John Doe", patient_id=12345678, patient_record=record )
If you navigate to your medical_records.patients collection on MongoDB Atlas, you can see that the document's
patient_record.ssn and patient_record.billing fields are encrypted.
Next Steps
Congratulations on completing the Queryable Encryption tutorial! You now have a sample Django application that uses Queryable Encryption to automatically encrypt and decrypt document fields. Your application encrypts sensitive data on the server side and queries the data on the client side.
To learn more about Queryable Encryption and Django MongoDB Backend, visit the following resources:
View more driver Queryable Encryption tutorials in the MongoDB Server manual.
Learn more about Queryable Encryption with Django MongoDB Backend in the API documentation