Mautic & GCP: Automate Database Password Rotation with Secrets Manager

PUBLISHED ON AUG 4, 2025 — CODE, GCP, HOW-TO, LINUX, PHP

For a Mautic instance hosted on GCP, I needed to automate the process of updating the database password. The credentials were automatically rotated by Google Secrets Manager, requiring a solution for Mautic to dynamically fetch the new password.

Install the dependency for Mautic.

composer require google/cloud-secret-manager

You can find the changes the changes for local.php below

<?php

use Google\Cloud\SecretManager\V1\SecretManagerServiceClient;
use Google\ApiCore\ApiException;

// Use a static variable to ensure the configuration is only processed once per request.
static $mautic_parameters_config = null;


if (null === $mautic_parameters_config) {
    // Define your project and secret details here, you can add the username and db_host if needed.
    define('GCP_PROJECT_ID', 'your-gcp-project');
    define('SECRET_DB_PASSWORD', 'your-secret-for-password');

    // The path to the cache file.
    define('CREDENTIALS_CACHE_FILE', __DIR__ . '/../cache/prod/db_credentials.cache');

    // Cache lifetime, you can set whatever you want here according to your needs.
    define('CACHE_TTL_SECONDS', 3600);

    $dbCredentials = null;

    // Try credentials from the cache before geting new ones
    if (file_exists(CREDENTIALS_CACHE_FILE) && (time() - filemtime(CREDENTIALS_CACHE_FILE) < CACHE_TTL_SECONDS)) {
        $cachedData = file_get_contents(CREDENTIALS_CACHE_FILE);
        if ($cachedData) {
            $dbCredentials = unserialize($cachedData);
        }
    }

    // If the cache is invalid or empty.
    if (!$dbCredentials) {
        try {
            // Include the Composer autoloader.
            require_once __DIR__ . '/../vendor/autoload.php';

            // Create the Secret Manager client.
            $client = new SecretManagerServiceClient();

            function getSecretValue(SecretManagerServiceClient $client, string $projectId, string $secretId): string {
                $name = $client->secretVersionName($projectId, $secretId, 'latest');
                $response = $client->accessSecretVersion($name);
                return $response->getPayload()->getData();
            }

            // Fetch the password (you can fetch the username, hostname, etc)
            $dbCredentials = [
                'password' => getSecretValue($client, GCP_PROJECT_ID, SECRET_DB_PASSWORD),
            ];

            // Ensure the cache directory exists before writing to it.
            $cacheDir = dirname(CREDENTIALS_CACHE_FILE);
            if (!is_dir($cacheDir)) {
                mkdir($cacheDir, 0775, true);
            }
            
            // Save the credentials to the cache file.
            file_put_contents(CREDENTIALS_CACHE_FILE, serialize($dbCredentials));

        } catch (Exception $e) {
            error_log('ERROR: Could not fetch the credentials from secret manager. Error: ' . $e->getMessage());
            $dbCredentials = ['host' => 'FETCH_FAILED', 'name' => 'FETCH_FAILED', 'user' => 'FETCH_FAILED', 'password' => 'FETCH_FAILED'];
        }
    }

    // Build the final parameters array and store it in our static variable.
    $mautic_parameters_config = [
        'db_password' => $dbCredentials['password'], // Magic happens here
        'db_host'     => 'localhost',
        'db_name'     => 'dbname',
        'db_user'     => 'username',
        'db_driver'   => 'pdo_mysql',
        'db_host_ro' => null,
        'db_table_prefix' => null,
        'db_port'     => '3306',
        'db_backup_tables' => 1,
        'db_backup_prefix' => 'bak_',
        'secret_key' => 'xxxxx,
        'site_url' => 'http://mautic.web/index.php',
    ];
}

$parameters = $mautic_parameters_config;

TAGS: LINUX, MAUTIC, SECRETS