<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Martin Lubo</title>
    <description>The latest articles on Forem by Martin Lubo (@martinlubo).</description>
    <link>https://forem.com/martinlubo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2439857%2F59baa44f-c5c0-4dd5-8acc-438c129b928a.jpg</url>
      <title>Forem: Martin Lubo</title>
      <link>https://forem.com/martinlubo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/martinlubo"/>
    <language>en</language>
    <item>
      <title>Como conectar Facebook messenger con AWS Connect</title>
      <dc:creator>Martin Lubo</dc:creator>
      <pubDate>Sun, 28 Sep 2025 20:19:29 +0000</pubDate>
      <link>https://forem.com/martinlubo/como-conectar-facebook-messenger-con-aws-connect-1kg6</link>
      <guid>https://forem.com/martinlubo/como-conectar-facebook-messenger-con-aws-connect-1kg6</guid>
      <description>&lt;p&gt;Hoy día los clientes están buscando reducir costos de contact center mediante la automatización de procesos y resolución de consultas de sus clientes. En ese contexto Amazon Connect se presenta como una alternativa que permite la integración con los servicios de AWS como Lex o Bedrock para la generación de bots conversacionales que resuelvan esta necesidad y permitiendo escalar los casos que no se pueden resolver a un agente humano.&lt;/p&gt;

&lt;p&gt;Dentro de esta necesidad, uno de los puntos críticos es el manejo de la omnicanalidad, es decir que independientemente de la plataforma desde donde los clientes se contactan (WhatsApp, Facebook Messenger, Instagram, etc.) debemos tener una plataforma unificada donde recibir y responder a esos mensajes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Omnicanalidad en Amazon Connect
&lt;/h2&gt;

&lt;p&gt;Si bien en la documentación lo presentan como una solución omnicanal, la experiencia en la integración de los distintos canales puede variar muchísimo, desde ser nativa, utilizar otros servicios o requerir la conexión mediante APIs y desarrollos propios.&lt;/p&gt;

&lt;p&gt;En el caso los mensajes mediante WhatsApp, Amazon cuenta con el servicio de &lt;strong&gt;End User Messaging&lt;/strong&gt; que permite la integración directa con Amazon Connect. Para esto necesitamos vincular nuestra cuenta de AWS con el servicio WhatsApp Business Account (WABA)&lt;/p&gt;

&lt;p&gt;Para el caso de Facebook o Instagram la conexión se debe realizar mediante APIs y el uso de Webhooks que debemos crear de manera manual.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como conectar Facebook Messenger a Amazon Connect
&lt;/h2&gt;

&lt;p&gt;Como base para la implementación se utilizo este repositorio: &lt;a href="https://github.com/amazon-connect/amazon-connect-message-streaming-examples/" rel="noopener noreferrer"&gt;https://github.com/amazon-connect/amazon-connect-message-streaming-examples/&lt;/a&gt;, actualizando algunos de los componentes para ser compatibles con la API v23.0 de Facebook.&lt;/p&gt;

&lt;p&gt;Para poder hacer la conexión vamos a tener que realizar una serie de configuraciones y despliegues tanto en AWS como en la plataforma de Facebook Developers. Para este escenario vamos a asumir que ya se tiene una pagina existente en facebook y que es desde donde los usuarios nos van a enviar mensajes y que ya realizamos la creación de una App dentro del panel de apps de Meta. Respecto a la parte en AWS debemos tener ya creada una instancia de connect, un flujo de atencion que derive a una cola y al menos un agente asignado a esa cola y por ultimo un secreto en Secret Manager ya que es necesario el ARN del recurso para desplegar el repositorio.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuración de webhook
&lt;/h3&gt;

&lt;p&gt;Para realizar la configuración del webhook vamos a tener que levantar un endpoint donde nuestra aplicación de Facebook va a enviar un mensaje para “registrarse” y dar por valido el endpoint. Esta validación se hace mediante el envió de una clave que nosotros definimos para la aplicación y un token numérico que debemos devolver en respuesta a modo de confirmación.&lt;/p&gt;

&lt;p&gt;Dentro de la app de Meta, en el menú de webhooks vamos a ver la siguiente pantalla:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1vu5ce9zd6ssjw6do18.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1vu5ce9zd6ssjw6do18.png" alt="Pantalla de configuracion de webhooks en plataforma de meta" width="800" height="709"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lo primero que debemos hacer es seleccionar a que producto u “objeto” nos vamos a subscribir, para el caso de los mensajes el producto es &lt;strong&gt;Page.&lt;/strong&gt; Luego debemos configurar la URL de nuestro endpoint de registración y un token que definimos nosotros y que va a estar configurado en nuestro servicio.&lt;/p&gt;

&lt;p&gt;En la sección de &lt;strong&gt;campos del webhook&lt;/strong&gt; podemos seleccionar los campos a los cuales nos vamos a subscribir para recibir novedades. Para el caso de los mensajes el campo es &lt;em&gt;messages.&lt;/em&gt; A su vez desde el botón de Probar podemos enviar un request con los campos correspondientes para verificar la recepción en nuestro servicio&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Al momento de escribir este documento, por motivos que desconozco, el envió prueba de mensajes no estaría funcionando a pesar de recibir un mensaje de envió correcto por parte de la pagina. En internet hay algunos usuarios que reportan el mismo problema pero sin mucha claridad en como resolverlo.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Diagrama de registro del webhook
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwlpiw6ueyctdvkh24bge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwlpiw6ueyctdvkh24bge.png" alt="Diagrama de registro de webhooks" width="522" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;La App hace un llamado GET al endpoint enviando por query los campos &lt;strong&gt;Mode&lt;/strong&gt;, &lt;strong&gt;Token&lt;/strong&gt; y &lt;strong&gt;Challenge&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;En nuestro servicio debemos verificar que &lt;strong&gt;Mode&lt;/strong&gt; = &lt;strong&gt;“subscribe”&lt;/strong&gt; y que el &lt;strong&gt;Token&lt;/strong&gt; sea el que definimos para nuestro servicio. Por ultimo debemos devolver el contenido del campo &lt;strong&gt;Challenge&lt;/strong&gt; sin modificaciones (el body es directamente el código numérico recibido, sin ningún formato)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Tokens de acceso
&lt;/h3&gt;

&lt;p&gt;Luego de configurar el webhook, debemos ir al menú de Messenger donde podremos conectar la pagina desde donde los usuarios se van a estar contactando y generar el token de acceso correspondiente. Este secreto lo vamos a almacenar en Secret Manager con la key &lt;strong&gt;PAGE_TOKEN.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;En el repositorio hay referencias al campo APP_SECRET que es un campo que se puede obtener desde la web de Meta y se usaba para generar una firma en la request de envio de mensajes. En la version V23.0 de la API parece no ser necesaria.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz09swgica2zv6zk4d4gd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz09swgica2zv6zk4d4gd.png" alt="Pantalla de configuracion de token de aplicacion en Meta" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Permisos de la app
&lt;/h3&gt;

&lt;p&gt;Para poder completar el proceso de revisión de la aplicación es necesario contar con un negocio validado en la plataforma de Meta. Es importante que al momento de solicitar permisos para la aplicación sean exclusivamente los necesarios para la función que queremos ejecutar, el exceso en la cantidad de permisos puede llevar al bloqueo de la aplicación.&lt;/p&gt;

&lt;p&gt;Para el caso de los mensajes desde Facebook únicamente pasando la aplicación a modo activo fue suficiente para recibir mensajes. Es necesario validar esto para los escenarios productivos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Camino completo de los mensajes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frapkn8cxkb0sybghvvh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frapkn8cxkb0sybghvvh0.png" alt="Diagrama del flujo para recibir y enviar mensajes" width="661" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;El usuario se comunica mediante el chat de Facebook en la pagina de la empresa&lt;/li&gt;
&lt;li&gt;La app de meta envía el evento al endpoint configurado&lt;/li&gt;
&lt;li&gt;API Gateway revise la petición POST y la deriva a la lambda de inbound&lt;/li&gt;
&lt;li&gt;Se revisa la existencia de un chat previo abierto entre el usuario y un agente.&lt;/li&gt;
&lt;li&gt;Se envía el mensaje hacia la conversación de connect existente o bien se abre una nueva conversación para ser atendida por un agente.&lt;/li&gt;
&lt;li&gt;Las respuesta de los agentes y eventos de connect se envía mediante un tópico SNS el cual dispara la lambda de Outbound.&lt;/li&gt;
&lt;li&gt;Dependiendo el tipo de evento detectado se actualiza la base de datos&lt;/li&gt;
&lt;li&gt;Utilizando el token de la pagina almacenado en Secret Manager se envía un mensaje directamente a la pagina con los datos del usuario y el mensaje de respuesta&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>spanish</category>
      <category>aws</category>
      <category>amazonconnect</category>
      <category>facebook</category>
    </item>
    <item>
      <title>Mi experiencia rindiendo el examen AWS Certified AI Practitioner</title>
      <dc:creator>Martin Lubo</dc:creator>
      <pubDate>Sun, 28 Sep 2025 20:15:37 +0000</pubDate>
      <link>https://forem.com/martinlubo/mi-experiencia-rindiendo-el-examen-aws-certified-ai-practitioner-4kie</link>
      <guid>https://forem.com/martinlubo/mi-experiencia-rindiendo-el-examen-aws-certified-ai-practitioner-4kie</guid>
      <description>&lt;p&gt;Hace ya algunos meses AWS lanzó un nuevo examen, el Certified AI Practitioner que, junto al Cloud Practitioner, componen el nivel fundacional del esquema de certificaciones de AWS.&lt;/p&gt;

&lt;p&gt;Y acá es donde tenemos que hacer una aclaración importante, si bien es un examen fundacional no necesariamente va a ser fácil, o al menos no tanto como puede ser el CCP, ya que si bien no requiere un conocimiento profundo de todos los temas si nos van a preguntar sobre puntos muy variados sobre el mundo de la inteligencia artificial y va a ser necesario que conozcamos no sólo los servicios de AWS que existe para nuestros proyectos de AI o ML sino también tener idea de conceptos fundamentales como pueden ser algoritmos, tipos de entrenamiento, prompt engineering, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué tengo que saber para rendir el examen?
&lt;/h2&gt;

&lt;p&gt;AWS nos brinda para sus exámenes una guía con los dominios y temas que deberíamos entender para presentarnos al examen y que porcentaje del contenido del mismo que corresponde con cada tema. Esta tabla nos va a ayudar a entender cuáles son los temas que mas nos vamos a encontrar en el examen y guiarnos sobre que debemos hacer foco.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;% de Examen&lt;/th&gt;
&lt;th&gt;Dominio&lt;/th&gt;
&lt;th&gt;Temas&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;td&gt;Fundamentos de IA y ML&lt;/td&gt;
&lt;td&gt;Conceptos básicos, casos de uso, ciclo de vida de Machine Learning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;24%&lt;/td&gt;
&lt;td&gt;Fundamentos de IA generativa&lt;/td&gt;
&lt;td&gt;Conceptos básicos, capacidades y limitaciones, servicios y tecnología disponible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;28%&lt;/td&gt;
&lt;td&gt;Aplicaciones de los modelos fundamentales (FMs)&lt;/td&gt;
&lt;td&gt;Consideraciones de diseño, prompt engineering, evaluación de modelos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14%&lt;/td&gt;
&lt;td&gt;IA responsable&lt;/td&gt;
&lt;td&gt;Características, herramientas y servicios, modelos transparentes y explicables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14%&lt;/td&gt;
&lt;td&gt;Seguridad, cumplimiento y gobierno para soluciones de IA&lt;/td&gt;
&lt;td&gt;Métodos para IA segura, estándares de cumplimiento para IA&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Para conocer el temario completo puede acceder a la &lt;a href="https://d1.awsstatic.com/training-and-certification/docs-ai-practitioner/AWS-Certified-AI-Practitioner_Exam-Guide.pdf?p=cert&amp;amp;c=ai&amp;amp;z=3" rel="noopener noreferrer"&gt;guía oficial&lt;/a&gt; que contiene toda la información necesaria.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparándome para rendir el examen
&lt;/h2&gt;

&lt;p&gt;En mi caso particular, al trabajar en un partner de AWS, me invitaron a participar de una iniciativa llamada “AI Practitioner Mission” brindada por el equipo de training de AWS.&lt;br&gt;
Si bien esta capacitación constaba de una serie de charlas técnicas, el resto del contenido es accesible a través del sitio de &lt;a href="https://explore.skillbuilder.aws/learn" rel="noopener noreferrer"&gt;AWS Skill Builder&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Para poder acceder al portal de Skill Builder vamos a necesitar un Builder ID. En caso de no tener, vamos a poder registrarnos de manera completamente gratuita con nuestra cuenta personal.&lt;/p&gt;

&lt;p&gt;Como primer paso realicé el plan estándar de preparación para el examen de AI Practitioner que pueden encontrar en el siguiente link: &lt;a href="https://explore.skillbuilder.aws/learn/learning_plan/view/2193/standard-exam-prep-plan-aws-certified-ai-practitioner-aif-c01" rel="noopener noreferrer"&gt;https://explore.skillbuilder.aws/learn/learning_plan/view/2193/standard-exam-prep-plan-aws-certified-ai-practitioner-aif-c01&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este plan es gratuito y cuenta con 11 lecciones de aproximadamente 1 hora mas un plan de 8 horas de preparación para el examen. Dentro del tier gratuito de Skill Builder podemos acceder a un set de 20 preguntas de examen de prueba para tener un acercamiento al tipo y estilo de preguntas que podemos encontrar en el examen real. (&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/19790/exam-prep-official-practice-question-set-aws-certified-ai-practitioner-aif-c01-english" rel="noopener noreferrer"&gt;https://explore.skillbuilder.aws/learn/course/external/view/elearning/19790/exam-prep-official-practice-question-set-aws-certified-ai-practitioner-aif-c01-english&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;En caso de contar con una licencia paga de Skill Builder vamos a poder acceder al &lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/20479/exam-prep-enhanced-course-aws-certified-ai-practitioner-aif-c01-english" rel="noopener noreferrer"&gt;curso extendido&lt;/a&gt;, con aproximadamente 8 horas extra de contenido, un &lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/20657/aws-escape-room-exam-prep-for-aws-certified-ai-practitioner-aif-c01-english" rel="noopener noreferrer"&gt;Escape Room&lt;/a&gt; bastante entretenido donde reforzar los contenidos y, desde mi punto de vista el mejor beneficio, acceso a un &lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/20274/exam-prep-official-pretest-aws-certified-ai-practitioner-aif-c01-english" rel="noopener noreferrer"&gt;examen completo&lt;/a&gt; de prueba de 65 preguntas que nos va a permitir tener una idea bastante real de cuan preparados estamos para el examen.&lt;/p&gt;

