<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Will Peixoto | AWS, Serverless e Arquitetura na prática]]></title><description><![CDATA[Arquitetura event-driven e cloud-native na prática: AWS, serverless, resiliência, custo e AI agents. Posts curtos, com código e decisões que escalam.]]></description><link>https://willpeixoto.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/615b22eead6beb6f6506f2b9/e307190a-71df-47fb-a644-8ed8d632c487.png</url><title>Will Peixoto | AWS, Serverless e Arquitetura na prática</title><link>https://willpeixoto.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 13 Sep 2026 15:04:58 GMT</lastBuildDate><atom:link href="https://willpeixoto.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Data Streaming on AWS: Kinesis, Firehose, Flink, or MSK?]]></title><description><![CDATA[Some data can't wait. The suspicious transaction you need to block now, not tomorrow in a report. The user click that turns into a sharp recommendation if you read it on the spot, and into a missed ch]]></description><link>https://willpeixoto.dev/data-streaming-on-aws-kinesis-firehose-flink-msk</link><guid isPermaLink="true">https://willpeixoto.dev/data-streaming-on-aws-kinesis-firehose-flink-msk</guid><category><![CDATA[AWS]]></category><category><![CDATA[streaming]]></category><category><![CDATA[data streaming]]></category><category><![CDATA[Kinesis]]></category><category><![CDATA[kafka]]></category><category><![CDATA[flink]]></category><category><![CDATA[architecture]]></category><category><![CDATA[serverless]]></category><dc:creator><![CDATA[Willian Peixoto]]></dc:creator><pubDate>Sat, 18 Jul 2026 04:34:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/ddde06b5-635e-4f22-8327-0232b95ef595.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Some data can't wait. The suspicious transaction you need to block now, not tomorrow in a report. The user click that turns into a sharp recommendation if you read it on the spot, and into a missed chance if you read it later. For a long time we treated everything the same way: collect a pile of data, store it in a database, and process it in a batch later. But some things live in the now.</p>
<p>The picture that helps me explain this is a river. Notice that the water doesn't stop to be used. It flows by, and whoever is on the bank takes advantage of it along the way: one turns the mill wheel, another irrigates the field, another generates power. Nobody dams it all up first just to use it afterward. Now swap the water for data and you have data streaming: information arrives in a continuous flow and you react the instant it passes, instead of stacking it all up to process down the line.</p>
<p>That difference is what separates reacting from only finding out later. A bank that blocks fraud the second the transaction happens, an e-commerce that recommends on the click, a factory that adjusts the machine before it breaks: in all of them, processing later is almost not processing, because by the time the midnight batch runs, the moment is gone.</p>
<p>The trouble is that "streaming on AWS" gets confusing, because there are four services with similar names and even good people pick the wrong one. Come with me and I'll sort them out.</p>
<blockquote>
<p><strong>Freshness note:</strong> I wrote this guide in June 2026 and revised it in July 2026 (the math already includes On-demand Advantage and an important fix about ordering). Streaming services move fast: mode, quota, and price. I'll keep the post current, but if something doesn't match the screen in front of you, check the <a href="https://docs.aws.amazon.com/streams/latest/dev/introduction.html">official Kinesis docs</a> and tell me in the comments so I can fix it.</p>
</blockquote>
<h2>Before the service, the concept: stream or batch</h2>
<p>Batch is collecting a pile of data and processing it every so often, like the report that runs overnight. Streaming is processing event by event, as it arrives. They don't compete: each solves a different kind of problem. Month-end accounting close is batch and it's just fine. A fraud alert is streaming, because one minute of delay is money lost. The mistake is using batch where the business needs to react on the spot.</p>
<h2>The map: the four services (and what each one actually does)</h2>
<p>Before diving into each one, two warnings that save you confusion. First, AWS <strong>renamed</strong> two services: <strong>Kinesis Data Firehose</strong> became <strong>Amazon Data Firehose</strong> (Feb 2024) and <strong>Kinesis Data Analytics</strong> became <strong>Amazon Managed Service for Apache Flink</strong> (Aug 2023). If you find a tutorial with the old name, it's the same service, just a new sign on the door. And Data Streams got a new mode, <strong>On-demand Advantage</strong>, which I'll explain in a moment.</p>
<p>Second, for those coming from Kafka: what's a <strong>topic</strong> there is a <strong>stream</strong> here in Kinesis; what's a <strong>partition</strong> there is a <strong>shard</strong> here. The map helps, but it isn't identical: Kinesis's <code>PartitionKey</code> runs through a hash that picks the shard, so several different keys can share the same shard. From here on I use each service's real name, but know that the two worlds mirror each other.</p>
<img src="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/648c7548-8b78-4d45-9242-152c3b35b5ed.png" alt="Data Streaming pipeline on AWS: producers send events to Kinesis Data Streams, which feeds a Lambda consumer in real time, Amazon Data Firehose delivering to S3, and Managed Service for Apache Flink processing to a dashboard; Amazon MSK appears as an alternative entry point." style="display:block;margin:0 auto" />

<h3>Kinesis Data Streams: the river you can re-read</h3>
<p>It's the heart of the story. The stream (the topic, remember?) is durable: producers write, consumers read, and the data is retained for a while (up to 365 days), so you can reprocess it. It's the "log" of the river. Use it when you need a durable stream, with replay, and you'll build the consumer (a Lambda, or an app with the Kinesis Client Library, the KCL, which handles shard distribution and checkpointing for you). Capacity comes split into <strong>shards</strong> (the partitions), each with a write and read ceiling, and you pick between three capacity modes:</p>
<ul>
<li><p><strong>Provisioned:</strong> you set the number of shards and pay for them, whether they're busy or not.</p>
</li>
<li><p><strong>On-demand:</strong> AWS manages the shards for you and you pay for the throughput you use.</p>
</li>
<li><p><strong>On-demand Advantage</strong> (the newest): brings warm throughput, with instant capacity for spikes, up to 10 GiB/s. One detail the sales page doesn't shout: it's an ACCOUNT billing mode, with a minimum usage commitment (25 MiB/s for at least 24h, charged even if you use less). In exchange, throughput comes out 60%+ cheaper and the per-stream-hour charge goes away. It makes sense from real volume up; for a small stream, stick with the first two modes.</p>
</li>
</ul>
<h3>Amazon Data Firehose: just deliver it to a destination</h3>
<p>This one was renamed from Kinesis Data Firehose in 2024, same thing, new name. Here you don't write a consumer, it's the role Kafka Connect plays in the Kafka world (the sink connectors). You point at a source and a destination (S3, OpenSearch, Redshift, and others) and Firehose delivers, with buffering, optional transformation, and compression along the way. No replay, it's near-real-time delivery. Use it when the goal is to take the stream and drop it somewhere, with no consumption logic of your own.</p>
<h3>Managed Service for Apache Flink: STATEFUL processing</h3>
<p>This one was Kinesis Data Analytics, renamed in 2023. It runs managed Apache Flink for stateful processing, what Kafka Streams or ksqlDB do in the Kafka world: windows (summing per minute), joins between streams, and exactly-once on state recovery. When the question is "what's the moving average of the last 5 minutes per user," the answer lives here. The state, checkpoint, and recovery infrastructure is the service's responsibility; end-to-end semantics (what your sources and sinks guarantee) and state compatibility across versions remain your decisions.</p>
<h3>Amazon MSK (and MSK Serverless): managed Kafka</h3>
<p>If your world is already Kafka (ecosystem, Kafka API, portability across clouds, a team that knows it), MSK is AWS's managed Kafka. MSK Serverless provisions and scales capacity on its own and manages the topic's partitions, without you sizing a cluster. Use it when you need real Kafka, not a native equivalent.</p>
<h2>When to use each</h2>
<table>
<thead>
<tr>
<th>You want...</th>
<th>AWS service</th>
<th>Kafka equivalent</th>
</tr>
</thead>
<tbody><tr>
<td>a durable, replayable stream with your own consumer</td>
<td>Kinesis Data Streams</td>
<td>Apache Kafka (Amazon MSK)</td>
</tr>
<tr>
<td>to just deliver the stream to a destination, no code</td>
<td>Amazon Data Firehose</td>
<td>Kafka Connect (sink)</td>
</tr>
<tr>
<td>stateful processing (window, join, aggregation)</td>
<td>Managed Service for Apache Flink</td>
<td>Kafka Streams / ksqlDB</td>
</tr>
</tbody></table>
<p>In real life, a lot of architectures combine these services in three layers: ingest, delivery, and processing. Data Streams at the entrance, Firehose delivering a raw copy to S3 for history, and Flink processing in real time for a dashboard. And the entrance doesn't have to be Data Streams: you can have MSK up front and Flink after, because Managed Flink reads from both Kinesis and MSK.</p>
<h2>Hands-on: producer and consumer on Kinesis Data Streams</h2>
<p>The producer writes events to the stream. Look at the <code>PartitionKey</code>: it runs through a hash that decides which shard the record lands in. Same key, same shard, and the shard is the territory where order can exist.</p>
<pre><code class="language-js">import { KinesisClient, PutRecordsCommand } from "@aws-sdk/client-kinesis";

const kinesis = new KinesisClient({});

await kinesis.send(new PutRecordsCommand({
  StreamName: "customer-events",
  Records: [
    {
      Data: Buffer.from(JSON.stringify({ userId: "u-42", event: "click", ts: Date.now() })),
      PartitionKey: "u-42", // same key = same shard (the territory of order)
    },
  ],
}));
</code></pre>
<p>Now the gotcha almost everyone learns late, me included: <code>PutRecords</code><strong>, the batch one, does not guarantee order</strong>. Not even with the same key. It processes each record individually, accepts partial success (half the batch goes in, half fails and you resend), and the <a href="https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecords.html">docs are explicit</a>: if you need to read in the order you wrote, the path is <code>PutRecord</code> in the singular, serial, chaining each write's <code>SequenceNumberForOrdering</code> into the next one:</p>
<pre><code class="language-js">import { KinesisClient, PutRecordCommand } from "@aws-sdk/client-kinesis";

const kinesis = new KinesisClient({});

const putEvent = async (payload, previousSequence) =&gt;
  kinesis.send(new PutRecordCommand({
    StreamName: "customer-events",
    PartitionKey: payload.userId, // same entity, same shard
    Data: Buffer.from(JSON.stringify(payload)),
    // chain the previous write: this is what guarantees the sequence
    ...(previousSequence ? { SequenceNumberForOrdering: previousSequence } : {}),
  }));

const login = await putEvent({ userId: "u-42", event: "login" });
await putEvent({ userId: "u-42", event: "purchase" }, login.SequenceNumber);
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/d541fafc-02f6-450a-8518-e4047c85dcf8.png" alt="Order lives inside the shard: the PartitionKey runs through the hash and picks the shard; events with the same key stay in sequence in the same shard; across shards there is no global order. Batch PutRecords does not guarantee order, strict order needs serial chained PutRecord." style="display:block;margin:0 auto" />

<p>With that, the consumer always sees "login" before "purchase." The price is honest: you traded batch throughput for the sequence guarantee. If it's thousands of events per second and strict order isn't a requirement, <code>PutRecords</code> is the right call. The guarantee you ask for changes the bill you pay; that's what architecture is.</p>
<p>On the other side, the serverless consumer is a Lambda with an event source mapping on the stream. And here's the second truth that separates blog examples from production code: delivery is <strong>at-least-once</strong>, the same event can arrive twice. So the handler needs to be idempotent and know how to fail per item, without taking down the whole batch:</p>
<pre><code class="language-js">export const handler = async (event) =&gt; {
  const batchItemFailures = [];

  for (const record of event.Records) {
    try {
      const payload = JSON.parse(Buffer.from(record.kinesis.data, "base64").toString("utf8"));

      // In production: check and write an eventId to an idempotent store
      // BEFORE the side effect. A duplicate processed twice = a customer charged twice.
      console.log(payload.userId, payload.event);
    } catch (error) {
      // fail ONLY this item; the rest of the batch continues
      batchItemFailures.push({ itemIdentifier: record.kinesis.sequenceNumber });
    }
  }

  return { batchItemFailures };
};
</code></pre>
<p>Returning partial failures only takes effect with <code>ReportBatchItemFailures</code> enabled on the event source mapping. And for real production I'd still add persistent idempotency, Logger and Metrics from <a href="https://docs.powertools.aws.dev/lambda/typescript/latest/">AWS Lambda Powertools</a>, a retry limit, a maximum record age, and an on-failure destination. A poison record can't stall the shard forever.</p>
<p>One detail to close: <strong>order is per shard</strong>, not across the whole stream. If order matters for an entity (a user, an order), the key is that entity's. Otherwise, events spread across shards and global order becomes an illusion.</p>
<h2>The honest trade-offs</h2>
<ul>
<li><p><strong>Ordering and scale:</strong> order is per shard, not global, and strict order needs serial <code>PutRecord</code> (the batch one doesn't guarantee it). The partition key choice isn't a detail, it's a design decision that defines how your application behaves AND how it scales. A skewed key throws too much traffic at a single shard (the hot shard) and you lose throughput even paying for several; and each partition key handles at most 1 MiB/s, no matter the warm throughput you configured. This alone is worth a whole post, and it will get one.</p>
</li>
<li><p><strong>Duplicates and observability:</strong> delivery is at-least-once, so replay and retry require an idempotent consumer; reprocessing an event that charges the customer twice just trades one incident for another. And consumer lag needs an alarm: streaming without observability turns into accidental batch, the event arrives now and the consumer processes it half an hour later. The Well-Architected Framework names these bills: Reliability asks for idempotency and recovery, Operational Excellence asks for metrics and alarms, Cost Optimization asks for a capacity mode that follows real traffic, not the team's hopes.</p>
</li>
<li><p><strong>Retention and replay:</strong> Data Streams retains and lets you reprocess; Firehose doesn't, it delivers and moves on.</p>
</li>
<li><p><strong>Cost:</strong> provisioned pays for shards even when idle; on-demand pays a per-stream-hour rate plus usage. A stream on 24/7 with predictable traffic is sometimes cheaper provisioned. Cost is an architecture decision, as Werner Vogels hammers in the Frugal Architect, and it's the same talk as <a href="https://willpeixoto.dev/high-availability-has-a-price-resilience-is-a-decision-not-a-stack">availability has a price</a>.</p>
</li>
<li><p><strong>Latency:</strong> streaming is low, but not zero. Firehose still has buffering (seconds to minutes), so don't count on it for instant reaction.</p>
</li>
</ul>
<h2>Kinesis or MSK?</h2>
<p>If you have no commitment to Kafka, Kinesis is simpler and native, it pairs better with Lambda and the rest of serverless. If you already live on Kafka (connectors, tooling, multi-cloud, a trained team), MSK gives you Kafka without operating the cluster by hand. The choice is about context and ecosystem; "which is best" is the wrong question.</p>
<h2>What you take away</h2>
<ul>
<li><p>Data streaming is processing in the flow, in real time, to react in the moment (fraud, recommendation, IoT). Batch is for when the delay doesn't hurt.</p>
</li>
<li><p>Kinesis Data Streams is the durable, replayable stream; Amazon Data Firehose delivers to a destination; Managed Service for Apache Flink does stateful processing; MSK is managed Kafka.</p>
</li>
<li><p>Order is per shard, so choose the partition key with intent. And STRICT order needs serial <code>PutRecord</code> with <code>SequenceNumberForOrdering</code>: batch <code>PutRecords</code> doesn't guarantee it.</p>
</li>
<li><p>Lambda with Kinesis is at-least-once: idempotency and per-item failure (<code>batchItemFailures</code>) are part of the design, not a luxury.</p>
</li>
<li><p>Provisioned or on-demand is a cost decision, and real architecture combines the services instead of picking just one.</p>
</li>
</ul>
<h2>Your turn</h2>
<p>Do you use streaming in a project? Tell me which of these four made it into your design, and whether picking the wrong one has ever burned you. Drop that like, share it with someone who still processes everything in the midnight batch, and let's talk. Thanks a lot! BUILD. SCALE. REPEAT. =D</p>
<h2>Sources</h2>
<ul>
<li><p><a href="https://aws.amazon.com/kinesis/data-streams/faqs/">Amazon Kinesis Data Streams (FAQs)</a></p>
</li>
<li><p><a href="https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecords.html">PutRecords does not guarantee ordering (API Reference)</a></p>
</li>
<li><p><a href="https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecord.html">PutRecord and SequenceNumberForOrdering (API Reference)</a></p>
</li>
<li><p><a href="https://docs.aws.amazon.com/lambda/latest/dg/services-kinesis-batchfailurereporting.html">Lambda with Kinesis: partial batch failures (ReportBatchItemFailures)</a></p>
</li>
<li><p><a href="https://aws.amazon.com/blogs/big-data/amazon-kinesis-data-streams-launches-on-demand-advantage-for-instant-throughput-increases-and-streaming-at-scale/">Kinesis Data Streams On-demand Advantage</a></p>
</li>
<li><p><a href="https://docs.aws.amazon.com/managed-flink/latest/java/how-fault.html">Fault tolerance in Managed Service for Apache Flink</a></p>
</li>
<li><p><a href="https://aws.amazon.com/blogs/aws/announcing-amazon-managed-service-for-apache-flink-renamed-from-amazon-kinesis-data-analytics/">Amazon Managed Service for Apache Flink (rename)</a></p>
</li>
<li><p><a href="https://aws.amazon.com/blogs/machine-learning/category/analytics/amazon-kinesis/amazon-data-firehose/">Amazon Data Firehose</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Is multi-cloud more resilient? The math says no]]></title><description><![CDATA[🇧🇷 Leia em português clique aqui
After every big cloud outage, it comes back. And it almost always arrives the same way: a C-level who had lunch with a vendor, heard that the magic solution exists, ]]></description><link>https://willpeixoto.dev/multi-cloud-less-resilient-availability-math</link><guid isPermaLink="true">https://willpeixoto.dev/multi-cloud-less-resilient-availability-math</guid><category><![CDATA[AWS]]></category><category><![CDATA[architecture]]></category><category><![CDATA[Resilience]]></category><category><![CDATA[multi-cloud]]></category><category><![CDATA[serverless]]></category><dc:creator><![CDATA[Willian Peixoto]]></dc:creator><pubDate>Thu, 16 Jul 2026 23:38:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/7c5e17e1-1c1f-4422-b3ee-1012591641c7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>🇧🇷 <a href="https://willpeixoto.dev/multi-cloud-menos-resiliente-conta-disponibilidade">Leia em português clique aqui</a></p>
<p>After every big cloud outage, it comes back. And it almost always arrives the same way: a C-level who had lunch with a vendor, heard that the magic solution exists, and walks into the meeting with the line ready. "We need to go multi-cloud, so if AWS goes down we stay up on Google." The whole room nods. Sounds obvious. Two vendors, twice the safety, right?</p>
<p>Wrong. And yes, that is my opinion. Only mine comes with the math on the table.</p>
<p>And if you think I am just being difficult, hold on to one name: Snap. The company behind Snapchat, the app where everything is built to disappear. It signed with the two biggest clouds on the planet. Billions of dollars in contracts, the word "REDUNDANT" printed right there in the IPO filing, lawyers reviewing it, the market applauding, and the board reading that and thinking "there we go, now we are doing it right". All by the book, right? Well: in October 2025 it went down along with the rest of the internet, exactly like a three-person startup running in a single region. The reason is written by Snap itself, in the risk section of the reports it files with the market, and I will come back to it later.</p>
<h2>The intuition that fools you about multi-cloud: parallel redundancy</h2>
<p>Before the math, let's agree on what the numbers mean, because availability is easy to quote and annoying to translate.</p>
<p>When someone says 99.9% availability, they are saying the system can be down for about 8 hours and 46 minutes per year. That is a perfectly realistic number for a well-built application running in a single cloud.</p>
<p>Now the magic trick everyone does in their head during the meeting. If a system is down 0.1% of the time, and I have TWO independent systems, the chance of both being down at the same instant is tiny. It is the logic of two flashlights in a drawer: the chance of both burning out at the exact same second is far smaller than the chance of one burning out. Only one has to light up for you to see.</p>
<p>In reliability theory this has a name, parallel redundancy, and the math goes like this:</p>
<pre><code class="language-plaintext">Parallel (the intuition):  1 - (0.001 x 0.001) = 99.9999%
</code></pre>
<p>Six nines. About 30 seconds of downtime per year. It is beautiful, and the math is dead right, go ahead and check it. The math does not lie. It just answers a very specific question: what is the availability of two systems that are sufficient, independent and genuinely parallel? Hold on to those three words, because that is exactly where multi-cloud projects tend to fall apart.</p>
<h2>The detail that has to enter the math: what sits in series</h2>
<p>Here is the thing. For "only one has to work" to leave the slide and become real, something has to decide which cloud serves each request, something has to keep the data coherent on both sides, and something has to say who the user is on both sides. Those somethings are not dedicated employees: they are new layers, that YOU build, operate and keep alive.</p>
<p>Go back to the flashlights for a second. They are genuinely independent: you switch one on, the other stays in the drawer, and neither depends on the other to work. Now imagine that, to make the two flashlights work as a pair, you had to wire both into the same switch, with a circuit that decides which one lights up. Guess what happens when the switch burns out? You are standing in the dark holding two perfectly good flashlights.</p>
<p>The switch is the dependency the slide does not show. And it rarely shows up alone.</p>
<p>Those layers sit <strong>in series</strong> with the service, series as in the circuit, one piece after another in the request path. And a component in series does the opposite of parallel: it multiplies availability downwards.</p>
<p>Imagine a naive design I have actually seen, where global routing, synchronous consistency between the two clouds, and a shared identity all have to work for the request to complete. If each piece delivers 99.9%, the math looks like this:</p>
<pre><code class="language-plaintext">Series (in this design):  0.999  (global traffic routing)
                        x 0.999  (synchronous cross-cloud consistency)
                        x 0.999  (shared identity)
                        = 99.7%   &lt;- worse than a single cloud
</code></pre>
<img src="./01-series-vs-parallel-en.png" alt="Where the series hides in multi-cloud: global routing, synchronous consistency and shared identity sit in the request path, in front of the two parallel clouds" style="display:block;margin:0 auto" />

<p>See the irony? You spent a fortune to put two clouds in parallel and landed on 99.7% because of what ended up in series. Every piece you added to "gain resilience" became a brand new single point of failure. If one piece of the critical path delivers 99.9%, that becomes the ceiling of the entire system, no matter how good the two clouds underneath are.</p>
<p>Now, being fair to the math, because I would rather hand you the ammunition before you use it against me. The 99.9% on each piece is an illustrative number, picked so the idea is visible; your design may have better pieces, worse pieces, or pieces outside the request path. And here is the caveat that matters most: if replication is asynchronous, it drops out of this math. Cloud A confirms the write and ships the copy to B right after, so when replication breaks the service stays up and the damage lands entirely on the data. The problem moves somewhere else and becomes RPO, which we will get to later.</p>
<p>So the math does not prove that every multi-cloud is less available. It proves something more modest and more uncomfortable: the second cloud does not erase the glue that makes the two work as a single service, and that glue has availability of its own.</p>
<p>There is also a way to pull a piece out of the series, and it has a name: <strong>static stability</strong>, which AWS itself documents in the <a href="https://aws.amazon.com/builders-library/static-stability-using-availability-zones/">Builders' Library</a>. The idea is that the system keeps serving even when the control plane (the piece that decides things) dies. In practice: both sides are already active and taking traffic, with capacity pre-provisioned on both sides, and the health check simply pulls a sick endpoint out of the pool instead of having to "wake up" the side that was sleeping. If failover orchestration goes down, traffic keeps flowing through whatever is still standing.</p>
<img src="./02-static-stability-en.png" alt="Reactive failover vs static stability: in the first, the control plane sits in the request path and becomes the availability ceiling; in the second, both sides already serve and the control plane drops out of the math" style="display:block;margin:0 auto" />

<p>Which means a good architect can absolutely pull pieces out of the series, and should try. It is just that real static stability is expensive, because it requires idle pre-provisioned capacity on both sides, all the time. You take the piece out of the availability math and it reappears in the cost math, doubled now, because it is two idle clouds instead of one.</p>
<p>There is no free lunch. There is a menu, and somebody always picks up the tab.</p>
<p>The exact number varies with your project. The direction is what matters: every dependency you add to the critical path multiplies availability downwards. Routing is the most stubborn of them, because something always has to pick the destination of a request, but even routing can be distributed, cached and made statically stable. One question settles it: if that layer stops deciding right now, does the traffic that is already working keep flowing? Add the operational complexity of keeping all of it alive and you understand why the six nines never show up.</p>
<h2>Independence is fiction</h2>
<p>There is an even deeper detail. The parallel math only holds if the two failures are independent. And they almost never are.</p>
<p>Picture two giant container ships sailing side by side, connected by a bridge. That is the image being sold to you: if one sinks, the other keeps going with your cargo. Beautiful. Except both ships have the same captain, and he is the one picking the route. If the captain misreads the map, both run into the same sandbar, together. And the bridge, which exists only to keep the cargo identical on both ships, is the most expensive and most fragile part of the story: it sways in every storm, charges a toll in both directions, and on the day it collapses you are not left with two identical ships. You are left with two different ships, each carrying its own cargo, and nobody on board knows which one is the real thing.</p>
<p>The two clouds share dependencies you do not even remember exist: the same DNS, the same certificate authority behind your TLS, the same identity provider and, above all, the same deploy pipeline. Guess what happens when the team pushes a bad config? It ships to both clouds at the same time.</p>
<p>And look at the size of that hole: the <a href="https://journal.uptimeinstitute.com/outages-understanding-the-human-factor/">Uptime Institute</a> estimates, based on 25 years of data, that human error plays some role in somewhere between two-thirds and four-fifths of all outages. Notice the words they chose, because they are honest: "some role". Human error rarely shows up as the lone root cause, it is the thread running through the incident. And the most stubborn piece is always the same: people not following the procedure, or the procedure being bad from birth. Guess how much switching vendors helps with that? Not at all.</p>
<p>And here is where the joke lives: if there is one thing DevOps culture has delivered masterfully over the years, it is the ability to propagate nonsense in seconds, with a green pipeline, two reviewer approvals and a rocket emoji in the channel. We automated everything, including the mistake. Except now, with two clouds, it lands in both places at the same time and you pay double for the privilege. Deploy is the most reliable thing in your stack, and that is exactly why it carries the bad config to both destinations without failing once.</p>
<img src="./03-correlated-failure-en.png" alt="Independence is fiction: the deploy pipeline, DNS, certificate authority and identity provider are shared and deliver the same bad config to both clouds at the same time" style="display:block;margin:0 auto" />

