Code-Memo

Environment Variables and Secret Keys

Why Environment Variables Are Important

Environment variables allow you to separate configuration from code, which is particularly important for storing sensitive data like API keys, database credentials, and secret keys. In Django, this helps to keep sensitive information such as the SECRET_KEY and database connection details out of your source code, which is essential for security.

By using environment variables, you ensure that your application can behave differently based on the environment it’s running in (e.g., development, staging, production), making it easy to manage different configurations without changing the codebase.

Storing Secret Keys Using Environment Variables

In Django, a common use case for environment variables is storing the SECRET_KEY, which is critical for cryptographic signing (such as for sessions or cookies). Hardcoding this value in the settings file is unsafe, especially if the codebase is shared publicly (e.g., on GitHub). Instead, you can store it in an environment variable and load it from there.

Here’s how you can manage the SECRET_KEY securely with environment variables:

Step 1: Set the Environment Variable

In your terminal (or your hosting service), set the environment variable. For local development, you can set it manually or use .env files to load environment variables.

export DJANGO_SECRET_KEY='your-very-secure-secret-key'

While you can use the built-in os module to access environment variables, it’s often more convenient to use libraries like python-decouple to manage settings. This library allows you to load variables from a .env file, making it easier to work with configuration in multiple environments.

To install it, run:

pip install python-decouple
Step 3: Add the Code to Your settings.py

You can then import the environment variable into your settings.py file using python-decouple or os. Here’s how:

Using python-decouple:

from decouple import config

SECRET_KEY = config('DJANGO_SECRET_KEY')

Using os:

import os

SECRET_KEY = os.getenv('DJANGO_SECRET_KEY')

This retrieves the DJANGO_SECRET_KEY from your environment variables.

Step 4: Using a .env File for Local Development (Optional)

If you don’t want to set environment variables manually every time, you can create a .env file in your project root and store the keys there. For example, create a .env file:

DJANGO_SECRET_KEY=your-very-secure-secret-key

Ensure that this .env file is added to .gitignore so it’s not pushed to version control.

With python-decouple, environment variables in .env files are automatically loaded, so the above code will work without any further changes.

Database Configuration Using Environment Variables

Another common use case for environment variables is configuring database connections. Instead of hardcoding your database credentials, you can set the database settings via environment variables.

First, add your database credentials as environment variables:

export DB_NAME='mydb'
export DB_USER='myuser'
export DB_PASSWORD='mypassword'
export DB_HOST='localhost'
export DB_PORT='5432'

Then, in your settings.py:

from decouple import config

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': config('DB_NAME'),
        'USER': config('DB_USER'),
        'PASSWORD': config('DB_PASSWORD'),
        'HOST': config('DB_HOST'),
        'PORT': config('DB_PORT', default='5432'),
    }
}

This allows you to change your database configuration by simply modifying environment variables instead of touching the settings.py file, making it easier to manage different configurations for different environments.

Handling Other Sensitive Information

Apart from the SECRET_KEY and database credentials, you might have other sensitive data like API keys or third-party service credentials. Using environment variables for all sensitive data makes your application more secure.

Example for Using API Keys from Environment Variables
API_KEY = config('MY_API_KEY')

Now, you can set your API key in an environment variable:

export MY_API_KEY='your-api-key-here'

Loading Environment Variables in Production

In production environments (like on a cloud server), you will typically set these environment variables in the hosting service’s configuration interface (e.g., AWS, Heroku, DigitalOcean, etc.). The approach will vary depending on the platform, but the principle remains the same: keep sensitive data out of your code and instead load it from environment variables.

Heroku Example:

If you’re using Heroku, you can set environment variables via the Heroku CLI:

heroku config:set DJANGO_SECRET_KEY='your-very-secure-secret-key'
Docker Example:

If you’re using Docker, you can pass environment variables through a .env file or directly in the docker-compose.yml file.

Example using a .env file:

# .env file
DJANGO_SECRET_KEY=your-very-secure-secret-key

Then, in your docker-compose.yml:

version: '3'
services:
  web:
    image: django-app
    env_file:
      - .env
    ports:
      - "8000:8000"

This ensures that your Django application will read the environment variables from the .env file when the container is started.

Secret Key Management for Multiple Environments

For managing secret keys across different environments (e.g., development, staging, production), it’s a good practice to store environment variables for each environment separately. You can use different .env files, one for each environment, and load them conditionally.

Example for Multiple Environments

Create different .env files like .env.dev, .env.prod, and load the appropriate file based on the environment:

# .env.dev
DJANGO_SECRET_KEY=dev-secret-key

# .env.prod
DJANGO_SECRET_KEY=prod-secret-key

You can then load the right file in your Django application by using the python-decouple library or django-environ to manage these files and automatically switch based on the environment. Here’s an example using django-environ:

import environ

env = environ.Env()
environ.Env.read_env()  # Read .env file

SECRET_KEY = env('DJANGO_SECRET_KEY')

This allows you to easily manage different secret keys for different environments.

Best Practices for Secret Key Management

  1. Never hardcode secret keys: Always use environment variables to store secret keys and other sensitive information. Hardcoding them in source code is a significant security risk.
  2. Use .env files for local development: They make it easier to manage different configurations locally.
  3. Keep .env files out of version control: Ensure that your .env files are included in .gitignore so they are not accidentally pushed to a public repository.
  4. Set environment variables in production: Use the environment configuration options provided by your hosting provider (e.g., Heroku, AWS, etc.) to set environment variables securely.
  5. Rotate secret keys periodically: Regularly changing secret keys is a good security practice, especially if you suspect they may have been compromised.