.NET Workloads on AWS Lambda

MÓDULO 4

Módulo 4: Trabajar con otros servicios de AWS

 MÓDULO DE APRENDIZAJE

Tenga en cuenta que puede seguir los ejemplos que se presentan aquí, pero no es necesario.

Hay varias formas de trabajar con otros servicios de AWS.

Si el servicio al que está accediendo es una base de datos de AWS RDS, como SQL Server o Postgres, utilizará las mismas bibliotecas que utilizaría si alojara las bases de datos en su propia computadora o centro de datos. Necesita una cadena de conexión con nombre de usuario y contraseña, u otra forma de autenticación de su elección. No hay nada diferente del uso diario de la base de datos. No necesita ningún permiso adicional para acceder al servidor de la base de datos. La única advertencia al respecto es que si la base de datos no es de acceso público, tendrá que conectar la Lambda a la VPC (ese proceso requiere permisos adicionales).

Si su función de Lambda utiliza S3, DynamoDB, Kinesis, etc., utilice los SDK de AWS para interactuar con esos servicios. El rol en el que se ejecuta su función de Lambda necesita los permisos adecuados para interactuar con cada servicio. Por ejemplo, si desea añadir un elemento a un bucket de S3, el rol necesitará permiso para escribir en ese bucket. Si desea obtener elementos de una tabla de DynamoDB, el rol necesitará permisos para leer de esa tabla.

El tercer escenario es en el que desea que otro servicio active su función de Lambda en respuesta a algún evento. Por ejemplo, es posible que desee activar la función de Lambda cuando se agrega un elemento nuevo a un bucket de S3 determinado o cuando los eventos llegan a una secuencia de Kinesis. Para ello, la función de Lambda debe utilizar una “política basada en recursos”. Esta política otorga a otros servicios el permiso para invocar su función de Lambda.

 Tiempo de realización

30 minutos 

Acceso a los servidores de bases de datos de RDS desde una función de Lambda

Lo mejor de usar servicios conocidos como SQL Server, Postgres o MySQL es que, desde la perspectiva del código, no es necesario hacer nada diferente al llamarlos desde una función de Lambda. Entity Framework/ADO/Npgsql, etc., funcionan igual de bien con una base de datos alojada en AWS que con una base de datos local o en bastidor. Lo llama de la misma manera, no necesita una biblioteca de SDK de AWS, pero, desde luego, aún necesita agregar los paquetes NuGet relevantes a su proyecto. Por lo demás, todo es lo mismo.

Acceso a los servicios de AWS desde una función de Lambda

Para acceder a la mayoría de los servicios de AWS, debe conceder permiso a la función de Lambda para interactuar con ese servicio. Para ello, agregue una política al rol en el que se ejecuta la función de Lambda. La política tendrá que conceder permiso a la función de Lambda para interactuar con el servicio. Puede crear la política de dos maneras:
1. Como una política integrada que solo se usa con ese rol.

2. Como una política independiente que puede adjuntar a cualquier rol. En AWS, esta última se denomina política administrada por el cliente.

Siempre es una buena práctica asignar la menor cantidad de permisos posible al rol. En el siguiente ejemplo, en el que leerá la tabla de DynamoDB, tendrá que conceder al rol de Lambda dos permisos: dynamodb:GetItem y dynamodb:DescribeTable. Además, limitará esos permisos a la tabla específica que le interese.

Primero, cree una nueva tabla de DynamoDB llamada People. Los siguientes comandos funcionarán con PowerShell, si usa la línea de comandos de Windows o el shell de Linux necesitará un escape diferente para las cadenas.

Ejecute lo siguiente:
aws dynamodb create-table --table-name People --attribute-definitions AttributeName=PersonId,AttributeType=N --key-schema AttributeName=PersonId,KeyType=HASH --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
Guarde el ARN de la tabla; lo utilizará en un momento. Estará cerca de la parte inferior de la salida.

Añada algunos elementos a la tabla:
aws dynamodb put-item --table-name People --item '{"PersonId":{"N":"1"},"State":{"S":"MA"}, "FirstName": {"S":"Alice"}, "LastName": {"S":"Andrews"}}'
aws dynamodb put-item --table-name People --item '{"PersonId":{"N":"2"},"State":{"S":"MA"}, "FirstName": {"S":"Ben"}, "LastName": {"S":"Bradley"}}'
aws dynamodb put-item --table-name People --item '{"PersonId":{"N":"3"},"State":{"S":"MA"}, "FirstName": {"S":"Claire"}, "LastName": {"S":"Connor"}}'
Ahora tiene una tabla con tres elementos.

A continuación, cree una función de Lambda con:
dotnet new lambda.EmptyFunction -n LambdaFunctionDynamoDB 
Cambie al directorio LambdaFunctionDynamoDB /src/LambdaFunctionDynamoDB y añada el paquete NuGet AWSSDK.DynamoDBv2:
cd LambdaFunctionDynamoDB /src/LambdaFunctionDynamoDB 
dotnet add package AWSSDK.DynamoDBv2
A continuación, abra el archivo Function.cs y sustituya el código por el siguiente:
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.Lambda.Core;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace LambdaFunctionDynamoDB ;

public class Function
{
   public async Task<string> FunctionHandler(ILambdaContext lambdaContext)
 {
   AmazonDynamoDBConfig clientConfig = new AmazonDynamoDBConfig(); 
   AmazonDynamoDBClient client = new AmazonDynamoDBClient(clientConfig);
   DynamoDBContext dynamoDbContext = new DynamoDBContext(client);

   Person person = await dynamoDbContext.LoadAsync<Person>(1);

   return $"{person.FirstName} {person.LastName} lives in {person.State}";
 }
}

[DynamoDBTable("People")]
public class Person
{
    [DynamoDBHashKey]
    public int PersonId {get; set;}
    public string State {get; set;}
    public string FirstName {get; set;}
    public string LastName {get; set;}
}
Despliegue la función de Lambda en AWS Lambda mediante:
dotnet lambda deploy-function LambdaFunctionDynamoDB

Despliegue la función de Lambda en AWS Lambda mediante:

dotnet lambda deploy-function LambdaFunctionDynamoDB

A continuación, se le preguntará “Seleccione el rol de IAM para proporcionar las credenciales de AWS a su código”. Es posible que se le presente una lista de los roles que creó anteriormente, pero al final de la lista aparecerá la opción “*** Crear un nuevo rol de IAM ***”, escriba ese número junto a esa opción.

Se le pedirá que “Introduzca el nombre del nuevo rol de IAM:”. Escriba “LambdaFunctionDynamoDBRole”.

A continuación, se le pedirá que “Seleccione la política de IAM para adjuntarla a la nueva función y conceder permisos” y se mostrará una lista de políticas. Seleccione AWSLambdaBasicExecutionRole, es el número 6 de mi lista. (Sé que hay una política llamada AWSLambdaDynamoDBExecutionRole, pero el objetivo de este módulo es mostrarle cómo agregar usted mismo los permisos necesarios).

Intente invocar la función de Lambda mediante:

dotnet lambda invoke-function LambdaFunctionDynamoDB 
Recibirá un mensaje de error largo, pero muy cerca de la parte superior verá algo como:
 "errorMessage": "User: arn:aws:sts::YOUR_ACCOUNT_NUMBER:assumed-role/LambdaFunctionDynamoDB Role/LambdaFunctionDynamoDB  is not authorized to perform: dynamodb:DescribeTable on resource: arn:aws:dynamodb:us-east-1:YOUR_ACCOUNT_NUMBER:table/People because no identity-based policy allows the dynamodb:DescribeTable action"
Considere el mensaje: “... ninguna política basada en la identidad permite la acción dynamodb:DescribeTable”.

Esto indica que el rol en el que se ejecuta la función de Lambda no tiene el permiso dynamodb:DescribeTable requerido.

Para solucionarlo, debe añadir una política que conceda el permiso dynamodb:DescribeTable al rol. Como se mencionó anteriormente, puede agregar una política en línea (solo para este rol) o una política independiente (disponible para todos los roles).

Cree un archivo denominado DynamoDBAccessPolicy.json en la carpeta LambdaFunctionDynamoDB /src/LambdaFunctionDynamoDB.

Edite DynamoDBAccessPolicy, pero utilice su número de cuenta en el recurso:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:DescribeTable"
            ],
            "Resource": "arn:aws:dynamodb:us-east-1:YOUR_ACCOUNT_NUMBER:table/People"
        }
    ]
}
Ejecute lo siguiente:
aws iam put-role-policy --role-name LambdaFunctionDynamoDBRole --policy-name LambdaFunctionDynamoDBAccess --policy-document file://DynamoDBAccessPolicy.json
La política puede tardar un tiempo en entrar en vigor. Puede esperar unos minutos o volver a desplegar la función de Lambda. Si desea volver a desplegar la función, ejecute:
dotnet lambda deploy-function LambdaFunctionDynamoDB 
Una vez que haya desplegado la función de Lambda, puede volver a invocarla mediante:
dotnet lambda invoke-function LambdaFunctionDynamoDB
Otro error.

Esta vez el mensaje es:
"errorMessage": "User: arn:aws:sts::YOUR_ACCOUNT_NUMBER:assumed-role/LambdaFunctionDynamoDB Role/LambdaFunctionDynamoDB  is not authorized to perform: dynamodb:GetItem on resource: arn:aws:dynamodb:us-east-1:YOUR_ACCOUNT_NUMBER:table/People because no identity-based policy allows the dynamodb:GetItem action",
Debe añadir “dynamodb:GetItem” a la matriz de permisos de la política.

Actualice el archivo DynamoDBAccessPolicy.json con lo siguiente:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:DescribeTable",
        "dynamodb:GetItem"
      ],
      "Resource": "arn:aws:dynamodb:us-east-1:YOUR_ACCOUNT_NUMBER:table/People"
    }
  ]
}
Vuelva a desplegar la función de Lambda:
dotnet lambda deploy-function LambdaFunctionDynamoDB
Invoque de nuevo:
dotnet lambda invoke-function LambdaFunctionDynamoDB 
¡Correcto!
Amazon Lambda Tools for .NET Core applications (5.4.2)
Project Home: https://github.com/aws/aws-extensions-for-dotnet-cli, https://github.com/aws/aws-lambda-dotnet

Payload:
"Alice Andrews lives in MA"
Los mensajes de error de Lambda resultarán muy útiles a la hora de intentar conceder los mínimos permisos posibles a un rol, pero como ha visto, puede que tenga que repetir este proceso varias veces.

Otra opción es colocar el cursor sobre el método del SDK que esté utilizando; los metadatos pueden contener información útil sobre los permisos. No todos los metadatos del método contendrán información de permisos.
También debe consultar la documentación del servicio de AWS para obtener información sobre los permisos necesarios.

Ahora sabe cómo averiguar qué permisos necesita su función y cómo conceder los permisos correctos al rol en el que se ejecutan sus funciones de Lambda.

Permitir que otros servicios invoquen funciones de Lambda

Tendrá muchos escenarios en los que necesitará que otro servicio invoque una función de Lambda por usted. Algunos escenarios comunes son la llegada de un mensaje a una cola, la llegada de un evento a una secuencia de Kinesis, un cambio en un objeto/bucket en S3 o la llegada de una solicitud a una API Gateway. En cada uno de estos casos, otro servicio de AWS invocará la función de Lambda.

En la sección anterior, aprendió a conceder permisos a la función de Lambda para realizar acciones en otros servicios. En esta sección, verá cómo conceder permisos a otros servicios para invocar su función de Lambda.

Si utiliza las plantillas sin servidor.*, probablemente ya esté concediendo a una API Gateway el permiso necesario para invocar su función de Lambda. Si ha desplegado una función de este tipo, vaya a la pestaña Configuración, seleccione Permisos a la izquierda y desplácese hasta la sección Política basada en recursos. Verá políticas que permiten a la API Gateway invocar su función de Lambda. Esta política se agregó mediante el comando dotnet lambda deploy-serverless y el archivo serverless.template de su proyecto.

