AWS Secrets Manager 代理人 - AWS Secrets Manager

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

AWS Secrets Manager 代理人

AWS Secrets Manager 代理是一项客户端HTTP服务,可用于在亚马逊弹性容器服务 AWS Lambda、亚马逊弹性容器服务、亚马逊弹性 Kubernetes Service 和亚马逊弹性计算云等环境中标准化 Secrets Manager 机密的使用。Secrets Manager 代理可以在内存中检索和缓存密钥,以便您的应用程序可以直接使用缓存中的密钥。这意味着您可以从本地主机获取应用程序所需的密钥,而不是调用 Secrets Manager。Secrets Manager Agent 只能向 Secrets Manager 发出读取请求,而无法修改密钥。

Secrets Manager Agent 使用你在环境中提供的 AWS 凭据来调用 Secrets Manager。Secrets Manager Agent 提供针对服务器端请求伪造 (SSRF) 的保护,以帮助提高机密安全性。您可以通过设置最大连接数、生存时间 (TTL)、本地主机HTTP端口和缓存大小来配置 Secrets Manager 代理。

由于 Secrets Manager 代理使用内存缓存,因此它会在 Secrets Manager 代理重启时重置。Secrets Manager 代理会定期刷新缓存的密钥值。当你在 Secrets Manager 代理过期后尝试从 Secrets Manager 代理读取密钥时,TTL就会发生刷新。默认刷新频率 (TTL) 为 300 秒,您可以使用--config命令行参数将其传递给 Secrets Manager Agent 来更改刷新频率。配置文件Secrets Manager 代理不包括缓存失效。例如,如果密钥在缓存条目过期之前轮换,则 Secrets Manager 代理可能会返回过时的密钥值。

Secrets Manager 代理返回的密钥值与 GetSecretValue 的响应格式相同。密钥值在缓存中未进行加密。

要下载源代码,请参阅https://github.com/aws/aws-secretsmanager-agent上的 GitHub。

步骤 1:构建 Secrets Manager 代理二进制文件

要在本机构建 Secrets Manager 代理二进制文件,您需要标准开发工具和 Rust 工具。或者,您可以为支持它的系统进行交叉编译,也可以使用 Rust 进行交叉编译。

RPM-based systems
  1. 在RPM基于 AL2 023 的系统上,您可以使用开发工具组来安装开发工具。

    sudo yum -y groupinstall "Development Tools"
  2. 按照 Rust 文档安装 Rust 的说明进行操作。

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh . "$HOME/.cargo/env"
  3. 使用 cargo build 命令构建代理:

    cargo build --release

    您将在 target/release/aws-secrets-manager-agent 下找到可执行文件。

Debian-based systems
  1. 在基于 Debian 的系统(例如 Ubuntu)上,您可以使用 build-essential 包安装开发人员工具。

    sudo apt install build-essential
  2. 按照 Rust 文档安装 Rust 的说明进行操作。

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh . "$HOME/.cargo/env"
  3. 使用 cargo build 命令构建代理:

    cargo build --release

    您将在 target/release/aws-secrets-manager-agent 下找到可执行文件。

Windows

要在 Windows 上构建,请按照 Microsoft Windows 文档中的 Set up your dev environment on Windows for Rust 中的说明进行操作。

Cross-compile natively

在 mingw-w64 包可用的发行版(例如 Ubuntu)上,您可以在本机进行交叉编译。

# Install the cross compile tool chain sudo add-apt-repository universe sudo apt install -y mingw-w64 # Install the rust build targets rustup target add x86_64-pc-windows-gnu # Cross compile the agent for Windows cargo build --release --target x86_64-pc-windows-gnu

您将在 target/x86_64-pc-windows-gnu/release/aws-secrets-manager-agent.exe 处找到可执行文件。

Cross compile with Rust cross

如果系统本身没有交叉编译工具,则可以使用 Rust 交叉项目。有关更多信息,请参阅 c https://github.com/cross-rs/ross

重要

我们建议为构建环境提供 32GB 的磁盘空间。

# Install and start docker sudo yum -y install docker sudo systemctl start docker sudo systemctl enable docker # Make docker start after reboot # Give ourselves permission to run the docker images without sudo sudo usermod -aG docker $USER newgrp docker # Install cross and cross compile the executable cargo install cross cross build --release --target x86_64-pc-windows-gnu

步骤 2:安装 Secrets Manager 代理

根据计算类型,您可以通过多种方式安装 Secrets Manager 代理。

Amazon EKS, Amazon EC2, and Amazon ECS
安装 Secrets Manager 代理
  1. 使用存储库中提供的 install 脚本。

    该脚本在启动时生成一个随机SSRF令牌并将其存储在文件中/var/run/awssmatoken。安装脚本创建的 awssmatokenreader 组可以读取该令牌。

  2. 要允许您的应用程序读取令牌文件,您需要将应用程序在其下运行的用户账户添加到 awssmatokenreader 组。例如,您可以使用以下 usermod 命令授予应用程序读取令牌文件的权限,其中<APP_USER>是运行应用程序的用户 ID。

    sudo usermod -aG awssmatokenreader <APP_USER>
