constup/aws-secrets-bundle
Symfony bundle that loads parameters from AWS Secrets Manager into the service container. Supports Symfony 5/6 (v1/v2) and requires aws/aws-sdk-php. Configure region/credentials and reference secrets in config for environment-specific setups.
Install Dependencies:
composer require aws/aws-sdk-php constup/aws-secrets-bundle:^1 # For Laravel 9.x (Symfony 5.3+)
composer require aws/aws-sdk-php constup/aws-secrets-bundle:^2 # For Laravel 10.x+ (Symfony 6.0+)
Configure AWS Credentials:
~/.aws/credentials.Add Bundle Configuration:
Create or update config/packages/aws_secrets.yaml (or config/aws_secrets.php for Laravel):
aws_secrets:
client_config:
region: 'us-east-1' # Required if "ignore" is false
version: 'latest'
cache: 'filesystem' # Use 'array' for local dev, 'filesystem' for staging/prod
ignore: false # Set to true for local development
Define Secrets in AWS Secrets Manager:
DB_PASSWORD, STRIPE_API_KEY).{"username": "admin", "password": "secure123"}).Reference Secrets in Laravel:
Update your .env file to reference AWS secrets:
AWS_DB_PASSWORD=my-db-secret,password # Format: secret_name,key (optional)
AWS_STRIPE_KEY=stripe-api-key
Bind secrets in config/services.php (or config/packages/services.yaml):
'parameters' => [
'db.password' => '%env(aws:AWS_DB_PASSWORD)%',
'stripe.key' => '%env(aws:AWS_STRIPE_KEY)%',
],
First Use Case: Fetch a secret dynamically in a Laravel service:
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
class StripeService {
public function __construct(private ParameterBagInterface $params) {}
public function getKey() {
return $this->params->get('stripe.key'); // Resolves to AWS secret
}
}
Environment-Specific Secrets:
dev-db-secret, prod-db-secret).AWS_SECRET variables in .env files for each environment.Nested JSON Secrets:
AWS_FEATURE_FLAGS=feature-flags,enabled_features
config/services.php:
'feature.flags' => '%env(aws:AWS_FEATURE_FLAGS)%', // Returns JSON string
Doctrine Database Connections: Dynamically configure Doctrine connections using AWS secrets:
# config/packages/doctrine.yaml
doctrine:
dbal:
connections:
default:
url: '%env(aws:DB_URL)%' # e.g., AWS_SECRET=db-url,url
Queue/Service Configurations: Inject secrets into queue workers or external services:
// app/Providers/AppServiceProvider.php
public function register() {
$this->app->singleton(SqsClient::class, function ($app) {
return new SqsClient([
'region' => 'us-east-1',
'credentials' => [
'key' => $app['config']['aws.credentials.key'],
'secret' => $app['config']['aws.credentials.secret'],
],
'endpoint' => $app['config']['aws.endpoint'],
]);
});
}
Local Development Workflow:
ignore: true in config/packages/aws_secrets.yaml to bypass AWS calls locally..env.local to override secrets for development:
AWS_DB_PASSWORD=local_db_password # Overrides AWS fetch
Secret Rotation:
CI/CD Integration:
jobs:
deploy:
steps:
- name: Set AWS secrets
run: |
echo "AWS_DB_PASSWORD=$(aws secretsmanager get-secret-value --secret-id prod-db-secret --query SecretString --output text)" >> $GITHUB_ENV
- name: Deploy
run: php artisan deploy
Testing:
array cache for local testing to avoid AWS API calls:
aws_secrets:
cache: 'array'
$this->get('aws_secrets.manager')->shouldReceive('getSecret')
->once()
->andReturn(['SecretString' => 'mocked-secret']);
Laravel-Specific Adjustments:
env() helper:
// app/Providers/AppServiceProvider.php
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
public function boot(ParameterBagInterface $params) {
if (!function_exists('env')) {
function env($key, $default = null) {
return $params->get($key) ?? $default;
}
}
}
Caching Strategies:
filesystem cache to reduce AWS API calls:
aws_secrets:
cache: 'filesystem'
cache_dir: '%kernel.project_dir%/var/aws_secrets_cache'
php artisan cache:clear
Error Handling:
$secret = $this->params->get('db.password');
if (empty($secret)) {
throw new RuntimeException('Database password not configured.');
}
Symfony 6.0+ Adaptations:
HttpClient is configured to work with the bundle’s AWS SDK:
// config/services.php
'http_client' => [
'base_uri' => 'https://example.com',
'aws_sdk' => fn() => new Aws\SecretsManager\SecretsManagerClient([
'region' => 'us-east-1',
'version' => 'latest',
]),
],
AWS SDK Version Conflicts:
aws/aws-sdk-php, ensure the bundle uses the same version to avoid conflicts.composer.json:
"require": {
"aws/aws-sdk-php": "^3.200"
}
Caching Issues:
php artisan cache:clear
aws_secrets:
cache_ttl: 300 # 5 minutes
Local Development Bypass:
ignore: true skips AWS calls but may lead to secrets being hardcoded in .env.local..env.local and document the workflow:
# .env.local
AWS_DB_PASSWORD=local_override # Only for local testing
Symfony Version Mismatches:
v1.x of the bundle.composer why-not to identify conflicts and override dependencies:
composer why-not symfony/dependency-injection:^5.4
Nested JSON Parsing:
secret_name,key.path) return strings. Parse manually:
$secret = json_decode($this->params->get('aws:FEATURE_FLAGS'), true);
IAM Permissions:
secretsmanager:GetSecretValue permissions for the required secrets.{
"Version": "2012-10
How can I help you explore Laravel packages today?