Tutorial: Desplegar una función AWS Lambda con dependencias, variables de entorno y refresh token, usando la consola de AWS

1. Crear la función en AWS Lambda

Paso 1: Acceder a la consola de Lambda

  1. Inicia sesión en tu Consola de AWS.
  2. En el buscador, escribe “Lambda” y selecciona AWS Lambda.
  3. Haz clic en Create function (Crear función).

Paso 2: Configurar la función

  1. Selecciona “Author from scratch” (Autor desde cero).
  2. Completa los campos:
    • Function name: assign_badges_lambda
    • Runtime: Python 3.11
    • Architecture: x86_64
    • Execution role:
      • Selecciona “Create a new role with basic Lambda permissions”.
  3. Haz clic en Create function.

2. Crear el código y sus dependencias

Necesitamos un deployment package (archivo ZIP) con nuestro código en lambda_function.py y las librerías (por ejemplo, requests).

Paso 1: Preparar el paquete localmente

  1. Crea una carpeta, por ejemplo: su-lambda.
  2. Dentro de su-lambda, crea lambda_function.py con un ejemplo de código que usa un refresh token si el access token está expirado. Asumamos que en tu API hay un endpoint /auth/login/refresh/ que recibe {"refresh": "<REFRESH_TOKEN>"} y retorna un nuevo access token
import requests
import os
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def refresh_access_token(session, refresh_url, refresh_token):
    """
    Solicita un nuevo access token usando el refresh token.
    Retorna el nuevo token o None si falla.
    """
    logger.info("Attempting to refresh access token...")
    try:
        # Suponemos que tu API de refresh es un POST a refresh_url con el JSON: {"refresh": "<REFRESH_TOKEN>"}
        response = session.post(refresh_url, json={"refresh": refresh_token})
        response.raise_for_status()
        data = response.json()
        new_access = data.get("access")
        if new_access:
            logger.info("Access token refreshed successfully.")
            return new_access
        else:
            logger.error("Refresh response did not include an 'access' token.")
            return None
    except requests.exceptions.RequestException as e:
        logger.error(f"Error refreshing token: {str(e)}")
        return None

def lambda_handler(event, context):
    logger.info("Lambda function started execution.")

    # Leer variables de entorno
    API_URL = os.environ.get("DJANGO_API_URL", "https://api.ejemplo.com/assign-badges/")
    REFRESH_URL = os.environ.get("DJANGO_REFRESH_URL", "https://api.ejemplo.com/auth/login/refresh/")
    ACCESS_TOKEN = os.environ.get("DJANGO_API_ACCESS_TOKEN")  # Access Token inicial
    REFRESH_TOKEN = os.environ.get("DJANGO_API_REFRESH_TOKEN")  # Refresh Token

    if not ACCESS_TOKEN or not REFRESH_TOKEN:
        logger.error("Access or Refresh token is missing. Check environment variables.")
        return {
            'statusCode': 500,
            'body': 'Missing tokens in environment variables'
        }

    # Usar requests.Session() para manejar cookies si fuera necesario.
    session = requests.Session()

    headers = {
        'Authorization': f'Bearer {ACCESS_TOKEN}',
        'Content-Type': 'application/json'
    }

    try:
        # Intentar la llamada principal
        logger.info(f"Sending request to {API_URL}")
        response = session.post(API_URL, headers=headers)
        
        # Si el access token está expirado, la API podría responder 401
        if response.status_code == 401:
            logger.info("Access token expired. Attempting to refresh...")
            new_access = refresh_access_token(session, REFRESH_URL, REFRESH_TOKEN)
            if new_access:
                # Actualiza el header con el nuevo token
                headers['Authorization'] = f'Bearer {new_access}'
                # Reintenta la solicitud
                logger.info("Retrying the API call with new access token...")
                response = session.post(API_URL, headers=headers)
            else:
                logger.error("Could not refresh access token. Aborting.")
                return {
                    'statusCode': 401,
                    'body': 'Unable to refresh token'
                }

        # Manejo final de la respuesta
        response.raise_for_status()
        logger.info(f"Response Status: {response.status_code}")
        logger.info(f"Response Content: {response.text}")

        return {
            'statusCode': 200,
            'body': 'Badges assigned successfully!'
        }
    except requests.exceptions.RequestException as e:
        logger.error(f"Error calling the API: {str(e)}")
        return {
            'statusCode': 500,
            'body': f'Error: {str(e)}'
        }


  1. Comprime todo en un ZIP:bashCopyzip -r deployment_package.zip .

