Is it Secure to Store Passwords as Environment Variables in Django?

When building a Django application, one of the most important considerations is how to securely store sensitive data like passwords, API keys, and other credentials. A common question that arises is whether it is safe to store these secrets as environment variables rather than hardcoding them in config files. In this post, we’ll explore the pros and cons of using environment variables to store passwords in Django.The Risks of

Hardcoded Passwords

First, let’s look at why storing unencrypted passwords directly in config files is problematic. For one, checking the passwords into source control means multiple engineers can easily view them. Additionally, if the source code gets leaked, then any passwords checked into version control are compromised. Finally, moving the app across environments means needing to change the credentials each time. Due to these risks, it’s never a good idea to store unencrypted passwords in version control or config files that get bundled with application code.

The Benefits of Environment Variables

Unlike config files that live alongside source code, environment variables are dynamic configuration options set on the server or execution context in which an application runs. Rather than bundling sensitive values into app code, you store them externally and reference them indirectly via env vars. This offers several security and workflow benefits:

  • Isolation from source code: Env vars don’t check into source control or transfer across environments by default, avoiding accidental leaks.
  • Runtime injection: The app loads passwords dynamically at runtime rather than having them hardcoded, meaning you can change them without modifying source code.
  • Configuration flexibility: Developers can customize env vars per machine without affecting the main codebase or other environments.

Overall, externalizing secret values into environment variables enhances security and limits the blast radius when (not if) credentials get compromised down the road.

Storing Passwords with Environment Variables in Django

In Django, it’s simple to reference environment variables using the os.environ dictionary. For example, to load a password named ‘DB_PASS’:

import os

db_password = os.environ['DB_PASS']

You can load these values into Django settings or pass them directly to APIs. Django also offers a helper method, get_env_variable(), for retrieving env vars with a default fallback.

Best Practices for Managing Secrets in Django

When using environment variables to store passwords in Django, adhere to these security best practices:

  • Use a secrets manager: Rather than directly setting secrets on servers, use a purpose-built secrets manager like HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault. These tools provide encrypted storage, access controls, auditing, and rotation for secrets.
  • Minimize plaintext exposure: If directly setting env vars on servers, minimize how many machines and processes see the plaintext values. Production deployments should use a secrets manager instead.
  • Omit passwords from code reviews: When submitting pull requests, use placeholder values rather than real passwords your reviewers shouldn’t see.
  • Follow the principle of least privilege: Only grant access to secrets on an as-needed basis. The frontend app server may only need read access, for example.
  • Rotate credentials periodically: Change out sensitive credentials every 90 days or less to limit the blast radius from any leaks.

By following these best practices in addition to using env vars over hardcoded passwords, you can secure critical secrets in your Django application.

Conclusion

Storing unencrypted passwords in version control and config files is an anti-pattern that jeopardizes application security. While environment variables aren’t perfect, they offer improved isolation, configurability, and security over hardcoded credentials checked into source.

To safely manage secrets, use a dedicated secrets manager rather than raw environment variables when possible. Additionally, grant limited access to credentials, rotate secrets frequently, and follow proven security practices for working with sensitive data.

By externalizing passwords from source code into environment variables and using tools purpose-built for secrets management, you can drastically improve your Django app’s security posture. Though env vars have downsides to be aware of, they can be an acceptable interim solution for storing passwords as you build out a robust, production-grade secrets management strategy.