<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://rsalgadoc.github.io//blog/feed.xml" rel="self" type="application/atom+xml" /><link href="https://rsalgadoc.github.io//blog/" rel="alternate" type="text/html" /><updated>2026-05-07T03:52:42+00:00</updated><id>https://rsalgadoc.github.io//blog/feed.xml</id><title type="html">Desafiando la Nube: 365 Días de AWS</title><subtitle>A flexible Jekyll theme for your blog or site with a minimalist aesthetic.</subtitle><author><name>Rodrigo Salgado</name></author><entry><title type="html">Día 29: TTL y Backups: Limpieza automática y protección de datos</title><link href="https://rsalgadoc.github.io//blog/dynamodb-ttl-backups/" rel="alternate" type="text/html" title="Día 29: TTL y Backups: Limpieza automática y protección de datos" /><published>2026-05-07T00:00:00+00:00</published><updated>2026-05-07T00:00:00+00:00</updated><id>https://rsalgadoc.github.io//blog/dynamodb-ttl-backups</id><content type="html" xml:base="https://rsalgadoc.github.io//blog/dynamodb-ttl-backups/"><![CDATA[<h1 id="-día-29-datos-que-se-autodestruyen-y-copias-de-seguridad">⏳ Día 29: Datos que se autodestruyen y copias de seguridad</h1>
<p>¡Llegamos al final de nuestra serie de DynamoDB! Ya sabemos crear tablas rápidas y reactivas, pero un buen arquitecto también sabe cuándo deshacerse de los datos que ya no sirven y cómo protegerse ante un desastre. Hoy aprenderás el <strong>TTL (Time to Live)</strong> para ahorrar espacio y los métodos de <strong>Backup</strong> para dormir tranquilo.</p>

<h3 id="1-ttl-time-to-live-la-papelera-automática">1. TTL (Time to Live): La papelera automática</h3>
<p>¿Para qué pagar por guardar logs de hace 3 años o sesiones de usuario que ya expiraron?</p>
<ul>
  <li><strong>Ahorro total</strong>: AWS borra los items expirados automáticamente y <strong>no te cobra</strong> por esas escrituras de borrado.</li>
  <li><strong>Cómo funciona</strong>: Eliges un atributo que contenga una fecha en formato <em>Unix Timestamp</em>. Cuando llega esa hora, DynamoDB marca el item para eliminarlo.</li>
</ul>

<h3 id="2-backups-y-point-in-time-recovery-pitr">2. Backups y Point-in-Time Recovery (PITR)</h3>
<ul>
  <li><strong>On-Demand Backups</strong>: Fotos completas de tu tabla que puedes guardar por años.</li>
  <li><strong>PITR (Point-in-Time Recovery)</strong>: Es como una máquina del tiempo. Si lo activas, puedes restaurar tu tabla a <strong>cualquier segundo exacto</strong> de los últimos 35 días. Ideal si un script mal programado borra media base de datos por error.</li>
</ul>

<h3 id="️-el-código-cloudformation">🛠️ El Código (CloudFormation)</h3>
<p>Vamos a crear una tabla de “Sesiones” que tenga el PITR activado para seguridad y el TTL configurado para limpiar sesiones viejas.</p>

<h4 id="1-tabla-con-auto-limpieza-y-protección">1. Tabla con Auto-limpieza y Protección</h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">TablaSesionesSegura</span><span class="pi">:</span>
  <span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::DynamoDB::Table</span>
  <span class="na">Properties</span><span class="pi">:</span>
    <span class="na">TableName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">SesionesApp"</span>
    <span class="na">AttributeDefinitions</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">SessionId"</span>
        <span class="na">AttributeType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">S"</span>
    <span class="na">KeySchema</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">SessionId"</span>
        <span class="na">KeyType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">HASH"</span>
    <span class="na">BillingMode</span><span class="pi">:</span> <span class="s">PAY_PER_REQUEST</span>
    <span class="c1"># 1. ACTIVAR EL TTL (Auto-borrado)</span>
    <span class="na">TimeToLiveSpecification</span><span class="pi">:</span>
      <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ExpiraEn"</span> <span class="c1"># Nombre del campo con la fecha</span>
      <span class="na">Enabled</span><span class="pi">:</span> <span class="no">true</span>
    <span class="c1"># 2. ACTIVAR LA MÁQUINA DEL TIEMPO (PITR)</span>
    <span class="na">PointInTimeRecoverySpecification</span><span class="pi">:</span>
      <span class="na">PointInTimeRecoveryEnabled</span><span class="pi">:</span> <span class="no">true</span>
</code></pre></div></div>

<h3 id="-conceptos-nuevos-explicados">📚 Conceptos Nuevos Explicados</h3>

<h4 id="1-unix-timestamp">1. Unix Timestamp</h4>
<p>Para que el TTL funcione, la fecha debe estar en segundos desde el 1 de enero de 1970 (ej: <code class="language-plaintext highlighter-rouge">1714834800</code>). Si lo pones en formato normal (YYYY-MM-DD), DynamoDB lo ignorará.</p>

<h4 id="2-borrado-asíncrono">2. Borrado Asíncrono</h4>
<p>El TTL no borra el archivo exactamente al segundo que expira. Suele tardar entre unos minutos y 48 horas en desaparecer físicamente, pero para tu aplicación es como si ya no existiera.</p>

<h4 id="3-restauración-de-tablas">3. Restauración de Tablas</h4>
<p>Cuando restauras un Backup o usas PITR, AWS crea una <strong>tabla nueva</strong>. No sobreescribe la actual. Esto te permite comparar datos antes de decidir cuál conservar.</p>

<h3 id="-cómo-desplegarlo">🚀 Cómo Desplegarlo</h3>

<p>Protege tus datos y automatiza su limpieza con un solo comando:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>aws cloudformation deploy <span class="se">\</span>
  <span class="nt">--stack-name</span> Dynamo-Final-D29 <span class="se">\</span>
  <span class="nt">--template-file</span> 29-dynamo-final.yaml
</code></pre></div></div>

<h3 id="-cómo-probar-el-ttl">📈 Cómo probar el TTL</h3>

<ol>
  <li>Ve a la consola de <strong>DynamoDB</strong> → Tabla <code class="language-plaintext highlighter-rouge">SesionesApp</code>.</li>
  <li>En la pestaña <strong>Additional settings</strong>, verifica que el TTL está “Enabled” apuntando al campo <code class="language-plaintext highlighter-rouge">ExpiraEn</code>.</li>
  <li>Crea un Item y en el campo <code class="language-plaintext highlighter-rouge">ExpiraEn</code> pon un número de hace 5 minutos (puedes buscar “Unix Timestamp converter” en Google).</li>
  <li>En un rato (puede tardar), verás que el registro desaparece solo. ¡Magia serverless!</li>
</ol>

<h3 id="-código-adjunto">📂 Código Adjunto</h3>

<p>Puedes bajar el template final con seguridad y TTL aquí: 
<a href="/blog/code-samples/2026/04/29-dynamo-final.yaml">Ver archivo en GitHub</a></p>

<hr />

<h3 id="-video-tutorial">🎥 Video Tutorial</h3>

<p>En el video de hoy te enseño cómo recuperar una tabla que fue borrada “accidentalmente” en menos de 5 minutos usando PITR:</p>

<!-- Courtesy of embedresponsively.com -->

<div class="responsive-video-container">
    <iframe src="https://www.youtube-nocookie.com/embed/VIDEO_ID_DYNAMO_BACKUP1" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
  </div>

<hr />

<h3 id="-qué-sigue">💡 ¿Qué sigue?</h3>
<p>Hemos terminado con las bases de datos NoSQL. Ahora que tenemos dónde guardar archivos (S3) y dónde guardar datos (DynamoDB), es momento de aprender a enviar mensajes entre ellos. ¡Próximo módulo: <strong>Amazon SNS y SQS</strong> para desacoplar nuestra arquitectura!</p>]]></content><author><name>Rodrigo Salgado</name></author><category term="DynamoDB" /><category term="Seguridad" /><category term="Backup" /><category term="FinOps" /><summary type="html"><![CDATA[⏳ Día 29: Datos que se autodestruyen y copias de seguridad ¡Llegamos al final de nuestra serie de DynamoDB! Ya sabemos crear tablas rápidas y reactivas, pero un buen arquitecto también sabe cuándo deshacerse de los datos que ya no sirven y cómo protegerse ante un desastre. Hoy aprenderás el TTL (Time to Live) para ahorrar espacio y los métodos de Backup para dormir tranquilo.]]></summary></entry><entry><title type="html">Día 28: DynamoDB Streams: Reacciona a los cambios en tiempo real</title><link href="https://rsalgadoc.github.io//blog/dynamodb-stream/" rel="alternate" type="text/html" title="Día 28: DynamoDB Streams: Reacciona a los cambios en tiempo real" /><published>2026-05-06T00:00:00+00:00</published><updated>2026-05-06T00:00:00+00:00</updated><id>https://rsalgadoc.github.io//blog/dynamodb-stream</id><content type="html" xml:base="https://rsalgadoc.github.io//blog/dynamodb-stream/"><![CDATA[<h1 id="-día-28-tus-datos-tienen-vida-dispara-acciones-con-streams">🌊 Día 28: ¡Tus datos tienen vida! Dispara acciones con Streams</h1>
<p>¿Qué pasaría si pudieras enviar un correo de bienvenida automáticamente cuando un usuario se registra? ¿O actualizar un contador en otra tabla cuando se realiza una venta? En lugar de que tu aplicación tenga que hacer estas dos tareas a la vez, puedes usar <strong>DynamoDB Streams</strong>. Este servicio captura cada cambio en tu tabla y permite que otras herramientas (como AWS Lambda) reaccionen al instante.</p>

<h3 id="qué-es-un-dynamodb-stream">¿Qué es un DynamoDB Stream?</h3>

<ul>
  <li><strong>Registro de cambios</strong>: Es un historial ordenado de lo que ha pasado en tu tabla (inserciones, modificaciones y borrados).</li>
  <li><strong>Tiempo real</strong>: Las acciones ocurren milisegundos después de que el dato cambió.</li>
  <li><strong>Arquitectura desacoplada</strong>: Tu base de datos no tiene que saber qué hace la Lambda; ella solo emite el evento y quien quiera escucharlo, que actúe.</li>
</ul>

