Navigation

Manage Client-Side Encryption Data Keys

beta

Client-Side Field Level Encryption is available as a beta. The contents of this page may change during the beta period.

New in version 4.2.

Client-side field level encryption uses data keys for encryption and decryption. The mongo shell getKeyVault() method returns a key vault object for creating, modifying, and deleting data keys.

This page documents client-side field level encryption using the mongo shell, and does not refer to any official MongoDB 4.2-compatible driver. See the relevant documentation for driver-specific data key management methods and syntax.

Create a Data Key

The following procedure uses the mongo shell to create a data key for use with client-side field level encryption and decryption. For guidance on data key management using a 4.2-compatible driver, see the documentation for that driver.

1

Create the database connection.

Client-side field level encryption requires a Key Management Service (KMS). Each tab corresponds to a supported KMS and contains instructions specific to that KMS.

Configuring client-side field level encryption for the AWS KMS requires an AWS Access Key ID and its associated Secret Access Key. The AWS Access Key must correspond to an IAM user with all List and Read permissions for the KMS service. To mitigate the risk of the AWS Access Key ID or Secret leaking into logs, this procedure passes those values into the shell using environment variables.

Create a mongo shell session using the --eval, --shell, and --nodb options:

mongo --eval "
    var AWS_ACCESS_KEY_ID = '$AWS_ACCESS_KEY_ID'
    var AWS_SECRET_ACCESS_KEY = '$AWS_SECRET_ACCESS_KEY'
  " \
  --shell --nodb

The example automatically opens a mongo shell without a connection to a MongoDB database. The --eval option set the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY variables in the shell to the value of the corresponding environment variable. The specified variables are also supported by the AWS CLI.

Create a new variable for storing the client-side field level encryption configuration document:

var ClientSideFieldLevelEncryptionOptions = {
  "keyVaultNamespace" : "encryption.__dataKeys",
  "kmsProviders" : {
    "aws" : {
      "accessKeyId" : AWS_ACCESS_KEY_ID,
      "secretAccessKey" : AWS_SECRET_ACCESS_KEY
    }
  }
}

Configuring client-side field level encryption for a locally managed key requires specifying a base64-encoded 96-byte string with no line breaks. To mitigate the risk of the key leaking into logs, this procedure passes the value into the mongo shell using an environment variable.

The following operation generates a key that meets the stated requirements and adds it to the users ~/.profile. If the key DEV_LOCAL_KEY already exists, skip this operation.

echo "export DEV_LOCAL_KEY=\"$(head -c 96 /dev/urandom | base64 | tr -d '\n')\"" >> ~/.profile

The host operating system may require logging out and in to refresh the loaded environment variables. Alternatively, use source ~/.profile to manually refresh the shell.

Note

The host operating system or shell may have different procedures for setting persistent environment variables. Defer to the documentation for the host OS or shell for a more specific procedure.

Create a mongo shell session using the --eval, --shell and --nodb options.

mongo --eval "var LOCAL_KEY = '$DEV_LOCAL_KEY' " \
  --shell --nodb

The example automatically opens a mongo shell without a connection to a MongoDB database. The --eval option set the LOCAL_KEY variable in the mongo shell to the value of the corresponding environment variable.

Create a new variable in the mongo shell for storing the client-side field level encryption configuration document:

var ClientSideFieldLevelEncryptionOptions = {
  "keyVaultNamespace" : "encryption.__dataKeys",
  "kmsProviders" : {
    "local" : {
      "key" : BinData(0, LOCAL_KEY)
    }
  }
}

Use the Mongo() constructor in the mongo shell to establish a database connection to the target cluster. Configure the connection for client-side field level encryption by specifying the ClientSideFieldLevelEncryption document as the second parameter:

csfleDatabaseConnection = Mongo(
  "mongodb://replaceMe.example.net:27017/?replicaSet=myMongoCluster",
  ClientSideFieldLevelEncryptionOptions
)

Replace the replaceMe.example.net URI with the connection string for the target cluster.

Use the csfleDatabaseConnection object to access client-side field level encryption shell methods.

For complete documentation on establishing database connections configured for client-side field level encryption, see the Mongo() constructor reference.

2

Create the key vault object.

Use the getKeyVault() method on the csfleDatabaseConnection database connection object to create the key vault object:

