Prevent Unintended Data Modification With django-read-only

Last week I released a new Django package, django-read-only. It provides a read-only mode for Django’s database layer.
This can be useful to reduce the risk of giving developers access to your production instances. Access to manage.py shell
on production allows you to iterate faster when creating new features, migrations, and backfills. But with great power comes great accident potential.
It’s all too easy to mix up terminal sessions and run the wrong thing on production. Even if the individual chance of making such a mistake is small, multiplying it by team size and time, the chance of a mistake can become almost certain, and the potential cost can be huge.
Rather than locking your team members out of production, you can protect against these mistakes with django-read-only. The package uses some always-installed database instrumentation to block database access when its read-only mode is active.
You can then enable read-only mode for interactive production sessions via an environment variable or setting, so when developers access production writes are disabled by default. Read-only mode can be disabled, so the occasional manual data fix is still possible.
For example, if the environment variable was set, we couldn’t log into the shell and create a user straight away:
$ export DJANGO_READ_ONLY=1
$ python manage.py shell
>>> from django.contrib.auth.models import User
>>> User.objects.create_user(username="hacker", password="hunter2")
DjangoReadOnlyError(...)
But after seeing this we could re-enable writes and try again:
>>> import django_read_only
>>> django_read_only.enable_writes()
>>> User.objects.create_user(username="hacker", password="hunter2")
We had a read-only mode back at YPlan, where I worked until four years ago (time flies!). That implementation actually used a second database user with read-only permissions, swapped into the DATABASES
setting - slightly more accurate, but preventing the read-only mode being disabled in the same process.
I created django-read-only to provide this protection for a client project. I hope you find it useful too!
If your Django project’s long test runs bore you, I wrote a book that can help.
One summary email a week, no spam, I pinky promise.
Related posts:
- Backporting a Django ORM Feature with Database Instrumentation
- How to Make Always-Installed Django Database Instrumentation
Tags: django