

# Uso de AWS Lambda con Amazon RDS
<a name="services-rds"></a>

Puede conectar una función de Lambda a una base de datos de Amazon Relational Database Service (Amazon RDS) directamente y a través de un Amazon RDS Proxy. Las conexiones directas son útiles en escenarios sencillos y los proxies se recomiendan para la producción. Un proxy de base de datos administra un grupo de conexiones de bases de datos compartidas que permite que su función alcance niveles altos de simultaneidad sin agotar las conexiones de base de datos.

Se recomienda utilizar Amazon RDS Proxy para las funciones de Lambda que establezcan conexiones cortas y frecuentes a bases de datos o que abran y cierren una gran cantidad de conexiones a bases de datos. Para obtener más información, consulte [Conexión automática de una función de Lambda y una instancia de base de datos](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/lambda-rds-connect.html) en la Guía para desarrolladores de Amazon Relational Database Service.

**sugerencia**  
Para conectar rápidamente una función de Lambda a una base de datos de Amazon RDS, puede utilizar el asistente guiado de la consola. Para abrir el asistente, haga lo siguiente:  
Abra la página de [Funciones](https://console.aws.amazon.com/lambda/home#/functions) en la consola de Lambda.
Seleccione la función a la que desea conectar una base de datos.
En la pestaña **Configuración**, seleccione **Bases de datos de RDS**.
Seleccione **Conectar a la base de datos de RDS**.
Después de haber conectado la función a una base de datos, podrá crear un proxy. Para ello, elija **Agregar proxy**.

## Configuración de la función para que funcione con los recursos de RDS
<a name="rds-configuration"></a>

En la consola de Lambda, puede configurar y aprovisionar determinadas instancias de bases de datos y recursos de proxy de Amazon RDS. Para ello, vaya a las **bases de datos de RDS** en la pestaña **Configuración**. Como alternativa, también puede crear y configurar conexiones a funciones de Lambda en la consola de Amazon RDS. Al configurar una instancia de base de datos de RDS para utilizarla con Lambda, tenga en cuenta los siguientes criterios:
+ Para conectarse a una base de datos, su función debe estar en la misma Amazon VPC donde se ejecuta la base de datos.
+ Puede utilizar las bases de datos de Amazon RDS con los motores MySQL, MariaDB, PostgreSQL o Microsoft SQL Server.
+ También puede utilizar clústeres de bases de datos de Aurora con motores MySQL o PostgreSQL.
+ Debe proporcionar un secreto de Secrets Manager para la autenticación de la base de datos.
+ Un rol de IAM debe otorgar permiso para utilizar el secreto y una política de confianza debe permitir que Amazon RDS asuma el rol.
+  La entidad principal de IAM que usa la consola para configurar el recurso de Amazon RDS y conectarlo a su función debe tener los siguientes permisos:

### Ejemplo de política de permisos
<a name="rds-lambda-permissions"></a>

**nota**  
 Solo necesitará los permisos de Amazon RDS Proxy si configura un Amazon RDS Proxy para administrar un grupo de conexiones de base de datos. 

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:CreateSecurityGroup",
        "ec2:DescribeSecurityGroups",
        "ec2:DescribeSubnets",
        "ec2:DescribeVpcs",
        "ec2:AuthorizeSecurityGroupIngress",
        "ec2:AuthorizeSecurityGroupEgress",
        "ec2:RevokeSecurityGroupEgress",
        "ec2:CreateNetworkInterface",
        "ec2:DeleteNetworkInterface",
        "ec2:DescribeNetworkInterfaces"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "rds-db:connect",
        "rds:CreateDBProxy",
        "rds:CreateDBInstance",
        "rds:CreateDBSubnetGroup",
        "rds:DescribeDBClusters",
        "rds:DescribeDBInstances",
        "rds:DescribeDBSubnetGroups",
        "rds:DescribeDBProxies",
        "rds:DescribeDBProxyTargets",
        "rds:DescribeDBProxyTargetGroups",
        "rds:RegisterDBProxyTargets",
        "rds:ModifyDBInstance",
        "rds:ModifyDBProxy"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "lambda:CreateFunction",
        "lambda:ListFunctions",
        "lambda:UpdateFunctionConfiguration"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iam:AttachRolePolicy",
        "iam:CreateRole",
        "iam:CreatePolicy"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetResourcePolicy",
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:ListSecretVersionIds",
        "secretsmanager:CreateSecret"
      ],
      "Resource": "*"
    }
  ]
}
```

------

Amazon RDS cobra una tarifa por hora para los proxies en función del tamaño de la instancia de la base de datos. Consulte los [precios de los proxies de RDS](https://aws.amazon.com/rds/proxy/pricing/) para obtener más información. Para obtener más información general sobre las conexiones proxy, consulte [Uso de Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html) en la Guía del usuario de Amazon RDS.

### Requisitos de SSL/TLS para las conexiones de Amazon RDS
<a name="rds-lambda-certificates"></a>

Para establecer conexiones SSL/TLS seguras a una instancia de base de datos de Amazon RDS, la función de Lambda debe verificar la identidad del servidor de base de datos mediante un certificado de confianza. Lambda administra estos certificados de forma diferente según el tipo de paquete de implementación:
+ [Archivos en formato .zip](configuration-function-zip.md): la gestión de los certificados varía según el tiempo de ejecución:
  + **Node.js 18 y versiones anteriores**: Lambda incluye de manera automática los certificados CA y los certificados RDS.
  + **Node.js 20 y posteriores**: Lambda ya no carga certificados CA adicionales de forma predeterminada. Establezca la variable de entorno `NODE_EXTRA_CA_CERTS` en `/var/runtime/ca-cert.pem`.

  Los certificados de Amazon RDS de las nuevas Regiones de AWS pueden tardar hasta 4 semanas en agregarse a los tiempos de ejecución administrados por Lambda.
+ [Imágenes de contenedores](images-create.md): las imágenes de base de AWS solo incluyen certificados de CA. Si su función se conecta a una instancia de base de datos de Amazon RDS, es necesario que incluya los certificados correspondientes en la imagen del contenedor. En su Dockerfile, descargue el [paquete de certificados correspondiente a la Región de AWS donde se aloja su base de datos](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html#UsingWithRDS.SSL.CertificatesDownload). Ejemplo:

  ```
  RUN curl https://truststore.pki.rds.amazonaws.com/us-east-1/us-east-1-bundle.pem -o /us-east-1-bundle.pem
  ```

Este comando descarga el paquete de certificados de Amazon RDS y lo guarda en la ruta absoluta `/us-east-1-bundle.pem` en el directorio raíz de su contenedor. Cuando configure la conexión a la base de datos en el código de su función, debe hacer referencia a esta ruta exacta. Ejemplo:

------
#### [ Node.js ]

La función `readFileSync` es necesaria porque los clientes de bases de datos de Node.js necesitan el contenido real del certificado en la memoria, no solo la ruta al archivo de certificado. Sin `readFileSync`, el cliente interpreta la cadena de ruta como contenido del certificado, lo que genera un error “certificado autofirmado en la cadena de certificados”.

**Example Configuración de una conexión de Node.js para la función de OCI**  

```
import { readFileSync } from 'fs';

// ...

let connectionConfig = {
    host: process.env.ProxyHostName,
    user: process.env.DBUserName,
    password: token,
    database: process.env.DBName,
    ssl: {
        ca: readFileSync('/us-east-1-bundle.pem') // Load RDS certificate content from file into memory
    }
};
```

------
#### [ Python ]

**Example Configuración de una conexión de Python para la función de OCI**  

```
connection = pymysql.connect(
    host=proxy_host_name,
    user=db_username,
    password=token,
    db=db_name,
    port=port,
    ssl={'ca': '/us-east-1-bundle.pem'}  #Path to the certificate in container
)
```

------
#### [ Java ]

Para las funciones de Java que usan conexiones de JDBC, la cadena de conexión debe incluir lo siguiente:
+ `useSSL=true`
+ `requireSSL=true`
+ Un parámetro `sslCA` que apunte a la ubicación del certificado de Amazon RDS en la imagen del contenedor

**Example Cadena de conexión de Java para la función de OCI**  

```
// Define connection string
String connectionString = String.format("jdbc:mysql://%s:%s/%s?useSSL=true&requireSSL=true&sslCA=/us-east-1-bundle.pem", // Path to the certificate in container
        System.getenv("ProxyHostName"),
        System.getenv("Port"),
        System.getenv("DBName"));
```

------
#### [ .NET ]

**Example Cadena de conexión de .NET para la conexión de MySQL en la función de OCI**  

```
/// Build the Connection String with the Token 
string connectionString = $"Server={Environment.GetEnvironmentVariable("RDS_ENDPOINT")};" +
                         $"Port={Environment.GetEnvironmentVariable("RDS_PORT")};" +
                         $"Uid={Environment.GetEnvironmentVariable("RDS_USERNAME")};" +
                         $"Pwd={authToken};" +
                         "SslMode=Required;" +
                         "SslCa=/us-east-1-bundle.pem";  // Path to the certificate in container
```

------
#### [ Go ]

Para las funciones de Go que usan conexiones de MySQL, cargue el certificado de Amazon RDS en un grupo de certificados y regístrelo con el controlador de MySQL. A continuación, la cadena de conexión debe hacer referencia a esta configuración mediante el parámetro `tls`.

**Example Código de Go para la conexión de MySQL en la función de OCI**  

```
import (
    "crypto/tls"
    "crypto/x509"
    "os"
    "github.com/go-sql-driver/mysql"
)

...

// Create certificate pool and register TLS config
rootCertPool := x509.NewCertPool()
pem, err := os.ReadFile("/us-east-1-bundle.pem")  // Path to the certificate in container
if err != nil {
    panic("failed to read certificate file: " + err.Error())
}
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
    panic("failed to append PEM")
}

mysql.RegisterTLSConfig("custom", &tls.Config{
    RootCAs: rootCertPool,
})

dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?allowCleartextPasswords=true&tls=custom",
    dbUser, authenticationToken, dbEndpoint, dbName,
)
```

------
#### [ Ruby ]

**Example Configuración de una conexión de Ruby para la función de OCI**  

```
conn = Mysql2::Client.new(
    host: endpoint,
    username: user,
    password: token,
    port: port,
    database: db_name,
    sslca: '/us-east-1-bundle.pem',  # Path to the certificate in container
    sslverify: true
)
```

------

## Conexión a una base de datos de Amazon RDS en una función de Lambda
<a name="rds-connection"></a>

En el siguiente ejemplo de código, se muestra cómo se lleva a cabo la implementación de una función de Lambda que se conecta a una base de datos de Amazon RDS. La función realiza una solicitud sencilla a la base de datos y devuelve el resultado.

**nota**  
Estos ejemplos de código son válidos únicamente para [paquetes de implementación .zip](configuration-function-zip.md). Si va a implementar la función mediante una [imagen de contenedor](images-create.md), debe especificar el archivo de certificado de Amazon RDS en el código de la función, tal como se explica en la [sección anterior](#oci-certificate).

------
#### [ .NET ]

**SDK para .NET**  
 Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el repositorio de [ejemplos de tecnología sin servidor](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam). 
Conexión a una base de datos de Amazon RDS en una función de Lambda mediante .NET.  

```
using System.Data;
using System.Text.Json;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using MySql.Data.MySqlClient;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace aws_rds;

public class InputModel
{
    public string key1 { get; set; }
    public string key2 { get; set; }
}

public class Function
{
    /// <summary>
    // Handles the Lambda function execution for connecting to RDS using IAM authentication.
    /// </summary>
    /// <param name="input">The input event data passed to the Lambda function</param>
    /// <param name="context">The Lambda execution context that provides runtime information</param>
    /// <returns>A response object containing the execution result</returns>

    public async Task<APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
    {
        // Sample Input: {"body": "{\"key1\":\"20\", \"key2\":\"25\"}"}
        var input = JsonSerializer.Deserialize<InputModel>(request.Body);

        /// Obtain authentication token
        var authToken = RDSAuthTokenGenerator.GenerateAuthToken(
            Environment.GetEnvironmentVariable("RDS_ENDPOINT"),
            Convert.ToInt32(Environment.GetEnvironmentVariable("RDS_PORT")),
            Environment.GetEnvironmentVariable("RDS_USERNAME")
        );

        /// Build the Connection String with the Token 
        string connectionString = $"Server={Environment.GetEnvironmentVariable("RDS_ENDPOINT")};" +
                                  $"Port={Environment.GetEnvironmentVariable("RDS_PORT")};" +
                                  $"Uid={Environment.GetEnvironmentVariable("RDS_USERNAME")};" +
                                  $"Pwd={authToken};";


        try
        {
            await using var connection = new MySqlConnection(connectionString);
            await connection.OpenAsync();

            const string sql = "SELECT @param1 + @param2 AS Sum";

            await using var command = new MySqlCommand(sql, connection);
            command.Parameters.AddWithValue("@param1", int.Parse(input.key1 ?? "0"));
            command.Parameters.AddWithValue("@param2", int.Parse(input.key2 ?? "0"));

            await using var reader = await command.ExecuteReaderAsync();
            if (await reader.ReadAsync())
            {
                int result = reader.GetInt32("Sum");

                //Sample Response: {"statusCode":200,"body":"{\"message\":\"The sum is: 45\"}","isBase64Encoded":false}
                return new APIGatewayProxyResponse
                {
                    StatusCode = 200,
                    Body = JsonSerializer.Serialize(new { message = $"The sum is: {result}" })
                };
            }

        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }

        return new APIGatewayProxyResponse
        {
            StatusCode = 500,
            Body = JsonSerializer.Serialize(new { error = "Internal server error" })
        };
    }
}
```

------
#### [ Go ]

**SDK para Go V2**  
 Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el repositorio de [ejemplos de tecnología sin servidor](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam). 
Conexión a una base de datos de Amazon RDS en una función de Lambda mediante Go.  

```
/*
Golang v2 code here.
*/

package main

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"os"

	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/feature/rds/auth"
	_ "github.com/go-sql-driver/mysql"
)

type MyEvent struct {
	Name string `json:"name"`
}

func HandleRequest(event *MyEvent) (map[string]interface{}, error) {

	var dbName string = os.Getenv("DatabaseName")
	var dbUser string = os.Getenv("DatabaseUser")
	var dbHost string = os.Getenv("DBHost") // Add hostname without https
	var dbPort int = os.Getenv("Port")      // Add port number
	var dbEndpoint string = fmt.Sprintf("%s:%d", dbHost, dbPort)
	var region string = os.Getenv("AWS_REGION")

	cfg, err := config.LoadDefaultConfig(context.TODO())
	if err != nil {
		panic("configuration error: " + err.Error())
	}

	authenticationToken, err := auth.BuildAuthToken(
		context.TODO(), dbEndpoint, region, dbUser, cfg.Credentials)
	if err != nil {
		panic("failed to create authentication token: " + err.Error())
	}

	dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=true&allowCleartextPasswords=true",
		dbUser, authenticationToken, dbEndpoint, dbName,
	)

	db, err := sql.Open("mysql", dsn)
	if err != nil {
		panic(err)
	}

	defer db.Close()

	var sum int
	err = db.QueryRow("SELECT ?+? AS sum", 3, 2).Scan(&sum)
	if err != nil {
		panic(err)
	}
	s := fmt.Sprint(sum)
	message := fmt.Sprintf("The selected sum is: %s", s)

	messageBytes, err := json.Marshal(message)
	if err != nil {
		return nil, err
	}

	messageString := string(messageBytes)
	return map[string]interface{}{
		"statusCode": 200,
		"headers":    map[string]string{"Content-Type": "application/json"},
		"body":       messageString,
	}, nil
}

func main() {
	lambda.Start(HandleRequest)
}
```

------
#### [ Java ]

**SDK para Java 2.x**  
 Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el repositorio de [ejemplos de tecnología sin servidor](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam). 
Conexión a una base de datos de Amazon RDS en una función de Lambda mediante Java.  

```
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.rdsdata.RdsDataClient;
import software.amazon.awssdk.services.rdsdata.model.ExecuteStatementRequest;
import software.amazon.awssdk.services.rdsdata.model.ExecuteStatementResponse;
import software.amazon.awssdk.services.rdsdata.model.Field;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class RdsLambdaHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    @Override
    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent event, Context context) {
        APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent();

        try {
            // Obtain auth token
            String token = createAuthToken();

            // Define connection configuration
            String connectionString = String.format("jdbc:mysql://%s:%s/%s?useSSL=true&requireSSL=true",
                    System.getenv("ProxyHostName"),
                    System.getenv("Port"),
                    System.getenv("DBName"));

            // Establish a connection to the database
            try (Connection connection = DriverManager.getConnection(connectionString, System.getenv("DBUserName"), token);
                 PreparedStatement statement = connection.prepareStatement("SELECT ? + ? AS sum")) {

                statement.setInt(1, 3);
                statement.setInt(2, 2);

                try (ResultSet resultSet = statement.executeQuery()) {
                    if (resultSet.next()) {
                        int sum = resultSet.getInt("sum");
                        response.setStatusCode(200);
                        response.setBody("The selected sum is: " + sum);
                    }
                }
            }

        } catch (Exception e) {
            response.setStatusCode(500);
            response.setBody("Error: " + e.getMessage());
        }

        return response;
    }

    private String createAuthToken() {
        // Create RDS Data Service client
        RdsDataClient rdsDataClient = RdsDataClient.builder()
                .region(Region.of(System.getenv("AWS_REGION")))
                .credentialsProvider(DefaultCredentialsProvider.create())
                .build();

        // Define authentication request
        ExecuteStatementRequest request = ExecuteStatementRequest.builder()
                .resourceArn(System.getenv("ProxyHostName"))
                .secretArn(System.getenv("DBUserName"))
                .database(System.getenv("DBName"))
                .sql("SELECT 'RDS IAM Authentication'")
                .build();

        // Execute request and obtain authentication token
        ExecuteStatementResponse response = rdsDataClient.executeStatement(request);
        Field tokenField = response.records().get(0).get(0);

        return tokenField.stringValue();
    }
}
```

------
#### [ JavaScript ]

**SDK para JavaScript (v3)**  
 Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el repositorio de [ejemplos de tecnología sin servidor](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam). 
Conexión a una base de datos de Amazon RDS en una función de Lambda mediante JavaScript.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
/* 
Node.js code here.
*/
// ES6+ example
import { Signer } from "@aws-sdk/rds-signer";
import mysql from 'mysql2/promise';

async function createAuthToken() {
  // Define connection authentication parameters
  const dbinfo = {

    hostname: process.env.ProxyHostName,
    port: process.env.Port,
    username: process.env.DBUserName,
    region: process.env.AWS_REGION,

  }

  // Create RDS Signer object
  const signer = new Signer(dbinfo);

  // Request authorization token from RDS, specifying the username
  const token = await signer.getAuthToken();
  return token;
}

async function dbOps() {

  // Obtain auth token
  const token = await createAuthToken();
  // Define connection configuration
  let connectionConfig = {
    host: process.env.ProxyHostName,
    user: process.env.DBUserName,
    password: token,
    database: process.env.DBName,
    ssl: 'Amazon RDS'
  }
  // Create the connection to the DB
  const conn = await mysql.createConnection(connectionConfig);
  // Obtain the result of the query
  const [res,] = await conn.execute('select ?+? as sum', [3, 2]);
  return res;

}

export const handler = async (event) => {
  // Execute database flow
  const result = await dbOps();
  // Return result
  return {
    statusCode: 200,
    body: JSON.stringify("The selected sum is: " + result[0].sum)
  }
};
```
Conexión a una base de datos de Amazon RDS en una función de Lambda mediante TypeScript.  

```
import { Signer } from "@aws-sdk/rds-signer";
import mysql from 'mysql2/promise';

// RDS settings
// Using '!' (non-null assertion operator) to tell the TypeScript compiler that the DB settings are not null or undefined,
const proxy_host_name = process.env.PROXY_HOST_NAME!
const port = parseInt(process.env.PORT!)
const db_name = process.env.DB_NAME!
const db_user_name = process.env.DB_USER_NAME!
const aws_region = process.env.AWS_REGION!


async function createAuthToken(): Promise<string> {

    // Create RDS Signer object
    const signer = new Signer({
        hostname: proxy_host_name,
        port: port,
        region: aws_region,
        username: db_user_name
    });

    // Request authorization token from RDS, specifying the username
    const token = await signer.getAuthToken();
    return token;
}

async function dbOps(): Promise<mysql.QueryResult | undefined> {
    try {
        // Obtain auth token
        const token = await createAuthToken();
        const conn = await mysql.createConnection({
            host: proxy_host_name,
            user: db_user_name,
            password: token,
            database: db_name,
            ssl: 'Amazon RDS' // Ensure you have the CA bundle for SSL connection
        });
        const [rows, fields] = await conn.execute('SELECT ? + ? AS sum', [3, 2]);
        console.log('result:', rows);
        return rows;
    }
    catch (err) {
        console.log(err);
    }
}

export const lambdaHandler = async (event: any): Promise<{ statusCode: number; body: string }> => {
    // Execute database flow
    const result = await dbOps();

    // Return error is result is undefined
    if (result == undefined)
        return {
            statusCode: 500,
            body: JSON.stringify(`Error with connection to DB host`)
        }

    // Return result
    return {
        statusCode: 200,
        body: JSON.stringify(`The selected sum is: ${result[0].sum}`)
    };
};
```