keyVault = csfleDatabaseConnection.getKeyVault();

Important

Client-side field level encryption depends on server-enforced uniqueness of key alternate names. getKeyVault() creates a unique index on keyAltNames if one does not exist. Do not drop the unique index created by getKeyVault().

3

Create the data key.

Use the KeyVault.createKey() method on the keyVault object to create a new data key in the key vault.

 keyVault.createKey(
   "aws",
   "arn:aws:kms:region:account:key/keystring",
   [ "keyAlternateName" ]
)

The first parameter must be "aws" to specify the configured Amazon Web Services KMS.

The second parameter must be the full Amazon Resource Name (ARN) of the Customer Master Key (CMK). MongoDB uses the specified CMK to encrypt the data key.

 keyVault.createKey(
   "local",
   "",
   [ "myFirstCSFLEDataKey" ]
)

The first parameter must be local to specify the configured Locally Managed Key.

The second parameter must be an empty string. MongoDB does not use the value specified for this parameter.

The third parameter may be an array of one or more keyAltNames for the data key. Each key alternate name must be unique. getKeyVault() creates a unique index on keyAltNames to enforce uniqueness on the field if one does not already exist. Key alternate names facilitate data key findability.

4

Retrieve the created data key.

Use the KeyVault.getKeyByAltName() method on the keyVault object to retrieve the created data key by its alternate name.

keyVault.getKeyByAltName("myFirstCSFLEDataKey")

The method returns output similar to the following:

{
    "_id" : UUID("b4b41b33-5c97-412e-a02b-743498346079"),
    "keyMaterial" : BinData(0,"PXRsLOAYxhzTS/mFQAI8486da7BwZgqA91UI7NKz/T/AjB0uJZxTvhvmQQsKbCJYsWVS/cp5Rqy/FUX2zZwxJOJmI3rosPhzV0OI5y1cuXhAlLWlj03CnTcOSRzE/YIrsCjMB0/NyiZ7MRWUYzLAEQnE30d947XCiiHIb8a0kt2SD0so8vZvSuP2n0Vtz4NYqnzF0CkhZSWFa2e2yA=="),
    "creationDate" : ISODate("2019-08-12T21:21:30.569Z"),
    "updateDate" : ISODate("2019-08-12T21:21:30.569Z"),
    "status" : 0,
    "version" : NumberLong(0),
    "masterKey" : {
        "provider" : "local"
    },
    "keyAltNames" : [
        "myFirstCSFLEDataKey"
    ]
}

The UUID is a BSON Binary (BinData) object with subtype 4 that uniquely identifies the data key. The UUID string is the hex representation of the underlying data.

Configuring official 4.2-compatible drivers for automatic client-side field level encryption requires specifying the data key _id using its base64 representation. The following operation converts a UUID from hex to base64:

keyVault.getKeyByAltName("myFirstCSFLEDataKey").next()._id.base64()

For a key created without an alternate name, issue the KeyVault.getKeys() method with the sort() modifier to sort on creationDate descending:

keyVault.getKeys().sort({"creationDate" : -1})

The operation returns all data keys starting from the most recently inserted data key.

Manage a Data Key’s Alternate Name

The following procedure uses the mongo shell to manage the alternate names of a data key. For guidance on data key management using a 4.2-compatible driver, see the documentation for that driver.

1

Create the database connection.

Client-side field level encryption requires a Key Management Service (KMS). Each tab corresponds to a supported KMS and contains instructions specific to that KMS.

Configuring client-side field level encryption for the AWS KMS requires an AWS Access Key ID and its associated Secret Access Key. The AWS Access Key must correspond to an IAM user with all List and Read permissions for the KMS service. To mitigate the risk of the AWS Access Key ID or Secret leaking into logs, this procedure passes those values into the shell using environment variables.

Create a mongo shell session using the --eval, --shell, and --nodb options:

mongo --eval "
    var AWS_ACCESS_KEY_ID = '$AWS_ACCESS_KEY_ID'
    var AWS_SECRET_ACCESS_KEY = '$AWS_SECRET_ACCESS_KEY'
  " \
  --shell --nodb

The example automatically opens a mongo shell without a connection to a MongoDB database. The --eval option set the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY variables in the shell to the value of the corresponding environment variable. The specified variables are also supported by the AWS CLI.

