Database credentials — cloaking
Open a hosted Drupal or Backdrop site's sites/<uri>/settings.php and you will
not find a database password. You will find this instead:
'password' => $_SERVER['db_passwd'],
That is credential cloaking: the file names the credentials rather than containing them, and something outside the file supplies the values at the moment they are needed. It is on by default.
Why the password is not in that file
Each Octopus instance runs one PHP-FPM pool, as the instance's own web user
(oN.<php>.web, in group www-data). Every site in that instance is served by
that pool — and so is the instance's own Ægir panel. For any of them to be
served, settings.php has to be readable by that shared web user; it ships
0440 owned oN:www-data precisely so it can be.
That makes settings.php the wrong place to keep a secret. Anything running as
the pool user can read every one of them, and the panel's own database account
is far more privileged than a single site's. Cloaking removes the value from
the file the web user can read, and keeps it in files the web user cannot.
The isolation between Octopus accounts rests on separate Unix users, separate pools and, since the per-instance group, separate groups on the files — each site's database account is in any case granted rights over its own database and nothing else. Cloaking closes the one channel that sat inside an instance, where the sharing is by design.
Where the credentials actually live
| Holder | Mode | Read by |
|---|---|---|
The site's Nginx vhost, as fastcgi_param db_* |
0600 oN:<account group> |
Nginx, which passes the values into PHP as $_SERVER |
sites/<uri>/drushrc.php |
0440 oN:<account group> |
Drush and the account's shell identities (oN, oN.ftp) |
| A site backup archive | inside the archive | see Backups below |
The common thread is the group. settings.php carries group www-data because
the web server must read it. Both on-disk holders carry the account's own
group instead — the per-instance group oN,
whose only members are that account's identities; users, the old box-wide
group, on an instance not yet converted — and the web pool user is a member
of neither. So a web request can obtain the credentials for the site it is
serving, the account's own shell identities can read them for Drush, and
nothing else on the box can read them off disk.
The Ægir site alias in ~/.drush/ is not a credential holder: it records
db_server and the site's other context, and Drush takes the credentials
themselves from drushrc.php.
The two paths
A web request arrives through the site's vhost, which passes the six
db_* values to PHP-FPM. settings.php reads them from $_SERVER, builds the
connection, and the request proceeds normally. Nothing about this is visible to
the site's code beyond the connection itself.
The command line has no vhost, so $_SERVER is empty. settings.php
therefore falls back to reading the values out of the sibling drushrc.php,
which the shell identities can read. This is what keeps ordinary Drush,
site-local Drush and vdrush in the limited shell
working exactly as before — including updatedb and cache rebuilds on
Drupal 10 and 11, which run through a site-local Drush of their own. The
values are read back as the var_export() literals drushrc.php is written
with, so a password carrying an apostrophe or a backslash — an adopted site's,
typically — arrives intact; the file is parsed, never executed.
You do not have to do anything to get either path. Both are wired by Provision when it writes the site.
Backups keep the real credentials
A backup is deliberately not cloaked. Before the archive is written the
credentials are put back into settings.php in full, and restored to their
cloaked form immediately afterwards. Without that, an archive would be useless
anywhere except a server that already had a matching vhost — which would defeat
the point of an off-site backup.
So an archive from ~/backups, or one opened with
boa-restore, contains
a working settings.php with real credentials. Treat those archives as
secrets, which is the same rule that already applied to the database dump
inside them.
Where cloaking does not apply
Textpattern keeps its credentials in the site's own
sites/<uri>/private/config.php (mode 0440, group www-data, the same terms
as an uncloaked settings.php), and Grav sites have no database at all. Neither participates in cloaking. Nothing is
weakened by that: those sites hold only their own database account, scoped to
their own database, exactly as a Drupal site's is.
Reading a site's credentials as an operator
When you need the values — to open a client's database by hand, for instance —
take them from drushrc.php, or let the tooling do it:
drush @<site-alias> sql-connect
The database GUI tools and
sqlmagic work through the
site's Drush alias rather than by reading settings.php, so they are
unaffected.
Advanced — turning it off
Cloaking is a property of the HTTP service, resolved per site when Provision
writes settings.php:
$this->cloaked = drush_get_option('provision_db_cloaking', …->cloaked_db_creds());
The Nginx service returns TRUE, so cloaking is the default for every site on the server. A single Provision command can be overridden:
drush @<site-alias> provision-verify --provision_db_cloaking=0
That re-renders one site's settings.php with literal credentials, and the next
ordinary Verify puts it back. There is no reason to run it in normal operation;
it exists for the backup path described above and for debugging. Turning
cloaking off server-wide means editing the Provision service and is not
supported as a configuration choice.