------
#### [ PHP ]

**SDK para PHP**  
 Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el repositorio de [ejemplos de tecnología sin servidor](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam). 
Conexión a una base de datos de Amazon RDS en una función de Lambda mediante PHP.  

```
<?php
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\Handler as StdHandler;
use Bref\Logger\StderrLogger;
use Aws\Rds\AuthTokenGenerator;
use Aws\Credentials\CredentialProvider;

require __DIR__ . '/vendor/autoload.php';

class Handler implements StdHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }


    private function getAuthToken(): string {
        // Define connection authentication parameters
        $dbConnection = [
            'hostname' => getenv('DB_HOSTNAME'),
            'port' => getenv('DB_PORT'),
            'username' => getenv('DB_USERNAME'),
            'region' => getenv('AWS_REGION'),
        ];

        // Create RDS AuthTokenGenerator object
        $generator = new AuthTokenGenerator(CredentialProvider::defaultProvider());

        // Request authorization token from RDS, specifying the username
        return $generator->createToken(
            $dbConnection['hostname'] . ':' . $dbConnection['port'],
            $dbConnection['region'],
            $dbConnection['username']
        );
    }

    private function getQueryResults() {
        // Obtain auth token
        $token = $this->getAuthToken();

        // Define connection configuration
        $connectionConfig = [
            'host' => getenv('DB_HOSTNAME'),
            'user' => getenv('DB_USERNAME'),
            'password' => $token,
            'database' => getenv('DB_NAME'),
        ];

        // Create the connection to the DB
        $conn = new PDO(
            "mysql:host={$connectionConfig['host']};dbname={$connectionConfig['database']}",
            $connectionConfig['user'],
            $connectionConfig['password'],
            [
                PDO::MYSQL_ATTR_SSL_CA => '/path/to/rds-ca-2019-root.pem',
                PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
            ]
        );

        // Obtain the result of the query
        $stmt = $conn->prepare('SELECT ?+? AS sum');
        $stmt->execute([3, 2]);

        return $stmt->fetch(PDO::FETCH_ASSOC);
    }

    /**
     * @param mixed $event
     * @param Context $context
     * @return array
     */
    public function handle(mixed $event, Context $context): array
    {
        $this->logger->info("Processing query");

        // Execute database flow
        $result = $this->getQueryResults();

        return [
            'sum' => $result['sum']
        ];
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**SDK para Python (Boto3)**  
 Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el repositorio de [ejemplos de tecnología sin servidor](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam). 
Conexión a una base de datos de Amazon RDS en una función de Lambda mediante Python.  

```
import json
import os
import boto3
import pymysql

# RDS settings
proxy_host_name = os.environ['PROXY_HOST_NAME']
port = int(os.environ['PORT'])
db_name = os.environ['DB_NAME']
db_user_name = os.environ['DB_USER_NAME']
aws_region = os.environ['AWS_REGION']


# Fetch RDS Auth Token
def get_auth_token():
    client = boto3.client('rds')
    token = client.generate_db_auth_token(
        DBHostname=proxy_host_name,
        Port=port
        DBUsername=db_user_name
        Region=aws_region
    )
    return token

def lambda_handler(event, context):
    token = get_auth_token()
    try:
        connection = pymysql.connect(
            host=proxy_host_name,
            user=db_user_name,
            password=token,
            db=db_name,
            port=port,
            ssl={'ca': 'Amazon RDS'}  # Ensure you have the CA bundle for SSL connection
        )
        
        with connection.cursor() as cursor:
            cursor.execute('SELECT %s + %s AS sum', (3, 2))
            result = cursor.fetchone()

        return result
        
    except Exception as e:
        return (f"Error: {str(e)}")  # Return an error message if an exception occurs
```

------
#### [ Ruby ]

**SDK para Ruby**  
 Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el repositorio de [ejemplos de tecnología sin servidor](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam). 
Conexión a una base de datos de Amazon RDS en una función de Lambda mediante Ruby.  

```
# Ruby code here.

require 'aws-sdk-rds'
require 'json'
require 'mysql2'

def lambda_handler(event:, context:)
  endpoint = ENV['DBEndpoint'] # Add the endpoint without https"
  port = ENV['Port']           # 3306
  user = ENV['DBUser']
  region = ENV['DBRegion']     # 'us-east-1'
  db_name = ENV['DBName']

  credentials = Aws::Credentials.new(
    ENV['AWS_ACCESS_KEY_ID'],
    ENV['AWS_SECRET_ACCESS_KEY'],
    ENV['AWS_SESSION_TOKEN']
  )
  rds_client = Aws::RDS::AuthTokenGenerator.new(
    region: region, 
    credentials: credentials
  )

  token = rds_client.auth_token(
    endpoint: endpoint+ ':' + port,
    user_name: user,
    region: region
  )

  begin
    conn = Mysql2::Client.new(
      host: endpoint,
      username: user,
      password: token,
      port: port,
      database: db_name,
      sslca: '/var/task/global-bundle.pem', 
      sslverify: true,
      enable_cleartext_plugin: true
    )
    a = 3
    b = 2
    result = conn.query("SELECT #{a} + #{b} AS sum").first['sum']
    puts result
    conn.close
    {
      statusCode: 200,
      body: result.to_json
    }
  rescue => e
    puts "Database connection failed due to #{e}"
  end