Docker

您可以使用 Docker 将 Secrets Manager 代理作为附加容器与应用程序一起运行。然后,您的应用程序可以从 Secrets Manager 代理提供的本地HTTP服务器中检索密钥。有关 Docker 的信息,请参阅 Docker 文档

使用 Docker 为 Secrets Manager 代理创建附加容器
  1. 为 Secrets Manager 代理附加容器创建 Dockerfile。以下示例使用 Secrets Manager 代理二进制文件创建一个 Docker 容器。

    # Use the latest Debian image as the base FROM debian:latest # Set the working directory inside the container WORKDIR /app # Copy the Secrets Manager Agent binary to the container COPY secrets-manager-agent . # Install any necessary dependencies RUN apt-get update && apt-get install -y ca-certificates # Set the entry point to run the Secrets Manager Agent binary ENTRYPOINT ["./secrets-manager-agent"]
  2. 为您的客户端应用程序创建一个 Dockerfile。

  3. 创建 Docker Compose 文件来运行两个容器,确保它们使用相同的网络接口。这是必要的,因为 Secrets Manager 代理不接受来自本地主机接口之外的请求。以下示例显示了一个 Docker Compose 文件,其中 network_mode 键将 secrets-manager-agent 容器附加到 client-application 容器的网络命名空间,这允许它们共享相同的网络接口。

    重要

    您必须加载 AWS 凭据和SSRF令牌,应用程序才能使用 Secrets Manager 代理。请参阅以下内容:

    version: '3' services: client-application: container_name: client-application build: context: . dockerfile: Dockerfile.client command: tail -f /dev/null # Keep the container running secrets-manager-agent: container_name: secrets-manager-agent build: context: . dockerfile: Dockerfile.agent network_mode: "container:client-application" # Attach to the client-application container's network depends_on: - client-application
  4. secrets-manager-agent 二进制文件复制到包含您的 Dockerfile 和 Docker Compose 文件的同一个目录中。

  5. 使用以下 docker-compose 命令基于提供的 Dockerfile 构建和运行容器。

    docker-compose up --build
  6. 在您的客户端容器中,您现在可使用 Secrets Manager 代理来检索密钥。有关更多信息,请参阅 第 3 步:使用 Secrets Manager 代理检索密钥

AWS Lambda

你可以将 S ecrets Manager 代理打包为 AWS Lambda 扩展。然后,您可以将其作为层添加到 Lambda 函数中,并从 Lambda 函数调用 Secrets Manager 代理来获取密钥。

以下说明说明如何使用secrets-manager-agent-extension.sh中的示例脚本将 Secret MyTest s Manager 代理作为 Lambda 扩展进行安装,https://github.com/aws/aws-secretsmanager-agent从而获取名为的密钥。

注意

该示例脚本使用 curl 命令,该命令包含在基于 Amazon Linux 2023 的运行时(例如 Python 3.12 和 Node.js 20)中。如果使用基于 Amazon Linux 2 的运行时环境(例如 Python 3.11 或 Node.js 18),则必须先在 Lambda 容器映像中安装 curl。有关说明,请参阅 re: Post 上AWS 如何使用 Amazon Linux 2 AMI 原生二进制包和 Lambda

创建打包 Secrets Manager 代理的 Lambda 扩展
  1. 创建一个 Python Lambda 函数,用于查询 http://localhost:2773/secretsmanager/get?secretId=MyTest 以获取密钥。务必在应用程序代码中实现重试逻辑,以适应 Lambda 扩展初始化和注册中的延迟。

  2. 从 Secrets Manager 代理代码包的根目录运行以下命令来测试 Lambda 扩展。

    AWS_ACCOUNT_ID=<AWS_ACCOUNT_ID> LAMBDA_ARN=<LAMBDA_ARN> # 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` 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') # Attach the layer version to the Lambda function aws lambda update-function-configuration \ --function-name $LAMBDA_ARN \ --layers "$LAYER_VERSION_ARN"
  3. 调用 Lambda 函数以验证是否已正确获取密钥。

第 3 步:使用 Secrets Manager 代理检索密钥

要使用代理,请调用本地 Secrets Manager 代理端点,并将密钥ARN的名称或作为查询参数包括在内。默认情况下,Secrets Manager 代理会检索密钥的 AWSCURRENT 版本。要检索其他版本,您可以设置 versionStageversionId

为了帮助保护 Secrets Manager 代理,您必须在每个请求中包含一个SSRF令牌标头:X-Aws-Parameters-Secrets-Token。Secrets Manager Agent 会拒绝没有此标头或具有无效SSRF令牌的请求。您可以在中自定义SSRF标题名称配置文件