<h3 id="️-el-código-cloudformation">🛠️ El Código (CloudFormation)</h3>
<p>Vamos a crear una tabla que tenga el <strong>Stream activado</strong>. Para que funcione, debemos indicarle a DynamoDB qué tipo de información queremos que envíe cuando algo cambie.</p>

<h4 id="1-tabla-con-stream-habilitado">1. Tabla con Stream Habilitado</h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">TablaConEventos</span><span class="pi">:</span>
  <span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::DynamoDB::Table</span>
  <span class="na">Properties</span><span class="pi">:</span>
    <span class="na">TableName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">RegistroActividad"</span>
    <span class="na">AttributeDefinitions</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Id"</span>
        <span class="na">AttributeType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">S"</span>
    <span class="na">KeySchema</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Id"</span>
        <span class="na">KeyType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">HASH"</span>
    <span class="na">BillingMode</span><span class="pi">:</span> <span class="s">PAY_PER_REQUEST</span>
    <span class="c1"># ACTIVACIÓN DEL STREAM</span>
    <span class="na">StreamSpecification</span><span class="pi">:</span>
      <span class="na">StreamViewType</span><span class="pi">:</span> <span class="s">NEW_AND_OLD_IMAGES</span> <span class="c1"># Envía el dato antes y después del cambio</span>
</code></pre></div></div>

<h3 id="-conceptos-nuevos-explicados">📚 Conceptos Nuevos Explicados</h3>

<h4 id="1-streamviewtype">1. StreamViewType</h4>
<p>Define qué información se incluirá en el evento del Stream:</p>
<ul>
  <li><strong>KEYS_ONLY</strong>: Solo las llaves del elemento modificado.</li>
  <li><strong>NEW_IMAGE</strong>: El elemento completo tal como quedó después del cambio.</li>
  <li><strong>OLD_IMAGE</strong>: El elemento tal como estaba antes del cambio.</li>
  <li><strong>NEW_AND_OLD_IMAGES</strong>: Ambos (ideal para comparar qué cambió exactamente).</li>
</ul>

<h4 id="2-disparador-trigger">2. Disparador (Trigger)</h4>
<p>Es la conexión entre el Stream y una función <strong>AWS Lambda</strong>. Cuando llega un nuevo registro al Stream, AWS invoca a tu Lambda pasando los datos del cambio como un evento JSON.</p>

<h4 id="3-retención-de-datos">3. Retención de datos</h4>
<p>Los eventos en el Stream solo viven por <strong>24 horas</strong>. Si tu función Lambda falla o no los procesa a tiempo, esos eventos desaparecerán.</p>

<h3 id="-cómo-desplegarlo">🚀 Cómo Desplegarlo</h3>

<p>Activa el flujo de eventos en tu infraestructura:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>aws cloudformation deploy <span class="se">\</span>
  <span class="nt">--stack-name</span> Dynamo-Streams-D28 <span class="se">\</span>
  <span class="nt">--template-file</span> 28-dynamo-streams.yaml
</code></pre></div></div>

<h3 id="-cómo-probar-la-reacción-de-tus-datos">📈 Cómo probar la “reacción” de tus datos</h3>

<ol>
  <li>Ve a la consola de <strong>DynamoDB</strong> → <strong>Explore items</strong> → Tabla <code class="language-plaintext highlighter-rouge">RegistroActividad</code>.</li>
  <li>Ve a la pestaña <strong>Exports and streams</strong>.</li>
  <li>Verás que el Stream está “Enabled”. Allí mismo podrías hacer clic en <strong>Create trigger</strong> para conectarlo a una Lambda existente.</li>
  <li>Si creas un Item nuevo, DynamoDB generará un evento invisible que viajará por el Stream. En una arquitectura real, tu Lambda recibiría un JSON parecido a este:
    <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"eventName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"INSERT"</span><span class="err">,</span><span class="w">
</span><span class="nl">"dynamodb"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"NewImage"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"Id"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="nl">"S"</span><span class="p">:</span><span class="w"> </span><span class="s2">"123"</span><span class="p">},</span><span class="w"> </span><span class="nl">"Status"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="nl">"S"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Activo"</span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div>    </div>
  </li>
</ol>

<h3 id="-código-adjunto">📂 Código Adjunto</h3>

<p>Puedes bajar el template con la especificación del Stream aquí: 
<a href="/blog/code-samples/2026/04/28-dynamo-streams.yaml">Ver archivo en GitHub</a></p>

<hr />

<h3 id="-video-tutorial">🎥 Video Tutorial</h3>

<p>En el video de hoy construimos una automatización completa: insertamos un dato en DynamoDB y vemos cómo llega un email automáticamente usando Lambda y SES:</p>

<!-- Courtesy of embedresponsively.com -->

<div class="responsive-video-container">
    <iframe src="https://www.youtube-nocookie.com/embed/VIDEO_ID_DYNAMO_STREAMS" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
  </div>

<hr />

<h3 id="-próximos-pasos">💡 Próximos pasos</h3>
<ul>
  <li><strong>Día 29: TTL (Time to Live) y copias de seguridad</strong>: Aprenderemos a hacer que los datos se borren solos cuando ya no los necesitemos y cómo proteger nuestra tabla contra desastres.</li>
</ul>]]></content><author><name>Rodrigo Salgado</name></author><category term="DynamoDB" /><category term="Lambda" /><category term="EventDriven" /><category term="Serverless" /><summary type="html"><![CDATA[🌊 Día 28: ¡Tus datos tienen vida! Dispara acciones con Streams ¿Qué pasaría si pudieras enviar un correo de bienvenida automáticamente cuando un usuario se registra? ¿O actualizar un contador en otra tabla cuando se realiza una venta? En lugar de que tu aplicación tenga que hacer estas dos tareas a la vez, puedes usar DynamoDB Streams. Este servicio captura cada cambio en tu tabla y permite que otras herramientas (como AWS Lambda) reaccionen al instante.]]></summary></entry><entry><title type="html">Día 27: Índices en DynamoDB: GSI vs LSI</title><link href="https://rsalgadoc.github.io//blog/dynamodb-gsi-lsi/" rel="alternate" type="text/html" title="Día 27: Índices en DynamoDB: GSI vs LSI" /><published>2026-05-05T00:00:00+00:00</published><updated>2026-05-05T00:00:00+00:00</updated><id>https://rsalgadoc.github.io//blog/dynamodb-gsi-lsi</id><content type="html" xml:base="https://rsalgadoc.github.io//blog/dynamodb-gsi-lsi/"><![CDATA[<h1 id="-día-27-cómo-buscar-datos-sin-usar-la-llave-principal">🔍 Día 27: ¿Cómo buscar datos sin usar la Llave Principal?</h1>
<p>Hasta ahora, hemos aprendido que para ser rápidos en DynamoDB debemos buscar por la <strong>Partition Key</strong>. Pero, ¿qué pasa si en nuestra tabla de usuarios queremos buscar por <code class="language-plaintext highlighter-rouge">Email</code> en lugar de <code class="language-plaintext highlighter-rouge">UserId</code>? Si hiciéramos un <em>Scan</em>, sería lento y costoso. Para solucionar esto existen los <strong>Índices</strong>, que son como “copias” de nuestra tabla organizadas de otra forma.</p>

<h3 id="1-gsi-global-secondary-index---el-más-flexible">1. GSI (Global Secondary Index) - El más flexible</h3>
<p>Es el tipo de índice más potente y el que usarás el 90% del tiempo.</p>
<ul>
  <li><strong>Flexibilidad</strong>: Puedes elegir cualquier atributo como nueva Partition Key y Sort Key.</li>
  <li><strong>Escalabilidad</strong>: Tiene su propia capacidad (RCU/WCU) independiente de la tabla principal.</li>
  <li><strong>Alcance</strong>: Se puede consultar a través de toda la tabla, sin importar la partición original.</li>
</ul>

<h3 id="2-lsi-local-secondary-index---el-hermano-estricto">2. LSI (Local Secondary Index) - El hermano estricto</h3>
<p>Es mucho más limitado y solo se puede crear al momento de crear la tabla.</p>
<ul>
  <li><strong>Restricción</strong>: Debe compartir la <strong>misma Partition Key</strong> que la tabla original, pero usa una Sort Key distinta.</li>
  <li><strong>Consistencia</strong>: Permite lecturas “Fuertemente Consistentes” (cosa que el GSI no puede).</li>
</ul>

<h3 id="️-el-código-cloudformation">🛠️ El Código (CloudFormation)</h3>
<p>Vamos a crear una tabla de usuarios donde la Partition Key es <code class="language-plaintext highlighter-rouge">UserId</code>, pero añadiremos un <strong>GSI</strong> para poder buscar instantáneamente por <code class="language-plaintext highlighter-rouge">Email</code>.</p>

<h4 id="1-tabla-con-índice-secundario-global-gsi">1. Tabla con Índice Secundario Global (GSI)</h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">TablaUsuariosConGSI</span><span class="pi">:</span>
  <span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::DynamoDB::Table</span>
  <span class="na">Properties</span><span class="pi">:</span>
    <span class="na">TableName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">UsuariosSeguridad"</span>
    <span class="na">AttributeDefinitions</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">UserId"</span>
        <span class="na">AttributeType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">S"</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Email"</span>
        <span class="na">AttributeType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">S"</span>
    <span class="na">KeySchema</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">UserId"</span>
        <span class="na">KeyType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">HASH"</span>
    <span class="na">BillingMode</span><span class="pi">:</span> <span class="s">PAY_PER_REQUEST</span>
    <span class="c1"># Definición del Índice</span>
    <span class="na">GlobalSecondaryIndexes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">IndexName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">EmailIndex"</span>
        <span class="na">KeySchema</span><span class="pi">:</span>
          <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Email"</span>
            <span class="na">KeyType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">HASH"</span>
        <span class="na">Projection</span><span class="pi">:</span>
          <span class="na">ProjectionType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ALL"</span> <span class="c1"># Copia todos los atributos al índice</span>
</code></pre></div></div>

<h3 id="-conceptos-nuevos-explicados">📚 Conceptos Nuevos Explicados</h3>

<h4 id="1-proyección-projection">1. Proyección (Projection)</h4>
<p>Cuando creas un índice, debes decidir qué datos se “copian” de la tabla original al índice:</p>
<ul>
  <li><strong>KEYS_ONLY</strong>: Solo las llaves (ahorra espacio).</li>
  <li><strong>INCLUDE</strong>: Solo los atributos que tú elijas.</li>
  <li><strong>ALL</strong>: Todos los atributos (más fácil de usar, pero más caro en almacenamiento).</li>
