Using AWS Secrets Manager with Yii2
AWS Secrets Manager is used manage, retrieve, and rotate database credentials, API keys, and other secrets throughout their lifecycles.
Prerequisites
- PHP >= 7.4
- PHP apcu module should be installed (this can be checked using
php -m | grep "apcu"
). - AWS crededtial with Secrets manager access or server with secrets manager IAM role attached.
Usage
For this tutorial we'll assume that the following key-value secrets are already stored in the secrets manager:
{
"DB_USER_UIMS": "",
"DB_PASS_UIMS": "",
"DB_HOST_UIMS": "",
"DB_NAME_UIMS": "",
"DB_HOST_RO_UIMS": ""
}
There could be more key-value secrets based on the requirement.
Creating config file
Create a _conf.php
file in the config
folder
<?php
use Aws\Exception\AwsException;
use Aws\SecretsManager\SecretsManagerClient;
$secretName ='<secret name>';
// Checking apcu cache for stored secret
$secret = apcu_fetch($secretName);
// if secret is not cached, get the secret by calling the secrets manager SDK
if (!$secret) {
try {
$client = new SecretsManagerClient([
'version' => 'latest',
'region' => '<aws region>'
]);
$result = $client->getSecretValue([
'SecretId' => $secretName,
]);
} catch (AwsException $e) {
$error = $e->getAwsErrorCode();
if ($error == 'DecryptionFailureException') {
// Secrets Manager can't decrypt the protected secret text using the provided AWS KMS key.
// Handle the exception here, and/or rethrow as needed.
throw $e;
}
if ($error == 'InternalServiceErrorException') {
// An error occurred on the server side.
// Handle the exception here, and/or rethrow as needed.
throw $e;
}
if ($error == 'InvalidParameterException') {
// You provided an invalid value for a parameter.
// Handle the exception here, and/or rethrow as needed.
throw $e;
}
if ($error == 'InvalidRequestException') {
// You provided a parameter value that is not valid for the current state of the resource.
// Handle the exception here, and/or rethrow as needed.
throw $e;
}
if ($error == 'ResourceNotFoundException') {
// We can't find the resource that you asked for.
// Handle the exception here, and/or rethrow as needed.
throw $e;
}
}
// Decrypts secret using the associated KMS CMK.
// Depending on whether the secret is a string or binary, one of these fields will be populated.
if (isset($result['SecretString'])) {
$secret = $result['SecretString'];
} else {
$secret = base64_decode($result['SecretBinary']);
}
$secret = json_decode($secret, true);
// store the secret in cache for 1 week
apcu_store($secretName, $secret, 604800);
}
return $secret;
tip
This _conf.php
file can be imported wherever the secrets are required.
Updating the existing DB file
Update the existing db.php
and rest of the DB files according to the following snippet:
<?php
$conf = require (__DIR__."/_conf.php");
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host='.$conf["DB_HOST_UIMS"].';dbname='.$conf["DB_NAME_UIMS"],
'username' => $conf["DB_USER_UIMS"],
'password' => $conf["DB_PASS_UIMS"],
'charset' => 'utf8mb4',
'enableSchemaCache' => true,
'schemaCacheDuration' => 3600,
'schemaCache' => 'cache',
'slaveConfig' => [
'username' => $conf["DB_USER_UIMS"],
'password' => $conf["DB_PASS_UIMS"],
'charset' => 'utf8mb4',
'attributes' => [
PDO::ATTR_TIMEOUT => 10,
],
],
// list of slave configurations
'slaves' => [
[
'dsn' => 'mysql:host='.$conf["DB_HOST_RO_UIMS"].';dbname='.$conf["DB_NAME_UIMS"],
]
]
];