<p>Correlated failure breaks the independence assumption, and without independence the parallel math simply does not exist.</p>
<h2>The hidden price: the lowest common denominator</h2>
<p>To truly run active-active on AWS and Google at the same time, everything has to be portable across both. So you give up the managed services that are the most resilient part of the cloud (DynamoDB, S3, SQS, battle-tested at absurd scale) and fall back to whatever runs anywhere: Kubernetes plus a pile of open source that YOU install, operate and keep alive.</p>
<p>And here goes an uncomfortable question, with zero disrespect: does your team operate that stack with more reliability than AWS operates DynamoDB? The team keeping those managed services up at global scale is huge, dedicated, and has been doing only that for over a decade. Betting that your team, split across a thousand priorities, delivers more uptime by hand than they deliver managed is quite a bet. No judgment on anyone's competence; it is simply the matchup of whoever just stepped into the arena against people who made this their life's work.</p>
<p>You traded managed resilience for resilience that became your phone ringing at 3 a.m. As Werner Vogels hammers, "everything fails, all the time". So the question that matters becomes another one: who is on call when it fails? Active-active multi-cloud puts you on that rotation, twice. And notice that it is not enough to have someone who knows AWS on one side and someone who knows Google Cloud on the other. Somebody has to master the glue between them, that piece that exists only inside your company, that has no support button, no ready-made tutorial, and nobody on Stack Overflow who has been through it. On-call costs money, and this on-call costs more. It is a fat line item that rarely shows up in the business case.</p>
<h2>And the cost? You pay for data to leave, on both sides</h2>
<p>There is one item the project spreadsheet usually ignores: egress. Clouds charge little (or nothing) for data coming in, and charge for data going out. In a real active-active setup you are constantly syncing data between AWS and Google to keep both ends identical, so you pay data transfer out on both sides, all the time, just to keep the copies coherent. It is a faucet left running, every month, forever.</p>
<p>I can already hear the objection: "but egress became free in 2024". Careful with that one. What <a href="https://aws.amazon.com/blogs/aws/free-data-transfer-out-to-internet-when-moving-out-of-aws/">AWS</a>, <a href="https://cloud.google.com/exit-cloud">Google</a> and Microsoft zeroed out that year, pushed by the EU Data Act, is egress for people who are leaving the cloud, and even then with rules that vary by provider: you take everything with you, you go through support, and with Google and Microsoft you also have to close the account or cancel the subscriptions within a deadline (AWS, notably, did not include that requirement). That is a divorce subsidy, not an open marriage subsidy. Continuous replication between two clouds, which is precisely what active-active demands, still runs through the register every month.</p>
<p>And add the rest: you duplicate managed services, duplicate the observability stack, duplicate the security and compliance surface, and you need a team with depth in both clouds. The cost does not double, it more than doubles, because the glue integrating the two is a cost center of its own.</p>
<p>Werner Vogels sums it up in <a href="https://thefrugalarchitect.com/">The Frugal Architect</a>: cost is an architecture requirement, and whoever only discovers the number on the invoice discovered it too late. Multi-cloud almost always flunks that test, you pay a fat, continuous bill for insurance against an event that almost never happens.</p>
<p>And let me confess something. Every time that slide shows up in a meeting, there is an architect in some corner of the room who wants to lie down in fetal position under the table (me included). While everybody celebrates the bold decision, they are running the math in their head and watching how much money is about to be burned buying protection against a rare event, money that would solve, I don't know, the multi-Region setup the company has been postponing for two years. If you are that person, breathe: this post is your argument in writing, with the math in hand. And if you are the one approving the project, take another look at the numbers above before you sign.</p>
<p>And before anyone closes the tab in anger: relax, I am not saying multi-cloud never works. There are times when it is the right answer, and I have an entire section about that further down. It is just that those times have a name, a context, and are almost never "resilience". Hold on, we will get there.</p>
<h2>What multi-cloud protects you from, and how rarely that happens</h2>
<p>Think about the real outages you have seen. They were regional, zonal, or a specific service (us-east-1 in October 2025 was exactly that). It is almost never "all of AWS died globally". Whoever went down that day was pinned to a single region, and what would have saved most of them was multi-Region in the same cloud, not a second cloud. Multi-AZ and multi-Region within the SAME cloud cover the overwhelming majority of cases, at a fraction of the complexity. And it is not just me saying it: <a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/aws-multi-region-fundamentals/fundamental-1.html">AWS's own multi-Region guidance</a> recommends confirming that your objectives do not fit inside a single Region before you go for several.</p>
<p>So let's do the homework before drawing two clouds on the whiteboard: does Multi-AZ solve it? Does multi-Region solve it? Or are we overengineering to buy a feeling of safety? What each of those steps costs, and why that math is a business decision before it is a technical one, I went into in <a href="https://willpeixoto.dev/high-availability-has-a-price-resilience-is-a-decision-not-a-stack">the post on the price of high availability</a>. If the requirement fits inside one cloud, adding a second vendor is not automatic maturity. Sometimes it is just complexity wearing a suit.</p>
<p>This has a pattern name: Bulkhead and <a href="https://docs.aws.amazon.com/wellarchitected/latest/reducing-scope-of-impact-with-cell-based-architecture/reducing-scope-of-impact-with-cell-based-architecture.html">cell-based architecture</a>, isolating the blast radius inside your own vendor, in compartments that do not sink together. Multi-cloud protects you from the extremely rare event (the whole provider vanishing from the map) and, in exchange, exposes you to a pile of everyday failures you introduced yourself.</p>
<p>And before I sell you multi-Region as a silver bullet, the fine print: in that same outage, plenty of multi-Region architectures went down too, because they depended on a global control plane (IAM, STS) or had a hidden dependency in us-east-1 that nobody had mapped. This is not theory: <a href="https://aws.amazon.com/message/101925/">AWS's own post-event summary</a> records that STS choked, and that customers using identity federation pointing at signin.aws.amazon.com got console errors <strong>in other Regions too</strong>. No medicine comes without a leaflet. The difference is that the multi-Region leaflet fits in a paragraph and the active-active multi-cloud one is a two-year project.</p>
<h2>The Snap case: multi-cloud on paper, downtime in practice</h2>
<p>I promised to come back to Snap, so here we go.</p>
<p>It did exactly what every board dreams of: signed with both. Google Cloud as primary, and the 2017 IPO S-1 showed a <a href="https://www.geekwire.com/2017/snap-commits-spend-1b-amazon-web-services-next-five-years/">one billion dollar commitment to AWS</a>, with the phrase every executive loves to read, "for redundant infrastructure support of our business operations". Textbook multi-cloud, the two biggest clouds on the planet on the same invoice.</p>
<p>Then, on October 20, 2025, AWS us-east-1 choked. And <a href="https://www.nbcnews.com/news/us-news/amazon-web-services-outage-websites-offline-rcna238594">Snapchat went down</a> along with the rest of the internet.</p>
<p>And the rest of the story is written by Snap itself. Year after year, in the risk section of the reports it files with the market, there it is: a warning that its systems are <strong>not fully redundant</strong>. Look at the timing: that warning was already sitting there long before the fall, in the same stack of paper where the billion dollar contract said "redundant". Nobody wrote it afterwards to explain themselves. The redundancy existed in the contract and in the investor slide. In the application's critical path, it did not.</p>
<p>That is the punch of the argument, and it holds for any company, not just Snap: two clouds on the invoice do not give you two clouds in the architecture. If the critical path depends on a region that went down, the contract with the other vendor sitting in a drawer does not bring your service back up. And if not even a company that size, with billions allocated and elite teams, turned two contracts into real redundancy, the uncomfortable question is worth asking: why would your project turn it?</p>
<h2>But what if I already have failover ready on the other cloud?</h2>
<p>Here the attentive reader raises a hand: "fine, but if cloud A goes down and I have DR ready to flip to B, multi-cloud saved me, right?". It can save you, yes. And notice this scenario is active-passive (one cloud hot, the other on standby), not the active-active that the math above tears apart. They are different things, and this is the legitimate version of the story.</p>
<p>Except three gotchas knock "I have failover" down in practice.</p>
<p>The first: having failover is not the same as failover working. The DR path is the least tested stretch of your system, and you only trigger it at the worst possible moment, under pressure. DR that was never exercised is Schrödinger's backup, you find out whether it works exactly when you need it. It is the classic untested-DR movie: when you go to flip the switch, capacity is not provisioned on the other side, secrets are out of sync, IAM is different. The plan existed, the failover never came.</p>
<p>The second: failover takes time and you lose data along the way. Synchronous replication between two clouds (the kind where a write is only confirmed after it landed on both sides) is too expensive and too slow, so in practice everybody uses asynchronous: cloud A confirms the write to the user and ships the copy to B right after, with a delay of a few seconds.</p>
<p>Look at the hole that opens. If A goes down in exactly that window, everything it confirmed and had not yet copied to B is gone. The order the customer saw on the screen, the payment that showed up as approved, simply does not exist on the other side. That is what RPO (Recovery Point Objective) means, how much data you accept losing, measured in time. And there is RTO (Recovery Time Objective), the time until the service is back, which cross-cloud runs from minutes to hours: bringing up the passive side, propagating DNS, warming caches. It is not pressing a button.</p>
<p>The third: for the outage that actually happens, multi-Region in the same cloud delivers the same DR without the cross-cloud pain. us-east-1 went down, not AWS globally. A Warm Standby or a Pilot Light in another Region of the same cloud brings you back with native managed services, the same IAM and the same tooling (AWS documents all four strategies, with the RTO and the cost of each, in the <a href="https://docs.aws.amazon.com/whitepapers/latest/disaster-recovery-workloads-on-aws/disaster-recovery-options-in-the-cloud.html">Disaster Recovery whitepaper</a>). Going cross-cloud, you throw all of that away to protect against a much rarer event.</p>
<p>Bottom line: cross-cloud failover can exist and even work, but it is expensive, fragile when untested, and almost always loses to same-cloud multi-Region for the kind of outage that actually knocks on your door.</p>
<h2>So multi-cloud is never worth it?</h2>
<p>It is. Just almost never for technical resilience, and this is where most people get the argument wrong. Multi-cloud is justified by business reasons:</p>
<ul>
<li><p>Data sovereignty and regulation: the law says the data must live in a given cloud or country.</p>
</li>
<li><p>Leverage against vendor lock-in: commercial bargaining power (uptime does not even enter that equation).</p>
</li>
<li><p>SaaS that must run wherever the customer demands.</p>
</li>
<li><p>DR required by compliance, sometimes existing only on paper to pass the audit, not because the architecture actually fails over.</p>
</li>
</ul>
<p>And notice that when it is worth it, it is almost always active-passive (one cloud hot, one cold just for disaster recovery), rather than the active-active that wrecks your availability. It is a business and risk decision, recorded in an ADR, with no promise of an extra nine attached.</p>
<p>Since we made it this far, let me plant my position, and it is an opinion, not a theorem. Every architecture decision has two sides, and the question that settles this one is not technical: what is your real pain, and how much does it cost if it happens? If the answer comes from the regulator, the contract or data sovereignty, multi-cloud is in, usually active-passive, and the ROI justifies the complexity. Outside of that, for me, active-active hurts to watch: you buy two ships, a bridge, a double on-call rotation and an overloaded captain to protect yourself from an event that probably is not coming, while the multi-Region setup that would solve your real case keeps waiting for budget. Resilience is not what you buy. It is what you decide, and then sustain.</p>
<p>That is the heart of <a href="https://willpeixoto.dev/high-availability-has-a-price-resilience-is-a-decision-not-a-stack">the post on the price of high availability</a>: resilience starts with a strategic decision, and the stack comes after, as a consequence. Multi-cloud is the most expensive way there is to flip that order.</p>
<h2>What you take from this post</h2>
<ul>
<li><p>The parallel math (99.9999%) only holds for systems that are sufficient, independent and genuinely parallel. Global routing, synchronous consistency and shared identity sit in series and drag the number below what a single cloud delivers.</p>
</li>
<li><p>Asynchronous replication drops out of the uptime math and reappears in RPO: the service stays up and swallows the last writes.</p>
</li>
<li><p>Correlated failure (config, deploys, DNS, CA) breaks the independence assumption the math requires.</p>
</li>
<li><p>Active-active forces the lowest common denominator: you trade mature managed services for a stack that becomes your on-call.</p>
</li>
<li><p>The cost more than doubles: egress on both sides to keep data in sync, duplicated infra, and a team with depth in two clouds.</p>
</li>
<li><p>Multi-AZ and multi-Region in the same cloud (Bulkhead, cells) solve the real case at a fraction of the complexity.</p>
</li>
<li><p>Multi-cloud is worth it for business reasons (regulation, lock-in), not resilience. And then it is active-passive, documented in an ADR.</p>
</li>
</ul>
<p>Honest question for you: have you ever been pushed into a multi-cloud project "for resilience" and found out you gained two on-call rotations instead of one? Tell me how it went. And if you disagree, even better, drop your availability math in the comments, I want to see where mine leaks. Smash that like, share this with whoever is about to approve that project, and let's talk. Thanks a lot! BUILD. SCALE. REPEAT. =D</p>
<h2>Want to go deeper</h2>
<p>The sources worth your next half hour (the rest are linked along the way, right where they matter):</p>
<ul>
<li><p><a href="https://aws.amazon.com/builders-library/static-stability-using-availability-zones/">Static stability using Availability Zones</a>, from the Amazon Builders' Library. The source of the concept that takes the control plane out of the request path, with the control plane vs data plane split explained by the people who built EC2.</p>
</li>
<li><p><a href="https://docs.aws.amazon.com/whitepapers/latest/disaster-recovery-workloads-on-aws/disaster-recovery-options-in-the-cloud.html">Disaster recovery options in the cloud</a>, from the AWS DR whitepaper. Pilot Light, Warm Standby and the note that finally explains the difference between them. This is the alternative that solves your real case without going cross-cloud.</p>
</li>
<li><p><a href="https://aws.amazon.com/message/101925">Post-event summary of the October 2025 outage</a>, by AWS itself. The race condition in DynamoDB's DNS and the cascade that followed: the primary source for the case that opens this post.</p>
</li>
<li><p><a href="https://thefrugalarchitect.com/">The Frugal Architect</a>, by Werner Vogels. Law I is "Make Cost a Non-functional Requirement", and it is the test multi-cloud fails.</p>
</li>
<li><p><a href="https://willpeixoto.dev/high-availability-has-a-price-resilience-is-a-decision-not-a-stack">High availability has a price: resilience is a decision, not a stack</a>, here on the blog. The pillar for this post: the cost of the nines, RTO/RPO and ADRs.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Multi-cloud te deixa menos resiliente, não mais (e dá para provar na conta)]]></title><description><![CDATA[🇺🇸 Also available in English: Multi-cloud makes you less resilient, not more
Depois de todo apagão grande de cloud, ele volta. E quase sempre chega pelo mesmo caminho: um C-level que almoçou com um ]]></description><link>https://willpeixoto.dev/multi-cloud-menos-resiliente-conta-disponibilidade</link><guid isPermaLink="true">https://willpeixoto.dev/multi-cloud-menos-resiliente-conta-disponibilidade</guid><category><![CDATA[AWS]]></category><category><![CDATA[multi-cloud]]></category><category><![CDATA[Resilience]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[architecture]]></category><category><![CDATA[serverless]]></category><dc:creator><![CDATA[Willian Peixoto]]></dc:creator><pubDate>Thu, 16 Jul 2026 23:24:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/dbe63686-c983-4994-b457-13adc0372884.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>🇺🇸 Also available in English: <a href="https://willpeixoto.dev/multi-cloud-less-resilient-availability-math">Multi-cloud makes you less resilient, not more</a></p>
<p>Depois de todo apagão grande de cloud, ele volta. E quase sempre chega pelo mesmo caminho: um C-level que almoçou com um fornecedor, ouviu que a solução mágica existe, e entra na reunião com a frase pronta. "Precisamos ir para multi-cloud, aí se a AWS cair a gente continua de pé na Google." A sala inteira balança a cabeça. Parece óbvio. Dois fornecedores, o dobro de segurança, certo?</p>
<p>Errado. E sim, isso é opinião minha. Só que a minha vem com a conta aberta.</p>
<p>E se você acha que é implicância minha, guarda um nome: Snap. A dona do Snapchat, aquele app de visualização curta, assinou com as duas maiores clouds do planeta. Bilhões de dólares em contrato, a palavra "REDUNDÂNCIA" em letras garrafais e carimbada no documento do IPO, advogado revisando, o mercado inteiro aplaudindo, e a diretoria lendo aquilo e pensando "tá vendo, agora sim, assim é que se faz". Tudo nos conformes, certo? Pois bem: em outubro de 2025 ela caiu junto com o resto da internet, igualzinho a uma startup de três pessoas rodando numa região só. O porquê está escrito pela própria Snap, na seção de risco dos relatórios que ela manda para o mercado, e eu volto nisso lá na frente.</p>
<h2>A intuição que engana no multi-cloud: redundância em paralelo</h2>
<p>Antes da conta, vamos combinar o que os números querem dizer, porque disponibilidade é fácil de citar e chato de traduzir.</p>
<p>Quando alguém fala em 99,9% de disponibilidade, está dizendo que o sistema pode ficar fora do ar umas 8 horas e 46 minutos por ano. É um número bem realista para uma aplicação bem feita rodando numa cloud só.</p>
<p>Agora a mágica que todo mundo faz de cabeça na reunião. Se um sistema fica fora 0,1% do tempo, e eu tenho DOIS sistemas independentes, a chance dos dois estarem fora no mesmo instante é minúscula. É a lógica das duas lanternas na gaveta: a chance de as duas queimarem exatamente no mesmo segundo é muito menor do que a de uma queimar. Basta uma acender e você enxerga.</p>
<p>Na teoria da confiabilidade isso tem nome, redundância em paralelo, e a conta é essa:</p>
<pre><code class="language-plaintext">Paralelo (a intuição):  1 - (0,001 x 0,001) = 99,9999%
</code></pre>
<p>Seis noves. Uns 30 segundos de downtime por ano. É lindo, e a matemática está certíssima, pode conferir. A conta não mente. Ela só responde uma pergunta bem específica: qual é a disponibilidade de dois sistemas suficientes, independentes e realmente paralelos? Guarda essas três palavras, porque é nelas que o projeto multi-cloud costuma desmontar.</p>
<h2>O detalhe que precisa entrar na conta: o que está em série</h2>
<p>Só que, para o "basta uma funcionar" sair do slide e virar realidade, alguém precisa decidir qual cloud atende cada request, alguém precisa manter os dados coerentes dos dois lados, e alguém precisa dizer quem é o usuário nos dois lados. Esses "alguéns" não são funcionários dedicados: são camadas novas, que VOCÊ constrói, opera e mantém de pé.</p>
<p>Volta para as lanternas por um segundo. Elas são independentes de verdade: você acende uma, a outra fica na gaveta, e nenhuma depende da outra para funcionar. Agora imagina que, para as duas lanternas servirem de par, você precisou ligar as duas num mesmo interruptor, com um fio que decide qual acende. Adivinha o que acontece se o interruptor queimar? Você fica no escuro com duas lanternas boas na mão.</p>
<p>O interruptor é a dependência que o slide não mostra. E ela quase nunca vem sozinha.</p>
<p>Essas camadas entram <strong>em série</strong> com o serviço, série no sentido do circuito mesmo, uma peça depois da outra no caminho do request. E componente em série faz o oposto do paralelo: ele multiplica a disponibilidade para baixo.</p>
<p>Imagina um desenho ingênuo que eu já vi na prática, em que o roteamento global, a consistência síncrona entre as duas clouds e uma identidade compartilhada precisam funcionar para o request ser concluído. Se cada peça entrega 99,9%, a conta fica assim:</p>
<pre><code class="language-plaintext">Série (neste desenho):  0,999  (roteamento global de tráfego)
                      x 0,999  (consistência síncrona cross-cloud)
                      x 0,999  (identidade compartilhada)
                      = 99,7%   &lt;- pior que uma cloud sozinha
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/9cb40770-ad42-481a-8a32-5b7920e37907.svg" alt="Onde a série se esconde no multi-cloud: roteamento global, consistência síncrona e identidade compartilhada ficam no caminho do request, na frente das duas clouds em paralelo" style="display:block;margin:0 auto" />

<p>Sacou a ironia? Você gastou uma fortuna para colocar duas clouds em paralelo e terminou em 99,7% por causa do que ficou em série. Cada peça que você adicionou para "ganhar resiliência" virou um novo single point of failure. Se uma peça do caminho crítico entrega 99,9%, esse vira o teto do sistema inteiro, não importa quão boas sejam as duas clouds embaixo.</p>
<p>Agora, sendo justo com a conta, porque eu prefiro te dar a munição antes que você a use contra mim. Os 99,9% de cada peça são um número ilustrativo, escolhido para a ideia ficar visível; o seu desenho pode ter peças melhores, piores ou fora do request path. E olha a ressalva mais importante: se a replicação for assíncrona, ela sai dessa conta. A cloud A confirma a escrita e manda a cópia para a B logo depois, então, quando a replicação quebra, o serviço continua no ar e o estrago vai todo para o dado. O problema muda de lugar e vira RPO, que é papo lá na frente.</p>
<p>Ou seja, a conta não prova que todo multi-cloud é menos disponível. Ela prova uma coisa mais modesta e mais incômoda: a segunda cloud não apaga a cola que faz as duas trabalharem como um serviço só, e essa cola tem disponibilidade própria.</p>
<p>Tem também um jeito de tirar peça da série, e ele tem nome: <strong>static stability</strong>, que a própria AWS documenta na <a href="https://aws.amazon.com/builders-library/static-stability-using-availability-zones/">Builders' Library</a>. A ideia é que o sistema continue servindo mesmo quando o control plane (a peça que decide as coisas) morre. Na prática: os dois lados já ficam ativos e recebendo tráfego, com capacidade pré-provisionada dos dois lados, e o health check apenas tira um endpoint doente do balanceamento em vez de precisar "ligar" o lado que estava dormindo. Se a orquestração de failover cair, o tráfego continua fluindo pelo que está de pé.</p>
<img src="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/7cf1c0da-7997-4a45-ad66-78a67f10869c.png" alt="Failover reativo x static stability: no primeiro, o control plane fica no caminho do request e vira teto de disponibilidade; no segundo, os dois lados já servem e o control plane sai da conta" style="display:block;margin:0 auto" />

<p>Quer dizer, um arquiteto bom consegue, sim, tirar peças da série, e deveria tentar. Só que static stability de verdade custa caro, porque exige capacidade ociosa pré-provisionada dos dois lados, o tempo todo. Você tira a peça da conta de disponibilidade e ela reaparece na conta de custo, agora dobrada, porque são duas clouds ociosas em vez de uma.</p>
<p>Não tem almoço grátis. Tem cardápio, e alguém sempre paga.</p>
<p>O número exato varia com o seu projeto. A direção é o que importa: cada dependência que você adiciona ao caminho crítico multiplica a disponibilidade para baixo. O roteamento é a mais teimosa delas, porque alguém sempre precisa escolher o destino do request, mas mesmo ela dá para distribuir, cachear e deixar statically stable. A pergunta que resolve é uma só: se essa camada parar de decidir agora, o tráfego que já está funcionando continua fluindo? Some a isso a complexidade operacional de manter tudo de pé e você entende por que a promessa dos seis noves nunca chega.</p>
<h2>Independência é ficção</h2>
<p>Tem um detalhe ainda mais fundo. A conta do paralelo só vale se as duas falhas forem independentes. E quase nunca são.</p>
<p>Pensa em dois navios porta-contêineres gigantes navegando lado a lado, ligados por uma ponte. É essa a imagem que te vendem: se um afundar, o outro segue viagem com a sua carga. Bonito. Só que os dois navios têm o mesmo capitão, e é ele que decide a rota. Se o capitão erra o mapa, os dois vão para o mesmo banco de areia, juntinhos. E a ponte, que existe só para manter a carga dos dois idêntica, é a parte mais cara e mais frágil da história: ela balança em toda tempestade, cobra pedágio nos dois sentidos e, no dia em que cai, você não fica com dois navios iguais. Fica com dois navios diferentes, cada um com uma carga, e ninguém a bordo sabe qual das duas é a verdadeira.</p>
<p>As duas clouds compartilham dependências que você nem lembra que existem: o mesmo DNS, a mesma autoridade certificadora do seu TLS, o mesmo provedor de identidade, e, principalmente, o mesmo pipeline de deploy. Adivinha o que acontece quando o time empurra uma config errada? Ela vai para as duas clouds ao mesmo tempo.</p>
<p>Fronteira de verdade entre duas cargas é outra história, e custa outro preço. Quando o vizinho é código que você não escreveu, o isolamento precisa descer ao nível de VM, que é o assunto de <a href="https://willpeixoto.dev/aws-lambda-microvms-codigo-isolado-serverless">AWS Lambda MicroVMs: rode código não confiável com isolamento de VM</a>.</p>
<p>E olha o tamanho desse buraco: o <a href="https://journal.uptimeinstitute.com/outages-understanding-the-human-factor/">Uptime Institute</a> estima, com base em 25 anos de dados, que erro humano tem algum papel em algo entre dois terços e quatro quintos de todos os outages. Repara na palavra que eles escolheram, porque ela é honesta: "algum papel". Erro humano raramente aparece como causa raiz sozinho, ele é o fio que atravessa o incidente. E o pedaço mais teimoso é sempre o mesmo: gente não seguindo o procedimento, ou o procedimento já nascendo ruim. Adivinha o quanto trocar de fornecedor ajuda nisso? Nada.</p>
<p>E aí mora a piada: se tem uma coisa que a cultura DevOps entregou com maestria nesses anos todos, é a capacidade de propagar besteira em segundos, com pipeline verde, aprovação de dois reviewers e um emoji de foguete no canal. Automatizamos tudo, inclusive o erro. Só que agora, com duas clouds, ele chega nos dois lugares ao mesmo tempo e você paga em dobro pelo privilégio. Deploy é a coisa mais confiável da sua stack, e é justamente por isso que ele leva a config errada aos dois destinos sem falhar nenhuma vez.</p>
<img src="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/1243a766-5bd1-4f0c-af14-8e0b6f6dc872.png" alt="Independência é ficção: pipeline de deploy, DNS, autoridade certificadora e provedor de identidade são compartilhados e entregam a mesma config errada nas duas clouds ao mesmo tempo" style="display:block;margin:0 auto" />

