📝

AWS Secrets Manager Agent を Lambda で使ってみた

2025/01/18に公開

aws/aws-secretsmanager-agent: The AWS Secrets Manager Agent is a local HTTP service that you can install and use in your compute environments to read secrets from Secrets Manager and cache them in memory.

Lambda で使用するパターンを試してみました。

前提

  • Lambda 実行ロール用の IAM ロールを作成済みであること
    • AdministratorAccess 権限を付与
  • コマンド実行環境は Cloud9
    • インスタンスタイプは m5.large (ビルドでのメモリ不足回避のため)
  • Secrets Manager のシークレットを作成済みであること

手順概要

  1. リポジトリのクローン
  2. Secrets Manager Agent のビルド
  3. Lambda 関数の作成
  4. Lambda レイヤー作成
  5. 動作確認

1. リポジトリのクローン

1-1. リポジトリをクローンします。

$ git clone https://github.com/aws/aws-secretsmanager-agent.git

1-2. aws-secretsmanager-agent ディレクトに移動します。

$ cd aws-secretsmanager-agent

2. Secrets Manager Agent のビルド

今回は Amazon Linux 2023 の Cloud9 環境を作成したので、[ RPM-based systems ] の手順でビルドします。

2-1. Development Tools をインストールします。

$ sudo yum -y groupinstall "Development Tools"

2-2. Rust をインストールします。

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Follow the on-screen instructions

# デフォルトの 1 でインストールしました。
1) Proceed with standard installation (default - just press enter)
2) Customize installation
3) Cancel installation

$ . "$HOME/.cargo/env"

2-3. エージェントをビルドします。

$ cargo build --release

3. Lambda 関数の作成

AWS CLI で作成しますが、コンソールから作成しても問題ありません。

3-1. Python ファイルを作成します。
<YOUR_SECRET_ID> を Secrets Manager シークレット名に置換してください。

$ cd ..

$ nano lambda_function.py

# 以下のコードを書き込みます。
import requests
import json
import time
import os

# Function that fetches the secret from Secrets Manager Agent for the provided secret id. 
def lambda_handler(event, context):

    # Construct the URL for the GET request
    url = f"http://localhost:2773/secretsmanager/get?secretId=<YOUR_SECRET_ID>"

    headers = {
        "X-Aws-Parameters-Secrets-Token": os.environ.get('AWS_SESSION_TOKEN').strip()
    }

    retries = 3
    delay = 5

    for attempt in range(retries):
        try:
            # Send the GET request with headers
            response = requests.get(url, headers=headers)

            # Check if the request was successful
            if response.status_code == 200:
                # Return the secret value
                return response.text
            else:
                # Handle error cases
                raise Exception(f"Status code {response.status_code} - {response.text}")

        except Exception as e:
            if attempt < retries - 1:
                time.sleep(delay)
            else:
                # Handle network errors
                raise Exception(f"Error: {e}")

3-2. Python ファイルを zip 化します。

$ zip code.zip lambda_function.py

3-3. create-function コマンドを実行します。

$ aws lambda create-function \
--function-name SecretsManagerAgent \
--handler lambda_function.lambda_handler \
--runtime python3.13 \
--role your-role-arn \
--zip-file fileb://code.zip \
--timeout 30 \
--memory-size 512

4. Lambda レイヤー作成

レイヤーは Secrets Manager Agent 用と requests モジュール用に 2 つ作成します。

4-1. Secrets Manager Agent 用レイヤー作成

GitHub の Step 2: Install the Secrets Manager Agent の [ AWS Lambda ] のコマンドを実行します。

$ AWS_ACCOUNT_ID=<AWS_ACCOUNT_ID>
$ LAMBDA_ARN=<LAMBDA_ARN>

$ cd aws-secretsmanager-agent

# Build the release binary 
$ cargo build --release --target=x86_64-unknown-linux-gnu

# Copy the release binary into the `bin` folder
$ mkdir -p ./bin
$ cp ./target/x86_64-unknown-linux-gnu/release/aws_secretsmanager_agent ./bin/secrets-manager-agent

# Copy the `secrets-manager-agent-extension.sh` example script into the `extensions` folder.
$ mkdir -p ./extensions
$ cp aws_secretsmanager_agent/examples/example-lambda-extension/secrets-manager-agent-extension.sh ./extensions

