前回のブログ記事で、AWS Parameters and Secrets Lambda Extension のドキュメントの記載の注意点について説明しましたが、今回は AWS CLI を主体としてシンプルに試す手順を説明します。
なお、この記事の内容は 2022年 10月 23日時点のものになります。
まず、Lambda 関数からアクセスする Secrets Manager のシークレットを作成します。
aws secretsmanager create-secret \ --name MyTestSecret \ --description "My test secret created with the CLI." \ --secret-string "{\"user\":\"admin\",\"password\":\"admin1234\"}"
次に、Lambda関数の実行ロールを作成し、ポリシーをアタッチします。
なお、今回はサンプルのため管理ポリシーとして SecretsManagerReadWrite を設定していますが、実際は最小限の権限に絞ったポリシーを設定して下さい。
aws iam create-role --role-name my-function-role --assume-role-policy-document '{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}' aws iam attach-role-policy --role-name my-function-role --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole aws iam attach-role-policy --role-name my-function-role --policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite
次に Lambda 関数のコードを用意します。 今回は、ラインタイムとして Python 3.9 の関数のコードを my-function.py に保存します。
import json import os import urllib.request secrets_extension_http_port = os.environ.get('PARAMETERS_SECRETS_EXTENSION_HTTP_PORT',"2773") # default 2773 def lambda_handler(event, context): # TODO implement secret_name = os.environ.get('MY_SECRET_NAME') secrets_extension_endpoint = "http://localhost:" + \ secrets_extension_http_port + \ "/secretsmanager/get?secretId=" + \ secret_name req = urllib.request.Request(secrets_extension_endpoint) req.add_header('X-Aws-Parameters-Secrets-Token', os.environ.get('AWS_SESSION_TOKEN')) with urllib.request.urlopen(req) as res: secret = json.loads(res.read())['SecretString'] user = json.loads(secret)['user'] return { 'statusCode': 200, 'body': user }
このコードをみるとわかるように、Paramerer Store や Secrets Manager の値は、内部に構成された Web サーバーに対してリクエストを送ることで取得できます。
リクエストには、X-Aws-Parameters-Secrets-Token ヘッダで、環境変数の AWS_SESSION_TOKEN の値をセットします。
このコードのファイルを zip 化します。
zip my-function.zip my-function.py
次に Lamnda関数を作成します。ここでは、AWS アカウント ID は すべて 0 にしています。
aws lambda create-function --function-name my-function \ --zip-file fileb://my-function.zip --handler my-function.lambda_handler --runtime python3.9 \ --role arn:aws:iam::000000000000:role/my-function-role
次に、この Lambda 関数に AWS Parameters and Secrets Lambda Extension の Lambda レイヤーを設定します。
レイヤーの ARN はリージョンにより異なります。次のドキュメントを参照してください。
aws lambda update-function-configuration --function-name my-function \ --layers arn:aws:lambda:ap-northeast-1:133490724326:layer:AWS-Parameters-and-Secrets-Lambda-Extension:2
また、今回は Secrets Manager のシークレット名を環境変数で渡す前提にしているので、Lambda 関数に環境変数を設定します。
aws lambda update-function-configuration \ --function-name my-function \ --environment Variables='{MY_SECRET_NAME="MyTestSecret"}' \
では、Lambda 関数を実行してみます。
aws lambda invoke --function-name my-function response.json cat response.json
次の出力例のように、body に Secrets Manager のシークレットで格納していた user の値である admin が表示されればOKです。
{"statusCode": 200, "body": "admin"}
キャッシュの機能を試したい場合は、次のような手順で試します。
Lambda 関数に SECRETS_MANAGER_TTL の環境変数 で 120 秒ほど設定します。
Lambda 関数を実行して値を取得します。
その後、すぐに Secrets Manager の値を変更します。
Lambda 関数を実行を繰り返して、何度も値を取得し続けます。
すると、2 分経過するまでは、変更前の値が取得されますが、2 分経過後は新しい値が取得されます。
このキャッシュ機能を試すには、作成されたLambda 関数の実行環境を維持する必要があるので、Lambda関数のバージョンを作成し、「プロビジョニングされた同時実行」を 1 にすると試しやすいです。ただし、この機能は別途料金がかかるので、注意して下さい!