<p>Falha correlacionada quebra a premissa de independência, e sem independência a conta do paralelo simplesmente não existe.</p>
<h2>O preço escondido: o menor denominador comum</h2>
<p>Para rodar de verdade em AWS e Google ao mesmo tempo, em active-active, você precisa de tudo portável entre as duas. Aí você abre mão dos managed services que são a parte mais resiliente da cloud (DynamoDB, S3, SQS, testados em escala absurda) e cai no que roda em qualquer lugar: Kubernetes e um monte de open source que VOCÊ instala, opera e mantém de pé.</p>
<p>E olha que esse dilema não é abstrato, eu já destrinchei um caso dele. No post de <a href="https://willpeixoto.dev/data-streaming-na-aws-kinesis-firehose-flink-msk">data streaming na AWS</a>, a escolha entre Kinesis e MSK é exatamente essa: o nativo que casa com o resto da casa contra o Kafka que roda em qualquer lugar. Lá a portabilidade é uma escolha legítima, feita de olhos abertos, num serviço só, porque o time já vive de Kafka. Aqui no active-active ela deixa de ser escolha e vira imposição, de uma vez, em cima da stack inteira.</p>
<p>E aqui vai uma pergunta desconfortável, sem desmerecer ninguém: a sua equipe opera esse stack com mais confiabilidade do que a AWS opera o DynamoDB? O time que segura esses managed services em escala global é enorme, dedicado e faz só isso há mais de uma década. Apostar que o seu time, dividido entre mil prioridades, entrega mais uptime na unha do que eles entregam gerenciado é uma aposta e tanto. Longe de julgar a competência de ninguém, é só o paralelo de quem está na arena contra quem fez disso a vida inteira.</p>
<p>Você trocou resiliência gerenciada por resiliência que virou o seu celular tocando às 3 da manhã. Como o Werner Vogels martela, "everything fails, all the time". Então a pergunta que importa vira outra: quem está de plantão quando falhar? O multi-cloud active-active coloca você nesse plantão, em dobro. E repara que não basta ter alguém que saiba AWS de um lado e alguém que saiba Google Cloud do outro. Alguém precisa dominar justamente a cola entre as duas, aquela peça que só existe dentro da sua empresa, que não tem botão de suporte, não tem tutorial pronto e não tem ninguém no Stack Overflow que já passou por isso. Plantão custa, e esse plantão custa mais ainda. É uma linha gorda na conta que raramente aparece no business case.</p>
<h2>E o custo? Você paga para o dado sair, dos dois lados</h2>
<p>Tem um item que a planilha do projeto costuma ignorar: egress. A cloud cobra barato (ou de graça) para o dado entrar, e cobra para o dado sair. Num active-active de verdade, você vive sincronizando dados entre AWS e Google para manter as duas pontas iguais, então paga data transfer out dos dois lados, o tempo todo, só para manter as cópias coerentes. É uma torneira aberta, todo mês, para sempre.</p>
<p>Já ouço a objeção: "mas o egress ficou de graça em 2024". Cuidado com essa. O que <a href="https://aws.amazon.com/blogs/aws/free-data-transfer-out-to-internet-when-moving-out-of-aws/">AWS</a>, <a href="https://cloud.google.com/exit-cloud">Google</a> e Microsoft passaram a zerar naquele ano, empurrados pelo EU Data Act, é o egress de quem está <strong>indo embora</strong> da cloud, <code>e mesmo assim com regras que variam por provedor: você leva tudo, passa pelo suporte, e no Google e na Microsoft ainda precisa encerrar a conta ou cancelar as subscriptions dentro do prazo (a AWS, notavelmente, não incluiu essa exigência)</code>. Isso é um subsídio de divórcio, não de casamento aberto. A replicação contínua entre duas clouds, que é justo o que o active-active exige, continua passando no caixa todo mês.</p>
<p>E soma o resto: você duplica os managed services, duplica a stack de observability, duplica a superfície de security e compliance, e precisa de um time com profundidade nas duas clouds. O custo não dobra, ele faz mais que dobrar, porque a cola que integra as duas é um centro de custo por si só.</p>
<p>O Werner Vogels resume isso no <a href="https://thefrugalarchitect.com/">Frugal Architect</a>: custo é requisito de arquitetura, e quem só descobre o número na fatura descobriu tarde demais. Multi-cloud quase sempre reprova nesse teste, você paga uma conta contínua e gorda por um seguro contra um evento que quase nunca acontece.</p>
<p>E deixa eu confessar uma coisa. Toda vez que esse slide aparece numa reunião, tem um arquiteto em algum canto da sala com vontade de deitar em posição fetal embaixo da mesa (assim como eu). Enquanto todo mundo comemora a decisão corajosa, ele está fazendo a conta de cabeça e vendo o tanto de dinheiro que vai ser queimado para comprar proteção contra um evento raro, dinheiro esse que resolveria, sei lá, a multi-região que a empresa adia há dois anos. Se você é essa pessoa, respira: esse post é o teu argumento por escrito, com a conta na mão. E se você é quem está aprovando o projeto, olha de novo para os números lá de cima antes de assinar.</p>
<p>E antes que alguém feche a aba com raiva: calma, eu não estou dizendo que multi-cloud nunca presta. Existe hora em que ele é a resposta certa, e eu tenho uma seção inteira sobre isso mais para o fim. Só que essa hora tem nome, tem contexto e quase nunca é "resiliência". Segura a emoção que a gente chega lá.</p>
<h2>O que o multi-cloud protege, e que quase nunca acontece</h2>
<p>Pensa nos apagões reais que você viu. Foram regionais, zonais ou de um serviço específico (o us-east-1 de outubro de 2025 foi exatamente isso). Quase nunca é "a AWS global inteira morreu". Quem ficou fora do ar naquele dia estava preso a uma única região, e o que teria segurado a maioria era multi-região na mesma cloud, não uma segunda nuvem. Multi-AZ e multi-região dentro da MESMA cloud cobrem a esmagadora maioria dos casos, com uma fração da complexidade. E olha que nem sou eu dizendo: a <a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/aws-multi-region-fundamentals/fundamental-1.html">própria orientação de multi-region da AWS</a> recomenda confirmar que os seus objetivos não cabem dentro de uma região só antes de partir para várias.</p>
<p>Então vamos fazer a lição de casa antes de desenhar duas clouds no quadro: Multi-AZ resolve? Multi-região resolve? Ou a gente está fazendo overengineering para comprar uma sensação de segurança? Quanto custa cada um desses degraus, e por que essa conta é decisão de negócio antes de ser de tecnologia, eu abri no <a href="https://willpeixoto.dev/resiliencia-custo-ha-multi-regiao-ou-on-premise">post sobre o custo da alta disponibilidade</a>. Se o requisito cabe dentro de uma cloud, botar um segundo fornecedor não é maturidade automática. Às vezes é só complexidade usando roupa social.</p>
<p>Isso tem nome de pattern: Bulkhead e <a href="https://docs.aws.amazon.com/wellarchitected/latest/reducing-scope-of-impact-with-cell-based-architecture/reducing-scope-of-impact-with-cell-based-architecture.html">cell-based architecture</a>, isolar o blast radius dentro do próprio fornecedor, em compartimentos que não afundam juntos. O multi-cloud te protege contra o evento raríssimo (o provedor inteiro sumir do mapa) e, em troca, te expõe a uma porção de falhas comuns que você mesmo introduziu.</p>
<p>E antes que eu te venda multi-região como bala de prata, a letra miúda: naquele mesmo apagão, muita arquitetura multi-região caiu junto, porque dependia de control plane global (IAM, STS) ou tinha uma dependência escondida em us-east-1 que ninguém tinha mapeado. Isso não é teoria: o <a href="https://aws.amazon.com/message/101925/">post-event summary da própria AWS</a> registra que o STS engasgou, e que quem usava federação de identidade apontando para signin.aws.amazon.com tomou erro no console <strong>em outras regiões também</strong>. Remédio nenhum vem sem bula. A diferença é que a bula da multi-região cabe num parágrafo e a do multi-cloud active-active é um projeto de dois anos.</p>
<h2>O caso Snap: multi-cloud no papel, tombo na prática</h2>
<p>Prometi voltar na Snap, então vamos lá.</p>
<p>Ela fez exatamente o que todo board sonha: assinou com as duas. Google Cloud como principal, e no S-1 do IPO em 2017 apareceu um <a href="https://www.geekwire.com/2017/snap-commits-spend-1b-amazon-web-services-next-five-years/">compromisso de um bilhão de dólares com a AWS</a>, com a frase que todo executivo adora ler, "for redundant infrastructure support of our business operations". Multi-cloud de livro, as duas maiores nuvens do planeta na mesma fatura.</p>
<p>Aí, em 20 de outubro de 2025, o us-east-1 da AWS engasgou. E o <a href="https://www.nbcnews.com/news/us-news/amazon-web-services-outage-websites-offline-rcna238594">Snapchat caiu</a> junto com o resto da internet.</p>
<p>E o resto da história está escrito pela própria Snap. Ano após ano, na seção de risco dos relatórios que ela manda para o mercado, aparece o aviso de que os sistemas dela <strong>não são totalmente redundantes</strong>. Repara na data: esse alerta já estava lá muito antes do tombo, na mesma pilha de papel em que o contrato bilionário dizia "redundant". Ninguém escreveu aquilo depois, para se explicar. A redundância existia no contrato e no slide do investidor. No caminho crítico da aplicação, não.</p>
<p>Esse é o soco do argumento, e ele vale para qualquer empresa, não só para a Snap: duas clouds na fatura não te dão duas clouds na arquitetura. Se o caminho crítico depende de uma região que caiu, o contrato com o outro fornecedor guardado na gaveta não levanta o seu serviço. E se nem uma empresa desse tamanho, com bilhões alocados e times de elite, transformou dois contratos em redundância real, vale a pergunta desconfortável: por que o seu projeto transformaria?</p>
<h2>Mas e se eu já tiver o failover pronto para a outra cloud?</h2>
<p>Aqui o leitor atento levanta a mão: "beleza, mas se a cloud A cair e eu tiver o DR pronto para virar na B, o multi-cloud me salvou, não?". Pode salvar, sim. E repara que esse cenário é active-passive (uma cloud quente, a outra de prontidão), não o active-active que a conta lá em cima destrói. São coisas diferentes, e essa é a versão legítima da história.</p>
<p>Só que três pegadinhas derrubam o "eu tenho o failover" na prática.</p>
<p>A primeira: ter o failover não é o mesmo que o failover funcionar. O caminho de DR é o trecho menos testado do seu sistema, e você só aciona ele no pior momento, sob pressão. DR que nunca foi exercitado é backup de Schrödinger, você descobre se presta na hora que precisa. É o filme clássico do DR não testado: na hora de virar a chave, a capacidade não está provisionada do outro lado, os secrets estão dessincronizados, o IAM é diferente. O plano existia, o failover não veio.</p>
<p>A segunda: o failover demora e você perde dado no caminho. Replicação síncrona entre duas clouds (aquela em que a escrita só é confirmada depois que chegou nos dois lados) é cara e lenta demais, então na prática todo mundo usa assíncrona: a cloud A confirma a escrita para o usuário e manda a cópia para a B logo depois, com um atraso de alguns segundos.</p>
<p>Repara no buraco que isso abre. Se a A cai justo naquele intervalo, tudo que ela confirmou e ainda não tinha copiado para a B some. O pedido que o cliente viu na tela, o pagamento que apareceu como aprovado, simplesmente não existe do outro lado. Esse é o tal do RPO (Recovery Point Objective), o quanto de dado você aceita perder, medido em tempo. E tem o RTO (Recovery Time Objective), o tempo até o serviço voltar, que no cross-cloud vai de minutos a horas: subir o lado passivo, propagar DNS, esquentar cache. Não é apertar um botão.</p>
<p>A terceira: para o apagão que de fato acontece, multi-região na mesma cloud entrega o mesmo DR sem a dor cross-cloud. O us-east-1 caiu, não a AWS global. Um Warm Standby ou um Pilot Light em outra região da mesma cloud te levanta com os managed services nativos, o mesmo IAM e a mesma tooling (a AWS documenta as quatro estratégias, com os RTOs e os custos de cada uma, no <a href="https://docs.aws.amazon.com/whitepapers/latest/disaster-recovery-workloads-on-aws/disaster-recovery-options-in-the-cloud.html">whitepaper de Disaster Recovery</a>). No cross-cloud você joga tudo isso fora para se proteger de um evento bem mais raro.</p>
<p>Ou seja: failover cross-cloud pode existir e até funcionar, mas é caro, frágil quando não é testado, e quase sempre perde para multi-região na mesma cloud no tipo de apagão que realmente bate na porta.</p>
<h2>Então multi-cloud nunca presta?</h2>
<p>Presta. Só que quase nunca por resiliência técnica, e é aqui que a maioria erra o argumento. Multi-cloud se justifica por motivos de negócio:</p>
<ul>
<li><p>Soberania de dados e regulação: a lei manda o dado morar em tal nuvem ou país.</p>
</li>
<li><p>Alavanca contra vendor lock-in: poder de barganha comercial (o uptime nem entra nessa conta).</p>
</li>
<li><p>SaaS que precisa rodar onde o cliente exige.</p>
</li>
<li><p>DR exigido por compliance, às vezes existindo só no papel para passar na auditoria, não porque a arquitetura faz failover de verdade.</p>
</li>
</ul>
<p>E repare que, quando vale, quase sempre é active-passive (uma cloud quente, outra fria só para disaster recovery), não o active-active que detona a sua disponibilidade. A decisão é de negócio e risco, registrada num ADR, sem nenhuma promessa de nove extra.</p>
<p>Já que a gente chegou até aqui, deixa eu cravar a minha posição, e ela é uma opinião, não um teorema. Toda decisão de arquitetura tem dois lados, e a pergunta que resolve essa aqui não é técnica: qual é a sua dor de verdade e quanto ela custa se acontecer? Se a resposta vem do regulador, do contrato ou da soberania de dado, multi-cloud entra, geralmente active-passive, e o ROI justifica a complexidade. Fora disso, para mim, active-active dói no peito: você compra dois navios, uma ponte, um plantão em dobro e um capitão sobrecarregado para se proteger de um evento que provavelmente não vem, enquanto a multi-região que resolveria o seu caso real segue esperando budget. Resiliência não é o que você compra. É o que você decide, e depois sustenta.</p>
<p>Esse é o coração do <a href="https://willpeixoto.dev/resiliencia-custo-ha-multi-regiao-ou-on-premise">post sobre o custo da alta disponibilidade</a>: resiliência começa numa decisão estratégica, e o stack vem depois, como consequência. Multi-cloud é o jeito mais caro que existe de inverter essa ordem.</p>
<h2>O que você leva</h2>
<ul>
<li><p>A conta do paralelo (99,9999%) só vale para sistemas suficientes, independentes e realmente paralelos. Roteamento global, consistência síncrona e identidade compartilhada entram em série e derrubam o número para baixo do que uma cloud só entrega.</p>
</li>
<li><p>Replicação assíncrona sai da conta de uptime e reaparece no RPO: o serviço continua de pé e engole as últimas escritas.</p>
</li>
<li><p>Falha correlacionada (config, deploy, DNS, CA) quebra a premissa de independência que a conta exige.</p>
</li>
<li><p>Active-active força o menor denominador comum: você troca managed service maduro por stack que vira o seu plantão.</p>
</li>
<li><p>O custo não dobra, faz mais que dobrar: egress dos dois lados para sincronizar dados, infra duplicada e time com profundidade em duas clouds.</p>
</li>
<li><p>Multi-AZ e multi-região na mesma cloud (Bulkhead, cells) resolvem o caso real com uma fração da complexidade.</p>
</li>
<li><p>Multi-cloud vale por negócio (regulatório, lock-in), não por resiliência. E aí é active-passive, documentado num ADR.</p>
</li>
</ul>
<p>Pergunta sincera para você: já foi obrigado a um projeto de multi-cloud "por resiliência" e descobriu na prática que ganhou dois plantões no lugar de um? Conta aí como foi. E se você discorda, melhor ainda, joga a sua conta de disponibilidade nos comentários que eu quero ver onde a minha fura. Manda aquele joinha, compartilha com quem está prestes a aprovar esse projeto, e bora trocar ideia. Valeu demais! BUILD. SCALE. REPEAT. =D</p>
<h2>Para ir mais fundo</h2>
<p>As fontes que valem a sua próxima meia hora (as outras estão linkadas ao longo do texto, no ponto onde importam):</p>
<ul>
<li><p><a href="https://aws.amazon.com/builders-library/static-stability-using-availability-zones/">Static stability using Availability Zones</a>, na Amazon Builders' Library. A fonte do conceito que tira o control plane do caminho do request, com a separação control plane x data plane explicada por quem construiu o EC2.</p>
</li>
<li><p><a href="https://docs.aws.amazon.com/whitepapers/latest/disaster-recovery-workloads-on-aws/disaster-recovery-options-in-the-cloud.html">Disaster recovery options in the cloud</a>, do whitepaper de DR da AWS. Pilot Light, Warm Standby e a nota que explica a diferença entre os dois. É a alternativa que resolve o seu caso real sem cross-cloud.</p>
</li>
<li><p><a href="https://aws.amazon.com/message/101925">Post-event summary do apagão de outubro de 2025</a>, pela própria AWS. A race condition no DNS do DynamoDB e o efeito cascata: a fonte primária do caso que abre este post.</p>
</li>
<li><p><a href="https://thefrugalarchitect.com/">The Frugal Architect</a>, do Werner Vogels. A lei I é "Make Cost a Non-functional Requirement", e é o teste que o multi-cloud reprova.</p>
</li>
<li><p><a href="https://willpeixoto.dev/resiliencia-custo-ha-multi-regiao-ou-on-premise">Resiliência em arquitetura: a decisão é estratégica, não apenas técnica</a>, aqui do blog. O pillar deste post: o custo dos noves, RTO/RPO e ADRs.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Data Streaming na AWS: Kinesis, Firehose, Flink ou MSK?]]></title><description><![CDATA[Tem um tipo de dado que não pode esperar. A transação suspeita que precisa ser barrada agora, não amanhã no relatório. O clique do usuário que, se você lê na hora, vira recomendação certeira, e se lê ]]></description><link>https://willpeixoto.dev/data-streaming-na-aws-kinesis-firehose-flink-msk</link><guid isPermaLink="true">https://willpeixoto.dev/data-streaming-na-aws-kinesis-firehose-flink-msk</guid><category><![CDATA[AWS]]></category><category><![CDATA[data streaming]]></category><category><![CDATA[streaming]]></category><category><![CDATA[Kinesis]]></category><category><![CDATA[kafka]]></category><category><![CDATA[architecture]]></category><dc:creator><![CDATA[Willian Peixoto]]></dc:creator><pubDate>Fri, 26 Jun 2026 19:20:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/21e70b06-f3b4-4561-b892-2c81d17f2e7d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Tem um tipo de dado que não pode esperar. A transação suspeita que precisa ser barrada agora, não amanhã no relatório. O clique do usuário que, se você lê na hora, vira recomendação certeira, e se lê depois, vira oportunidade perdida. Por muito tempo a gente tratou tudo igual: junta um monte de dado, guarda num banco, e processa em lote mais tarde. Só que tem coisa que vive no agora.</p>
<p>A imagem que me ajuda a explicar isso é a de um rio. Repara que a água não para pra ser usada. Ela passa, e quem está na margem aproveita no caminho: um move a roda do moinho, outro irriga a plantação, outro gera energia. Ninguém represa tudo primeiro pra só então usar. Agora troca a água por dado e você tem data streaming: a informação chega num fluxo contínuo e você reage no instante em que ela passa, em vez de empilhar tudo pra processar lá na frente.</p>
<p>É essa diferença que separa reagir de só descobrir depois. Um banco que barra a fraude no segundo da transação, um e-commerce que recomenda no clique, uma fábrica que ajusta a máquina antes de ela quebrar: em todos, processar depois é quase não processar, porque quando o batch da meia-noite roda o momento já passou.</p>
<p>Só que "streaming na AWS" confunde, porque são quatro serviços de nomes parecidos e até gente boa erra qual usar. Vem comigo que eu separo.</p>
<blockquote>
<p><strong>Nota de validade:</strong> escrevi este guia em junho de 2026 e revisei em julho de 2026 (a conta já inclui o On-demand Advantage e uma correção importante sobre ordenação). Serviço de streaming muda rápido: modo, quota e preço. Vou manter o post em dia, mas se algo não bater com a tela na tua frente, confere a <a href="https://docs.aws.amazon.com/streams/latest/dev/introduction.html">doc oficial do Kinesis</a> e me avisa nos comentários que eu corrijo.</p>
</blockquote>
<h2>Antes do serviço, o conceito: stream ou batch</h2>
<p>Batch é juntar um monte de dado e processar de tempos em tempos, tipo o relatório que roda de madrugada. Streaming é processar evento a evento, conforme chega. Não competem: cada um resolve um tipo de problema. Fechamento contábil do mês é batch e está ótimo. Alerta de fraude é streaming, porque um minuto de atraso já é dinheiro perdido. O erro é usar batch onde o negócio precisa reagir na hora.</p>
<h2>O mapa: os quatro serviços (e o que cada um faz de verdade)</h2>
<p>Antes de entrar em cada um, dois avisos que evitam confusão. Primeiro, a AWS <strong>renomeou</strong> dois serviços: o <strong>Kinesis Data Firehose</strong> virou <strong>Amazon Data Firehose</strong> (fev/2024) e o <strong>Kinesis Data Analytics</strong> virou <strong>Amazon Managed Service for Apache Flink</strong> (ago/2023). Se você achar tutorial com o nome antigo, é o mesmo serviço, só trocou a placa. E o Data Streams ganhou um modo novo, o <strong>On-demand Advantage</strong>, que eu explico já já.</p>
<p>Segundo, pra quem vem do Kafka: o que lá é <strong>topic</strong>, aqui no Kinesis é <strong>stream</strong>; o que lá é <strong>partition</strong>, aqui é <strong>shard</strong>. O mapa ajuda, mas não é idêntico: a <code>PartitionKey</code> do Kinesis passa por um hash que escolhe o shard, então várias chaves diferentes podem dividir o mesmo shard. Daqui pra frente eu uso o nome certo de cada serviço, mas saiba que os dois mundos se espelham.</p>
<img src="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/79b54b09-9e82-40cb-a658-abb20264f673.png" alt="Pipeline de Data Streaming na AWS: produtores enviam eventos pro Kinesis Data Streams, que alimenta um consumer Lambda em tempo real, o Amazon Data Firehose entregando no S3 e o Managed Service for Apache Flink processando pra um dashboard; o Amazon MSK aparece como entrada alternativa." style="display:block;margin:0 auto" />

<h3>Kinesis Data Streams: o rio que você pode reler</h3>
<p>É o coração da história. O stream (o topic, lembra?) é durável: produtores escrevem, consumidores leem, e o dado fica retido por um tempo (até 365 dias), então dá pra reprocessar. É o "log" do rio. Use quando você precisa de um stream durável, com replay, e vai construir o consumer (uma Lambda, ou um app com a Kinesis Client Library, a KCL, que cuida da distribuição de shards e do checkpoint pra você). A capacidade vem dividida em <strong>shards</strong> (as partitions), cada um com um teto de escrita e leitura, e você escolhe entre três modos de capacidade:</p>
<ul>
<li><p><strong>Provisioned:</strong> você define o número de shards e paga por eles, ligados ou não.</p>
</li>
<li><p><strong>On-demand:</strong> a AWS gerencia os shards sozinha e você paga pelo throughput que usa.</p>
</li>
<li><p><strong>On-demand Advantage</strong> (o mais novo): traz warm throughput, com capacidade instantânea pra picos, até 10 GiB/s. Um detalhe que a página de vendas não grita: é um modo de billing da CONTA, com compromisso mínimo de uso (25 MiB/s por pelo menos 24h, cobrado mesmo que você use menos). Em troca, o throughput sai 60%+ mais barato e some a cobrança por stream-hora. Faz sentido a partir de volume de verdade; pro stream pequeno, fica nos dois primeiros modos.</p>
</li>
</ul>
<h3>Amazon Data Firehose: só me entrega num destino</h3>
<p>Esse foi renomeado de Kinesis Data Firehose em 2024, mesma coisa, nome novo. Aqui você não escreve consumer, é o papel que o Kafka Connect faz no mundo Kafka (os sink connectors). Você aponta uma fonte e um destino (S3, OpenSearch, Redshift e outros) e o Firehose entrega, com buffering, transformação opcional e compressão no caminho. Não tem replay, é entrega quase em tempo real. Use quando o objetivo é pegar o stream e jogar num lugar, sem lógica de consumo própria.</p>
<h3>Managed Service for Apache Flink: processamento COM estado</h3>
<p>Esse era o Kinesis Data Analytics, renomeado em 2023. Roda Apache Flink gerenciado pra processamento com estado, o que o Kafka Streams ou o ksqlDB fazem no mundo Kafka: janelas (somar por minuto), joins entre streams, e exactly-once na recuperação do estado. Quando a pergunta é "qual a média móvel dos últimos 5 minutos por usuário", a resposta mora aqui. A infraestrutura de estado, checkpoint e recuperação é responsabilidade do serviço; a semântica de ponta a ponta (o que os teus sources e sinks garantem) e a compatibilidade do estado entre versões continuam sendo decisões suas.</p>
<h3>Amazon MSK (e MSK Serverless): Kafka gerenciado</h3>
<p>Se o teu mundo já é Kafka (ecossistema, Kafka API, portabilidade entre nuvens, time que manja), o MSK é o Kafka gerenciado da AWS. O MSK Serverless provisiona e escala a capacidade sozinho e gerencia as partições do topic, sem você dimensionar cluster. Use quando você precisa do Kafka de verdade, não de um equivalente nativo.</p>
<h2>Quando usar cada um</h2>
<table>
<thead>
<tr>
<th>Você quer...</th>
<th>Serviço AWS</th>
<th>Equivalente no Kafka</th>
</tr>
</thead>
<tbody><tr>
<td>stream durável e replayável, com consumer seu</td>
<td>Kinesis Data Streams</td>
<td>Apache Kafka (Amazon MSK)</td>
</tr>
<tr>
<td>só entregar o stream num destino, sem escrever código</td>
<td>Amazon Data Firehose</td>
<td>Kafka Connect (sink)</td>
</tr>
<tr>
<td>processamento com estado (janela, join, agregação)</td>
<td>Managed Service for Apache Flink</td>
<td>Kafka Streams / ksqlDB</td>
</tr>
</tbody></table>
<p>Na vida real, muita arquitetura combina esses serviços em três camadas: entrada, entrega e processamento. Data Streams na entrada, Firehose entregando uma cópia crua no S3 pra histórico, e Flink processando em tempo real pra dashboard. E a entrada não precisa ser o Data Streams: dá pra ter MSK na frente e o Flink depois, porque o Managed Flink lê tanto do Kinesis quanto do MSK.</p>
<h2>Mão na massa: produtor e consumidor no Kinesis Data Streams</h2>
<p>O produtor escreve eventos no stream. Repara na <code>PartitionKey</code>: ela passa por um hash que decide em qual shard o registro cai. Mesma chave, mesmo shard, e o shard é o território onde a ordem pode existir.</p>
<pre><code class="language-js">import { KinesisClient, PutRecordsCommand } from "@aws-sdk/client-kinesis";

const kinesis = new KinesisClient({});

await kinesis.send(new PutRecordsCommand({
  StreamName: "eventos-clientes",
  Records: [
    {
      Data: Buffer.from(JSON.stringify({ userId: "u-42", evento: "clique", ts: Date.now() })),
      PartitionKey: "u-42", // mesma chave = mesmo shard (o territorio da ordem)
    },
  ],
}));
</code></pre>
<p>Agora a pegadinha que quase todo mundo descobre tarde, eu incluso: <strong>o</strong> <code>PutRecords</code><strong>, esse de lote, não garante a ordem</strong>. Nem com a mesma chave. Ele processa cada registro individualmente, aceita sucesso parcial (metade do lote entra, metade falha e você reenvia), e a <a href="https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecords.html">doc é explícita</a>: se você precisa ler na ordem em que escreveu, o caminho é o <code>PutRecord</code> no singular, serial, encadeando o <code>SequenceNumberForOrdering</code> de cada escrita na seguinte:</p>
<pre><code class="language-js">import { KinesisClient, PutRecordCommand } from "@aws-sdk/client-kinesis";

const kinesis = new KinesisClient({});

const putEvento = async (payload, sequenciaAnterior) =&gt;
  kinesis.send(new PutRecordCommand({
    StreamName: "eventos-clientes",
    PartitionKey: payload.userId, // mesma entidade, mesmo shard
    Data: Buffer.from(JSON.stringify(payload)),
    // encadeia a escrita anterior: e isso que garante a sequencia
    ...(sequenciaAnterior ? { SequenceNumberForOrdering: sequenciaAnterior } : {}),
  }));

const login = await putEvento({ userId: "u-42", evento: "login" });
await putEvento({ userId: "u-42", evento: "compra" }, login.SequenceNumber);
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/962c8710-392d-4e8c-8ce7-167f49807b27.png" alt="A ordem vive dentro do shard: a PartitionKey passa pelo hash e escolhe o shard; eventos da mesma chave ficam em sequência no mesmo shard; entre shards não existe ordem global. PutRecords de lote não garante ordem, ordem estrita pede PutRecord serial encadeado." style="display:block;margin:0 auto" />

