🔐

Cargo Lambda で Lambda layer を使って Parameter Store から値を取得する

2025/02/23に公開

内容

AWS 公式が用意している Lambda から Parameter StoreSecrets Manager から値を取得する方法を RustCargo Lambda で説明する。

Lambda で Parameter Store などから何かシークレットを取得するとき AWS SDK でパラメーターを取得することはできる。しかし、頻繁に呼び出される Lambda の場合はクォータに引っかかり、値が取得できなくなってしまう。
シンプルに解決するなら Lambda の環境変数に突っ込んでしまえばいいのだが CloudFormation や Lambda のコンソールの画面で値が見えてしまう。組織などの運用であればこれ健全ではない。
Lambda はキャッシュすることもできるのでグローバルな環境変数に1度保存しておけば毎回リクエストすることは無くなる。しかし、パラメーターを変更したときなどのリフレッシュの頻度は制御が難しい。

以上の問題を解決する方法として AWS が用意しているのが AWS Parameters and Secrets Lambda Extension という Lambda extensions を設定できる Lambda layers である。

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

これを実現するための手順とサンプルを示す。

https://github.com/Creanciel/ZennCargoLambdaParameterStore

AWS Parameters and Secrets Lambda Extension とは

シンプルに言えば Lambda に張り付けるとわざわざ SDK を入れなくても Parameter Store などの値を取得し、さらにキャッシュを行ってくれる。
パラメーターの取得の仕方はシンプルで localhost に対して取得したい値のキーをリクエストするだけで良い。

例えば Parameter Store に "/lambda" (1単語だと Parameter Store では / が表示されない模様) というキーで保存した値を取得したい場合、

http://localhost:2773/systemsmanager/parameters/get?name=%2Flambda

というような HTTP Request をするだけで取得できる。

header に取得しなければいけない値であったり、 ポートがデフォルトは 2773 であったり、詳細は公式ドキュメントで。ちなみに Secret Manager も Parameter Store も手順は同様だがリクエスト URL が違っている。

https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html

手順

はじめに

Lambda extensions に対しては前述通り HTTP Request をしなければならなくなる。
Cargo Lambda でやるのなら reqwest などであろう。これを愚直に追加すると OpenSSL の依存関係などで途端にビルドできなくなったり、動かなかったりする。
これに関しては別の記事を参考にされたい。

https://zenn.dev/creanciel/articles/cargo-lambda

環境変数の取得

基本的には Lambda の環境変数から AWS_SESSION_TOKEN が取得さえできればいい。サンプルではポートを変更する想定もされているが別にしなくていい。

environment details
AWS_SESSION_TOKEN からリクエストのヘッダーに必要な値を取得する。
PARAMETERS_SECRETS_EXTENSION_HTTP_PORT Lambda extensions と喋るためのポート (デフォルトが2773)

https://github.com/Creanciel/ZennCargoLambdaParameterStore/blob/776bce17b10788ca91a78b3f74eb313143ab77ed/app/src/secrets.rs#L52-L55

リクエストURLの作成

先ほど取得したポートをいれている。サンプルは Parameter Store の値を取得するもの。前述通り Secrets Manager の場合は少し URL が違うので注意。

そしてクエリパラメーターで値を設定している。

environment details
name パラメーターストアに保存したキー。
withDecryption パラメーターストアの値が SecureString (安全な文字列) の場合は必要

エスケープなどが面倒なので直接 format! などで文字列を作るより reqwest に任せてしまうのがいいだろう。
withDecryption はそもそも Parameter Store を使うのならつけるだろうか。固定の値であるならば基本的には Lambda の環境変数にしてしまったほうがレイテンシーが少なくていいはず。

https://github.com/Creanciel/ZennCargoLambdaParameterStore/blob/776bce17b10788ca91a78b3f74eb313143ab77ed/app/src/secrets.rs#L57-L65

レスポンス

HTTP Request のレスポンスの型を次のように定義している。

https://github.com/Creanciel/ZennCargoLambdaParameterStore/blob/776bce17b10788ca91a78b3f74eb313143ab77ed/app/src/secrets.rs#L67-L77

実際のレスポンスは次のようなものらしい。

実際に必要な値は ".Parameter.Value" のみなので struct の定義は絞っている。

{
    "Parameter": {
        "ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/<PARAMETER_NAME>",
        "DataType": "text",
        "LastModifiedDate": "2025-01-01T00:00:00.000Z",
        "Name": "<PARAMETER_NAME>",
        "Selector": null,
        "SourceResult": null,
        "Type": "SecureString",
        "Value": "<PARAMETER_VALUE>",
        "Version": 1
    },
    "ResultMetadata": {}
}

ちなみに値がないときのレスポンスは

an unexpected error occurred while executing request

となり JSON ではないらしい。パースできないので大丈夫であろう。

リクエスト

ヘッダーに X-Aws-Parameters-Secrets-Token というキーで最初に環境変数から取得した AWS_SESSION_TOKEN をいれてリクエストしている。

https://github.com/Creanciel/ZennCargoLambdaParameterStore/blob/776bce17b10788ca91a78b3f74eb313143ab77ed/app/src/secrets.rs#L79-L89

CDK

Lambda layer

layer を AWS 公式が準備した既存の Arn から作成して Lambda に付与している。

https://github.com/Creanciel/ZennCargoLambdaParameterStore/blob/776bce17b10788ca91a78b3f74eb313143ab77ed/cdk/lib/cdk-stack.ts#L10-L11
https://github.com/Creanciel/ZennCargoLambdaParameterStore/blob/776bce17b10788ca91a78b3f74eb313143ab77ed/cdk/lib/cdk-stack.ts#L81-L107

ここで使われる AWS 公式の Lambda extensions の Arn は リージョンアーキテクチャー によって異なっている。
サンプルでは us-east-1arm を使っている。
ドキュメントに載っているので確認して対応するものを使う。

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

Lambda Policy

あと気を付ける点で言うと ssm:GetParameter のポリシーが必要。 SecureString をデクリプトするために kms:Decrypt も必要かもしれない。権限は適宜絞ること。

https://github.com/Creanciel/ZennCargoLambdaParameterStore/blob/776bce17b10788ca91a78b3f74eb313143ab77ed/cdk/lib/cdk-stack.ts#L64-L79

まとめ

Cargo Lambda で AWS Parameters and Secrets Lambda Extension を使い、 Parameter Store の値を取得する手順とサンプルを紹介した。
手順は少し込み入っているが実際に慣れてしまうとコードからはただ HTTP Request を飛ばすだけなので結構楽なものである。

近年は GitHub Copilot などの利用により、ソースコードが学習されるという危険をはらんでいる。なあなあでクレデンシャルがコード上に存在するのは特に危険な状態になってきた。

秘匿しなければならない情報は正しく秘匿し、保存して安全な運用を心掛けていきたい。

Discussion