# Zip the extension shell script and the binary 
$ zip secrets-manager-agent-extension.zip bin/* extensions/*

# Publish the layer version
$ LAYER_VERSION_ARN=$(aws lambda publish-layer-version \
--layer-name secrets-manager-agent-extension \
--zip-file "fileb://secrets-manager-agent-extension.zip" | jq -r '.LayerVersionArn')

4-2. requests モジュール用レイヤー作成

$ cd ..; mkdir python; cd python

$ pip install requests -t .

$ cd ..

$ zip -r python.zip python

$ aws lambda publish-layer-version \
--layer-name python-requests \
--zip-file fileb://python.zip

# レスポンスの LayerVersionArn は以降の手順で使用するため控えておいてください。

4-3. Lambda 関数にレイヤーを追加

Max length char of 140 for layers arn in lambda update-function-configuration --layers command · Issue #8426 · aws/aws-cli

update-function-configuration コマンドの制限で 2 つのレイヤーを同時に指定した場合にレイヤー名の文字数制限に抵触するため、requests モジュール用レイヤーはコンソールから追加します。

Secrets Manager Agent 用レイヤーは GitHub の以下のコマンドで追加します。

$ aws lambda update-function-configuration \
--function-name $LAMBDA_ARN \
--layers "$LAYER_VERSION_ARN"

requests モジュール用レイヤーはコンソールから追加します。

4-2 で取得した LayerVersionArn を指定して追加します。

5. 動作確認

AWS CLI の invoke コマンドまたは Lambda コンソール上からテスト実行して動作確認します。

$ aws lambda invoke \
--function-name SecretsManagerAgent \
response.json > /dev/null && cat response.json

# 以下のようなレスポンスを取得できれば成功です。
"{\"ARN\":\"arn:aws:secretsmanager:ap-northeast-1:012345678901:secret:test-xxx\",\"Name\":\"test\",\"VersionId\":\"c05621eb-b4ec-4c0a-aa88-767bb6d8930a\",\"SecretString\":\"{\\\"key\\\":\\\"value\\\"}\",\"VersionStages\":[\"AWSCURRENT\"],\"CreatedDate\":\"1737073840.909\"}

CloudTrail で GetSecretValue の記録を確認したところ、Lambda 実行ロールの認証情報を使用して Secrets Manager Agent が GetSecretValue を実行していることも確認できました。

GetSecretValue
{
    "eventVersion": "1.11",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "xxx:SecretsManagerAgent",
        "arn": "arn:aws:sts::012345678901:assumed-role/LambdaBasicExecutionRole/SecretsManagerAgent",
        "accountId": "012345678901",
        "accessKeyId": "xxx",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "xxx",
                "arn": "arn:aws:iam::012345678901:role/LambdaBasicExecutionRole",
                "accountId": "012345678901",
                "userName": "LambdaBasicExecutionRole"
            },
            "attributes": {
                "creationDate": "2025-01-17T08:02:31Z",
                "mfaAuthenticated": "false"
            }
        },
        "inScopeOf": {
            "issuerType": "AWS::Lambda::Function",
            "credentialsIssuedTo": "arn:aws:lambda:ap-northeast-1:012345678901:function:SecretsManagerAgent"
        }
    },
    "eventTime": "2025-01-17T08:02:37Z",
    "eventSource": "secretsmanager.amazonaws.com",
    "eventName": "GetSecretValue",
    "awsRegion": "ap-northeast-1",
    "sourceIPAddress": "3.115.88.245",
    "userAgent": "aws-sdk-rust/1.3.3 os/linux lang/rust/1.84.0 aws-secrets-manager-agent/1.0.1",
    "requestParameters": {
        "secretId": "test"
    },
    "responseElements": null,
    "requestID": "ecf6f6ab-37e8-48ae-ac0b-5df961b7611c",
    "eventID": "37cc8c7b-3ff0-4fa0-a9fe-3b30a2f82083",
    "readOnly": true,
    "eventType": "AwsApiCall",
    "managementEvent": true,
    "recipientAccountId": "012345678901",
    "eventCategory": "Management",
    "tlsDetails": {
        "tlsVersion": "TLSv1.3",
        "cipherSuite": "TLS_AES_128_GCM_SHA256",
        "clientProvidedHostHeader": "secretsmanager.ap-northeast-1.amazonaws.com"
    }
}

注意事項

AWS Secrets Manager Agent - AWS Secrets Manager

Lambda を使用する場合の上記ドキュメントの手順と冒頭の GitHub の手順が異なりますが、本ブログ執筆時点では GitHub 側の情報が最新です。

まとめ

今回は AWS Secrets Manager Agent を Lambda で使ってみました。
どなたかの参考に慣れば幸いです。

参考資料

Discussion