end
```

------
#### [ Rust ]

**SDK para Rust**  
 Hay más en GitHub. Busque el ejemplo completo y aprenda a configurar y ejecutar en el repositorio de [ejemplos de tecnología sin servidor](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam). 
Conexión a una base de datos de Amazon RDS en una función de Lambda mediante Rust.  

```
use aws_config::BehaviorVersion;
use aws_credential_types::provider::ProvideCredentials;
use aws_sigv4::{
    http_request::{sign, SignableBody, SignableRequest, SigningSettings},
    sign::v4,
};
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
use serde_json::{json, Value};
use sqlx::postgres::PgConnectOptions;
use std::env;
use std::time::{Duration, SystemTime};

const RDS_CERTS: &[u8] = include_bytes!("global-bundle.pem");

async fn generate_rds_iam_token(
    db_hostname: &str,
    port: u16,
    db_username: &str,
) -> Result<String, Error> {
    let config = aws_config::load_defaults(BehaviorVersion::v2024_03_28()).await;

    let credentials = config
        .credentials_provider()
        .expect("no credentials provider found")
        .provide_credentials()
        .await
        .expect("unable to load credentials");
    let identity = credentials.into();
    let region = config.region().unwrap().to_string();

    let mut signing_settings = SigningSettings::default();
    signing_settings.expires_in = Some(Duration::from_secs(900));
    signing_settings.signature_location = aws_sigv4::http_request::SignatureLocation::QueryParams;

    let signing_params = v4::SigningParams::builder()
        .identity(&identity)
        .region(&region)
        .name("rds-db")
        .time(SystemTime::now())
        .settings(signing_settings)
        .build()?;

    let url = format!(
        "https://{db_hostname}:{port}/?Action=connect&DBUser={db_user}",
        db_hostname = db_hostname,
        port = port,
        db_user = db_username
    );

    let signable_request =
        SignableRequest::new("GET", &url, std::iter::empty(), SignableBody::Bytes(&[]))
            .expect("signable request");

    let (signing_instructions, _signature) =
        sign(signable_request, &signing_params.into())?.into_parts();

    let mut url = url::Url::parse(&url).unwrap();
    for (name, value) in signing_instructions.params() {
        url.query_pairs_mut().append_pair(name, &value);
    }

    let response = url.to_string().split_off("https://".len());

    Ok(response)
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    run(service_fn(handler)).await
}

async fn handler(_event: LambdaEvent<Value>) -> Result<Value, Error> {
    let db_host = env::var("DB_HOSTNAME").expect("DB_HOSTNAME must be set");
    let db_port = env::var("DB_PORT")
        .expect("DB_PORT must be set")
        .parse::<u16>()
        .expect("PORT must be a valid number");
    let db_name = env::var("DB_NAME").expect("DB_NAME must be set");
    let db_user_name = env::var("DB_USERNAME").expect("DB_USERNAME must be set");

    let token = generate_rds_iam_token(&db_host, db_port, &db_user_name).await?;

    let opts = PgConnectOptions::new()
        .host(&db_host)
        .port(db_port)
        .username(&db_user_name)
        .password(&token)
        .database(&db_name)
        .ssl_root_cert_from_pem(RDS_CERTS.to_vec())
        .ssl_mode(sqlx::postgres::PgSslMode::Require);

    let pool = sqlx::postgres::PgPoolOptions::new()
        .connect_with(opts)
        .await?;

    let result: i32 = sqlx::query_scalar("SELECT $1 + $2")
        .bind(3)
        .bind(2)
        .fetch_one(&pool)
        .await?;

    println!("Result: {:?}", result);

    Ok(json!({
        "statusCode": 200,
        "content-type": "text/plain",
        "body": format!("The selected sum is: {result}")
    }))
}
```

------

## Procesamiento de las notificaciones de eventos de Amazon RDS
<a name="rds-events"></a>

Puede utilizar Lambda para procesar las notificaciones de eventos desde una base de datos de Amazon RDS. Amazon RDS envía notificaciones a un tema de Amazon Simple Notification Service (Amazon SNS), que puede configurar para invocar una función Lambda. Amazon SNS ajusta el mensaje de Amazon RDS en su propio documento de evento y lo envía a su función.

Para obtener más información sobre cómo configurar una base de datos de Amazon RDS a fin de enviar notificaciones, consulte [Uso de las notificaciones de eventos de Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Events.html). 

**Example Mensaje de Amazon RDS en un evento de Amazon SNS**  

```
{
        "Records": [
          {
            "EventVersion": "1.0",
            "EventSubscriptionArn": "arn:aws:sns:us-east-2:123456789012:rds-lambda:21be56ed-a058-49f5-8c98-aedd2564c486",
            "EventSource": "aws:sns",
            "Sns": {
              "SignatureVersion": "1",
              "Timestamp": "2023-01-02T12:45:07.000Z",
              "Signature": "tcc6faL2yUC6dgZdmrwh1Y4cGa/ebXEkAi6RibDsvpi+tE/1+82j...65r==",
              "SigningCertUrl": "https://sns.us-east-2.amazonaws.com/SimpleNotificationService-ac565b8b1a6c5d002d285f9598aa1d9b.pem",
              "MessageId": "95df01b4-ee98-5cb9-9903-4c221d41eb5e",
              "Message": "{\"Event Source\":\"db-instance\",\"Event Time\":\"2023-01-02 12:45:06.000\",\"Identifier Link\":\"https://console.aws.amazon.com/rds/home?region=eu-west-1#dbinstance:id=dbinstanceid\",\"Source ID\":\"dbinstanceid\",\"Event ID\":\"http://docs.amazonwebservices.com/AmazonRDS/latest/UserGuide/USER_Events.html#RDS-EVENT-0002\",\"Event Message\":\"Finished DB Instance backup\"}",
              "MessageAttributes": {},
              "Type": "Notification",
              "UnsubscribeUrl": "https://sns.us-east-2.amazonaws.com/?Action=Unsubscribe&amp;SubscriptionArn=arn:aws:sns:us-east-2:123456789012:test-lambda:21be56ed-a058-49f5-8c98-aedd2564c486",
              "TopicArn":"arn:aws:sns:us-east-2:123456789012:sns-lambda",
              "Subject": "RDS Notification Message"
            }
          }
        ]
      }