</ul>

<h4 id="2-replicación-asíncrona">2. Replicación Asíncrona</h4>
<p>Cuando escribes en la tabla principal, DynamoDB copia el dato al <strong>GSI</strong> de forma automática en milisegundos. Esta copia es <strong>asíncrona</strong>, por lo que los GSI solo soportan consistencia eventual.</p>

<h4 id="3-diferencia-crítica-creación">3. Diferencia Crítica: Creación</h4>
<ul>
  <li><strong>GSI</strong>: Puedes crearlo, modificarlo o borrarlo en cualquier momento, incluso si la tabla ya tiene datos.</li>
  <li><strong>LSI</strong>: <strong>Solo</strong> se puede crear cuando creas la tabla por primera vez. Si lo olvidas, tendrías que borrar y recrear la tabla.</li>
</ul>

<h3 id="-cómo-desplegarlo">🚀 Cómo Desplegarlo</h3>

<p>Despliega tu tabla con capacidad de búsqueda avanzada:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>aws cloudformation deploy <span class="se">\</span>
  <span class="nt">--stack-name</span> Dynamo-Indices-D27 <span class="se">\</span>
  <span class="nt">--template-file</span> 27-dynamo-indices.yaml
</code></pre></div></div>

<h3 id="-cómo-probar-tus-índices">📈 Cómo probar tus índices</h3>

<ol>
  <li>Ve a la consola de <strong>DynamoDB</strong> → <strong>Explore items</strong> → Tabla <code class="language-plaintext highlighter-rouge">UsuariosSeguridad</code>.</li>
  <li>Crea un item con un <code class="language-plaintext highlighter-rouge">UserId</code> y un <code class="language-plaintext highlighter-rouge">Email</code>.</li>
  <li>Ve a la pestaña <strong>Query</strong>.</li>
  <li>En el menú desplegable de “Source”, cambia de [Table] a <strong>[Index: EmailIndex]</strong>.</li>
  <li>Ahora puedes buscar directamente por el correo electrónico. ¡Es igual de rápido que buscar por el ID!</li>
</ol>

<h3 id="-código-adjunto">📂 Código Adjunto</h3>

<p>Puedes bajar el template con la configuración del GSI aquí: 
<a href="/blog/code-samples/2026/04/27-dynamo-indices.yaml">Ver archivo en GitHub</a></p>

<hr />

<h3 id="-video-tutorial">🎥 Video Tutorial</h3>

<p>En el video de hoy te explico cuándo vale la pena pagar por un GSI y cómo evitar el error común de crear demasiados índices:</p>

<!-- Courtesy of embedresponsively.com -->

<div class="responsive-video-container">
    <iframe src="https://www.youtube-nocookie.com/embed/VIDEO_ID_DYNAMO_INDEXES" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
  </div>

<hr />

<h3 id="-próximos-pasos">💡 Próximos pasos</h3>
<ul>
  <li><strong>Día 28: DynamoDB Streams</strong>: ¿Quieres que algo pase automáticamente cuando un dato cambia? Aprenderemos a disparar funciones Lambda al detectar inserciones o borrados.</li>
</ul>]]></content><author><name>Rodrigo Salgado</name></author><category term="DynamoDB" /><category term="NoSQL" /><category term="DatabaseDesign" /><category term="Performance" /><summary type="html"><![CDATA[🔍 Día 27: ¿Cómo buscar datos sin usar la Llave Principal? Hasta ahora, hemos aprendido que para ser rápidos en DynamoDB debemos buscar por la Partition Key. Pero, ¿qué pasa si en nuestra tabla de usuarios queremos buscar por Email en lugar de UserId? Si hiciéramos un Scan, sería lento y costoso. Para solucionar esto existen los Índices, que son como “copias” de nuestra tabla organizadas de otra forma.]]></summary></entry><entry><title type="html">Día 26: El motor de DynamoDB: Consistencia y Capacidad (RCU/WCU)</title><link href="https://rsalgadoc.github.io//blog/dynamodb-rcu-wcu/" rel="alternate" type="text/html" title="Día 26: El motor de DynamoDB: Consistencia y Capacidad (RCU/WCU)" /><published>2026-05-04T00:00:00+00:00</published><updated>2026-05-04T00:00:00+00:00</updated><id>https://rsalgadoc.github.io//blog/dynamodb-rcu-wcu</id><content type="html" xml:base="https://rsalgadoc.github.io//blog/dynamodb-rcu-wcu/"><![CDATA[<h1 id="️-día-26-cuánta-potencia-necesita-tu-base-de-datos">⏱️ Día 26: ¿Cuánta potencia necesita tu base de datos?</h1>
<p>En las bases de datos tradicionales, hablamos de RAM y CPU. En DynamoDB, hablamos de <strong>Capacidad de Lectura y Escritura</strong>. Hoy aprenderás a medir el “esfuerzo” que hace tu tabla para procesar datos y cómo elegir entre pagar por uso o reservar potencia para ahorrar dinero.</p>

<h3 id="1-las-unidades-de-medida-rcu-y-wcu">1. Las unidades de medida: RCU y WCU</h3>
<p>AWS mide el rendimiento de tu tabla con estas dos unidades:</p>

<ul>
  <li><strong>WCU (Write Capacity Unit)</strong>: 1 WCU permite escribir 1 KB por segundo.</li>
  <li><strong>RCU (Read Capacity Unit)</strong>: 1 RCU permite leer 4 KB por segundo (en lectura eventualmente consistente).</li>
</ul>

<h3 id="2-lectura-fuerte-o-eventual">2. ¿Lectura Fuerte o Eventual?</h3>
<p>Aquí es donde muchos se confunden. Cuando lees datos en DynamoDB, tienes dos opciones:</p>
<ul>
  <li><strong>Eventualmente Consistente (Por defecto)</strong>: Es más rápida y barata. Puede que leas un dato un milisegundo antes de que se actualice en todas las copias de AWS. (Gasta 0.5 RCU por 4KB).</li>
  <li><strong>Fuertemente Consistente</strong>: Te asegura que leerás el dato más reciente, pero cuesta el doble. (Gasta 1 RCU por 4KB).</li>
</ul>

<h3 id="️-el-código-cloudformation">🛠️ El Código (CloudFormation)</h3>
<p>Hasta ahora hemos usado <code class="language-plaintext highlighter-rouge">PAY_PER_REQUEST</code>. Hoy veremos cómo configurar una tabla con <strong>Capacidad Provisionada</strong>, ideal cuando ya sabes cuánto tráfico tendrá tu app y quieres predecir tus costos.</p>

<h4 id="1-tabla-con-capacidad-definida">1. Tabla con Capacidad Definida</h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">TablaConCapacidad</span><span class="pi">:</span>
  <span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::DynamoDB::Table</span>
  <span class="na">Properties</span><span class="pi">:</span>
    <span class="na">TableName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">InventarioGlobal"</span>
    <span class="na">AttributeDefinitions</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ItemId"</span>
        <span class="na">AttributeType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">S"</span>
    <span class="na">KeySchema</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ItemId"</span>
        <span class="na">KeyType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">HASH"</span>
    <span class="c1"># Configuramos la potencia reservada</span>
    <span class="na">BillingMode</span><span class="pi">:</span> <span class="s">PROVISIONED</span>
    <span class="na">ProvisionedThroughput</span><span class="pi">:</span>
      <span class="na">ReadCapacityUnits</span><span class="pi">:</span> <span class="m">5</span>  <span class="c1"># Capacidad de lectura</span>
      <span class="na">WriteCapacityUnits</span><span class="pi">:</span> <span class="m">5</span> <span class="c1"># Capacidad de escritura</span>
</code></pre></div></div>

<h3 id="-conceptos-nuevos-explicados">📚 Conceptos Nuevos Explicados</h3>

<h4 id="1-provisioned-mode-vs-on-demand">1. Provisioned Mode vs. On-Demand</h4>
<ul>
  <li><strong>On-Demand (Pay-per-request)</strong>: Pagas por cada lectura/escritura real. Ideal para tráfico impredecible o apps que están empezando.</li>
  <li><strong>Provisioned</strong>: Tú dices “quiero 5 RCU y 5 WCU”. AWS te cobra un monto fijo por hora. Es más barato si tienes un tráfico constante y alto.</li>
</ul>

<h4 id="2-throttling-estrangulamiento">2. Throttling (Estrangulamiento)</h4>
<p>Si configuraste 5 WCU pero intentas escribir 10 KB por segundo, AWS lanzará un error de <code class="language-plaintext highlighter-rouge">ProvisionedThroughputExceededException</code>. Tu aplicación “chocará” contra el muro que tú mismo definiste para ahorrar.</p>

<h4 id="3-consistencia-eventual">3. Consistencia Eventual</h4>
<p>Recuerda que DynamoDB guarda tus datos en 3 lugares distintos. La consistencia eventual lee de la copia más cercana, aunque la actualización de las otras dos esté en proceso (tarda milisegundos).</p>

<h3 id="-cómo-desplegarlo">🚀 Cómo Desplegarlo</h3>

<p>Crea la tabla con capacidad controlada:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>aws cloudformation deploy <span class="se">\</span>
  <span class="nt">--stack-name</span> Dynamo-Capacidad-D26 <span class="se">\</span>
  <span class="nt">--template-file</span> 26-dynamo-capacidad.yaml
</code></pre></div></div>

<h3 id="-cómo-probar-la-consistencia">📈 Cómo probar la consistencia</h3>

<ol>
  <li>Cuando uses el SDK (Python/Node.js) para leer un dato, busca el parámetro <code class="language-plaintext highlighter-rouge">ConsistentRead</code>.</li>
  <li>Si lo pones en <code class="language-plaintext highlighter-rouge">True</code>, estarás forzando una <strong>Lectura Fuerte</strong> (más lenta y cara).</li>
  <li>Si lo dejas en <code class="language-plaintext highlighter-rouge">False</code>, estarás usando <strong>Consistencia Eventual</strong> (más eficiente).</li>
</ol>

<h3 id="-código-adjunto">📂 Código Adjunto</h3>

<p>Puedes bajar el template con capacidad provisionada aquí: 
<a href="/blog/code-samples/2026/04/26-dynamo-performance.yaml">Ver archivo en GitHub</a></p>

<hr />

