のべラボ.blog

Tech Blog | AWS や サーバーレスやコンテナ などなど

AWS Parameters and Secrets Lambda Extension を試してみる

前回のブログ記事で、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 はリージョンにより異なります。次のドキュメントを参照してください。

docs.aws.amazon.com

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 にすると試しやすいです。ただし、この機能は別途料金がかかるので、注意して下さい!

/* -----codeの行番号----- */