MongoServerError: A non-static (JSONPointer) keyId is not supported

290 Views Asked by At

I'm using csfle using mongoDB enterprise 5 by setting up authenticated client. I've got the field level encryption with json pointer keys working (every document can have a different encryption key).

I'm also using an authenticated client with the key vault and passing that to mongoose as the orm. Mongoose does not need to know about the csfle bits as that's handled by the driver and mongocryptd internally.

Here is the schema definition of one of my collections

{
    bsonType: 'object',
    encryptMetadata: {
      keyId: '/encKeyId',  // dynamic json pointer key
    },
    properties: {
      description: {
        encrypt: {
          bsonType: 'string',
          algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Random',
        },
      },
      adminComment: {
        encrypt: {
          bsonType: 'string',
          algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Random',
        },
      },
    },
  }

Inserts work fine and I'm able to create and store the encryption keys in a seperate collection as documented. But updates are not working and failing with the following error.

const act = await Activity.findOne({})
    if (act) {
      console.log(act)
      act.description = "yolo". // any encrypted field edit causes an error
      await act.save()
    }

Please note edits on non-encrypted fields work just fine.

The error is as follows

MongoServerError: A non-static (JSONPointer) keyId is not supported.
    at Connection.onMessage (/Users/Sanket/Workspace/emit-backend/node_modules/mongodb/lib/cmap/connection.js:203:30)
    at MessageStream.<anonymous> (/Users/Sanket/Workspace/emit-backend/node_modules/mongodb/lib/cmap/connection.js:63:60)
    at MessageStream.emit (node:events:526:28)
    at processIncomingData (/Users/Sanket/Workspace/emit-backend/node_modules/mongodb/lib/cmap/message_stream.js:108:16)
    at MessageStream._write (/Users/Sanket/Workspace/emit-backend/node_modules/mongodb/lib/cmap/message_stream.js:28:9)
    at writeOrBuffer (node:internal/streams/writable:389:12)
    at _write (node:internal/streams/writable:330:10)
    at MessageStream.Writable.write (node:internal/streams/writable:334:10)
    at Socket.ondata (node:internal/streams/readable:754:22)
    at Socket.emit (node:events:526:28)
    at addChunk (node:internal/streams/readable:315:12)
    at readableAddChunk (node:internal/streams/readable:289:9)
    at Socket.Readable.push (node:internal/streams/readable:228:10)
    at TCP.onStreamRead (node:internal/stream_base_commons:190:23) {
  ok: 0,
  code: 51093,
  codeName: 'Location51093',
  [Symbol(errorLabels)]: Set(0) {}
}

I did an experiment with keeping the key static and not dynamic, and that works just fine. i.e using the same encryption key for the full collection.

sample definition of static key:

encryptMetadata: {
      keyId: [new Binary(Buffer.from("<some-key-here>", 'base64'), Binary.SUBTYPE_UUID)],
    },

So without updates to documents, per document keys are kind of useless. Is there any known workaround for this? Otherwise, I will have to drop to per collection static encryption keys.

Regards,

1

There are 1 best solutions below

0
On

I know this is a bit old, but I was experienceing the same issue and could not find any answers, so I thought I would post my findings.

The documentation is a bit misleading as it suggests that the only issues for reads and updates when using CSFLE are when the encrypted field needs reading during the operation. If you are replacing a value of an encrypted field, intuitively, you would have thought there would be no need to read it.

However, this does say that $set in an update operator is supported against deterministically encrypted fields and as there is no mention of randomised encryption, we can assume it is not supported.

I have tried various update operators as well as replaceOne and all return the A non-static (JSONPointer) keyId is not supported error when I use a dynamic key. So it seems this is not currently supported.

My work around is to create a method that first deletes the document then inserts the updated version. This is probably not as efficient as a supported update operation but it does work with dynamic keys.