<h3 id="-video-tutorial">🎥 Video Tutorial</h3>

<p>En el video de hoy te enseño a usar la calculadora de AWS para saber cuántos RCU y WCU necesitas realmente para tu aplicación:</p>

<!-- Courtesy of embedresponsively.com -->

<div class="responsive-video-container">
    <iframe src="https://www.youtube-nocookie.com/embed/VIDEO_ID_DYNAMO_CAPACITY" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
  </div>

<hr />

<h3 id="-próximos-pasos">💡 Próximos pasos</h3>
<ul>
  <li><strong>Día 27: Índices: GSI (Global) vs LSI (Local)</strong>: ¿Qué pasa si necesitas buscar por algo que no es tu Partition Key? Aprenderemos a crear “vistas” de nuestros datos.</li>
</ul>]]></content><author><name>Rodrigo Salgado</name></author><category term="DynamoDB" /><category term="Performance" /><category term="CostOptimization" /><category term="Architecture" /><summary type="html"><![CDATA[⏱️ Día 26: ¿Cuánta potencia necesita tu base de datos? En las bases de datos tradicionales, hablamos de RAM y CPU. En DynamoDB, hablamos de Capacidad de Lectura y Escritura. Hoy aprenderás a medir el “esfuerzo” que hace tu tabla para procesar datos y cómo elegir entre pagar por uso o reservar potencia para ahorrar dinero.]]></summary></entry><entry><title type="html">Día 25: El secreto del éxito: Partition Key y Sort Key</title><link href="https://rsalgadoc.github.io//blog/dynamodb-partition-sort-key/" rel="alternate" type="text/html" title="Día 25: El secreto del éxito: Partition Key y Sort Key" /><published>2026-05-03T00:00:00+00:00</published><updated>2026-05-03T00:00:00+00:00</updated><id>https://rsalgadoc.github.io//blog/dynamodb-partition-sort-key</id><content type="html" xml:base="https://rsalgadoc.github.io//blog/dynamodb-partition-sort-key/"><![CDATA[<h1 id="-día-25-las-llaves-que-abren-la-velocidad-de-milisegundos">🔑 Día 25: Las llaves que abren la velocidad de milisegundos</h1>
<p>Si intentas usar DynamoDB como si fuera SQL, vas a sufrir. En SQL puedes buscar por cualquier columna, pero en DynamoDB, la forma en que recuperas tus datos depende casi totalmente de cómo diseñes tu <strong>Primary Key</strong>. Hoy entenderás la diferencia entre una llave simple y una compuesta.</p>

<h3 id="1-partition-key-pk---la-brújula-de-aws">1. Partition Key (PK) - La brújula de AWS</h3>
<p>También conocida como <strong>Hash Key</strong>. Es obligatoria. AWS pasa este valor por un algoritmo (hash) para decidir en qué servidor físico guardará tus datos.</p>
<ul>
  <li><strong>Regla de oro</strong>: Debe estar bien distribuida. Si todos tus usuarios tienen la misma PK, crearás un “Hot Partition” y tu base de datos se volverá lenta.</li>
</ul>

<h3 id="2-sort-key-sk---el-orden-del-caos">2. Sort Key (SK) - El orden del caos</h3>
<p>También conocida como <strong>Range Key</strong>. Es opcional. Permite guardar varios elementos con la misma <em>Partition Key</em>, pero organizados por la <em>Sort Key</em>.</p>
<ul>
  <li><strong>Su superpoder</strong>: Te permite hacer consultas como “tráeme todos los pedidos del Usuario X (PK) que ocurrieron en el último mes (SK)”.</li>
</ul>

<h3 id="️-el-código-cloudformation">🛠️ El Código (CloudFormation)</h3>
<p>Vamos a crear una tabla de “Pedidos” (Orders) que utiliza una <strong>Llave Compuesta</strong> (PK + SK).</p>

<h4 id="1-tabla-de-pedidos-con-llave-compuesta">1. Tabla de Pedidos con Llave Compuesta</h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">TablaPedidos</span><span class="pi">:</span>
  <span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::DynamoDB::Table</span>
  <span class="na">Properties</span><span class="pi">:</span>
    <span class="na">TableName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">PedidosClientes"</span>
    <span class="na">AttributeDefinitions</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">CustomerId"</span> <span class="c1"># Partition Key</span>
        <span class="na">AttributeType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">S"</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">OrderId"</span>    <span class="c1"># Sort Key</span>
        <span class="na">AttributeType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">S"</span>
    <span class="na">KeySchema</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">CustomerId"</span>
        <span class="na">KeyType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">HASH"</span> <span class="c1"># PK</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">OrderId"</span>
        <span class="na">KeyType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">RANGE"</span> <span class="c1"># SK</span>
    <span class="na">BillingMode</span><span class="pi">:</span> <span class="s">PAY_PER_REQUEST</span>
</code></pre></div></div>

<h3 id="-conceptos-nuevos-explicados">📚 Conceptos Nuevos Explicados</h3>

<h4 id="1-llave-primaria-simple">1. Llave Primaria Simple</h4>
<p>Solo tiene <strong>Partition Key</strong>. El valor debe ser único en toda la tabla (como el DNI de una persona).</p>

<h4 id="2-llave-primaria-compuesta-pk--sk">2. Llave Primaria Compuesta (PK + SK)</h4>
<p>La combinación de ambas debe ser única. Esto permite modelar relaciones 1:N (un cliente, muchos pedidos).</p>
<ul>
  <li><strong>Ejemplo</strong>:
    <ul>
      <li>
        <table>
          <tbody>
            <tr>
              <td>PK: <code class="language-plaintext highlighter-rouge">USER#123</code></td>
              <td>SK: <code class="language-plaintext highlighter-rouge">ORDER#001</code></td>
            </tr>
          </tbody>
        </table>
      </li>
      <li>
        <table>
          <tbody>
            <tr>
              <td>PK: <code class="language-plaintext highlighter-rouge">USER#123</code></td>
              <td>SK: <code class="language-plaintext highlighter-rouge">ORDER#002</code></td>
            </tr>
          </tbody>
        </table>
      </li>
    </ul>
  </li>
</ul>

<h4 id="3-query-vs-scan">3. Query vs Scan</h4>
<ul>
  <li><strong>Query</strong>: Buscas por PK. Es extremadamente rápido y barato porque AWS sabe exactamente a qué servidor ir.</li>
  <li><strong>Scan</strong>: Buscas en toda la tabla (como leer un libro completo para encontrar una palabra). Es lento y muy caro. <strong>¡Evítalo a toda costa!</strong></li>
</ul>

<h3 id="-cómo-desplegarlo">🚀 Cómo Desplegarlo</h3>

<p>Crea la tabla de pedidos con este comando:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>aws cloudformation deploy <span class="se">\</span>
  <span class="nt">--stack-name</span> Dynamo-Keys-D25 <span class="se">\</span>
  <span class="nt">--template-file</span> 03-dynamodb-partition-sort-key.yaml
</code></pre></div></div>

<h3 id="-cómo-probar-las-llaves">📈 Cómo probar las llaves</h3>

<ol>
  <li>Ve a la consola de <strong>DynamoDB</strong> → <strong>Explore items</strong> → Tabla <code class="language-plaintext highlighter-rouge">PedidosClientes</code>.</li>
  <li>Crea varios items usando el mismo <code class="language-plaintext highlighter-rouge">CustomerId</code> (ej. <code class="language-plaintext highlighter-rouge">CLIENTE_A</code>) pero diferentes <code class="language-plaintext highlighter-rouge">OrderId</code>.</li>
  <li>Ahora ve a la pestaña de “Query”. Selecciona <code class="language-plaintext highlighter-rouge">CustomerId</code> e ingresa <code class="language-plaintext highlighter-rouge">CLIENTE_A</code>.</li>
  <li>Verás cómo DynamoDB te devuelve instantáneamente todos los pedidos de ese cliente específico sin revisar el resto de la tabla.</li>
</ol>

<h3 id="-código-adjunto">📂 Código Adjunto</h3>

<p>Puedes bajar el template de la tabla con llaves compuestas aquí: 
<a href="/blog/code-samples/2026/05/03-dynamodb-partition-sort-key.yaml">Ver archivo en GitHub</a></p>

<hr />

<h3 id="-video-tutorial">🎥 Video Tutorial</h3>

<p>Mira el proceso paso a paso en video:</p>

<!-- Courtesy of embedresponsively.com -->

<div class="responsive-video-container">
    <iframe src="https://www.youtube-nocookie.com/embed/yhjHWDMZqPQ" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
  </div>

<hr />

<h3 id="-próximos-pasos">💡 Próximos pasos</h3>
<ul>
  <li><strong>Día 26: Lecturas y escrituras: Consistencia y capacidad (RCU/WCU)</strong>: ¿Cómo cobra AWS por usar DynamoDB? Aprenderemos a medir el “esfuerzo” de nuestra base de datos.</li>
</ul>]]></content><author><name>Rodrigo Salgado</name></author><category term="DynamoDB" /><category term="NoSQL" /><category term="DatabaseDesign" /><category term="Architecture" /><summary type="html"><![CDATA[🔑 Día 25: Las llaves que abren la velocidad de milisegundos Si intentas usar DynamoDB como si fuera SQL, vas a sufrir. En SQL puedes buscar por cualquier columna, pero en DynamoDB, la forma en que recuperas tus datos depende casi totalmente de cómo diseñes tu Primary Key. Hoy entenderás la diferencia entre una llave simple y una compuesta.]]></summary></entry><entry><title type="html">Día 24: Anatomía de DynamoDB: Tablas, Items y Atributos</title><link href="https://rsalgadoc.github.io//blog/dynamodb-tables-items-attributes/" rel="alternate" type="text/html" title="Día 24: Anatomía de DynamoDB: Tablas, Items y Atributos" /><published>2026-05-02T00:00:00+00:00</published><updated>2026-05-02T00:00:00+00:00</updated><id>https://rsalgadoc.github.io//blog/dynamodb-tables-items-attributes</id><content type="html" xml:base="https://rsalgadoc.github.io//blog/dynamodb-tables-items-attributes/"><![CDATA[<h1 id="-día-24-cómo-se-organizan-los-datos-en-dynamodb">📋 Día 24: ¿Cómo se organizan los datos en DynamoDB?</h1>
<p>Ayer creamos nuestra primera tabla, pero hoy vamos a entender qué hay dentro. Si vienes del mundo SQL (MySQL, PostgreSQL), prepárate para desaprender un poco. En DynamoDB no hablamos de filas y columnas, sino de una jerarquía mucho más flexible y potente.</p>

