Skip to content

Instantly share code, notes, and snippets.

@mariocesar
Last active May 24, 2023 10:12
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mariocesar/d3198a267f835d6fb474 to your computer and use it in GitHub Desktop.
Save mariocesar/d3198a267f835d6fb474 to your computer and use it in GitHub Desktop.
Django load secrets and settings from a safe file

This util manage to load django settings from a config file that contain sensitive information such as cache, database and project passwords/secrets.

The util also check the permissions file to be safe, and the existence of the SECRET_KEY variable, if no file is found it will automatically create a file with a random SECRET_KEY value.

How to use it?

Add the method load_environment_file into your code, an use it in your django settings module load_environment_file('environment.ini')

Note that after that, all options in the django section in the file will be prefixed with DJANGO, and avaiable as enviroment variables.

[django]
test_var = Hello

Will be loaded as:

>>> import os
>>> print(os.environ.get('DJANGO_TEST_VAR'))
Hello
[django]
secret_key = QZexrc8oCNMKsA8Hzxn1A1dPaj1o3x7kpVGs52ERU3wxawbHupfiasGga2iaEwip
allowed_hosts = 127.0.0.1 localhost
import os
from .utils import load_environment_file
load_environment_file('environment.ini')
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', None)
ALLOWED_HOSTS = os.environ.get('DJANGO_ALLOWED_HOSTS', '*').split()
import os
import string
from filelock import FileLock
from configparser import ConfigParser
from django.core.exceptions import ImproperlyConfigured
from django.utils.crypto import get_random_string
VALID_KEY_CHARS = string.ascii_uppercase + string.ascii_lowercase + string.digits
class FilePermissionError(Exception):
"""The file permissions are insecure."""
pass
def load_environment_file(envfile, key_length=64):
config = None
lock = FileLock(os.path.abspath(envfile) + ".lock")
with lock:
if not os.path.exists(envfile):
# Create empty file if it doesn't exists
old_umask = os.umask(0o177) # Use '0600' file permissions
config = ConfigParser()
config.add_section('django')
config['django']['secret_key'] = get_random_string(key_length, VALID_KEY_CHARS)
with open(envfile, 'w') as configfile:
config.write(configfile)
os.umask(old_umask)
if (os.stat(envfile).st_mode & 0o777) != 0o600:
raise FilePermissionError("Insecure environment file permissions for %s!" % envfile)
if not config:
config = ConfigParser()
config.read_file(open(envfile))
if not config.has_section('django'):
raise ImproperlyConfigured('Missing `django` section in the environment file.')
if not config.get('django', 'secret_key', fallback=None):
raise ImproperlyConfigured('Missing `secret_key` in django section in the environment file.')
# Register all keys as environment variables
for key, value in config.items('django'):
envname = 'DJANGO_%s' % key.upper() # Prefix to avoid collisions with existing env variables
if envname not in os.environ: # Don't replace existing defined variables
os.environ[envname] = value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment