Uso de secretos de Secrets Manager en Funciones de Lambda - AWS Lambda

Uso de secretos de Secrets Manager en Funciones de Lambda

AWS Secrets Manager lo ayuda a administrar credenciales, claves de API y otros secretos que necesitan sus funciones de Lambda. Existen dos enfoques principales para recuperar secretos en sus funciones de Lambda, y ambos ofrecen un mejor rendimiento y costos más bajos en comparación con la recuperación de secretos de manera directa mediante AWS SDK:

  • Extensión de Lambda para parámetros y secretos de AWS: una solución independiente del tiempo de ejecución que proporciona una interfaz HTTP sencilla para la recuperación de secretos

  • Powertools para la utilidad de parámetros de AWS Lambda: una solución integrada en el código compatible con varios proveedores (Secrets Manager, Parameter Store, AppConfig) con transformaciones integradas

Ambos enfoques mantienen una caché local de secretos, lo que elimina la necesidad de que la función llame a Secrets Manager por cada invocación. Cuando la función solicita un secreto, primero se comprueba la caché. Si el secreto está disponible y no ha caducado, se devuelve de inmediato. De lo contrario, se recupera de Secrets Manager, se almacena en caché y se devuelve. Este mecanismo de almacenamiento en caché se traduce en tiempos de respuesta más rápidos y costos reducidos al minimizar las llamadas a la API.

Elección de un enfoque

Tenga en cuenta estos factores al elegir entre la extensión y PowerTools:

Se debe utilizar la extensión de Lambda para parámetros y secretos de AWS en los siguientes casos:
  • Se desea una solución independiente del tiempo de ejecución que funcione con cualquier entorno de ejecución de Lambda

  • Se prefiere no agregar dependencias de código a su función

  • Solo se necesitan recuperar secretos de Secrets Manager o Parameter Store

Se debe utilizar la utilidad de Powertools para parámetros de AWS Lambda en los siguientes casos:
  • Se desea una experiencia de desarrollo integrada con el código de su aplicación

  • Se requiere soporte para varios proveedores (Secrets Manager, Parameter Store, AppConfig)

  • Se quiere contar con transformaciones de datos integradas (análisis de JSON, decodificación de base64)

  • Se están utilizando tiempos de ejecución de Python, TypeScript, Java o .NET

Cuándo usar Secrets Manager con Lambda

Entre los escenarios más comunes para usar Secrets Manager con Lambda se incluyen los siguientes:

  • Almacenar las credenciales de base de datos que su función utiliza para conectarse a Amazon RDS u otras bases de datos

  • Administrar las claves de API para los servicios externos a los que llama su función

  • Almacenar claves de cifrado u otros datos de configuración confidenciales

  • Rotar de forma automática las credenciales sin necesidad de actualizar el código de función

Uso de la extensión de Lambda para parámetros y secretos de AWS

La extensión de Lambda para parámetros y secretos de AWS utiliza una interfaz HTTP sencilla compatible con cualquier tiempo de ejecución de Lambda. De forma predeterminada, guarda en caché los secretos durante 300 segundos (5 minutos) y puede almacenar hasta 1000 secretos. Puede personalizar estos ajustes con variables de entorno.

Uso de Secrets Manager en una función de Lambda

En esta sección se supone que ya tiene un secreto de Secrets Manager. Para crear un secreto, consulte Creación de un secreto de AWS Secrets Manager.

Elige tu tiempo de ejecución preferido y sigue los pasos para crear una función que recupere los secretos de Secrets Manager. La función de ejemplo recupera un secreto de Secrets Manager y se puede utilizar para acceder a las credenciales de la base de datos, las claves de API u otros datos de configuración confidenciales de sus aplicaciones.

Python
Para crear una función Python
  1. Cree y navegue hasta un nuevo directorio del proyecto. Ejemplo:

    mkdir my_function cd my_function
  2. Cree un archivo llamado lambda_function.py con el siguiente código. Para secret_name, use el nombre o el nombre de recurso de Amazon (ARN) de su secreto.

    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) }) }
  3. Cree un archivo llamado requirements.txt con este contenido:

    requests
  4. Instale las dependencias:

    pip install -r requirements.txt -t .
  5. Cree un archivo .zip que contenga todos los archivos:

    zip -r function.zip .
Node.js
Para crear una función de Node.js.
  1. Cree y navegue hasta un nuevo directorio del proyecto. Ejemplo:

    mkdir my_function cd my_function
  2. Cree un archivo llamado index.mjs con el siguiente código. Para secret_name, use el nombre o el nombre de recurso de Amazon (ARN) de su secreto.

    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 }) }; } };
  3. Cree un archivo .zip que contenga el archivo index.mjs:

    zip -r function.zip index.mjs
Java
Para crear una función Java
  1. Cree un proyecto de Maven:

    mvn archetype:generate \ -DgroupId=example \ -DartifactId=lambda-secrets-demo \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DarchetypeVersion=1.4 \ -DinteractiveMode=false
  2. Navegue hasta el directorio del proyecto:

    cd lambda-secrets-demo
  3. Abra el archivo pom.xml y reemplace el contenido con lo siguiente:

    <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>
  4. Cambie el nombre del archivo /lambda-secrets-demo/src/main/java/example/App.java por Hello.java para que coincida con el nombre del controlador Java predeterminado de Lambda (example.Hello::handleRequest):

    mv src/main/java/example/App.java src/main/java/example/Hello.java
  5. Abra el archivo Hello.java y reemplace el contenido con lo siguiente. Para secretName, use el nombre o el nombre de recurso de Amazon (ARN) de su secreto.

    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() ); } } }
  6. Elimine el directorio de prueba. Maven lo crea de forma predeterminada, pero no lo necesitamos para este ejemplo.

    rm -rf src/test
  7. Compile el proyecto:

    mvn package
  8. Descarga el archivo JAR (target/function.jar) para usarlo más adelante.

  1. Abra la página de Functions (Funciones) en la consola de Lambda.

  2. Seleccione Creación de función.

  3. Seleccione Crear desde cero.

  4. En Nombre de la función, introduzca secret-retrieval-demo.

  5. Elija el tiempo de ejecución que prefiera.

  6. Seleccione Creación de función.

Cómo cargar el paquete de implementación
  1. En la pestaña Código de la función, elija Cargar desde y seleccione un archivo .zip (para Python y Node.js) o un archivo .jar (para Java).

  2. Cargue el paquete de implementación que creó anteriormente.

  3. Seleccione Save.

Cómo agregar la extensión de Lambda AWS Parameters and Secrets como una capa
  1. En la pestaña Código de la función, desplácese hacia abajo hasta Capas.

  2. Elija Add a layer (Añadir una capa).

  3. Selecciona las capas de AWS.

  4. Elija AWS-Parameters-and-Secrets-Lambda-Extension.

  5. Seleccione la versión más reciente.

  6. Elija Agregar.