<h3 id="-la-jerarquía-de-datos">🧬 La jerarquía de datos</h3>

<ol>
  <li><strong>Tablas (Tables)</strong>: Es el contenedor principal (similar a una tabla SQL).</li>
  <li><strong>Elementos (Items)</strong>: Es un registro individual dentro de la tabla (similar a una “fila”).</li>
  <li><strong>Atributos (Attributes)</strong>: Son los datos específicos de cada elemento (similar a las “columnas”).</li>
</ol>

<h3 id="por-qué-decimos-que-es-schema-less">¿Por qué decimos que es “Schema-less”?</h3>
<p>En una base de datos tradicional, si una tabla tiene las columnas <code class="language-plaintext highlighter-rouge">Nombre</code> y <code class="language-plaintext highlighter-rouge">Email</code>, todas las filas DEBEN tener esas columnas. En DynamoDB, un <strong>Item</strong> puede tener <code class="language-plaintext highlighter-rouge">Nombre</code> y <code class="language-plaintext highlighter-rouge">Email</code>, pero el siguiente Item puede tener <code class="language-plaintext highlighter-rouge">Nombre</code> y <code class="language-plaintext highlighter-rouge">Twitter</code>, ¡y no pasa nada! La tabla no explota.</p>

<h3 id="️-el-código-cloudformation">🛠️ El Código (CloudFormation)</h3>
<p>Vamos a crear una tabla de “Productos” que nos permita ver cómo se definen los tipos de datos básicos.</p>

<h4 id="1-tabla-de-catálogo-de-productos">1. Tabla de Catálogo de Productos</h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">TablaProductos</span><span class="pi">:</span>
  <span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::DynamoDB::Table</span>
  <span class="na">Properties</span><span class="pi">:</span>
    <span class="na">TableName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">CatalogoProductos"</span>
    <span class="c1"># Definimos solo la llave principal (obligatorio)</span>
    <span class="na">AttributeDefinitions</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">SKU"</span>
        <span class="na">AttributeType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">S"</span> <span class="c1"># S = String (Texto)</span>
    <span class="na">KeySchema</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">SKU"</span>
        <span class="na">KeyType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">HASH"</span>
    <span class="na">BillingMode</span><span class="pi">:</span> <span class="s">PAY_PER_REQUEST</span>
</code></pre></div></div>

<h3 id="-conceptos-nuevos-explicados">📚 Conceptos Nuevos Explicados</h3>

<h4 id="1-atributos-escalares-tipos-básicos">1. Atributos Escalares (Tipos Básicos)</h4>
<ul>
  <li><strong>S (String)</strong>: Texto.</li>
  <li><strong>N (Number)</strong>: Números (enteros, decimales).</li>
  <li><strong>B (Binary)</strong>: Datos binarios (como imágenes en miniatura).</li>
</ul>

<h4 id="2-atributos-de-documento-tipos-complejos">2. Atributos de Documento (Tipos Complejos)</h4>
<p>Aquí es donde DynamoDB brilla. Puedes guardar:</p>
<ul>
  <li><strong>L (List)</strong>: Una lista ordenada de valores (como una lista de tags: <code class="language-plaintext highlighter-rouge">['electronica', 'oferta']</code>).</li>
  <li><strong>M (Map)</strong>: Un objeto JSON anidado dentro de un atributo. ¡Puedes tener mini-estructuras dentro de un Item!</li>
</ul>

<h4 id="3-el-tamaño-del-item">3. El tamaño del Item</h4>
<p>Ojo: Un solo <strong>Item</strong> (con todos sus atributos) no puede pesar más de <strong>400 KB</strong>. DynamoDB está hecho para datos rápidos y ligeros, no para guardar archivos pesados (para eso usamos S3).</p>

<h3 id="-cómo-desplegarlo">🚀 Cómo Desplegarlo</h3>

<p>Actualiza tu infraestructura para añadir la tabla de productos:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>aws cloudformation deploy <span class="se">\</span>
  <span class="nt">--stack-name</span> Dynamo-Conceptos-D24 <span class="se">\</span>
  <span class="nt">--template-file</span> 02-dynamo-tables-items-attributes.yaml
</code></pre></div></div>

<h3 id="-cómo-probar-la-flexibilidad">📈 Cómo probar la flexibilidad</h3>

<ol>
  <li>Ve a la consola de <strong>DynamoDB</strong> → <strong>Explore items</strong> → Tabla <code class="language-plaintext highlighter-rouge">CatalogoProductos</code>.</li>
  <li>Crea un Item: <code class="language-plaintext highlighter-rouge">SKU: PROD-001</code>, <code class="language-plaintext highlighter-rouge">Nombre: Camiseta</code>.</li>
  <li>Crea otro Item: <code class="language-plaintext highlighter-rouge">SKU: PROD-002</code>, <code class="language-plaintext highlighter-rouge">Nombre: Laptop</code>, y añade un nuevo atributo tipo <strong>Number</strong> llamado <code class="language-plaintext highlighter-rouge">Precio: 1200</code>.</li>
  <li>Observa cómo la tabla muestra ambos, aunque uno tenga precio y el otro no. ¡Eso es flexibilidad NoSQL!</li>
</ol>

<h3 id="-código-adjunto">📂 Código Adjunto</h3>

<p>Puedes bajar el template de la tabla de productos aquí: 
<a href="/blog/code-samples/2026/05/02-dynamo-tables-items-attributes.yaml">Ver archivo en GitHub</a></p>

<hr />

<h3 id="-video-tutorial">🎥 Video Tutorial</h3>

<p>Mira el proceso paso a paso en video:</p>

<!-- Courtesy of embedresponsively.com -->

<div class="responsive-video-container">
    <iframe src="https://www.youtube-nocookie.com/embed/BSfdzTG91z0" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
  </div>

<hr />

<h3 id="-próximos-pasos">💡 Próximos pasos</h3>
<ul>
  <li><strong>Día 25: La importancia de la Partition Key y Sort Key</strong>: Mañana veremos el concepto más importante de DynamoDB. Si entiendes las llaves, dominas la base de datos.</li>
</ul>]]></content><author><name>Rodrigo Salgado</name></author><category term="DynamoDB" /><category term="NoSQL" /><category term="DatabaseDesign" /><category term="Serverless" /><summary type="html"><![CDATA[📋 Día 24: ¿Cómo se organizan los datos en DynamoDB? Ayer creamos nuestra primera tabla, pero hoy vamos a entender qué hay dentro. Si vienes del mundo SQL (MySQL, PostgreSQL), prepárate para desaprender un poco. En DynamoDB no hablamos de filas y columnas, sino de una jerarquía mucho más flexible y potente.]]></summary></entry><entry><title type="html">Día 23: ¿Qué es DynamoDB y cuándo usar NoSQL?</title><link href="https://rsalgadoc.github.io//blog/dynamo-intro/" rel="alternate" type="text/html" title="Día 23: ¿Qué es DynamoDB y cuándo usar NoSQL?" /><published>2026-05-01T00:00:00+00:00</published><updated>2026-05-01T00:00:00+00:00</updated><id>https://rsalgadoc.github.io//blog/dynamo-intro</id><content type="html" xml:base="https://rsalgadoc.github.io//blog/dynamo-intro/"><![CDATA[<h1 id="-día-23-bases-de-datos-a-la-velocidad-del-rayo-con-dynamodb">⚡ Día 23: Bases de datos a la velocidad del rayo con DynamoDB</h1>
<p>Después de dominar S3, hoy entramos en el corazón de las aplicaciones modernas: las bases de datos. Pero no vamos a hablar de las clásicas tablas con filas y columnas de toda la vida. Hoy conocerás <strong>Amazon DynamoDB</strong>, la base de datos NoSQL de AWS que puede manejar millones de peticiones por segundo con una latencia de milisegundos.</p>

<h3 id="qué-hace-a-dynamodb-tan-especial">¿Qué hace a DynamoDB tan especial?</h3>

<ul>
  <li><strong>Serverless total</strong>: No eliges cuánta RAM o CPU necesitas; AWS se encarga de todo el escalado.</li>
  <li><strong>Velocidad consistente</strong>: No importa si tienes 1 GB o 100 TB de datos, el tiempo de respuesta siempre es de un solo dígito de milisegundo.</li>
  <li><strong>Disponibilidad extrema</strong>: Tus datos se replican automáticamente en tres zonas de disponibilidad (AZ) distintas.</li>
  <li><strong>Sin esquemas rígidos</strong>: Cada registro puede tener atributos diferentes sin necesidad de alterar una tabla.</li>
</ul>

<h3 id="-cuándo-elegir-nosql-dynamodb-en-lugar-de-sql">🤔 ¿Cuándo elegir NoSQL (DynamoDB) en lugar de SQL?</h3>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Situación</th>
      <th style="text-align: left">¿Usar DynamoDB?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Necesitas escalar a millones de usuarios</td>
      <td style="text-align: left">✅ <strong>Sí</strong></td>
    </tr>
    <tr>
      <td style="text-align: left">Datos con estructura flexible</td>
      <td style="text-align: left">✅ <strong>Sí</strong></td>
    </tr>
    <tr>
      <td style="text-align: left">Relaciones complejas entre tablas (Joins)</td>
      <td style="text-align: left">❌ No (Mejor usar RDS)</td>
    </tr>
    <tr>
      <td style="text-align: left">Aplicaciones de baja latencia (juegos, carritos de compra)</td>
      <td style="text-align: left">✅ <strong>Sí</strong></td>
    </tr>
    <tr>
      <td style="text-align: left">Consultas de analítica profunda y reportes complejos</td>
      <td style="text-align: left">❌ No</td>
    </tr>
  </tbody>
</table>

<h3 id="️-el-código-cloudformation">🛠️ El Código (CloudFormation)</h3>
<p>Para empezar, vamos a crear nuestra primera tabla. En DynamoDB, lo único que debemos definir obligatoriamente al inicio es el nombre de la tabla y su llave principal.</p>

<h4 id="1-mi-primera-tabla-de-dynamodb">1. Mi primera tabla de DynamoDB</h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">MiTablaUsuarios</span><span class="pi">:</span>
  <span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::DynamoDB::Table</span>
  <span class="na">Properties</span><span class="pi">:</span>
    <span class="na">TableName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">UsuariosApp"</span>
    <span class="c1"># Definimos el esquema de la llave (Partition Key)</span>
    <span class="na">AttributeDefinitions</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">UserId"</span>
        <span class="na">AttributeType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">S"</span> <span class="c1"># S de String</span>
    <span class="na">KeySchema</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">AttributeName</span><span class="pi">:</span> <span class="s2">"</span><span class="s">UserId"</span>
        <span class="na">KeyType</span><span class="pi">:</span> <span class="s2">"</span><span class="s">HASH"</span> <span class="c1"># HASH es el identificador único</span>
    <span class="c1"># Modo de pago por uso (ideal para empezar)</span>
    <span class="na">BillingMode</span><span class="pi">:</span> <span class="s">PAY_PER_REQUEST</span>
    <span class="na">Tags</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">Key</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Modulo"</span>
        <span class="na">Value</span><span class="pi">:</span> <span class="s2">"</span><span class="s">DynamoDB-Intro"</span>
</code></pre></div></div>

<h3 id="-conceptos-nuevos-explicados">📚 Conceptos Nuevos Explicados</h3>

<h4 id="1-nosql-not-only-sql">1. NoSQL (Not Only SQL)</h4>
<p>A diferencia de SQL, donde todo debe encajar en columnas fijas, en NoSQL priorizamos el rendimiento y la flexibilidad. No hay “JOINs” entre tablas; los datos se guardan de forma que leerlos sea lo más rápido posible.</p>

<h4 id="2-partition-key-llave-de-partición">2. Partition Key (Llave de Partición)</h4>
<p>Es el identificador único de cada registro. AWS usa este valor para saber en qué parte física de sus servidores guardar tu dato.</p>

<h4 id="3-billing-mode-pay_per_request">3. Billing Mode: PAY_PER_REQUEST</h4>
<p>Es el modo “On-Demand”. No pagas nada por hora; solo pagas por cada lectura o escritura real que hagas. Es perfecto para el blog porque si nadie entra a tu app, te cuesta <strong>$0</strong>.</p>

<h3 id="-cómo-desplegarlo">🚀 Cómo Desplegarlo</h3>

<p>Crea tu primera base de datos NoSQL con este comando:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>aws cloudformation deploy <span class="se">\</span>
  <span class="nt">--stack-name</span> Dynamo-Intro-D23 <span class="se">\</span>
  <span class="nt">--template-file</span> 01-dynamo-intro.yaml
</code></pre></div></div>

<h3 id="-cómo-probar-tu-tabla">📈 Cómo probar tu tabla</h3>

<ol>
  <li>Ve a la consola de <strong>DynamoDB</strong> → <strong>Tables</strong> → Selecciona <code class="language-plaintext highlighter-rouge">UsuariosApp</code>.</li>
  <li>Haz clic en <strong>Explore table items</strong>.</li>
  <li>Haz clic en <strong>Create item</strong>.</li>
  <li>En <code class="language-plaintext highlighter-rouge">UserId</code>, pon <code class="language-plaintext highlighter-rouge">101</code>.</li>
  <li>Haz clic en <strong>Add new attribute</strong> → <strong>String</strong> → Nombre: <code class="language-plaintext highlighter-rouge">Nombre</code>, Valor: <code class="language-plaintext highlighter-rouge">Tu Nombre</code>.</li>
  <li>¡Guárdalo! Acabas de insertar tu primer registro en una base de datos de clase mundial.</li>
</ol>

<h3 id="-código-adjunto">📂 Código Adjunto</h3>

<p>Puedes bajar el template de esta primera tabla aquí: 
<a href="/blog/code-samples/2026/05/01-dynamo-intro.yaml">Ver archivo en GitHub</a></p>

<hr />

<h3 id="-video-tutorial">🎥 Video Tutorial</h3>

<p>Mira el proceso paso a paso en video:</p>

<!-- Courtesy of embedresponsively.com -->

<div class="responsive-video-container">
    <iframe src="https://www.youtube-nocookie.com/embed/z7SzhrvpzzU" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
  </div>

<hr />

<h3 id="-próximos-pasos">💡 Próximos pasos</h3>
<ul>
  <li><strong>Día 24: Conceptos clave: Tablas, Items y Atributos</strong>: Mañana aprenderemos la anatomía real de los datos y cómo se diferencian de una base de datos tradicional.</li>
</ul>]]></content><author><name>Rodrigo Salgado</name></author><category term="DynamoDB" /><category term="NoSQL" /><category term="Serverless" /><category term="Databases" /><summary type="html"><![CDATA[⚡ Día 23: Bases de datos a la velocidad del rayo con DynamoDB Después de dominar S3, hoy entramos en el corazón de las aplicaciones modernas: las bases de datos. Pero no vamos a hablar de las clásicas tablas con filas y columnas de toda la vida. Hoy conocerás Amazon DynamoDB, la base de datos NoSQL de AWS que puede manejar millones de peticiones por segundo con una latencia de milisegundos.]]></summary></entry><entry><title type="html">Día 22: Mejores prácticas y optimización de costos en S3</title><link href="https://rsalgadoc.github.io//blog/s3-best-practices/" rel="alternate" type="text/html" title="Día 22: Mejores prácticas y optimización de costos en S3" /><published>2026-04-30T00:00:00+00:00</published><updated>2026-04-30T00:00:00+00:00</updated><id>https://rsalgadoc.github.io//blog/s3-best-practices</id><content type="html" xml:base="https://rsalgadoc.github.io//blog/s3-best-practices/"><![CDATA[<h1 id="-día-22-el-toque-final-mejores-prácticas-y-ahorro-extremo">✨ Día 22: El toque final. Mejores prácticas y ahorro extremo</h1>
<p>¡Llegamos al final de nuestra serie de S3! Hemos pasado de crear un simple bucket a configurar sitios web y cifrado de grado militar con KMS. Pero para ser un verdadero experto en AWS, no solo basta con saber “cómo funciona”, sino con saber <strong>cómo hacerlo de la forma más eficiente y barata posible</strong>.</p>

<h3 id="por-qué-son-vitales-las-mejores-prácticas">¿Por qué son vitales las mejores prácticas?</h3>

<ul>
  <li><strong>Evitar sorpresas en la factura</strong>: S3 es barato, pero un mal patrón de acceso o millones de archivos pequeños pueden salir caros.</li>
  <li><strong>Rendimiento</strong>: Saber cómo nombrar tus archivos puede mejorar la velocidad de lectura.</li>
  <li><strong>Higiene de la nube</strong>: Mantener buckets limpios y bien etiquetados facilita la gestión a largo plazo.</li>
</ul>

<h3 id="️-el-código-cloudformation">🛠️ El Código (CloudFormation)</h3>
<p>Para este cierre, vamos a crear un “Bucket Maestro” que reúne lo mejor de lo que hemos visto: bloqueos de seguridad, etiquetas de costos y una regla de ciclo de vida para limpiar archivos temporales automáticamente.</p>

<h4 id="1-el-bucket-optimizado">1. El Bucket Optimizado</h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">BucketProfesional</span><span class="pi">:</span>
  <span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::S3::Bucket</span>
  <span class="na">Properties</span><span class="pi">:</span>
    <span class="na">BucketName</span><span class="pi">:</span> <span class="kt">!Sub</span> <span class="s2">"</span><span class="s">s3-optimizacion-final-${AWS::AccountId}"</span>
    <span class="c1"># 1. Seguridad Total</span>
    <span class="na">PublicAccessBlockConfiguration</span><span class="pi">:</span>
      <span class="na">BlockPublicAcls</span><span class="pi">:</span> <span class="no">true</span>
      <span class="na">BlockPublicPolicy</span><span class="pi">:</span> <span class="no">true</span>
      <span class="na">IgnorePublicAcls</span><span class="pi">:</span> <span class="no">true</span>
      <span class="na">RestrictPublicBuckets</span><span class="pi">:</span> <span class="no">true</span>
    <span class="c1"># 2. Control de Costos (Limpieza automática)</span>
    <span class="na">LifecycleConfiguration</span><span class="pi">:</span>
      <span class="na">Rules</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">Id</span><span class="pi">:</span> <span class="s2">"</span><span class="s">LimpiarUploadsIncompletos"</span>
          <span class="na">Status</span><span class="pi">:</span> <span class="s">Enabled</span>
          <span class="na">AbortIncompleteMultipartUpload</span><span class="pi">:</span>
            <span class="na">DaysAfterInitiation</span><span class="pi">:</span> <span class="m">7</span>
    <span class="c1"># 3. Organización (Tags para facturación)</span>
    <span class="na">Tags</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">Key</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Proyecto"</span>
        <span class="na">Value</span><span class="pi">:</span> <span class="s2">"</span><span class="s">SerieAWS7Dias"</span>
      <span class="pi">-</span> <span class="na">Key</span><span class="pi">:</span> <span class="s2">"</span><span class="s">CostCenter"</span>
        <span class="na">Value</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Aprendizaje"</span>
</code></pre></div></div>

<h3 id="-los-5-consejos-de-oro-mejores-prácticas">📚 Los 5 Consejos de Oro (Mejores Prácticas)</h3>

<h4 id="1-nombres-de-archivo-aleatorios-al-inicio">1. Nombres de archivo aleatorios al inicio</h4>
<p>Si vas a tener miles de lecturas por segundo, no nombres tus archivos por fecha (ej. <code class="language-plaintext highlighter-rouge">2026-01-01-archivo.jpg</code>). Es mejor usar un prefijo aleatorio o un hash al principio para distribuir la carga en los servidores de AWS.</p>

<h4 id="2-limpia-las-cargas-incompletas">2. Limpia las “Cargas Incompletas”</h4>
<p>A veces, cuando subes un archivo grande, la subida falla a la mitad. AWS guarda esos “pedazos” y te los cobra aunque no veas el archivo. Usa la regla <code class="language-plaintext highlighter-rouge">AbortIncompleteMultipartUpload</code> (como la del código de arriba) para borrarlos automáticamente tras unos días.</p>

<h4 id="3-cuidado-con-los-archivos-pequeños">3. ¡Cuidado con los archivos pequeños!</h4>
<p>S3 cobra por cada 1,000 peticiones. Si tienes 1 millón de archivos de 1 KB, pagarás mucho más en peticiones que en almacenamiento. En esos casos, es mejor agruparlos en un archivo <code class="language-plaintext highlighter-rouge">.zip</code> o <code class="language-plaintext highlighter-rouge">.tar</code>.</p>

