Django web application with client-side encryption (AcraWriter), decryption on AcraServer, PostgreSQL
Follow Integrating AcraServer into infrastructure guide.
Client-side encryption and Acra-side decryption: data is encrypted on the application side and decrypted on the AcraServer:
curl https://raw.githubusercontent.com/cossacklabs/acra-engineering-demo/master/run.sh | \
bash -s -- django
This command downloads the code of Django website example, Acra Docker containers, PostgreSQL database, Prometheus, Grafana, pgAdmin images and sets up the environment, configures Django application to encrypt data, and provides a list of links for you to try.
The client application is the famous Django app example – the source code of djangoproject.com. We've updated their source code to protect blog posts. Application stores blog posts in PosgtreSQL database. We encrypt blog posts' content before storing in database, and decrypt when reading from database.
Django app encrypts the sensitive fields of blog posts into separate AcraStructs (author name, author email, content are encrypted; blog post ID and title are in plaintext).
Django app writes AcraStructs to the database and reads the decrypted posts through AcraServer (which pretends to be a database).
From the users' perspective, the website works as it used to. However, the blog posts are protected now.
Please add a temporary entry to the hosts file:
echo "$SERVER_IP www.djangoproject.example" >> /etc/hosts
where SERVER_IP
is the IP address of the server that is running the Acra Engineering Demo (if you run the demo on your machine, set it to 127.0.0.1
). Updating the hosts file is required because we will run the protected djangoproject site locally. You can remove this line when you stop needed to access the demo site.
- Log into admin cabinet http://www.djangoproject.example:8000/admin/blog/entry/ using user/password:
admin/admin
. Add a blog post to the Blogs/Entries:
- Open the blog posts' feed http://www.djangoproject.example:8000/weblog/ and see your fresh post.
Everything worked well! Now, let's check the content of the database.
Log into the web PostgreSQL interface http://www.djangoproject.example:8008 using user/password: test@test.test
/test
. Find your blog post in Servers > postgresql > databases > djangoproject > Schemas > public > Tables > blog_entries
and open context menu with right-click. Select View/Edit Data > All rows
and now you can see content of the table. Download and read the content – it's encrypted.
So, the blog posts are stored encrypted, but it's transparent for site visitors and admins.
Open Grafana dashboards to see the performance stats of AcraServer. We collect following metrics: the number of decrypted cryptographic containers (AcraStructs and AcraBlocks), request and response processing time.
Grafana is available at http://localhost:3000.
AcraServer can export detailed traces to Jaeger. Use this data to optimize the performance of the entire system.
Jaeger is available at http://localhost:16686.
There's more to explore:
-
PostgreSQL – connect directly to the database using the admin account
postgres/test
: postgresql://localhost:5432. -
pgAdmin - connect directly to the database using WebUI and user account
login:test@test.test
/password:test
: http://localhost:8008 -
Prometheus – examine the collected metrics: http://localhost:9090.
-
Grafana – see the dashboards with Acra metrics: http://localhost:3000.
-
Jaeger – view traces: http://localhost:16686.
-
Docker-compose.django.yml file – read details about configuration and containers used in this example.
So, was it easy to integrate Acra into Django application? Sure it was!
You can compare our repo to the original repo and see how few changes we introduced:
- We've added Acra storage public key (L278) necessary for AcraWriter to encrypt the data:
ACRA_SERVER_PUBLIC_KEY = b64decode(SECRETS.get('acra_storage_public_key'))
- We added AcraWriter as a dependency and wrapped the original fields with it:
import acrawriter.django
summary = acrawriter.django.TextField()
summary_html = acrawriter.django.TextField()
body = acrawriter.django.TextField()
body_html = acrawriter.django.TextField()
author = acrawriter.django.CharField(max_length=100)
- We've also run a database migration that changed the fields' format from
string
tobinary
to store the encrypted data.
Those are all the code changes! 🎉