SSMパラメータストアとは
パスワード、データベース文字列、Amazon Machine Image (AMI) ID、ライセンスコードなどのデータをパラメータ値として保存することができます。
例えば、プログラムからデータベースにアクセスする際に、データベース接続文字列をどこに保管するかが問題になりますが、その保管場所としてパラメータストアはうってつけではないでしょうか。
保存したパラメータの暗号化キーの自動ローテーションの機能が必要な時はSecretManagerが候補に挙がるかと思います。
今回のゴール
パラメータストアは階層(パス)で管理する事ができます。
今回は、
- /dev/db
- /prod/db
の階層を作成して、/dev/のパスにのみ読み取り権限を与えるようにします。
また、データベースの接続情報は重要な情報ですので、SSMのCMK(カスタマーマスターキー)で暗号化してパラメータストアに保存するようにします。
KMSのCMK(カスタマーマスターキー)の作成
データベース文字列を格納しますので、暗号化して保存するために、CMK(カスタマーマスターキー)を作成します。
[KMSサービス]-[キーの作成]とクリックして、デフォルトの状態で「次へ」をクリックします。
[エイリアス]:cmk-parameter-store-test
あとは全てデフォルトの状態で作成を完了しました。
パラメータストアの作成
[SSMサービス]-[パラメータストア]-[パラメータの作成]をクリックします。
[名前]:/dev/db
[タイプ]:安全な文字列
[KMS キー ID]:先ほど作成したCMKを選択
[値]:connection_string_XXXXXXXXXX
同様に、 /prod/dbも作成します。
EC2の設定
IAMロールにポリシーのアタッチ
CMKで暗号化しているので、下記の復号するためのポリシーをアタッチします。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey*"
],
"Resource": "(your KMS key ARN)"
}
]
}
パラメータストアのdevのパスのみ読み取り可のポリシーをアタッチします。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:DescribeParameters"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ssm:GetParameters"
],
"Resource": "arn:aws:ssm:ap-northeast-1:(your account ID):parameter/dev*"
}
]
}
PHPのインストール
手順は省略しますが、
必要であれば過去の記事をご参照ください。
PHPファイルの作成
今回は下記のファイルを作成しました。
ハイライトされている行は後で変更する箇所です。
<?php
require 'vendor/autoload.php';
use Aws\Ssm\SsmClient;
use Aws\Exception\AwsException;
function getParameters(array $names)
{
$client = new SsmClient([
'region' => 'ap-northeast-1',
'version' => '2014-11-06',
]);
$result = $client->getParameters(
[
'Names' => $names,
'WithDecryption' => true
]
);
echo $result;
$params = [];
foreach ($result['Parameters'] as $v) {
$name = $v['Name'];
$params[$name] = $v['Value'];
}
return $params;
}
try {
$params = getParameters(['/dev/db']);
var_dump($params);
} catch (AwsException $e) {
var_dump('---AwsException---');
error_log($e->getMessage());
} catch (Exception $e) {
var_dump('---Exception---');
error_log($e->getMessage());
}
確認
get-parameters.phpを実行すると、パラメータが取得できました。
php get-parameters.php
{
"Parameters": [
{
"Name": "\/dev\/db",
"Type": "SecureString",
"Value": "connection_string_XXXXXXXXXX",
"Version": 3,
"LastModifiedDate": "2021-11-13T09:40:09+00:00",
"ARN": "arn:aws:ssm:ap-northeast-1:000000000000:parameter\/dev\/db",
"DataType": "text"
}
],
"InvalidParameters": [],
"@metadata": {
"statusCode": 200,
"effectiveUri": "https:\/\/ssm.ap-northeast-1.amazonaws.com",
"headers": {
"x-amzn-requestid": "635e49cf-8f2d-4440-89af-85a2f5272ef0",
"content-type": "application\/x-amz-json-1.1",
"content-length": "249",
"date": "Sat, 13 Nov 2021 03:37:59 GMT"
},
"transferStats": {
"http": [
[]
]
}
}
}
array(1) {
["/dev/db"]=>
string(28) "connection_string_XXXXXXXXXX"
}
次に”/dev/xxx”のように、dev内の存在しないパスを get-parameters.phpを変更して実行します。
$params = getParameters(['/dev/db', '/dev/xxx']);
すると、InvalidParametersに “/dev/xxx”がセットされてました。
{
"Parameters": [
{
"Name": "\/dev\/db",
"Type": "SecureString",
"Value": "connection_string_XXXXXXXXXX",
"Version": 3,
"LastModifiedDate": "2021-11-13T09:40:09+00:00",
"ARN": "arn:aws:ssm:ap-northeast-1:000000000000:parameter\/dev\/db",
"DataType": "text"
}
],
"InvalidParameters": [
"\/dev\/xxx"
],
"@metadata": {
"statusCode": 200,
"effectiveUri": "https:\/\/ssm.ap-northeast-1.amazonaws.com",
"headers": {
"x-amzn-requestid": "a15c3baa-b1a9-49de-8acc-904f33a04fd2",
"content-type": "application\/x-amz-json-1.1",
"content-length": "259",
"date": "Sat, 13 Nov 2021 03:50:40 GMT"
},
"transferStats": {
"http": [
[]
]
}
}
}
array(1) {
["/dev/db"]=>
string(28) "connection_string_XXXXXXXXXX"
}
最後に権限のない’/prod/db’を追加して実行します。
$params = getParameters(['/dev/db', '/dev/xxx', '/prod/db']);
すると、AwsExceptionの例外が発生して、AccessDeniedExceptionとなっておりました。
string(18) "---AwsException---"
Error executing "GetParameters" on "https://ssm.ap-northeast-1.amazonaws.com"; AWS HTTP error: Client error: `POST https://ssm.ap-northeast-1.amazonaws.com` resulted in a `400 Bad Request` response:
{"__type":"AccessDeniedException","Message":"User: arn:aws:sts::000000000000:assumed-role/ec2_sqs_test/i-000000000000 (truncated...)
AccessDeniedException (client): User: arn:aws:sts::000000000000:assumed-role/ec2_sqs_test/i-000000000000 is not authorized to perform: ssm:GetParameters on resource: arn:aws:ssm:ap-northeast-1:000000000000:parameter/prod/db because no identity-based policy allows the ssm:GetParameters action - {"__type":"AccessDeniedException","Message":"User: arn:aws:sts::000000000000:assumed-role/ec2_sqs_test/i-000000000000 is not authorized to perform: ssm:GetParameters on resource: arn:aws:ssm:ap-northeast-1:000000000000:parameter/prod/db because no identity-based policy allows the ssm:GetParameters action"}