<h4 id="4-usa-s3-storage-lens">4. Usa S3 Storage Lens</h4>
<p>Es una herramienta gratuita en la consola de S3 que te da un panel de control con sugerencias de dónde estás desperdiciando dinero y qué buckets no tienen protección.</p>

<h4 id="5-etiquetas-tags-siempre">5. Etiquetas (Tags) siempre</h4>
<p>Nunca crees un recurso sin etiquetas como <code class="language-plaintext highlighter-rouge">Proyecto</code>, <code class="language-plaintext highlighter-rouge">Entorno</code> (Dev/Prod) o <code class="language-plaintext highlighter-rouge">Creador</code>. Cuando llegue la factura a fin de mes, sabrás exactamente qué bucket es el responsable del gasto.</p>

<h3 id="-cómo-cerrar-este-ciclo">🚀 Cómo cerrar este ciclo</h3>

<p>Desplegar este bucket final es tu graduación en S3:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>aws cloudformation deploy <span class="se">\</span>
  <span class="nt">--stack-name</span> S3-Mejores-Practicas <span class="se">\</span>
  <span class="nt">--template-file</span> 30-s3-best-practices.yaml
</code></pre></div></div>

<h3 id="-código-adjunto">📂 Código Adjunto</h3>

<p>Puedes descargar el template completo aquí: 
<a href="/blog/code-samples/2026/04/30-s3-best-practices.yaml">Ver archivo en GitHub</a></p>

<hr />

<h3 id="-video-tutorial">🎥 Video Tutorial</h3>

<p>Mira el proceso paso a paso en video:</p>

<!-- Courtesy of embedresponsively.com -->

<div class="responsive-video-container">
    <iframe src="https://www.youtube-nocookie.com/embed/5REX9NTJT1c" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
  </div>

<hr />

<h3 id="-qué-sigue">💡 ¿Qué sigue?</h3>
<p>Hemos terminado con S3, ¡pero el viaje serverless continúa! En el próximo módulo exploraremos <strong>Amazon DynamoDB</strong>, la base de datos NoSQL que escala a millones de usuarios.</p>]]></content><author><name>Rodrigo Salgado</name></author><category term="S3" /><category term="BestPractices" /><category term="FinOps" /><category term="CloudExpert" /><summary type="html"><![CDATA[✨ Día 22: El toque final. Mejores prácticas y ahorro extremo ¡Llegamos al final de nuestra serie de S3! Hemos pasado de crear un simple bucket a configurar sitios web y cifrado de grado militar con KMS. Pero para ser un verdadero experto en AWS, no solo basta con saber “cómo funciona”, sino con saber cómo hacerlo de la forma más eficiente y barata posible.]]></summary></entry><entry><title type="html">Día 21: Seguridad nivel experto: Cifrado de S3 con AWS KMS</title><link href="https://rsalgadoc.github.io//blog/s3-key-encryption/" rel="alternate" type="text/html" title="Día 21: Seguridad nivel experto: Cifrado de S3 con AWS KMS" /><published>2026-04-29T00:00:00+00:00</published><updated>2026-04-29T00:00:00+00:00</updated><id>https://rsalgadoc.github.io//blog/s3-key-encryption</id><content type="html" xml:base="https://rsalgadoc.github.io//blog/s3-key-encryption/"><![CDATA[<h1 id="-día-21-blindaje-total-cifra-tus-archivos-con-tus-propias-llaves-kms">🔐 Día 21: Blindaje total. Cifra tus archivos con tus propias llaves (KMS)</h1>
<p>Hasta ahora, nuestros buckets usaban el cifrado por defecto de S3 (donde AWS gestiona las llaves). Pero para datos sensibles o entornos corporativos, necesitas tener el control total. Hoy aprenderás a usar <strong>AWS KMS (Key Management Service)</strong> para cifrar tus archivos con una llave que tú mismo controlas.</p>

<h3 id="por-qué-usar-kms-en-lugar-del-cifrado-estándar">¿Por qué usar KMS en lugar del cifrado estándar?</h3>

<ul>
  <li><strong>Control de acceso granular</strong>: Puedes decidir qué usuarios pueden cifrar y quiénes pueden “desencriptar” para ver el contenido.</li>
  <li><strong>Auditoría total</strong>: Cada vez que alguien lee un archivo, queda un registro en AWS CloudTrail indicando que se usó la llave KMS.</li>
  <li><strong>Cumplimiento</strong>: Muchas normativas (como las bancarias o de salud) exigen que el cliente gestione sus propias llaves de cifrado.</li>
</ul>

<h3 id="️-el-código-cloudformation">🛠️ El Código (CloudFormation)</h3>
<p>Este template crea una <strong>llave maestra (KMS Key)</strong> y configura un bucket para que la use de forma obligatoria. Si alguien intenta subir un archivo sin cifrar, S3 lo cifrará automáticamente con esta llave.</p>

<h4 id="1-llave-kms-y-bucket-cifrado">1. Llave KMS y Bucket Cifrado</h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 1. Creamos la llave maestra de cifrado</span>
<span class="na">MiLlaveMaestra</span><span class="pi">:</span>
  <span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::KMS::Key</span>
  <span class="na">Properties</span><span class="pi">:</span>
    <span class="na">Description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Llave</span><span class="nv"> </span><span class="s">maestra</span><span class="nv"> </span><span class="s">para</span><span class="nv"> </span><span class="s">el</span><span class="nv"> </span><span class="s">blog</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">Cifrado</span><span class="nv"> </span><span class="s">S3"</span>
    <span class="na">Enabled</span><span class="pi">:</span> <span class="no">true</span>
    <span class="na">KeyPolicy</span><span class="pi">:</span>
      <span class="na">Version</span><span class="pi">:</span> <span class="s2">"</span><span class="s">2012-10-17"</span>
      <span class="na">Statement</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">Sid</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Permitir</span><span class="nv"> </span><span class="s">uso</span><span class="nv"> </span><span class="s">total</span><span class="nv"> </span><span class="s">al</span><span class="nv"> </span><span class="s">administrador"</span>
          <span class="na">Effect</span><span class="pi">:</span> <span class="s">Allow</span>
          <span class="na">Principal</span><span class="pi">:</span>
            <span class="na">AWS</span><span class="pi">:</span> <span class="kt">!Sub</span> <span class="s2">"</span><span class="s">arn:aws:iam::${AWS::AccountId}:root"</span>
          <span class="na">Action</span><span class="pi">:</span> <span class="s2">"</span><span class="s">kms:*"</span>
          <span class="na">Resource</span><span class="pi">:</span> <span class="s2">"</span><span class="s">*"</span>

<span class="c1"># 2. Creamos el bucket vinculado a esa llave</span>
<span class="na">BucketUltraSeguro</span><span class="pi">:</span>
  <span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::S3::Bucket</span>
  <span class="na">Properties</span><span class="pi">:</span>
    <span class="na">BucketName</span><span class="pi">:</span> <span class="kt">!Sub</span> <span class="s2">"</span><span class="s">s3-cifrado-kms-${AWS::AccountId}"</span>
    <span class="c1"># Bloqueo de acceso público (Mejor práctica del Día 18)</span>
    <span class="na">PublicAccessBlockConfiguration</span><span class="pi">:</span>
      <span class="na">BlockPublicAcls</span><span class="pi">:</span> <span class="no">true</span>
      <span class="na">BlockPublicPolicy</span><span class="pi">:</span> <span class="no">true</span>
    <span class="c1"># Configuración de cifrado obligatorio</span>
    <span class="na">BucketEncryption</span><span class="pi">:</span>
      <span class="na">ServerSideEncryptionConfiguration</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">ServerSideEncryptionByDefault</span><span class="pi">:</span>
            <span class="na">SSEAlgorithm</span><span class="pi">:</span> <span class="s">aws:kms</span>
            <span class="na">KMSMasterKeyID</span><span class="pi">:</span> <span class="kt">!Ref</span> <span class="s">MiLlaveMaestra</span>
</code></pre></div></div>

<h3 id="-conceptos-nuevos-explicados">📚 Conceptos Nuevos Explicados</h3>

<h4 id="1-aws-kms-key-management-service">1. AWS KMS (Key Management Service)</h4>
<p>Es el servicio de AWS para crear y controlar llaves de cifrado. Piensa en él como una “caja fuerte” donde viven las llaves maestras que nunca salen de los módulos de seguridad de AWS.</p>

<h4 id="2-sse-kms-server-side-encryption-with-kms">2. SSE-KMS (Server-Side Encryption with KMS)</h4>
<p>A diferencia de SSE-S3 (el gratuito), aquí tú pagas por la llave ($1 USD al mes aprox.) y por el uso, pero ganas el control de la llave. Si deshabilitas la llave en la consola, <strong>nadie</strong> podrá leer los archivos del bucket, ni siquiera el administrador.</p>

<h4 id="3-key-policy">3. Key Policy</h4>
<p>Es el documento JSON que ves dentro de la llave. Define quién es el dueño de la llave. Es vital que el usuario <code class="language-plaintext highlighter-rouge">root</code> tenga acceso, o podrías “perder las llaves” de tu propia casa.</p>

<h3 id="-cómo-desplegarlo">🚀 Cómo Desplegarlo</h3>

<p>Despliega tu infraestructura con cifrado avanzado:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>aws cloudformation deploy <span class="se">\</span>
  <span class="nt">--stack-name</span> S3-KMS-Seguridad <span class="se">\</span>
  <span class="nt">--template-file</span> 29-s3-key-encryption.yaml
</code></pre></div></div>

<h3 id="-cómo-probar-el-cifrado">📈 Cómo probar el cifrado</h3>

<ol>
  <li>Sube un archivo a este nuevo bucket.</li>
  <li>Selecciona el objeto y ve a la pestaña <strong>Properties</strong>.</li>
  <li>Busca la sección <strong>Server-side encryption settings</strong>.</li>
  <li>Verás que el algoritmo es <strong>AWS Key Management Service concepts (SSE-KMS)</strong> y aparecerá el ARN de la llave que creaste.</li>
  <li><strong>Prueba de fuego</strong>: Si fueras a otra cuenta de AWS e intentaras leer el archivo (aunque el bucket fuera público), no podrías porque no tienes permiso para usar la llave KMS.</li>
</ol>

<h3 id="-código-adjunto">📂 Código Adjunto</h3>