<p>Com isso o consumidor sempre vê "login" antes de "compra". O preço é honesto: você trocou o throughput do lote pela garantia de sequência. Se são milhares de eventos por segundo e a ordem estrita não é requisito, o <code>PutRecords</code> é a escolha certa. A garantia que você pede muda a conta que você paga; arquitetura é isso.</p>
<p>Do lado de lá, o consumidor serverless é uma Lambda com event source mapping no stream. E aqui vai a segunda verdade que separa exemplo de blog de código de produção: a entrega é <strong>at-least-once</strong>, o mesmo evento pode chegar duas vezes. Então o handler precisa ser idempotente e saber falhar por item, sem derrubar o lote inteiro:</p>
<pre><code class="language-js">export const handler = async (event) =&gt; {
  const batchItemFailures = [];

  for (const record of event.Records) {
    try {
      const payload = JSON.parse(Buffer.from(record.kinesis.data, "base64").toString("utf8"));

      // Em producao: consulte e grave um eventId num store idempotente
      // ANTES do efeito colateral. Duplicata processada duas vezes = cliente cobrado duas vezes.
      console.log(payload.userId, payload.evento);
    } catch (error) {
      // falha SO este item; o resto do lote segue
      batchItemFailures.push({ itemIdentifier: record.kinesis.sequenceNumber });
    }
  }

  return { batchItemFailures };
};
</code></pre>
<p>O retorno de falhas parciais só tem efeito com <code>ReportBatchItemFailures</code> ligado no event source mapping. E pra produção de verdade eu ainda colocaria idempotência persistente, Logger e Metrics do <a href="https://docs.powertools.aws.dev/lambda/typescript/latest/">AWS Lambda Powertools</a>, limite de retries, idade máxima do registro e um destination pra falha. Um poison record não pode travar o shard pra sempre.</p>
<p>Um detalhe pra fechar: a <strong>ordem é por shard</strong>, não no stream inteiro. Se a ordem importa pra uma entidade (um usuário, um pedido), a chave é a dessa entidade. Senão, os eventos espalham pelos shards e a ordem global vira ilusão.</p>
<h2>Os trade-offs honestos</h2>
<ul>
<li><p><strong>Ordenação e escala:</strong> a ordem é por shard, não global, e ordem estrita pede <code>PutRecord</code> serial (o lote não garante). A escolha da partition key não é um detalhe, é uma decisão de design que define como a sua aplicação se comporta E como ela escala. Chave enviesada joga tráfego demais num shard só (o hot shard) e você perde throughput mesmo pagando por vários; e cada partition key aguenta no máximo 1 MiB/s, não importa o warm throughput que você configurou. Isso sozinho rende um post inteiro, e vai ter.</p>
</li>
<li><p><strong>Duplicata e observabilidade:</strong> a entrega é at-least-once, então replay e retry exigem consumer idempotente; reprocessar um evento que cobra o cliente duas vezes só troca um incidente por outro. E consumer lag precisa de alarme: streaming sem observabilidade vira batch acidental, o evento chega agora e o consumer processa meia hora depois. O Well-Architected dá nome a essas contas: Reliability pede idempotência e recuperação, Operational Excellence pede métrica e alarme, Cost Optimization pede modo de capacidade que siga o tráfego real, não a esperança do time.</p>
</li>
<li><p><strong>Retenção e replay:</strong> Data Streams retém e deixa reprocessar; Firehose não, ele entrega e segue.</p>
</li>
<li><p><strong>Custo:</strong> provisioned paga shard mesmo parado; on-demand paga uma taxa por stream-hora mais o uso. Stream ligado 24/7 com tráfego previsível às vezes sai mais barato provisionado. Custo é decisão de arquitetura, como o Werner Vogels martela no Frugal Architect, e é o mesmo papo de <a href="https://willpeixoto.dev/resiliencia-custo-ha-multi-regiao-ou-on-premise">disponibilidade tem um preço</a>.</p>
</li>
<li><p><strong>Latência:</strong> streaming é baixa, mas não é zero. O Firehose ainda tem buffering (de segundos a minutos), então não conte com ele pra reação instantânea.</p>
</li>
</ul>
<h2>Kinesis ou MSK?</h2>
<p>Se você não tem compromisso com Kafka, o Kinesis é mais simples e nativo, casa melhor com Lambda e o resto do serverless. Se você já vive de Kafka (conectores, ferramentas, multi-cloud, time treinado), o MSK te dá o Kafka sem você operar o cluster na unha. A escolha é de contexto e ecossistema; "qual é o melhor" é a pergunta errada.</p>
<h2>O que você leva</h2>
<ul>
<li><p>Data streaming é processar no fluxo, em tempo real, pra reagir no momento (fraude, recomendação, IoT). Batch é pra quando o atraso não dói.</p>
</li>
<li><p>Kinesis Data Streams é o stream durável e replayável; Amazon Data Firehose entrega num destino; Managed Service for Apache Flink faz processamento com estado; MSK é Kafka gerenciado.</p>
</li>
<li><p>A ordem é por shard, então escolha a partition key com intenção. E ordem ESTRITA pede <code>PutRecord</code> serial com <code>SequenceNumberForOrdering</code>: o <code>PutRecords</code> de lote não garante.</p>
</li>
<li><p>Lambda com Kinesis é at-least-once: idempotência e falha por item (<code>batchItemFailures</code>) fazem parte do desenho, não são luxo.</p>
</li>
<li><p>Provisioned ou on-demand é decisão de custo, e arquitetura real combina os serviços em vez de escolher um só.</p>
</li>
</ul>
<h2>Sua vez</h2>
<p>Você usa streaming em algum projeto? Conta qual desses quatro entrou no teu desenho, e se já te queimou escolher o errado. Manda aquele joinha, compartilha com quem ainda processa tudo no batch da meia-noite, e bora trocar ideia. Valeu demais!</p>
<p>BUILD. SCALE. REPEAT. =D</p>
<h2>Fontes</h2>
<ul>
<li><p><a href="https://aws.amazon.com/kinesis/data-streams/faqs/">Amazon Kinesis Data Streams (FAQs)</a></p>
</li>
<li><p><a href="https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecords.html">PutRecords não garante ordenação (API Reference)</a></p>
</li>
<li><p><a href="https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecord.html">PutRecord e SequenceNumberForOrdering (API Reference)</a></p>
</li>
<li><p><a href="https://docs.aws.amazon.com/lambda/latest/dg/services-kinesis-batchfailurereporting.html">Lambda com Kinesis: falhas parciais (ReportBatchItemFailures)</a></p>
</li>
<li><p><a href="https://aws.amazon.com/blogs/big-data/amazon-kinesis-data-streams-launches-on-demand-advantage-for-instant-throughput-increases-and-streaming-at-scale/">Kinesis Data Streams On-demand Advantage</a></p>
</li>
<li><p><a href="https://docs.aws.amazon.com/managed-flink/latest/java/how-fault.html">Fault tolerance no Managed Service for Apache Flink</a></p>
</li>
<li><p><a href="https://aws.amazon.com/blogs/aws/announcing-amazon-managed-service-for-apache-flink-renamed-from-amazon-kinesis-data-analytics/">Amazon Managed Service for Apache Flink (renomeação)</a></p>
</li>
<li><p><a href="https://aws.amazon.com/blogs/machine-learning/category/analytics/amazon-kinesis/amazon-data-firehose/">Amazon Data Firehose</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[AWS Lambda MicroVMs: run untrusted code with VM-level isolation (no infra to manage)]]></title><description><![CDATA[🇧🇷 Leia em português.
Let me put you in a situation. You need to run a piece of code you did not write. Maybe it is the script your user pasted into your platform, maybe it is the snippet an AI agen]]></description><link>https://willpeixoto.dev/aws-lambda-microvms-untrusted-code-isolation</link><guid isPermaLink="true">https://willpeixoto.dev/aws-lambda-microvms-untrusted-code-isolation</guid><category><![CDATA[AWS]]></category><category><![CDATA[aws lambda]]></category><category><![CDATA[serverless]]></category><category><![CDATA[firecracker]]></category><category><![CDATA[microvm]]></category><category><![CDATA[AI]]></category><dc:creator><![CDATA[Willian Peixoto]]></dc:creator><pubDate>Wed, 24 Jun 2026 03:50:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/c7c831bc-2ddc-458b-813e-d5ec4f8c2869.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>🇧🇷</em> <a href="https://willpeixoto.dev/aws-lambda-microvms-codigo-isolado-serverless"><em>Leia em português</em></a><em>.</em></p>
<p>Let me put you in a situation. You need to run a piece of code you did not write. Maybe it is the script your user pasted into your platform, maybe it is the snippet an AI agent just generated and wants to execute. And then comes the question that keeps anyone working with multi-tenant up at night: how do I run this without handing a stranger the keys to the house?</p>
<p>Until last week you had three paths, each with a catch. A VM gives you strong isolation but takes minutes to boot. A container starts in seconds but shares a kernel, so running untrusted code there takes a pile of hardening. And the Lambda Function was built for short request-response, not for a session that has to keep live state between one interaction and the next (externalizing it to DynamoDB stores the data, not the live runtime: the running process, the loaded packages, the memory). In the end you chose between performance and isolation. No way around it. Or there was.</p>
<h2>Container, VM, or Lambda: the trade-off none of them solved alone</h2>
<p>This pattern got common: AI coding assistants, interactive code environments, analytics, vulnerability scanners, game servers running player scripts. They all need the same thing: give each user their own environment to run code the team did not write, safely and without lag.</p>
<p>The knot is that real isolation and low latency pull in opposite directions. From a security angle you want a hard boundary between tenants (the Security pillar of the Well-Architected Framework: isolate what is not trusted). From an experience angle you want that environment up the instant the user shows up. Reconciling the two was the expensive work.</p>
<p>And there is a nice irony in this story. We spent years learning to build stateless apps, and now state is a requirement again.</p>
<blockquote>
<p>The solution to the future was hiding in the past.</p>
</blockquote>
<p>That is a line a friend dropped in a conversation, and it has not left my head since. Ever felt that way? Because I have. And it is roughly what Lambda MicroVMs does: it brings state back, without handing you the weight of a full VM.</p>
<h2>What Lambda MicroVMs is</h2>
<p>Lambda MicroVMs is a new primitive <strong>inside</strong> Lambda, built exactly for that gap. Each MicroVM gives a single user or session its own isolated environment that boots fast, keeps memory and disk for the whole session, and pauses to a low cost when the user steps away.</p>
<p>The magic comes from <strong>Firecracker</strong>, the same lightweight virtualization that already runs over 15 trillion Lambda invocations a month. This is not raw new tech, it is the mature foundation of Lambda itself, exposed in a new way.</p>
<p>The model is <strong>image-then-launch</strong>:</p>
<img src="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/623913f5-46be-4eab-a8e9-660e65a5db84.png" alt="" style="display:block;margin:0 auto" />

<p>You build the <strong>image</strong> once (AWS runs your Dockerfile, initializes the app, and takes a snapshot of memory and disk). After that, every MicroVM you launch resumes from that snapshot instead of cold-booting. That is why launch and resume are near-instant, even for a multi-gigabyte session.</p>
<h2>What it is actually for (with examples you will recognize)</h2>
<p>The main cue: this only enters the picture if you are <strong>building a platform that runs third-party code</strong>. If your app does not execute outside code, you do not need it. It is a building block for people who build that kind of product:</p>
<ul>
<li><p><strong>Replit, CodeSandbox, "VS Code in the browser":</strong> the user types code in the browser and it runs isolated, per user, holding state while the tab is open. That "runs isolated" is the MicroVM.</p>
</li>
<li><p><strong>Code interpreter (like ChatGPT's or Claude's):</strong> you ask "plot this CSV", the AI writes Python and <strong>runs it</strong> to answer you. The runtime that executes that generated code, isolated per conversation, is the use case.</p>
</li>
<li><p><strong>CI/CD runner (and relatives):</strong> a job runs the code of a Pull Request that may come from any stranger's fork, untrusted by definition, so you want an isolated, disposable runner per job. Same family: a scanner that runs a suspicious binary, a coding-interview platform (the candidate's code runs isolated), an AI agent that runs shell commands. The thread tying it all together: <strong>each user, session, or job needs its own isolated environment, and the code running there is not code you wrote.</strong> That is the cue to use a MicroVM instead of a Lambda Function.</p>
</li>
</ul>
<h2>Lambda Function or Lambda MicroVM?</h2>
<p>They do not compete, they complete each other. The official comparison:</p>
<table>
<thead>
<tr>
<th></th>
<th>Lambda Functions</th>
<th>Lambda MicroVMs</th>
</tr>
</thead>
<tbody><tr>
<td>Best for</td>
<td>request-response or event-driven (APIs, data processing, automation)</td>
<td>persistent environments running user or AI-produced untrusted code</td>
</tr>
<tr>
<td>Programming model</td>
<td>function handler invoked in a supported runtime</td>
<td>any application: run your own binaries, listen on ports, use Linux OS capabilities</td>
</tr>
<tr>
<td>Duration</td>
<td>up to 15 min per invocation; multi-step workflows up to a year with Lambda Durable Functions</td>
<td>up to 8 hours per session; suspend and resume across sessions</td>
</tr>
<tr>
<td>Runtime</td>
<td>service-provided runtimes (or customer-provided)</td>
<td>customer-provided MicroVM images</td>
</tr>
<tr>
<td>Inbound networking</td>
<td>direct invocations or event-source integrations; response streaming</td>
<td>inbound access to any port using OSI Layer 7 protocols</td>
</tr>
<tr>
<td>Concurrency</td>
<td>one request per execution environment at a time</td>
<td>multiple concurrent connections per MicroVM</td>
</tr>
<tr>
<td>Environment state</td>
<td>warm starts may reuse the environment, but state may not persist across invocations</td>
<td>memory and disk state preserved on suspend, restored on resume</td>
</tr>
<tr>
<td>Scaling</td>
<td>automatic: Lambda creates and destroys environments in response to traffic</td>
<td>developer-controlled: you create, suspend, resume, and terminate via API</td>
</tr>
<tr>
<td>Lifecycle</td>
<td>fully managed by Lambda</td>
<td>developer-controlled, with optional idle policies</td>
</tr>
<tr>
<td>Pricing</td>
<td>per-request + GB-seconds</td>
<td>per-second of compute while running + snapshot storage while suspended</td>
</tr>
</tbody></table>
<p>The most common confusion: people assume the duration is the same as Lambda's. The startup is similar (both resume from a snapshot), but a Function dies at 15 minutes while a MicroVM holds a session for up to 8 hours with state intact. The real design: your app keeps Lambda Functions for the event-driven backbone, and <strong>calls</strong> MicroVMs only for the steps that need to run untrusted code in isolation.</p>
<h2>How it works in practice: from endpoint to orchestration</h2>
<p>Three things that trip people up at first, together.</p>
<p><strong>The endpoint has a status.</strong> When you call <code>run-microvm</code>, you get an ID and a dedicated HTTPS endpoint for that MicroVM. But it is not ready instantly: it goes through states, from launch to <code>RUNNING</code> (about 2 seconds), and when idle it moves to suspended, coming back on resume. The endpoint is per MicroVM, per session.</p>
<p><strong>One image, many MicroVMs.</strong> You build the image once (<code>create-microvm-image</code>) and each MicroVM is a <code>run-microvm</code>. Want two? Call it twice, and you get two independent instances. Idle behavior is governed by the <code>idle-policy</code>: <code>maxIdleDurationSeconds</code> (suspend after X idle) and <code>autoResumeEnabled</code> (the next request wakes the MicroVM on its own, in about 1s, no manual restart). When you are done, <code>terminate-microvm</code> releases everything.</p>
<p><strong>You become the orchestrator.</strong> Since the endpoint is per session, something has to decide when to launch and where to route. Typically a Lambda Function in the backbone does it: it keeps a <code>session -&gt; MicroVM</code> map (a store like DynamoDB in production), calls <code>RunMicrovm</code> on a user's first access, stores the ID and endpoint, mints a short-lived token with <code>CreateMicrovmAuthToken</code>, and proxies the request to the MicroVM's endpoint with the <code>X-aws-proxy-auth</code> header. If the instance is suspended and <code>autoResume</code> is on, the request itself wakes it. Add a routine to terminate orphan MicroVMs and you have the skeleton. The backbone code is in the next post in the series. And do not confuse this with Step Functions: MicroVM is the execution environment, Step Functions is an orchestrator, different layers.</p>
<h2>Cost, limits, and what is still missing</h2>
<p><strong>Cost is a decision, not a detail.</strong> Werner Vogels keeps hammering in the <strong>Frugal Architect</strong> that cost is an architecture requirement, not a number you discover on the bill. The suspend is exactly that in practice: you pay a lot for VM-level isolation, but only while the user is active. When they leave, the MicroVM suspends and the cost drops, with no loss of state. Designing your <code>idle-policy</code> on purpose is a cost decision. The model, from the official table: you pay <strong>per second of compute while it runs</strong>, and only <strong>snapshot storage while it is suspended</strong>. Unit prices are on the <a href="https://aws.amazon.com/lambda/pricing/">Lambda pricing page</a>.</p>
<p><strong>Limits:</strong> ARM64, up to 16 vCPUs, 32 GB of memory, and 32 GB of disk per MicroVM, and up to 8 hours of total runtime. Provisioning is flexible: you set a baseline and burst up to 4x at peak, paying the baseline while it runs.</p>
<p><strong>IaC:</strong> you can use the console, CloudFormation, and CDK.</p>
<p><strong>Why Dockerfile + zip, and not a prebuilt ECR image?</strong> Aidan Steele dug into it: Lambda builds two copies of the image, one for Graviton 3 and one for Graviton 4, so it needs the source to recompile. The base comes from ECR Public, but pushing your own prebuilt image from a private ECR as the artifact is not the path. One thing that confuses people coming from containers: ECR does not leave your life. You do not <strong>deliver</strong> the MicroVM image via ECR, but <strong>inside</strong> the running MicroVM you can run Docker and <code>docker pull</code> your private ECR images at runtime. ECR is for consumption inside, not for delivering the image itself.</p>
<p><strong>Networking and region:</strong> inbound traffic on configurable ports (HTTP/2, gRPC, WebSockets), service-provided JWE auth, outbound to the internet or your VPC. And it is available so far only in US East (N. Virginia, Ohio), US West (Oregon), Europe (Ireland), and Asia Pacific (Tokyo).</p>
<h2>When NOT to use it</h2>
<p>If the workload is short request-response with no state, it stays a Lambda Function. A MicroVM there is a cannon for a mosquito. And if you just need <strong>more than 15 minutes with your own (trusted) code</strong>, a MicroVM is also overkill: for a long job, look at Fargate; for a multi-step workflow, Lambda Durable Functions (up to a year, as the table shows). MicroVMs are for when the differentiator is <strong>isolating untrusted code</strong>, not just going past 15 minutes.</p>
<p>There is also a gotcha AWS itself flags, and it rhymes with the determinism conversation: since the MicroVM boots from a pre-initialized snapshot (the equivalent of Lambda SnapStart, as Aidan Steele confirmed by testing), apps that generate unique content, open connections, or load ephemeral data at init may diverge. The snapshot froze a moment; whatever needs to be fresh per session cannot be frozen along with it. The fix has a name: <strong>lifecycle hooks</strong> to re-initialize randomness when each MicroVM is created. Map that out before assuming it just works.</p>
<h2>Does it kill the container? No, and the reason is even better.</h2>
<p>The hype of the week is "containers are obsolete." They are not. Quite the opposite: Aidan Steele tested it and <strong>you can run Docker inside a MicroVM</strong>, with OS capabilities enabled. So the MicroVM does not kill the container, it is more isolated and still runs containers inside. The honest cut is different: there is one specific spot, running untrusted code in isolation, where you will no longer want to harden a container by hand. There the MicroVM wins. Everywhere else, the container is still king.</p>
<h2>The details the docs leave out</h2>
<p>Aidan Steele spent launch day poking at the service and found some really interesting things that are not in the official docs. I read it and figured it was worth bringing here:</p>
<ul>
<li><p><strong>You can get a shell into the MicroVM</strong>, via the <code>CreateMicrovmShellAuthToken</code> API, with pty as a first-class citizen (Lambda Functions do not have it). Gold for IDE and coding-agent use cases.</p>
</li>
<li><p><strong>Outbound UDP is blocked by default</strong> and DNS is a local stub, so DNS inside a container falls back to 8.8.8.8 and fails. The fix is to run with Lambda's DNS: <code>docker run --dns 169.254.169.253</code>, or go via VPC.</p>
</li>
<li><p><strong>Lambda network connectors:</strong> a reified VPC config (subnets, security groups, an IAM role for the ENI) with its own lifecycle. The network team creates it, the developer just consumes it.</p>
</li>
<li><p><strong>Performance</strong> (his tests): image build 2-3 min; <code>RunMicrovm</code> to RUNNING about 2s, plus 2s to serve; suspend and resume about 1s each.</p>
</li>
</ul>
<h2>What you take away</h2>
<ul>
<li><p>Lambda MicroVMs fills a real gap: VM-level isolation <strong>with</strong> near-instant launch <strong>and</strong> per-session state, which no single service delivered together.</p>
</li>
<li><p>It does not replace the Lambda Function, it complements it. Function in the backbone, MicroVM for the untrusted code.</p>
</li>
<li><p>The idle suspend is a deliberate cost lever, design your <code>idle-policy</code> on purpose.</p>
</li>
<li><p>Before locking in architecture: check the region (no São Paulo yet), the limits (ARM64, 16 vCPU, 32 GB, 8h), and the snapshot caveat. This post was the map. In the next one in the series I actually spin up a MicroVM and we prove the isolation in practice, launching two MicroVMs and testing whether one can reach the other, with the repo on GitHub for you to run along.</p>
</li>
</ul>
<p>Got a case where you run user or AI code that today is duct-taped onto a container or a hand-rolled VM? Does this primitive fit? Drop a like, share it with whoever is building a multi-tenant platform, and let's talk. Cheers! =D</p>
<p><em>Originally published on</em> <a href="https://willpeixoto.dev"><em>willpeixoto.dev</em></a><em>.</em></p>
]]></content:encoded></item><item><title><![CDATA[AWS Lambda MicroVMs: rode código não confiável com isolamento de VM (sem gerenciar infra)]]></title><description><![CDATA[🇺🇸 Leia em inglês.
Deixa eu te colocar numa situação. Você precisa rodar um código que não foi você que escreveu. Pode ser o script que o seu usuário colou na plataforma, pode ser o trecho que um ag]]></description><link>https://willpeixoto.dev/aws-lambda-microvms-codigo-isolado-serverless</link><guid isPermaLink="true">https://willpeixoto.dev/aws-lambda-microvms-codigo-isolado-serverless</guid><category><![CDATA[AWS]]></category><category><![CDATA[serverless]]></category><category><![CDATA[lambda]]></category><category><![CDATA[firecracker]]></category><category><![CDATA[microvm]]></category><category><![CDATA[AI]]></category><category><![CDATA[aws lambda]]></category><dc:creator><![CDATA[Willian Peixoto]]></dc:creator><pubDate>Wed, 24 Jun 2026 03:15:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/6183607e-99f0-48ed-a463-ec9939e75cf9.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>🇺🇸</em> <a href="https://willpeixoto.dev/aws-lambda-microvms-untrusted-code-isolation"><em>Leia em inglês</em></a><em>.</em></p>
<p>Deixa eu te colocar numa situação. Você precisa rodar um código que não foi você que escreveu. Pode ser o script que o seu usuário colou na plataforma, pode ser o trecho que um agente de IA gerou na hora e quer executar. E aí bate a pergunta que tira o sono de quem trabalha com multi-tenant: como eu rodo isso sem entregar a chave da casa para um estranho?</p>
<p>Até semana passada você tinha três caminhos, e todos com um porém. VM dá isolamento forte, mas leva minutos para subir. Container sobe em segundos, mas compartilha kernel, então rodar código não confiável ali exige um trabalhão de hardening. E a Lambda Function foi feita para request-response de vida curta, não para uma sessão que precisa guardar estado vivo entre uma interação e outra (externalizar num DynamoDB resolve o dado, não o runtime em memória, o processo rodando, os pacotes carregados). No fim, você escolhia entre performance e isolamento. Não tem para onde fugir, ou tinha.</p>
<h2>Container, VM ou Lambda: o trade-off que nenhum resolvia sozinho</h2>
<p>Esse padrão virou comum: assistente de código com IA, ambiente de código interativo, analytics, scanner de vulnerabilidade, game server com script do jogador. Todos precisam da mesma coisa: dar a cada usuário um ambiente próprio para executar código que o time não escreveu, com segurança e sem lentidão.</p>
<p>O nó é que isolamento de verdade e baixa latência puxavam para lados opostos. Pela ótica de segurança, você quer uma fronteira dura entre os tenants (o pilar de Security do Well-Architected: isolar o que não é confiável). Pela ótica de experiência, você quer o ambiente de pé na hora. Conciliar os dois era o trabalho caro.</p>
<p>E tem uma ironia boa nessa história. A gente passou anos aprendendo a construir aplicação stateless, e agora o estado voltou a ser requisito. Outro dia, numa conversa com uns amigos, alguém soltou uma frase que não saiu mais da minha cabeça:</p>
<blockquote>
<p>A solução do futuro estava no passado.</p>
</blockquote>
<p>Já se sentiu assim? Pois é, eu também. É mais ou menos isso que o Lambda MicroVMs faz: traz o estado de volta, sem te devolver o peso da VM.</p>
<h2>O que é o Lambda MicroVMs</h2>
<p>O Lambda MicroVMs é um primitivo novo <strong>dentro</strong> do Lambda, feito exatamente para esse buraco. Cada MicroVM dá a um único usuário ou sessão um ambiente isolado, que sobe rápido, retém memória e disco pela sessão inteira, e pausa para um custo baixo quando o usuário some.</p>
<p>A mágica vem do <strong>Firecracker</strong>, a mesma virtualização leve que já roda mais de 15 trilhões de invocações de Lambda por mês. Não é tecnologia crua, é a fundação madura do próprio Lambda exposta de um jeito novo.</p>
<p>O modelo é <strong>image-then-launch</strong>:</p>
<img src="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/bf9078e8-bc36-40d4-ae3c-e57cf4cef01e.png" alt="" style="display:block;margin:0 auto" />

