Cybersecurity is a growing concern across the globe, and with good reason. Securing the credentials, or secrets, used in your code is one of the most important things you can do to protect yourself.
Most applications need to access external resources such as databases, storage systems, or third-party web services to perform essential functions. In order to do that, the application needs to authenticate itself to the external resource using credentials, which could be in the form of secret keys or passwords.
Credentials are valuable targets for malicious hackers as they can then impersonate your company or your application to access your critical data. Therefore, it is crucial to protect these credentials and keep them secret as much as possible.
By removing the secrets from your source code and using a secrets manager, you can boost the security of your code secrets and protect your data from bad actors.
Consider this sample snippet for Django’s DATABASES
setting.
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'mydatabase', 'USER': 'mydatabaseuser', 'PASSWORD': 'mypassword', 'HOST': '127.0.0.1', 'PORT': '5432', } }
This can help programmers of all experience levels easily get started in running Django locally because it clearly illustrates what key/value pairs to use and what they are meant to contain. Hardcoding the values, however, only makes it easy to leak your database credentials to others. If your source code leaks, the credentials will leak as well.
Storing the credentials as environment variables is a common pattern to remove credentials from the source code. Instead of defining the credentials in the source code, they are instead defined in the environment the application is running in. The application then retrieves those values at runtime. This is a pattern recommended by the widely-known set of best practices called The Twelve-Factor App.
To set the environment variables on Linux/OS X, the following lines can be defined in .bashrc
or .bash_profile
(outside of the application source code):
export DB_NAME='mydatabase' export DB_USER='mydatabaseuser' export DB_PASSWORD='mypassword' export DB_HOST='127.0.0.1' export DB_PORT='5432'
In our example Django application, those credentials are retrieved from the environment at runtime.
import os DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.getenv('DB_NAME'), 'USER': os.getenv('DB_USER'), 'PASSWORD': os.getenv('DB_PASSWORD'), 'HOST': os.getenv('DB_HOST'), 'PORT': os.getenv('DB_PORT'), } }
There you go. No more credentials in the source code. No more chance of your credentials leaking out together with your source code.
While this is a good first step, it can still be improved further. The credentials may not be in the source code but it is available in the runtime environment itself. Any process running in the same environment as your application can also easily access those credentials. To mitigate this, we can then use secret managers.
A secret manager is an application that serves as a secure storage system for credentials and other sensitive data. There are many options for secrets managers:
For our sample code, we will use AWS’ offering. We store our example credentials in a secret called DB_CREDENTIALS
in AWS Secrets Manager.
Assuming boto3
has been installed as a dependency and configured correctly, our Django settings snippet can now be changed to this:
import boto3 import json # Create a Secrets Manager client client = boto3.client( service_name='secretsmanager', region_name='us-east-1' ) db_credentials = json.loads(client.get_secret_value(SecretId='DB_CREDENTIALS')['SecretString']) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': db_credentials['DB_NAME'], 'USER': db_credentials['DB_USER'], 'PASSWORD': db_credentials['DB_PASSWORD'], 'HOST': db_credentials['DB_HOST'], 'PORT': db_credentials['DB_PORT'], } }
By doing it this way, the credentials are neither present in the source code nor in the environment. A malicious process in the same environment as the application would not be able to retrieve them from the environment variables.
Using secret managers to store credentials requires very minimal additional effort and cost but it greatly helps in improving the security of your application.