Create a new variable for storing the client-side field level encryption configuration document:

var ClientSideFieldLevelEncryptionOptions = {
  "keyVaultNamespace" : "encryption.__dataKeys",
  "kmsProviders" : {
    "aws" : {
      "accessKeyId" : AWS_ACCESS_KEY_ID,
      "secretAccessKey" : AWS_SECRET_ACCESS_KEY
    }
  }
}

Configuring client-side field level encryption for a locally managed key requires specifying a base64-encoded 96-byte string with no line breaks. To mitigate the risk of the key leaking into logs, this procedure passes the value into the mongo shell using an environment variable.

The following operation generates a key that meets the stated requirements and adds it to the users ~/.profile. If the key DEV_LOCAL_KEY already exists, skip this operation.

echo "export DEV_LOCAL_KEY=\"$(head -c 96 /dev/urandom | base64 | tr -d '\n')\"" >> ~/.profile

The host operating system may require logging out and in to refresh the loaded environment variables. Alternatively, use source ~/.profile to manually refresh the shell.

Note

The host operating system or shell may have different procedures for setting persistent environment variables. Defer to the documentation for the host OS or shell for a more specific procedure.

Create a mongo shell session using the --eval, --shell and --nodb options.

mongo --eval "var LOCAL_KEY = '$DEV_LOCAL_KEY' " \
  --shell --nodb

The example automatically opens a mongo shell without a connection to a MongoDB database. The --eval option set the LOCAL_KEY variable in the mongo shell to the value of the corresponding environment variable.

Create a new variable in the mongo shell for storing the client-side field level encryption configuration document:

var ClientSideFieldLevelEncryptionOptions = {
  "keyVaultNamespace" : "encryption.__dataKeys",
  "kmsProviders" : {
    "local" : {
      "key" : BinData(0, LOCAL_KEY)
    }
  }
}

Use the Mongo() constructor in the mongo shell to establish a database connection to the target cluster. Configure the connection for client-side field level encryption by specifying the ClientSideFieldLevelEncryption document as the second parameter:

csfleDatabaseConnection = Mongo(
  "mongodb://replaceMe.example.net:27017/?replicaSet=myMongoCluster",
  ClientSideFieldLevelEncryptionOptions
)

Replace the replaceMe.example.net URI with the connection string for the target cluster.

Use the csfleDatabaseConnection object to access client-side field level encryption shell methods.

For complete documentation on establishing database connections configured for client-side field level encryption, see the Mongo() constructor reference.

2

Create the key vault object.

Use the getKeyVault() method on the csfleDatabaseConnection database connection object to create the key vault object:

keyVault = csfleDatabaseConnection.getKeyVault();

Important

Client-side field level encryption depends on server-enforced uniqueness of key alternate names. getKeyVault() creates a unique index on keyAltNames if one does not exist. Do not drop the unique index created by getKeyVault().

3

Manage the data key’s alternate name.

Add Key Alternate Name

Important

Client-side field level encryption depends on server-enforced uniqueness of key alternate names. Validate that a unique index exists on keyAltNames prior to adding a new key alternate name. If the unique index was dropped, you must re-create it prior to adding any key alternate names.

Use the KeyVault.addKeyAlternateName() to add a new alternate name to a data key:

keyVault.addKeyAlternateName(
  UUID("<Replace Me With The UUID Of The Key To Modify"),
  "NewKeyAltNameForMyFirstCSFLEDataKey"
)

The first parameter must be the UUID of the data key to modify.

The second parameter must be a unique string. getKeyVault() creates a unique index on keyAltNames to enforce uniqueness of key alternate names.

KeyVault.addKeyAlternateName() returns the data key document prior to modification. Use KeyVault.getKey() to retrive the modified data key.

Remove Key Alternate Name

Use the KeyVault.removeKeyAlternateName() to remove a key alternate name from a data key:

keyVault.removeKeyAlternateName(
  UUID("<Replace Me With The UUID Of The Key To Modify"),
  "NewKeyAltNameForMyFirstCSFLEDataKey"
)

The first parameter must be the UUID of the data key to modify.

The second parameter must be a string key alternate name.

KeyVault.removeKeyAlternateName() returns the data key prior to modification. Use KeyVault.getKey() to retrieve the modified data key.

Remove a Data Key

Warning