<p>Você cria a <strong>imagem</strong> uma vez (a AWS roda o seu Dockerfile, inicializa a app e tira um snapshot da memória e do disco). Depois, toda MicroVM que você lança parte desse snapshot, em vez de bootar do zero. Por isso o launch e o resume são quase instantâneos, mesmo numa sessão de vários gigabytes.</p>
<h2>Para que serve (com exemplos que você reconhece)</h2>
<p>A deixa principal: isso só entra em cena se você está <strong>construindo uma plataforma que roda código de terceiros</strong>. Se o seu app não executa código de fora, você não precisa disso. É um tijolo para quem constrói esse tipo de produto:</p>
<ul>
<li><p><strong>Replit, CodeSandbox, "VS Code no browser":</strong> o usuário digita código no navegador e ele roda isolado, por usuário, segurando estado enquanto a aba está aberta. Esse "roda isolado" é a MicroVM.</p>
</li>
<li><p><strong>Code interpreter (tipo o do ChatGPT ou do Claude):</strong> você pede "faz um gráfico desse CSV", a IA escreve um Python e <strong>roda</strong> para te responder. O runtime que executa esse código gerado, isolado por conversa, é o caso.</p>
</li>
<li><p><strong>Runner de CI/CD (e parentes):</strong> um job roda o código de um Pull Request que pode vir do fork de qualquer estranho, código não confiável por definição, então você quer um runner isolado e descartável por job. Na mesma família: scanner que executa um binário suspeito, plataforma de entrevista de código (o código do candidato roda isolado) e agente de IA que roda comandos de shell.</p>
</li>
</ul>
<p>O fio que une tudo: <strong>cada usuário, sessão ou job precisa do próprio ambiente isolado, e o código que roda ali não foi você que escreveu.</strong> É essa a deixa para usar MicroVM em vez de Lambda Function.</p>
<h2>Lambda Function ou Lambda MicroVM?</h2>
<p>Os dois não competem, eles se completam. A comparação oficial:</p>
<table>
<thead>
<tr>
<th></th>
<th>Lambda Function</th>
<th>Lambda MicroVM</th>
</tr>
</thead>
<tbody><tr>
<td>Melhor para</td>
<td>request-response ou event-driven (APIs, processamento, automação)</td>
<td>ambiente persistente rodando código não confiável de usuário ou de IA</td>
</tr>
<tr>
<td>Modelo de programação</td>
<td>function handler num runtime suportado</td>
<td>qualquer aplicação: seus binários, escutando em portas, com capabilities do Linux</td>
</tr>
<tr>
<td>Duração</td>
<td>até 15 min por invocação; workflow multi-step de até um ano com Lambda Durable Functions</td>
<td>até 8 horas por sessão; suspend e resume entre sessões</td>
</tr>
<tr>
<td>Runtime</td>
<td>runtimes do serviço (ou customizado)</td>
<td>imagem de MicroVM provida por você</td>
</tr>
<tr>
<td>Rede de entrada</td>
<td>invocação direta ou event source; response streaming</td>
<td>qualquer porta, protocolos OSI camada 7</td>
</tr>
<tr>
<td>Concorrência</td>
<td>uma request por ambiente por vez</td>
<td>múltiplas conexões simultâneas por MicroVM</td>
</tr>
<tr>
<td>Estado do ambiente</td>
<td>warm start pode reusar o ambiente, mas o estado não persiste</td>
<td>memória e disco preservados no suspend, restaurados no resume</td>
</tr>
<tr>
<td>Escala</td>
<td>automática: o Lambda cria e destrói ambientes conforme o tráfego</td>
<td>você controla: cria, suspende, resume e termina via API</td>
</tr>
<tr>
<td>Ciclo de vida</td>
<td>totalmente gerenciado pelo Lambda</td>
<td>você controla, com idle policies opcionais</td>
</tr>
<tr>
<td>Preço</td>
<td>por request + GB-segundos</td>
<td>por segundo de compute rodando + storage do snapshot enquanto suspensa</td>
</tr>
</tbody></table>
<p>A confusão mais comum: muita gente assume que o tempo é igual ao do Lambda. O startup até é parecido (os dois resumem de snapshot), mas a Function morre em 15 minutos e a MicroVM segura uma sessão por até 8 horas com o estado intacto. O desenho real: a sua app continua com Lambda Functions no backbone event-driven, e <strong>chama</strong> o MicroVMs só nos passos que precisam rodar código não confiável isolado.</p>
<h2>Como funciona na prática: do endpoint à orquestração</h2>
<p>Três coisas que confundem no começo, juntas.</p>
<p><strong>O endpoint tem status.</strong> Quando você chama <code>run-microvm</code>, vem um ID e um endpoint HTTPS dedicado daquela MicroVM. Mas ela não nasce pronta: passa por status, do launch até <code>RUNNING</code> (uns 2 segundos), e no ocioso vai para suspensa, voltando no resume. O endpoint é por MicroVM, por sessão.</p>
<p><strong>Uma imagem, muitas MicroVMs.</strong> Você builda a imagem uma vez (<code>create-microvm-image</code>) e cada MicroVM é um <code>run-microvm</code>. Quer duas? Chama duas vezes, e vêm duas instâncias independentes. O ocioso é governado pela <code>idle-policy</code>: <code>maxIdleDurationSeconds</code> (suspende após X ocioso) e <code>autoResumeEnabled</code> (a próxima request acorda a MicroVM sozinha em ~1s, sem você ligar na mão). No fim, <code>terminate-microvm</code> libera tudo.</p>
<p><strong>Você vira o orquestrador.</strong> Como o endpoint é por sessão, alguém precisa decidir quando lançar e para quem rotear. Tipicamente uma Lambda Function no backbone faz isso: mantém um mapa <code>sessão → MicroVM</code> (em produção um store, tipo DynamoDB), lança com <code>run-microvm</code> no primeiro acesso do usuário, gera um token com <code>CreateMicrovmAuthToken</code> e faz proxy da request para o endpoint da MicroVM. Se ela estiver suspensa e o <code>autoResume</code> estiver ligado, a própria request acorda ela. Some a isso uma rotina para terminar MicroVMs órfãs e você tem o esqueleto. O código desse backbone fica no próximo post da série. E não confunda com Step Functions: MicroVM é o ambiente de execução, Step Functions é orquestrador, são camadas diferentes.</p>
<h2>Custo, limites e o que ainda falta</h2>
<p><strong>Custo é decisão, não detalhe.</strong> O Werner Vogels martela no <strong>Frugal Architect</strong> que custo é requisito de arquitetura, não número que você descobre na fatura. O suspend é isso na prática: você paga caro pelo isolamento de VM, mas só enquanto o usuário está ativo. Quando ele some, a MicroVM suspende e o custo cai, sem perder o estado. Desenhar a <code>idle-policy</code> com intenção é uma decisão de custo. O modelo, pela tabela oficial: você paga <strong>por segundo de compute enquanto a MicroVM roda</strong>, e só o <strong>storage do snapshot enquanto ela está suspensa</strong>. Os valores unitários estão na <a href="https://aws.amazon.com/lambda/pricing/">página de pricing do Lambda</a>.</p>
<p><strong>Limites:</strong> ARM64, até 16 vCPUs, 32 GB de memória e 32 GB de disco por MicroVM, e até 8 horas de runtime total. Provisionamento flexível: você define um baseline e escala até 4x no pico, pagando o baseline enquanto roda.</p>
<p><strong>IaC:</strong> dá para usar console, CloudFormation e CDK.</p>
<p><strong>Por que Dockerfile + zip, e não uma imagem ECR pronta?</strong> O Aidan Steele cavou: a Lambda builda duas cópias, uma para Graviton 3 e outra para Graviton 4, então precisa do fonte para recompilar. A base sai do ECR Public, mas empurrar a sua imagem pronta de um ECR privado como artefato não é o caminho. Um detalhe que confunde: ECR não some, dentro da MicroVM você roda Docker e dá <code>docker pull</code> do seu ECR em runtime. ECR é para consumo dentro, não para entregar a imagem.</p>
<p><strong>Rede e região:</strong> tráfego de entrada em portas configuráveis (HTTP/2, gRPC, WebSockets), auth JWE do serviço, saída para internet ou VPC. E o aviso BR: por enquanto só em US East (N. Virginia, Ohio), US West (Oregon), Europe (Ireland) e Asia Pacific (Tokyo). Sem sa-east-1 ainda.</p>
<h2>Quando NÃO usar</h2>
<p>Se o workload é request-response curtinho e sem estado, continua sendo Lambda Function. MicroVM ali é matar mosquito com canhão. E se você só precisa de <strong>mais de 15 minutos com o seu próprio código</strong> (confiável), MicroVM também é overkill: para job longo, olhe Fargate; para workflow multi-step, Lambda Durable Functions (até um ano, como a tabela mostra). MicroVM é para quando o diferencial é o <strong>isolamento de código não confiável</strong>, não só passar dos 15 minutos.</p>
<p>E tem uma pegadinha que a própria AWS avisa, e que lembra muito o papo de determinismo: como a MicroVM sobe de um snapshot pré-inicializado (o equivalente ao SnapStart da Lambda, como o Aidan Steele confirmou testando), aplicações que geram conteúdo único, abrem conexões ou carregam dados efêmeros na inicialização podem divergir. O snapshot congelou um momento; o que precisa ser fresco a cada sessão não pode estar congelado junto. O conserto tem nome: <strong>lifecycle hooks</strong> para reinicializar a aleatoriedade na criação de cada MicroVM. Mapeie isso antes de assumir que vai funcionar de primeira.</p>
<h2>Mata o container? Não, e o motivo é até melhor.</h2>
<p>O hype de plantão é "containers ficaram obsoletos". Não ficaram. Pelo contrário: o Aidan Steele testou e <strong>você roda Docker dentro de uma MicroVM</strong>, com as capabilities de OS liberadas. Ou seja, o MicroVM não mata o container, ele é mais isolado e ainda roda container por dentro. O recorte honesto é outro: tem um lugar específico, rodar código não confiável isolado, onde você não vai mais querer endurecer container na mão. Ali o MicroVM ganha. No resto, container segue rei.</p>
<h2>Os detalhes que a doc deixou de fora</h2>
<p>O <a href="https://awsteele.com/blog/2026/06/23/some-notes-on-lambda-microvms.html">Aidan Steele</a> passou o dia do lançamento cutucando o serviço e achou coisas bem interessantes que não estão na doc oficial.<br />Eu li e achei importante trazer para cá:</p>
<ul>
<li><p><strong>Você consegue um shell na MicroVM</strong>, via API <code>CreateMicrovmShellAuthToken</code>, com pty como cidadão de primeira classe (a Lambda Function não tem). Ouro para IDE e coding agent.</p>
</li>
<li><p><strong>UDP de saída é bloqueado por padrão</strong> e o DNS é um stub local, então DNS dentro de container cai no 8.8.8.8 e falha. O fix é rodar com o DNS da Lambda: <code>docker run --dns 169.254.169.253</code>, ou ir de VPC.</p>
</li>
<li><p><strong>Lambda network connectors:</strong> config de VPC reificada (subnets, security groups, IAM role para ENI) com ciclo de vida próprio. O time de rede cria, o dev só consome.</p>
</li>
<li><p><strong>Performance</strong> (testes dele): build da imagem 2-3 min; <code>RunMicrovm</code> até RUNNING ~2s, mais ~2s para servir; suspend e resume ~1s cada.</p>
</li>
</ul>
<h2>O que você leva</h2>
<ul>
<li><p>O Lambda MicroVMs preenche um buraco real: isolamento de VM <strong>com</strong> launch quase instantâneo <strong>e</strong> estado por sessão, que nenhum serviço entregava junto.</p>
</li>
<li><p>Não substitui a Lambda Function, complementa. Function no backbone, MicroVM para o código não confiável.</p>
</li>
<li><p>O suspend ocioso é uma alavanca de custo consciente, desenhe a <code>idle-policy</code> de propósito.</p>
</li>
<li><p>Antes de cravar arquitetura: confira região (sem sa-east-1 ainda), os limites (ARM64, 16 vCPU, 32 GB, 8h) e o caveat do snapshot.</p>
</li>
</ul>
<p>Esse post foi o mapa. No próximo da série eu subo o MicroVMs de verdade e a gente prova o isolamento na prática, lançando duas MicroVMs e testando se uma alcança a outra, com o repo no GitHub para você rodar junto.</p>
<p>Comenta aí: você tem um caso de rodar código de usuário ou de IA que hoje gambiarra em container ou em VM na mão?<br />Manda aquele joinha, compartilha com quem está montando plataforma multi-tenant, e bora trocar ideia. Valeu demais! =D</p>
<p><em>Publicado originalmente em</em> <a href="https://willpeixoto.dev"><em>willpeixoto.dev</em></a><em>.</em></p>
]]></content:encoded></item><item><title><![CDATA[High Availability Has a Price: Resilience Is a Decision, Not a Stack]]></title><description><![CDATA[🇧🇷 This article is also available in Portuguese: Resiliência em Arquitetura: A Decisão é Estratégica, não apenas Técnica
After a major outage like the October 2025 event in AWS's us-east-1 region, t]]></description><link>https://willpeixoto.dev/high-availability-has-a-price-resilience-is-a-decision-not-a-stack</link><guid isPermaLink="true">https://willpeixoto.dev/high-availability-has-a-price-resilience-is-a-decision-not-a-stack</guid><category><![CDATA[AWS]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[architecture]]></category><category><![CDATA[Reliability]]></category><category><![CDATA[Disaster recovery]]></category><dc:creator><![CDATA[Willian Peixoto]]></dc:creator><pubDate>Sat, 20 Jun 2026 19:01:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/e8d1e07c-4d19-4069-a366-35ecc195a262.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>🇧🇷 This article is also available in Portuguese:</em> <a href="https://willpeixoto.dev/resiliencia-custo-ha-multi-regiao-ou-on-premise"><em>Resiliência em Arquitetura: A Decisão é Estratégica, não apenas Técnica</em></a></p>
<p>After a major outage like the October 2025 event in AWS's us-east-1 region, the smoke clears and the same questions that haunt CTOs and architects always resurface:</p>
<blockquote>
<p><em>"Should we be multi-region?" Or worse (and a little nostalgic): "Should we go back to on-premises?"</em></p>
</blockquote>
<p><strong>The truth is that the right answer is rarely technical.</strong></p>
<p><strong>It's strategic, first and foremost.</strong></p>
<p>As Werner Vogels (Amazon CTO) likes to put it in his talks:</p>
<blockquote>
<p><em>"Everything fails, all the time."</em></p>
</blockquote>
<p>And that's exactly it. The central question isn't <strong>whether</strong> it will fail, it's <strong>when</strong> it will fail and <strong>how</strong> prepared you'll be when that inevitable moment arrives. Because it will arrive. Whether you're in the cloud, on-premises, or running a complex multi-cloud setup.</p>
<p>What really separates resilient teams isn't the absence of failure. It's the <strong>speed, clarity, and effectiveness</strong> with which they respond and recover.</p>
<p>And that's where real architectural maturity lives: resilience isn't about choosing "multi-region" or "on-premises." It's about <strong>understanding the inherent risk, documenting the choice transparently, and reacting with a plan</strong>.</p>
<hr />
<h2>The Context Behind the Question: The Paradox of Visible Failure</h2>
<p>Every time there's a big outage, I notice technical teams and executives splitting into two extreme reactions, both driven by fear and pressure:</p>
<ul>
<li><p>"We need to go multi-region, now! Cost is secondary!"</p>
</li>
<li><p>"See? The cloud isn't reliable. We should have stayed on-premises, where we had control!"</p>
</li>
</ul>
<p>Both extremes are dangerous shortcuts.</p>
<p>Multi-region is not a vaccine against downtime, and going back to on-premises is not a synonym for control; it just moves the maintenance complexity onto you.</p>
<blockquote>
<p><strong>A Crucial Point of Reflection:</strong> The cloud doesn't fail more than a traditional data center, it just fails in a way that is more <strong>visible, shared, and, ironically, democratic</strong>. On AWS, problems scale globally and become trending topics in minutes. On-premises, they hide behind scattered logs, long repair times, and, often, they only hit you. <strong>Honestly: do you believe your company has a greater capacity than AWS (or any major cloud provider) to manage physical security, cabling, power, cooling, and, above all, the resilience of infrastructure at global scale?</strong></p>
</blockquote>
<p>Migrating or evolving an architecture, at its core, is not about "throwing everything away" or "buying the hype." It's about <strong>keeping what's good in the legacy and removing what limits growth</strong>.</p>
<p>This isn't a black-and-white fight of "Cloud vs. Data Center." It's a strategic game of <strong>Conscious Resilience vs. Comfort Zone</strong>.</p>
<hr />
<h2>Cost vs. Continuity: The Economics Behind the 9s</h2>
<p>In the world of infrastructure, each additional "9" in your SLA (Service Level Agreement) doesn't just cost more. It costs <strong>exponentially</strong> more.</p>
<p>To illustrate the real impact of each availability tier, here's the maximum allowed downtime per year:</p>
<ul>
<li><p><strong>99% (two 9s):</strong> about <strong>3.65 days</strong> of downtime per year. <em>Cost and complexity:</em> baseline (1x).</p>
</li>
<li><p><strong>99.9% (three 9s):</strong> about <strong>8 hours and 46 minutes</strong> of downtime per year. <em>Cost and complexity:</em> 1.5x to 2x the baseline.</p>
</li>
<li><p><strong>99.99% (four 9s):</strong> about <strong>52 minutes</strong> of downtime per year. <em>Cost and complexity:</em> 2x to 3x. Requires Multi-AZ and strong automation.</p>
</li>
<li><p><strong>99.999% (five 9s):</strong> about <strong>5 minutes</strong> of downtime per year. <em>Cost and complexity:</em> 3x and up. Requires flawless automation and, often, a Multi-Region architecture.</p>
</li>
</ul>
<p>Each tier jump means more than doubling or tripling infrastructure; it also demands <strong>operational review and sophistication</strong>. And here's the catch: every additional <strong>9</strong> has to be justified by <strong>ROI (Return on Investment)</strong>, never by technical pride.</p>
<blockquote>
<p>📢 <strong>The Non-Negotiable Factor: Regulation.</strong> For sectors like finance, healthcare, or telecom, the SLA choice isn't always purely economic. Often, the availability requirement (and the data recovery capability, the RPO) is <strong>imposed by law or industry rules</strong>. In those cases, the debate isn't <em>whether</em> you can afford it, but <em>how</em> to hit the legally mandated SLA at the lowest possible cost and complexity, because the cost of a regulatory fine outweighs any technical saving.</p>
</blockquote>
<p><strong>Rule of Thumb for Complexity:</strong></p>
<ul>
<li><p><strong>High availability (within a single region):</strong> can cost 1.5x to 2x the baseline.</p>
</li>
<li><p><strong>Multi-Region (Active/Passive):</strong> can cost 2.5x to 3x.</p>
</li>
<li><p><strong>Multi-Cloud (Active/Active):</strong> almost never reduces risk. On the contrary, it usually increases the <strong>failure surface</strong> and operational complexity.</p>
</li>
</ul>
<hr />
<h2>Conscious Decisions: The Virtue of ADRs</h2>
<p>Every architectural choice is a commitment based on a <strong>context</strong>, and that context is volatile. Without a record, the context is lost, which condemns us to redo decisions, revisit old discussions, and rack up unnecessary cost.</p>
<p>That's where the practice of <strong>ADRs (Architecture Decision Records)</strong> becomes crucial. These aren't 50-page documents. They're short records that capture the <strong>decision</strong>, the <strong>reason</strong>, and the <strong>accepted risk</strong> at a specific point in time.</p>
<p><code>Example ADR (focused on the accepted risk):</code></p>
<pre><code class="language-markdown"># ADR-014: Do not use multi-region replication in the MVP

Context:
- Current traffic &lt; 10 req/s.
- Multi-region replication cost is estimated at &gt; 3x current cost.

Decision:
Keep a single-region architecture (using Multi-AZ for intra-region HA),
with a daily cross-region backup.

Review Trigger:
After reaching an average of 100 req/s, or when the current SLA (99.95%)
starts causing business impact.

Accepted Risk / Consequence:
Risk of total service downtime if an outage affects the entire region
(estimated RTO of 4 hours for cross-region recovery).
</code></pre>
<p>An ADR doesn't prevent failure. But it prevents failure from catching the team by surprise, because the risk was mapped, accepted, and justified by the business. It's the map for future discussions.</p>
<hr />
<h2>Selective Resilience: Not Everything Needs HA (and That's Fine)</h2>
<p>Selective resilience is a <strong>virtue of economy and clarity</strong>. Not every service needs global redundancy. Spending finite resources (money and engineering attention) on unnecessary redundancy is one of the biggest forms of waste in architecture.</p>
<p><strong>Prioritize High Availability (HA) only for what truly matters:</strong></p>
<ul>
<li><p><strong>Direct revenue functions:</strong> components critical to the financial transaction (e.g., <strong>checkout</strong> and <strong>payment APIs</strong>).</p>
</li>
<li><p><strong>The critical customer journey:</strong> functions that block the core value of the product (e.g., <strong>login</strong> or the <strong>main catalog</strong>).</p>
</li>
<li><p><strong>Regulatory and legal risk:</strong> services where failure triggers <strong>legal fines</strong> or breaches a <strong>penalizing contractual SLA</strong>.</p>
</li>
<li><p><strong>Integrity of critical data:</strong> where data loss violates an acceptable <strong>RPO</strong> (e.g., mandatory data retention systems).</p>
</li>
</ul>
<p>Everything else? It can be restored through a well-defined recovery playbook. Batch jobs, internal back-office systems, and dashboards can tolerate minutes (or even hours) of downtime, as long as the reprocessing plan is clear.</p>
<blockquote>
<p><strong>High availability with no purpose is like installing an airbag on a bicycle.</strong> It's a sophisticated solution to a problem that doesn't exist in that context.</p>
</blockquote>
<hr />
<h2>Managed != Failure-Proof: The Serverless Mindset</h2>
<p>A common mistake is believing that using serverless services (Lambda, DynamoDB, SQS, EventBridge) is a synonym for immunity to failure. It isn't.</p>
<p>Failure will come, and often from where you least expect it, because the serverless paradigm shifts the <strong>risk surface</strong>, it doesn't remove it.</p>
<p>The key point is this:</p>
<p>Managed services reduce your <strong>operational surface</strong> (you don't manage the OS, patching, or capacity), but they <strong>don't replace good design and preparation</strong>.</p>
<p>During the October 2025 us-east-1 outage, plenty of 100% serverless applications went down. Not because serverless failed them, but because they leaned on a single region. When DNS resolution for the regional DynamoDB endpoint broke, anything pinned to us-east-1 (directly, or indirectly through a global control plane like IAM or STS) broke with it. Multi-AZ wouldn't have saved you here: the endpoint was regional, not zonal. And the applications that recovered slowest were frequently the ones whose code answered the failure with aggressive, unbounded retries, turning one outage into a self-inflicted retry storm.</p>
<blockquote>
<p><strong>Real resilience doesn't come from AWS. It comes from the architecture you design <em>on top</em> of it.</strong></p>
</blockquote>
<hr />
<h2>The Decision Belongs to the Business, the Clarity to the Architect</h2>
<p>The difference between "having an opinion" and "having influence" lies in your ability to translate technical complexity into <strong>strategic clarity</strong>. Your job isn't to scare the board with jargon. It's to give them the visibility they need to decide consciously.</p>
<p>Experience has taught me that a team's maturity can be measured precisely by its ability to ask the right question:</p>
<p>❓ Where Is Your Team's Maturity?</p>
<p><em><strong>Immature teams focus on the tool:</strong></em></p>
<ul>
<li><p>They ask: <strong>"Which stack solves this?"</strong></p>
</li>
<li><p>They ask: <strong>"Should we use K8s or Serverless?"</strong></p>
</li>
<li><p>They ask: <strong>"What does Netflix do?"</strong></p>
</li>
</ul>
<p><em><strong>Mature teams focus on risk and the business:</strong></em></p>
<ul>
<li><p>They ask: <strong>"What risk are we willing to accept for this cost?"</strong></p>
</li>
<li><p>They ask: <strong>"What RTO/RPO does the end customer require from this service?"</strong></p>
</li>
<li><p>They ask: <strong>"What does our business need to survive a disaster?"</strong></p>
</li>
</ul>
<p>The result is that two teams can use the exact same <strong>cloud</strong>: one scales predictably, the other lives in panic mode. The difference isn't the cloud. It's the level of understanding, documentation, and technical humility behind the decisions made.</p>
<blockquote>
<p><strong>The Common Trap:</strong> Who hasn't heard an executive say, "Technical decisions are up to the Architecture team"? What they're actually doing is transferring responsibility for defining <strong>business risk</strong>. Your team defines the <strong>HOW</strong> (the stack), but the Business defines the <strong>HOW MUCH</strong> (the acceptable RTO and RPO). It's your job to <strong>hand the question back</strong>, so the risk decision belongs to the business.</p>
</blockquote>
<h3>Translating Resilience Concepts for Leadership</h3>
<p>(After all, who hasn't heard: <em>"Now translate that so I can understand it!"</em>)</p>
<pre><code class="language-plaintext">1. Multi-Region Failover

   Translation: Insurance against catastrophe. It guarantees that a
                regional disaster won't take us offline for days,
                reducing revenue loss to a few hours.

   Question:    How many hours (or minutes) of downtime can the
                business accept for service X if an entire region goes down?
------------------------------------------------------------------
2. Active-Active Setup

   Translation: Maximum, uninterrupted availability. It lets us perform
                any maintenance or update without ever impacting the
                end customer.

   Question:    Does service X need to be 100% continuous? Can we afford
                a 15-minute maintenance window?
------------------------------------------------------------------
3. RTO / RPO

   Translation: Defining the limit of the damage. These are the numbers
                that tell us what we can lose, and for how long, before
                fines or reputation become unsustainable.

   Question:    How much data (RPO) can we lose, and how long (RTO) does
                the team have to restore the service before the business breaks?
------------------------------------------------------------------
4. SPOF (Single Point of Failure)

   Translation: The Achilles' heel of revenue. It's the weak point that,
                if broken, paralyzes the whole company. This is where the
                risk must be zero.

   Question:    If this component goes down, what's the financial loss
                in 1 hour?
</code></pre>
<hr />
<h2>Conclusion</h2>
<p>There is no such thing as a <strong>failure-proof</strong> architecture.</p>
<p>But there is such a thing as an <strong>organization that is surprise-proof</strong>.</p>
<p>And it starts with conscious decisions, documentation (the ADRs), and the technical humility to accept that error and risk are part of the equation.</p>
<p>Teams that understand the <strong>"why"</strong> before diving into the <strong>"how"</strong> build systems that don't just scale. They <strong>survive</strong>, and grow predictably.</p>
<hr />
<h2>Essential References</h2>
<p>For anyone who wants to go deeper on risk decisions and architectural patterns, these are the documents we use as a foundation for resilience on any cloud (with a focus on AWS):</p>
<ul>
<li><p><strong>AWS Well-Architected Framework (Reliability Pillar):</strong> the fundamental guide to understanding disaster recovery (DR) and high availability (HA) principles. <a href="https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/reliability.html">Reliability Pillar</a></p>
</li>
<li><p><strong>Disaster Recovery of Workloads on AWS:</strong> the key document for going deeper on RTO/RPO and choosing between patterns like Pilot Light and Active-Active. <a href="https://docs.aws.amazon.com/whitepapers/latest/disaster-recovery-workloads-on-aws/introduction.html">DR Whitepaper</a></p>
</li>
<li><p><strong>DynamoDB Global Tables:</strong> an excellent practical case study of HA at the data layer, abstracting away multi-region complexity. <a href="https://aws.amazon.com/dynamodb/global-tables/">DynamoDB Global Tables</a></p>
</li>
<li><p><strong>EventBridge Resilience Guide:</strong> essential for anyone working with serverless, focused on event-based resilience patterns. <a href="https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-resilience.html">EventBridge Resilience Guide</a></p>
</li>
<li><p><strong>AWS Post-Event Summary: Amazon DynamoDB Service Disruption in US-EAST-1 (Oct 19-20, 2025):</strong> the primary source on the outage referenced in this article, straight from AWS. <a href="https://aws.amazon.com/message/101925">Service Disruption Summary</a></p>
</li>
</ul>
<hr />
<h2>Essential Resilience Glossary</h2>
<p>So everyone is on the same page, here are some key terms used in this article, explained simply:</p>
<ul>
<li><p><strong>High Availability (HA):</strong> the ability of a system to keep operating even when one or more of its components fail. Measured in "9s" (e.g., 99.99%).</p>
</li>
<li><p><strong>Outage:</strong> an unplanned interruption of a service: the service goes down.</p>
</li>
<li><p><strong>On-premises:</strong> infrastructure and data centers you own, physically located at the company (not in the cloud).</p>
</li>
<li><p><strong>Multi-Region:</strong> using data centers in two or more different geographic cloud regions (e.g., US East and São Paulo) for maximum protection against regional disasters.</p>
</li>
<li><p><strong>Multi-AZ (Multi-Availability Zone):</strong> using two or more Availability Zones (isolated, nearby data centers) <strong>within</strong> the same cloud region. This is the baseline HA pattern.</p>
</li>
<li><p><strong>SLA (Service Level Agreement):</strong> a formal agreement defining the level of service a provider is expected to deliver (usually measured in uptime).</p>
</li>
<li><p><strong>ROI (Return on Investment):</strong> a financial metric measuring the relationship between money earned (or saved) and money invested.</p>
</li>
<li><p><strong>ADR (Architecture Decision Record):</strong> a short document recording an architectural decision, the reasoning, and the accepted risk at a specific point in time.</p>
</li>
<li><p><strong>RTO (Recovery Time Objective):</strong> the maximum acceptable <strong>time</strong> a system can be down after a failure.</p>
</li>
<li><p><strong>RPO (Recovery Point Objective):</strong> the amount of <strong>data</strong> (measured in time, e.g., 5 minutes) that can be lost during a disaster event.</p>
</li>
<li><p><strong>Serverless:</strong> a cloud computing model where the provider manages all the infrastructure and the developer focuses only on the code, paying only for usage.</p>
</li>
<li><p><strong>Circuit Breaker:</strong> a software pattern that, when a dependency starts failing repeatedly, "opens" the circuit to protect the rest of the application from cascading failures.</p>
</li>
</ul>
<hr />
<h2>Going deeper</h2>
<p>Three posts here on the blog that carry this conversation into different corners:</p>
<ul>
<li><p><a href="https://willpeixoto.dev/multi-cloud-less-resilient-availability-math">Is multi-cloud more resilient? The math says no</a>: what happens to your availability math once you put two clouds in series.</p>
</li>
<li><p><a href="https://willpeixoto.dev/data-streaming-on-aws-kinesis-firehose-flink-msk">Data Streaming on AWS: Kinesis, Firehose, Flink, or MSK?</a>: where RPO stops being a number on a slide and becomes a service choice.</p>
</li>
<li><p><a href="https://willpeixoto.dev/aws-lambda-microvms-untrusted-code-isolation">AWS Lambda MicroVMs: run untrusted code with VM-level isolation</a>: when isolation moves from implementation detail to architectural requirement.</p>
</li>
</ul>
<p>And I would like to hear from you: how did your architecture hold up during the last regional outage, and which trade-offs had you already written down <em>before</em> it happened? Tell me in the comments, or find me on LinkedIn and let's compare notes. If this post helped, drop a like and share it around. Thanks a lot!</p>
<p>BUILD. SCALE. REPEAT. =D</p>
]]></content:encoded></item><item><title><![CDATA[AWS MCP Server: which one to use, when, and how to set it up (now that AWS recommends just one)]]></title><description><![CDATA[🇧🇷 Também disponível em português: AWS MCP Server: qual usar, quando e como configurar
Let me tell you a scene. I bet you've lived it.
It's 11pm, you're coding with an AI sitting right next to you. ]]></description><link>https://willpeixoto.dev/aws-mcp-server-which-to-use-and-configure</link><guid isPermaLink="true">https://willpeixoto.dev/aws-mcp-server-which-to-use-and-configure</guid><category><![CDATA[AWS]]></category><category><![CDATA[agentic AI]]></category><category><![CDATA[Security]]></category><category><![CDATA[serverless]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Cloud Computing]]></category><dc:creator><![CDATA[Willian Peixoto]]></dc:creator><pubDate>Sat, 20 Jun 2026 18:37:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/051cb2d7-c997-45b7-845e-be698a84a8e1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>🇧🇷 Também disponível em português:</em> <a href="https://willpeixoto.dev/aws-mcp-server-qual-usar-quando-e-como-configurar-os-dois-servidores-explicados"><em>AWS MCP Server: qual usar, quando e como configurar</em></a></p>
<p>Let me tell you a scene. I bet you've lived it.</p>
<p>It's 11pm, you're coding with an AI sitting right next to you. You ask it something and it swears the thing exists: it makes up a service, a name that sounds a lot like something you've built before, even an implementation it promises works, with the full how-to. And you think: huh, didn't know that one, let me check the docs because it makes total sense. And bang, you find out it was hallucinating. It was writing Lambda code calling an AWS service from a function that doesn't exist, wiring up the DynamoDB table, building the IaC, the whole thing. Then it asks to "take a look at your account's current config" to validate the names, and you hit the wall everyone hits.</p>
<p>The agent, besides hallucinating, has no access to your account. It can't see your resources, it has no idea what's actually there. So it does what it does best: it's creative, it's proactive, and it invents something to make you happy. To it, that thing makes sense to exist, so it assumes it exists. The little guy doesn't even blush: it hands you an ARN that doesn't exist, picks a region you don't use, and guesses a table name. There it goes. It's doing exactly what it was built to do, which is make you happy.</p>
<p>And you, tired of fighting with it and just wanting to wrap up, do what? You paste an access key into a <code>.env</code> so it can "just see the account for a second" and give you everything right, with the real names. Who's never done that?</p>
<p>And it's all fine, except for one detail: you forget you did it. And bang, the <code>.env</code> went along in the commit. It's already in the git history, alerts firing everywhere, the usual mess. The key is exposed now. And that's also how your agent, in that moment where it seems to want to punish you or decided to be a little too proactive, gets real access to your account and, who knows, decides to delete the wrong stack. Or it's just the surprise bill of forty bucks in a single day, which turns into a much worse number when nobody's watching. I've been through this. You probably have too.</p>
<p>The good news is that AWS solved this. Actually, it solved it two different ways, with names so similar they confuse a lot of people. This post is the map I wish I'd had: what the two are, which pain each one kills, and when and how to use each. Let's go.</p>
<blockquote>
<p><strong>Freshness note:</strong> the MCP world moves fast. I wrote this guide in June 2026 and already had to update it in July 2026, when the connection flow changed (the version you're reading has direct OAuth). I'll do my best to keep it current as things ship, but if something doesn't match the screen in front of you, check the <a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/mcp-server.html">official docs</a> and tell me in the comments so I can fix it.</p>
</blockquote>
<h2>What you'll walk away knowing</h2>
<p>So you don't get lost, here's what we cover:</p>
<ul>
<li><p>The difference between the two AWS MCP servers and which pain each one solves</p>
</li>
<li><p>How to connect it in Claude Code, the Claude app, and Kiro, step by step</p>
</li>
<li><p>How to set up your account's IAM to grant access safely</p>
</li>
<li><p>When NOT to use it, and how to avoid a nasty surprise on your bill</p>
</li>
</ul>
<h2>But what is MCP, anyway?</h2>
<p>Before talking about the servers, let's level set.</p>
<p>MCP (<a href="https://modelcontextprotocol.io">Model Context Protocol</a>) is the "plug" your AI assistant uses to talk to the outside world: tools, data and services. Anthropic created it, it's under open governance now, and over the last year every assistant worth using (Claude Code, Kiro, Cursor) started speaking MCP.</p>
<p>Want an easy analogy? Think about the API. The API is what lets two applications talk to each other. MCP is the same idea, just for the agent: it's what lets the AI talk to any tool without you having to build a custom integration for every single system. MCP connects the agent to the system through a standard everyone agreed to use. And that's the nice thing about a standard: you learn it once and it works for any tool and any client. So if you want to give an AI access to your system, this is the path to follow.</p>
<p>And here's something that makes life a lot easier: for most cases, you don't even need to build your own MCP server. You can build one, sure (on Lambda, on Fargate, whatever you prefer), and AWS even has an <a href="https://aws.amazon.com/solutions/guidance/deploying-model-context-protocol-servers-on-aws/">official guidance for that</a> if that's your case. But AWS already runs managed servers ready to go, so a lot of the time you just plug in and use it. Building your own makes sense when the goal is different: exposing your own internal system (an API, a runbook, an alert) to the agent.</p>
<h2>The two AWS MCP servers</h2>
<p>Yep, there are two. And the names don't help at all. Here's everything in one table, then I break down each one:</p>
<table>
<thead>
<tr>
<th></th>
<th><strong>AWS Knowledge MCP Server</strong></th>
<th><strong>AWS MCP Server</strong> (managed, GA)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>What it solves</strong></td>
<td>"My agent hallucinates AWS APIs, ARNs and service names."</td>
<td>"My agent needs to see or act on my account, without me leaking a key."</td>
</tr>
<tr>
<td><strong>What it accesses</strong></td>
<td>Only AWS docs and knowledge (read-only)</td>
<td>Docs + real services in <em>your</em> account (authenticated)</td>
</tr>
<tr>
<td><strong>Credentials</strong></td>
<td>None. You don't even need an AWS account.</td>
<td>AWS browser sign-in (OAuth) or AWS CLI (SigV4)</td>
</tr>
<tr>
<td><strong>Audit</strong></td>
<td>Not applicable</td>
<td>CloudTrail + CloudWatch</td>
</tr>
<tr>
<td><strong>Use it when</strong></td>
<td>You want correct syntax, current docs, regional availability</td>
<td>You want the agent inspecting or operating real infra</td>
</tr>
<tr>
<td><strong>Risk if misused</strong></td>
<td>Basically zero</td>
<td>Real. It's your account. Least-privilege matters.</td>
</tr>
</tbody></table>
<p>If you keep one sentence from this post, keep this one:</p>
<blockquote>
<p><strong>One server gives your agent knowledge. The other gives it hands.</strong></p>
</blockquote>
<p>Figuring out which problem you actually have is half the battle.</p>
<p>Want another analogy? The Knowledge server is the guru: that friend who memorized the entire AWS documentation and clears up your doubt on the spot. The managed one is the doorman checking badges: it lets you into the account for real, but it stands there checking and only opens the doors IAM authorized. Name doesn't match the badge? You don't get in.</p>
<blockquote>
<p><strong>Where does this run?</strong> The AWS MCP Server is remote, and what connects to it is the MCP client: Claude Code, the Claude app (Desktop and claude.ai), Kiro, Cursor, or your own agent's code (Strands, SDK). That holds even with inference running on Bedrock, because the client is the application, never the model. A production agent on AgentCore, though, typically consumes tools through the AgentCore Gateway (which also speaks MCP) or your own MCP server. That production scenario is a topic for another post in this series.</p>
</blockquote>
<h2>Server #1: AWS Knowledge MCP Server</h2>
<p>What this server does is simple: it's remote, fully managed, and it gives the model structured access to the official docs, always current. And that "current" is the point. What the model knows on its own stops at its training date, so it has no clue about what came after and ends up guessing. AWS keeps this server in sync, so it becomes your source of truth: it searches the docs, returns the page as clean markdown, checks whether a service exists in a region, and lists the current regions. Read-only, it doesn't write or touch the account.</p>
<p>Why is it almost a no-brainer to turn on? Because there's no credential, and no AWS account needed. Nothing to protect, nothing to leak. The risk is basically zero and the payoff is the agent stops guessing and starts citing the real docs before it spits out the CDK.</p>
<p>Use it when you're learning a service, designing the architecture you want to build and validating the idea, checking syntax, generating IaC you actually trust, or answering "is this in my region yet?" without opening the browser. Connecting is pasting a URL: add <code>https://knowledge-mcp.global.api.aws</code> as a remote (HTTP) server in your client and that's it, no credentials at all. With it on, the agent checks the live docs before spitting out the CDK instead of guessing from training. Hallucinated ARNs drop off a cliff. Pretty good, right?</p>
<h2>Server #2: AWS MCP Server, the managed one (reads and operates the account)</h2>
<p>This is the one that cures the <code>.env</code> shame.</p>
<p>The pain is different: the agent needs to see or do something in the account for real. Read the CloudWatch logs of the function that's breaking, list what's actually in the bucket, check the real schema of the DynamoDB table. The old "solution" was to hand it a long-lived credential. That's the part that keeps the security folks up at night. And honestly, it should keep you up too.</p>
<p>What this server does: it's remote, hosted and managed by AWS, and it gives the agent authenticated access to AWS services through a small, fixed set of tools. No local install, automatic updates, and (this part I really like) every call lands in CloudTrail. The agent doesn't get a master key. It authenticates as you, through a real auth flow, on an IAM leash.</p>
<p>The auth flow in plain English: there are two paths now, and the newer one is the simpler one. Today the server speaks <strong>OAuth directly</strong>. You add the URL to your client, the first tool call opens the browser on AWS Sign-in, you log in with your usual identity, done. The token lasts 1 hour and refreshes itself for up to 12. No proxy, nothing to install.</p>
<p>The second path is <strong>SigV4 with</strong> <code>mcp-proxy-for-aws</code>, an open source proxy that runs on your machine, takes your local AWS CLI credentials, and signs every call. It still exists and it has its moment: multiple accounts in the same session, read-only mode (hiding write-capable tools from the agent), a fixed default region, or an org that blocks the OAuth permissions (<code>signin:AuthorizeOAuth2Access</code> and <code>signin:CreateOAuth2Token</code>).</p>
<p>Either way the outcome is the same: you don't paste a key anywhere, the agent acts with your identity, and everything respects your IAM. Documentation search, by the way, needs no credentials at all.</p>
<p>The OAuth flow, step by step:</p>
<ol>
<li><p>You attach the <code>AWSMCPSignInOAuthAccessPolicy</code> managed policy to your role or user (once).</p>
</li>
<li><p>You add the server URL to your client and fire the first call.</p>
</li>
<li><p>The browser opens on AWS Sign-in, you authorize, and the client keeps the token (1 hour, auto-refresh up to 12).</p>
</li>
<li><p>The server applies the context keys and forwards to the AWS service.</p>
</li>
<li><p>IAM authorizes via your policy and responds.</p>
</li>
<li><p>The whole call is logged to CloudTrail.</p>
</li>
</ol>
<p>The "ohhh, got it" moment is this: ask "why did <code>checkout-prod</code> start throwing 500s after 2pm?" and watch the agent pull the real CloudWatch logs, cross-reference a recent deploy, and point at the actual resource. All inside what IAM allows, all auditable, with no key in any dotfile. And it works with what you already use: Claude Code, Kiro, Cursor, any MCP-compatible client.</p>
<h2>How to connect: Claude Code, the Claude app, and Kiro</h2>
<p>Now the practical part. The OAuth path has a single prerequisite: the identity you'll use needs the sign-in managed policy. Attach it once and forget it:</p>
<pre><code class="language-bash">aws iam attach-role-policy \
  --role-name MyRole \
  --policy-arn arn:aws:iam::aws:policy/AWSMCPSignInOAuthAccessPolicy
</code></pre>
<p>(If you use an IAM user instead of a role, it's <code>attach-user-policy</code> with <code>--user-name</code>.)</p>
<h3>In Claude Code</h3>
<p>One line, and that's really it:</p>
<pre><code class="language-bash">claude mcp add aws-mcp https://aws-mcp.us-east-1.api.aws/mcp --transport http
</code></pre>
<p>On the first tool call the browser opens, you log in, and the agent sees the account on an IAM leash.</p>
<p>There's also a second route: the <code>aws-core</code> plugin. On top of the AWS MCP Server pre-configured, it brings the AWS agent skills, which are ready-made instruction packs so the agent handles CDK, serverless, containers and billing tasks well. If you want the server plus that extra context in one go, install it from Anthropic's official marketplace, which Claude Code already ships with:</p>
<pre><code class="language-bash">/plugin install aws-core@claude-plugins-official
</code></pre>
<p>One detail that trips people up: this command runs inside Claude Code, in the terminal. The "Plugins" section in the Claude Desktop app is a different catalog, so don't go looking for <code>aws-core</code> there (in the app, the path is the connector in the next section). The steering equivalent here is a <code>CLAUDE.md</code> at the project root, with the same rules I show in the Kiro block below.</p>
<h3>In the Claude app (Desktop and claude.ai)</h3>
<p>Yes, it works in the app, no terminal needed. In Claude Desktop: Settings, Connectors, "Add custom connector", give it a name (I called mine <code>aws-mcp</code>) and paste the URL:</p>
<pre><code class="language-plaintext">https://aws-mcp.us-east-1.api.aws/mcp?oauth=initialize
</code></pre>
<p>The <code>?oauth=initialize</code> suffix tells the server to kick off the OAuth flow explicitly (Cursor and Kiro IDE use the same trick). Leave the OAuth Client ID and Secret fields empty, the flow handles that. On claude.ai web it's the same URL without the suffix, in the connector settings.</p>
<img src="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/43501d79-076e-47ce-b2fd-1ec830a3c141.png" alt="Adding the AWS MCP Server as a custom connector in Claude Desktop" style="display:block;margin:0 auto" />

<p>On the first call, the AWS authorization screen opens:</p>
<img src="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/27fc1dfc-b72d-4859-87d9-68f4c2bd770b.png" alt="AWS Sign-in consent screen connecting the MCP client to the AWS MCP Server" style="display:block;margin:0 auto" />

<p>Two warnings here, because I hit them first so you don't have to:</p>
<p><strong>It's not the Directory connector.</strong> If you search "AWS" in Claude's connector directory, an "AWS API MCP Server" shows up. That is NOT the new managed one: it's the older <code>aws-api-mcp-server</code> from awslabs (look at its tools, just <code>suggest_aws_commands</code> and <code>call_aws</code>), precisely one of the servers the official docs tell you to replace. The right path is the custom connector with the URL above. And don't run both, that's the exact tool-conflict scenario AWS warns about.</p>
<p><strong>Don't authorize as root.</strong> The consent screen offers "Continue with Root or IAM user" and says access follows "your existing AWS permissions". Whatever identity you use there defines the agent's blast radius. Sign in with an IAM user or a dedicated role, with the sign-in managed policy and least-privilege. Root driven by an agent is everything we don't want. And a practical red flag: if the connection worked without you attaching any policy, investigate with an <code>aws sts get-caller-identity</code>. Either your identity is an admin, or you signed in as root, which doesn't go through IAM at all, imagine what an agent can do as root.</p>
<h3>In Kiro</h3>
<p>In Kiro CLI (2.11 or later):</p>
<pre><code class="language-bash">kiro-cli mcp add --name aws-mcp --url https://aws-mcp.us-east-1.api.aws/mcp
</code></pre>
<p>In Kiro IDE, add it as a remote server with the <code>?oauth=initialize</code> URL, or via <code>mcp.json</code> (per project at <code>&lt;root&gt;/.kiro/settings/mcp.json</code>, global at <code>~/.kiro/settings/mcp.json</code>; when both exist, the project one wins).</p>
<p>But config only turns the server on, it doesn't guarantee Kiro will use it. To make it prefer these tools, create a steering file at <code>.kiro/steering/aws-mcp.md</code>:</p>
<pre><code class="language-markdown">---
inclusion: always
---

# Using AWS via MCP

- Before generating any AWS code or IaC (CDK, CloudFormation, SDK), validate
  service names, syntax and regional availability against the docs via the
  `aws-mcp` server (documentation search tool). Don't guess APIs or ARNs.
- To inspect real account resources (CloudWatch logs, S3 items, DynamoDB
  schema), use the same `aws-mcp` server. Never ask for or use an access key.
- Never run a destructive action (delete, scaling) without confirming first.
</code></pre>
<p><code>inclusion: always</code> makes that rule part of every Kiro conversation in that project.</p>
<h3>The advanced path: SigV4 with the proxy</h3>
<p>If you landed on one of the SigV4 cases (multi-account, read-only mode, default region, no-OAuth org), the setup asks a bit more of your local machine: AWS CLI 2.32+ signed in with <code>aws login</code> (credentials rotate on their own every 15 minutes, sessions up to 12 hours), <code>uv</code> installed, and the proxy in <code>mcp.json</code>:</p>
<pre><code class="language-json">{
  "mcpServers": {
    "aws-mcp": {
      "command": "uvx",
      "args": [
        "mcp-proxy-for-aws==1.6.2",
        "https://aws-mcp.us-east-1.api.aws/mcp",
        "--metadata", "AWS_REGION=sa-east-1"
      ]
    }
  }
}
</code></pre>
<p>Pin the proxy version (your supply chain will thank you) and check PyPI for the current pin. The endpoint is regional (today <code>us-east-1</code> and <code>eu-central-1</code>); you connect to one of them and operate on resources in whatever region you pass in <code>AWS_REGION</code>. Check the current list in the <a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/getting-started-aws-mcp-server.html">official docs</a>, since this can change.</p>
<h2>The security part you can't ignore</h2>
<blockquote>
<p><strong>"Everything fails, all the time."</strong></p>
<p><em>Werner Vogels, Amazon CTO</em></p>
</blockquote>
<p>If there's one part not to skip, it's this one. Werner's right, and with an AI driving your account it's worth taking that literally: assume the agent will mess up sooner or later, and design for it. Giving it access to read and operate your account is as serious as it sounds, so it's worth doing carefully.</p>
<p>First thing: IAM is still the boss. The managed server doesn't go over your permissions, it rides on top of them. Treat the agent like a new coworker. Or better: like that fresh intern who does everything to the letter, no questions asked, and who's so afraid of getting it wrong that they don't even stop to think. The type who, if you tell them to go find the spark stockroom to store some in a bottle, will actually go looking. Yeah, the agent is just like that too: give it too much access and it'll use it, even when it makes no sense. So, least-privilege, scoped only to what the task needs, nothing beyond that. AWS added standardized IAM context keys for these managed MCP servers, so you can write policy that knows "this call came through the MCP server" and restrict accordingly.</p>
<p>Second: there's no long-lived key anywhere. With OAuth, what exists is a 1-hour token with automatic refresh; on the SigV4 path, temporary AWS CLI credentials that rotate on their own every 15 minutes. So no secret sits around in your shell history, your repo, or your <code>.env</code>, which is exactly where we tend to leak them.</p>
<p>Third: everything is auditable. CloudTrail logs every call and CloudWatch gives you the metrics. After an incident you can answer "what did the agent actually do?" with a straight face. If you can't answer that today about your current setup, that alone is reason enough to switch.</p>
<p>And one that's still coming: VPC endpoint support, for teams that need to keep this traffic inside the network boundary. If that's a hard requirement for you, wait for it before going to production.</p>
<p>My rule of thumb? One dedicated IAM role per agent purpose. If an agent gets compromised or goes sideways, the blast radius stops at that role. Don't reuse your admin identity. And don't hand it <code>*</code> on <code>*</code> "just to unblock the demo", because the demo becomes prod faster than you'd think.</p>
<h2>Setting up the AWS account side (the essentials)</h2>
<p>On the account side it's less than it seems, because the managed AWS MCP Server doesn't create IAM actions of its own. There's no <code>mcp:Invoke</code> to allow: it signs every call with SigV4 using your credentials and forwards it to the service, which authorizes against your usual policies. If your identity can't call <code>logs:GetLogEvents</code>, neither can the agent. Your current permissions are the boundary.</p>
<p>The quick-start is this: begin with a read-only identity (a dedicated role or an SSO permission set) and use the new context keys, <code>aws:ViaAWSMCPService</code> and <code>aws:CalledViaAWSMCP</code>, to deny destructive actions when the call comes from the agent, even if your role could do them. That way the agent reads all it wants and the dangerous verbs are blocked just for it. Then let CloudTrail show what it actually used and tighten the policy around that.</p>
<p>A simple guardrail, just so you get the idea:</p>
<pre><code class="language-json">{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "BlockDestructiveActionsViaMCP",
    "Effect": "Deny",
    "Action": ["dynamodb:DeleteTable", "s3:DeleteBucket", "lambda:DeleteFunction"],
    "Resource": "*",
    "Condition": { "Bool": { "aws:ViaAWSMCPService": "true" } }
  }]
}
</code></pre>
<p>This setup deserves a post of its own, done as code. Later in the series I'll publish an <strong>"IAM for AI agents on AWS, with CDK"</strong> covering the full step by step (CLI, console and CDK), cdk-nag, org-wide SCP and multi-account. I'll link it here once it's out.</p>
<h2>Which one to use: the decision changed</h2>
<p>When this post first went out, the answer was "depends on the pain". Three weeks later, AWS settled it: the official setup guide now recommends migrating to the AWS MCP Server and <strong>removing Knowledge (and the older AWS API MCP) from your configuration</strong>. The reason is practical: duplicate tools confuse the agent and hurt performance, and it's the docs themselves telling you to clean up.</p>
<p>Knowledge wasn't shut down. It's still GA, credential-free, working. One legitimate case remains: you want ONLY doc lookups, with no AWS account and nothing to authorize (studying a service, say). For everything else, it's one server: the managed one, which already does credential-free doc search and operates the account when you authorize it. Less config, fewer conflicts, same IAM leash.</p>
<h2>When NOT to reach for this</h2>
<p>Because there's no silver bullet, and someone has to say it.</p>
<p>Don't drop this on a production account with no guardrails. Start in a sandbox and get your IAM boundaries right before the agent can touch anything that bills or deletes. In the Frugal Architect, Werner makes the point that cost is an architecture requirement, not something to find out at the end of the month, and with an agent firing off calls that goes double.</p>
<p>Don't grant broad permissions "for now". There's no "for now", trust me. Scope it from the first connection.</p>
<p>And don't leave anything irreversible on autopilot. Deletes, scaling actions, money movement: keep a human in the loop. The agent proposes, you approve.</p>
<h2>Mind your region and compliance</h2>
<p>A few things that matter if you operate outside us-east-1 (for me, that's <code>sa-east-1</code>, São Paulo).</p>
<p>Before pointing the agent anywhere, confirm the services and the managed server are available in your region. And here's the nice part: that's literally a question the MCP server itself answers for you (the doc search does it, no credentials). Check it instead of assuming.</p>
<p>On data residency and privacy laws (LGPD here in Brazil, GDPR and friends elsewhere), if the agent is going to touch resources with personal data, scope IAM so it can't read what it shouldn't, and use the CloudTrail trail as evidence of who accessed what. Auditability here isn't just good engineering, it's a compliance argument.</p>
<p>And for small teams: that "free" CloudTrail trail is gold when you don't have a dedicated security team. You get a record of everything the agent did without building anything.</p>
<h2>To wrap up</h2>
<ol>
<li><p>There are two AWS MCP servers for two pains: knowledge (stop hallucinating) and action (operate the account safely).</p>
</li>
<li><p>The simple path is OAuth now: add the URL, log in through the browser, done. Works in Claude Code, the Claude app (Desktop and claude.ai), and Kiro.</p>
</li>
<li><p>The managed one gets you off <code>.env</code>: a short-lived token (OAuth) or temporary CLI credentials (SigV4), with least-privilege and everything logged to CloudTrail.</p>
</li>
<li><p>The official recommendation became one server: migrate to the AWS MCP Server and drop Knowledge from your config. It's still alive for credential-free doc lookups, but running both confuses the agent.</p>
</li>
</ol>
<p>If you've been doing the <code>.env</code> hack, relax, everyone has. But the tools to stop are right here, they're managed, and they're auditable. There's no good excuse left to keep handing your account's keys to a robot that occasionally goes off the rails.</p>
<p>This post kicks off a series on MCP and agents on AWS. Next up I go deep on two tracks: setting up IAM as code (CDK) and OpenAI landing on Bedrock. Which one first? Tell me in the comments.</p>
<p>Liked it? Drop a like, tell me what you think in the comments, and share it with your crew to keep the community strong. Thanks a lot for reading this far. See you in the next one? =D</p>
<h2>Want to go deeper</h2>
<ul>
<li><p><a href="https://github.com/awslabs/mcp">AWS's open source MCP servers (awslabs/mcp)</a>, home of the Knowledge MCP Server</p>
</li>
<li><p><a href="https://github.com/aws/agent-toolkit-for-aws">Agent Toolkit for AWS</a>, where the managed AWS MCP Server lives</p>
</li>
<li><p><a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/mcp-server.html">AWS MCP Server, the official page</a></p>
</li>
<li><p><a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/getting-started-aws-mcp-server.html">Official AWS MCP Server setup (OAuth and SigV4)</a></p>
</li>
<li><p><a href="https://aws.amazon.com/blogs/aws/the-aws-mcp-server-is-now-generally-available/">The AWS MCP Server is now GA (official announcement)</a></p>
</li>
</ul>
<p><em>Prefer Portuguese?</em> <a href="https://willpeixoto.dev/aws-mcp-server-qual-usar-quando-e-como-configurar-os-dois-servidores-explicados"><em>Read the PT version here</em></a><em>.</em></p>
]]></content:encoded></item><item><title><![CDATA[AWS MCP Server: qual usar, quando e como configurar (agora que a AWS recomenda um só)]]></title><description><![CDATA[🇺🇸 Also available in English: AWS MCP Server: which one to use, when, and how to set it up
Deixa eu te contar uma cena. Aposto que você já viveu ela.
São 11 da noite, você tá de boas codando com a a]]></description><link>https://willpeixoto.dev/aws-mcp-server-qual-usar-quando-e-como-configurar-os-dois-servidores-explicados</link><guid isPermaLink="true">https://willpeixoto.dev/aws-mcp-server-qual-usar-quando-e-como-configurar-os-dois-servidores-explicados</guid><category><![CDATA[AWS]]></category><category><![CDATA[mcp]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Security]]></category><category><![CDATA[serverless]]></category><dc:creator><![CDATA[Willian Peixoto]]></dc:creator><pubDate>Sat, 20 Jun 2026 17:26:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/0bf84943-4284-426e-b624-51ce65349f3c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>🇺🇸 Also available in English:</em> <a href="https://willpeixoto.dev/aws-mcp-server-which-to-use-and-configure"><em>AWS MCP Server: which one to use, when, and how to set it up</em></a></p>
<p>Deixa eu te contar uma cena. Aposto que você já viveu ela.</p>
<p>São 11 da noite, você tá de boas codando com a ajuda de uma IA do lado. Você faz uma pergunta pra ela e ela jura que existe: inventa um serviço, um nome que bate com algo parecido que você já fez, e até uma implementação que ela garante que funciona, com tudo e como resolver. E você pensa: caramba, não sabia disso, preciso olhar melhor a documentação porque faz muito sentido. E bang, você descobre que ela tava alucinando. Tava escrevendo código na Lambda chamando um serviço da AWS de uma função que não existe, ligando a tabela do DynamoDB, montando o IaC, tudinho. Aí ela pede pra "dar uma olhada na config atual da sua conta" pra validar os nomes, e você bate na parede que todo mundo bate.</p>
<p>O agente, além de alucinar, não tem acesso à sua conta. Ele não enxerga seus recursos, não faz ideia do que realmente tá lá. E faz o que ele faz de melhor: é criativo, é proativo, e inventa algo pra te deixar feliz. Pra ele, aquilo faz sentido existir, então ele assume que existe. O bichinho não fica nem com vergonha: na maior cara de pau, devolve um ARN que não existe, escolhe uma região que você nem usa e chuta o nome de uma tabela. Dá-lhe. Ele tá fazendo exatamente o que foi programado pra fazer: te deixar feliz.</p>
<p>E você, cansado de brigar com ele e já querendo finalizar, faz o quê? Cola uma access key num <code>.env</code> pra ele "só enxergar a conta um segundinho" e te devolver tudo certinho, com os nomes verdadeiros. Quem nunca?</p>
<p>E tá tudo bem, só que tem um detalhe: você esquece que fez isso. E bang, o <code>.env</code> foi junto no commit. Já tá no histórico do git, alerta pra todo lado, aquela doideira de sempre. Pronto, a chave tá exposta. E é assim também que o seu agente, naquele momento em que parece que quer te punir ou que resolveu ser proativo demais, ganha acesso de verdade à sua conta e, sei lá, decide apagar a stack errada. Ou então é só a continha surpresa de R$ 40 num dia, que vira um número bem pior quando ninguém tá olhando. Eu já passei por isso. Você provavelmente também.</p>
<p>A boa notícia é que a AWS resolveu esse problema. Na real, resolveu de duas formas diferentes, com nomes tão parecidos que confunde muita gente. Esse post é o mapa que eu queria ter tido: o que são os dois, qual dor cada um mata, e quando e como usar cada. Vamos lá.</p>
<blockquote>
<p><strong>Nota de validade:</strong> esse mundo de MCP muda rápido. Escrevi este guia em junho de 2026 e já precisei atualizar em julho de 2026, quando o fluxo de conexão mudou (a versão que você está lendo traz o OAuth direto). Vou procurar manter em dia conforme sair novidade, mas se algo não bater com a tela na sua frente, confere a <a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/mcp-server.html">doc oficial</a> e me avisa nos comentários que eu corrijo.</p>
</blockquote>
<h2>O que você vai sair sabendo</h2>
<p>Pra você não se perder, é isso que a gente cobre aqui:</p>
<ul>
<li><p>A diferença entre os dois servidores MCP da AWS e qual dor cada um resolve</p>
</li>
<li><p>Como conectar no Claude Code, no app do Claude e no Kiro, passo a passo</p>
</li>
<li><p>Como configurar o IAM da sua conta pra dar acesso com segurança</p>
</li>
<li><p>Quando NÃO usar, e os cuidados pra não tomar susto na conta</p>
</li>
</ul>
<h2>Mas o que é MCP afinal?</h2>
<p>Antes de falar dos servidores, vamos nivelar.</p>
<p>O MCP (<a href="https://modelcontextprotocol.io">Model Context Protocol</a>) é o "plugue" que o seu assistente de IA usa pra falar com o mundo lá fora: ferramentas, dados e serviços. A Anthropic criou, hoje ele tá sob governança aberta, e no último ano todo assistente que presta (Claude Code, Kiro, Cursor) passou a falar MCP.</p>
<p>Quer uma analogia fácil? Pensa na API. A API é o que deixa duas aplicações conversarem entre si. O MCP é a mesma ideia, só que pro agente: é o que deixa a IA conversar com qualquer ferramenta sem você ter que criar uma integração personalizada pra cada sistema diferente. O MCP conecta o agente ao sistema num padrão que todo mundo combinou de usar. E o bom de ser padrão é esse: você aprende uma vez e serve pra qualquer ferramenta e qualquer cliente. Então, se você quer dar acesso ao seu sistema pra uma IA, é por esse caminho que você vai.</p>
<p>E tem uma coisa que facilita demais: na maioria dos casos, você nem precisa construir um MCP server seu. Dá pra construir, claro (rodando no Lambda, no Fargate, no que você preferir), e a AWS até tem um <a href="https://aws.amazon.com/solutions/guidance/deploying-model-context-protocol-servers-on-aws/">guidance oficial pra isso</a> se for o seu caso. Mas a AWS já roda servidores gerenciados prontos, então muita vez é só plugar e usar. Construir o seu faz sentido quando a ideia é outra: expor o SEU sistema interno (uma API, um runbook, um alerta) pro agente.</p>
<h2>Os dois servidores MCP da AWS</h2>
<p>Pois é, são dois. E os nomes não ajudam em nada, viu. Olha tudo numa tabela só e depois eu destrincho cada um:</p>
<table>
<thead>
<tr>
<th></th>
<th><strong>AWS Knowledge MCP Server</strong></th>
<th><strong>AWS MCP Server</strong> (gerenciado, GA)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Que dor resolve</strong></td>
<td>"Meu agente alucina API, ARN e nome de serviço da AWS."</td>
<td>"Meu agente precisa ver ou agir na minha conta, sem eu vazar chave."</td>
</tr>
<tr>
<td><strong>O que acessa</strong></td>
<td>Só documentação e conhecimento da AWS (read-only)</td>
<td>Documentação + serviços reais da <em>sua</em> conta (autenticado)</td>
</tr>
<tr>
<td><strong>Credenciais</strong></td>
<td>Nenhuma. Nem conta AWS você precisa.</td>
<td>Login AWS no browser (OAuth) ou AWS CLI (SigV4)</td>
</tr>
<tr>
<td><strong>Auditoria</strong></td>
<td>Não se aplica</td>
<td>CloudTrail + CloudWatch</td>
</tr>
<tr>
<td><strong>Use quando</strong></td>
<td>Quer sintaxe certa, docs atuais, disponibilidade regional</td>
<td>Quer o agente inspecionando ou operando infra real</td>
</tr>
<tr>
<td><strong>Risco se usar errado</strong></td>
<td>Praticamente zero</td>
<td>Real. É a sua conta. Least-privilege importa.</td>
</tr>
</tbody></table>
<p>Se você guardar uma frase só desse post, guarda essa:</p>
<blockquote>
<p><strong>Um servidor dá conhecimento pro seu agente. O outro dá mãos pra ele.</strong></p>
</blockquote>
<p>Sacar qual problema você tem de verdade já é metade do caminho.</p>
<p>Quer outra analogia? O Knowledge é o guru: aquele amigo que decorou a documentação inteira da AWS e tira sua dúvida na hora. Já o gerenciado é o porteiro cara-crachá: ele te deixa entrar na conta de verdade, mas fica ali conferindo e só abre as portas que o IAM autorizou. Cara, crachá. Não bateu, não passa.</p>
<blockquote>
<p><strong>Onde isso roda?</strong> O AWS MCP Server é remoto, e quem conecta nele é o MCP client: Claude Code, app do Claude (Desktop e claude.ai), Kiro, Cursor, ou o código do seu próprio agente (Strands, SDK). Isso vale inclusive com a inferência rodando no Bedrock, porque o client é a aplicação, nunca o modelo. Já um agente de produção no AgentCore normalmente consome tools pelo AgentCore Gateway (que também fala MCP) ou por um MCP server seu. Esse cenário de produção fica para outro post da série.</p>
</blockquote>
<h2>Servidor #1: AWS Knowledge MCP Server</h2>
<p>O que esse servidor faz é simples: é remoto, totalmente gerenciado, e dá ao modelo acesso estruturado à documentação oficial, sempre atualizada. E esse "atualizada" é o ponto. O que o modelo sabe sozinho para na data de treino dele, então ele não conhece o que veio depois e acaba chutando. A AWS mantém esse servidor em dia, então ele vira a sua fonte da verdade: busca na doc, traz a página em markdown limpo, checa se um serviço existe numa região e lista as regiões atuais. Só leitura, não escreve nem toca na conta.</p>
<p>Por que é quase óbvio ligar? Porque não tem credencial, e nem conta AWS é necessária. Não tem nada pra proteger, nada pra vazar. O risco é praticamente zero e o ganho é o agente parar de chutar e começar a citar a doc real antes de cuspir o CDK.</p>
<p>Use quando você tá aprendendo um serviço, desenhando a arquitetura que quer construir e validando a ideia, conferindo sintaxe, gerando IaC em que você confia, ou respondendo "isso já tá na minha região?" sem precisar abrir o navegador. Ligar é colar uma URL: adiciona <code>https://knowledge-mcp.global.api.aws</code> como servidor remoto (HTTP) no teu cliente e pronto, sem credencial nenhuma. Com ele no ar, o agente consulta a doc live antes de cuspir o CDK em vez de chutar pelo que viu no treino. ARN alucinado despenca. Legal não?</p>
<h2>Servidor #2: AWS MCP Server, o gerenciado (que lê e opera a conta)</h2>
<p>Esse aqui é o que cura a vergonha do <code>.env</code>.</p>
<p>A dor é outra: o agente precisa ver ou fazer algo na conta de verdade. Ler o log do CloudWatch da função que tá quebrando, listar o que realmente tem no bucket, conferir o schema da tabela do DynamoDB. A "solução" antiga era entregar credencial de longa duração pra ele. É essa parte que tira o sono do pessoal de segurança. E, sinceramente, devia tirar o seu também.</p>
<p>O que esse servidor faz: ele é remoto, hospedado e gerenciado pela AWS, e dá ao agente acesso autenticado aos serviços da AWS através de um conjunto pequeno e fixo de ferramentas. Sem instalação local, com update automático, e (essa parte eu curto demais) toda chamada vai parar no CloudTrail. O agente não ganha uma chave-mestra. Ele se autentica como você, por um fluxo de auth de verdade, com a sua identidade do IAM.</p>
<p>O fluxo de auth, em bom português: agora são dois caminhos, e o mais novo é o mais simples. Hoje o servidor fala <strong>OAuth direto</strong>. Você adiciona a URL no seu cliente, a primeira chamada de tool abre o browser no AWS Sign-in, você entra com a sua identidade de sempre e pronto. O token dura 1 hora e se renova sozinho por até 12. Sem proxy, sem instalar nada.</p>
<p>O segundo caminho é o <strong>SigV4 com o</strong> <code>mcp-proxy-for-aws</code>, um proxy open source que roda na sua máquina, pega as suas credenciais locais da AWS CLI e assina cada chamada. Ele continua existindo e tem hora certa: múltiplas contas na mesma sessão, read-only mode (esconder as tools de escrita do agente), região default fixa, ou organização que bloqueia as permissions de OAuth (<code>signin:AuthorizeOAuth2Access</code> e <code>signin:CreateOAuth2Token</code>).</p>
<p>Nos dois casos o resultado é o mesmo: você não cola chave em lugar nenhum, o agente age com a sua identidade, e tudo respeita o seu IAM. Busca na documentação, aliás, nem credencial precisa.</p>
<p>O fluxo OAuth, passo a passo:</p>
<ol>
<li><p>Você anexa a managed policy <code>AWSMCPSignInOAuthAccessPolicy</code> na sua role ou user (uma vez).</p>
</li>
<li><p>Adiciona a URL do servidor no cliente e dispara a primeira chamada.</p>
</li>
<li><p>O browser abre no AWS Sign-in, você autoriza, e o cliente guarda o token (1 hora, refresh automático até 12).</p>
</li>
<li><p>O server aplica as context keys e repassa para o serviço da AWS.</p>
</li>
<li><p>O IAM autoriza pela sua policy e responde.</p>
</li>
<li><p>A chamada inteira fica registrada no CloudTrail.</p>
</li>
</ol>
<p>O momento "aaah, sacou" é esse: pergunta "por que o <code>checkout-prod</code> começou a dar 500 depois das 14h?" e vê o agente puxar o log real do CloudWatch, cruzar com um deploy recente e apontar o recurso de verdade. Tudo dentro do que o IAM permite, tudo auditável, sem chave em dotfile nenhum. E funciona com o que você já usa: Claude Code, Kiro, Cursor, qualquer cliente compatível com MCP.</p>
<h2>Como conectar: Claude Code, app do Claude e Kiro</h2>
<p>Agora a parte prática. O pré-requisito do caminho OAuth é um só: a identidade que você vai usar precisa da managed policy de sign-in. Anexa uma vez e esquece:</p>
<pre><code class="language-bash">aws iam attach-role-policy \
  --role-name SuaRole \
  --policy-arn arn:aws:iam::aws:policy/AWSMCPSignInOAuthAccessPolicy
</code></pre>
<p>(Se você usa IAM user em vez de role, é <code>attach-user-policy</code> com <code>--user-name</code>.)</p>
<h3>No Claude Code</h3>
<p>Uma linha, e é isso mesmo:</p>
<pre><code class="language-bash">claude mcp add aws-mcp https://aws-mcp.us-east-1.api.aws/mcp --transport http
</code></pre>
<p>Na primeira chamada de tool o browser abre, você loga, e o agente já enxerga a conta pela sua identidade do IAM.</p>
<p>Tem também um segundo jeito: o plugin <code>aws-core</code>. Além do AWS MCP Server já configurado, ele traz as agent skills da AWS, que são pacotes de instrução prontos para o agente executar bem tarefas de CDK, serverless, containers e billing. Se você quer o server mais esse contexto extra de uma vez, instala do marketplace oficial da Anthropic, que já vem registrado no Claude Code:</p>
<pre><code class="language-bash">/plugin install aws-core@claude-plugins-official
</code></pre>
<p>Detalhe que confunde: esse comando roda dentro do Claude Code, no terminal. A seção "Plugins" do app Claude Desktop é outro catálogo, então não procura o <code>aws-core</code> lá (no app, o caminho é o connector da próxima seção). O equivalente do steering aqui é um <code>CLAUDE.md</code> na raiz do projeto, com as mesmas regras que eu mostro no bloco do Kiro logo abaixo.</p>
<h3>No app do Claude (Desktop e claude.ai)</h3>
<p>Sim, funciona no app, sem terminal. No Claude Desktop: Settings, Connectors, "Add custom connector", dá um nome (eu chamei de <code>aws-mcp</code>) e cola a URL:</p>
<pre><code class="language-plaintext">https://aws-mcp.us-east-1.api.aws/mcp?oauth=initialize
</code></pre>
<p>O sufixo <code>?oauth=initialize</code> instrui o server a disparar o fluxo OAuth explicitamente (Cursor e Kiro IDE usam o mesmo truque). Os campos de OAuth Client ID e Secret ficam vazios, o fluxo cuida disso. No claude.ai web é a mesma URL sem o sufixo, nas configurações de conector.</p>
<blockquote>
<p><strong>No Codex:</strong> use a URL limpa, sem <code>?oauth=initialize</code>: <code>https://aws-mcp.us-east-1.api.aws/mcp</code>. O Codex detecta e inicia o OAuth automaticamente.</p>
</blockquote>
<img src="./assets/claude-desktop-add-connector.png" alt="Adicionando o AWS MCP Server como custom connector no Claude Desktop" style="display:block;margin:0 auto" />

<p>Na primeira chamada abre a tela de autorização da AWS:</p>
<img src="./assets/aws-mcp-oauth-signin.png" alt="Tela de consent do AWS Sign-in conectando o MCP client ao AWS MCP Server" style="display:block;margin:0 auto" />

<p>Dois avisos aqui, porque eu caí neles primeiro para você não cair:</p>
<p><strong>Não é o conector do Directory.</strong> Se você buscar "AWS" no diretório de conectores do Claude, aparece um "AWS API MCP Server". Ele NÃO é o gerenciado novo: é o <code>aws-api-mcp-server</code> antigo do awslabs (repara nas tools dele, só <code>suggest_aws_commands</code> e <code>call_aws</code>), justamente um dos que a doc oficial manda substituir. O caminho certo é o custom connector com a URL acima. E não rode os dois juntos, que é o cenário exato de conflito de tools que a AWS alerta.</p>
<p><strong>Não autorize como root.</strong> A tela de consent oferece "Continue with Root or IAM user" e diz que o acesso segue "your existing AWS permissions". A identidade que você usar ali define o raio de acesso do agente. Entra com um IAM user ou role dedicada, com a managed policy de sign-in e least-privilege. Root pilotado por agente é tudo que a gente não quer. E um sinal de alerta prático: se a conexão funcionou sem você anexar policy nenhuma, investiga com um <code>aws sts get-caller-identity</code>. Ou a tua identidade é admin, ou você entrou como root, que nem passa pelo IAM imagina um agente operando root na conta inteira, é o que não queremos.</p>
<h3>No Kiro</h3>
<p>No Kiro CLI (2.11 em diante):</p>
<pre><code class="language-bash">kiro-cli mcp add --name aws-mcp --url https://aws-mcp.us-east-1.api.aws/mcp
</code></pre>
<p>No Kiro IDE, adiciona como servidor remoto com a URL <code>?oauth=initialize</code>, ou via <code>mcp.json</code> (por projeto em <code>&lt;raiz&gt;/.kiro/settings/mcp.json</code>, global em <code>~/.kiro/settings/mcp.json</code>; quando os dois existem, o do projeto ganha).</p>
<p>Só que config liga o server, não garante que o Kiro vá usar. Para ele preferir essas tools, cria um steering file em <code>.kiro/steering/aws-mcp.md</code>:</p>
<pre><code class="language-markdown">---
inclusion: always
---

# Uso de AWS via MCP

- Antes de gerar código ou IaC de AWS (CDK, CloudFormation, SDK), valide nome
  de serviço, sintaxe e disponibilidade regional na doc via server `aws-mcp`
  (tool de busca na documentação). Não chute API nem ARN.
- Para inspecionar recursos reais da conta (logs do CloudWatch, itens do S3,
  schema do DynamoDB), use o mesmo server `aws-mcp`. Nunca peça nem use access key.
- Nunca rode ação destrutiva (delete, scaling) sem confirmar antes.
</code></pre>
<p>O <code>inclusion: always</code> faz essa regra entrar em toda conversa do Kiro naquele projeto.</p>
<h3>O caminho avançado: SigV4 com proxy</h3>
<p>Se você caiu num dos casos do SigV4 (multi-conta, read-only mode, região default, org sem OAuth), o setup pede um pouco mais de máquina local: AWS CLI 2.32+ logada com <code>aws login</code> (as credenciais giram sozinhas a cada 15 minutos, sessão de até 12 horas), <code>uv</code> instalado, e o proxy no <code>mcp.json</code>:</p>
<pre><code class="language-json">{
  "mcpServers": {
    "aws-mcp": {
      "command": "uvx",
      "args": [
        "mcp-proxy-for-aws==1.6.2",
        "https://aws-mcp.us-east-1.api.aws/mcp",
        "--metadata", "AWS_REGION=sa-east-1"
      ]
    }
  }
}
</code></pre>
<p>Deixe a versão do proxy pinada (supply chain agradece) e confira de vez em quando no PyPI se saiu versão nova. O endpoint é regional (hoje <code>us-east-1</code> e <code>eu-central-1</code>); você conecta num deles e opera nos recursos da região que passar em <code>AWS_REGION</code>. Confere o atual na <a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/getting-started-aws-mcp-server.html">doc oficial</a>, que isso pode mudar.</p>
<h2>A parte de segurança que você não pode ignorar</h2>
<blockquote>
<p><strong>"Everything fails, all the time."</strong></p>
<p><em>Werner Vogels, CTO da Amazon</em></p>
</blockquote>
<p>Se tem uma parte pra não pular, é essa. O Werner tá certo, e com uma IA pilotando a sua conta vale levar a frase ao pé da letra: parte do princípio de que uma hora o agente vai aprontar, e projete pra isso. Dar acesso pra ele ler e operar a conta é tão sério quanto parece, então vale fazer com cuidado.</p>
<p>Primeira coisa: o IAM continua sendo o chefe. O servidor gerenciado não passa por cima das suas permissões, ele anda em cima delas. Trate o agente como um colega de trabalho novo. Ou melhor: como aquele estagiário recém-formado que faz tudo ao pé da letra, sem questionar, e que, com medo de fazer errado, nem para pra pensar. É o tipo que, se você mandar procurar o estoque de faísca pra guardar numa garrafa, ele sai atrás de boa. Pois é, o agente é assim também: se você der acesso demais, ele usa, mesmo quando não faz o menor sentido. Por isso, least-privilege, escopado só pro que a tarefa precisa, e nada além disso. A AWS criou context keys de IAM padronizadas pra esses servidores MCP gerenciados, então dá pra escrever policy que sabe "essa chamada veio pelo MCP server" e restringir de acordo.</p>
<p>E quando o assunto sai de "dar permissão pro agente" e vira "rodar código que eu não escrevi", o isolamento entra na conversa junto com o IAM. Eu tratei desse outro lado em <a href="https://willpeixoto.dev/aws-lambda-microvms-codigo-isolado-serverless">AWS Lambda MicroVMs: rode código não confiável com isolamento de VM</a>.</p>
<p>Segunda: não tem chave de longa duração em lugar nenhum. No OAuth, o que existe é um token de 1 hora com refresh automático; no caminho SigV4, as credenciais temporárias da AWS CLI, que giram sozinhas a cada 15 minutos. Ou seja, não sobra segredo parado no seu histórico de shell, no repo ou no <code>.env</code>, que é exatamente onde a gente costuma vazar.</p>
<p>Terceira: tudo é auditável. O CloudTrail loga cada chamada e o CloudWatch te dá as métricas. Depois de um incidente, você responde "o que o agente fez, afinal?" de cara limpa. Se hoje você não consegue responder isso sobre o seu setup atual, só isso já é motivo de sobra pra trocar.</p>
<p>E uma que ainda tá chegando: suporte a VPC endpoint, pra quem precisa manter esse tráfego dentro da fronteira da rede. Se isso é requisito duro pra você, espera por ele antes de levar pra produção.</p>
<p>Minha regra de bolso? Uma role de IAM dedicada por propósito de agente. Se um agente for comprometido ou der ruim, o estrago para naquela role. Não reusa sua identidade de admin. E não dá <code>*</code> em <code>*</code> "só pra destravar a demo", porque a demo vira prod mais rápido do que você imagina.</p>
<h2>Configurando o lado da SUA conta AWS (o essencial)</h2>
<p>Do lado da conta é menos coisa do que parece, porque o AWS MCP Server gerenciado não cria ações de IAM próprias. Não existe <code>mcp:Invoke</code> pra liberar: ele assina cada chamada com SigV4 usando as suas credenciais e encaminha pro serviço, que autoriza pelas suas policies de sempre. Se a sua identidade não pode chamar <code>logs:GetLogEvents</code>, o agente também não pode. As suas permissões atuais são a fronteira.</p>
<p>O quick-start é esse: comece com uma identidade read-only (uma role dedicada ou um permission set de SSO) e use as context keys novas, <code>aws:ViaAWSMCPService</code> e <code>aws:CalledViaAWSMCP</code>, pra negar ação destrutiva quando a chamada vier do agente, mesmo que a sua role pudesse fazer. Assim o agente lê à vontade e os verbos perigosos ficam bloqueados só pra ele. Depois, deixa o CloudTrail mostrar o que ele realmente usou e aperta a policy em cima disso.</p>
<p>Um guardrail simples, só pra você pegar a ideia:</p>
<pre><code class="language-jsonc">{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "BlockDestructiveActionsViaMCP",
    "Effect": "Deny",
    "Action": ["dynamodb:DeleteTable", "s3:DeleteBucket", "lambda:DeleteFunction"],
    "Resource": "*",
    "Condition": { "Bool": { "aws:ViaAWSMCPService": "true" } }
  }]
}
</code></pre>
<p>Esse setup merece um post só dele, feito como código. Vou soltar num próximo post da série um <strong>"IAM pra agente de IA na AWS, com CDK"</strong> com o passo a passo completo (CLI, console e CDK), cdk-nag, SCP org-wide e multi-conta. Quando sair, linko aqui.</p>
<h2>Qual dos dois usar: a decisão mudou</h2>
<p>Quando esse post saiu, a resposta era "depende da dor". Três semanas depois, a AWS bateu o martelo: o setup guide oficial agora recomenda migrar para o AWS MCP Server e <strong>remover o Knowledge (e o antigo AWS API MCP) da configuração</strong>. O motivo é prático: tools duplicadas confundem o agente e derrubam a performance, e é a própria doc que manda limpar.</p>
<p>O Knowledge não foi desligado. Continua GA, sem credencial, funcionando. Sobrou um caso legítimo para ele: você quer SÓ consultar doc, sem conta AWS e sem autorizar nada (estudando um serviço, por exemplo). Para todo o resto, é um servidor só: o gerenciado, que já faz busca na doc sem credencial e opera a conta quando você autorizar. Menos config, menos conflito, mesma identidade sua do IAM.</p>
<h2>Quando NÃO usar isso</h2>
<p>Porque não existe bala de prata, e alguém tem que falar.</p>
<p>Não solta isso numa conta de produção sem guardrail. Começa num sandbox e acerta as fronteiras de IAM antes do agente poder tocar em qualquer coisa que cobra ou apaga. No Frugal Architect, o Werner prega que custo é requisito de arquitetura, não algo pra descobrir no fim do mês, e com um agente disparando chamada isso vale dobrado.</p>
<p>Não libera permissão larga "por enquanto". Não existe "por enquanto", confia em mim. Escopa desde a primeira conexão.</p>
<p>E não deixa coisa irreversível no automático. Delete, ação de scaling, movimentação de dinheiro: mantém humano no loop. O agente propõe, você aprova.</p>
<h2>Recorte Brasil</h2>
<p>Três pontos que importam pra quem opera aqui em São Paulo.</p>
<p>O primeiro é a região <code>sa-east-1</code>. Antes de apontar o agente, confirma a disponibilidade dos serviços e do servidor gerenciado na região de São Paulo. E olha que beleza: essa é literalmente uma pergunta que o próprio MCP server responde pra você (a busca na doc faz isso, sem credencial). Vale checar em vez de assumir.</p>
<p>O segundo é LGPD e residência de dado. Se o agente vai tocar em recurso com dado pessoal, escopa o IAM pra ele não conseguir ler o que não deve, e usa a trilha do CloudTrail como evidência de quem acessou o quê. Auditabilidade aqui não é só boa prática técnica, é argumento de conformidade.</p>
<p>O terceiro é auditoria pra time pequeno. Esse CloudTrail "de graça" é ouro pra quem não tem um time de segurança dedicado. Você ganha o registro de tudo que o agente fez sem montar nada.</p>
<h2>Pra fechar</h2>
<ol>
<li><p>São dois servidores MCP da AWS pra duas dores: conhecimento (parar de alucinar) e ação (operar a conta com segurança).</p>
</li>
<li><p>O caminho simples agora é OAuth: adiciona a URL, loga no browser e pronto. Funciona no Claude Code, no app do Claude (Desktop e claude.ai) e no Kiro.</p>
</li>
<li><p>O gerenciado te tira do <code>.env</code>: token de curta duração (OAuth) ou credenciais temporárias da CLI (SigV4), com least-privilege e tudo logado no CloudTrail.</p>
</li>
<li><p>A recomendação oficial virou um servidor só: migre para o AWS MCP Server e tire o Knowledge da config. Ele segue vivo para consulta de doc sem credencial, mas rodar os dois juntos confunde o agente.</p>
</li>
</ol>
<p>Se você vinha fazendo a gambiarra do <code>.env</code>, relaxa, todo mundo já fez. Mas as ferramentas pra parar estão aqui, são gerenciadas e são auditáveis. Não tem mais desculpa boa pra continuar entregando as chaves da sua conta pra um robô que de vez em quando viaja na maionese.</p>
<p>Esse post abre uma série sobre MCP e agentes na AWS. Nos próximos eu vou fundo em dois caminhos: configurar o IAM como código (CDK) e a OpenAI chegando no Bedrock.Comenta aí.</p>
<p>Curtiu? Manda aquele joinha, comenta o que achou e compartilha com a galera pra fortalecer. Valeu demais por ler até aqui.Te vejo no próximo? BUILD ESCALE REPEAT =D</p>
<h2>Pra ir mais fundo</h2>
<ul>
<li><p><a href="https://github.com/awslabs/mcp">Os MCP servers open source da AWS (awslabs/mcp)</a>, onde vive o Knowledge MCP Server</p>
</li>
<li><p><a href="https://github.com/aws/agent-toolkit-for-aws">Agent Toolkit for AWS</a>, de onde vem o AWS MCP Server gerenciado</p>
</li>
<li><p><a href="https://aws.amazon.com/blogs/aws/the-aws-mcp-server-is-now-generally-available/">AWS MCP Server agora em GA (anúncio oficial)</a></p>
</li>
<li><p><a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/mcp-server.html">AWS MCP Server, a página oficial</a></p>
</li>
<li><p><a href="https://docs.aws.amazon.com/agent-toolkit/latest/userguide/getting-started-aws-mcp-server.html">Setup oficial do AWS MCP Server (OAuth e SigV4)</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Resiliência em Arquitetura: A Decisão é Estratégica, não apenas Técnica]]></title><description><![CDATA[🇺🇸 Also available in English: Resilience in Architecture: The Decision Is Strategic, Not Just Technical
Depois de um outage grande como o que vimos recentemente na AWS, a fumaça sobe e, invariavelme]]></description><link>https://willpeixoto.dev/resiliencia-custo-ha-multi-regiao-ou-on-premise</link><guid isPermaLink="true">https://willpeixoto.dev/resiliencia-custo-ha-multi-regiao-ou-on-premise</guid><category><![CDATA[AWS]]></category><category><![CDATA[architecture]]></category><category><![CDATA[Reliability]]></category><category><![CDATA[Disaster recovery]]></category><category><![CDATA[Cloud Computing]]></category><dc:creator><![CDATA[Willian Peixoto]]></dc:creator><pubDate>Thu, 23 Oct 2025 04:49:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/615b22eead6beb6f6506f2b9/5651f416-5dc7-4438-8e52-a20c1d3d02af.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>🇺🇸 Also available in English:</em> <a href="https://willpeixoto.dev/resilience-in-architecture-the-decision-is-strategic-not-just-technical"><em>Resilience in Architecture: The Decision Is Strategic, Not Just Technical</em></a></p>
<p>Depois de um <em>outage</em> grande como o que vimos recentemente na AWS, a fumaça sobe e, invariavelmente, surgem as mesmas perguntas que assombram <em>CTOs</em> e arquitetos:</p>
<blockquote>
<p><em>"Deveríamos estar em multi-região?" ou pior (e até um pouco nostálgica): "Será que deveríamos voltar para o on-premise?"</em></p>
</blockquote>
<p><strong>A verdade é que a resposta certa raramente é técnica.</strong></p>
<p><strong>Ela é, antes de tudo, estratégica.</strong></p>
<p>Como o próprio <strong>Werner Vogels (CTO da AWS)</strong> costuma cravar em suas palestras:</p>
<blockquote>
<p><em>"Everything fails, all the time."</em> (Tudo falha, o tempo todo).</p>
</blockquote>
<p>E é exatamente isso. A questão central não é <strong>se</strong> vai falhar, é <strong>quando</strong> vai falhar e <strong>como</strong> você estará preparado quando esse momento inevitável chegar. Porque ele virá. Quer você esteja na nuvem, no <em>on-premises</em> ou em uma complexa arquitetura <em>multi-cloud</em>.</p>
<p>O que realmente diferencia times resilientes não é a ausência de falhas, mas a <strong>velocidade, clareza e eficácia</strong> com que respondem e se recuperam.</p>
<p>E é aí que entra a verdadeira maturidade arquitetural: resiliência não é sobre escolher "multi-região" ou "on-premises". É sobre <strong>entender o risco inerente, documentar a escolha de forma transparente e reagir com um plano</strong>.</p>
<h2>O Contexto por Trás da Pergunta: O Paradoxo da Falha Visível</h2>
<p>Toda vez que há um grande <em>outage</em>, noto que times técnicos e executivos tendem a se dividir entre duas reações extremas, movidas pelo medo e pela pressão:</p>
<ul>
<li><p>"Precisamos ser multi-região urgente! O custo é secundário!"</p>
</li>
<li><p>"Tá vendo? Cloud não é confiável. Devíamos ter ficado on-premise, onde tínhamos o controle!"</p>
</li>
</ul>
<p>Ambos os extremos são atalhos perigosos.</p>
<p>Multi-região não é uma vacina contra a indisponibilidade, e voltar para o <em>on-premise</em> não é sinônimo de controle (apenas transfere a complexidade de manutenção).</p>
<blockquote>
<p><strong>Ponto de Reflexão Crucial:</strong> A nuvem não falha mais do que um <em>data center</em> tradicional. Ela apenas falha de forma mais <strong>visível, compartilhada e, ironicamente, democrática</strong>. Na AWS, os problemas escalam globalmente e se tornam <em>trending topics</em> em minutos. No <em>on-premise</em>, eles ficam escondidos atrás de <em>logs</em> dispersos, longos tempos de reparo e, muitas vezes, apenas impactam você. <strong>Honestamente, você acredita que sua empresa tem uma capacidade superior à AWS (ou a qualquer grande <em>cloud provider</em>) para gerenciar a segurança física, o cabeamento, a energia, o resfriamento e, principalmente, a <em>resiliência</em> de uma infraestrutura em escala global?</strong></p>
</blockquote>
<p>Migrar ou evoluir a arquitetura, no fundo, não é sobre "jogar tudo fora" ou "comprar o hype". É sobre <strong>aproveitar o que o legado tem de bom e eliminar o que limita o crescimento</strong>.</p>
<p>Não é uma briga maniqueísta de <em>"Cloud vs. Data Center"</em>. É um jogo estratégico de <strong>Resiliência Consciente vs. Zona de Conforto</strong>.</p>
<h2>Custo vs Continuidade: A Economia por Trás dos 9s</h2>
<p>No mundo da infraestrutura, cada "9" adicional no SLA (Service Level Agreement) não apenas custa, mas custa <strong>exponencialmente</strong> mais.</p>
<p>Para ilustrar o impacto real de cada nível de disponibilidade, veja o <em>downtime</em> máximo permitido por ano:</p>
<ul>
<li><p><strong>99% (Dois 9s):</strong> Cerca de <strong>3,6 dias</strong> fora do ar por ano. <em>Custo e complexidade:</em> Base (Custo 1x).</p>
</li>
<li><p><strong>99,9% (Três 9s):</strong> Cerca de <strong>8 horas e 46 minutos</strong> fora do ar por ano. <em>Custo e complexidade:</em> Custo 1,5x a 2x o ambiente base.</p>
</li>
<li><p><strong>99,99% (Quatro 9s):</strong> Cerca de <strong>52 minutos</strong> fora do ar por ano. <em>Custo e complexidade:</em> Custo 2x a 3x. Exige Multi-AZ e automação forte.</p>
</li>
<li><p><strong>99,999% (Cinco 9s):</strong> Cerca de <strong>5 minutos</strong> fora do ar por ano. <em>Custo e complexidade:</em> Custo 3x+. Exige automação impecável e, muitas vezes, arquitetura Multi-Region.</p>
</li>
</ul>
<p>Cada salto de nível exige não só duplicar ou triplicar a infraestrutura, mas também exige <strong>revisão e sofisticação operacional</strong>. E o pulo do gato é que cada <em>9</em> adicional precisa ser justificado em <strong>ROI (Retorno Sobre o Investimento)</strong>, e nunca em orgulho técnico.</p>
<blockquote>
<p>📢 <strong>O Fator Inegociável: Regulamentação</strong> Para setores como financeiro, saúde (LGPD) ou telecomunicações, a escolha do SLA nem sempre é puramente econômica. Muitas vezes, o requisito de disponibilidade (e a capacidade de recuperação de dados, o RPO) é <strong>imposto por lei ou normas setoriais</strong>. Nesses casos, o debate não é <em>se</em> podemos pagar, mas sim <em>como</em> atingir o SLA legalmente obrigatório com o menor custo e complexidade possíveis, pois o custo da <strong>multa regulatória</strong> supera qualquer economia técnica.</p>
</blockquote>
<p><strong>Regra Prática de Complexidade:</strong></p>
<ul>
<li><p><strong>Alta disponibilidade (dentro de uma única região)</strong>: Pode custar 1,5x a 2x o ambiente base.</p>
</li>
<li><p><strong>Multi-Região (Active/Passive)</strong>: Pode custar 2,5x a 3x.</p>
</li>
<li><p><strong>Multi-Cloud (Active/Active)</strong>: Quase nunca reduz risco. Pelo contrário, normalmente aumenta a <strong>superfície de falha</strong> e a complexidade operacional.</p>
</li>
</ul>
<h2>Decisões Conscientes: A Virtude dos ADRs</h2>
<p>Toda escolha arquitetural é um compromisso baseado em um <strong>contexto</strong>, e esse contexto é volátil. Sem registro, o contexto se perde, o que nos condena a refazer decisões, revisitar discussões e incorrer em custos desnecessários.</p>
<p>É aí que a prática dos <strong>ADRs (Architecture Decision Records)</strong> se torna crucial. Não são documentos longos de 50 páginas, mas sim documentos curtos que capturam a <strong>decisão</strong>, o <strong>motivo</strong> e o <strong>risco assumido</strong> em um dado momento.</p>
<p><code>Exemplo de ADR (com foco no risco assumido):</code></p>
<pre><code class="language-markdown"># ADR-014: Não usar replicação multi-região no MVP