Notas:

  • refresh_access_token realiza el flujo para solicitar un nuevo access token.
  • Se asume que la API regresa JSON con una clave "access" si todo va bien.
  • Si tu API maneja cookies/CSRF, deberás ampliar el código para obtener un csrftoken y adjuntarlo en cada llamada.

3.- Desde la carpeta su-lambda, instala las dependencias (p.ej. requests):

pip3 install requests -t .

4.- Comprime todo en un ZIP:

zip -r deployment_package.zip .

Paso 2: Subir el ZIP a AWS Lambda

  1. Vuelve a la consola de AWS Lambda, selecciona tu función assign_badges_lambda.
  2. Ve a la pestaña Code y haz clic en “Upload from” → “.zip file”.
  3. Selecciona deployment_package.zip y confirma.
  4. Haz clic en Deploy.

3. Configurar las variables de entorno

Ve a la pestaña ConfigurationEnvironment variables para especificar la URL de tu API, el access token, el refresh token, etc.

Por ejemplo:

  • Key: DJANGO_API_URL
    Value: https://api.ejemplo.com/assign-badges/
  • Key: DJANGO_REFRESH_URL
    Value: https://api.ejemplo.com/auth/login/refresh/
  • Key: DJANGO_API_ACCESS_TOKEN
    Value: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... (token inicial)
  • Key: DJANGO_API_REFRESH_TOKEN
    Value: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... (refresh token)

Consejo:
Si manejas credenciales reales (usuario/contraseña, tokens, etc.), es más seguro usar AWS Secrets Manager o AWS Systems Manager Parameter Store con cifrado y rotación.


4. Programar la ejecución con AWS EventBridge

Para que tu Lambda se ejecute automáticamente (por ejemplo, a diario):

  1. Ve a EventBridge en la consola de AWS.
  2. Haz clic en RulesCreate rule.
  3. Asigna un nombre, por ejemplo DailyAssignBadges.
  4. Selecciona Schedule y usa una cron expression. Por ejemplo, para medianoche diaria:scssCopycron(0 0 * * ? *)
  5. En Select target, elige Lambda function y selecciona assign_badges_lambda.
  6. Haz clic en Create.

5. Monitoreo con CloudWatch

  1. En la consola de AWS, abre CloudWatch.
  2. Selecciona LogsLog groups.
  3. Busca /aws/lambda/assign_badges_lambda.
  4. Haz clic para ver los registros, donde encontrarás info y errores (logger.info, logger.error).

6. Pruebas y Verificación

  1. En Lambda, ve a la pestaña Test.
  2. Crea un evento de prueba (un JSON sencillo, por ejemplo: {"test": "run"}).
  3. Ejecuta la prueba y verifica si la invocación es SUCCESS o ERROR.
  4. Abre CloudWatch para ver los logs y diagnosticar cualquier problema.

Notas sobre Cookies y CSRF

  • Si tu API utiliza cookies para manejar la sesión y requiere un csrftoken, necesitarás:
    1. Hacer un GET inicial para obtener la cookie.
    2. Leer la cookie csrftoken y enviarla en la cabecera X-CSRFToken.
    3. Incluir la cookie en cada POST (con session.cookies o la cabecera Cookie: ...).
  • Si tu API no exenta los endpoints de JWT del CSRF, ajusta la configuración de Django o DRF (@csrf_exempt en las vistas o configuraciones avanzadas) para que no bloquee las peticiones “headless” con tokens.

Conclusión

Con este flujo:

  1. Desplegaste una función Lambda con requests.
  2. Manejaste un refresh token para reobtener un access token cuando sea necesario.
  3. Configuraste variables de entorno (o Secrets Manager) para no exponer credenciales en el código.
  4. Programaste la ejecución con EventBridge y monitoreas logs en CloudWatch.

Así, tu Lambda podrá comunicarse con APIs seguras (JWT + refresh tokens) sin necesidad de reingresar manualmente credenciales, y ejecutar la lógica de asignar medallas (u otra tarea) de forma automática.