&lt;p&gt;Además de los contenidos oficiales de AWS, hubo algunos temas que fui reforzando con recursos de otros sitios, acá les dejo un listado de los que me parecieron mas claros o didácticos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Precision, Recall y F-Score:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=H8FSfqxRWmA" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=H8FSfqxRWmA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/machine-learning/crash-course/classification/accuracy-precision-recall" rel="noopener noreferrer"&gt;https://developers.google.com/machine-learning/crash-course/classification/accuracy-precision-recall&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Métrica BLEU: &lt;a href="https://www.youtube.com/watch?v=M05L1DhFqcw" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.youtube.com/watch?v=M05L1DhFqcw" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=M05L1DhFqcw&lt;/a&gt;
&lt;/li&gt;

&lt;li&gt;Métrica ROUGE : &lt;a href="https://www.youtube.com/watch?v=TMshhnrEXlg" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.youtube.com/watch?v=TMshhnrEXlg" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=TMshhnrEXlg&lt;/a&gt;
&lt;/li&gt;

&lt;li&gt;Explicación de múltiples algoritmos: &lt;a href="https://www.youtube.com/watch?v=E0Hmnixke2g" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.youtube.com/watch?v=E0Hmnixke2g" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=E0Hmnixke2g&lt;/a&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  ¿Cómo es el examen?
&lt;/h2&gt;

&lt;p&gt;El examen consta de 65 preguntas que pueden ser las habituales múltiple choice donde seleccionamos cuál es la opción correcta o preguntas con respuesta múltiple donde tendremos que seleccionar 2 o mas opciones y en las cuáles no existen los créditos parciales, es decir, en caso de no seleccionar todas las opciones correctas la pregunta se toma como invalida.&lt;/p&gt;

&lt;p&gt;Además de esto podremos encontrar preguntas donde debemos ordenar bajo un determinado criterio la respuesta, por ejemplo, de mayor a menor costo o complejidad de implementación o bien hacer match de palabras con su concepto. Por último también nos pueden tocar casos de estudio, donde planteado un escenario, nos realizarán una serie de preguntas relacionadas con el mismo.&lt;/p&gt;

&lt;p&gt;En cuanto a la duración, vamos a contar con 90 minutos para realizar el examen. En caso que el inglés sea tu segunda lengua (cosa probable si estás leyendo este blog en español) podes solicitar una adaptación llamada &lt;strong&gt;ESL +30 MINUTES&lt;/strong&gt; Lo que nos permitirá contar con 30 minutos extra para rendir.&lt;/p&gt;

&lt;p&gt;Este beneficio es válido para todos los exámenes, pero debés tener en cuenta que es necesario solicitarlo antes de comprar el examen para que se aplique correctamente. Al momento de escribir este artículo el examen AIF-C01 sólo se encuentra disponible en Inglés, Japonés, Coreano, Portugués y Chino simplificado.&lt;/p&gt;

&lt;p&gt;A la hora de rendir podemos hacerlo tanto de forma online, como presencial en algún centro autorizado. Desde mi perspectiva esta última opción es la mas recomendable, ya que no tenemos que preocuparnos por las condiciones de la habitación donde vamos a rendir, ni por ser interrumpidos durante el examen, o por ruidos fuera de nuestro control, factores que pueden generar la cancelación automática de nuestro examen en caso de que nuestro supervisor del examen online asi lo disponga.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Como conclusión final, puedo decir que el AWS Certified AI Practitioner es un examen desafiante en algunos aspectos, pero alcanzable con la preparación adecuada.&lt;/p&gt;

&lt;p&gt;Respecto a los recursos proporcionados por AWS, especialmente a través de Skill Builder, son más que suficientes para prepararse adecuadamente. La combinación de contenido teórico, ejercicios prácticos y exámenes de prueba te da una buena base para enfrentar el examen real.&lt;/p&gt;

&lt;p&gt;Mi recomendación para quiénes planean rendirlo es:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Completar todo el contenido del plan de preparación oficial&lt;/li&gt;
&lt;li&gt;Realizar los exámenes de práctica hasta obtener un puntaje consistente superior al 85%&lt;/li&gt;
&lt;li&gt;Reforzar los conceptos fundamentales de IA y ML con recursos adicionales&lt;/li&gt;
&lt;li&gt;Tomar el tiempo necesario para entender bien los conceptos, no solo memorizar respuestas&lt;/li&gt;
&lt;li&gt;Al momento de rendir respondé todas las preguntas aunque no estés completamente seguro. No se penalizan las respuestas incorrectas, así que podés intentar adivinar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dedicándole unas dos o tres semanas es perfectamente posible aprobar este examen y obtener una certificación que valida tus conocimientos en el campo emergente de la IA en AWS.&lt;/p&gt;

&lt;p&gt;¡Buena suerte!&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>aws</category>
      <category>aipractitioner</category>
      <category>ai</category>
    </item>
    <item>
      <title>Modelo de Madurez de Seguridad en AWS</title>
      <dc:creator>Martin Lubo</dc:creator>
      <pubDate>Sun, 28 Sep 2025 19:59:58 +0000</pubDate>
      <link>https://forem.com/martinlubo/modelo-de-madurez-de-seguridad-en-aws-336b</link>
      <guid>https://forem.com/martinlubo/modelo-de-madurez-de-seguridad-en-aws-336b</guid>
      <description>&lt;p&gt;El modelo de madurez de seguridad, del ingles “AWS Security Maturity Model” es un modelo de trabajo que nos permitirá evaluar, gestionar y reducir el riesgo en nuestra infraestructura ayudándonos a priorizar las medidas de seguridad que debemos implementar.&lt;/p&gt;

&lt;p&gt;Pero para poder hablar de seguridad primero debemos entender como se gestiona la seguridad en la nube de AWS y quien es responsable de que.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modelo de responsabilidad compartida
&lt;/h2&gt;

&lt;p&gt;El modelo de responsabilidad compartida de AWS es un marco fundamental que define cómo se distribuyen las responsabilidades de seguridad entre AWS y sus clientes. Este modelo se divide en dos partes principales:&lt;/p&gt;

&lt;h3&gt;
  
  
  Responsabilidades de AWS (Seguridad DE la nube)
&lt;/h3&gt;

&lt;p&gt;AWS es responsable de la seguridad DE la nube, lo que incluye:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protección de la infraestructura física (centros de datos)&lt;/li&gt;
&lt;li&gt;Seguridad de la red&lt;/li&gt;
&lt;li&gt;Virtualización de la infraestructura&lt;/li&gt;
&lt;li&gt;Seguridad del software que ejecuta los servicios de AWS&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Responsabilidades del Cliente (Seguridad EN la nube)
&lt;/h3&gt;

&lt;p&gt;Los clientes son responsables de la seguridad EN la nube, lo que abarca:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuración de seguridad de los servicios de AWS utilizados&lt;/li&gt;
&lt;li&gt;Gestión de datos y su encriptación&lt;/li&gt;
&lt;li&gt;Gestión de identidades y accesos&lt;/li&gt;
&lt;li&gt;Seguridad de las aplicaciones desplegadas en AWS&lt;/li&gt;
&lt;li&gt;Configuración del sistema operativo y red de las instancias EC2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Este modelo asegura que tanto AWS como sus clientes trabajen juntos para mantener un entorno en la nube seguro y eficiente. AWS proporciona una infraestructura segura, mientras que los clientes son responsables de cómo utilizan y configuran esa infraestructura para sus necesidades específicas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz60u9bt17rw7dfh1q7ua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz60u9bt17rw7dfh1q7ua.png" alt="Diagrama de responsabilidad compartida entre AWS y el cliente" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  La importancia de implementar un modelo de seguridad en la nube
&lt;/h2&gt;

&lt;p&gt;En el complejo y dinámico entorno de la computación en la nube, contar con un modelo de seguridad robusto es fundamental. Este modelo no solo proporciona una estructura para proteger nuestros activos digitales, sino que también nos ayuda a navegar por los desafíos únicos que presenta la nube. Veamos algunas razones clave por las que necesitamos un modelo de seguridad bien definido:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visibilidad y compliance:&lt;/strong&gt; Un modelo de seguridad estructurado ofrece una visión clara de los recursos y actividades en la nube, facilitando la detección de vulnerabilidades y el seguimiento de medidas de seguridad. Ayuda a cumplir con normativas y estándares, crucial en sectores regulados. Esta visibilidad mejora la seguridad, facilita auditorías y mantiene la confianza del cliente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infraestructura a proteger:&lt;/strong&gt; Un modelo de seguridad robusto es crucial para proteger la infraestructura en la nube, incluyendo servidores virtuales, bases de datos y redes. Ayuda a identificar y priorizar activos valiosos, permitiendo una asignación eficiente de recursos y facilitando la implementación de controles de acceso y cifrado adaptados a cada componente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursos y automatización:&lt;/strong&gt; Un modelo de seguridad efectivo optimiza los recursos humanos y tecnológicos. Proporciona una estructura clara para identificar áreas de automatización, mejorando la eficiencia y reduciendo errores en entornos de nube complejos. Automatiza tareas rutinarias, como la aplicación de parches y la gestión de configuraciones, ahorrando tiempo y mejorando la consistencia. Además, facilita la integración de herramientas automatizadas para el monitoreo continuo y la respuesta rápida ante amenazas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protección ante amenazas:&lt;/strong&gt; Un modelo de seguridad integral protege contra amenazas cibernéticas en constante evolución. Implementa múltiples capas de defensa para diversos riesgos, desde ataques DDoS hasta infiltraciones sofisticadas. Ofrece un marco para la detección temprana, respuesta rápida y mitigación eficaz, fortaleciendo así la postura de seguridad de la organización en la nube.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Un camino evolutivo
&lt;/h2&gt;

&lt;p&gt;El modelo de madurez de seguridad de AWS es un camino evolutivo que guía a las organizaciones a través de diferentes etapas para mejorar progresivamente su postura de seguridad en la nube. Este camino se puede visualizar en cuatro etapas:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Quick Wins
&lt;/h3&gt;

&lt;p&gt;En esta primer etapa se hace foco en la implementación de cambios de muy fácil configuración y de gran impacto para la seguridad de la organización.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Fundacional
&lt;/h3&gt;

&lt;p&gt;Luego de alcanzar los “Quick Wins”, podremos enforcarnos en aquellos requerimientos que requieren un poco mas de esfuerzo implementar pero que nos permitirán sentar las bases de nuestra postura de seguridad&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Eficiente
&lt;/h3&gt;

&lt;p&gt;Como siguiente paso, no solo continuaremos mejorando nuestra postura de seguridad, sino que también nos enfocaremos en gestionar la seguridad de manera más eficiente.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Optimizado
&lt;/h3&gt;

&lt;p&gt;En esta última etapa, el foco está puesto en la mejora continua de nuestra postura de seguridad. Trabajaremos en los controles y realizaremos revisiones periódicas en toda la organización para mantener y optimizar nuestras medidas de seguridad.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Wins
&lt;/h2&gt;

&lt;p&gt;A continuación veremos el listado de configuraciones y funcionalidad sencillas que nos permitirán, en el plazo de una o dos semanas, mejorar rápidamente nuestra postura de seguridad, permitiéndonos operar con tranquilidad en un entorno cloud.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/assign-security-contacts/" rel="noopener noreferrer"&gt;Asignar los contactos de Seguridad&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/choose-regions/" rel="noopener noreferrer"&gt;Seleccionar las regiones con las que queremos trabajar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/security-hub/" rel="noopener noreferrer"&gt;Buenas practicas mediante AWS Security Hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/mfa/" rel="noopener noreferrer"&gt;Activar MFA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/root-account-lock-audit/" rel="noopener noreferrer"&gt;Evitar y auditar el uso de la cuenta Root&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/iam-access-analyzer/" rel="noopener noreferrer"&gt;Análisis de accesos y roles con AIM Access Analyzer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/guardduty/" rel="noopener noreferrer"&gt;Detección de amenazas con Amazon GuardDuty y responder a los hallazgos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/cloudtrail/" rel="noopener noreferrer"&gt;Auditoria de AWS CloudTrail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/trusted-advisor/" rel="noopener noreferrer"&gt;Remediar los hallazgos de AWS Trusted Advisor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/billing-alarm/" rel="noopener noreferrer"&gt;Configuración de alarmas de Billing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/security-groups/" rel="noopener noreferrer"&gt;Configuración de Security Groups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/s3-block-public-access/" rel="noopener noreferrer"&gt;Bloquear acceso publico a S3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/macie-intentional-data-policies/" rel="noopener noreferrer"&gt;Revisar la seguridad de los datos con Amazon Macie&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://maturitymodel.security.aws.dev/es/1.-quickwins/waf/" rel="noopener noreferrer"&gt;Configurar WAF&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ¿Cómo sigo una vez que alcance los Quick Wins?
&lt;/h2&gt;

&lt;p&gt;Para dar nuestros siguientes pasos podremos apoyarnos en la guía del Modelo de Madurez de Seguridad: &lt;a href="https://maturitymodel.security.aws.dev/es/2.-foundational/" rel="noopener noreferrer"&gt;https://maturitymodel.security.aws.dev/es/2.-foundational/&lt;/a&gt;&lt;br&gt;
Ahí encontraremos todas las configuraciones y herramientas que AWS nos recomienda para tener un entorno seguro.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué otros servicios ofrece AWS?
&lt;/h2&gt;

&lt;p&gt;En la siguiente imagen se puede observar un listado por área de los servicios que AWS ofrece para auditar, automatizar, detectar o responder ante distintos escenarios donde la seguridad de nuestra organización pueda estar en riesgo.&lt;/p&gt;

&lt;p&gt;Muchos de estos servicios son, o bien completamente gratis, como el caso de IAM u AWS Organizations, o que incluyen una capa gratuita bastante generosa que nos permitirá utilizarlo en las etapas iniciales de nuestros proyectos.&lt;/p&gt;

&lt;p&gt;Por otra parte, podemos encontrar los servicios pagos pero para los cuales podremos contar con un free trial que nos permitirá evaluar las funcionalidades y los costos y analizar la posterior implementación definitiva en nuestra organización.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7fh2l5x0ggcnzwlt3ep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7fh2l5x0ggcnzwlt3ep.png" alt="Tabla de servicios de seguridad disponibles en AWS" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>aws</category>
    </item>
    <item>
      <title>Deployando una aplicación en AWS usando CloudFormation (Parte 2)</title>
      <dc:creator>Martin Lubo</dc:creator>
      <pubDate>Sun, 28 Sep 2025 19:54:43 +0000</pubDate>
      <link>https://forem.com/martinlubo/deployando-una-aplicacion-en-aws-usando-cloudformation-parte-2-232j</link>
      <guid>https://forem.com/martinlubo/deployando-una-aplicacion-en-aws-usando-cloudformation-parte-2-232j</guid>
      <description>&lt;p&gt;Luego de la primer parte de este articulo, donde hicimos un repaso de las distintas maneras de generar un template de CloudFormation, en esta etapa vamos a entrar de lleno a la creación del mismo y usando como guía un caso de uso simple&lt;/p&gt;

&lt;h2&gt;
  
  
  Diseño de la solución
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Caso de uso
&lt;/h3&gt;

&lt;p&gt;Para hacerlo un poco mas didáctico vamos a plantear un caso de uso que podría ser igual (o muy parecido) a lo que nos pueden pedir solucionar en nuestro día a día&lt;/p&gt;

&lt;p&gt;En este caso vamos a crear una pequeña API Rest con 2 endpoints distintos, uno para hacer un upload de un archivo a S3, guardar el nombre del archivo y otros datos del archivo en una base de datos DynamoDB y un segundo endpoint donde poder consultar esa información.&lt;/p&gt;

&lt;p&gt;En el siguiente diagrama vamos a poder ver la conexión entre los distintos servicios:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r64dasboqf8a7yiwh5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r64dasboqf8a7yiwh5k.png" alt="Diagrama de aplicacion serverless en AWS" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Servicios involucrados
&lt;/h3&gt;

&lt;p&gt;Para entender mejor el diagrama anterior vamos a hacer una breve descripción de los servicios que aparecen en el mismo&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amazon API Gateway&lt;/strong&gt;: El servicio de API Gateway nos permite crear, publicar y monitorear APIs REST o WebSocket. Al ser parte de los servicios sin servidor de AWS no vamos a necesitar gestionar ningún entorno por nosotros mismos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Lambda&lt;/strong&gt;: Lambda es el servicio de computo serverless de AWS, con este servicio vamos a poder ejecutar nuestro código escrito en JavaScript, Python, Go o Java entre otros como así también nos da la posibilidad de ejecutar nuestras propias imágenes de docker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon DynamoDB&lt;/strong&gt;: DynamoDB es una base de datos NoSQL serverless para aplicaciones de cualquier escala y al igual que otros servicios serverless vamos a pagar solo por el espacio u operaciones que realicemos evitando los gastos fijos de un servidor propio 24/7.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Simple Storage Service (Amazon S3)&lt;/strong&gt;: S3 es el servicio de storage de objetos de AWS, donde podremos subir una cantidad ilimitada de archivos cuyo tamaño máximo puede ser de hasta 5TB cada uno.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Identity and Access Management (IAM)&lt;/strong&gt;: Si bien no lo pusimos en nuestro diagrama, IAM es un servicio transversal a todo el ecosistema de AWS y nos va a permitir gestionar los permisos y accesos de nuestros usuarios o aplicaciones, como sera el caso de nuestras funciones Lambda.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementación
&lt;/h2&gt;

&lt;p&gt;A partir de ahora vamos a iniciar la creación de nuestro template con un archivo vacío (template.yaml) y vamos a ir agregando de a poco todas las partes necesarias para implementar la solución.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-requisitos
&lt;/h3&gt;

&lt;p&gt;Antes de empezar es necesario que tengas creado un bucket de S3 en tu cuenta para usarlo como source del código de la lambdas, te recomiendo ponerle de nombre &lt;code&gt;cloudformation-code-artifacts-{AccountID}&lt;/code&gt; , donde &lt;code&gt;{AccountID}&lt;/code&gt; es el numero de tu cuenta de AWS pero podes optar por cualquier otro nombre.&lt;br&gt;
Una vez creado el bucket es necesario subir los archivos .zip con el código de las lambdas que vas a encontrar en &lt;a href="https://github.com/MartinEzeLubo/blog-resources/tree/main/IaC/cloudformation" rel="noopener noreferrer"&gt;este link&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Parameters
&lt;/h3&gt;

