本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
在 Lambda 函數中使用 Secrets Manager 秘密
AWS Secrets Manager 可協助您管理 Lambda 函數所需的登入資料、API 金鑰和其他秘密。我們建議您使用 AWS Parameters and Secrets Lambda 延伸模組來擷取 Lambda 函數中的秘密。相較於直接使用 AWS SDK 擷取秘密, 擴充功能可提供更好的效能並降低成本。
AWS Parameters and Secrets Lambda 延伸模組會維護秘密的本機快取,因此您的函數不需要在每次叫用時呼叫 Secrets Manager。當您的函數請求秘密時,延伸模組會先檢查其快取。如果秘密可用且尚未過期,則會立即傳回。否則,延伸模組會從 Secrets Manager 擷取它、快取它,然後將它傳回給您的函數。此快取機制可減少對 Secrets Manager 的 API 呼叫,進而加快回應時間並降低成本。
延伸模組使用與任何 Lambda 執行時間相容的簡單 HTTP 界面。根據預設,它會快取秘密 300 秒 (5 分鐘),最多可保留 1,000 個秘密。您可以使用環境變數自訂這些設定。
何時搭配 Lambda 使用 Secrets Manager
搭配 Lambda 使用 Secrets Manager 的常見案例包括:
在 Lambda 函數中使用 Secrets Manager
本節假設您已擁有 Secrets Manager 秘密。若要建立秘密,請參閱建立 AWS Secrets Manager 秘密。
選擇您偏好的執行時間,並依照步驟建立從 Secrets Manager 擷取秘密的函數。範例函數會從 Secrets Manager 擷取秘密,並可用來存取應用程式中的資料庫登入資料、API 金鑰或其他敏感組態資料。
- Python
-
若要建立 Python 函數
-
建立並導覽至新的專案目錄。範例:
mkdir my_function
cd my_function
-
lambda_function.py
使用下列程式碼建立名為 的檔案。對於 secret_name
,請使用秘密的名稱或 Amazon Resource Name (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 Resource Name (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
})
};
}
};
-
建立包含 檔案的 .zip index.mjs
檔案:
zip -r function.zip index.mjs
- Java
-
若要建立 Lambda 函數
-
建立 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 Resource Name (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
) 以供日後使用。
開啟 Lambda 主控台中的 函數頁面。
-
選擇建立函數。
-
選取從頭開始撰寫。
-
針對函數名稱,請輸入 secret-retrieval-demo
。
-
選擇您偏好的執行時間。
-
選擇 Create function (建立函數)。
上傳部署套件
-
在函數的程式碼索引標籤中,選擇從 上傳,然後選取 .zip 檔案 (適用於 Python 和 Node.js) 或 .jar 檔案 (適用於 Java)。
-
上傳您先前建立的部署套件。
-
選擇儲存。
新增 AWS Parameters and Secrets Lambda 延伸做為 layer
-
在函數的程式碼索引標籤中,向下捲動至圖層。
-
選擇 Add a layer (新增 layer)。
-
選取AWS 圖層。
-
選擇 AWS-Parameters-and-Secrets-Lambda-Extension。
-
選取最新版本。
-
選擇新增。
將 Secrets Manager 許可新增至執行角色
-
依序選擇 Configuration (組態) 索引標籤和 Permissions (許可)。
-
在角色名稱下面,選擇執行角色連結。此連結會在 IAM 主控台中開啟該角色。
-
選擇新增許可,然後選擇建立內嵌政策。
-
選擇 JSON 索引標籤並新增下列政策。針對 Resource
,輸入秘密的 ARN。
- JSON
-
-
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME
"
}
]
}
-
選擇下一步。
-
輸入政策的名稱。
-
選擇建立政策。
若要測試函數
-
返回 Lambda 主控台。
-
選取測試索引標籤。
-
選擇測試。您應該會看到下列回應:
環境變數
AWS Parameters and Secrets 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 |
快取秘密的Time-to-live。設定為 0 以停用快取。如果 PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE 的值為 0,則會忽略此變數。 |
參數存放區 TTL |
300 秒 |
0 - 300 秒 |
SSM_PARAMETER_STORE_TTL |
快取參數的Time-to-live。設定為 0 以停用快取。如果 PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE 的值為 0,則會忽略此變數。 |
日誌層級 |
INFO |
除錯 | 資訊 | 警告 | 錯誤 | 無 |
PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL |
擴充功能日誌中報告的詳細資訊層級 |
最大連線數 |
3 |
1 或以上 |
PARAMETERS_SECRETS_EXTENSION_MAX_CONNECTIONS |
參數存放區或 Secrets Manager 請求的 HTTP 連線數目上限 |
Secrets Manager 逾時 |
0 (無逾時) |
所有整數 |
SECRETS_MANAGER_TIMEOUT_MILLIS |
Secrets Manager 請求逾時 (以毫秒為單位) |
參數存放區逾時 |
0 (無逾時) |
所有整數 |
SSM_PARAMETER_STORE_TIMEOUT_MILLIS |
參數存放區的請求逾時 (以毫秒為單位) |
使用秘密輪換
如果您經常輪換秘密,預設的 300 秒快取持續時間可能會導致您的函數使用過時的秘密。您有兩個選項可確保函數使用最新的秘密值:
-
將SECRETS_MANAGER_TTL
環境變數設定為較低的值 (以秒為單位),以減少快取 TTL。例如,將其設定為 60
可確保您的函數永遠不會使用超過一分鐘的秘密。
-
在秘密請求中使用 AWSPREVIOUS
AWSCURRENT
或 預備標籤,以確保您取得所需的特定版本:
secretsmanager/get?secretId=YOUR_SECRET_NAME&versionStage=AWSCURRENT
選擇最能平衡效能和新鮮度需求的方法。較低的 TTL 表示更頻繁地呼叫 Secrets Manager,但確保您使用的是最新的秘密值。