google/cloud-secret-manager
Idiomatic PHP client for Google Cloud Secret Manager. Manage secrets and versions, access payloads, and integrate securely with GCP apps. Supports REST and gRPC transports, with official API docs and auth guides via Google Cloud PHP.
Install the Package
composer require google/cloud-secret-manager
Ensure your project uses PHP 8.1+ (verified in v1.15.4).
Set Up Authentication Configure credentials via:
putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json');
$client = new SecretManagerServiceClient([
'credentials' => new WorkloadIdentityCredentials([
'project_id' => 'your-project-id',
'service_account' => 'your-service-account@project.iam.gserviceaccount.com',
// ... other WIF config
]),
]);
See Authentication Guide for details.
First Use Case: Fetch a Secret
use Google\Cloud\SecretManager\V1\SecretManagerServiceClient;
use Google\Cloud\SecretManager\V1\GetSecretRequest;
$client = new SecretManagerServiceClient();
$secretName = 'projects/YOUR_PROJECT_ID/secrets/YOUR_SECRET_ID/versions/latest';
$request = (new GetSecretRequest())->setName($secretName);
$secret = $client->getSecret($request);
$payload = $secret->getPayload()->getData();
$decryptedValue = base64_decode($payload);
Integrate with Laravel’s Config Create a custom service provider to inject secrets into Laravel’s config:
// app/Providers/SecretManagerServiceProvider.php
namespace App\Providers;
use Google\Cloud\SecretManager\V1\SecretManagerServiceClient;
use Illuminate\Support\ServiceProvider;
class SecretManagerServiceProvider extends ServiceProvider
{
public function register()
{
$client = new SecretManagerServiceClient();
$this->app->singleton('secret-manager', function () use ($client) {
return $client;
});
}
public function boot()
{
$this->app->bind('config', function () {
$client = $this->app['secret-manager'];
$config = config('secret-manager');
foreach ($config['secrets'] as $key => $secretName) {
$secret = $client->getSecret((new GetSecretRequest())->setName($secretName));
config([$key => base64_decode($secret->getPayload()->getData())]);
}
return config();
});
}
}
Register in config/app.php and define secrets in config/secret-manager.php:
return [
'secrets' => [
'services.database.password' => 'projects/.../secrets/db-password/versions/latest',
'services.stripe.key' => 'projects/.../secrets/stripe-key/versions/latest',
],
];
use Illuminate\Support\Facades\Cache;
$secretValue = Cache::remember('secret_db_password', now()->addHours(1), function () {
$client = app('secret-manager');
$request = (new GetSecretRequest())->setName('projects/.../secrets/db-password/versions/latest');
$secret = $client->getSecret($request);
return base62_decode($secret->getPayload()->getData());
});
// app/Console/Commands/RotateDatabasePassword.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Google\Cloud\SecretManager\V1\AddSecretVersionRequest;
use Google\Cloud\SecretManager\V1\SecretManagerServiceClient;
class RotateDatabasePassword extends Command
{
protected $signature = 'secrets:rotate-db-password';
protected $description = 'Rotate database password in Secret Manager';
public function handle()
{
$client = new SecretManagerServiceClient();
$secretName = 'projects/.../secrets/db-password';
// Generate a new password (e.g., using Laravel's Str::random())
$newPassword = Str::random(32);
// Add new version to Secret Manager
$request = (new AddSecretVersionRequest())
->setParent($secretName)
->setPayload((new \Google\Cloud\SecretManager\V1\SecretPayload())
->setData(base64_encode($newPassword)));
$client->addSecretVersion($request);
// Update Laravel's config cache
Cache::forget('secret_db_password');
$this->info('Database password rotated successfully!');
}
}
app/Console/Kernel.php:
protected function schedule(Schedule $schedule)
{
$schedule->command('secrets:rotate-db-password')->dailyAt('03:00');
}
prod, staging).$environment = app()->environment();
$secretName = sprintf(
'projects/%s/secrets/%s/versions/latest',
config('services.google.project_id'),
$environment === 'production'
? 'prod-db-password'
: 'staging-db-password'
);
$client = app('secret-manager');
$secret = $client->getSecret((new GetSecretRequest())->setName($secretName));
# Grant staging access to the staging secret
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:staging-sa@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor" \
--condition="resource.name.startsWith('projects/YOUR_PROJECT_ID/secrets/staging-')"
use Google\ApiCore\ApiException;
use Illuminate\Support\Facades\Log;
try {
$secret = $client->getSecret($request);
} catch (ApiException $e) {
Log::error('Failed to fetch secret: ' . $e->getMessage(), [
'status' => $e->getStatus()->getCode(),
'details' => $e->getStatus()->getDetails(),
]);
throw new \RuntimeException('Secret retrieval failed. Check logs.');
}
Database Configuration
Use secrets for DB_PASSWORD and DB_USERNAME:
// config/database.php
'connections' => [
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => config('services.database.username'), // Injected via secret-manager
'password' => config('services.database.password'), // Injected via secret-manager
// ...
],
],
Mail Configuration
// config/mail.php
'driver' => env('MAIL_DRIVER', 'smtp'),
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
'port' => env('MAIL_PORT', 587),
'username' => config('services.mail.username'), // From Secret Manager
'password' => config('services.mail.password'), // From Secret Manager
Third-Party Services (Stripe, AWS, etc.)
// config/services.php
'stripe' => [
'key' => config('services.stripe.key'), // From Secret Manager
'secret' => config('services.stripe.secret'), // From Secret Manager
],
Secret Versioning and Rollback
listSecretVersions to track versions and roll back if needed:
$versions = $client->listSecretVersions((new ListSecretVersionRequest())->setParent($secretName));
foreach ($versions as $version) {
if ($version->getName() === 'projects/.../versions/1') {
$client->getSecret((new GetSecretRequest())->setName($version->getName()));
break;
}
}
How can I help you explore Laravel packages today?