<p>Puedes descargar el template completo aquí: 
<a href="/blog/code-samples/2026/04/29-s3-key-encryption.yaml">Ver archivo en GitHub</a></p>

<hr />

<h3 id="-video-tutorial">🎥 Video Tutorial</h3>

<p>Mira el proceso paso a paso en video:</p>

<!-- Courtesy of embedresponsively.com -->

<div class="responsive-video-container">
    <iframe src="https://www.youtube-nocookie.com/embed/Sci-uwVMYUo" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
  </div>

<hr />

<h3 id="-próximos-pasos">💡 Próximos pasos</h3>
<ul>
  <li><strong>Día 22: Mejores prácticas y optimización de costos</strong>: El gran cierre. Repasaremos todo lo aprendido para que tu arquitectura en S3 sea impecable.</li>
</ul>]]></content><author><name>Rodrigo Salgado</name></author><category term="S3" /><category term="Seguridad" /><category term="KMS" /><category term="Encryption" /><summary type="html"><![CDATA[🔐 Día 21: Blindaje total. Cifra tus archivos con tus propias llaves (KMS) Hasta ahora, nuestros buckets usaban el cifrado por defecto de S3 (donde AWS gestiona las llaves). Pero para datos sensibles o entornos corporativos, necesitas tener el control total. Hoy aprenderás a usar AWS KMS (Key Management Service) para cifrar tus archivos con una llave que tú mismo controlas.]]></summary></entry><entry><title type="html">Día 20: Alojamiento de sitios web estáticos en S3</title><link href="https://rsalgadoc.github.io//blog/s3-web-site/" rel="alternate" type="text/html" title="Día 20: Alojamiento de sitios web estáticos en S3" /><published>2026-04-28T00:00:00+00:00</published><updated>2026-04-28T00:00:00+00:00</updated><id>https://rsalgadoc.github.io//blog/s3-web-site</id><content type="html" xml:base="https://rsalgadoc.github.io//blog/s3-web-site/"><![CDATA[<h1 id="-día-20-tu-sitio-web-en-la-nube-por-centavos">🚀 Día 20: Tu sitio web en la nube por centavos</h1>
<p>¿Sabías que no necesitas un servidor EC2 para alojar una página web? Si tu sitio es <strong>estático</strong> (HTML, CSS, JavaScript, imágenes), puedes usar Amazon S3 para servirlo al mundo. Es la forma más barata, escalable y sencilla de desplegar un portafolio o una landing page.</p>

<h3 id="qué-es-un-sitio-web-estático-en-s3">¿Qué es un sitio web estático en S3?</h3>

<ul>
  <li><strong>Sin servidores</strong>: No hay sistema operativo que parchear ni servidores que gestionar.</li>
  <li><strong>Escalabilidad infinita</strong>: S3 maneja desde 1 hasta millones de visitas sin configurar nada.</li>
  <li><strong>Costo mínimo</strong>: Solo pagas por el almacenamiento y la transferencia de datos (centavos al mes).</li>
  <li><strong>Nota importante</strong>: Solo sirve para contenido estático. Si necesitas base de datos en el servidor (como PHP o Python), necesitarás otros servicios, aunque puedes usar APIs con JavaScript.</li>
</ul>

<h3 id="️-el-código-cloudformation">🛠️ El Código (CloudFormation)</h3>
<p>Para que un bucket funcione como sitio web, necesitamos activar la configuración de hosting y, por primera vez en esta serie, permitir el <strong>acceso de lectura público</strong> para que cualquier persona en internet pueda ver tu página.</p>

<h4 id="1-bucket-configurado-como-sitio-web">1. Bucket configurado como sitio web</h4>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">WebsiteBucket</span><span class="pi">:</span>
  <span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::S3::Bucket</span>
  <span class="na">Properties</span><span class="pi">:</span>
    <span class="na">BucketName</span><span class="pi">:</span> <span class="kt">!Sub</span> <span class="s2">"</span><span class="s">mi-web-estatica-${AWS::AccountId}"</span>
    <span class="c1"># Configuramos el archivo principal y el de error</span>
    <span class="na">WebsiteConfiguration</span><span class="pi">:</span>
      <span class="na">IndexDocument</span><span class="pi">:</span> <span class="s">index.html</span>
      <span class="na">ErrorDocument</span><span class="pi">:</span> <span class="s">error.html</span>
    <span class="c1"># Para una web pública, quitamos los bloqueos que usamos antes</span>
    <span class="na">PublicAccessBlockConfiguration</span><span class="pi">:</span>
      <span class="na">BlockPublicAcls</span><span class="pi">:</span> <span class="no">false</span>
      <span class="na">BlockPublicPolicy</span><span class="pi">:</span> <span class="no">false</span>
      <span class="na">IgnorePublicAcls</span><span class="pi">:</span> <span class="no">false</span>
      <span class="na">RestrictPublicBuckets</span><span class="pi">:</span> <span class="no">false</span>

<span class="c1"># 2. Permitir que TODO EL MUNDO lea los archivos</span>
<span class="na">WebsiteBucketPolicy</span><span class="pi">:</span>
  <span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::S3::BucketPolicy</span>
  <span class="na">Properties</span><span class="pi">:</span>
    <span class="na">Bucket</span><span class="pi">:</span> <span class="kt">!Ref</span> <span class="s">WebsiteBucket</span>
    <span class="na">PolicyDocument</span><span class="pi">:</span>
      <span class="na">Version</span><span class="pi">:</span> <span class="s1">'</span><span class="s">2012-10-17'</span>
      <span class="na">Statement</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">Sid</span><span class="pi">:</span> <span class="s">PublicReadForGetBucketObjects</span>
          <span class="na">Effect</span><span class="pi">:</span> <span class="s">Allow</span>
          <span class="na">Principal</span><span class="pi">:</span> <span class="s1">'</span><span class="s">*'</span>
          <span class="na">Action</span><span class="pi">:</span> <span class="s1">'</span><span class="s">s3:GetObject'</span>
          <span class="na">Resource</span><span class="pi">:</span> <span class="kt">!Sub</span> <span class="s1">'</span><span class="s">arn:aws:s3:::${WebsiteBucket}/*'</span>
</code></pre></div></div>

<h3 id="-conceptos-nuevos-explicados">📚 Conceptos Nuevos Explicados</h3>

<h4 id="1-websiteconfiguration">1. WebsiteConfiguration</h4>
<p>Le indica a S3 que este bucket no es solo para guardar archivos, sino que debe comportarse como un servidor web. El <code class="language-plaintext highlighter-rouge">IndexDocument</code> es la página que se cargará por defecto cuando alguien entre a tu URL.</p>

<h4 id="2-s3-website-endpoint">2. S3 Website Endpoint</h4>
<p>Al activar esta función, AWS te dará una URL especial (distinta a la de los objetos normales). El formato suele ser: <code class="language-plaintext highlighter-rouge">http://mi-web-estatica.s3-website-us-east-1.amazonaws.com/</code>.</p>

<h4 id="3-acceso-público-lectura">3. Acceso Público (Lectura)</h4>
<p>A diferencia de los días anteriores, aquí <strong>sí queremos acceso público</strong>. La política <code class="language-plaintext highlighter-rouge">s3:GetObject</code> aplicada al Principal <code class="language-plaintext highlighter-rouge">*</code> permite que cualquier navegador pueda descargar y mostrar tu HTML.</p>

<h3 id="-cómo-desplegarlo">🚀 Cómo Desplegarlo</h3>

<ol>
  <li>Crea el stack de CloudFormation:
    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  aws cloudformation deploy <span class="se">\</span>
 <span class="nt">--stack-name</span> S3-Web-Estatica <span class="se">\</span>
 <span class="nt">--template-file</span> 20-s3-web.yaml
</code></pre></div>    </div>
  </li>
  <li>
    <p>Sube un archivo llamado <code class="language-plaintext highlighter-rouge">index.html</code> básico:</p>

    <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt">&lt;h1&gt;</span>¡Hola Mundo!<span class="nt">&lt;/h1&gt;</span>
</code></pre></div>    </div>
  </li>
  <li>Súbelo usando la CLI:
    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  aws s3 <span class="nb">cp </span>index.html s3://tu-nombre-de-bucket/
</code></pre></div>    </div>
  </li>
</ol>

<h3 id="-cómo-probar-tu-nueva-web">📈 Cómo probar tu nueva web</h3>

<ol>
  <li>Ve a la consola de <strong>S3</strong> → Entra en tu bucket.</li>
  <li>Ve a la pestaña <strong>Properties</strong> (Propiedades).</li>
  <li>Baja hasta el final a la sección <strong>Static website hosting</strong>.</li>
  <li>Haz clic en el enlace que aparece debajo de <strong>Bucket website endpoint</strong>.</li>
  <li>¡Deberías ver tu mensaje de “Hola Mundo” en el navegador!</li>
</ol>

<h3 id="-código-adjunto">📂 Código Adjunto</h3>

<p>Puedes descargar el template de CloudFormation y un ejemplo de <code class="language-plaintext highlighter-rouge">index.html</code> aquí: 
<a href="/blog/code-samples/2026/04/28-s3-web-site.yaml">Ver archivo en GitHub</a></p>

<hr />

<h3 id="-video-tutorial">🎥 Video Tutorial</h3>

<p>Mira el proceso paso a paso en video:</p>

<!-- Courtesy of embedresponsively.com -->

<div class="responsive-video-container">
    <iframe src="https://www.youtube-nocookie.com/embed/0ul5M9KjNwk" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
  </div>

<hr />

<h3 id="-próximos-pasos">💡 Próximos pasos</h3>
<ul>
  <li><strong>Día 21: Replicación entre regiones y seguridad con cifrado (KMS)</strong>: Aprende a copiar tus archivos automáticamente a otro país por seguridad y a cifrarlos con llaves maestras.</li>
</ul>]]></content><author><name>Rodrigo Salgado</name></author><category term="S3" /><category term="Web Design" /><category term="CloudFormation" /><category term="Serverless" /><summary type="html"><![CDATA[🚀 Día 20: Tu sitio web en la nube por centavos ¿Sabías que no necesitas un servidor EC2 para alojar una página web? Si tu sitio es estático (HTML, CSS, JavaScript, imágenes), puedes usar Amazon S3 para servirlo al mundo. Es la forma más barata, escalable y sencilla de desplegar un portafolio o una landing page.]]></summary></entry></feed>