Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅
中国的 Amazon Web Services 服务入门
(PDF)。
在 Lambda 函数中使用 Secrets Manager 密钥
Amazon Secrets Manager 可帮助您管理 Lambda 函数所需的凭证、API 密钥和其他密钥。我们建议您使用 Amazon 参数和密钥 Lambda 扩展来在 Lambda 函数中检索密钥。与直接使用 Amazon SDK 检索密钥相比,该扩展性能更佳,成本更低。
Amazon 参数和密钥 Lambda 扩展维护密钥的本地缓存,因此您的函数无需在每次调用时都调用 Secrets Manager。当您的函数请求密钥时,扩展会首先检查其缓存。如果密钥可用且尚未过期,则会立即返回该密钥。否则,扩展会从 Secrets Manager 中检索它,将其缓存,然后返回给您的函数。此缓存机制可最大限度地减少对 Secrets Manager 的 API 调用,从而缩短响应时间并降低成本。
该扩展使用与任何 Lambda 运行时兼容的简单 HTTP 接口。默认情况下,它会缓存密钥 300 秒(5 分钟),最多可容纳 1,000 个密钥。您可以使用环境变量自定义这些设置。
何时将 Secrets Manager 与 Lambda 结合使用
将 Secrets Manager 与 Lambda 结合使用的常见场景包括:
在 Lambda 函数中使用 Secrets Manager
本节假设您已经拥有 Secrets Manager 密钥。要创建密钥,请参阅 Create an Amazon Secrets Manager secret。
选择您的首选运行时,并按照步骤创建用于从 Secrets Manager 检索密钥的函数。该示例函数从 Secrets Manager 中检索密钥,并可用于访问数据库凭证、API 密钥或应用程序中的其他敏感配置数据。
- Python
-
创建 Python 函数
-
创建并导航到新的项目目录。示例:
mkdir my_function
cd my_function
-
使用以下代码创建名为 lambda_function.py
的文件。对于 secret_name
,使用您的密钥的名称或 Amazon 资源名称 (ARN)。
import json
import os
import requests
def lambda_handler(event, context):
try:
# Replace with the name or ARN of your secret
secret_name = "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME
"
secrets_extension_endpoint = f"http://localhost:2773/secretsmanager/get?secretId={secret_name}"
headers = {"X-Aws-Parameters-Secrets-Token": os.environ.get('AWS_SESSION_TOKEN')}
response = requests.get(secrets_extension_endpoint, headers=headers)
print(f"Response status code: {response.status_code}")
secret = json.loads(response.text)["SecretString"]
print(f"Retrieved secret: {secret}")
return {
'statusCode': response.status_code,
'body': json.dumps({
'message': 'Successfully retrieved secret',
'secretRetrieved': True
})
}
except Exception as e:
print(f"Error: {str(e)}")
return {
'statusCode': 500,
'body': json.dumps({
'message': 'Error retrieving secret',
'error': str(e)
})
}
-
使用此内容创建名为 requirements.txt
的文件:
requests
-
安装依赖项:
pip install -r requirements.txt -t .
-
创建包含所有文件的 .zip 文件:
zip -r function.zip .
- Node.js
-
创建 Node.js 函数
-
创建并导航到新的项目目录。示例:
mkdir my_function
cd my_function
-
使用以下代码创建名为 index.mjs
的文件。对于 secret_name
,使用您的密钥的名称或 Amazon 资源名称 (ARN)。
import http from 'http';
export const handler = async (event) => {
try {
// Replace with the name or ARN of your secret
const secretName = "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME
";
const options = {
hostname: 'localhost',
port: 2773,
path: `/secretsmanager/get?secretId=${secretName}`,
headers: {
'X-Aws-Parameters-Secrets-Token': process.env.AWS_SESSION_TOKEN
}
};
const response = await new Promise((resolve, reject) => {
http.get(options, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
resolve({
statusCode: res.statusCode,
body: data
});
});
}).on('error', reject);
});
const secret = JSON.parse(response.body).SecretString;
console.log('Retrieved secret:', secret);
return {
statusCode: response.statusCode,
body: JSON.stringify({
message: 'Successfully retrieved secret',
secretRetrieved: true
})
};
} catch (error) {
console.error('Error:', error);
return {
statusCode: 500,
body: JSON.stringify({
message: 'Error retrieving secret',
error: error.message
})
};
}
};
-
创建包含 index.mjs
文件的 .zip 文件:
zip -r function.zip index.mjs
- Java
-
创建 Java 函数
-
创建 Maven 项目:
mvn archetype:generate \
-DgroupId=example \
-DartifactId=lambda-secrets-demo \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.4 \
-DinteractiveMode=false
-
导航到项目目录:
cd lambda-secrets-demo
-
打开 pom.xml
并将内容替换为以下内容:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>example</groupId>
<artifactId>lambda-secrets-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.2.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<finalName>function</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
-
将 /lambda-secrets-demo/src/main/java/example/App.java
重命名为 Hello.java
,以匹配 Lambda 的默认 Java 处理程序名称 (example.Hello::handleRequest
):
mv src/main/java/example/App.java src/main/java/example/Hello.java
-
打开 Hello.java
文件并将其内容替换为以下内容。对于 secretName
,使用您的密钥的名称或 Amazon 资源名称 (ARN)。
package example;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Hello implements RequestHandler<Object, String> {
private final HttpClient client = HttpClient.newHttpClient();
@Override
public String handleRequest(Object input, Context context) {
try {
// Replace with the name or ARN of your secret
String secretName = "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME
";
String endpoint = "http://localhost:2773/secretsmanager/get?secretId=" + secretName;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.header("X-Aws-Parameters-Secrets-Token", System.getenv("AWS_SESSION_TOKEN"))
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
String secret = response.body();
secret = secret.substring(secret.indexOf("SecretString") + 15);
secret = secret.substring(0, secret.indexOf("\""));
System.out.println("Retrieved secret: " + secret);
return String.format(
"{\"statusCode\": %d, \"body\": \"%s\"}",
response.statusCode(), "Successfully retrieved secret"
);
} catch (Exception e) {
e.printStackTrace();
return String.format(
"{\"body\": \"Error retrieving secret: %s\"}",
e.getMessage()
);
}
}
}
-
删除测试目录。Maven 默认创建此项,但在本例中我们不需要它。
rm -rf src/test
-
构建项目:
mvn package
-
下载 JAR 文件 (target/function.jar
) 以供稍后使用。
打开 Lamba 控制台的 Functions page(函数页面)。
-
选择 Create function(创建函数)。
-
选择从头开始编写。
-
对于函数名称,请输入 secret-retrieval-demo
。
-
选择您的首选运行时。
-
选择创建函数。
上传部署包
-
在函数的代码选项卡中,选择上传自,然后选择 .zip 文件(对于 Python 和 Node.js)或 .jar 文件(对于 Java)。
-
上传您之前创建的部署包。
-
选择保存。
将 Amazon 参数和密钥 Lambda 扩展添加为层
-
在函数的代码选项卡中,向下滚动到层。
-
选择 Add a layer。
-
选择 Amazon 层。
-
选择 Amazon-Parameters-and-Secrets-Lambda-Extension。
-
选择最新版本。
-
选择添加。
向您的执行角色添加 Secrets Manager 权限
-
选择 Configuration(配置)选项卡,然后选择 Permissions(权限)。
-
在角色名称下,选择至执行角色的链接。此角色将在 IAM 控制台中打开角色。
-
选择添加权限,然后选择创建内联策略。
-
选择 JSON 选项卡,然后添加以下策略。对于 Resource
,输入您的密钥的 ARN。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME
"
}
]
}
-
选择下一步。
-
输入策略的名称。
-
选择创建策略。
测试此函数
-
返回 Lambda 控制台。
-
选择测试选项卡。
-
选择测试。您应看到以下响应:
环境变量
Amazon 参数和密钥 Lambda 扩展使用下面的默认设置。您可以通过创建相应的环境变量来覆盖这些设置。要查看函数的当前设置,请将 PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL
设置为 DEBUG
。该扩展将在每次函数调用开始时将其配置信息记录到 CloudWatch Logs 中。
设置 |
默认值 |
有效值 |
环境变量 |
详细信息 |
HTTP 端口 |
2773 |
1-65535 |
PARAMETERS_SECRETS_EXTENSION_HTTP_PORT |
本地 HTTP 服务器的端口 |
已启用缓存 |
TRUE |
TRUE | FALSE |
PARAMETERS_SECRETS_EXTENSION_CACHE_ENABLED |
启用或禁用缓存 |
缓存大小 |
1000 |
0 - 1000 |
PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE |
设置为 0 以禁用缓存 |
Secrets Manager TTL |
300 秒 |
0 - 300 秒 |
SECRETS_MANAGER_TTL |
缓存密钥的生存时间。设置为 0 以禁用缓存。如果 PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE 的值为 0,则忽略此变量。 |
Parameter Store TTL |
300 秒 |
0 - 300 秒 |
SSM_PARAMETER_STORE_TTL |
缓存参数的生存时间。设置为 0 以禁用缓存。如果 PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE 的值为 0,则忽略此变量。 |
日志级别 |
INFO |
调试 | 信息 | 警告 | 错误 | 无 |
PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL |
扩展日志中报告的详细信息级别 |
最大连接数 |
3 |
1 或更多 |
PARAMETERS_SECRETS_EXTENSION_MAX_CONNECTIONS |
对 Parameter Store 或 Secrets Manager 的请求的最大 HTTP 连接数 |
Secrets Manager 超时 |
0(无超时) |
所有整数 |
SECRETS_MANAGER_TIMEOUT_MILLIS |
Secrets Manager 的请求超时(以毫秒为单位) |
Parameter Store 超时 |
0(无超时) |
所有整数 |
SSM_PARAMETER_STORE_TIMEOUT_MILLIS |
Parameter Store 的请求超时(以毫秒为单位) |
使用密钥轮换
如果频繁轮换密钥,则默认 300 秒缓存持续时间可能会导致您的函数使用过时的密钥。您有两种方法可以确保函数使用最新的密钥值:
-
通过将 SECRETS_MANAGER_TTL
环境变量设置为较低的值(以秒为单位)来缩短缓存 TTL。例如,将其设置为 60
可确保函数永远不会使用超过一分钟的密钥。
-
在密钥请求中使用 AWSCURRENT
或 AWSPREVIOUS
暂存标签来确保获得所需的特定版本:
secretsmanager/get?secretId=YOUR_SECRET_NAME&versionStage=AWSCURRENT
选择最能平衡您对性能和新鲜度需求的方法。较低 TTL 意味着对 Secrets Manager 的调用更频繁,但可确保您使用最新的密钥值。