Jump to content

Database password in config.php


AAD Web Team
 Share

Recommended Posts

G’day,

We’re about to put one of our ProcessWire sites into a Git-based source control system. The repository is private, but I still want to keep passwords out of it. I’ve been thinking about how to handle the database password in /site/config.php (I’ve read the documentation about securing the config.php file itself). I’ve thought of the following options:

  1. Just leave config.php as-is, with the database password in plain text. Make sure config.php is added to the .gitignore file. [But I’d actually like to have config.php file in source control given it’s vital to the operation of the system.]
  2. Create a PHP file outside of the web root, something like passwords.php, which contains a databasePassword() function. Include this file from config.php and reference the function. [I don’t like this because it creates a possibly obscure dependency outside the site directory.]
  3. Set the database password in an environment variable in the PHP-FPM configuration file (env[DB_PASSWD] = MyPassword). Then use PHP’s getenv() function in the config.php file. [Maybe not very secure, and then doesn’t work when the ProcessWire API is accessed from a stand-alone script.]
  4. Set the database password in an environment variable defined in the .bashrc file. Use the getenv() function in config.php. [Maybe not very secure.]
  5. Set mysql.default_pw in php.ini [Comments in this file say this would be a bad idea.]

None of these options seems ideal. Does anyone have any suggestions?

Cheers,

Warwick

Link to comment
Share on other sites

This is what I do, which is almost like (2).

site/config.php:

<?php namespace ProcessWire;

if(!defined("PROCESSWIRE")) die();

// Other PW default config values...
// ...

$config->dbHost = 'localhost';
$config->dbName = 'example_site';
$config->dbUser = '';
$config->dbPass = '';
$config->dbPort = '3306';
$config->dbCharset = 'utf8mb4';
$config->dbEngine = 'InnoDB';

// Environment overwrite
if (file_exists(__DIR__ . '/config.local.php')) {
	require_once(__DIR__ . '/config.local.php');
}

config.local.php:

<?php
namespace ProcessWire;

$config->dbUser = 'example_site_user';
$config->dbPass = 'example_user_pass_123456';

 

config.local.php is in .gitignore, so never committed, and separate config.local.php files exist on testing / live environments. (I use DeployHQ and this is added as a config file that gets deployed with the rest of the code).

To me, the benefits of this approach means that the entire config can be changed depending on the environment, and used to turn things on or off, like debug or advanced mode.

  • Like 9
Link to comment
Share on other sites

  • 2 weeks later...

I'm a little late to the game on this but wanted to throw out what we use on our PW sites. We keep all credentials in .env files in the root directory and then loaded using a package called phpdotenv. The .env file is loaded and then the credentials can be accessed at runtime via the $_ENV global. Some further details on this setup:

  • .env files are automatically protected system files in Apache and will not be served (unless someone actively overrides this, but that would be bad).
  • These files are not added to the Git repository and never stored.
  • We have .env files for local, staging, and production. The contents of each file are stored in whole as a secure note in our password manager.
  • The dotenv library is loaded once in config.php and the values are available globally.
  • We also store credentials for external APIs and services. This allows us to store not only credentials, but any values that differ between local/staging/production.
  • We store all of our config.php variable values in .env so that the config.php file is environment agnostic and we can always be sure that the .env is the single source of truth for the entire CMS configuration.

We use Git to deploy to staging/production servers so using .env files allows us to push all of our code while knowing that sensitive information and data that changes between environments never gets mixed up. Also makes it very clear to anyone looking at the code that these values are stored in a dedicated system dot file.

Here's the package, can be installed with composer https://github.com/vlucas/phpdotenv

This is what a config.php file looks like with it in use:

<?php namespace ProcessWire;

// Load env variables from .env in root directory
$dotenv = \Dotenv\Dotenv::createImmutable(__DIR__ . '/../');
$dotenv->load();

$config->debug = filter_var($_ENV['CMS_DEBUG'], FILTER_VALIDATE_BOOLEAN);

$config->usePageClasses = filter_var($_ENV['CMS_USE_PAGE_CLASSES'], FILTER_VALIDATE_BOOLEAN);

$config->useFunctionsAPI = filter_var($_ENV['CMS_USE_FUNCTIONS_API'], FILTER_VALIDATE_BOOLEAN);

/**
 * Database Configuration
 */