```

## Tutorial completo de Lambda y Amazon RDS
<a name="rds-database-samples"></a>
+ [Uso de una función de Lambda para acceder a una base de datos de Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-lambda-tutorial.html): con la Guía del usuario de Amazon RDS, puede aprender a utilizar una función de Lambda para escribir datos en una base de datos de Amazon RDS a través de Amazon RDS Proxy. La función de Lambda leerá registros de una cola de Amazon SQS y escribirá elementos nuevos en una tabla de la base de datos siempre que se agrega un mensaje.

# Seleccione un servicio de base de datos para sus aplicaciones basadas en Lambda
<a name="ddb-rds-database-decision"></a>

Muchas aplicaciones sin servidor necesitan almacenar y recuperar datos. AWS ofrece varias opciones de bases de datos que funcionan con funciones de Lambda. Dos de las opciones más populares son Amazon DynamoDB, un servicio de base de datos NoSQL, y Amazon RDS, una solución de base de datos relacional tradicional. En las siguientes secciones se explican las principales diferencias entre estos servicios cuando se utilizan con Lambda y se lo ayuda a seleccionar el servicio de base de datos adecuado para su aplicación sin servidor.

Para obtener más información sobre los demás servicios de bases de datos que AWS ofrece y comprender sus casos de uso y sus desventajas de manera más general, consulte [Elegir un servicio de base de datos de AWS](https://docs.aws.amazon.com/decision-guides/latest/databases-on-aws-how-to-choose/databases-on-aws-how-to-choose.html). Todos los servicios de bases de datos de AWS son compatibles con Lambda, pero es posible que no todos sean adecuados para su caso de uso particular.

## ¿Cuáles son sus opciones al momento de seleccionar un servicio de base de datos con Lambda?
<a name="w2aad101d101c19b9"></a>

AWS ofrece varios servicios de bases de datos. Para las aplicaciones sin servidor, dos de las opciones más populares son DynamoDB y Amazon RDS.
+ **DynamoDB** es una base de datos NoSQL completamente administrada y optimizada para aplicaciones sin servidor. Ofrece un escalado fluido y un rendimiento uniforme de milisegundos de un solo dígito a cualquier escala.
+ **Amazon RDS** es un servicio de base de datos relacional gestionado que admite varios motores de bases de datos, incluidos MySQL y PostgreSQL. Proporciona funciones SQL conocidas con una infraestructura gestionada.

## Recomendaciones si ya conoce sus requisitos
<a name="w2aad101d101c19c11"></a>

Si ya tiene claros sus requisitos, estas son nuestras recomendaciones básicas:

Recomendamos [DynamoDB](with-ddb.md) para las aplicaciones sin servidor que necesitan un rendimiento uniforme de baja latencia, escalado automático y que no requieren uniones ni transacciones complejas. Es especialmente adecuado para aplicaciones basadas en Lambda debido a su naturaleza sin servidor.

[Amazon RDS](services-rds.md) es una mejor opción cuando necesita consultas SQL complejas, uniones o si tiene aplicaciones existentes que utilizan bases de datos relacionales. Sin embargo, tenga en cuenta que la conexión de las funciones de Lambda a Amazon RDS requiere una configuración adicional y puede afectar a los tiempos de arranque en frío.

## Aspectos a tener en cuenta al seleccionar un servicio de base de datos
<a name="w2aad101d101c19c13"></a>

Al elegir entre DynamoDB y Amazon RDS para sus aplicaciones Lambda, tenga en cuenta los siguientes factores:
+ Administración de conexiones y arranques en frío
+ Patrones de acceso a datos
+ Complejidad de la consulta
+ Requisitos de consistencia de datos
+ Características de escalado
+ Modelo de costos

Si comprende estos factores, puede seleccionar la opción que mejor se adapte a sus necesidades de uso específicas.

### Administración de conexiones y arranques en frío
<a name="w2aad101d101c19c13b9b1"></a>
+ DynamoDB utiliza una API HTTP para todas las operaciones. Las funciones de Lambda pueden realizar solicitudes inmediatas sin mantener las conexiones, lo que se traduce en un mejor rendimiento de arranque en frío. Cada solicitud se autentica mediante credenciales de AWS sin sobrecargar la conexión.
+ Amazon RDS requiere la administración de grupos de conexiones, ya que utiliza conexiones de bases de datos tradicionales. Esto puede afectar a los arranques en frío, ya que las nuevas instancias de Lambda necesitan establecer conexiones. Tendrá que implementar estrategias de agrupación de conexiones y, posiblemente, utilizar [Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html) para gestionar las conexiones de forma eficaz. Tenga en cuenta que el uso de Amazon RDS Proxy conlleva costos adicionales.

### Patrones de acceso a datos
<a name="w2aad101d101c19c13b9b3"></a>
+ DynamoDB funciona mejor con patrones de acceso conocidos y diseños de tabla única. Es ideal para las aplicaciones de Lambda que necesitan un acceso uniforme de baja latencia a los datos en función de claves principales o índices secundarios.
+ Amazon RDS proporciona flexibilidad para consultas complejas y patrones de acceso cambiantes. Es más adecuado cuando las funciones de Lambda necesitan realizar consultas únicas y personalizadas, o uniones complejas en varias tablas.

### Complejidad de la consulta
<a name="w2aad101d101c19c13b9b5"></a>
+ DynamoDB se destaca por sus operaciones sencillas basadas en claves y por sus patrones de acceso predefinidos. Las consultas complejas deben diseñarse en torno a estructuras de índices y las uniones deben gestionarse en el código de la aplicación.
+ Amazon RDS admite consultas SQL complejas con uniones, subconsultas y agregaciones. Esto puede simplificar el código de la función de Lambda cuando se necesitan operaciones de datos complejas.

### Requisitos de consistencia de datos
<a name="w2aad101d101c19c13b9b7"></a>
+ DynamoDB ofrece opciones de consistencia posterior y alta, con una consistencia alta disponible para lecturas de un solo elemento. Se admiten transacciones, pero con algunas limitaciones.
+ Amazon RDS es totalmente compatibles con las propiedades de atomicidad, coherencia, aislamiento y durabilidad (ACID), y admite transacciones complejas. Si sus funciones de Lambda requieren transacciones complejas o una consistencia alta en varios registros, Amazon RDS podría ser más adecuado.

### Características de escalado
<a name="w2aad101d101c19c13b9b9"></a>
+ DynamoDB escala automáticamente en función de su carga de trabajo. Puede gestionar picos repentinos de tráfico procedentes de las funciones de Lambda sin necesidad de aprovisionamiento previo. Puede utilizar el modo de capacidad bajo demanda para pagar solo lo que utilice, lo que se adapta perfectamente al modelo de escalado de Lambda.
+ Amazon RDS tiene una capacidad fija en función del tamaño de instancia que elija. Si varias funciones de Lambda intentan conectarse al mismo tiempo, es posible que supere la cuota de conexión. Debe administrar cuidadosamente los grupos de conexiones y, si es posible, implementar una lógica de reintento.

### Modelo de costos
<a name="w2aad101d101c19c13b9c11"></a>
+ Los precios de DynamoDB se ajustan bien a los de las aplicaciones sin servidor. Con la capacidad bajo demanda, solo paga las lecturas y escrituras reales que realizan sus funciones de Lambda. No se cobran cargos por el tiempo de inactividad.
+ Amazon RDS cobra por la instancia en ejecución independientemente del uso. Esto puede resultar menos rentable para las cargas de trabajo esporádicas que pueden ser típicas de las aplicaciones sin servidor. Sin embargo, podría resultar más económico para las cargas de trabajo de alto rendimiento con un uso constante.

## Comenzar a usar el servicio de base de datos de su elección
<a name="w2aad101d101c19c15"></a>

Ahora que ha leído los criterios para seleccionar entre DynamoDB y Amazon RDS y las principales diferencias entre ellos, puede seleccionar la opción que mejor se adapte a sus necesidades y utilizar los siguientes recursos para empezar a utilizarla.

------
#### [ DynamoDB ]

**Comenzar a usar DynamoDB con los siguientes recursos**
+ Para obtener una introducción al servicio de DynamoDB, consulte [¿Qué es DynamoDB?](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) en la *Guía para desarrolladores de Amazon DynamoDB*.
+ Siga el tutorial [Uso de Lambda con API Gateway](services-apigateway-tutorial.md) para ver un ejemplo del uso de una función de Lambda para realizar operaciones CRUD en una tabla de DynamoDB en respuesta a una solicitud de API.
+ Lea [Programación con DynamoDB y los SDK de AWS](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.html) en la *Guía para desarrolladores de Amazon DynamoDB* para obtener más información sobre cómo acceder a DynamoDB desde la función de Lambda mediante uno de los SDK de AWS.

------
#### [ Amazon RDS ]

**Comience a usar Amazon RDS con los siguientes recursos**
+ Para obtener una introducción al servicio de Amazon RDS, consulte [¿Qué es Amazon Relational Database Service (Amazon RDS)?](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html) en la *Guía del usuario de Amazon Relational Database Service*.
+ Siga el tutorial [Uso de una función de Lambda para acceder a una base de datos de Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-lambda-tutorial.html) en la *Guía del usuario de Amazon Relational Database Service*.
+ Obtenga más información sobre el uso de Lambda con Amazon RDS en [Uso de AWS Lambda con Amazon RDS](services-rds.md).

------