Contexto:
- Tráfego atual &lt; 10 req/s.
- O custo de replicação multi-região é estimado em &gt; 3x o custo atual.

Decisão:
Manter arquitetura single-region (usando Multi-AZ para HA intra-região),
com backup cross-region diário.

Gatilho de Revisão:
Após atingir 100 req/s médios ou quando o SLA atual (99,95%) gerar
impacto de negócio.

Risco/Consequência Aceita:
Risco de downtime total do serviço em caso de um outage que afete a
região inteira (RTO estimado em 4 horas para recuperação cross-region).
</code></pre>
<p>Um ADR não evita a falha. Mas evita que a falha pegue o time de surpresa, pois o risco foi mapeado, assumido e justificado pelo negócio. É o mapa para as futuras discussões.</p>
<h2>Resiliência Seletiva: Nem Tudo Precisa de HA (e tudo bem)</h2>
<p>A resiliência seletiva é uma <strong>virtude de economia e clareza</strong>. Não é todo serviço que precisa de redundância global. Alocar recursos finitos (dinheiro e atenção de engenharia) em redundância desnecessária é um dos grandes desperdícios em arquitetura.</p>
<p><strong>Priorize Alta Disponibilidade (HA) apenas para o que realmente importa:</strong></p>
<ul>
<li><p><strong>Funções de Receita Direta:</strong> Componentes cruciais para a transação financeira (ex: <strong>checkout</strong> e <strong>APIs de pagamento</strong>).</p>
</li>
<li><p><strong>Jornada Crítica do Cliente:</strong> Funções que impedem o uso do valor central do produto (ex: <strong>login</strong> ou <strong>catálogo principal</strong>).</p>
</li>
<li><p><strong>Risco Regulatório e Legal:</strong> Serviços onde a falha gera <strong>multas legais</strong> ou quebra um <strong>SLA contratual penalizador</strong>.</p>
</li>
<li><p><strong>Integridade de Dados Críticos:</strong> Onde a perda de dados viola o <strong>RPO</strong> aceitável (ex: sistemas de retenção de dados obrigatórios).</p>
</li>
</ul>
<p>O resto? Pode ser restaurado via um <em>recovery playbook</em> bem definido. <em>Jobs batch</em>, sistemas internos de retaguarda, e <em>dashboards</em> podem tolerar minutos (ou até horas) de inatividade, desde que o plano de reprocessamento seja claro.</p>
<blockquote>
<p><strong>Alta disponibilidade sem propósito é como instalar um airbag em uma bicicleta.</strong> É uma solução sofisticada para um problema que não existe naquele contexto.</p>
</blockquote>
<p>Esse último critério, o de integridade de dados, fica bem mais concreto quando o dado está em movimento. Onde o RPO encosta na escolha do serviço de streaming, eu abri em <a href="https://willpeixoto.dev/data-streaming-na-aws-kinesis-firehose-flink-msk">Data Streaming na AWS: Kinesis, Firehose, Flink ou MSK?</a>.</p>
<h2>Gerenciado != Isento de Falhas: A Mentalidade Serverless</h2>
<p>Um erro comum é acreditar que usar serviços <em>serverless</em> (Lambda, DynamoDB, SQS, EventBridge) é sinônimo de imunidade a falhas. Não é.</p>
<p>A falha vai vir, e com frequência de onde você menos espera, pois o paradigma <em>serverless</em> muda a <strong>superfície de risco</strong>.</p>
<p>O ponto chave é:</p>
<p>Serviços gerenciados reduzem a <strong>superfície operacional</strong> (você não gerencia OS, patching ou capacidade), mas <strong>não substituem o bom <em>design</em> e preparo</strong>.</p>
<p>Durante o <em>outage</em> de us-east-1 em outubro de 2025, muitas aplicações 100% <em>serverless</em> ficaram indisponíveis. Não porque o <em>serverless</em> falhou, mas porque dependiam de uma <strong>única região</strong>. Quando a resolução de DNS do <em>endpoint</em> regional do DynamoDB quebrou, tudo que estava preso ao us-east-1 (direto, ou indireto via um <em>control plane</em> global como IAM ou STS) quebrou junto. Multi-AZ não teria salvado: o <em>endpoint</em> era regional, não zonal. E as aplicações que demoraram mais a se recuperar eram, com frequência, as que respondiam à falha com <em>retries</em> agressivos e sem limite, transformando um <em>outage</em> em um <em>retry storm</em> autoinfligido.</p>
<blockquote>
<p><strong>A Resiliência Real não vem da AWS. Vem da Arquitetura que você desenha <em>em cima</em> dela.</strong></p>
</blockquote>
<p>E "superfície de risco" muda de figura quando o código que roda não é seu. Aí o isolamento deixa de ser detalhe de implementação e vira requisito de arquitetura, que é o assunto de <a href="https://willpeixoto.dev/aws-lambda-microvms-codigo-isolado-serverless">AWS Lambda MicroVMs: rode código não confiável com isolamento de VM</a>.</p>
<h2>A Decisão é do Negócio, mas a Clareza é do Arquiteto</h2>
<p>A diferença entre "ter opinião" e "ter influência" está em sua capacidade de traduzir a complexidade técnica em <strong>clareza estratégica</strong>. Seu papel não é assustar o <em>board</em> com jargões, mas sim dar a eles a visibilidade necessária para decidir com consciência.</p>
<p>Minha experiência me ensinou que a maturidade de um time pode ser medida justamente por essa habilidade de fazer a pergunta certa:</p>
<p>❓ Onde está a Maturidade do Seu Time?</p>
<p><em><strong>Times Imaturos Focam na Ferramenta:</strong></em></p>
<ul>
<li><p>Perguntam: <strong>"Qual <em>stack</em> resolve isso?"</strong></p>
</li>
<li><p>Perguntam: <strong>"Devemos usar K8S ou <em>Serverless</em>?"</strong></p>
</li>
<li><p>Perguntam: <strong>"O que a Netflix faz?"</strong></p>
</li>
</ul>
<p><em><strong>Times Maduros Focam no Risco e no Negócio:</strong></em></p>
<ul>
<li><p>Perguntam: <strong>"Qual risco estamos dispostos a aceitar por esse custo?"</strong></p>
</li>
<li><p>Perguntam: <strong>"Qual é o RTO/RPO que o cliente final exige deste serviço?"</strong></p>
</li>
<li><p>Perguntam: <strong>"O que o nosso negócio precisa para sobreviver a um desastre?"</strong></p>
</li>
</ul>
<p>O resultado é que dois times podem usar exatamente a mesma <strong>CLOUD</strong>: um escala com previsibilidade, o outro vive em modo pânico. A diferença não é a <em>cloud</em>. É o nível de entendimento, documentação e humildade técnica sobre as decisões tomadas.</p>
<blockquote>
<p><strong>A Armadilha Comum:</strong> Quem nunca ouviu de um executivo: "Decisões técnicas são com o time de Arquitetura"? Ele está, na verdade, transferindo a responsabilidade pela definição do <strong>risco de negócio</strong>. Seu time define o <strong>COMO</strong> (a <em>stack</em>), mas o Negócio define o <strong>QUANTO</strong> (o RTO e o RPO aceitáveis). É seu papel <strong>devolver a pergunta</strong> para que a decisão de risco seja do negócio.</p>
</blockquote>
<h3>Traduzindo Conceitos de Resiliência para a Liderança</h3>
<p>(Afinal, quem nunca ouviu: <em>"Agora traduz isso pra eu entender!"</em>)</p>
<pre><code class="language-plaintext">1. Failover Multi-Region

   Tradução: O seguro contra a catástrofe. Garante que um desastre
             regional não nos tire do ar por dias, reduzindo o 
             prejuízo de receita a poucas horas.

   Pergunta: Quantas horas (ou minutos) de downtime o negócio pode
             aceitar no serviço X, caso a região inteira caia?
