Encrypt your Plone Database
It all began with a customer that needed his database and blobs encrypted on our server so the sysadmin or a hacker isn't able to read database records or blobs without additional efforts.
We thought about how to implement that and found cipher.encryptingstorage but it didn't encrypt blobs, so we asked for existing solutions on stackoverflow - without success. So we had some work to do...
cipher.encryptingstorage uses keas.kmi as encryption key manager, so you can have your encryption keys stored on another server. In this example, however we use a local keystore.
Tell buildout to create the dek-storage directory
Add the following to your buildout:
[buildout] parts += dek-storage_directory blobstorage-enc # Creates the directory var/dek-storage for keas.kmi [dek-storage_directory] recipe = z3c.recipe.mkdir paths = ${buildout:directory}/var/dek-storage/ # Creates the encrypted blobstorage directory [blobstorage-enc] recipe = z3c.recipe.mkdir paths = ${buildout:directory}/var/blobstorage-enc/
Add an encryption.conf
Create the file production/encryption.conf.template:
[encryptingstorage:encryption] enabled = true kek-path = ${buildout:directory}/var/kek.key dek-storage-path = ${buildout:directory}/var/dek-storage/
Add the following to your buildout:
[buildout] parts += encryption.conf # Creates the encryption.conf for keas.kmi [encryption.conf] recipe = collective.recipe.template input = ${buildout:directory}/production/encryption.conf.template output = ${buildout:directory}/encryption.conf
Add relstorage to your eggs and create a zodbconvert.conf
(This is only needed if you need to encrypt an existing database and blobstorage)
We use zodbconvert from relstorage to encrypt our "old" unencrypted Database.
Add it to your eggs:
[instance] eggs = ... relstorage
Create a zodbconvert.conf.template:
%import cipher.encryptingstorage <filestorage source> path ${buildout:directory}/var/filestorage/Data.fs blob-dir ${buildout:directory}/var/blobstorage/ </filestorage> <encryptingstorage destination> config ${buildout:directory}/encryption.conf # FileStorage database <filestorage> path ${buildout:directory}/var/filestorage/encrypted.fs blob-dir ${buildout:directory}/var/blobstorage-enc/ </filestorage> </encryptingstorage>
Let buildout generate the template:
[buildout] parts += zodbconvert.conf # For converting a unencrypted Data.fs to a encrytped.fs # with the help of relstorage.zodbconvert [zodbconvert.conf] recipe = collective.recipe.template input = ${buildout:directory}/production/zodbconvert.conf.template output = ${buildout:directory}/zodbconvert.conf
Add an /enc mountpoint to your ZEO and Instance(s)
We can't replace the main mountpoint in plone.recipe.zope2instance so we sadly need to add another mountpoint.
Add this to your plone.recipe.zeoserver:
# cipher.encryptingstorage eggs = zope.component cipher.encryptingstorage zeo-conf-additional = %import cipher.encryptingstorage <serverencryptingstorage enc> config ${buildout:directory}/encryption.conf # FileStorage database <filestorage> path ${:zeo-var}/filestorage/encrypted.fs blob-dir ${:blob-storage-enc} </filestorage> </serverencryptingstorage>
And this to your instance(s):
zope-conf-imports = cipher.encryptingstorage zope-conf-additional = <zodb_db enc> # Main database cache-size 30000 # Blob-enabled ZEOStorage database <encryptingstorage> config ${buildout:directory}/encryption.conf <zeoclient> blob-dir ${zeoserver:blob-storage-enc} shared-blob-dir on server ${zeoserver:zeo-address} storage enc name enc_zeostorage var ${zeoserver:zeo-var} cache-size 128MB </zeoclient> </encryptingstorage> mount-point /enc/Plone:/Plone </zodb_db>
Add a cronjob to remove decrypted blobs
Files in blobstorage need to be files on the filesystem so the application can access them. Due to this technical limitation, we need to save decrypted files to a temporary directory. To not end up with a decrypted copy of the whole blobstorage directory we are deleting all files older than 5 minutes that are currently not accessed by any user via a cronjob. See cipher.encryptingstorage pull #1.
Add this to your buildout:
[buildout] parts += remove_plain_blobs [remove_plain_blobs] recipe = z3c.recipe.usercrontab # Run every 5 minutes. times = */5 * * * * command = /usr/bin/find ${buildout:directory}/var/tmp -type f -amin +5 -exec sh -c "fuser -s {} || rm -f {}" \; comment = Remove old decrypted blobs.
Now stop any instances and the zeo server
and run ./bin/buildout -c <your-conf>
Convert your existing Data.fs
run:
$ ./bin/zodbconvert zodbconvert.conf
This script will copy AND encrypt your var/filestorage/Data.fs into var/filestorage/encrypted.fs AND all blobs from var/blobstorage/ to var/blobstorage-enc/
It also creates a file var/kek.key - This is the encryption key for your encstorage!
Attention!
keep var/kek.key and var/dek-storage - both is needed to encrypt and decrypt your data! (you'll also need those keys to use the storage in another buildout.)
Move the old Data.fs and blobstorage
run:
$ mv var/filestorage/Data.fs var/filestorage/Data.fs.unencrypted $ mv var/blobstorage var/blobstorage.unencrypted
(can/will be removed later)
Start your site.
run:
$ ./bin/zeoserver start $ ./bin/instance fg
Connect somehow to your site
If running locally it's http://localhost:8461/manage
Create a new "ZODB Mount point"
In the ZMI choose add / "ZODB Mount point"
select "/enc" and click "Create selected mount points"
This will allow you to mount your Plonesite (previously located under /Plone) to enc/Plone (which is using the encrypted database created in step 3.
Rebuild the catalog
click on /enc/Plone then portal_catalog then the tab "advanced"
next click on "Clear and Rebuild".
Enable ZOPE users for Plone
Somehow you need to create a Plone site in / so that the Login as ZOPE User works in /enc/Plone.
Go to the ZMI and add a Plone site.
Done
Your site is now available through /enc/Plone.
Cleanup
If you feel save remove unencpryted data:
rm -rf var/filestorage/Data.fs.unencrypted rm -rf var/blobstorage.unencrypted
- Näher dran bleiben?
-