Deleting a data key renders all fields encrypted using that key as permanently unreadable.

The following procedure uses the mongo shell to remove a data key from the key vault. For guidance on data key management using a 4.2-compatible driver, see the documentation for that driver.

1

Create the database connection.

Client-side field level encryption requires a Key Management Service (KMS). Each tab corresponds to a supported KMS and contains instructions specific to that KMS.

Configuring client-side field level encryption for the AWS KMS requires an AWS Access Key ID and its associated Secret Access Key. The AWS Access Key must correspond to an IAM user with all List and Read permissions for the KMS service. To mitigate the risk of the AWS Access Key ID or Secret leaking into logs, this procedure passes those values into the shell using environment variables.

Create a mongo shell session using the --eval, --shell, and --nodb options:

mongo --eval "
    var AWS_ACCESS_KEY_ID = '$AWS_ACCESS_KEY_ID'
    var AWS_SECRET_ACCESS_KEY = '$AWS_SECRET_ACCESS_KEY'
  " \
  --shell --nodb

The example automatically opens a mongo shell without a connection to a MongoDB database. The --eval option set the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY variables in the shell to the value of the corresponding environment variable. The specified variables are also supported by the AWS CLI.

Create a new variable for storing the client-side field level encryption configuration document:

var ClientSideFieldLevelEncryptionOptions = {
  "keyVaultNamespace" : "encryption.__dataKeys",
  "kmsProviders" : {
    "aws" : {
      "accessKeyId" : AWS_ACCESS_KEY_ID,
      "secretAccessKey" : AWS_SECRET_ACCESS_KEY
    }
  }
}

Configuring client-side field level encryption for a locally managed key requires specifying a base64-encoded 96-byte string with no line breaks. To mitigate the risk of the key leaking into logs, this procedure passes the value into the mongo shell using an environment variable.

The following operation generates a key that meets the stated requirements and adds it to the users ~/.profile. If the key DEV_LOCAL_KEY already exists, skip this operation.

echo "export DEV_LOCAL_KEY=\"$(head -c 96 /dev/urandom | base64 | tr -d '\n')\"" >> ~/.profile

The host operating system may require logging out and in to refresh the loaded environment variables. Alternatively, use source ~/.profile to manually refresh the shell.

Note

The host operating system or shell may have different procedures for setting persistent environment variables. Defer to the documentation for the host OS or shell for a more specific procedure.

Create a mongo shell session using the --eval, --shell and --nodb options.

mongo --eval "var LOCAL_KEY = '$DEV_LOCAL_KEY' " \
  --shell --nodb

The example automatically opens a mongo shell without a connection to a MongoDB database. The --eval option set the LOCAL_KEY variable in the mongo shell to the value of the corresponding environment variable.

Create a new variable in the mongo shell for storing the client-side field level encryption configuration document:

var ClientSideFieldLevelEncryptionOptions = {
  "keyVaultNamespace" : "encryption.__dataKeys",
  "kmsProviders" : {
    "local" : {
      "key" : BinData(0, LOCAL_KEY)
    }
  }
}

Use the Mongo() constructor in the mongo shell to establish a database connection to the target cluster. Configure the connection for client-side field level encryption by specifying the ClientSideFieldLevelEncryption document as the second parameter:

csfleDatabaseConnection = Mongo(
  "mongodb://replaceMe.example.net:27017/?replicaSet=myMongoCluster",
  ClientSideFieldLevelEncryptionOptions
)

Replace the replaceMe.example.net URI with the connection string for the target cluster.

Use the csfleDatabaseConnection object to access client-side field level encryption shell methods.

For complete documentation on establishing database connections configured for client-side field level encryption, see the Mongo() constructor reference.

2

Create the key vault object.

Use the getKeyVault() method on the csfleDatabaseConnection database connection object to create the key vault object:

keyVault = csfleDatabaseConnection.getKeyVault();

Important

Client-side field level encryption depends on server-enforced uniqueness of key alternate names. getKeyVault() creates a unique index on keyAltNames if one does not exist. Do not drop the unique index created by getKeyVault().

3

Delete the data key using its UUID.

Use the KeyVault.deleteKey() method on the keyVault object to delete a data key from the key vault:

keyVault.deleteKey(UUID("<Replace Me With The UUID Of The Key To Delete"))