How to Keep Secrets out of Django Settings
Tags: django
Published: 2020-03-13 18:02:45

## Introduction

The Django startproject command creates a settings file that includes values that should be kept secret. These include:

* _SECRET_KEY_ is a value used when generating sessions and password reset tokens.

* _DATABASE_SETTINGS_ specifies the database connection settings and may include database credentials.

The DEBUG setting is also of interest:
_DEBUG_ is a boolean value which determines whether Django displays detailed tracebacks are displayed when exceptions are raised.

The deployment checklist recommends that:

* _DEBUG_ be set to _False_ to avoid leaking sensitive information from the detailed tracebacks that Django displays
* Secrets and database credentials be kept out of source control.

This is also consistent with the Twelve-factor recommendation to keep Config separate from Code.

[Twelve-factor](https://www.12factor.net/config)  is a useful set of recommendations for building web applications.

## Django-environ

Django-environ is a third-party Django library that can be used to manage environment variables.
Values are read on startup instead of hardcoded in the settings file. The benefits include:

* Your don't have to use multiple settings files to manage different deployments (e.g staging, production, developer).
* Secrets can be kept out of source control.

It reads values from a _.env_ file in the same folder as _settings.py_.

## Instructions

Note: In the instructions below _.env.example_ and _.env_ should be saved in the same folder as _settings.py_

Install django-environ
```
pip install django-environ
```

Add a .env.example file with these contents:
```
DEBUG=on
SECRET_KEY=your-secret-key
DATABASE_URL=psql://urser:urpassword@127.0.0.1:8458/database
```

This file is an example for collaborators to follow when creating the .env file for their local environment.

Add `.env` to your .gitignore file to prevent it from being added to the repository


At the top of your _settings.py_ add the following:
```
import environ
env = environ.Env(
    # set casting, default value
    DEBUG=(bool, False)
)
# reading .env file
environ.Env.read_env()
```

Change the DEBUG, SECRET_KEY and DATABASES lines in _settings.py_ to read their values from the environment.

```
DEBUG = env('DEBUG')
...
SECRET_KEY = env('SECRET_KEY')
...

DATABASES = {
    'default': env.db(),
}
```

Your can then add `.env.example` and the the modified settings file to the Git repository

```
git add .

git commit -m "Extracted secrets from the settings file"
```

For each deployment (staging, production, developer environment) you then:

Create a .env file with the settings specific to that environment. These include:

* Your desired DEBUG setting.
* The secret key.
* Your DATABASE connection string and credentials.

Django has a utility function that the startproject command uses to generate the secret
You can use it from the command line.
With your virtual environment activated run this command:
```
python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'
```
It will spit out a random string like:
```
a1$%jr29f2(u^l=r1q1a2$sztg%x7%g8s@!ne#_(^5$woi#wi$
```

Assuming your DATABASE setting was
```
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'blog',
        'USER': 'dbuser',
        'PASSWORD': 'dbpassword',
        'HOST': '127.0.0.1',
        'PORT': '5432',
    }
}
```
Your .env file would look like

```
DEBUG=on
SECRET_KEY=a1$%jr29f2(u^l=r1q1a2$sztg%x7%g8s@!ne#_(^5$woi#wi$
DATABASE_URL=psql://dbuser:dbpassword@127.0.0.1:5432/blog
```

 **Note that there are not quotes around the values in the .env file**
 
 For your production deployment change  `DEBUG=on` to `DEBUG=off` 
 
 You can confirm that your app starts up successfully by running the Django Dev Server
 
 `python manage runserver`
 
 If there are any errors consult the [Django-environ documentation](https://django-environ.readthedocs.io/en/latest/) for guidance.