Keeping access credentials, such as keys, secrets, and tokens safe and secure is important and also falls under Config in the Twelve-Factor App methodology. It is not secure to commit these values to your Git repository as plain text values in your code. An obvious security breach would be that your repository is or becomes public. Even if you have a private repository, by design, repositories can be cloned to any number of devices that you may not control. It’s just a security best practice to not commit sensitive data to version control. Here are some questions and answers to help protect your data.
If my key is not in the code, where does it live?
There are a couple of options for storing your access credentials. Environment variables are a great place to get started. If your access credentials are protecting highly sensitive data, you may want to consider subscribing to an encrypted key management provider. For this article, the use of environment variables is covered.
Environment variables
Most local development and hosting environments now provide a mechanism for registering custom environment variables. If you go this route, you’ll need to register your variables with each environment hosting your site.
Each environment will have its own method for registering variables from creating a file in a specified directory to modifying settings using a secure web page. Refer to each environment’s documentation for instructions.
Lando example
If you are using Lando for local development, you can add the following to the .lando.yml
configuration file found in the root of the project:
env_file:
- .env
Now you can create a .env
file in the root of the project and define your variables:
DATABASE_NAME=databasename
DATABASE_USERNAME=databaseusername
DATABASE_PASSWORD=databasepassword
MY_API_KEY=myapikey
If Lando is currently running, you will need to run lando restart
to make them available to your site.
Before committing any changes to your Git repository, you need to add these lines to the .gitignore
file in the root of your project to keep them private:
# Ignore .env files as they are personal
/.env
This will ensure that your .env
file will not accidentally be committed to your code repository.
How can my code access environment variables?
A typical scenario for a Drupal site might be that the database accesses credentials and information used in a site’s settings.php
file. If you use an environment variable solution to register values for DATABASE_NAME, DATABASE_USERNAME
and DATABASE_PASSWORD
, you can add something like this to your settings.php
file:
$databases['default']['default'] = [
'database' => getenv('DATABASE_NAME'),
'username' => getenv('DATABASE_USERNAME'),
'password' => getenv('DATABASE_PASSWORD'),
'host' => 'localhost',
'port' => '3306',
'driver' => 'mysql',
'prefix' => '',
'collation' => 'utf8mb4_general_ci',
];
There is a getenv()
PHP function that retrieves default environment variables but, in order to access the variables defined in your .env
file, you will need to include the vlucas/phpdotenv
project in your composer.json
file. If you are using drupal-composer/drupal-project as your project template, you are good to go.
The getenv()
function will retrieve the environment variable value and insert it into the settings.php
file at run time. It can also be used to retrieve the value anywhere in your custom PHP code.
The use of environment variables is not just available for PHP projects. For example, if you need to access environment variables in JavaScript, the npm package, dotenv
, can be used.
What about Drupal configuration?
You can do something similar with a configuration override in the settings.php
file for any core contributed or custom module configuration.
Note: A configuration override will set or override the values during run-time, but will not store them in the database or export them to configuration YAML files. This technique could cause confusion in the UI.
An example of overriding a module’s settings configuration would look something like this for a configuration YAML file named, my_custom_module.settings.yml
:
$config['my_custom_module.settings']['api_key'] = getenv('MY_API_KEY');
This will transform something like this:
api_key: api_key_from_env
to:
api_key: myapikey
Using configuration overrides can cause confusion in the admin editorial experience, for example, seeing a different value or no value in a form. If you would like to provide more insight about overrides to users, check out the Config Override Inspector module.
What if I already committed my keys to the code repository?
The first step is to revoke access for the compromised credentials. For some services, this may mean revoking a token or resetting a password. However you need to, it's very important that you make sure those credentials no longer work. Then you can request new access credentials moving forward.
Thanks to James Sansbury, Juampy NR, and Salvador Molina Moreno for their feedback.