En la imagen siguiente, puede ver dos declaraciones de política que permiten a una API Gateway invocar la función de Lambda.
Sin embargo, el ejemplo en el que trabajará permite que un bucket de S3 invoque su función de Lambda cada vez que cree o elimine un archivo de ese bucket.

Cree el bucket S3

El primer paso es crear un bucket de S3.

Si desea que su bucket esté en us-east-1, puede utilizar el siguiente comando:
aws s3api create-bucket --bucket my-unique-bucket-name-lambda-course
Si desea que su bucket esté en una región diferente, puede utilizar el siguiente comando:
aws s3api create-bucket --bucket my-unique-bucket-name-lambda-course --create-bucket-configuration LocationConstraint=REGION
Para obtener una lista de las regiones válidas para LocationConstraint, consulte el siguiente enlace: https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/create-bucket.html.

Tenga en cuenta que el nombre del bucket debe ser único. Consulte aquí para obtener más detalles

Cree la función de Lambda

Hay una plantilla de funciones de Lambda que le ayudará a gestionar los eventos de S3. Ya tiene agregados los paquetes NuGet del SDK necesarios. Aún debe agregar el permiso de rol requerido y crear la política basada en recursos para permitir que S3 invoque la función.

Desde la línea de comandos, ejecute:
dotnet new lambda.S3 -n S3EventHandler
Cambie al directorio S3EventHandler/src/S3EventHandler:
cd S3EventHandler/src/S3EventHandler
Abra el archivo Function.cs y sustituya el método FunctionHandler por el siguiente:
public async Task FunctionHandler(S3Event evnt, ILambdaContext context)
{
    context.Logger.LogInformation($"A S3 event has been received, it contains {evnt.Records.Count} records.");   
    foreach (var s3Event in evnt.Records)
    {
        context.Logger.LogInformation($"Action: {s3Event.EventName}, Bucket: {s3Event.S3.Bucket.Name}, Key: {s3Event.S3.Object.Key}");
       if (!s3Event.EventName.Contains("Delete"))
        {   
            try 
            {
                var response = await this.S3Client.GetObjectMetadataAsync(s3Event.S3.Bucket.Name, s3Event.S3.Object.Key);
                context.Logger.LogInformation( $"The file type is {response.Headers.ContentType}");
            } 
            catch (Exception e) 
            {
                context.Logger.LogError(e.Message);
                context.Logger.LogError($"An exception occurred while retrieving {s3Event.S3.Bucket.Name}/{s3Event.S3.Object.Key}. Exception - ({e.Message})");
            }
        } 
        else 
        {
            context.Logger.LogInformation($"You deleted {s3Event.S3.Bucket.Name}/{s3Event.S3.Object.Key}");
        }
    }
}
Cuando la función de Lambda reciba un evento de S3, registrará los detalles del evento en CloudWatch. Si el evento de S3 responde a la creación de un objeto, la función utilizará el SDK de AWS para realizar una llamada a S3 para obtener el tipo de archivo y, a continuación, registrará los detalles.

Si el evento de S3 responde a la eliminación de un objeto, la función registrará los nombres de los buckets o las claves en CloudWatch.

Desplegar la función de Lambda

Desde la línea de comandos, ejecute:
dotnet lambda deploy-function S3EventHandler

A continuación, se le preguntará “Seleccione el rol de IAM para proporcionar las credenciales de AWS a su código”. Es posible que se le presente una lista de los roles que creó anteriormente, pero al final de la lista aparecerá la opción “*** Crear un nuevo rol de IAM ***”, escriba ese número junto a esa opción.

Se le pedirá que “Introduzca el nombre del nuevo rol de IAM:”. Escriba “S3EventHandlerRole”.

A continuación, se le pedirá que “Seleccione la política de IAM para adjuntarla a la nueva función y conceder permisos” y se mostrará una lista de políticas. Seleccione AWSLambdaBasicExecutionRole, es el número 6 de mi lista. Tendrá que añadir una política para otorgar acceso al bucket de S3 para que funcione la llamada GetObjectMetadataAsync(..).

