Hiding SECRET_KEY environment variables

Obviously it’s important to avoid storing credentials in text files, especially in production. With Django on Heroku, you can’t use a .env variable because it is hidden and not tracked with git. Plus, since the file-system on Heroku is ephemeral, storing a .env file is just not possible. Instead, the SECRET_KEY is a dynamic environment variable which you can set by exporting it in the Heroku shell or add/remove/change it in the Heroku dashboard. I realize that this is far superior than storing a SECRET_KEY as plain text. But I don’t completely understand why.

How does Heroku (or any Django web host for that matter) protect SECRET_KEYs and other environment variables out of reach by hackers? A SECRET_KEY must be stored somewhere out of reach from hackers. How do Django web hosts achieve that?

How easy would it be for a malicious hacker to change an environment variable (assuming the admin follows Django’s official security deployment checklist and that the sysadmin has all the up to date packages installed with all known vulnerabilities patched)?

The reason why I am asking these novice questions is that when I login to my Heroku session in my shell and run $ export SECRET_KEY=<mysecretkey> (which is 50 characters or longer), I feel like it is arbitrary. Why do Django developers (for projects deployed on Heroku or maybe elsewhere) even bother with a SECRET_KEY if it is just a very long arbitrary string of characters and the admin just enters it once and then never needs to change it again?

I suppose a similar question is with CSRF tokens with HTML password forms: If a CSRF token is mandatory for every single POST request, why don’t Django developers just integrate it? A CSRF token is almost a redundant programmer’s convention. It should just be assumed and its integration automated. Postgres SECRET_KEYs should be integrated and assumed too.

Could someone comment on my novice understanding here?

Typically they’ll aim to use a secure secret storage service, that might use a hardware security module, and keep the decrypted version only ever in memory rather than disk, since memory is ephemeral.

There’s normally a lot going on to make sure your secrets are safe with such platforms.

Normally impossible! They’re part of the operating system. Unless you write some code that changes environment variables and expose it in a view, a hacker can’t do that.

You shouldn’t be running export SECRET_KEY on Heroku. If you’re using their config variables feature, the env var will be set for you when you use heroku run.

I guess you’re asking why do you need to use {% csrf_token %} in your template? It’s because Django leaves you in control of your HTML, rather than trying to automatically add it.

I don’t follow what you mean here.

Thank you @adamchainz for your detailed reply.

Could you elaborate a little on why it’s a bad idea to export a SECRET_KEY in my Heroku shell? I can use the Admin Dashboard to change my env variables going forward, no problem. But what is the reasoning for this policy?

Could you give me an example of some Python code in a views.py that would expose an environmental variable?

The main risk is your command may be logged, which would copy your secret key to disk. I can’t remember if Heroku logs all commands by default but it’s common for platforms.

Imagine a view that does os.environ["SOMETHING"] = user_provided_value - normally completely unnecessary code, but it can be done! This would affect the env vars for this process and any subprocesses it went on to launch.

I just checked. There is a .bash_history text file in my remote Heroku environment but the many other commands I used earlier today aren’t there because the Heroku Django file system is ephemeral. So if I were to have invoked $ export SECRET_KEY=<mysecretkey> say last week (or whenever), and if an attacker gained access to my remote host, then they wouldn’t find anything valuable in the contents of .bash_history because it’s empty.

However if my local development environment were compromised with a nasty root kit and keylogger, then, yes, they could view a record of me typing my secret key into my Heroku shell. But then changing an environmental variable in my Heroku dashboard would be exposed in that scenario as well.

So after having said all of that, is entering $ export SECRET_KEY=<mysecretkey> in my Heroku shell actually any more or less risky than changing an environmental variable inside the Heroku Dashboard compared to in the shell?

The .bash_history file isn’t preserved on Heroku since it gives you a new dyno (server) each time you use heroku run. I was more concerned about its logs feature (the heroku logs command) or how that changes when you add a better logging add-on, such as Papertrail.

But anyway, the main point is that there’s a secure, dcoumented way to add environment variables onto your shell, so just a hint that you should use that.