&lt;p&gt;Primero vamos a declarar unos parámetros a los cuales vamos a estar haciendo referencia en nuestro template:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SourceCodeBucketName&lt;/strong&gt;: Este parámetro indica el nombre del bucket donde subimos los archivos .zip de las lambdas y que configuramos en los pre-requisitos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UploadedFilesBucketName&lt;/strong&gt;: Nombre del bucket donde se van a guardar los archivos que subamos mediante nuestra API. Podemos reemplazar la variable &lt;code&gt;{AccountID}&lt;/code&gt; con el numero de tu cuenta de AWS o seleccionar cualquier otro string que queramos, recordando que los nombres de buckets deben ser únicos a nivel global, independientemente de si existen o no en nuestra cuenta.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DynamoDBTable&lt;/strong&gt;: Nombre de la tabla donde guardaremos la información de los archivos subidos mediante nuestra API. Puede ser modificado sin problema.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APIGatewayName&lt;/strong&gt;: Nombre para identificar a nuestra API. Puede ser modificado sin problema.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;SourceCodeBucketName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;String"&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cloudformation-code-artifacts-{AccountID}"&lt;/span&gt;
  &lt;span class="na"&gt;UploadedFilesBucketName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;String"&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uploaded-files-{AccountID}"&lt;/span&gt;
  &lt;span class="na"&gt;DynamoDBTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;String"&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UploadedFilesInfo"&lt;/span&gt;
  &lt;span class="na"&gt;APIGatewayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;String"&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FilesServiceAPI"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S3&lt;/strong&gt;: En esta sección vamos a crear el bucket donde se guardan los archivos que subimos, para indicar el &lt;code&gt;BucketName&lt;/code&gt; hacemos referencia al parámetro que configuramos en la sección anterior
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;UploadedFilesBucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::S3::Bucket"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;BucketName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;UploadedFilesBucketName&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DynamoDB&lt;/strong&gt;: Al igual que con el bucket S3, el nombre de la tabla lo tomamos del parámetro declarado anteriormente. Con los atributos &lt;code&gt;AttributeDefinitions&lt;/code&gt; y &lt;code&gt;KeySchema&lt;/code&gt; vamos a indicar como se llama nuestro campo, de que tipo es y luego indicarle que es la Key de nuestra tabla. Finalmente con el atributo &lt;code&gt;ProvisionedThroughput&lt;/code&gt; le indicamos la capacidad de lectura y escritura de nuestra tabla.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;FilesInfoTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::DynamoDB::Table"&lt;/span&gt;
  &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;DynamoDBTable&lt;/span&gt;
    &lt;span class="na"&gt;AttributeDefinitions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filename"&lt;/span&gt;
        &lt;span class="na"&gt;AttributeType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S"&lt;/span&gt;
    &lt;span class="na"&gt;KeySchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filename"&lt;/span&gt;
        &lt;span class="na"&gt;KeyType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HASH"&lt;/span&gt;
    &lt;span class="na"&gt;ProvisionedThroughput&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ReadCapacityUnits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;WriteCapacityUnits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IAM&lt;/strong&gt;: Ahora vamos a crear dos roles, uno para cada lambda para tener un mejor control sobre los permisos de cada una y seguir el principio de &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege" rel="noopener noreferrer"&gt;mínimos privilegios&lt;/a&gt; en nuestros servicios. Uno sera para nuestra lambda de &lt;code&gt;getFilesInfo&lt;/code&gt;, donde solo tendrá acceso a la tabla que creamos, y otro para &lt;code&gt;uploadFile&lt;/code&gt; que tendrá acceso a nuestra tabla y al bucket de S3 para guardar los archivos.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;GetFilesInfoFunctionRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FilesInfoTable&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::IAM::Role"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;RoleName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GetFilesInfoFunctionRole"&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lambda.amazonaws.com"&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sts:AssumeRole"&lt;/span&gt;
      &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;PolicyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GetFilesInfo-LambdaPolicy"&lt;/span&gt;
          &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
            &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb:*"&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${DynamoDBTable}"&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;logs:*"&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="na"&gt;UploadFunctionRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FilesInfoTable&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::IAM::Role"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;RoleName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UploadFunctionRole"&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lambda.amazonaws.com"&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sts:AssumeRole"&lt;/span&gt;
      &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;PolicyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UploadFunction-LambdaPolicy"&lt;/span&gt;
          &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
            &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3:*"&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:s3:::${UploadedFilesBucketName}"&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:s3:::${UploadedFilesBucketName}/*"&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb:*"&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${DynamoDBTable}"&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;logs:*"&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lambda&lt;/strong&gt;: Luego vamos a crear nuestras funciones lambda indicándoles en el atributo &lt;code&gt;Code&lt;/code&gt; el bucket (&lt;code&gt;S3Bucket&lt;/code&gt;) y el nombre del archivo (&lt;code&gt;S3Key&lt;/code&gt;). Con el atributo &lt;code&gt;Environment&lt;/code&gt; &lt;strong&gt;**&lt;/strong&gt;vamos a pasar como variable de entorno la información sobre la tabla de DynamoDB y el bucket de S3 donde guardar los archivos. Finalmente, dentro del atributo &lt;code&gt;Role&lt;/code&gt; le indicamos a cada función cual es el role de IAM que le corresponde
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;GetFilesInfoFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GetFilesInfoFunctionRole&lt;/span&gt;
  &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::Lambda::Function"&lt;/span&gt;
  &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;FunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GetFilesInfo"&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Obtiene&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;la&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;informacion&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;los&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;archivos&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;subidos&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;almacenada&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;DynamoDB"&lt;/span&gt;
    &lt;span class="na"&gt;PackageType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Zip&lt;/span&gt;
    &lt;span class="na"&gt;Code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;S3Bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;SourceCodeBucketName&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S3Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;getFilesInfo.zip&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.handler&lt;/span&gt;
    &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs20.x&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;BUCKET_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;UploadedFilesBucketName&lt;/span&gt;
        &lt;span class="na"&gt;REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;AWS::Region&lt;/span&gt;
        &lt;span class="na"&gt;TABLE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;DynamoDBTable&lt;/span&gt;
    &lt;span class="na"&gt;MemorySize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;
    &lt;span class="na"&gt;Timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
    &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;GetFilesInfoFunctionRole.Arn&lt;/span&gt;
&lt;span class="na"&gt;UploadFileFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;UploadFunctionRole&lt;/span&gt;
  &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::Lambda::Function"&lt;/span&gt;
  &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;FunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UploadFile"&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sube&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;el&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;archivo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;S3&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;guarda&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;la&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;informacion&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;del&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mismo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;DynamoDB"&lt;/span&gt;
    &lt;span class="na"&gt;PackageType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Zip"&lt;/span&gt;
    &lt;span class="na"&gt;Code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;S3Bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;SourceCodeBucketName&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;S3Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;uploadFile.zip&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.handler&lt;/span&gt;
    &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs20.x&lt;/span&gt;
    &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;BUCKET_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;UploadedFilesBucketName&lt;/span&gt;
        &lt;span class="na"&gt;REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;AWS::Region&lt;/span&gt;
        &lt;span class="na"&gt;TABLE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;DynamoDBTable&lt;/span&gt;
    &lt;span class="na"&gt;MemorySize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;
    &lt;span class="na"&gt;Timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
    &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;UploadFunctionRole.Arn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway&lt;/strong&gt;: En esta sección vamos a arrancar nuevamente con un rol de IAM ya que necesitamos hacer referencia al ARN de nuestras lambdas y es por eso que necesitamos que antes de poder crear este rol estén creadas nuestras funciones. Para poder crear esa dependencia usamos el atributo &lt;code&gt;DependsOn&lt;/code&gt; lo cual va a generar que nuestro template se vaya desplegando por etapas.
Luego de esto vamos a crear nuestra API, a la cual le asignaremos un &lt;code&gt;Resource&lt;/code&gt; &lt;strong&gt;**&lt;/strong&gt;para nuestro path &lt;code&gt;/files&lt;/code&gt;, a continuación le indicamos que para los métodos GET y POST debe usar nuestras lambdas mediante una integración del tipo &lt;code&gt;AWS_PROXY&lt;/code&gt; y por ultimo generamos el despliegue y el stage “dev”
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;ApiGatewayIamRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GetFilesInfoFunction&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;UploadFileFunction&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::Role&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Sid&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
            &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apigateway.amazonaws.com"&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sts:AssumeRole"&lt;/span&gt;
      &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;PolicyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LambdaAccess&lt;/span&gt;
          &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
            &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lambda:*"&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;GetFilesInfoFunction.Arn&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;UploadFileFunction.Arn&lt;/span&gt;

  &lt;span class="na"&gt;ApiGatewayRestApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GetFilesInfoFunction&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;UploadFileFunction&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::ApiGateway::RestApi"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;APIGatewayName&lt;/span&gt;
      &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Gateway"&lt;/span&gt;
      &lt;span class="na"&gt;EndpointConfiguration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REGIONAL"&lt;/span&gt;

  &lt;span class="na"&gt;ApiGatewayFilesResource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::ApiGateway::Resource&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ParentId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayRestApi.RootResourceId&lt;/span&gt;
      &lt;span class="na"&gt;PathPart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;files"&lt;/span&gt;
      &lt;span class="na"&gt;RestApiId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayRestApi&lt;/span&gt;

  &lt;span class="na"&gt;GETMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayRestApi&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::ApiGateway::Method"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AuthorizationType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NONE&lt;/span&gt;
      &lt;span class="na"&gt;HttpMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET"&lt;/span&gt;
      &lt;span class="na"&gt;Integration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_PROXY"&lt;/span&gt;
        &lt;span class="na"&gt;IntegrationHttpMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST"&lt;/span&gt;
        &lt;span class="na"&gt;Uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetFilesInfoFunction.Arn}/invocations"&lt;/span&gt;
        &lt;span class="na"&gt;Credentials&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayIamRole.Arn&lt;/span&gt;
      &lt;span class="na"&gt;ResourceId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayFilesResource&lt;/span&gt;
      &lt;span class="na"&gt;RestApiId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayRestApi&lt;/span&gt;

  &lt;span class="na"&gt;POSTMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayRestApi&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::ApiGateway::Method"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AuthorizationType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NONE&lt;/span&gt;
      &lt;span class="na"&gt;HttpMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST"&lt;/span&gt;
      &lt;span class="na"&gt;Integration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_PROXY"&lt;/span&gt;
        &lt;span class="na"&gt;IntegrationHttpMethod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST"&lt;/span&gt;
        &lt;span class="na"&gt;Uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${UploadFileFunction.Arn}/invocations"&lt;/span&gt;
        &lt;span class="na"&gt;Credentials&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayIamRole.Arn&lt;/span&gt;
      &lt;span class="na"&gt;ResourceId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayFilesResource&lt;/span&gt;
      &lt;span class="na"&gt;RestApiId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayRestApi&lt;/span&gt;

  &lt;span class="na"&gt;ApiGatewayDeployment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GETMethod&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTMethod&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::ApiGateway::Deployment"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;RestApiId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayRestApi&lt;/span&gt;

  &lt;span class="na"&gt;ApiGatewayStage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GETMethod&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTMethod&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::ApiGateway::Stage"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;StageName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dev"&lt;/span&gt;
      &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Dev&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Stage"&lt;/span&gt;
      &lt;span class="na"&gt;RestApiId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayRestApi&lt;/span&gt;
      &lt;span class="na"&gt;DeploymentId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;ApiGatewayDeployment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Outputs
&lt;/h3&gt;

&lt;p&gt;Para finalizar nuestro template vamos a agregar dentro de la sección de &lt;code&gt;outputs&lt;/code&gt; un parámetro para poder obtener fácilmente la URL de nuestro API Gateway&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ApiGatewayUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;URL&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;API&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Gateway"&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://${ApiGatewayRestApi}.execute-api.${AWS::Region}.amazonaws.com/${ApiGatewayStage}/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy del template
&lt;/h2&gt;

&lt;p&gt;Para deployar los recursos que declaramos en nuestro template debemos usar la aplicación de linea de comandos (CLI) de AWS, en caso de no tenerla instalada podes seguir la guía de la &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" rel="noopener noreferrer"&gt;documentación oficial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Dentro de la consola, debemos ubicarnos en la carpeta donde creamos nuestro archivo &lt;code&gt;template.yaml&lt;/code&gt; y ejecutar el siguiente comando y, de no existir errores, veremos el mensaje confirmando la creación de nuestro stack&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cloudformation deploy &lt;span class="nt"&gt;--template-file&lt;/span&gt; template.yaml &lt;span class="nt"&gt;--stack-name&lt;/span&gt; cloudformation-files-service-api &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_NAMED_IAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="/img/iac-cloudformation-deploy.png" class="article-body-image-wrapper"&gt;&lt;img src="/img/iac-cloudformation-deploy.png" alt="mensaje en consola de un deploy exitoso del stack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez deployado podemos obtener la URL de nuestro API Gateway mediante el siguiente comando.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;aws cloudformation describe-stacks --query 'Stacks[?StackName==`cloudformation-files-service-api`][].Outputs[?OutputKey==`ApiGatewayUrl`].OutputValue' --output text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Probando nuestro API Gateway
&lt;/h2&gt;

&lt;p&gt;Para revisar que todo este funcionando correctamente podemos enviar algunas peticiones a nuestra API mediante postman o cualquier otro método que nos resulte familiar.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Para subir un archivo vamos a enviar una petición POST a nuestro endpoint (&lt;code&gt;https://{APIGATEWAYID}.execute-api.us-east-1.amazonaws.com/dev/files&lt;/code&gt;) con el siguiente objeto JSON en el body
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"filename"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"archivo.pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contentType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Martin Lubo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JVBERi0xLjcNCiW1tbW1DQoxIDAgb2JqDQo8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFIvTGFuZyhlbikgL1N0cnVjdFRyZWVSb290IDE1IDAgUi9NYXJrSW5mbzw8L01hcmtlZCB0cnVlPj4vTWV0YWRhdGEgMjcgMCBSL1ZpZXdlclByZWZlcmVuY2VzIDI4IDAgUj4+DQplbmRvYmoNCjIgMCBvYmoNCjw8L1R5cGUvUGFnZXMvQ291bnQgMS9LaWRzWyAzIDAgUl0gPj4NCmVuZG9iag0KMyAwIG9iag0KPDwvVHlwZS9QYWdlL1BhcmVudCAyIDAgUi9SZXNvdXJjZXM8PC9Gb250PDwvRjEgNSAwIFIvRjIgMTIgMCBSPj4vRXh0R1N0YXRlPDwvR1MxMCAxMCAwIFIvR1MxMSAxMSAwIFI+Pi9Qcm9jU2V0Wy9QREYvVGV4dC9JbWFnZUIvSW1hZ2VDL0ltYWdlSV0gPj4vTWVkaWFCb3hbIDAgMCA2MTIgNzkyXSAvQ29udGVudHMgNCAwIFIvR3JvdXA8PC9UeXBlL0dyb3VwL1MvVHJhbnNwYXJlbmN5L0NTL0RldmljZVJHQj4+L1RhYnMvUy9TdHJ1Y3RQYXJlbnRzIDA+Pg0KZW5kb2JqDQo0IDAgb2JqDQo8PC9GaWx0ZXIvRmxhdGVEZWNvZGUvTGVuZ3RoIDI5OD4+DQpzdHJlYW0NCnicrZFNa8MwDIbvBv8HHdtBHElOYgeCoY3TsrEeRjJ2KDuU0fW0sI//D1ObFjZoe9jig6wv6/FrQ9q+b3qoqnRV30bA9H7T72Cy7ZPHdhoCzGMNH1qhwf0qiQGhEOtKhs+tVk830Gs177RKFwREhnPoXrUi6UMgcGzEYGkyhu5NupYtIey+ZCTshpCO4VKrdYXo5yGxtkKys0Cl7D4PCWUV2lgiFbPA+6TlQH7IYR2Rco/Y+JAUUiN7qBEVIWEnjovDhNNIORWeobvTqpGLP2j1H4WUZaa0PzUelJ302LgYk+WusdBnopjFYT4IRduMCC+84Ss6x3xThybLz7MgkbHWeuheBuzYaPlOfxnN5I7khtAu4t/IfI7s8SJ5PYHpLxA0qxq+Ad/BuJQNCmVuZHN0cmVhbQ0KZW5kb2JqDQo1IDAgb2JqDQo8PC9UeXBlL0ZvbnQvU3VidHlwZS9UeXBlMC9CYXNlRm9udC9CQ0RFRUUrQXB0b3MvRW5jb2RpbmcvSWRlbnRpdHktSC9EZXNjZW5kYW50Rm9udHMgNiAwIFIvVG9Vbmljb2RlIDIzIDAgUj4+DQplbmRvYmoNCjYgMCBvYmoNClsgNyAwIFJdIA0KZW5kb2JqDQo3IDAgb2JqDQo8PC9CYXNlRm9udC9CQ0RFRUUrQXB0b3MvU3VidHlwZS9DSURGb250VHlwZTIvVHlwZS9Gb250L0NJRFRvR0lETWFwL0lkZW50aXR5L0RXIDEwMDAvQ0lEU3lzdGVtSW5mbyA4IDAgUi9Gb250RGVzY3JpcHRvciA5IDAgUi9XIDI1IDAgUj4+DQplbmRvYmoNCjggMCBvYmoNCjw8L09yZGVyaW5nKElkZW50aXR5KSAvUmVnaXN0cnkoQWRvYmUpIC9TdXBwbGVtZW50IDA+Pg0KZW5kb2JqDQo5IDAgb2JqDQo8PC9UeXBlL0ZvbnREZXNjcmlwdG9yL0ZvbnROYW1lL0JDREVFRStBcHRvcy9GbGFncyAzMi9JdGFsaWNBbmdsZSAwL0FzY2VudCA5MzkvRGVzY2VudCAtMjgyL0NhcEhlaWdodCA5MzkvQXZnV2lkdGggNTYxL01heFdpZHRoIDE2ODIvRm9udFdlaWdodCA0MDAvWEhlaWdodCAyNTAvU3RlbVYgNTYvRm9udEJCb3hbIC01MDAgLTI4MiAxMTgyIDkzOV0gL0ZvbnRGaWxlMiAyNCAwIFI+Pg0KZW5kb2JqDQoxMCAwIG9iag0KPDwvVHlwZS9FeHRHU3RhdGUvQk0vTm9ybWFsL2NhIDE+Pg0KZW5kb2JqDQoxMSAwIG9iag0KPDwvVHlwZS9FeHRHU3RhdGUvQk0vTm9ybWFsL0NBIDE+Pg0KZW5kb2JqDQoxMiAwIG9iag0KPDwvVHlwZS9Gb250L1N1YnR5cGUvVHJ1ZVR5cGUvTmFtZS9GMi9CYXNlRm9udC9CQ0RGRUUrQXB0b3MvRW5jb2RpbmcvV2luQW5zaUVuY29kaW5nL0ZvbnREZXNjcmlwdG9yIDEzIDAgUi9GaXJzdENoYXIgMzIvTGFzdENoYXIgMzIvV2lkdGhzIDI2IDAgUj4+DQplbmRvYmoNCjEzIDAgb2JqDQo8PC9UeXBlL0ZvbnREZXNjcmlwdG9yL0ZvbnROYW1lL0JDREZFRStBcHRvcy9GbGFncyAzMi9JdGFsaWNBbmdsZSAwL0FzY2VudCA5MzkvRGVzY2VudCAtMjgyL0NhcEhlaWdodCA5MzkvQXZnV2lkdGggNTYxL01heFdpZHRoIDE2ODIvRm9udFdlaWdodCA0MDAvWEhlaWdodCAyNTAvU3RlbVYgNTYvRm9udEJCb3hbIC01MDAgLTI4MiAxMTgyIDkzOV0gL0ZvbnRGaWxlMiAyNCAwIFI+Pg0KZW5kb2JqDQoxNCAwIG9iag0KPDwvQXV0aG9yKE1hcnRpbiBMdWJvKSAvQ3JlYXRvcij+/wBNAGkAYwByAG8AcwBvAGYAdACuACAAVwBvAHIAZAAgAGYAbwByACAATQBpAGMAcgBvAHMAbwBmAHQAIAAzADYANSkgL0NyZWF0aW9uRGF0ZShEOjIwMjQwNTEyMTY1MjExLTAzJzAwJykgL01vZERhdGUoRDoyMDI0MDUxMjE2NTIxMS0wMycwMCcpIC9Qcm9kdWNlcij+/wBNAGkAYwByAG8AcwBvAGYAdACuACAAVwBvAHIAZAAgAGYAbwByACAATQBpAGMAcgBvAHMAbwBmAHQAIAAzADYANSkgPj4NCmVuZG9iag0KMjIgMCBvYmoNCjw8L1R5cGUvT2JqU3RtL04gNy9GaXJzdCA0Ni9GaWx0ZXIvRmxhdGVEZWNvZGUvTGVuZ3RoIDMxNj4+DQpzdHJlYW0NCnicbVHbisJADH1f8B/yB+l4WwURxAsuYimtsA/iw1izbbGdkXEK+vebbLtrH/Zhhpzk5MzJpB9AAGoKIwVqBCrgM2bM5x2GYy5NYDgZQF/BcDqB2QwjYQcQY4IRHp43wsS7OvXrkircHSE4AUYZDIQzn/fempZR27KyaV2R8f919sVKfIK2q8M4OKLYWo+xLWmvb+JR9CLtWEuqYlcyLNPYExd/1ZAefkdPUK30hrWM9YShXGtzeYEDU8/2gQmlHrekL+SaWHp+4w9TFoaSXItDSSwMK2hfWNNi54svzcEP+rTuerb2+ppeMvecyItJj3udOtvBy5zvDl4VurRZJ5GUxYU63OYdpmVOV7gpstrxKIUvCbcKl7aSVxcmzS1PcNOm/Yewru68Mdlu9+dDXdH92MDXWnpv388vrNwNCmVuZHN0cmVhbQ0KZW5kb2JqDQoyMyAwIG9iag0KPDwvRmlsdGVyL0ZsYXRlRGVjb2RlL0xlbmd0aCAzMTY+Pg0Kc3RyZWFtDQp4nF3SzYqDMBAA4LtPkWP3UDRa/0CEbqvgYX9Ydx/AJmNXWGOI6cG332SmdGEDET4mMxMmhqfu3KnJsvDdLKIHy8ZJSQPrcjMC2AWukwp4xOQk7F34FfOgg9Al99tqYe7UuARVxcIPF1yt2djuKJcLPAXhm5FgJnVlu69T79zftP6BGZRlUVDXTMLoCr0M+nWYgYWYtu+ki09227ucvxOfmwYWozldRiwSVj0IMIO6QlBFbtWsat2qA1DyX5wXlHYZxfdg/PE4dsej6HCovZKGlKGKAyqNSM+kBHU6ozKOagoSxjhPSAUpI5WohPplDelIalEpVcljVEaxPEXl1C/Hm/EiJWHN5Fyi4ojUkrBD0nCUa+TVUpW4xOHcp+DH5F/z8QbiZowbPz45zt1PfFLw+Cv0on2W37/b9p5GDQplbmRzdHJlYW0NCmVuZG9iag0KMjQgMCBvYmoNCjw8L0ZpbHRlci9GbGF0ZURlY29kZS9MZW5ndGggODQ2Mi9MZW5ndGgxIDIxOTE2Pj4NCnN0cmVhbQ0KeJztfAl4G9W18L0zI1leIzuJHWInGmVikUS27HhLbIeg2LEdO4sd20msrB5LY1u2towkOw5xCUmzoLL9hH2HAgFCYRwIJDxKoUA3SGj7WtpS1o9+QPq9Qh+vj5/SxPrPvTOSZWMoBUr7fX/mas7ce+65Z79nZhQ5CCOEpgDgkL25raik6a+H9QjhHYDtbGtf1v6LMy9FEWq9Bsa7nF4xMIefVYzQ9IMw/tA5EOLNh6f/GKF5Rhg/3R3o8W74zhToZ+8Cpnt7PEPdFccsT8D8zxFKXdUria65Qt5fgPYMnBW9gEg7o7sf5JXBeG6vN7Qj0Gz8IYx/i9BUxeN3iqm9GRUIleUhlGL0ijsCBu+UUZjvAHreK4XEQ39d9FeE1oI8PMMneqXpfVkwXloA6wsD/mAoejsqgfnNhD4gS4HAvuhUhCwwZKYgYjuDUGFgy7e3TVnyvyjVgMjx2t3hT8j1rfc2zz6Dz55MDhumwVBPaOkB65L2nv0B6GQ5gz/+MDlMOSUc3C8IRpeEisGvMxALK42oCFCYWTVlL4ww4rhd+CqkQwZdKXcSltykXpmTqJv5PVxTEceQg+MRcwDm2Rjv1W08j55G6WfPqDoYpjGlPMK3kzn2lK6GWIpY9nnQ4nFkICf6Fx66YaR8k/K4km9W3ucd+tZ/H1242z5bF+4AWvUNqvJve3B21PeNySqdXBa365vT4YsenBvdGevj0+gyOO+cSEPw/2zZk873/Wv8xXzv8/X6oge3A13/dfAhB3vbV5v/rIP71r8+J1k/amMPobZ/tR7njnPHuePcce44d5w7/v8+8B2T45lGdHfilfY70Pf+2fqAjKZ/BP+F+f4v2v9V1p87zh1f74Ff/Cfzf/Ofy3/Sg3y7SL7lmwYQ0yuHXoerDfHQy0Bz0HzoV6FlaDmqR6tRC7wNiciF3MiPZDSAhtAD6An0DF7IJkWjiHwLOBm9E/UiH9CHJ9Kzv2JH2MPRp6OvRz8G2WVoMfJomr0DHknDKehv0WXRd7AC2tkmtWA2yJwD1znj0ezv2D9wU9F76H08FWfjElyF+/AwQvamG2+4/roD+/d9e++eS3Zf/K3hXRftHNoxOBAOBeXtAb/P6+nvc/f2dEsuZ5fYuW3rls2bNjo6Nqxf1962tqV5zepVK5saVzTUzzMZU5IL8EhqSq1QK6UUFqCRlFTophYWYEVfqyRRpNJs5RX72g7zytaOuuW5ZrMjVzArdoXLryOn6Io4YxMOYAGrYC2wWNkmrFy7sYOvi3TSScC0jxup84vjc1pPYWrbO5R6K4wSxg10HB+umDDdGJsWeAW1RCKuEcTmA96eO4JpR1f7HQdY4hCULqtgFjokoB0xoDRze2ct9NJiPcw3AEf+uBF1wencIBzHWm9jh8J3djtWADVi8hX6aTuOyoUdar9T4Z08r+jzha6WjohZwZ1CrjZu7QCPYTE3YhbMvMNxPPpMHqEWzMCLQTUjAj64dsSOD7Zt7DhhhPw72N5xlMFMbWeNY2QuzHWc4CHoFMsQLEGSAU8GaCWGyBxlDJQ+94Qdod10lqMIOnaCFRRniOEwch5nVJxRFWShguywm5zHOXXGHqPmAGdQcbtV6nkatQFmjGTmCcTA3qOT6gFegsjYU3R2gz3ZnsakMxALgjoKmCeANhmjR9JwOs4dAZ6tFH0c7x5JtueeoJxaNcrdQElwu+M40JyQJTACearh68YsWLex45E0BPwpBIoachQW1I0wa6zCWFqv7YDo1Y3gNdZOSG0yZPPreEhrxd7WQWg7cyHnIbuXFxaQ7OI7BClXcIxMmxYJ1I0YjbUrI7WQyJBrNMFGRL2l0xpRU44kmmCsgjRl8xudQn0nkAiwbeDTCCjner5T6eq0Qpc31kfqSVaIhBpljzBs/gjm8vFStBT8pk9TUgSpRkkVauIzF6IL1Rk9mUkSahScrXq9TqjjZ7gjTqELMtDe0tGT2+0QgbdiF0SFE2pyRzhUA/tlBgaT6kbQGivYthJysNnasgk2KXEGH4ks50fsnEV0imS83Az7PqJNCcuXOxJW1PERxS46O4GizkGJYScCsk4QeRd4GcwFz7UJ0N24kaxp39gRSXMJLgE8bLdHRDA7l3c6ciMOJ/U4rAfVUGGBbqw6acWJIXs+39kN4DiPujqFLhVBdudEXM9ERDdQJeKEJiKOXjG9RpqEOhdQkFN0KSxknJl3OdSUQS20bnwmEU4g4iGmlHnEWB0bYW0EA/hElJ7xw974sJ6cneA1m5orCmchmddhVvpyFY/DGicRld1dfIQ3ClUCAXRxAzk7FR10djtFUpz0JPcA0QQIvqMLchkY1ndGYhkHyzhLXJLis45jCSUVt4NoJp+Yo+xu4TsdfGcnYGH3mHN5RQdXvlskyUXKbotqTwvUfriIkTZYi8gGylWS4A7QLUqCGaq1Qjat6n2iIwfaobYOBeVGIkJEwaBifj0QA3uLorc0kgt8AlZBlCCIRB4vSnRtPahLvUO45dYJZgeQMPnUl+A4qBZdBDgjkI3KFthtuvzMSFaEr4xA1doCBZezONd3wm2BN/L1PA21CJlMnNBIRg5gpBIm5xNCWE8/FsVrHdmSlD+GoR+/VSU2UK6gWWuH0hIjSaIf6Gy3KkzOYpgkxuNWqB8cDRRxni6/Edxrh6zKJat5hWnv0MJD1zeSpbmxgKnLAEPLLrktmmP6pqr6qkL19JNGP8n5iiEfAq1woIM6nUTMGUsC6IPS6hqWqqsaAH0QxWsz1JBObcDlS9Qm9XbIk/IJDwqiQM7c49GnW6BGdgrkdDiIeAMVRFZQ1hGVMXGXnkxO5gpNkvpJJZ9GakIiOoV+kqjOZE41STfe8Zr3TkSfRqrnzNpBcoZYeUDbldq+k3KVXofVpa7SaxWch4oKldu5lj5tbILdIJiToI6B+bCreKXNCjcRatsB1atNanUgWYnrBVQPOaR1UDZSkLACE4BgawkrFAaG8Z5wlEHYICwml2Rh8QiDk6Dak2JkTE+DQh9xdrrUGzV4GS3OXUIejfQ00Mk0tgOkNLV36HI5B00ZizJo1bJYhQPW+Pwg2ZNJMU8ayFwkPqmj7AbV3LBocMBqmHRVxPDFhBm0aCrJdI5UI4vh80WxaoCa1HA1MSrnJrVOANbijERIaRvZkkF2aJolE/BZoFolKFmpaQm+2QWqtBDRBoqhQ9huSUQdNWz5qTBhBNpn1NROhUkjaPNMrkoFnxPwIjBgjVGrTgC9U/LVPNemtdVqdg5aHdCrJ2cnkNSTU9tJqdouTZtQ9TX2akyTx08KcWbkRi/EOZLRCE6DZ2AuVwcSLbwR3FVF/WkBVWEcqRrBSRaNQEcImPyqSCQ1Vv9J+T8BD6CIPlwiR2QiQhmGeECs0yefMUzEplO0FuX0+JUgte2QUquk1pLnF3JvSiYJYIP4Dj+v1Rz6OJHgGIoiWzERO4P4PilWEvzW2NqY37rpltbWTsC2dwwDlnjqeXInUTBcdRYzOXOJ66g0kuN+q/agO0yiu4ey22PleTc8Z9VieNqCG6Wb3Kp4Qm2w0CIXgQcetyjSOkRfY2bAs1QreTqGNwDByOMlaIn6MiRo7xlwD+DyO5bkVjrgveJ49HSeQy1VDNzk4WyP8LwxE6YifBa8aCj7qHu1OYHi4C6ut2hUxIJ9sDlVOqJ9GhNZ2QZOIG9kKYtzU8hbXuwF6wbr503zZD1UKWWbsMNMXKGsF4bgYaFWUHh+M5REQDbkOSIRuJ1GBPImtb5DhWQKF+SRJwPyFKPR5ubBO9rYMC2PpJt4PPpIHnldiku7KCZNBmmkE4mJU5yTSiNZhjepuQYfqv5IBRJU+ZxFExrZHNkI74dmZRYRrOkBw4w8B+UAmtxANEH26LbiqGnrwqhpS5Fs2lx0yLSpKGraaIuaHLaTpo6CqGlDYdS0vvCkaZ01amqf32Rqmx81tS6ImtYuOGJqmc+bmufVmdbMO2JaPS9qWnV+1LTSEjU1Waymxrk9phVzT5oa5kZN9flRU13+EdNyIWqqnRM11ZhPmpaZoya7+YjpQv6kaSkfNV3AHzIt4YtM1bNlU9XsqKnSFDUtNu02LZolmypmRU3ls06ayvJOmkrzoqaSvCOmhcWyyVZwgamwQDYtmL/VlA+y5s7MPW+zMMdumsPOPG+zeeYFJn4JdEyze0yz58/I3jwrJ2rKy46acsvPq9o0oyK7atNMewvp55D+9POqs3s3Tq3MWpdZaVyX5TA60ivT1ukqmXUcnGmOKRUZ61IrU9YlVerXZThSHHoHciRXGtaxMGtwMA4jYu12HT6Br0Lt1pXHk6KtKxVDyyYFH1Ty2wiE1wZFf1BB6zZu6hjB+ArHvssvR7NqVipXtXUcZRF04UmSqV3bMcKxVzhqkBVZrVakNdrVxlYrTmgITvJBVrWjzmvkWj8+sMZINfy4mRlIV0Mayor+Ovou+xHKQij6fuwcvSn6J11ODId2oUuQF9ogckEj/Z0ogAZQG5JQGHlQD1D0AwyiPvQbJKKNSEbtQNGDLgLq/agXVgwA3A7jb6NO5AdOF6HVsL6DchCB0gOzA8B9mHIi9K30G68w2gs81wFPF2BltBZtQFuAYjs8OpBvnJ7XNSEWTUFTUSEqss9ckMPPPF83l0uZ5k7hjEbbrLlTp2JGRgYZjC8x/qgksxSANTMrp7J44fZMc2b+HEt5WUVpSfb0aXqdOdOMLRWLKirKyyzCHP10ITaTpNcnsc+Pnje3uHju3JKS0WXs0jM/xBJXXV1V0bq+fVvgrkv23NxSu2gOp2v65LE3iubOLSLnLdwPz3zU2l9Y0FBR3dzRMnxwV3+Lq8y6spx8B2iA5/iHIQJJKAXl2tNTOINej0BXjioLOlYWlWaClkFcigXWzE41swb88VP4v5/YffaX+x/HP/uDruaTp/DQ6AHGyFyM4I5NOeqf1VvIt4pYz71kgSfqx5hUjPGO9chaRqQqCOkyQGoKmo6Mj08HeamavBIQlWku4bKmT2M4Ib+0hLrBIsDt9Pn/xAtuuXX05V+OfnB65J3twXcfOq2ruX30l7/69egvb7t+++kR5V0ZZAJv9iPgnYxy7Kk6gwFxY64n1lAB0830VNj6sz6m/eyDuprrRlsPnb1WXa+7E9ZPQSa7kU1OZ9PS9EgPPAwxFTOzKotI5IKZ4BNcmiloV+V5/EYjfvnpkaWjiwZGi5fqas68y573yVPcg2f+xur+1q5ZzjUD9zSwHPRLT01F0yfRrySbBFwvmDOhTxPBrOB3hn8SCv1kePQUnrvz+huGRl/V1Ww7sX/v0c1n/8TcN3zxwT2g/aro+9wSXTsqQrPtWQXpusx5s6fPNSDzeaycjJJV/Wna1c2xWMpLp2Vnx1x8vo2BHCSplj1dqKCZB7M5sxmiCLP6qvcuPbblps3rLm+vufGSG57b5vnZd/b89pJH8QPDl1y59PoDtzy7ec+bWR1PXte/s6S0Z239xlrzvG1XeIO3trbfNyyHe5zVzXZhQed1O/ccWU/80Bd9n72ffQPNRvOQ2Z45M0U2CMIUlDYtSTbloVSiKPF0ZWVmqVVTtqxi7qKxLQGKgmqZwvl6/fklFYvKOaIuvqX9O21344Kf7tomRe7qORZeeanXfktS7UiT646K0Y/e3ZJlH9689+BCZvnwlm7fjmuW5zXtc58NX7Ny0+6tK37Ebu1v3AA+7It+wP6U6gY7In1m+kxkNCTJOapW4L7KyqKiuE7UYTmCJeYwcOei0gyGKfz2i8HtLxzYfszD3qPf1X/FZUu/tbV/P3sP6z2R6X/jvvve2t50rbzV86wS/u4Gf//ArWtiXnmV1ENkQrPsxowUOR3JM1NB+lRj3CklVus46TmZpXE3ZMb0wO8PPrRNOj7ce1PR4duSy+5e3X9Fwfx90r4DF2fJbx++9/Xtm9YwaZ88dUWD41KpAQ+29j/18LGnwPY7Yff8AjSYBtmZZmT1STJGsDlTqOkgm2Z9JpULzs8so/KSMu+8t/C+PXdfeXjWmkbvNYW6mrMfVbuffPDsZcyWet+Fzuqz1LrLoB5s0TXQSml8PIXDepkytp7S2LIJZfDOw+1FxNFVVeypMyXcvkULFiwip6ojXsGeAj5px+I8VA53HibUUIU0WXoLzoFeEvf46A+gUKc8QoVaTxUvjNnKvppoq/5TtuZ82tY79IX37b3j6sOzVxNj2VPXVbu/fwRs3dwwZmtf9M8cYt8iVQRsnQERNMbyZ3zqkN11fqzKzdHTHGKKr3yxv//FK69+ye9/6WrP7sWLd3vcF1VUXGQceuvm29/eufPt229+a2jftsN9ngdE8QFP3+FtSLWHOci+gjLQdHtqsmaP6p1Ea0qnEzlgx636+VeHp+U0+lp59tS9q7pvtNQWnG0nnK6P/jf7G/Cw6pkUeQqnl7NS4hmo5l85+FtLeC0D8cv3X3ff7PZm3zWF992pKzoy5cl7mF1nb67prdq0hDl6puS6qn6k/nadvQ2460HPFFaHdHE1SWktXijCvYZ8BkYjI5jHwgOjV0FUX2YXnCkhq0dvoqszYXdmJOtTU5P0sj4F0jRDixvl0VZO9FqkckrKYAR3a2VznmX0ohFciLMfGL3aNmd1YMPoTZELGjqA+dvsrDMlAxv6itTY/Yl9jX2d7sJ8+7QpKXKaXs6ZSfdh9tT4ToTKRMGE3Vg+2W78YOjhLa7Hh7032shuvKfZe5V13gFp76W7p25/897DbwY3rrz2TMmhlZsOupvwULP0jPLIk0STNqaQ+RtU8zxkgXqQzs+aZTZMMcxgZ6K0qaio9LmSHKiPoEPxwmWaBovGPTRkJxRImlq4qWb78r3v37V1xaruQ49dueHKdZcnlV1e1PIt8wsPNzKFZT2r+vvnMRUbljc0Ry6yBd1n/6/3guXbmy+8nF25tqpG1YhdBhpNAZ0yjhkNyJ1jAE1IVi/7dFZrSU0EPyff63DcKw88sGXLAwPDUkFXe9jlYgrFR4d3H+sUj108/Kg4dMdQ6+6mO3YN3UGy5O7oR/ge9CGCDfmIHmURl6tpF6sQ2LK4qWnxohUrUhrLFzU0LCpvhH1PV7Gn9Bao34hJovBV0Pt7gD9Cnwqmo6n2ZGQ0pnDuFMLVWkr812ZhaD7DkgQRZ405D+dkFi1ubFxc0dCAbw3h/EPkWefQ6CvBUUdjeUV9fUV5I9G2afRm/Gt4CpxCtXXrURGkRVtFVnkZc35pdhZ5nGGSmgblPT0HW0MXXBBsG735BfzTD36F7z0aGf3r6HvfvWP0ldE/HiCcotnA6fnxnDZ8Dqc/jjH6ePQ0MPrd6B/3k+zZz3oYP7V5KsQqhUN9GVwsVhCq8lLyTGmO9/DptCl3ZqSPrkkz3jUllfVsU/q2bOl/sCt2RRi/yO1jboMKTmKC9H2I6rYswWFMORRsUrQTCjase1P3GOvUPwsVG9bh2LqpsDnf/OEzo1HdYzh99H+gLGxDB9FNX7H95Eu2976OhnO+ltYwrt38b9BOf5nGWBJaz9fWrqXtBPNCvL32xRubOqHVfYXW9wXajV+oHZ/QTn9242xfuQ1yD55r59q5dq59je3H0P6TNB37D7d5CW3132kD59rX0q7+B9u932yD50ELPhX7W2d2MdLeHQHqYIS1XzEmsdu1PpuA5xL6OpTJ7tD6+gR8EqqM99Pxc+ylWj8DWXWrtb4xgT5zTBbmkF6n8cTwBqv7ltZPTqCpRmm6vVp/CdBfSX5pySWDEgHdtVofo5Q0ndZnUEbaoNZnE/BcQl+H5qTt0/r6BHwSkuN9A8rSfVfrJ6O8tMNaPxW1pz2r9dNQcXqO1k9nD6Y3aP0MtN74ktY3JvDPHNMNbE/LzNf6OpSSuVDrJyfQVKMZmdVafwnQt93PlxSXlPGr3U7ZH/R3h/havxzwy2LI7ffZ+GUeD9/q7ukNBflWKSjJA5LLxrf3Svycfkn2zeFDYpdH4v3dfKjXHeS7/b4QPygGeZc0IHn8AcnFu318QJRDfDjo9vXwIh8MhV1DfNcQv8znkq/g68PO3iDv98F6iZcljzQg+pyUIeFPlgREtxzk5/WGQoEgvMH0uEO94S6b0+8tEoGDVNhNOBRp1IWUuqjL4+8q8orBkCQXrWqsrVvTVmfzuubbwLbAkEzMAaMXVibqYONbJNnrDgbBbB5M6ZVkCbTskUVfSHIV8N2yRNVy9opyj1TAh/y86BviA5IchAX+rpDo9qkWOkFG3CPEo4OiLAGxixeDQb/TLQI/3uV3hr2SL0TdzHe7PRLYSHwwp01bMWc+FeKSRA9xIpmLTfGD4AR/OAQOC4Zkt5PwKAAipyfsIjrEpj1ur1uTQN2rxhGYhoNgAdGzgPf6Xe5ucpWoWYFwl8cd7C3gXW7CuiscAmSQIJ2Sj6wCO4r8Mh+UIDGAgxv0praOaUdpiJQAcWhIcxGVO9jr9463hCRNGEIX7JXoGpcfXEYl9knOEMEQ8m6/x+MfJKY5/T6Xm1gUrKJpKHb5ByRqihpWnz8EmqoaEP8HxoKqTQV7RVC9S9L8paaomGCNTKQHQxB3N7getgIVN9FK27JAyB8k+ot8SBZdkleU+2NEY5upR/aHAzRv/N6A6AMBtlapJ+wR5fXgFqJWia24uLq5tKJ8bFEwHAh43KAZ2U823uEP815xiEQtYZuBa5yyJJL4QKwCHnFIdXxAdsMs+CkE6QUpp4WBJB3kM9FOiyUPu8NL7dU63WpefMqGgOx3hZ0hiArsf1hbQNbEBIDzBnvdzt4JBSDm3DHt/T7PED/PPZ+XvF2SK4EcOHyetpScpnVCtgfHRS/Oq5p6YJ4bpIQkL6lishukuvyDPo9fdI33nqi6SpKJOX4QBTAcCsC+gepFMgVoeiVPYLxHoSTCtlfJSUBIjsn+XneXG3S2xaoUbO+gzRvzIK1WoaGAH6pJoHeoCJI2HNogkYTd4HaFepsDkJmQa23unVJjSIT4oPsRj0pQMZxl0FuN3MiJZORHQTi7UQhwtfTn/gEKRcCQn//76B8JLEMeaDxqBVwP6oW5IB1JcJXonwhIyEUp22FWoj/W76czPujxQC+iLuBAZog0gukFXoRLN5VC5A8CFcG4gI5w9MBMgHLmgdYHMAAUMqUNAyXB9UBfhDMI2DBQDkG/i8JlMOsC6tPQr4c58ucJQSrfp8kn2shUDpEnAt6ZoGFM/5gUItsNGMJjHvVBCHBBVIWKoPXAHOEZBuk24ONHXsCKmg4SKgSeMR2KJvAuTOBdRP3kB1gEHERqF6EtQqtQI0SoDq1BbQBtMOuif4ahxi0ANsvx6KiRXogqP9MPZF0L5eylcQhq0ea1qPTSOUnzZQ/NCB/VxYUKaNTI7Ji3CFcSmx7AFVD/+mlkfHR9gHILahKIdSFqsW9cDJ2aHZ/OkViODlIZksbZRa9BOusESlHTj2QQwYTBNolqPZbNRHM3jbgax1A8X9smyCB/FDNmCclJke4B97j8mbiKZLGaCX6QH9IyjERRpjsupkeBxskJPMP0hweqHyau9sDYS3GJNoxlb+J+VDUN0z1ZkOBP0vdCn0jpjo+lhGgFaN56qLd7KcZF+6rWXVQXlTIYp3RS38ZkqfEoorWDp1i1Yqg6uDV/j8V1Mt8VJMRVtSUQz9DQhCwas3eQesv7uTGJVZqwtuuClHJMjotCwnnMxj6gcFK5Kk2MO6lXHrpHB+NRc1KdXFRPt6ZfVUI1JNXPT2vaWFQSd6sPcCHNp4k+iOX/mB8Sd+r4VUG6A1Wvd2lWj+VXYhUVPyM2ctz2IM03H+WuZr16Vxiz7u/F0gZ1J0A9F4z7X6T0Mv3TMolWNxkq4UROk92Zeug4DBzH6g2JeYBqqVpgo/ejHvoDIcJ5vZYtMW+VAEUxtGrUjEpRBSoHnUPanYZIFWlFl7T8itV3tboP0majERiv21itD0FMiZfUWhkADkOAjd3dglo9T5Tx6RWEezDOczJPBKkXAnQHqjGNSSAV3UG9xFNJQ/FaMPndVs1qJ42WGN/f6r4PUB8OjduRAZqx6lqnxkXSxuKELA3FK7F6/4jFdnzd4LV7mzch/8ZjusfVs7+fJwE6dtG7XEjby+rziSq3IC5nogXqzhjUYtD7GT6LPaFM3FmT+Z6s8dDePKCfD1eS813xuvNp7qoOX9a3Y9zH7iaT33smsyDxvjZer+qEHCCWqLaEqLzYs6JM76lDWiUdpJb76T7/vNwTx2WVROPi12BIewLhtTthQLsfqs+GsZqn8umld5vA5+ao+hTr0yIzxj22Q2J1luRPL73nuTU/2z71rKc+XQS/VD1Q7wTElg3APXYH2AA9F9WqmVZNwlWtu23Q3wmUjbQiq/sHxf/Pvugt5P8gnPTA2pX8/4dsl9vj0vo7XR5fD1wfgrM8qPbfJn3yEtPu93vgNbjMVrrIVlbNh7v9Jd2hKnihLFlsK67mneGS7eEqfqGtwrbIRv4PxJJqvsczFOgNrnJ3VfEVtmJbRTXvDRJWHoIpti22LVxcTd5n6Mt3j5t8wzDgJq+pQF9ZvEh0lpWuEkO+Ar52SPYU8A2yJPUX8APuQhXb1VOoTgRlrRPup50vtQi8gpGB/pJzGoVliPEHgjtxNUKD8O6EOYQH4fUJ6xDjhtcmvAQ8bUB5cNtYQv+KmsHk+zSEUs+7CRnpd5KY4PBV4HAZzuPU8wylc9E+S/tIw2eoQWFaod8JmJlwkl98YNha5LvHKthuGC2FhpEdSgpGmxD5vnE3+j8AD6EjAB9CJwD+B3of4J/RhwD/AvpinARyME7FaQAz8HyAVtwMcC12ApTwMMCLcQTgZfghgA/jo6DbY/gx6B/HTwD8Pv4+wKfxz8i//5PvY/HP8a8Avox/A/A1/BrAt/BbAN/G7wD8EIN0/Bf8EcCPcRRhhmWSACYzqQAzyP+DyWQxswCamAUACxgbwHKmEuAS5gKAtcxqgGuZtQDbmHaA65kNAB3MRoCdDPiIcTF9AL2MF2CACQAcZHYD3M/sB3gFczXAG5k7AN7FPAjwYWYE4KPMowAfZx4H+AQDdjE/YJ4G+CMG7GJ+zvwa4G+Y3wJ8hXkF4KvMqwBfZ94A+BYDNjJ/YP4L4AfMnwF+yIClzEfMGYCjzCjCLJgKMIkFn7MZbAZAI2sEmMVmAcxmswHOYGcAnM3OBjiHLQRYzBYDtLPLANaytQhzSzmINVfH1QHcym0FeDt3O8DvcUcRyz3CHYP+Y9zvoP977vfQf5d7D+D7Oh3NZZZ+b40ghxAqof/351Huee5H3I8hv1hY9wRC3JPcs0jHvQA80kkOcv/BPff/AM8Eza8NCmVuZHN0cmVhbQ0KZW5kb2JqDQoyNSAwIG9iag0KWyAwWyA0NzFdICAzNFsgNjg2XSAgNjJbIDUyNF0gIDEzMlsgNTc3XSAgMTM5WyA1NjZdICAyMDVbIDUzMV0gIDIzMlsgNTI1XSAgMjc1WyA1NTFdICAyNzhbIDIzOV0gIDMwNlsgNTUxXSAgMzE0WyA1NTJdICAzNDRbIDMzNF0gIDM2MlsgNTU5XSAgMzgxWyA0NTJdICAzODlbIDQ1Ml0gIDk4NVsgMjAzXSAgOTkxWyAyODZdICA5OTNbIDI4Nl0gIDEwMjFbIDI5M10gXSANCmVuZG9iag0KMjYgMCBvYmoNClsgMjAzXSANCmVuZG9iag0KMjcgMCBvYmoNCjw8L1R5cGUvTWV0YWRhdGEvU3VidHlwZS9YTUwvTGVuZ3RoIDMwODc+Pg0Kc3RyZWFtDQo8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pjx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IjMuMS03MDEiPgo8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgo8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiAgeG1sbnM6cGRmPSJodHRwOi8vbnMuYWRvYmUuY29tL3BkZi8xLjMvIj4KPHBkZjpQcm9kdWNlcj5NaWNyb3NvZnTCriBXb3JkIGZvciBNaWNyb3NvZnQgMzY1PC9wZGY6UHJvZHVjZXI+PC9yZGY6RGVzY3JpcHRpb24+CjxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iPgo8ZGM6Y3JlYXRvcj48cmRmOlNlcT48cmRmOmxpPk1hcnRpbiBMdWJvPC9yZGY6bGk+PC9yZGY6U2VxPjwvZGM6Y3JlYXRvcj48L3JkZjpEZXNjcmlwdGlvbj4KPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+Cjx4bXA6Q3JlYXRvclRvb2w+TWljcm9zb2Z0wq4gV29yZCBmb3IgTWljcm9zb2Z0IDM2NTwveG1wOkNyZWF0b3JUb29sPjx4bXA6Q3JlYXRlRGF0ZT4yMDI0LTA1LTEyVDE2OjUyOjExLTAzOjAwPC94bXA6Q3JlYXRlRGF0ZT48eG1wOk1vZGlmeURhdGU+MjAyNC0wNS0xMlQxNjo1MjoxMS0wMzowMDwveG1wOk1vZGlmeURhdGU+PC9yZGY6RGVzY3JpcHRpb24+CjxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyI+Cjx4bXBNTTpEb2N1bWVudElEPnV1aWQ6REExNUU0OTktMjczMC00ODcyLUFGN0ItNDk3MkQyQkY5RUFBPC94bXBNTTpEb2N1bWVudElEPjx4bXBNTTpJbnN0YW5jZUlEPnV1aWQ6REExNUU0OTktMjczMC00ODcyLUFGN0ItNDk3MkQyQkY5RUFBPC94bXBNTTpJbnN0YW5jZUlEPjwvcmRmOkRlc2NyaXB0aW9uPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPC9yZGY6UkRGPjwveDp4bXBtZXRhPjw/eHBhY2tldCBlbmQ9InciPz4NCmVuZHN0cmVhbQ0KZW5kb2JqDQoyOCAwIG9iag0KPDwvRGlzcGxheURvY1RpdGxlIHRydWU+Pg0KZW5kb2JqDQoyOSAwIG9iag0KPDwvVHlwZS9YUmVmL1NpemUgMjkvV1sgMSA0IDJdIC9Sb290IDEgMCBSL0luZm8gMTQgMCBSL0lEWzw5OUU0MTVEQTMwMjc3MjQ4QUY3QjQ5NzJEMkJGOUVBQT48OTlFNDE1REEzMDI3NzI0OEFGN0I0OTcyRDJCRjlFQUE+XSAvRmlsdGVyL0ZsYXRlRGVjb2RlL0xlbmd0aCAxMDY+Pg0Kc3RyZWFtDQp4nC3Myw1AQBAG4H+fNiIRF11QgINKXNWgBUW46YiTOEtcVbDW/OYwX+YJpIhRpVwBHys5BfUIZiSXYBVZCJtuE3wgPeEs2wGdftbQxBBLHFHk3/TpLtxyns9CUQrNJLQDYdUdwAvgCQ+hDQplbmRzdHJlYW0NCmVuZG9iag0KeHJlZg0KMCAzMA0KMDAwMDAwMDAxNSA2NTUzNSBmDQowMDAwMDAwMDE3IDAwMDAwIG4NCjAwMDAwMDAxNjMgMDAwMDAgbg0KMDAwMDAwMDIxOSAwMDAwMCBuDQowMDAwMDAwNDk3IDAwMDAwIG4NCjAwMDAwMDA4NjkgMDAwMDAgbg0KMDAwMDAwMDk5NyAwMDAwMCBuDQowMDAwMDAxMDI1IDAwMDAwIG4NCjAwMDAwMDExODAgMDAwMDAgbg0KMDAwMDAwMTI1MyAwMDAwMCBuDQowMDAwMDAxNDkwIDAwMDAwIG4NCjAwMDAwMDE1NDQgMDAwMDAgbg0KMDAwMDAwMTU5OCAwMDAwMCBuDQowMDAwMDAxNzY1IDAwMDAwIG4NCjAwMDAwMDIwMDMgMDAwMDAgbg0KMDAwMDAwMDAxNiA2NTUzNSBmDQowMDAwMDAwMDE3IDY1NTM1IGYNCjAwMDAwMDAwMTggNjU1MzUgZg0KMDAwMDAwMDAxOSA2NTUzNSBmDQowMDAwMDAwMDIwIDY1NTM1IGYNCjAwMDAwMDAwMjEgNjU1MzUgZg0KMDAwMDAwMDAyMiA2NTUzNSBmDQowMDAwMDAwMDAwIDY1NTM1IGYNCjAwMDAwMDI2OTYgMDAwMDAgbg0KMDAwMDAwMzA4NyAwMDAwMCBuDQowMDAwMDExNjM5IDAwMDAwIG4NCjAwMDAwMTE4NjggMDAwMDAgbg0KMDAwMDAxMTg5NSAwMDAwMCBuDQowMDAwMDE1MDY1IDAwMDAwIG4NCjAwMDAwMTUxMTAgMDAwMDAgbg0KdHJhaWxlcg0KPDwvU2l6ZSAzMC9Sb290IDEgMCBSL0luZm8gMTQgMCBSL0lEWzw5OUU0MTVEQTMwMjc3MjQ4QUY3QjQ5NzJEMkJGOUVBQT48OTlFNDE1REEzMDI3NzI0OEFGN0I0OTcyRDJCRjlFQUE+XSA+Pg0Kc3RhcnR4cmVmDQoxNTQxNw0KJSVFT0YNCnhyZWYNCjAgMA0KdHJhaWxlcg0KPDwvU2l6ZSAzMC9Sb290IDEgMCBSL0luZm8gMTQgMCBSL0lEWzw5OUU0MTVEQTMwMjc3MjQ4QUY3QjQ5NzJEMkJGOUVBQT48OTlFNDE1REEzMDI3NzI0OEFGN0I0OTcyRDJCRjlFQUE+XSAvUHJldiAxNTQxNy9YUmVmU3RtIDE1MTEwPj4NCnN0YXJ0eHJlZg0KMTYxNzQNCiUlRU9G"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En caso de ejecutarse correctamente vamos a recibir el siguiente mensaje como respuesta&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;msg"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;File&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;uploaded&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;successfully"&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Para obtener la información de los archivos subidos debemos enviar una petición get a nuestro endpoint (&lt;code&gt;https://{APIGATEWAYID}.execute-api.us-east-1.amazonaws.com/dev/files&lt;/code&gt;) y en caso de estar todo bien recibiremos un array de objetos con la información de los archivos subidos
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="pi"&gt;[&lt;/span&gt;
    &lt;span class="pi"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filename"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;archivo.pdf"&lt;/span&gt; &lt;span class="pi"&gt;},&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contentType"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/pdf"&lt;/span&gt; &lt;span class="pi"&gt;},&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;author"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Martin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Lubo"&lt;/span&gt; &lt;span class="pi"&gt;},&lt;/span&gt;
    &lt;span class="pi"&gt;},&lt;/span&gt;
  &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Eliminar el deploy
&lt;/h2&gt;

&lt;p&gt;Por ultimo, en caso que necesitemos eliminar nuestro stack podemos hacerlo tanto desde la consola web como desde la linea de comando utilizando el siguiente comando&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;aws cloudformation delete-stack --stack-name cloudformation-files-service-api&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En ambos casos es importante que, antes de ejecutar este paso, eliminemos todo el contenido del bucket de destino para los archivos subidos para evitar errores, ya que AWS no permite eliminar un bucket que contenga archivos.&lt;/p&gt;

&lt;p&gt;En los próximos artículos estaremos deployando esta misma solución pero utilizando &lt;strong&gt;AWS Serverless Application Model (AWS SAM)&lt;/strong&gt; y &lt;strong&gt;AWS Cloud Development Kit (AWS CDK)&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>infrastructureascode</category>
      <category>cloudformation</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Deployando una aplicación en AWS usando CloudFormation (Parte 1)</title>
      <dc:creator>Martin Lubo</dc:creator>
      <pubDate>Sun, 28 Sep 2025 19:40:10 +0000</pubDate>
      <link>https://forem.com/martinlubo/deployando-una-aplicacion-en-aws-usando-cloudformation-parte-1-3pkd</link>
      <guid>https://forem.com/martinlubo/deployando-una-aplicacion-en-aws-usando-cloudformation-parte-1-3pkd</guid>
      <description>&lt;p&gt;Tal como hablamos en el &lt;a href="https://dev.to/martinlubo/infraestructura-como-codigo-iac-en-aws-56aa"&gt;articulo anterior&lt;/a&gt;, una de las formas de deployar nuestras aplicaciones en AWS es mediante el uso de CloudFormation. Para esto es necesario un template, ya sea en formato JSON o YAML, con todos los recursos que necesitamos y luego mediante el uso de la consola o la linea de comando realizar el despliegue de la infraestructura.&lt;/p&gt;

&lt;p&gt;Lo mas probable es que en este punto tu template se vea muy parecido a esto:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlfzf2bevsokf3y8sh6c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlfzf2bevsokf3y8sh6c.png" alt="Nuestro archivo template.yaml completamente en blanco" width="800" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y es que arrancar un template desde 0 es bastante complicado si no conocemos toda la estructura requerida, tanto para el template en si mismo como para cada uno de los recursos que queremos crear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entonces, ¿Como puedo escribir mi primer template?
&lt;/h2&gt;

&lt;p&gt;Existen distintas opciones que podemos elegir dependiendo de nuestro gusto personal o experiencia, pero no son caminos excluyentes sino que pueden complementarse y ser soluciones para distintos problemas. A su vez estas herramientas nos pueden ayudar a reducir la curva de aprendizaje y permitirnos generar nuestros templates con mayor agilidad.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Application Composer:
&lt;/h3&gt;

&lt;p&gt;Hace ya algún tiempo AWS nos ofrece una herramienta gráfica para poder crear nuestro template de una manera visual, seleccionando bloques que representan los servicios disponibles y dejándonos conectarlos con otros, facilitando de esta forma dar los primeros pasos de nuestro template.&lt;/p&gt;

&lt;p&gt;Para utilizar esta herramienta tenemos 2 opciones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usar el servicio online desde nuestra consola de AWS (&lt;a href="https://us-east-1.console.aws.amazon.com/cloudformation/designer/" rel="noopener noreferrer"&gt;https://us-east-1.console.aws.amazon.com/cloudformation/designer/&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Instalar la extension de &lt;a href="https://marketplace.visualstudio.com/items?itemName=AmazonWebServices.aws-toolkit-vscode" rel="noopener noreferrer"&gt;AWS Toolkit&lt;/a&gt; para Visual Studio Code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mbaegzayp2dadzhzw9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mbaegzayp2dadzhzw9w.png" alt="AWS Application Composer en VSCode" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez dentro del Application Composer debemos ir seleccionando los recursos que necesitamos arrastrándolos hasta el tablero de diseño y, de ser necesario, ir vinculándolos entre si. A su vez esta aplicación nos va a permitir editar los detalles de cada uno de los componentes según los requisitos de nuestro proyecto y los mismos se irán viendo reflejados en nuestro archivo de template, en el caso de VSCode, o bien en la solapa “template” de la aplicación online. Por otra parte, el Application Composer nos ira mostrando los errores en tiempo real sobre aquellas operaciones no permitidas en CloudFormation evitando que nos encontremos con conflictos al momento de deployar nuestra infraestructura.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxtxqo6edklrwf8obac6r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxtxqo6edklrwf8obac6r.png" alt="Application Composer online alertando un error" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  “Inspirarnos” en otros templates:
&lt;/h3&gt;

&lt;p&gt;Para poder iniciar nuestro template podemos basarnos en alguno de los multiples recursos que AWS y la comunidad ponen a disposición para este fin. Tanto en la &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/CHAP_TemplateQuickRef.html" rel="noopener noreferrer"&gt;documentación oficial&lt;/a&gt; como en este &lt;a href="https://github.com/awslabs/aws-cloudformation-templates" rel="noopener noreferrer"&gt;repositorio&lt;/a&gt; vamos a encontrar una serie de templates para desplegar algunos servicios o soluciones pre-armadas.&lt;/p&gt;

&lt;p&gt;Si bien la cantidad de templates que existen es bastante amplia, lo es también el numero de soluciones distintas que podemos crear, por lo que es muy probable que estos templates no satisfagan nuestra necesidad al 100% y debamos adaptarlos a nuestra aplicación.&lt;/p&gt;

&lt;p&gt;Hay que tener en cuenta que este camino no nos va a salvar de tener que revisar la &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html" rel="noopener noreferrer"&gt;documentación&lt;/a&gt; de CloudFormation, pero nos va a dar un excelente punto de partida para empezar a investigar, conocer la estructura del template.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generar un template en base a una infraestructura ya creada:
&lt;/h3&gt;

&lt;p&gt;En este 2024 una de las novedades por parte de AWS es una nueva herramienta llamada “IaC Generator” y como podemos deducir de su nombre nos permite generar un template de CloudFormation en base a recursos que ya tengamos creados en nuestra cuenta.&lt;/p&gt;

&lt;p&gt;El primer paso para generar un template es realizar un escaneo de los recursos de la cuenta, este proceso puede tardar desde algunos segundos hasta varios minutos dependiendo la cantidad de recursos y servicios que estemos utilizando ya que no solamente revisa los recursos en si mismos sino la relación con otros. Por ejemplo en caso de seleccionar una función lambda o un EC2 el IaC Generator nos va a mostrar los roles asociados a esos recursos para poder tenerlos también en nuestro template o bien no agregarlo en caso que consideremos que no es aplicable o necesario al template que estamos generando.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqbkc1czav28clmuidkxu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqbkc1czav28clmuidkxu.png" alt="en IaC Generator seleccionamos una función y nos muestra su rol como recurso asociado" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez seleccionados los recursos que necesitamos vamos pedirle a AWS crear nuestro template y nos va a devolver toda la estructura del mismo. Por defecto este template esta en formato YAML pero podemos optar por verlo o descargarlo en formato JSON.&lt;br&gt;
Si bien esta opción es bastante practica, es probable que el template generado requiera una revision de los parámetros y configuraciones para confirmar que podamos deployarlo, sea en la misma cuenta o en otra, sin tener conflictos de nombres de los recursos, como el nombre de un bucket, u otros recursos.&lt;/p&gt;

&lt;h3&gt;
  
  
  El Camino del Héroe:
&lt;/h3&gt;

&lt;p&gt;Al principio puede que tratemos de evitarlo, que busquemos salidas fáciles como el Application Composer o usar algún template que encontremos por ahi y se parezca a lo que necesitamos hacer, pero en el fondo sabemos que es inevitable, que en algún momento tenemos que enfrentarnos a la &lt;del&gt;adversidad&lt;/del&gt; documentación y entender como están estructurados los templates de CloudFormation.&lt;/p&gt;

&lt;p&gt;Y es que si bien las herramientas que vimos antes son excelentes no nos van a evitar al 100% que, en algunas circunstancias, debamos modificar nuestro template a mano.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estructura de un template de CloudFormation:
&lt;/h2&gt;

&lt;p&gt;Los templates de CloudFormation tienen una estructura predefinida que debemos respetar para que el archivo sea valido. Dentro de esta estructura algunas de las secciones son obligatorias y otras son opcionales, en la siguiente tabla podremos observar estos detalles y una breve descripción de la sección&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sección&lt;/th&gt;
&lt;th&gt;Obligatorio&lt;/th&gt;
&lt;th&gt;Descripción&lt;/th&gt;
&lt;th&gt;Documentación&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FormatVersion&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Version del formato de CloudFormation, si no esta definido toma por defecto la ultima disponible.&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/format-version-structure.html" rel="noopener noreferrer"&gt;LINK&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Description&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Cadena de texto que describe el template, debe estar siempre luego de la sección “AWSTemplateFormatVersion”&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-description-structure.html" rel="noopener noreferrer"&gt;LINK&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metadata&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Sección destinada a información relevante, en formato JSON o YAML, como detalles de implementación u otros elementos.&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html" rel="noopener noreferrer"&gt;LINK&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parameters&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;En esta sección podemos cargar variables para configurar nuestros recursos al momento de la creación o actualización.&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html" rel="noopener noreferrer"&gt;LINK&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rules&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Set de reglas para validar los parámetros de nuestro template antes de crear o actualizar los recursos.&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/rules-section-structure.html" rel="noopener noreferrer"&gt;LINK&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mappings&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;En mappings podemos configurar multiples objectos key-value donde value es un array de valores&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html" rel="noopener noreferrer"&gt;LINK&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conditions&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;En esta sección podemos definir condiciones especiales para resolver si un recurso debe ser creado o actualizado dependiendo de ciertos parámetros.&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html" rel="noopener noreferrer"&gt;LINK&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transform&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Macros personalizados o definidos por AWS para interpretar o procesar el template. Es usado por ejemplo por AWS Serverless Application Model.&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html" rel="noopener noreferrer"&gt;LINK&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resources&lt;/td&gt;
&lt;td&gt;SI&lt;/td&gt;
&lt;td&gt;Unica sección obligatoria. Contiene la configuración de todos los recursos que contiene el template.&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html" rel="noopener noreferrer"&gt;LINK&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Outputs&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Valores de respuesta que pueden ser utilizados en referencias cruzadas con otros stack o visualizar en la consola luego de la ejecución.&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html" rel="noopener noreferrer"&gt;LINK&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Como comentaba en el articulo anterior esta cantidad de secciones y configuraciones posibles hace que la curva de aprendizaje de CloudFormation sea bastante elevada pero no es necesario conocerlas todas para poder comenzar a trabajar en nuestro template ya que como vemos la unica sección obligatoria es la de “Resources”. El resto de las secciones las iremos usando a medida que nuestra aplicación, y por tanto nuestro template, vaya creciendo y por tanto siendo mas complejo, o bien a medida que nuestro proceso de despliegue lo vaya requiriendo.&lt;/p&gt;

&lt;p&gt;Antes de ver la segunda parte de este articulo, donde comenzaremos a crear un template de 0 para una aplicación serverless, te recomiendo revisar en la tabla anterior los links a la documentación de cada una de las secciones para ir familiarizándote con la misma y usarla de referencia en caso de dudas especificas sobre cada una.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>infrastructureascode</category>
      <category>cloudformation</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Infraestructura como código (IaC) en AWS</title>
      <dc:creator>Martin Lubo</dc:creator>
      <pubDate>Sun, 28 Sep 2025 19:35:11 +0000</pubDate>
      <link>https://forem.com/martinlubo/infraestructura-como-codigo-iac-en-aws-56aa</link>
      <guid>https://forem.com/martinlubo/infraestructura-como-codigo-iac-en-aws-56aa</guid>
      <description>&lt;p&gt;En la era actual de la computación en la nube, la infraestructura como código (IaC) se ha convertido en una práctica esencial para los equipos de desarrollo y/o DevOps. AWS, como uno de los principales proveedores de servicios en la nube, ofrece varias opciones para gestionar y desplegar infraestructura como código. En este artículo, exploraremos algunas de estas opciones y que nos permiten hacer para lograr entender cuál podría ser la mejor opción para cada proyecto.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Que es la “Infraestructura como código”?
&lt;/h2&gt;

&lt;p&gt;Infraestructura como código, que habitualmente lo veremos escrito como “IaC”, del ingles “Infrastructure as Code” es la capacidad para crear y mantener recursos usando código en lugar de procesos y configuraciones manuales.&lt;/p&gt;

&lt;p&gt;Algunos de los principios fundamentales de IaC son la automatización y el versionado del código. Mediante la automatización, se elimina la necesidad de realizar tareas manuales repetitivas que habitualmente generar errores, ya sea por olvidarnos de deployar algún recurso o bien por tener parámetros mal configurados.&lt;/p&gt;

&lt;p&gt;Por otro lado, el versionado del código permite a los equipos mantener un registro de todos los cambios realizados en la configuración de la infraestructura, facilitando el seguimiento y la resolución de problemas como así también la realización de rollbacks en caso de fallas en el despliegue.&lt;/p&gt;

&lt;p&gt;Ademas de los puntos antes mencionados, otra gran ventaja del uso de IaC es la capacidad de respuesta ante incidentes graves en nuestra infraestructura, como pueden ser la caída de determinadas zonas de disponibilidad o regiones de nuestro proveedor cloud, permitiendo tener una plan de recuperación ante desastres (DR o Disaster Recovery en ingles).&lt;/p&gt;

&lt;p&gt;Por ultimo, otro aspecto donde la infraestructura como código puede proveer mucho valor es en el control y reducción de los gastos. Por una parte podemos mediante definiciones en nuestros frameworks limitar los recursos o configuraciones que se permiten desplegar, como podrían ser determinados tipos de instancias EC2, como así también permitir la rápida eliminación de entornos en desuso como pueden ser aquellos utilizados en el proceso de desarrollo o testing.&lt;/p&gt;

&lt;p&gt;A continuación haremos un repaso por las principales herramientas disponibles para desplegar infraestructura en AWS, como son CloudFormation, SAM y CDK, y hablaremos también de uno de los principales referentes en este rubro, Terraform.&lt;/p&gt;

&lt;h2&gt;
  
  
  CloudFormation
&lt;/h2&gt;

&lt;p&gt;AWS CloudFormation es un servicio que ayuda a modelar y configurar recursos de AWS. Utiliza templates escritos en JSON o YAML para describir el conjunto de recursos y propiedades requerido.&lt;/p&gt;

&lt;p&gt;Este servicio es la base fundacional para el despliegue de recursos, en la &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html" rel="noopener noreferrer"&gt;documentation oficial&lt;/a&gt; vamos a encontrar las referencias y configuraciones para prácticamente cualquier servicio disponible en AWS y esta en constante actualización con las ultimas características y servicios.&lt;/p&gt;

&lt;p&gt;Para facilitar un poco las cosas, dentro de la consola de AWS vamos a poder contar con la herramienta &lt;a href="https://console.aws.amazon.com/cloudformation/designer" rel="noopener noreferrer"&gt;CloudFormation Designer&lt;/a&gt;, que nos permitirá de manera gráfica crear un stack con los recursos necesarios, establecer dependencias y configurar según los requisitos de nuestra aplicación. Ademas, desde esta herramienta vamos a poder exportar nuestro template en formato JSON o YAML.&lt;/p&gt;

&lt;p&gt;Si bien CloudFormation cuenta con una extensa y detallada documentación, es esta a su vez uno de sus principales desafíos, ya que la curva de aprendizaje suele ser un tanto empinada para los principiantes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"AWSTemplateFormatVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2010-09-09"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A sample template"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"MyEC2Instance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AWS::EC2::Instance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ImageId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ami-0ff8a91507f77f867"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"InstanceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"KeyName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"testkey"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"BlockDeviceMappings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"DeviceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/dev/sdm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Ebs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"VolumeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"io1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Iops"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"DeleteOnTermination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"VolumeSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2010-09-09&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;A sample template&lt;/span&gt;
&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;MyEC2Instance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::EC2::Instance"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ImageId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ami-0ff8a91507f77f867&lt;/span&gt;
      &lt;span class="na"&gt;InstanceType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;t2.micro&lt;/span&gt;
      &lt;span class="na"&gt;KeyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;testkey&lt;/span&gt;
      &lt;span class="na"&gt;BlockDeviceMappings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;DeviceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/dev/sdm&lt;/span&gt;
          &lt;span class="na"&gt;Ebs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;VolumeType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;io1&lt;/span&gt;
            &lt;span class="na"&gt;Iops&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;
            &lt;span class="na"&gt;DeleteOnTermination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
            &lt;span class="na"&gt;VolumeSize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AWS SAM
&lt;/h3&gt;

&lt;p&gt;SAM (Serverless Application Model), es un conjunto de herramientas desarrollado por Amazon para la construcción de aplicaciones serverless.&lt;/p&gt;

&lt;p&gt;SAM esta conformado por 2 partes principales&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Un framework open-source que utilizaremos para la definición de nuestro template&lt;/li&gt;
&lt;li&gt;SAM CLI: Una herramienta de linea de comando que nos permitirá inicializar, testear y deployar (entre varias otras tareas) nuestra aplicación.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Como funcionan los templates de SAM?
&lt;/h3&gt;

&lt;p&gt;Este framework esta basado en CloudFormation, con lo cual maneja la misma sintaxis y funciona como una extension del mismo. Tal como su nombre nos indica esta orientado a crear recursos serverless, como funciones Lambda, API Gateway o bases de dato DynamoDB.&lt;br&gt;
Dentro de los templates de SAM podemos usar indistintamente recursos del tipo serverless, que veremos dentro del template como *AWS::Serverless::** o recursos de CloudFormation como podría ser un *AWS::EC2::Instance.*&lt;/p&gt;

&lt;p&gt;Una particularidad de los templates de SAM es la declaración del “Transform” que se puede apreciar en la segunda linea de la siguiente imagen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2010-09-09&lt;/span&gt;
&lt;span class="na"&gt;Transform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless-2016-10-31&lt;/span&gt;
&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;getAllItemsFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Function&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;src/get-all-items.getAllItemsHandler&lt;/span&gt;
      &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs12.x&lt;/span&gt;
      &lt;span class="na"&gt;Events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HttpApi&lt;/span&gt;
          &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
            &lt;span class="na"&gt;Method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GET&lt;/span&gt;
    &lt;span class="na"&gt;Connectors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MyConn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SampleTable&lt;/span&gt;
          &lt;span class="na"&gt;Permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Read&lt;/span&gt;
  &lt;span class="na"&gt;SampleTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::SimpleTable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El "Transform" en un template de SAM es una instrucción clave que le indica a CloudFormation cómo procesar el archivo. Al especificar "AWS::Serverless-2016-10-31" como valor para "Transform", estamos indicando que el archivo debe ser procesado como un modelo de AWS Serverless Application. Esto permite transformar los recursos simplificados del tipo "AWS::Serverless::", como "AWS::Serverless::Function" para las funciones Lambda o "AWS::Serverless::Api" para API Gateway.&lt;/p&gt;

&lt;p&gt;Además, el "Transform" en SAM también permite el uso de algunas funcionalidades adicionales como las IAM policies generadas automáticamente para las funciones Lambda.&lt;/p&gt;

&lt;h3&gt;
  
  
  La magia de SAM CLI
&lt;/h3&gt;

&lt;p&gt;Si bien los templates SAM nos facilitan el armado de la infraestructura de nuestra aplicación, la verdadera magia ocurre con la herramienta de linea de comando, que nos va a permitir sacar el máximo potencial de este framework.&lt;/p&gt;

&lt;p&gt;En SAM CLI vamos a contar, entre otros, con los siguientes comandos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sam init&lt;/code&gt;: Este comando se utiliza para inicializar un nuevo proyecto SAM. Puedes crear un nuevo proyecto a partir de una plantilla de inicio rápido de AWS o de un ejemplo de la galería de aplicaciones de SAM.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam local invoke&lt;/code&gt;: Este comando permite invocar funciones Lambda localmente, lo que es útil para probar y depurar tus funciones antes de desplegarlas en AWS.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam local start-api&lt;/code&gt;: Este comando inicia una API local de Amazon API Gateway a partir de tu plantilla de SAM. Puedes usarlo para probar la interacción de tu función Lambda con API Gateway antes de desplegarlo a AWS.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam package&lt;/code&gt;: Este comando empaqueta tu aplicación y la carga en un bucket de Amazon S3.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam deploy&lt;/code&gt;: Este comando despliega tu aplicación en AWS con AWS CloudFormation. Utiliza el paquete creado por el comando &lt;code&gt;sam package&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam logs&lt;/code&gt;: Este comando te permite obtener los registros de CloudWatch Logs para las funciones Lambda desplegadas.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sam validate&lt;/code&gt;: Este comando valida que tu archivo de plantilla SAM sea válido.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como podemos ver el potencial de AWS Serverless Application Model es inmenso y nos proporciona un abanico muy interesante de herramientas que vamos a estar analizando en futuras entradas de este blog.&lt;/p&gt;

&lt;p&gt;Aunque AWS SAM ofrece una gran cantidad de ventajas, también tiene algunas desventajas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependencia de AWS&lt;/strong&gt;: AWS SAM está diseñado específicamente para AWS. Esto puede ser una limitación para las organizaciones que buscan una solución multi-cloud.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Curva de aprendizaje&lt;/strong&gt;: Para los nuevos usuarios, la sintaxis de los templates de CloudFormation que se utiliza en AWS SAM puede resultar compleja y difícil de aprender.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limitaciones de las políticas IAM generadas automáticamente&lt;/strong&gt;: AWS SAM genera políticas IAM automáticamente para las funciones Lambda, lo que puede ser conveniente, pero también puede resultar en políticas más permisivas de lo que se necesita, lo que puede ser un riesgo de seguridad.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Depuración&lt;/strong&gt;: Al igual que con otros frameworks basados en infraestructura como código, la depuración de los scripts de AWS SAM puede ser compleja y requerir un conocimiento más profundo de AWS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  AWS CDK
&lt;/h2&gt;

&lt;p&gt;El AWS Cloud Development Kit (CDK) es un framework open-source que permite a los desarrolladores modelar y aprovisionar sus recursos de AWS utilizando lenguajes de programación populares como TypeScript, Python, Java y .NET.&lt;/p&gt;

&lt;p&gt;A diferencia de SAM, donde usamos un template en formato JSON o YAML, con CDK declararemos nuestra infraestructura mediante nuestro lenguaje de preferencia, lo que facilita la curva de aprendizaje dentro del equipo y nos ahorra la necesidad de aprender la sintaxis requerida por los templates de CloudFormation o SAM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyEcsConstructStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MyVpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;maxAzs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default is all AZs in region&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Cluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MyCluster&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Create a load-balanced Fargate service and make it public&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ecs_patterns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ApplicationLoadBalancedFargateService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MyFargateService&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Required&lt;/span&gt;
        &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default is 256&lt;/span&gt;
        &lt;span class="na"&gt;desiredCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default is 1&lt;/span&gt;
        &lt;span class="na"&gt;taskImageOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ContainerImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromRegistry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amazon/amazon-ecs-sample&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;memoryLimitMiB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default is 512&lt;/span&gt;
        &lt;span class="na"&gt;publicLoadBalancer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default is false&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En CDK vamos a declarar los recursos necesarios mediante el uso de “Constructs”, los cuales son bloques de código reutilizables que encapsulan uno o más recursos de AWS, junto con la configuración requerida para usar esos recursos. Los Constructs pueden ser anidados dentro de otros Constructs para crear una jerarquía, lo cual permite crear abstracciones de alto nivel que encapsulan detalles de la implementación de la infraestructura.&lt;br&gt;
Existen 3 niveles de constructs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Constructs de nivel 1 (L1)&lt;/strong&gt;: Representan los recursos de AWS CloudFormation. Estos son los bloques de construcción básicos que representan a cada uno de los servicios de AWS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constructs de nivel 2 (L2)&lt;/strong&gt;: Son abstracciones pre-construidas que encapsulan un patrón o una pieza de infraestructura que es usada de manera habitual como como puede ser una función lambda, un bucket S3, entre otros.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constructs de nivel 3 (L3)&lt;/strong&gt;: Son los constructs creados por los desarrolladores. Estos pueden combinar varios L2 y L1 para crear abstracciones personalizadas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A su vez, estos constructs los vamos a estar organizando en “Stacks”. Los stacks son una pieza de la infraestructura de nuestra aplicación que se puede gestionar y actualizar de manera independiente. Cada aplicación de AWS CDK puede constar de uno o varios stacks. Un stack en CDK corresponde a una 'pila' en AWS CloudFormation, que es la unidad de implementación en CloudFormation.&lt;/p&gt;

&lt;p&gt;El uso de los Stacks en AWS CDK nos van a permitir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Organización y modularidad:&lt;/strong&gt; Los Stacks permiten agrupar y organizar recursos relacionados en unidades lógicas y manejables. Esto facilita la gestión de la infraestructura, especialmente en aplicaciones grandes y complejas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Despliegue independiente:&lt;/strong&gt; Cada Stack puede desplegarse de manera independiente, lo que permite actualizar partes específicas de la infraestructura sin afectar a otras.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reutilización de código:&lt;/strong&gt; Los Stacks pueden definirse una vez y luego reutilizarse en varias aplicaciones o entornos, lo que permite un desarrollo más rápido y consistente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gestión de dependencias:&lt;/strong&gt; AWS CDK maneja automáticamente las dependencias entre los recursos dentro de un Stack, lo que simplifica la creación y actualización de infraestructuras complejas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si bien el poder utilizar un lenguaje de programación ya conocido por nuestro equipo facilita la curva de aprendizaje, esto puede ser un punto en contra para aquellos perfiles mas cercanos a las areas de infraestructura, ya que en lugar de utilizar un template con una sintaxis agnóstica deberán estar familiarizados con el lenguaje que estemos utilizando en nuestra aplicación de CDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform
&lt;/h2&gt;

&lt;p&gt;Terraform, desarrollado por HashiCorp, es una herramienta que permite a los usuarios definir y proporcionar infraestructura utilizando un lenguaje de configuración declarativo. Esto significa que los usuarios describen el estado deseado de la infraestructura y Terraform se encarga de crear, modificar o eliminar recursos para alcanzar ese estado.&lt;/p&gt;

&lt;p&gt;A diferencia de CloudFormation, Terraform es agnóstico a la plataforma, lo que significa que no está atado a AWS y puede ser utilizado con otros proveedores de servicios en la nube. Esta característica puede ser especialmente útil para organizaciones que utilizan una estrategia multi-cloud.&lt;/p&gt;

&lt;p&gt;Aunque su sintaxis es más simple que CloudFormation, Terraform no está tan profundamente integrado con AWS, lo que puede llevar a algunas complicaciones. Por ejemplo, puede que no soporte las últimas características y servicios de AWS tan rápido como CloudFormation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entonces, ¿Que me conviene que usar?
&lt;/h2&gt;

&lt;p&gt;Puede que esta no sea la respuesta que estabas buscando pero, depende… Cada una de las herramientas tienen sus pro y contras y es importante conocerlas y probarlas para definir cual tiene mejor fit con los requisitos de nuestro proyecto o equipo de trabajo.&lt;/p&gt;

&lt;p&gt;Para eso, en los siguientes capítulos de este blog, vamos a estar revisando en profundidad estas herramientas, creando una aplicación serverless simple y con una misma arquitectura que nos permita comparar los procesos de cada uno y poder elegir si queremos crear nuestra aplicación con CloudFormation, SAM o CDK.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>infrastructureascode</category>
      <category>cloudformation</category>
      <category>spanish</category>
    </item>
  </channel>
</rss>