$config->dbHost = $_ENV['CMS_DB_HOST'];
$config->dbName = $_ENV['CMS_DB_NAME'];
$config->dbUser = $_ENV['CMS_DB_USER'];
$config->dbPass = $_ENV['CMS_DB_PASS'];
$config->dbPort = $_ENV['CMS_DB_PORT'];
$config->dbEngine = $_ENV['CMS_DB_ENGINE'];

// Etc...

Hope this might be useful to someone!

 

  • Like 10
Link to comment
Share on other sites

It's a very interesting setup @FireWire but I was wondering how you're dealing with API keys when used by modules. Usually, like in your (excellent) Fluency module, API keys are stored in the db through the module configuration, which is convenient since it's local to the module but in your setup ends up scattering around your credentials.

It's an open question but should there be a $config object that would contain api keys that modules could check first and if empty rely on the administrator to input these in the module configuration ?

Link to comment
Share on other sites

5 hours ago, monollonom said:

It's a very interesting setup @FireWire but I was wondering how you're dealing with API keys when used by modules. Usually, like in your (excellent) Fluency module, API keys are stored in the db through the module configuration, which is convenient since it's local to the module but in your setup ends up scattering around your credentials.

It's an open question but should there be a $config object that would contain api keys that modules could check first and if empty rely on the administrator to input these in the module configuration ?

You're 100% right about the DB storage of keys for modules. My use case for the credentials in .env is for non-module related needs that are necessary in various scripts around the codebase. Some of which aren't in the ProcessWire namespace so wire() & $config aren't available.

A good example is where I work I've built a company-wide REST API to interact with our systems so those keys are in .env. It makes it very easy to work with at a glance. With clean variable names I haven't run into any $_ENV pollution/collisions. Two custom variables that we do create are $config->envIsProduction and $config->envIsDevelopment to help alter code behavior when needed, we use that to do things like switch scripts in markup (like production/development Google Tag Manager/Analytics).

Here's a more robust (dummy) example of our local development .env,

ENVIRONMENT="development" # Either production or development

# CMS
CMS_DEBUG="true"
CMS_CHMOD_DIR=0755
CMS_CHMOD_FILE=0644
CMS_USE_PAGE_CLASSES="true"
CMS_USE_FUNCTIONS_API="true"
CMS_PREPEND_TEMPLATE_FILE="_init.php"
CMS_USER_AUTH_SALT="d5e3ac4deba1e382255bbd8755d7e713"
CMS_LOCALE="en_US.UTF-8"
CMS_TIMEZONE="America/Los_Angeles"
CMS_DEFAULT_ADMIN_THEME="AdminThemeUikit"
CMS_INSTALLED=1580677417
CMS_MODULE_INSTALL="true"

# CMS Database - Development
CMS_DB_HOST="127.0.0.1"
CMS_DB_NAME="pw_website_db_name"
CMS_DB_USER="db_user_name"
CMS_DB_PASS="hB99kVrqS444VZlrrr"
CMS_DB_PORT="3306"
CMS_DB_ENGINE="InnoDB"

# Renova Energy API - Development
RE_API_URL="https://secure-tunnel-url.ngrok.io/"
RE_API_KEY_WEBSITE="d5d891e204f5473990bb533cf7fca22f"
RE_API_KEY_EVENT="531706b9837744ecbbf2b008bc11a681"

# Mailgun
MG_KEY="5af07ec6-315c-48d9-b615-f1cfb3d75820"
MG_DOMAIN="mg.ourconfigureddomain.com"

# Forecast.io
FORECAST_IO_KEY="5fce4a3251f711ecbf630242ac130002"

# CallTrackingMetrics Webhook Auth Token
CTM_WEBHOOK_AUTH_HASH="227040707a1b4e13bc88facf928defe0"

# Web API Authentication Keys
WEB_API_KEY_SALESFORCE="84f13985-77f5-4521-9c2d-1567ddb9bf2e"
WEB_API_KEY_APP="e7051f6e-5905-47f6-9108-93d2f02a53b8"

Also, thank you for the kind words about Fluency, looking forward to the next big (biggest yet) release soon!

Link to comment
Share on other sites

14 hours ago, FireWire said:

We keep all credentials in .env files in the root directory and then loaded using a package called phpdotenv. The .env file is loaded and then the credentials can be accessed at runtime via the $_ENV global. Some further details on this setup:

I think this should be the default for credentials in ProcessWire. Many other CMS or Frameworks like Laravel or Statamic (which is an Laravel application) use this method.

  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...