------------------------------------------------------------------
2. Active-Active Setup

   Tradução: Disponibilidade máxima e ininterrupta. Permite que 
             façamos qualquer manutenção ou atualização sem jamais 
             impactar o cliente final.

   Pergunta: O serviço X precisa estar 100% contínuo? Podemos ter 
             um período de 15 minutos de downtime para manutenção?
------------------------------------------------------------------
3. RTO / RPO

   Tradução: Definindo o Limite do Prejuízo. São os números que 
             nos dizem o que e por quanto tempo podemos perder antes
             que as multas ou a reputação se tornem insustentáveis.

   Pergunta: Quantos dados (RPO) podemos perder e quanto tempo (RTO)
             o time tem para restaurar o serviço sem que o negócio quebre?
------------------------------------------------------------------
4. SPOF (Single Point of Failure)

   Tradução: O Calcanhar de Aquiles da Receita. É o ponto fraco que,
             se quebrado, paralisa a empresa inteira. É onde o risco 
             deve ser zero.

   Pergunta: Se este componente cair, qual é o prejuízo financeiro 
             em 1 hora?
</code></pre>
<h2>Conclusão</h2>
<p>Não existe arquitetura <strong>à prova de falhas</strong>.</p>
<p>Mas existe <strong>organização à prova de surpresas</strong>.</p>
<p>E ela começa com decisões conscientes, documentação (os ADRs), e a humildade técnica de aceitar que o erro e o risco fazem parte da equação.</p>
<p>Times que entendem o <strong>"porquê"</strong> antes de se aprofundarem no <strong>"como"</strong> constroem sistemas que não apenas escalam, mas que, acima de tudo, <strong>sobrevivem</strong>, e crescem com previsibilidade.</p>
<p>E se a conclusão do seu time foi "então vamos para duas clouds", vale abrir a conta antes de desenhar: <a href="https://willpeixoto.dev/multi-cloud-menos-resiliente-conta-disponibilidade">Multi-cloud te deixa menos resiliente, não mais</a>.</p>
<h2>Referências Essenciais</h2>
<p>Para quem deseja aprofundar as decisões de risco e os padrões arquiteturais, estes são os documentos que usamos como base para a resiliência em qualquer <em>cloud</em> (com foco em AWS):</p>
<ul>
<li><p><strong>AWS Well-Architected Framework: <em>Reliability Pillar</em></strong>: O guia fundamental para entender os princípios de recuperação de desastres (DR) e alta disponibilidade (HA). <a href="https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/reliability.html"><strong>Guia de Confiabilidade (Reliability Pillar)</strong></a></p>
</li>
<li><p><em><strong>Disaster Recovery of Workloads on AWS</strong></em>: Documento-chave para aprofundar RTO/RPO e escolher entre padrões como <em>Pilot Light</em> e <em>Active-Active</em>. <a href="https://docs.aws.amazon.com/whitepapers/latest/disaster-recovery-workloads-on-aws/introduction.html"><strong>Whitepaper de DR</strong></a></p>
</li>
<li><p><em><strong>DynamoDB Global Tables</strong></em>: Um excelente estudo de caso prático de HA a nível de dados, que abstrai a complexidade do <em>multi-region</em>. <a href="https://aws.amazon.com/pt/dynamodb/global-tables/"><strong>Documentação do DynamoDB Global Tables</strong></a></p>
</li>
<li><p><em><strong>EventBridge Resilience Guide</strong></em>: Essencial para quem trabalha com <em>serverless</em>, focando em padrões de resiliência baseados em eventos. <a href="https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-resilience.html"><strong>Guia de Resiliência do EventBridge</strong></a></p>
</li>
</ul>
<h2>Glossário Essencial para Resiliência</h2>
<p>Para que todos estejam na mesma página, aqui estão alguns termos-chave utilizados neste artigo, explicados de forma simples:</p>
<ul>
<li><p><strong>Alta Disponibilidade (HA):</strong> É a capacidade de um sistema continuar operando mesmo quando um ou mais de seus componentes falham. Medimos em "9s" (ex: 99,99%).</p>
</li>
<li><p><strong>Outage:</strong> Uma interrupção não planejada de um serviço, ou seja, o serviço fica fora do ar.</p>
</li>
<li><p><strong>On-premise:</strong> Infraestrutura e data centers próprios que estão fisicamente no local da empresa (não na nuvem).</p>
</li>
<li><p><strong>Multi-Região:</strong> Usar data centers em duas ou mais regiões geográficas diferentes da nuvem (ex: Leste dos EUA e São Paulo) para máxima proteção contra desastres regionais.</p>
</li>
<li><p><strong>Multi-AZ (Multi-Availability Zone):</strong> Usar duas ou mais Zonas de Disponibilidade (datacenters isolados e próximos) <strong>dentro</strong> da mesma região da nuvem. É o padrão básico de HA.</p>
</li>
<li><p><strong>SLA (Service Level Agreement):</strong> Um acordo formal que define o nível de serviço esperado de um fornecedor para um cliente (geralmente medido em tempo de <em>uptime</em>).</p>
</li>
<li><p><strong>ROI (Retorno Sobre o Investimento):</strong> Uma métrica financeira que mede a relação entre o dinheiro ganho (ou economizado) e o dinheiro investido.</p>
</li>
<li><p><strong>ADR (Architecture Decision Record):</strong> Documento curto que registra uma decisão arquitetural, o motivo e o risco aceito em um ponto específico do tempo.</p>
</li>
<li><p><strong>RTO (Recovery Time Objective):</strong> O <strong>tempo</strong> máximo aceitável que um sistema pode ficar fora do ar após uma falha.</p>
</li>
<li><p><strong>RPO (Recovery Point Objective):</strong> A <strong>quantidade de dados</strong> (medida em tempo, ex: 5 minutos) que pode ser perdida durante um evento de desastre.</p>
</li>
<li><p><strong>Serverless:</strong> Um modelo de computação em nuvem onde o provedor gerencia toda a infraestrutura, e o desenvolvedor se foca apenas no código, pagando apenas pelo uso.</p>
</li>
<li><p><strong>Circuit Breaker:</strong> Um padrão de software que, quando um serviço dependente começa a falhar repetidamente, "abre" o circuito, protegendo o restante da aplicação de falhas em cascata.</p>
</li>
<li><p><strong>Resumo Pós-Evento da AWS: <em>Amazon DynamoDB Service Disruption</em> na região US-EAST-1 (19 a 20 de outubro de 2025)</strong>: a fonte primária e oficial sobre o <em>outage</em> citado neste artigo, com o post-mortem completo da causa-raiz e da cascata de falhas. <a href="https://aws.amazon.com/message/101925"><strong>Resumo da Interrupção</strong></a></p>
</li>
</ul>
<hr />
<h2>Para ir mais fundo</h2>
<p>Aqui no blog, três posts que puxam essa conversa por ângulos diferentes:</p>
<ul>
<li><p><a href="https://willpeixoto.dev/multi-cloud-menos-resiliente-conta-disponibilidade">Multi-cloud te deixa menos resiliente, não mais</a>: o que acontece com a conta de disponibilidade quando você põe duas clouds em série.</p>
</li>
<li><p><a href="https://willpeixoto.dev/data-streaming-na-aws-kinesis-firehose-flink-msk">Data Streaming na AWS: Kinesis, Firehose, Flink ou MSK?</a>: onde o RPO encosta na escolha do serviço.</p>
</li>
<li><p><a href="https://willpeixoto.dev/aws-lambda-microvms-codigo-isolado-serverless">AWS Lambda MicroVMs: rode código não confiável com isolamento de VM</a>: quando o isolamento sobe de detalhe de implementação para requisito de arquitetura.</p>
</li>
</ul>
<p>E você, como o seu time documenta as decisões de risco hoje? Se já usa ADR, me conta nos comentários o que funcionou e o que não pegou, porque essa parte costuma ser mais difícil do que parece. Se o post te ajudou, manda aquele joinha e compartilha para fortalecer. Valeu demais!</p>
<p>BUILD. SCALE. REPEAT. =D</p>
]]></content:encoded></item></channel></rss>