47ng / prisma-field-encryption

Transparent field-level encryption at rest for Prisma
https://github.com/franky47/prisma-field-encryption-sandbox
MIT License
223 stars 27 forks source link

Do we need both `CLOAK_KEYCHAIN` and `CLOAK_MASTER_KEY` or one of them #75

Open beeman opened 11 months ago

beeman commented 11 months ago

I'm integrating this extension and it's working great so far! It's simple to set up and it works transparently, I love it! 🙌

I'm curious if we need to provide both CLOACK_KEYCHAIN and CLOAK_MASTER_KEY to our environment when deploying the API.

When using the extension, I see only CLOAK_MASTER_KEY is documented, what to do with CLOAK_KEYCHAIN?

export const prisma = new PrismaClient().$extends(
  fieldEncryptionExtension({
    encryptionKey: process.env['CLOAK_MASTER_KEY'],
  }),
)

Some clarity here would be highly appreciated.

franky47 commented 11 months ago

Technically you don't need either.

The keychain system that uses environment variables in 47ng/cloak is not necessary to use prisma-field-encryption, it is actually replicated here when passing multiple decryption keys.

That being said, if you do use the cloak keychain, the master key should not be used for anything else than decrypting the CLOAK_KEYCHAIN environment variable. Your keychain would then contain keys to pass to prisma-field-encryption, along with the fingerprint of the key to use for encryption in the CLOAK_CURRENT_KEY environment variable.

Here's how this could be done (note that there is a lot of data massaging due to the fact that prisma-field-encryption doesn't accept byte arrays for keys, which could be a future improvement I guess):

import { importKeychain, serializeKey } from '@47ng/cloak'
import { fieldEncryptionExtension } from 'prisma-field-encryption'

const keychain = await importKeychain(
  process.env.CLOAK_KEYCHAIN,
  process.env.CLOAK_MASTER_KEY
)

const encryptionKey = await serializeKey(keychain[process.env.CLOAK_CURRENT_KEY])
const decryptionKeys = await Promise.all(Object.values(keychain).map(({ key }) => serializeKey(key)))

export const prisma = new PrismaClient().$extends(
  fieldEncryptionExtension({
    encryptionKey,
    decryptionKeys,
  })
)