Secrets Manager Agent 使用 for Rust,它使用默认的凭据提供者链。 AWS SDK这些IAM凭证的身份决定了 Secrets Manager 代理检索密钥的权限。

所需权限:

  • secretsmanager:DescribeSecret

  • secretsmanager:GetSecretValue

有关更多信息,请参阅 权限参考

重要

将密钥值提取到 Secrets Manager 代理后,任何有权访问计算环境和SSRF令牌的用户都可以从 Secrets Manager 代理缓存中访问该密钥。有关更多信息,请参阅 安全性注意事项

curl

以下 curl 示例展示了如何从 Secrets Manager 代理获取密钥。该示例依赖于文件中存在的内容,安装脚本将其存储在文件中。SSRF

curl -v -H \ "X-Aws-Parameters-Secrets-Token: $(</var/run/awssmatoken)" \ 'http://localhost:2773/secretsmanager/get?secretId=<YOUR_SECRET_ID>'; \ echo
Python

以下 Python 示例展示了如何从 Secrets Manager 代理获取密钥。该示例依赖于文件中存在的内容,安装脚本将其存储在文件中。SSRF

import requests import json # Function that fetches the secret from Secrets Manager Agent for the provided secret id. def get_secret(): # Construct the URL for the GET request url = f"http://localhost:2773/secretsmanager/get?secretId=<YOUR_SECRET_ID>" # Get the SSRF token from the token file with open('/var/run/awssmatoken') as fp: token = fp.read() headers = { "X-Aws-Parameters-Secrets-Token": token.strip() } 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: # Handle network errors raise Exception(f"Error: {e}")

配置 Secrets Manager 代理

要更改 Secrets Manager 代理的配置,请创建一个TOML配置文件,然后调用./aws-secrets-manager-agent --config config.toml

以下列表显示了可以为 Secrets Manager 代理配置的选项。

  • log_le vel — Secrets Manager 代理日志中报告的详细程度:DEBUG、INFO、WARNERROR、或。NONE默认为 INFO。

  • http_port — 本地HTTP服务器的端口,范围在 1024 到 65535 之间。默认值为 2773。

  • re gion-用于请求的 AWS 区域。如果未指定区域,则 Secrets Manager 代理将根据确定区域SDK。有关更多信息,请参阅 for Rust 开发者指南中的AWS SDK指定您的凭据和默认区域

  • ttl_sec onds — 缓存项目的秒数,范围在 1 到 3600 之间。TTL默认值为 300。如果缓存大小为 0,则不使用此设置。

  • cache_size – 缓存中可以存储的最大密钥数量,范围为 0 至 1000。0 表示没有缓存。默认值为 1000。

  • ssrf_headers — Secrets Manager 代理检查令牌的标头名称列表。SSRF默认为 “X-Aws-Parameters-Secrets-Token”。 X-Vault-Token

  • ssrf_env_v ariables — Secrets Manager Agent 检查令牌的环境变量名称列表。SSRF环境变量可以包含令牌或对令牌文件的引用,如下所示:AWS_TOKEN=file:///var/run/awssmatoken。默认值为 “AWS_TOKEN, AWS_SESSION_TOKEN”。

  • path_pre fix — 用于确定请求是否为基于路径的请求URI的前缀。默认值为“/v1/”。

  • max_conn — S ecrets Manager Agent 允许的来自HTTP客户端的最大连接数,范围在 1 到 1000 之间。默认值为 800。

日志记录

Secrets Manager 代理会在本地将错误记录到 logs/secrets_manager_agent.log 文件中。当应用程序调用 Secrets Manager 代理来获取密钥时,这些调用会显示在本地日志中。它们不会出现在 CloudTrail 日志中。

当文件达到 10 MB 时,Secrets Manager 代理会创建一个新的日志文件,并且总共最多存储五个日志文件。

日志不会转到 Secrets Manager CloudTrail、或 CloudWatch。从 Secrets Manager 代理获取密钥的请求不会出现在这些日志中。当 Secrets Manager 代理调用 Secrets Manager 获取密钥时,该呼叫将 CloudTrail 使用包含的用户代理字符串进行录音aws-secrets-manager-agent

您可以在 配置文件 中配置日志记录。

安全性注意事项

对于代理架构,信任域是代理端点和SSRF令牌可以访问的地方,通常是整个主机。为了保持相同的安全状况,Secrets Manager 代理的信任域应与 Secrets Manager 凭证可用的域相匹配。例如,在亚马逊EC2上,Secrets Manager 代理的信任域将与使用亚马逊角色时的证书域相同EC2。

具有安全意识的应用程序如果尚未使用代理解决方案,并且将 Secrets Manager 凭据锁定到该应用程序,则应考虑使用特定于语言的解决方案 AWS SDKs或缓存解决方案。有关更多信息,请参阅 从 AWS Secrets Manager 获取密钥