Cómo agregar permisos de Secrets Manager a su rol de ejecución
  1. Elija la pestaña Configuración y, a continuación, elija Permisos.

  2. En Nombre del rol, elija el enlace al rol de ejecución. Este enlace abre el rol en la consola de IAM.

    Enlace al rol de ejecución
  3. Seleccione Agregar permisos y, a continuación, Crear política insertada.

    Políticas adjuntas a la consola de IAM
  4. Elija la pestaña JSON y añada la siguiente política. Para Resource, introduzca el ARN de su secreto.

    JSON
    { "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "secretsmanager:GetSecretValue", "Resource": "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME" } ] }
  5. Elija Siguiente.

  6. Introduzca un nombre para la política.

  7. Seleccione Crear política.

Para probar la función
  1. Vuelva a la consola de Lambda.

  2. Seleccione la pestaña Pruebas.

  3. Seleccione Probar. Debería ver la siguiente respuesta:

    Resultado de prueba correcta

Variables de entorno

La extensión de Lambda AWS Parameters and Secrets utiliza la siguiente configuración predeterminada. Puede anular esta configuración creando las variables de entorno correspondientes. Para ver la configuración actual de una función, configure PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL en DEBUG. La extensión registrará su información de configuración en los registros de CloudWatch al inicio de cada invocación de función.

Ajuste Valor predeterminado Valores válidos Variable de entorno Detalles
Puerto HTTP 2773 1 a 65535 PARAMETERS_SECRETS_EXTENSION_HTTP_PORT Puerto para el servidor HTTP local
Caché habilitada TRUE TRUE, FALSE PARAMETERS_SECRETS_EXTENSION_CACHE_ENABLED Activa o desactiva la caché
Tamaño de caché 1 000 0 a 1000 PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE Configúrelo en 0 para deshabilitar el almacenamiento en caché
TTL de Secrets Manager 300 segundos 0 a 300 segundos SECRETS_MANAGER_TTL Tiempo de vida de los secretos en caché. Configúrelo en 0 para deshabilitar el almacenamiento en caché. Esta variable se ignora si el valor para PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE es 0.
TTL del almacén de parámetros 300 segundos 0 a 300 segundos SSM_PARAMETER_STORE_TTL Tiempo de vida de los parámetros en caché. Configúrelo en 0 para deshabilitar el almacenamiento en caché. Esta variable se ignora si el valor para PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE es 0.
Nivel de registro INFO DEPURAR | INFORMACIÓN | ADVERTIR | ERROR | NINGUNO PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL El nivel de detalle indicado en los registros de la extensión.
Máximo de conexiones 3 1 o más PARAMETERS_SECRETS_EXTENSION_MAX_CONNECTIONS Cantidad máxima de conexiones HTTP para las solicitudes al almacén de parámetros o Secrets Manager
Tiempo de espera de Secrets Manager 0 (sin tiempo de espera) Todos los números enteros SECRETS_MANAGER_TIMEOUT_MILLIS Tiempo de espera para las solicitudes a Secrets Manager (en milisegundos)
Tiempo de espera del almacén de parámetros 0 (sin tiempo de espera) Todos los números enteros SSM_PARAMETER_STORE_TIMEOUT_MILLIS Tiempo de espera para las solicitudes al almacén de parámetros (en milisegundos)

Trabajo con rotación de secretos

Si cambia los secretos con frecuencia, la duración predeterminada de la memoria caché de 300 segundos puede hacer que su función utilice secretos obsoletos. Tiene dos opciones para asegurarse de que su función utilice el valor secreto más reciente:

  • Reducir el TTL de la caché configurando la variable de entorno SECRETS_MANAGER_TTL en un valor inferior (en segundos). Por ejemplo, configúrelo en 60 garantiza que la función nunca utilice un secreto que tenga más de un minuto de antigüedad.

  • Usar las etiquetas de ensayo AWSCURRENT o AWSPREVIOUS de su solicitud secreta para asegurarse de obtener la versión específica que desea:

    secretsmanager/get?secretId=YOUR_SECRET_NAME&versionStage=AWSCURRENT

Elija el enfoque que mejor equilibre sus necesidades de rendimiento y actualización. Un TTL inferior significa llamadas más frecuentes a Secrets Manager, pero garantiza que trabaje con los valores secretos más recientes.

Uso de la utilidad de parámetros de Powertools para AWS Lambda

La utilidad de parámetros de Powertools para AWS Lambda proporciona una interfaz unificada para la recuperación de secretos de varios proveedores, incluidos Secrets Manager, el almacén de parámetros y AppConfig. Gestiona el almacenamiento en caché y las transformaciones, y proporciona una experiencia de desarrollo más integrada en comparación con el enfoque de extensión.

Ventajas de la utilidad de parámetros

  • Varios proveedores: recupera parámetros de Secrets Manager, Parameter Store y AppConfig mediante la misma interfaz

  • Transformaciones integradas: análisis automático de JSON, decodificación de base64 y otras transformaciones de datos

  • Almacenamiento en caché integrado: almacenamiento en caché configurable con soporte TTL para reducir las llamadas a la API

  • Seguridad de los tipos: sólida compatibilidad con TypeScript y otros tiempos de ejecución compatibles

  • Gestión de errores: lógica de reintento y gestión de errores integrados

Ejemplos de código

Los siguientes ejemplos muestran cómo recuperar secretos mediante la utilidad de parámetros en diferentes tiempos de ejecución:

Python
nota

Para ver ejemplos completos e instrucciones de configuración, consulte la documentación de la utilidad de parámetros.

Recuperación de secretos de Secrets Manager con Powertools para la utilidad de parámetros de AWS Lambda.

from aws_lambda_powertools import Logger from aws_lambda_powertools.utilities import parameters logger = Logger() def lambda_handler(event, context): try: # Get secret with caching (default TTL: 5 seconds) secret_value = parameters.get_secret("my-secret-name") # Get secret with custom TTL secret_with_ttl = parameters.get_secret("my-secret-name", max_age=300) # Get secret and transform JSON secret_json = parameters.get_secret("my-json-secret", transform="json") logger.info("Successfully retrieved secrets") return { 'statusCode': 200, 'body': 'Successfully retrieved secrets' } except Exception as e: logger.error(f"Error retrieving secret: {str(e)}") return { 'statusCode': 500, 'body': f'Error: {str(e)}' }
TypeScript
nota

Para ver ejemplos completos e instrucciones de configuración, consulte la documentación de la utilidad de parámetros.

Recuperación de secretos de Secrets Manager con Powertools para la utilidad de parámetros de AWS Lambda.

import { Logger } from '@aws-lambda-powertools/logger'; import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; import type { Context } from 'aws-lambda'; const logger = new Logger(); export const handler = async (event: any, context: Context) => { try { // Get secret with caching (default TTL: 5 seconds) const secretValue = await getSecret('my-secret-name'); // Get secret with custom TTL const secretWithTtl = await getSecret('my-secret-name', { maxAge: 300 }); // Get secret and transform JSON const secretJson = await getSecret('my-json-secret', { transform: 'json' }); logger.info('Successfully retrieved secrets'); return { statusCode: 200, body: 'Successfully retrieved secrets' }; } catch (error) { logger.error('Error retrieving secret', { error }); return { statusCode: 500, body: `Error: ${error}` }; } };
Java
nota

Para ver ejemplos completos e instrucciones de configuración, consulte la documentación de la utilidad de parámetros.

Recuperación de secretos de Secrets Manager con Powertools para la utilidad de parámetros de AWS Lambda.

import software.amazon.lambda.powertools.logging.Logging; import software.amazon.lambda.powertools.parameters.SecretsProvider; import software.amazon.lambda.powertools.parameters.ParamManager; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; public class SecretHandler implements RequestHandler<Object, String> { private final SecretsProvider secretsProvider = ParamManager.getSecretsProvider(); @Logging @Override public String handleRequest(Object input, Context context) { try { // Get secret with caching (default TTL: 5 seconds) String secretValue = secretsProvider.get("my-secret-name"); // Get secret with custom TTL (300 seconds) String secretWithTtl = secretsProvider.withMaxAge(300).get("my-secret-name"); // Get secret and transform JSON MySecret secretJson = secretsProvider.get("my-json-secret", MySecret.class); return "Successfully retrieved secrets"; } catch (Exception e) { return "Error retrieving secret: " + e.getMessage(); } } public static class MySecret { // Define your secret structure here } }
.NET
nota

Para ver ejemplos completos e instrucciones de configuración, consulte la documentación de la utilidad de parámetros.

Recuperación de secretos de Secrets Manager con Powertools para la utilidad de parámetros de AWS Lambda.

using AWS.Lambda.Powertools.Logging; using AWS.Lambda.Powertools.Parameters; using Amazon.Lambda.Core; [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] public class Function { private readonly ISecretsProvider _secretsProvider; public Function() { _secretsProvider = ParametersManager.SecretsProvider; } [Logging] public async Task<string> FunctionHandler(object input, ILambdaContext context) { try { // Get secret with caching (default TTL: 5 seconds) var secretValue = await _secretsProvider.GetAsync("my-secret-name"); // Get secret with custom TTL var secretWithTtl = await _secretsProvider.WithMaxAge(TimeSpan.FromMinutes(5)) .GetAsync("my-secret-name"); // Get secret and transform JSON var secretJson = await _secretsProvider.GetAsync<MySecret>("my-json-secret"); return "Successfully retrieved secrets"; } catch (Exception e) { return $"Error retrieving secret: {e.Message}"; } } public class MySecret { // Define your secret structure here } }

Configuración y permisos

Para utilizar la utilidad de parámetros, debe realizar lo siguiente:

  1. Instalar Powertools para AWS Lambda para su tiempo de ejecución. Para obtener más información, consulte Powertools para AWS Lambda.

  2. Agregar todos los permisos de IAM al rol de ejecución de la función. Consulte Administrar permisos en AWS Lambda para obtener más información.

  3. Configurar los ajustes opcionales mediante variables de entorno.

Los permisos de IAM obligatorios son los mismos que para el enfoque de la extensión. La utilidad gestionará automáticamente el almacenamiento en caché y las llamadas a la API a Secrets Manager según su configuración.