Otorgue permisos a la función de Lambda para obtener los metadatos del objeto

En el ejemplo anterior, creó una política integrada que se aplicaba únicamente al rol que estaba utilizando. Esta vez, creará una política que podrá utilizar cualquier rol.

Verá un par de maneras para hacerlo.
Línea de comandos
 
Cree un archivo con el nombre S3AccessPolicyForCourseBucket.json en la carpeta S3EventHandler/src/S3EventHandler.

La política tendrá este aspecto, pero con el nombre del bucket en el recurso. Tenga en cuenta el /* al final; esto significa que s3:GetObject se aplica a todos los objetos del bucket:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::my-unique-bucket-name-lambda-course/*"
        }
    ]
}
Ejecute lo siguiente:
aws iam create-policy --policy-name S3AccessPolicyForCourseBucket --policy-document file://S3AccessPolicyForCourseBucket.json
Tome nota del ARN de la política.

A continuación, adjunte la política al rol que creó anteriormente. Ejecute lo siguiente:
aws iam attach-role-policy --role-name S3EventHandlerRole --policy-arn arn:aws:iam::694977046108:policy/S3AccessPolicyForCourseBucket
Consola de AWS
 
Vaya a la función de Lambda en la Consola de AWS.

Haga clic en la pestaña Configuración, luego en Permisos a la izquierda y haga clic en el nombre del rol.
Se abre una nueva página con los detalles del rol.

Haga clic en Agregar permisos y Adjuntar políticas.

Haga clic en Crear política

En la sección de servicios, escriba s3 en el cuadro de texto resaltado y seleccione S3.

En la sección Acciones, escriba getobject y seleccione GetObject en la lista.

En la sección de recursos, elija Específico y haga clic en Agregar ARN.

Escriba el nombre del bucket y seleccione Cualquiera para el nombre del objeto.
Escriba un nombre para la política y haga clic en Crear política

Vuelva a la pestaña en la que hizo clic en Crear política. Siga estos pasos:

1. Recargue la lista de políticas

2. Escriba s3AccessPolicyForCourseBucket en el filtro

3. Marque la casilla situada junto a la política

4. Haga clic en Adjuntar políticas

En este punto, tiene un bucket de S3, la función de Lambda y los permisos necesarios para obtener los metadatos del objeto del bucket de S3.

Ahora es el momento de conectar el bucket de S3 a la función de Lambda para que los eventos de creación y eliminación activen la función de Lambda.

Active la función de Lambda desde el bucket de S3

Como ha visto, es bueno poder utilizar las herramientas de línea de comandos de AWS y la consola de interfaz de usuario. Para el siguiente paso, utilizará la consola de interfaz de usuario, porque es más fácil y claro para este paso.

Abra la lista de buckets en S3 https://s3.console.aws.amazon.com/s3/buckets.

Haga clic en el que creó.
Abra la pestaña Propiedades.

Desplácese hacia abajo hasta la sección Notificaciones de eventos.

Haga clic en Crear notificación de evento.

Introduzca un nombre para la notificación del evento.

Seleccione las dos primeras casillas de la izquierda: Todos los eventos de creación de objetos y Todos los eventos de eliminación de objetos.

Desplácese hasta la sección Destino en la parte inferior.

Elija la función de Lambda como destino.

En la lista desplegable, escriba el nombre de la función de Lambda que creó anteriormente.

Haga clic en Guardar los cambios.

Cuando termine, verá esta nueva notificación de evento en la sección Notificaciones de eventos.

En la Consola de AWS, vaya a la función de Lambda que creó anteriormente.

Tenga en cuenta que S3 ahora aparece como activador de la función de Lambda.

Haga clic en la pestaña Configuración y, a continuación, en Permisos a la izquierda.

Desplácese hacia abajo hasta la sección Política basada en recursos

Verá una declaración de política que permite a S3 invocar la función de Lambda.
Haga clic en el ID de la declaración para revisar la declaración de la política.

Realice pruebas

Esta función de Lambda no devuelve nada al autor de la llamada, S3 en este caso.

En su lugar, la función de Lambda se registra en CloudWatch, por lo que tiene que ir allí para ver su función en acción.

Cree un archivo de texto en su computadora para subirlo a S3.

Desde la línea de comandos, ejecute:
aws s3api put-object --bucket my-unique-bucket-name-lambda-course --key Hello.txt --body Hello.txt --content-type "text/plain"
aws s3api delete-object --bucket my-unique-bucket-name-lambda-course --key Hello.txt

Ahora vaya a su función de Lambda en la Consola de AWS y compruebe los registros.

Haga clic en la pestaña Supervisar y, a continuación, en Ver registros en CloudWatch.

Se le presentará una lista de secuencias de registro; elija la más reciente.
Debería ver las entradas de registro que muestran los eventos de S3 y el texto que registró en CloudWatch.
Otra forma de comprobar los registros es utilizar la extensión de AWS para Visual Studio, Visual Studio Code y Rider.

El proceso es similar para los tres: abra la extensión de AWS, haga clic en los registros de CloudWatch y busque el grupo o secuencia de registros de /aws/lambda/S3EventHandler. A continuación, abra la secuencia más reciente.
Otra forma de comprobar los registros es utilizar la extensión de AWS para Visual Studio, Visual Studio Code y Rider.

El proceso es similar para los tres: abra la extensión de AWS, haga clic en los registros de CloudWatch y busque el grupo o secuencia de registros de /aws/lambda/S3EventHandler. A continuación, abra la secuencia más reciente.

Conclusión

En este módulo relativamente corto, cubrió muchos conocimientos. Algunos dirían que comprender las funciones y las políticas es una de las cosas más importantes que hay que aprender en AWS. Esperamos que esto le haya dado una buena base en el tema en relación con las funciones de Lambda.

Este es el punto clave: si desea que su función de Lambda interactúe con otros servicios de AWS, debe otorgar permisos a su función para que actúe en ese otro servicio.

Si desea que otros servicios invoquen su función, debe utilizar políticas basadas en recursos para dar a esos servicios acceso a su función.

Pruebas de conocimientos

Ya completó el módulo 4: Trabajar con otros servicios de AWS. El siguiente test le permitirá comprobar lo que ha aprendido hasta ahora.

1. Cuando desea que otro servicio invoque una función de Lambda, ¿qué debe hacer? (seleccione una opción)

a. Crear un documento de ACL que conceda permisos al rol que ejecuta el otro servicio para invocar la función de Lambda5

b. Crear un documento de política basada en recursos que dé permiso a los servicios de llamada para invocar la función de Lambda

c. Nada, Lambda confía en todos los demás servicios de AWS

d. Agregar los permisos correctos al rol en el que se ejecuta la función de Lambda1

2. ¿Qué necesita añadir a un rol para concederle permisos de acceso a los servicios de AWS? (seleccione uno)

a. Nada, todos los roles pueden acceder a otros servicios de AWS.

b. Una política basada en los recursos

c. Una política con los permisos necesarios

d. Un documento de lista de control de acceso

3. ¿Cuáles son las dos formas de crear una política administrada por el cliente para utilizarla con el rol que desempeña una función de Lambda? (seleccione dos)

a. Mediante la línea de comandos

b. Incluirla en el código fuente de la función

c. Mediante esa Consola de AWS

d. Añadirla a la carga útil al ejecutar la función

Respuestas: 1-b, 2-c, 3-ac

Conclusión

En este módulo relativamente corto, cubrió muchos conocimientos. Algunos dirían que comprender las funciones y las políticas es una de las cosas más importantes que hay que aprender en AWS. Esperamos que esto le haya dado una buena base en el tema en relación con las funciones de Lambda.

Este es el punto clave: si desea que su función de Lambda interactúe con otros servicios de AWS, debe otorgar permisos a su función para que actúe en ese otro servicio.

Si desea que otros servicios invoquen su función, debe utilizar políticas basadas en recursos para dar a esos servicios acceso a su función.

¿Le resultó útil esta página?

PRUEBAS UNITARIAS Y DEPURACIÓN