AWS Lambda ( Node.js 18.x ) で AWS System Manager (SSM) パラメータストアのSecureStringの値を利用する

# 公式

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/ps-integration-lambda-extensions.html


# SSM ( AWS Systems Manager ) のパラメータを作成しておく

ここでは

```
testparam
```
というキー名で登録する

# Lambda関数を作成する

AWS上のlocalhostの固定のポートにGETリクエストするという仕組みのようだ

- URLパラメータとしてSSMのパラメータ名を渡す `name=testparam` 
- 秘密値のDecryptのために `withDecryption=true` をURLパラメータとして渡す

リクエストヘッダに `AWS_SESSION_TOKEN` を付与する必要があるが
これはLambda実行ではデフォルトで設定される環境変数のようだ
なので自分で何かを設定する必要はない

## コード例

`index.mjs`

```js
export const handler = async (event) => {
  console.log("START");

  const response = await fetch(
    "http://localhost:2773/systemsmanager/parameters/get?name=testparam&withDecryption=true",
    {
      headers: {
      "X-Aws-Parameters-Secrets-Token": process.env.AWS_SESSION_TOKEN,
      }
    }
  )
  const json = await response.json()
  console.log("VALUE IS ...")
  console.log(json["Parameter"]["Value"])
};

```

# 実行権限の付与

Lambda実行の権限に以下を付与する必要がある

- ssm:GetParameter — Parameter Store からパラメータの取得に必要
- kms:Decrypt — Parameter Store から SecureString パラメータを取得するために必要

Lambdaの実行ロールは Lambda関数の 設定 > アクセス権限から確認できるのでこのロールに権限を付与する


以下はLambda関数を作成した時のデフォルトの権限に ssm / ksm の権限を付与したもの

```json
{
	"Statement": [
		{
			"Action": [
				"logs:CreateLogGroup"
			],
			"Effect": "Allow",
			"Resource": "arn:aws:logs:<REGION>:<ACCOUNT_ID>:*"
		},
		{
			"Action": [
				"ssm:GetParameter"
			],
			"Effect": "Allow",
			"Resource": "arn:aws:ssm:<REGION>:<ACCOUNT_ID>:*"
		},
		{
			"Action": [
				"kms:Decrypt",
				"kms:*"
			],
			"Effect": "Allow",
			"Resource": "arn:aws:ksm:<REGION>:<ACCOUNT_ID>:*"
		},
		{
			"Action": [
				"logs:CreateLogStream",
				"logs:PutLogEvents"
			],
			"Effect": "Allow",
			"Resource": [
				"arn:aws:logs:<REGION>:<ACCOUNT_ID>:log-group:/aws/lambda/<LAMBDA_NAME>:*"
			]
		}
	],
	"Version": "2012-10-17"
}
```

パラメータのキー単位で権限を絞ることもできるようなので必要ならばそうする

# Lambda関数にレイヤーを追加する

この機能は拡張なのでレイヤー追加が必要のようだ

<img width="804" alt="image" src="https://github.com/YumaInaura/YumaInaura/assets/13635059/60b2474e-70c3-4389-a5c8-6037b3b65d2e">

# 実行例

レスポンスとして以下のようなJSONが得られるのでこれをparseして利用すればOK
`["Parameter"]["Value"]` に値が入っている

```json
{
  "Parameter": {
    "ARN": "arn:aws:ssm:<REGION>:<ACCOUNT_ID>:parameter/testparam",
    "DataType": "text",
    "LastModifiedDate": "2023-09-08T04:07:03.546Z",
    "Name": "testparam",
    "Selector": null,
    "SourceResult": null,
    "Type": "SecureString",
    "Value": "xxx",
    "Version": 1
  },
  "ResultMetadata": {}
}
```

# 実行時のエラー

## bad session token or header key

リクエストヘッダのSESSION_KEYが間違っている

## AccessDeniedException - ssm:GetParameter on resource

Lambdaの実行ロールにssm:GetParameterの権限がない場合に起こる

>[AWS Parameters and Secrets Lambda Extension] 2023/09/08 05:01:38 ERROR GetParameter request encountered an error: operation error SSM: GetParameter, https response error StatusCode: 400, RequestID: *********************, api error 
AccessDeniedException: User: arn:aws:sts::***:assumed-role/example-role/xxx is not authorized to perform:ssm:GetParameter on resource: arn:aws:ssm:ap-northeast-1:*********:parameter/testparam because no identity-based policy allows the ssm:GetParameter action

今回ここで少しはまった

原因は(当たり前だが)正しく権限付与が出来ていなかったことだった

Lambdaのデフォルトのポリシーに `ssm:GetParameter` を追加しようと思ってつい `"Resource": "arn:aws:logs` の方に許可を追加してしまっていたが
こちらはlogs用のリソース指定なので ssm の許可をしても意味がなかtgた


```json
{
	"Statement": [
		{
			"Action": [
				"logs:CreateLogGroup",
				"kms:Decrypt",
				"kms:*"
			],
			"Effect": "Allow",
			"Resource": "arn:aws:logs:<REGION>:<ACCOUNT_ID>:*"
		}
	]
}
```

前述の通りResource / Action を正しく指定することで実行可能になった


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura