<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en" xml:base="https://blog.sultanops.com/">
  <title>sultanops</title>
  <subtitle>Hands-on, step-by-step guides: launching servers on AWS, running your own WireGuard VPN, and hardening Linux servers.</subtitle>
  <link href="https://blog.sultanops.com/en/feed.xml" rel="self"/>
  <link href="https://blog.sultanops.com/en/"/>
  <updated>2026-11-02T00:00:00Z</updated>
  <id>https://blog.sultanops.com/en/</id>
  <author>
    <name>Sultan Ayidh</name>
  </author>
  <entry>
    <title>Cost and Good Architecture</title>
    <link href="https://blog.sultanops.com/en/posts/aws-29-cost-good-architecture/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-29-cost-good-architecture/</id>
    <summary>The series finale. Where your money goes on the network, the tools that watch your bill, the Well-Architected Framework, building everything from a template with CloudFormation, Systems Manager, and where to go after this series, with a hands-on.</summary>
    <content type="html">&lt;p&gt;You&#39;ve come a long way since &lt;a href=&quot;/en/posts/aws-01-global-infrastructure/&quot;&gt;part one&lt;/a&gt;. In this final part we answer two questions that apply to everything we built: &lt;strong&gt;how much does it cost?&lt;/strong&gt; and &lt;strong&gt;is it designed well?&lt;/strong&gt; Then we turn it all into a file you can rebuild with one command.&lt;/p&gt;
&lt;h2 id=&quot;where-does-the-network-money-go&quot; tabindex=&quot;-1&quot;&gt;Where does the network money go? &lt;a class=&quot;heading-anchor&quot; href=&quot;#where-does-the-network-money-go&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most people plan for servers and storage, then get surprised by data transfer. Prices here are approximate for US Regions:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 290&quot; role=&quot;img&quot; aria-labelledby=&quot;netcost-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;netcost-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;14&quot; y=&quot;14&quot; width=&quot;420&quot; height=&quot;262&quot; rx=&quot;14&quot; fill=&quot;none&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;6 6&quot;/&gt;
&lt;text x=&quot;224&quot; y=&quot;38&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Region&lt;/text&gt;
&lt;rect x=&quot;30&quot; y=&quot;50&quot; width=&quot;180&quot; height=&quot;124&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;120&quot; y=&quot;70&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Availability Zone 1&lt;/text&gt;
&lt;rect x=&quot;45&quot; y=&quot;82&quot; width=&quot;70&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;80&quot; y=&quot;109&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;EC2&lt;/text&gt;
&lt;rect x=&quot;125&quot; y=&quot;82&quot; width=&quot;70&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;160&quot; y=&quot;109&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;EC2&lt;/text&gt;
&lt;line x1=&quot;115&quot; y1=&quot;104&quot; x2=&quot;123&quot; y2=&quot;104&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot;/&gt;
&lt;text x=&quot;120&quot; y=&quot;152&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Free with private IPs&lt;/text&gt;
&lt;rect x=&quot;238&quot; y=&quot;50&quot; width=&quot;180&quot; height=&quot;124&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;328&quot; y=&quot;70&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Availability Zone 2&lt;/text&gt;
&lt;rect x=&quot;293&quot; y=&quot;82&quot; width=&quot;70&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;328&quot; y=&quot;109&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;EC2&lt;/text&gt;
&lt;line x1=&quot;195&quot; y1=&quot;104&quot; x2=&quot;291&quot; y2=&quot;104&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#netcost-arrow)&quot;/&gt;
&lt;text x=&quot;224&quot; y=&quot;204&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Between zones: $0.01 per GB each way&lt;/text&gt;
&lt;text x=&quot;224&quot; y=&quot;240&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;In from the internet: free&lt;/text&gt;
&lt;rect x=&quot;480&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;550&quot; y=&quot;60&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Internet&lt;/text&gt;
&lt;text x=&quot;550&quot; y=&quot;80&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;About $0.09 per GB&lt;/text&gt;
&lt;rect x=&quot;480&quot; y=&quot;170&quot; width=&quot;140&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;550&quot; y=&quot;200&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Other Region&lt;/text&gt;
&lt;text x=&quot;550&quot; y=&quot;220&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;From $0.02 per GB&lt;/text&gt;
&lt;line x1=&quot;434&quot; y1=&quot;65&quot; x2=&quot;478&quot; y2=&quot;65&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#netcost-arrow)&quot;/&gt;
&lt;line x1=&quot;434&quot; y1=&quot;205&quot; x2=&quot;478&quot; y2=&quot;205&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#netcost-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;netcost-caption&quot;&gt;Data going into AWS is free, and within a zone over private addresses too. You pay when it crosses a boundary: between zones, between Regions, or out to the internet.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Direction&lt;/th&gt;
&lt;th&gt;Approx. price per GB&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Into AWS from the internet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inside one Availability Zone, using private IPs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Between Availability Zones&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0.01 in each direction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Between Regions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;From about $0.02, and it varies by Region&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Out to the internet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;About $0.09 and falling with volume, with the first 100 GB a month free&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Small numbers add up quickly. Six things that cut them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Use private IPs&lt;/strong&gt; inside the VPC instead of public ones, and note that every public IPv4 address also has an hourly charge.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Put CloudFront in front of your application.&lt;/strong&gt; Data from AWS to CloudFront is free, and out through it costs less than going out directly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add a gateway endpoint&lt;/strong&gt; for &lt;a href=&quot;/en/posts/aws-14-vpc-connectivity/&quot;&gt;S3 and DynamoDB&lt;/a&gt;. It&#39;s free, and it spares you NAT charges per GB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One NAT gateway per Availability Zone,&lt;/strong&gt; so traffic doesn&#39;t cross zones to reach it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep chatty services close.&lt;/strong&gt; Balance this against availability, though, as splitting across zones is worth paying for.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compress what you send,&lt;/strong&gt; and cache it as far forward as you can.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;wheres-the-caching&quot; tabindex=&quot;-1&quot;&gt;Where&#39;s the caching? &lt;a class=&quot;heading-anchor&quot; href=&quot;#wheres-the-caching&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each layer saves work for the ones behind it, so the further forward the better, and we&#39;ve seen them all:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Saves&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;The edge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-12-cloudfront-global-accelerator/&quot;&gt;CloudFront&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The whole trip, for content that&#39;s the same for everyone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;The API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-22-serverless-design/&quot;&gt;API Gateway cache&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The function and the database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;The application&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-09-elasticache/&quot;&gt;ElastiCache&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Heavy queries and calculations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;The database&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-21-lambda-api-dynamodb/&quot;&gt;DAX&lt;/a&gt; or a read replica&lt;/td&gt;
&lt;td&gt;Reads from the main database&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;tools-that-watch-your-bill&quot; tabindex=&quot;-1&quot;&gt;Tools that watch your bill &lt;a class=&quot;heading-anchor&quot; href=&quot;#tools-that-watch-your-bill&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost Explorer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Charts your spending by service, account and tag, forecasts it, and recommends Savings Plans&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Budgets&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Alerts you when you reach or are forecast to reach a limit, and monitoring is free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost Anomaly Detection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Uses machine learning to spot unusual spending, at no charge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost Optimization Hub&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gathers recommendations for savings in one place: resizing, idle resources and more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compute Optimizer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Recommends suitable sizes based on your actual use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost and Usage Report&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The most detailed data on your costs and usage, delivered as files to S3 for you to analyze. &lt;strong&gt;AWS Data Exports&lt;/strong&gt; creates similar exports with the columns you choose&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;And the first step is &lt;strong&gt;tags&lt;/strong&gt;: without an &lt;code&gt;env&lt;/code&gt; or &lt;code&gt;team&lt;/code&gt; tag, you won&#39;t know who&#39;s spending what. And tags only reach your cost reports once you &lt;strong&gt;activate them as cost allocation tags&lt;/strong&gt; in the billing console.&lt;/p&gt;
&lt;h3 id=&quot;quick-savings&quot; tabindex=&quot;-1&quot;&gt;Quick savings &lt;a class=&quot;heading-anchor&quot; href=&quot;#quick-savings&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Where we saw it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Resize oversized servers&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-03-ec2-first-server/&quot;&gt;Part three&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commit with Savings Plans, and use Spot for what tolerates interruption&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-04-ec2-pricing-networking/&quot;&gt;Part four&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop dev servers at night, for example with &lt;strong&gt;Instance Scheduler on AWS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;This part&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lifecycle rules for S3&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-16-s3-classes-lifecycle/&quot;&gt;Part sixteen&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set a retention period on logs&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-25-monitoring-auditing/&quot;&gt;Part twenty-five&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete orphaned disks, snapshots and load balancers&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-05-ec2-storage/&quot;&gt;Part five&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;the-well-architected-framework&quot; tabindex=&quot;-1&quot;&gt;The Well-Architected Framework &lt;a class=&quot;heading-anchor&quot; href=&quot;#the-well-architected-framework&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AWS has summarized what it&#39;s learned from its customers in six pillars. Consider it a review for any design:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pillar&lt;/th&gt;
&lt;th&gt;The question&lt;/th&gt;
&lt;th&gt;We covered it in&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operational excellence&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can you run it and improve it?&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-25-monitoring-auditing/&quot;&gt;Monitoring&lt;/a&gt; and templates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are data and access protected?&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-02-iam/&quot;&gt;IAM&lt;/a&gt; and &lt;a href=&quot;/en/posts/aws-27-encryption-secrets-protection/&quot;&gt;encryption&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reliability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does it survive failures and recover?&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-07-auto-scaling/&quot;&gt;Scaling&lt;/a&gt; and &lt;a href=&quot;/en/posts/aws-28-disaster-recovery-migration/&quot;&gt;recovery&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance efficiency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are you using the right resources?&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-09-elasticache/&quot;&gt;Caching&lt;/a&gt; and &lt;a href=&quot;/en/posts/aws-10-choosing-database/&quot;&gt;choosing a database&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost optimization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are you paying for what you don&#39;t need?&lt;/td&gt;
&lt;td&gt;This part&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sustainability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Are you reducing your consumption and its impact?&lt;/td&gt;
&lt;td&gt;Right sizing and &lt;a href=&quot;/en/posts/aws-03-ec2-first-server/&quot;&gt;Graviton&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The pillars pull against each other at times: more copies mean better reliability and higher cost. The aim isn&#39;t to max out everything, but to make the trade-off knowingly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AWS Well-Architected Tool:&lt;/strong&gt; a free tool in the console that asks you questions about your workload and shows the risks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trusted Advisor:&lt;/strong&gt; checks your account against best practices. On the free plan you get service limits and a few security and fault-tolerance checks, and the rest need a paid support plan. Note that AWS is changing its support plans, with &lt;strong&gt;Developer&lt;/strong&gt; and &lt;strong&gt;Business&lt;/strong&gt; ending on January 1, 2027 in favor of &lt;strong&gt;Business Support+&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;cloudformation-your-infrastructure-in-a-file&quot; tabindex=&quot;-1&quot;&gt;CloudFormation: your infrastructure in a file &lt;a class=&quot;heading-anchor&quot; href=&quot;#cloudformation-your-infrastructure-in-a-file&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So far we&#39;ve created everything by hand or by command. What if you could describe it all in a file? &lt;strong&gt;AWS CloudFormation&lt;/strong&gt; reads a &lt;strong&gt;template&lt;/strong&gt; and builds a &lt;strong&gt;stack&lt;/strong&gt; of resources, in the right order, and:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Repeatable:&lt;/strong&gt; the same environment for development, testing and production.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reviewable:&lt;/strong&gt; the template sits in Git like code, and you review its changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Controlled:&lt;/strong&gt; a &lt;strong&gt;change set&lt;/strong&gt; shows what will change before it happens, and &lt;strong&gt;drift detection&lt;/strong&gt; reveals manual changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clean:&lt;/strong&gt; deleting a stack deletes everything in it, so nothing&#39;s left billing you.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Free:&lt;/strong&gt; you pay only for the resources it creates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Infrastructure Composer&lt;/strong&gt; lets you draw a template visually, and &lt;strong&gt;AWS CDK&lt;/strong&gt; writes it in Python or TypeScript. A &lt;strong&gt;service role&lt;/strong&gt; lets a developer deploy a stack without having permission over the resources themselves.&lt;/p&gt;
&lt;h2 id=&quot;systems-manager-running-your-servers&quot; tabindex=&quot;-1&quot;&gt;Systems Manager: running your servers &lt;a class=&quot;heading-anchor&quot; href=&quot;#systems-manager-running-your-servers&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;AWS Systems Manager&lt;/strong&gt; manages fleets of servers through an agent, already installed on Amazon Linux, and an IAM role:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Session Manager&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A terminal with no SSH port and no keys, with sessions logged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Run Command&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One command across a thousand servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Patch Manager&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Applies updates on a schedule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Maintenance Windows&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sets when these things are allowed to happen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Automation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ready documents for common tasks, like &lt;a href=&quot;/en/posts/aws-25-monitoring-auditing/&quot;&gt;Config&lt;/a&gt; remediation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;applications-you-cant-change&quot; tabindex=&quot;-1&quot;&gt;Applications you can&#39;t change &lt;a class=&quot;heading-anchor&quot; href=&quot;#applications-you-cant-change&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not every application can be rewritten, and you can often make an old one more reliable from the outside, without touching its code:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;One server that can fail&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An &lt;a href=&quot;/en/posts/aws-07-auto-scaling/&quot;&gt;Auto Scaling group&lt;/a&gt; of one with a health check, or &lt;a href=&quot;/en/posts/aws-25-monitoring-auditing/&quot;&gt;automatic recovery&lt;/a&gt;, which brings it back on new hardware with the same addresses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Load that overwhelms it&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-12-cloudfront-global-accelerator/&quot;&gt;CloudFront&lt;/a&gt; in front of it, for whatever can be cached&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Too many database connections&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-08-rds-aurora/&quot;&gt;RDS Proxy&lt;/a&gt;, which only needs a new endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A database that can go down&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-08-rds-aurora/&quot;&gt;Multi-AZ&lt;/a&gt;, which keeps the same endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Clients allowing fixed addresses through their firewalls&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The two static addresses of &lt;a href=&quot;/en/posts/aws-12-cloudfront-global-accelerator/&quot;&gt;Global Accelerator&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;services-worth-knowing&quot; tabindex=&quot;-1&quot;&gt;Services worth knowing &lt;a class=&quot;heading-anchor&quot; href=&quot;#services-worth-knowing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A last group that deserves a line each:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;What it&#39;s for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SES&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sending email, for transactions and marketing, with protection for your reputation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Batch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Batch jobs at any scale, on EC2 or Fargate, with no 15-minute limit like &lt;a href=&quot;/en/posts/aws-21-lambda-api-dynamodb/&quot;&gt;Lambda&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Outposts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS servers in your own data center, for when the data must stay with you&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon AppFlow&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moving data from SaaS applications such as Salesforce into S3 or Redshift, with no code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Amplify&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Quickly building and hosting web and mobile applications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Service Catalog&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A catalog of approved services, so teams deploy only what&#39;s allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;License Manager&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tracks software licenses, such as Oracle and SAP, across accounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Device Farm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Testing apps on real phones and tablets hosted by AWS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If you read older articles, &lt;strong&gt;Amazon Pinpoint&lt;/strong&gt; reached its end of support on October 30, 2026. AWS points to &lt;strong&gt;SES&lt;/strong&gt; for email, and to &lt;strong&gt;AWS End User Messaging&lt;/strong&gt; for SMS and push notifications. &lt;strong&gt;AWS Proton&lt;/strong&gt; also reached its end of support, on October 7, 2026, though the exam guide still lists it.&lt;/p&gt;
&lt;h3 id=&quot;high-performance-computing&quot; tabindex=&quot;-1&quot;&gt;High performance computing &lt;a class=&quot;heading-anchor&quot; href=&quot;#high-performance-computing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When you need thousands of processors working together:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Need&lt;/th&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compute&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A cluster &lt;a href=&quot;/en/posts/aws-04-ec2-pricing-networking/&quot;&gt;placement group&lt;/a&gt;, with Enhanced Networking or EFA, and Spot where possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-18-storage-transfer/&quot;&gt;FSx for Lustre&lt;/a&gt;, Instance Store and S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Orchestration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS Batch or &lt;strong&gt;AWS ParallelCluster&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Moving data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-18-storage-transfer/&quot;&gt;Direct Connect or DataSync&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;hands-on-a-whole-stack-from-a-file-and-a-budget-youll-keep&quot; tabindex=&quot;-1&quot;&gt;Hands-on: a whole stack from a file, and a budget you&#39;ll keep &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-a-whole-stack-from-a-file-and-a-budget-youll-keep&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Write a small template with a bucket and an SNS topic. From CloudShell:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; stack.yaml &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
AWSTemplateFormatVersion: &quot;2010-09-09&quot;
Description: A small stack from the AWS series
Parameters:
  Env:
    Type: String
    Default: dev
Resources:
  Files:
    Type: AWS::S3::Bucket
    Properties:
      VersioningConfiguration:
        Status: Enabled
      Tags:
        - Key: env
          Value: !Ref Env
  Alerts:
    Type: AWS::SNS::Topic
Outputs:
  BucketName:
    Value: !Ref Files
EOF&lt;/span&gt;

aws cloudformation deploy --stack-name series-stack --template-file stack.yaml

aws cloudformation describe-stack-resources --stack-name series-stack &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;StackResources[].[LogicalResourceId,ResourceType,ResourceStatus]&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; table&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;CloudFormation built both resources and named them itself. Now change one value. It updates only what changed, without touching the rest:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws cloudformation deploy --stack-name series-stack &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --template-file stack.yaml --parameter-overrides &lt;span class=&quot;token assign-left variable&quot;&gt;Env&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;prod

&lt;span class=&quot;token assign-left variable&quot;&gt;BUCKET&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws cloudformation describe-stacks --stack-name series-stack &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Stacks[0].Outputs[0].OutputValue&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws s3api get-bucket-tagging &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TagSet[?Key==&#39;env&#39;].Value&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;It prints &lt;code&gt;prod&lt;/code&gt;. Now the nicest part, deleting everything with one command:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws cloudformation delete-stack --stack-name series-stack
aws cloudformation &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt; stack-delete-complete --stack-name series-stack
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Everything is gone&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Finally, one thing to &lt;strong&gt;keep&lt;/strong&gt;: a budget of $10 a month that warns you when you&#39;re forecast to exceed 80% of it. Replace the email address with yours:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;EMAIL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;you@example.com
&lt;span class=&quot;token assign-left variable&quot;&gt;ACCOUNT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws sts get-caller-identity &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Account &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; budget.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
{
  &quot;BudgetName&quot;: &quot;series-monthly&quot;,
  &quot;BudgetLimit&quot;: {&quot;Amount&quot;: &quot;10&quot;, &quot;Unit&quot;: &quot;USD&quot;},
  &quot;TimeUnit&quot;: &quot;MONTHLY&quot;,
  &quot;BudgetType&quot;: &quot;COST&quot;
}
EOF&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; notify.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;EOF
[{
  &quot;Notification&quot;: {
    &quot;NotificationType&quot;: &quot;FORECASTED&quot;,
    &quot;ComparisonOperator&quot;: &quot;GREATER_THAN&quot;,
    &quot;Threshold&quot;: 80,
    &quot;ThresholdType&quot;: &quot;PERCENTAGE&quot;
  },
  &quot;Subscribers&quot;: [{&quot;SubscriptionType&quot;: &quot;EMAIL&quot;, &quot;Address&quot;: &quot;&lt;span class=&quot;token variable&quot;&gt;$EMAIL&lt;/span&gt;&quot;}]
}]
EOF&lt;/span&gt;

aws budgets create-budget --account-id &lt;span class=&quot;token variable&quot;&gt;$ACCOUNT&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--budget&lt;/span&gt; file://budget.json &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --notifications-with-subscribers file://notify.json

aws budgets describe-budgets --account-id &lt;span class=&quot;token variable&quot;&gt;$ACCOUNT&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Budgets[].[BudgetName,BudgetLimit.Amount,BudgetLimit.Unit]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; table&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;If you get &lt;code&gt;AccessDenied&lt;/code&gt;, your IAM user may need billing access, which the root user enables from the account settings.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Before you close the tab&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This budget is free, so leave it. And now that the series is over, take a look at &lt;strong&gt;Cost Explorer&lt;/strong&gt; and the &lt;a href=&quot;/en/posts/aws-03-ec2-first-server/&quot;&gt;EC2&lt;/a&gt; page in every Region you tried, to make sure no experiment is still running.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data transfer&lt;/strong&gt; is the hidden cost: between zones, between Regions, and out to the internet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Budgets&lt;/strong&gt; and &lt;strong&gt;Cost Anomaly Detection&lt;/strong&gt; warn you before the bill does.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Well-Architected Framework&lt;/strong&gt; has six pillars, and the point is to make trade-offs knowingly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CloudFormation&lt;/strong&gt; turns your infrastructure into a reviewable, deletable file.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Systems Manager&lt;/strong&gt; manages your servers without SSH.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 7&lt;/p&gt;
&lt;p&gt;Two EC2 servers in the same Availability Zone exchange terabytes a month by calling each other&#39;s public IP addresses, and the transfer shows up on the bill. What&#39;s the simplest fix?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Moving one server to another Availability Zone&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Using their private IP addresses instead&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Putting a NAT gateway between them&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Moving to larger instance types&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Data between servers in one Availability Zone is free over private addresses, while traffic through a public address is charged.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Crossing zones is charged in each direction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; A NAT gateway adds a charge for every gigabyte.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; The size of the server doesn&#39;t change what the transfer costs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#where-does-the-network-money-go&quot;&gt;Where does the network money go?&lt;/a&gt; in this part, and &lt;a href=&quot;https://aws.amazon.com/ec2/pricing/on-demand/&quot;&gt;EC2 On-Demand Instance Pricing&lt;/a&gt; on the AWS site.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 7&lt;/p&gt;
&lt;p&gt;A small team wants an email when this month&#39;s AWS spending is forecast to pass its limit, not after the bill arrives. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;AWS Budgets&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Cost Explorer, checked each morning&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Compute Optimizer&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;AWS Config&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A budget can alert on forecasted spending as well as actual spending, and the monitoring itself is free.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This charts your spending and forecasts it, but someone has to go and look.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This recommends suitable sizes, and sends no spending alerts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This records settings, not spending.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#tools-that-watch-your-bill&quot;&gt;Tools that watch your bill&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/cost-management/latest/userguide/budgets-managing-costs.html&quot;&gt;Managing your costs with AWS Budgets&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 7&lt;/p&gt;
&lt;p&gt;A team wants to review one workload&#39;s design against AWS&#39;s best practices, by answering questions about it and seeing the risks. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Amazon Inspector&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;AWS Trusted Advisor&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;AWS CloudTrail&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;AWS Well-Architected Tool&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The tool asks you questions about your workload, and shows you the risks. It&#39;s free in the console.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This scans what you run for known vulnerabilities, and doesn&#39;t review a design.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This checks your account&#39;s resources by itself, and doesn&#39;t ask about a workload.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This records who called what.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#the-well-architected-framework&quot;&gt;The Well-Architected Framework&lt;/a&gt; in this part, and &lt;a href=&quot;https://aws.amazon.com/well-architected-tool/faqs/&quot;&gt;AWS Well-Architected Tool FAQs&lt;/a&gt; on the AWS site.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 7&lt;/p&gt;
&lt;p&gt;A team wants the same environment in development and production from one file in Git, to see what an update will change before it happens, and to know if someone edits a resource by hand. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Systems Manager Run Command&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A golden AMI, copied between accounts&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;CloudFormation, with change sets and drift detection&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;AWS Config on its own&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A template builds the same stack every time and sits in Git. Change sets show what will change, and drift detection reveals manual edits.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This runs commands on servers, and doesn&#39;t describe infrastructure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This repeats a server&#39;s contents, not the network and other resources around it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This records settings and judges them, but doesn&#39;t build anything.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#cloudformation-your-infrastructure-in-a-file&quot;&gt;CloudFormation: your infrastructure in a file&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-changesets.html&quot;&gt;Update CloudFormation stacks using change sets&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-drift.html&quot;&gt;Detect unmanaged configuration changes to stacks and resources with drift detection&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 7&lt;/p&gt;
&lt;p&gt;A company must apply security updates across 500 EC2 servers, only during a Saturday night slot, and with no SSH access. Which &lt;strong&gt;two&lt;/strong&gt; tools fit? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Session Manager&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Patch Manager&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Parameter Store&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Compute Optimizer&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Maintenance Windows&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Patch Manager applies the updates, and Maintenance Windows sets when they&#39;re allowed to happen.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This gives you a terminal, one session at a time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This stores settings and simple secrets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This recommends suitable sizes based on your use.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#systems-manager-running-your-servers&quot;&gt;Systems Manager: running your servers&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/systems-manager/latest/userguide/patch-manager.html&quot;&gt;AWS Systems Manager Patch Manager&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/systems-manager/latest/userguide/maintenance-windows.html&quot;&gt;AWS Systems Manager Maintenance Windows&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 6 of 7&lt;/p&gt;
&lt;p&gt;A finance team wants the cost of each team in detailed files it can analyze itself. Resources are already tagged with &lt;code&gt;team&lt;/code&gt;, but the tag doesn&#39;t appear in the reports. Which &lt;strong&gt;two&lt;/strong&gt; steps fit? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Turn on AWS Config&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Activate &lt;code&gt;team&lt;/code&gt; as a cost allocation tag&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Run Compute Optimizer&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Turn on CloudTrail data events&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Set up a Cost and Usage Report delivered to S3&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Tags only reach cost reports once they&#39;re activated, and the Cost and Usage Report delivers the most detailed data as files in S3.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This records resource settings, not costs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This recommends suitable sizes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This records operations inside resources, not costs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#tools-that-watch-your-bill&quot;&gt;Tools that watch your bill&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/cur/latest/userguide/what-is-cur.html&quot;&gt;What are AWS Cost and Usage Reports?&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html&quot;&gt;Organizing and tracking costs using AWS cost allocation tags&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 7 of 7&lt;/p&gt;
&lt;p&gt;An old application runs on one EC2 server, and its clients connect to that server&#39;s address. The code can&#39;t be changed. If the hardware fails, the server must come back by itself with the same addresses. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Moving the application to Lambda&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;An Auto Scaling group of one&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Automatic instance recovery&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A nightly AMI of the server&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Recovery brings the server back on new hardware, keeping its instance ID and its private, public and Elastic IP addresses.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This is a rewrite, and the code can&#39;t change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; The replacement is a new server, with new addresses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; You&#39;d have to restore it by hand, onto a new server with new addresses.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#applications-you-cant-change&quot;&gt;Applications you can&#39;t change&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-recover.html&quot;&gt;Automatic instance recovery&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;h2 id=&quot;what-youve-learned&quot; tabindex=&quot;-1&quot;&gt;What you&#39;ve learned &lt;a class=&quot;heading-anchor&quot; href=&quot;#what-youve-learned&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Twenty-nine parts in nine sections. Look at what you can do now:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Section&lt;/th&gt;
&lt;th&gt;You can now&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/en/series/aws/#section-1&quot;&gt;Fundamentals&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Understand the global infrastructure and control permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/en/series/aws/#section-2&quot;&gt;Servers and their storage&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Run a server, choose its pricing and keep its data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/en/series/aws/#section-3&quot;&gt;High availability and scaling&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Build an application that survives failures and grows by itself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/en/series/aws/#section-4&quot;&gt;Databases&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Choose the right database and speed it up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/en/series/aws/#section-5&quot;&gt;Networking and content delivery&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Design a private network and deliver content around the world&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/en/series/aws/#section-6&quot;&gt;Object storage&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Store anything in S3 at the right price, and securely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/en/series/aws/#section-7&quot;&gt;Modern applications&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Separate services, and run containers and serverless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/en/series/aws/#section-8&quot;&gt;Data and AI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Analyze your data and add AI to your application&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/en/series/aws/#section-9&quot;&gt;Security and operations&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Monitor, protect, recover and control your costs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;where-to-go-from-here&quot; tabindex=&quot;-1&quot;&gt;Where to go from here &lt;a class=&quot;heading-anchor&quot; href=&quot;#where-to-go-from-here&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build something real.&lt;/strong&gt; A small project of your own teaches you more than any article, even a little site with an API.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Try the &lt;a href=&quot;/en/series/aws/quiz/&quot;&gt;comprehensive test&lt;/a&gt;.&lt;/strong&gt; It picks random questions from every part, so you can see what&#39;s stuck and what to review.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read the FAQs.&lt;/strong&gt; Each service&#39;s FAQ page is a short, rich and accurate summary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consider a certification.&lt;/strong&gt; &lt;strong&gt;Solutions Architect Associate&lt;/strong&gt; covers most of what&#39;s in this series, and the exam tests how you choose between services. Read each question for its deciding phrase, such as &amp;quot;lowest cost&amp;quot; or &amp;quot;least operational effort&amp;quot;, and eliminate the wrong answers first. Its official &lt;a href=&quot;https://docs.aws.amazon.com/aws-certification/latest/solutions-architect-associate-03/solutions-architect-associate-03.html&quot;&gt;exam guide&lt;/a&gt; lists every domain and service.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Follow the changes.&lt;/strong&gt; AWS changes quickly, and several things in this series changed even as it was being written. Check the docs before any decision.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks for coming along to the end, and good luck with what you build.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Disaster Recovery and Migration</title>
    <link href="https://blog.sultanops.com/en/posts/aws-28-disaster-recovery-migration/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-28-disaster-recovery-migration/</id>
    <summary>What RPO and RTO mean, the four disaster recovery strategies and their cost, central backups with AWS Backup, moving databases with DMS and servers with AWS Transform MGN, and a hands-on where you delete data and bring it back.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-07-auto-scaling/&quot;&gt;part seven&lt;/a&gt; our application survived losing an Availability Zone. But what if the disaster is bigger: a whole Region down, a mistaken &lt;code&gt;DELETE&lt;/code&gt;, or ransomware? And this part&#39;s other half: what if your application isn&#39;t on AWS yet, and you want to bring it over?&lt;/p&gt;
&lt;h2 id=&quot;rpo-and-rto&quot; tabindex=&quot;-1&quot;&gt;RPO and RTO &lt;a class=&quot;heading-anchor&quot; href=&quot;#rpo-and-rto&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before any technical decision, you need two numbers from the business:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 150&quot; role=&quot;img&quot; aria-labelledby=&quot;rporto-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;rporto-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;text x=&quot;245&quot; y=&quot;40&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;RPO: the data you lose&lt;/text&gt;
&lt;text x=&quot;410&quot; y=&quot;40&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;RTO: the time you&#39;re down&lt;/text&gt;
&lt;rect x=&quot;170&quot; y=&quot;52&quot; width=&quot;150&quot; height=&quot;28&quot; rx=&quot;6&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;rect x=&quot;320&quot; y=&quot;52&quot; width=&quot;180&quot; height=&quot;28&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;line x1=&quot;30&quot; y1=&quot;66&quot; x2=&quot;612&quot; y2=&quot;66&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#rporto-arrow)&quot;/&gt;
&lt;line x1=&quot;170&quot; y1=&quot;46&quot; x2=&quot;170&quot; y2=&quot;88&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot;/&gt;
&lt;line x1=&quot;320&quot; y1=&quot;46&quot; x2=&quot;320&quot; y2=&quot;88&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot;/&gt;
&lt;line x1=&quot;500&quot; y1=&quot;46&quot; x2=&quot;500&quot; y2=&quot;88&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot;/&gt;
&lt;text x=&quot;170&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Last backup&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Disaster&lt;/text&gt;
&lt;text x=&quot;500&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Back online&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;rporto-caption&quot;&gt;RPO looks backward from the disaster to the last good copy, and RTO looks forward to when service returns.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Number&lt;/th&gt;
&lt;th&gt;The question&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RPO&lt;/strong&gt; (Recovery Point Objective)&lt;/td&gt;
&lt;td&gt;How much data can we afford to lose?&lt;/td&gt;
&lt;td&gt;Backing up every hour means losing up to an hour of data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RTO&lt;/strong&gt; (Recovery Time Objective)&lt;/td&gt;
&lt;td&gt;How long can we stay down?&lt;/td&gt;
&lt;td&gt;Up to four hours of downtime&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The smaller the two numbers, the higher the cost. So the question isn&#39;t &amp;quot;what&#39;s best?&amp;quot;, but &amp;quot;what is an hour of downtime worth to us?&amp;quot;&lt;/p&gt;
&lt;h2 id=&quot;four-strategies&quot; tabindex=&quot;-1&quot;&gt;Four strategies &lt;a class=&quot;heading-anchor&quot; href=&quot;#four-strategies&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These are for recovering in another Region, ordered from the cheapest to the most expensive. The difference between them is how much is running there before the disaster:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 262&quot; role=&quot;img&quot; aria-labelledby=&quot;dr-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;dr-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;text x=&quot;90.5&quot; y=&quot;24&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Backup&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;36&quot; width=&quot;141&quot; height=&quot;54&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;90.5&quot; y=&quot;58&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Data&lt;/text&gt;
&lt;text x=&quot;90.5&quot; y=&quot;78&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Backups&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;96&quot; width=&quot;141&quot; height=&quot;54&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-dasharray=&quot;5 5&quot;/&gt;
&lt;text x=&quot;90.5&quot; y=&quot;118&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Servers&lt;/text&gt;
&lt;text x=&quot;90.5&quot; y=&quot;138&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;None&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;156&quot; width=&quot;141&quot; height=&quot;54&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-dasharray=&quot;5 5&quot;/&gt;
&lt;text x=&quot;90.5&quot; y=&quot;178&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Traffic&lt;/text&gt;
&lt;text x=&quot;90.5&quot; y=&quot;198&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;None&lt;/text&gt;
&lt;text x=&quot;243.5&quot; y=&quot;24&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Pilot light&lt;/text&gt;
&lt;rect x=&quot;173&quot; y=&quot;36&quot; width=&quot;141&quot; height=&quot;54&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;243.5&quot; y=&quot;58&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Data&lt;/text&gt;
&lt;text x=&quot;243.5&quot; y=&quot;78&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Replicated&lt;/text&gt;
&lt;rect x=&quot;173&quot; y=&quot;96&quot; width=&quot;141&quot; height=&quot;54&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-dasharray=&quot;5 5&quot;/&gt;
&lt;text x=&quot;243.5&quot; y=&quot;118&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Servers&lt;/text&gt;
&lt;text x=&quot;243.5&quot; y=&quot;138&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Stopped&lt;/text&gt;
&lt;rect x=&quot;173&quot; y=&quot;156&quot; width=&quot;141&quot; height=&quot;54&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-dasharray=&quot;5 5&quot;/&gt;
&lt;text x=&quot;243.5&quot; y=&quot;178&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Traffic&lt;/text&gt;
&lt;text x=&quot;243.5&quot; y=&quot;198&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;None&lt;/text&gt;
&lt;text x=&quot;396.5&quot; y=&quot;24&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Warm standby&lt;/text&gt;
&lt;rect x=&quot;326&quot; y=&quot;36&quot; width=&quot;141&quot; height=&quot;54&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;396.5&quot; y=&quot;58&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Data&lt;/text&gt;
&lt;text x=&quot;396.5&quot; y=&quot;78&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Replicated&lt;/text&gt;
&lt;rect x=&quot;326&quot; y=&quot;96&quot; width=&quot;141&quot; height=&quot;54&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;396.5&quot; y=&quot;118&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Servers&lt;/text&gt;
&lt;text x=&quot;396.5&quot; y=&quot;138&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;A few running&lt;/text&gt;
&lt;rect x=&quot;326&quot; y=&quot;156&quot; width=&quot;141&quot; height=&quot;54&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-dasharray=&quot;5 5&quot;/&gt;
&lt;text x=&quot;396.5&quot; y=&quot;178&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Traffic&lt;/text&gt;
&lt;text x=&quot;396.5&quot; y=&quot;198&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;On failover&lt;/text&gt;
&lt;text x=&quot;549.5&quot; y=&quot;24&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Multi-site&lt;/text&gt;
&lt;rect x=&quot;479&quot; y=&quot;36&quot; width=&quot;141&quot; height=&quot;54&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;549.5&quot; y=&quot;58&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Data&lt;/text&gt;
&lt;text x=&quot;549.5&quot; y=&quot;78&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Replicated&lt;/text&gt;
&lt;rect x=&quot;479&quot; y=&quot;96&quot; width=&quot;141&quot; height=&quot;54&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;549.5&quot; y=&quot;118&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Servers&lt;/text&gt;
&lt;text x=&quot;549.5&quot; y=&quot;138&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Full size&lt;/text&gt;
&lt;rect x=&quot;479&quot; y=&quot;156&quot; width=&quot;141&quot; height=&quot;54&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;549.5&quot; y=&quot;178&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Traffic&lt;/text&gt;
&lt;text x=&quot;549.5&quot; y=&quot;198&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Always&lt;/text&gt;
&lt;line x1=&quot;20&quot; y1=&quot;226&quot; x2=&quot;618&quot; y2=&quot;226&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#dr-arrow)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;248&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Higher cost, less data lost, faster recovery&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;dr-caption&quot;&gt;What&#39;s running in the other Region before the disaster: the more that&#39;s ready, the faster you recover and the more you pay.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;Approx. RPO&lt;/th&gt;
&lt;th&gt;Approx. RTO&lt;/th&gt;
&lt;th&gt;Suits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backup and restore&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hours&lt;/td&gt;
&lt;td&gt;Up to 24 hours&lt;/td&gt;
&lt;td&gt;Non-critical systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pilot light&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Minutes&lt;/td&gt;
&lt;td&gt;Tens of minutes&lt;/td&gt;
&lt;td&gt;The core data must always be ready&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Warm standby&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Seconds&lt;/td&gt;
&lt;td&gt;Minutes&lt;/td&gt;
&lt;td&gt;Important systems with a limited budget&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multi-site (active-active)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Close to zero&lt;/td&gt;
&lt;td&gt;Close to zero&lt;/td&gt;
&lt;td&gt;Where a minute of downtime costs a fortune&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backup and restore:&lt;/strong&gt; backups copied to another Region, with everything built from them in a disaster. A template helps, as we&#39;ll see in the &lt;a href=&quot;/en/posts/aws-29-cost-good-architecture/&quot;&gt;next part&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pilot light:&lt;/strong&gt; the data is replicating, such as an &lt;a href=&quot;/en/posts/aws-08-rds-aurora/&quot;&gt;Aurora&lt;/a&gt; Global Database or &lt;a href=&quot;/en/posts/aws-15-s3-basics/&quot;&gt;S3 replication&lt;/a&gt;, and the servers are ready but stopped.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Warm standby:&lt;/strong&gt; a small full copy is running and can take traffic right away, then it grows with Auto Scaling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-site:&lt;/strong&gt; both Regions serve users all the time, such as with &lt;a href=&quot;/en/posts/aws-11-dns-route53/&quot;&gt;Route 53&lt;/a&gt; and &lt;a href=&quot;/en/posts/aws-21-lambda-api-dynamodb/&quot;&gt;Global Tables&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;tips-that-make-the-difference&quot; tabindex=&quot;-1&quot;&gt;Tips that make the difference &lt;a class=&quot;heading-anchor&quot; href=&quot;#tips-that-make-the-difference&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Test your recovery.&lt;/strong&gt; A backup you&#39;ve never restored is only a hope. Run drills, and take advantage of &lt;strong&gt;AWS Fault Injection Service&lt;/strong&gt; to cause failures deliberately.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automate.&lt;/strong&gt; Build the environment from templates, because in a disaster nobody remembers the steps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protect your backups from yourself.&lt;/strong&gt; Put them in another account and another Region, because an attacker who gets into your account will go for them first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Think of Elastic Disaster Recovery.&lt;/strong&gt; &lt;strong&gt;AWS DRS&lt;/strong&gt; continuously replicates your servers to cheap storage, and launches them only when needed, with an RPO of seconds and an RTO of minutes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check the quotas in the standby Region.&lt;/strong&gt; Quotas are per Region, so a small standby can hit its limit just when it has to grow. Raise them there in advance, from the &lt;strong&gt;Service Quotas&lt;/strong&gt; console.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;aws-backup-everything-in-one-place&quot; tabindex=&quot;-1&quot;&gt;AWS Backup: everything in one place &lt;a class=&quot;heading-anchor&quot; href=&quot;#aws-backup-everything-in-one-place&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each service has its own backups, but &lt;strong&gt;AWS Backup&lt;/strong&gt; manages them centrally, for EC2, EBS, S3, RDS, Aurora, DynamoDB, EFS, FSx and others:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backup plan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A schedule and a retention period, such as daily for 35 days, then moving to cold storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vault&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Where the backups are stored, encrypted with KMS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tags&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Back up anything tagged &lt;code&gt;backup=daily&lt;/code&gt;, so new resources join by themselves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Copies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;To another Region or another account, for real disaster protection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vault Lock&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stops anyone, even the root user in compliance mode, from deleting backups before they expire&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Vault Lock&lt;/strong&gt; is your strongest defense against ransomware and against someone with stolen administrator credentials.&lt;/p&gt;
&lt;h2 id=&quot;migrating-databases-dms&quot; tabindex=&quot;-1&quot;&gt;Migrating databases: DMS &lt;a class=&quot;heading-anchor&quot; href=&quot;#migrating-databases-dms&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;AWS DMS&lt;/strong&gt; (Database Migration Service) moves a database while it stays in use: it copies the existing data, then keeps sending changes (known as &lt;strong&gt;CDC&lt;/strong&gt;) until you&#39;re ready to switch over.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Same engine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MySQL on a server to RDS for MySQL&lt;/td&gt;
&lt;td&gt;DMS alone is enough&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Different engine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Oracle to Aurora PostgreSQL&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DMS Schema Conversion&lt;/strong&gt; or &lt;strong&gt;SCT&lt;/strong&gt;, to convert the tables and code first, then DMS for the data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Sources and targets are many, including on-premises databases, RDS, S3, DynamoDB, Redshift and OpenSearch. It can run in &lt;strong&gt;Multi-AZ&lt;/strong&gt;, with a standby instance in another zone, or as &lt;strong&gt;Serverless&lt;/strong&gt; so you don&#39;t have to size it.&lt;/p&gt;
&lt;h3 id=&quot;moving-to-rds-or-aurora&quot; tabindex=&quot;-1&quot;&gt;Moving to RDS or Aurora &lt;a class=&quot;heading-anchor&quot; href=&quot;#moving-to-rds-or-aurora&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you&#39;re moving MySQL or PostgreSQL, you have simpler routes:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Downtime&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Snapshot from RDS to Aurora&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes, during the move&lt;/td&gt;
&lt;td&gt;Downtime is acceptable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Aurora read replica, then promote it&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very short&lt;/td&gt;
&lt;td&gt;From RDS, with no real downtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backup from S3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Coming from outside RDS: Percona XtraBackup for MySQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DMS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very short&lt;/td&gt;
&lt;td&gt;Continuous replication from anywhere&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;migrating-servers-and-whole-data-centers&quot; tabindex=&quot;-1&quot;&gt;Migrating servers and whole data centers &lt;a class=&quot;heading-anchor&quot; href=&quot;#migrating-servers-and-whole-data-centers&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You want&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Moving servers as they are (lift and shift)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Transform MGN&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Importing one virtual machine image&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VM Import/Export&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moving VMware as it is&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Elastic VMware Service&lt;/strong&gt;, or VMware Cloud on AWS from Broadcom&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Help planning a large migration&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Transform&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moving files&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-18-storage-transfer/&quot;&gt;DataSync&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Putting Java or .NET applications in containers&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;App2Container&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;AWS Transform MGN&lt;/strong&gt; was known as Application Migration Service until 2026. An agent on your server replicates its disks continuously to low-cost AWS resources, you test as often as you like, then you switch over in minutes. It&#39;s usually the fastest way out of a data center.&lt;/p&gt;
&lt;aside class=&quot;callout callout-note&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-info&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;circle cx=&quot;12&quot; cy=&quot;12&quot; r=&quot;8.5&quot;/&gt;&lt;path d=&quot;M12 11v5M12 8h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Older tools&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;You may read about &lt;strong&gt;Application Discovery Service&lt;/strong&gt; and &lt;strong&gt;Migration Hub&lt;/strong&gt;, which were for planning migrations. They&#39;re no longer open to new customers, and AWS Transform is now the path for this kind of work.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;And if you have huge amounts of data, we did the math in &lt;a href=&quot;/en/posts/aws-18-storage-transfer/&quot;&gt;part eighteen&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;hands-on-delete-the-data-and-bring-it-back&quot; tabindex=&quot;-1&quot;&gt;Hands-on: delete the data and bring it back &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-delete-the-data-and-bring-it-back&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll play out a small disaster: a table, a backup, a mistaken delete, then a restore. From CloudShell, create the table with one order:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws dynamodb create-table --table-name series-orders &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --attribute-definitions &lt;span class=&quot;token assign-left variable&quot;&gt;AttributeName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;id,AttributeType&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;S &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --key-schema &lt;span class=&quot;token assign-left variable&quot;&gt;AttributeName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;id,KeyType&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;HASH &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --billing-mode PAY_PER_REQUEST &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; TableDescription.TableStatus

aws dynamodb &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt; table-exists --table-name series-orders

aws dynamodb put-item --table-name series-orders &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--item&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;id&quot;:{&quot;S&quot;:&quot;1001&quot;},&quot;total&quot;:{&quot;N&quot;:&quot;120&quot;}}&#39;&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;TABLE_ARN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws dynamodb describe-table --table-name series-orders &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Table.TableArn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;AWS Backup needs a role and a vault:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; trust.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [{
    &quot;Effect&quot;: &quot;Allow&quot;,
    &quot;Principal&quot;: {&quot;Service&quot;: &quot;backup.amazonaws.com&quot;},
    &quot;Action&quot;: &quot;sts:AssumeRole&quot;
  }]
}
EOF&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;ROLE_ARN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws iam create-role --role-name series-backup-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --assume-role-policy-document file://trust.json &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Role.Arn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws iam attach-role-policy --role-name series-backup-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup
aws iam attach-role-policy --role-name series-backup-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores

aws backup create-backup-vault --backup-vault-name series-vault &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; BackupVaultName &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Start a backup, then wait for it. If you get a role error, wait a few seconds and repeat the first command. This usually takes a few minutes:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;&lt;span class=&quot;token environment constant&quot;&gt;JOB&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws backup start-backup-job --backup-vault-name series-vault &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --resource-arn $TABLE_ARN --iam-role-arn $ROLE_ARN &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; BackupJobId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;token assign-left variable&quot;&gt;STATE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws backup describe-backup-job --backup-job-id &lt;span class=&quot;token environment constant&quot;&gt;$JOB&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; State &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$STATE&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$STATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; COMPLETED&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;FAILED&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;ABORTED&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;EXPIRED&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;esac&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;POINT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws backup describe-backup-job --backup-job-id &lt;span class=&quot;token environment constant&quot;&gt;$JOB&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; RecoveryPointArn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Now the disaster. The order is gone:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws dynamodb delete-item --table-name series-orders &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--key&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;id&quot;:{&quot;S&quot;:&quot;1001&quot;}}&#39;&lt;/span&gt;

aws dynamodb get-item --table-name series-orders &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--key&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;id&quot;:{&quot;S&quot;:&quot;1001&quot;}}&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The second command prints nothing. Restore the backup to a new table, and note the time it takes, because this is your real RTO:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;RESTORE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws backup start-restore-job --recovery-point-arn $POINT &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --iam-role-arn $ROLE_ARN &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--metadata&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;targetTableName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;series-orders-restored,encryptionType&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;Default &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; RestoreJobId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;token assign-left variable&quot;&gt;STATE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws backup describe-restore-job --restore-job-id $RESTORE &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Status &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$STATE&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$STATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; COMPLETED&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;FAILED&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;ABORTED&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;esac&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;

aws dynamodb get-item --table-name series-orders-restored &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--key&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;id&quot;:{&quot;S&quot;:&quot;1001&quot;}}&#39;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Item&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The order&#39;s back. Anything written after the backup is lost, and that&#39;s your RPO.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This costs a fraction of a cent, but delete the vault&#39;s contents before the vault:&lt;/p&gt;
&lt;/aside&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws backup delete-recovery-point --backup-vault-name series-vault &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --recovery-point-arn &lt;span class=&quot;token variable&quot;&gt;$POINT&lt;/span&gt;
aws backup delete-backup-vault --backup-vault-name series-vault

aws dynamodb delete-table --table-name series-orders &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; TableDescription.TableStatus
aws dynamodb delete-table --table-name series-orders-restored &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; TableDescription.TableStatus

aws iam detach-role-policy --role-name series-backup-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup
aws iam detach-role-policy --role-name series-backup-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores
aws iam delete-role --role-name series-backup-role&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RPO&lt;/strong&gt; is the data you lose, &lt;strong&gt;RTO&lt;/strong&gt; is the time you&#39;re down, and the business decides both.&lt;/li&gt;
&lt;li&gt;The four strategies: &lt;strong&gt;backup&lt;/strong&gt;, &lt;strong&gt;pilot light&lt;/strong&gt;, &lt;strong&gt;warm standby&lt;/strong&gt; and &lt;strong&gt;multi-site&lt;/strong&gt;, with cost rising as they improve.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AWS Backup&lt;/strong&gt; manages backups centrally, and &lt;strong&gt;Vault Lock&lt;/strong&gt; protects them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DMS&lt;/strong&gt; moves databases while they run, and &lt;strong&gt;AWS Transform MGN&lt;/strong&gt; moves servers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test your recovery&lt;/strong&gt;, or you don&#39;t have any.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 6&lt;/p&gt;
&lt;p&gt;A company backs up its database every six hours, and a full restore takes two hours. In the worst case, what are its RPO and RTO?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;RPO of 2 hours, RTO of 6 hours&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;RPO of 8 hours, RTO of 8 hours&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;RPO of zero, RTO of 2 hours&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;RPO of 6 hours, RTO of 2 hours&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;RPO is the data you can lose, which is up to the six hours since the last backup. RTO is the time you&#39;re down, which is the two hours of restoring.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This swaps the two numbers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; The numbers measure different things, so they don&#39;t add together.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; Anything written since the last backup is lost, so the RPO isn&#39;t zero.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#rpo-and-rto&quot;&gt;RPO and RTO&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/whitepapers/latest/disaster-recovery-workloads-on-aws/business-continuity-plan-bcp.html&quot;&gt;Business Continuity Plan (BCP)&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 6&lt;/p&gt;
&lt;p&gt;An application must recover in another Region within an hour and lose only minutes of data, at the &lt;strong&gt;lowest cost&lt;/strong&gt; that meets this. Which strategy fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Backup and restore&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Pilot light&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Warm standby&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Multi-site active-active&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pilot light keeps the data replicating with the servers ready but stopped, which gets you back in tens of minutes for little running cost.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Recovery can take up to 24 hours, and you&#39;d lose hours of data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This also meets the need, but you&#39;d pay for a full copy running all the time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This meets it too, at by far the highest cost.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#four-strategies&quot;&gt;Four strategies&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/whitepapers/latest/disaster-recovery-workloads-on-aws/disaster-recovery-options-in-the-cloud.html&quot;&gt;Disaster recovery options in the cloud&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 6&lt;/p&gt;
&lt;p&gt;A company fears ransomware: an attacker with stolen administrator credentials could delete its backups. Which step protects them best?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;AWS Backup Vault Lock in compliance mode&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;An IAM policy denying deletion of backups&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Encrypting the backups with KMS&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A CloudWatch alarm on backup deletions&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In compliance mode nobody can delete a backup before it expires, not even the root user.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; An administrator can simply change the policy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; Encrypted backups can still be deleted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; You&#39;d hear about the deletion, but the backups would already be gone.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#aws-backup-everything-in-one-place&quot;&gt;AWS Backup: everything in one place&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/aws-backup/latest/devguide/vault-lock.html&quot;&gt;AWS Backup Vault Lock&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 6&lt;/p&gt;
&lt;p&gt;A company wants to move 200 servers from its data center to AWS as they are, test them there as often as it likes, and cut over in minutes. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;AWS DMS&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;AWS DataSync&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;AWS Transform MGN&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;VM Import/Export&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An agent on each server replicates its disks continuously to AWS, so you can test at will, then switch over in minutes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This moves databases, not whole servers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This moves files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This imports virtual machine images, with no continuous replication.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#migrating-servers-and-whole-data-centers&quot;&gt;Migrating servers and whole data centers&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/mgn/latest/ug/what-is-application-migration-service.html&quot;&gt;What Is AWS Transform MGN?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 6&lt;/p&gt;
&lt;p&gt;A company is moving a busy Oracle database to Aurora PostgreSQL, with very little downtime. Which &lt;strong&gt;two&lt;/strong&gt; tools does it need? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;AWS Transform MGN&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;AWS DataSync&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;DMS Schema Conversion or SCT&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;An Aurora read replica of the Oracle database&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;AWS DMS, with ongoing replication&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The engines differ, so the tables and code are converted first. DMS then copies the data and keeps sending changes until you&#39;re ready to switch.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This moves servers as they are, so the database would stay on Oracle.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This moves files, and can&#39;t keep a live database in sync.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Aurora read replicas come from RDS for MySQL or PostgreSQL, not from Oracle.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#migrating-databases-dms&quot;&gt;Migrating databases: DMS&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/dms/latest/userguide/Welcome.html&quot;&gt;What is AWS Database Migration Service?&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/dms/latest/userguide/CHAP_SchemaConversion.html&quot;&gt;Converting database schemas using DMS Schema Conversion&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 6 of 6&lt;/p&gt;
&lt;p&gt;In a recovery drill, a warm standby in a second Region starts to grow, but new servers fail to launch because of an account limit that&#39;s lower there than in the main Region. What should the team do?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Raise the quotas in the standby Region ahead of time&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Switch to pilot light&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Copy the backups to a third Region&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Raise the quotas in the main Region&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Quotas are per Region, so the standby needs limits high enough for production capacity before a disaster. You raise them from the Service Quotas console.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This keeps even less running, and would hit the same limit when it grows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This protects data, and doesn&#39;t change the limit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Quotas are per Region, so this doesn&#39;t help the standby.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#tips-that-make-the-difference&quot;&gt;Tips that make the difference&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/whitepapers/latest/disaster-recovery-workloads-on-aws/disaster-recovery-options-in-the-cloud.html&quot;&gt;Disaster recovery options in the cloud&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/servicequotas/latest/userguide/intro.html&quot;&gt;What is Service Quotas?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;Your application is now built, protected and recoverable. One last question remains: how much does it cost, and is it designed well? In &lt;a href=&quot;/en/posts/aws-29-cost-good-architecture/&quot;&gt;&lt;strong&gt;part twenty-nine&lt;/strong&gt;&lt;/a&gt; we close the series with cost and good architecture.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Encryption, Secrets and Threat Protection</title>
    <link href="https://blog.sultanops.com/en/posts/aws-27-encryption-secrets-protection/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-27-encryption-secrets-protection/</id>
    <summary>How KMS protects your keys, where to keep passwords with Parameter Store and Secrets Manager, free certificates from ACM, stopping attacks with WAF and Shield, and detecting threats with GuardDuty, Inspector and Macie, with a hands-on.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-26-organizations-identity-center/&quot;&gt;part twenty-six&lt;/a&gt; we controlled who gets in. This part assumes the worst: a disk gets stolen, a password leaks, or someone attacks your site. What protects you then?&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You want&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Encryption keys you control&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;KMS&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Settings and simple secrets&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Parameter Store&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Passwords that rotate by themselves&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Secrets Manager&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTPS certificates&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;ACM&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stopping web attacks&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;WAF&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Withstanding DDoS attacks&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Shield&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Detecting threats in your account&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;GuardDuty&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Finding vulnerabilities in what you run&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Inspector&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Finding sensitive data in S3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Macie&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;aws-kms-the-key-safe&quot; tabindex=&quot;-1&quot;&gt;AWS KMS: the key safe &lt;a class=&quot;heading-anchor&quot; href=&quot;#aws-kms-the-key-safe&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We saw the &lt;a href=&quot;/en/posts/aws-17-s3-security/&quot;&gt;types of encryption in S3&lt;/a&gt;. Behind most of them is &lt;strong&gt;KMS&lt;/strong&gt; (Key Management Service): keys are created and used inside it and never leave it unencrypted, access is controlled by policies, and every use is recorded in &lt;a href=&quot;/en/posts/aws-25-monitoring-auditing/&quot;&gt;CloudTrail&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;envelope-encryption&quot; tabindex=&quot;-1&quot;&gt;Envelope encryption &lt;a class=&quot;heading-anchor&quot; href=&quot;#envelope-encryption&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;KMS doesn&#39;t encrypt your large files itself. It makes a &lt;strong&gt;data key&lt;/strong&gt; that encrypts the file, and it encrypts that data key with your master key:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 214&quot; role=&quot;img&quot; aria-labelledby=&quot;envelope-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;envelope-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;14&quot; width=&quot;170&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;105&quot; y=&quot;44&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;KMS key&lt;/text&gt;
&lt;text x=&quot;105&quot; y=&quot;64&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Never leaves KMS&lt;/text&gt;
&lt;rect x=&quot;235&quot; y=&quot;14&quot; width=&quot;170&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;44&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Data key&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;64&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Encrypts the file&lt;/text&gt;
&lt;rect x=&quot;450&quot; y=&quot;14&quot; width=&quot;170&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;535&quot; y=&quot;44&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Your file&lt;/text&gt;
&lt;text x=&quot;535&quot; y=&quot;64&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Now encrypted&lt;/text&gt;
&lt;rect x=&quot;235&quot; y=&quot;130&quot; width=&quot;170&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;160&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Encrypted data key&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;180&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Stored with the file&lt;/text&gt;
&lt;line x1=&quot;190&quot; y1=&quot;49&quot; x2=&quot;233&quot; y2=&quot;49&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#envelope-arrow)&quot;/&gt;
&lt;line x1=&quot;405&quot; y1=&quot;49&quot; x2=&quot;448&quot; y2=&quot;49&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#envelope-arrow)&quot;/&gt;
&lt;line x1=&quot;320&quot; y1=&quot;84&quot; x2=&quot;320&quot; y2=&quot;128&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#envelope-arrow)&quot;/&gt;
&lt;line x1=&quot;405&quot; y1=&quot;165&quot; x2=&quot;535&quot; y2=&quot;86&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#envelope-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;envelope-caption&quot;&gt;The data key encrypts the file, and an encrypted copy of it is stored beside the file. Only KMS can open that copy, so the file is useless without permission.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So even whoever steals the disk gets encrypted data with an encrypted key next to it. To decrypt, you need permission to ask KMS to open the data key, and that&#39;s where your control sits.&lt;/p&gt;
&lt;h3 id=&quot;types-of-keys&quot; tabindex=&quot;-1&quot;&gt;Types of keys &lt;a class=&quot;heading-anchor&quot; href=&quot;#types-of-keys&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Who controls it&lt;/th&gt;
&lt;th&gt;Monthly cost&lt;/th&gt;
&lt;th&gt;Rotation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS owned&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS, and you never see it&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;By the service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS managed&lt;/strong&gt; (such as &lt;code&gt;aws/ebs&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;AWS, and you can view and audit it&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Yearly, and it can&#39;t be changed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Customer managed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You entirely&lt;/td&gt;
&lt;td&gt;$1 per key, plus API calls&lt;/td&gt;
&lt;td&gt;Optional, yearly by default, or from 90 to 2,560 days&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Most keys are &lt;strong&gt;symmetric&lt;/strong&gt;, one key for encrypting and decrypting that never leaves KMS. There are also &lt;strong&gt;asymmetric&lt;/strong&gt; pairs, where the public key leaves KMS, for signing or for encryption by parties outside AWS.&lt;/p&gt;
&lt;p&gt;Deleting a key is irreversible, because it destroys everything encrypted with it. So KMS imposes a waiting period of 7 to 30 days, during which you can cancel. To stop a key from being used in the meantime, disable it.&lt;/p&gt;
&lt;h3 id=&quot;key-policies&quot; tabindex=&quot;-1&quot;&gt;Key policies &lt;a class=&quot;heading-anchor&quot; href=&quot;#key-policies&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Every KMS key has a &lt;strong&gt;key policy&lt;/strong&gt;, and unlike other resources, IAM alone isn&#39;t enough without it. The default policy lets the account&#39;s IAM policies grant access to the key.&lt;/p&gt;
&lt;p&gt;This matters when copying encrypted data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;To another Region:&lt;/strong&gt; keys are Regional, so copying a snapshot re-encrypts it with a key in the destination Region.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;To another account:&lt;/strong&gt; share the snapshot, and allow that account in the policy of a &lt;strong&gt;customer managed&lt;/strong&gt; key. AWS managed keys, such as &lt;code&gt;aws/ebs&lt;/code&gt;, can&#39;t be shared, so a snapshot encrypted with one must first be copied with your own key.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;multi-region-keys&quot; tabindex=&quot;-1&quot;&gt;Multi-Region keys &lt;a class=&quot;heading-anchor&quot; href=&quot;#multi-region-keys&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Multi-Region keys&lt;/strong&gt; share the same key material and ID across Regions, so something encrypted in one Region can be decrypted in another without re-encrypting. They&#39;re not for everything, as AWS recommends single-Region keys by default. They suit cases such as client-side encryption of a field in &lt;a href=&quot;/en/posts/aws-21-lambda-api-dynamodb/&quot;&gt;Global Tables&lt;/a&gt; or Aurora Global.&lt;/p&gt;
&lt;h3 id=&quot;cloudhsm-your-own-hardware&quot; tabindex=&quot;-1&quot;&gt;CloudHSM: your own hardware &lt;a class=&quot;heading-anchor&quot; href=&quot;#cloudhsm-your-own-hardware&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With KMS, AWS manages the hardware holding your keys. If a regulation requires a hardware security module dedicated to you, &lt;strong&gt;AWS CloudHSM&lt;/strong&gt; gives you a single-tenant cluster of FIPS-validated HSMs. AWS handles provisioning and backups, while you control the keys and users yourself. Choose it only when you must, because you take on more responsibility than with KMS.&lt;/p&gt;
&lt;h2 id=&quot;where-do-you-keep-passwords&quot; tabindex=&quot;-1&quot;&gt;Where do you keep passwords? &lt;a class=&quot;heading-anchor&quot; href=&quot;#where-do-you-keep-passwords&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not in code, and not in Git. You have two services:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Parameter Store&lt;/th&gt;
&lt;th&gt;Secrets Manager&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Suits&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Settings and simple secrets&lt;/td&gt;
&lt;td&gt;Secrets that must rotate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Encryption&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Optional, with KMS, using &lt;code&gt;SecureString&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Always, with KMS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rotation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not built in&lt;/td&gt;
&lt;td&gt;Built in, with a Lambda function, and integrated with RDS and Aurora&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Replicas in other Regions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Price&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Standard is free&lt;/td&gt;
&lt;td&gt;$0.40 per secret per month, plus API calls&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;parameter-store&quot; tabindex=&quot;-1&quot;&gt;Parameter Store &lt;a class=&quot;heading-anchor&quot; href=&quot;#parameter-store&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Its names form a hierarchy, such as &lt;code&gt;/shop/prod/db-url&lt;/code&gt;, so an application can fetch a whole path, and IAM can allow &lt;code&gt;/shop/prod/*&lt;/code&gt; only.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Standard&lt;/th&gt;
&lt;th&gt;Advanced&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Max size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4 KB&lt;/td&gt;
&lt;td&gt;8 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Count per Region&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;10,000&lt;/td&gt;
&lt;td&gt;100,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Policies, such as expiry&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Price&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;$0.05 per parameter per month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;secrets-manager&quot; tabindex=&quot;-1&quot;&gt;Secrets Manager &lt;a class=&quot;heading-anchor&quot; href=&quot;#secrets-manager&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The point here is rotation: the password changes on a schedule you set, and the function updates it in the database too. Your application asks for the current value each time, so it doesn&#39;t notice. We saw in &lt;a href=&quot;/en/posts/aws-08-rds-aurora/&quot;&gt;part eight&lt;/a&gt; that RDS can manage its password here for you.&lt;/p&gt;
&lt;h2 id=&quot;acm-certificates-without-the-hassle&quot; tabindex=&quot;-1&quot;&gt;ACM: certificates without the hassle &lt;a class=&quot;heading-anchor&quot; href=&quot;#acm-certificates-without-the-hassle&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;AWS Certificate Manager&lt;/strong&gt; issues public TLS certificates for free when used with services like load balancers, CloudFront and API Gateway, and it renews them by itself.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Validation:&lt;/strong&gt; prove you own the domain by DNS, and it&#39;s best with &lt;a href=&quot;/en/posts/aws-11-dns-route53/&quot;&gt;Route 53&lt;/a&gt;, or by email.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validity:&lt;/strong&gt; public certificates now last 198 days, under new industry rules, and renewal happens automatically about 45 days before expiry. The period will shorten further in the coming years, which is more reason to leave it to automation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Imported certificates:&lt;/strong&gt; you can import your own, but ACM doesn&#39;t renew those, so set an alert on their expiry.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Other servers:&lt;/strong&gt; a normal ACM certificate can&#39;t be installed on your own server. If you need that, there are &lt;strong&gt;exportable certificates&lt;/strong&gt;, for a fee.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;callout callout-warning&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-alert&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 4l9 16H3L12 4z&quot;/&gt;&lt;path d=&quot;M12 10v4M12 17h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;The Region trap&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A certificate must be in the same Region as what uses it, with one exception to remember: &lt;strong&gt;CloudFront&lt;/strong&gt; and edge-optimized API Gateway need the certificate in &lt;strong&gt;&lt;code&gt;us-east-1&lt;/code&gt;&lt;/strong&gt;, wherever your application is.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;stopping-attacks&quot; tabindex=&quot;-1&quot;&gt;Stopping attacks &lt;a class=&quot;heading-anchor&quot; href=&quot;#stopping-attacks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here&#39;s how the protection layers sit together in a typical design:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 150&quot; role=&quot;img&quot; aria-labelledby=&quot;edge-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;edge-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;40&quot; width=&quot;110&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;75&quot; y=&quot;80&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Visitors&lt;/text&gt;
&lt;rect x=&quot;170&quot; y=&quot;26&quot; width=&quot;130&quot; height=&quot;98&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;235&quot; y=&quot;70&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;CloudFront&lt;/text&gt;
&lt;text x=&quot;235&quot; y=&quot;90&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;WAF and Shield&lt;/text&gt;
&lt;rect x=&quot;340&quot; y=&quot;40&quot; width=&quot;130&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;405&quot; y=&quot;70&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;ALB&lt;/text&gt;
&lt;text x=&quot;405&quot; y=&quot;90&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;CloudFront only&lt;/text&gt;
&lt;rect x=&quot;510&quot; y=&quot;40&quot; width=&quot;110&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;565&quot; y=&quot;70&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Servers&lt;/text&gt;
&lt;text x=&quot;565&quot; y=&quot;90&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Private&lt;/text&gt;
&lt;line x1=&quot;130&quot; y1=&quot;75&quot; x2=&quot;168&quot; y2=&quot;75&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#edge-arrow)&quot;/&gt;
&lt;line x1=&quot;300&quot; y1=&quot;75&quot; x2=&quot;338&quot; y2=&quot;75&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#edge-arrow)&quot;/&gt;
&lt;line x1=&quot;470&quot; y1=&quot;75&quot; x2=&quot;508&quot; y2=&quot;75&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#edge-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;edge-caption&quot;&gt;Attacks are absorbed at the edge, and the load balancer&#39;s security group accepts traffic only from CloudFront, so nobody can go around it.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WAF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Application (7)&lt;/td&gt;
&lt;td&gt;Rules on requests: SQL injection, XSS, country, IP lists, and rate limits&lt;/td&gt;
&lt;td&gt;Per rule and request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shield Standard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Network (3 and 4)&lt;/td&gt;
&lt;td&gt;Protection from common DDoS attacks&lt;/td&gt;
&lt;td&gt;Free and automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shield Advanced&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Up to 7&lt;/td&gt;
&lt;td&gt;A specialist response team, cost protection during attacks&lt;/td&gt;
&lt;td&gt;A monthly subscription, and it&#39;s expensive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Firewall Manager&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Management&lt;/td&gt;
&lt;td&gt;Applies WAF, Shield, security group and other rules across all your organization&#39;s accounts&lt;/td&gt;
&lt;td&gt;Per policy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;WAF attaches to &lt;strong&gt;CloudFront, Application Load Balancer, API Gateway and AppSync&lt;/strong&gt;, but not to a Network Load Balancer. If you need a fixed IP with WAF, put &lt;a href=&quot;/en/posts/aws-12-cloudfront-global-accelerator/&quot;&gt;Global Accelerator&lt;/a&gt; in front of the load balancer. &lt;strong&gt;Rate-based rules&lt;/strong&gt; are simple and effective: block any address sending more than a set number of requests.&lt;/p&gt;
&lt;h3 id=&quot;withstanding-ddos&quot; tabindex=&quot;-1&quot;&gt;Withstanding DDoS &lt;a class=&quot;heading-anchor&quot; href=&quot;#withstanding-ddos&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;/en/posts/aws-12-cloudfront-global-accelerator/&quot;&gt;earlier parts&lt;/a&gt; gave you most of what&#39;s needed already:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CloudFront and Route 53&lt;/strong&gt; absorb attacks at the edge, far from your servers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto Scaling&lt;/strong&gt; grows if something gets through, though watch the cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A security group&lt;/strong&gt; allows the load balancer only from CloudFront, so nobody can skip it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WAF&lt;/strong&gt; with rate limits and Bot Control for attacks that look like normal requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;blocking-one-address-where&quot; tabindex=&quot;-1&quot;&gt;Blocking one address: where? &lt;a class=&quot;heading-anchor&quot; href=&quot;#blocking-one-address-where&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your design&lt;/th&gt;
&lt;th&gt;Where to block&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EC2 with a public IP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A network ACL&lt;/td&gt;
&lt;td&gt;Security groups only allow; they can&#39;t deny&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A load balancer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A network ACL on its subnet, or WAF&lt;/td&gt;
&lt;td&gt;The server sees only the load balancer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CloudFront in front&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;WAF on CloudFront, or geo restriction&lt;/td&gt;
&lt;td&gt;A network ACL won&#39;t help, because requests arrive from CloudFront&#39;s addresses&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For protection at the VPC boundary, there&#39;s also &lt;a href=&quot;/en/posts/aws-14-vpc-connectivity/&quot;&gt;Network Firewall&lt;/a&gt;, which we covered in part fourteen.&lt;/p&gt;
&lt;h2 id=&quot;detecting-threats&quot; tabindex=&quot;-1&quot;&gt;Detecting threats &lt;a class=&quot;heading-anchor&quot; href=&quot;#detecting-threats&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Prevention isn&#39;t everything. You also need something to tell you when something&#39;s wrong:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;The question it answers&lt;/th&gt;
&lt;th&gt;Works from&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GuardDuty&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Is something suspicious happening in my account?&lt;/td&gt;
&lt;td&gt;CloudTrail, VPC Flow Logs and DNS logs, with no agents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inspector&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does what I run have known vulnerabilities?&lt;/td&gt;
&lt;td&gt;EC2 servers, ECR images and Lambda functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Macie&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Is there sensitive data somewhere it shouldn&#39;t be?&lt;/td&gt;
&lt;td&gt;S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security Hub&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;How&#39;s my security overall?&lt;/td&gt;
&lt;td&gt;Gathers and prioritizes the findings of the others&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Detective&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Why did this finding happen?&lt;/td&gt;
&lt;td&gt;Collects logs by itself and links them together, to find the root cause&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;GuardDuty catches things like crypto mining, or credentials used from a strange place. Send its findings through EventBridge to SNS or Lambda so you act on them. It&#39;s one click to enable, so turn it on from the start in any serious account, as it has a free trial period.&lt;/p&gt;
&lt;h3 id=&quot;compliance-documents-aws-artifact&quot; tabindex=&quot;-1&quot;&gt;Compliance documents: AWS Artifact &lt;a class=&quot;heading-anchor&quot; href=&quot;#compliance-documents-aws-artifact&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An auditor asks for proof that AWS itself meets ISO or PCI standards? &lt;strong&gt;AWS Artifact&lt;/strong&gt; gives you those reports on demand and free of charge, and it&#39;s also where you review and accept agreements with AWS. It covers AWS&#39;s side of the &lt;a href=&quot;/en/posts/aws-01-global-infrastructure/&quot;&gt;shared responsibility model&lt;/a&gt;, and proving your side is still up to you.&lt;/p&gt;
&lt;h2 id=&quot;hands-on-a-key-a-parameter-and-a-secret&quot; tabindex=&quot;-1&quot;&gt;Hands-on: a key, a parameter and a secret &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-a-key-a-parameter-and-a-secret&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;From CloudShell, create a key with an easy name, and encrypt some text:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;KEY_ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws kms create-key &lt;span class=&quot;token parameter variable&quot;&gt;--description&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Series demo key&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; KeyMetadata.KeyId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
aws kms create-alias --alias-name alias/series-demo --target-key-id &lt;span class=&quot;token variable&quot;&gt;$KEY_ID&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;CIPHER&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws kms encrypt --key-id alias/series-demo &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--plaintext&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;my secret note&quot;&lt;/span&gt; --cli-binary-format raw-in-base64-out &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; CiphertextBlob &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$CIPHER&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;You&#39;ll see unreadable text. Decrypt it. For a symmetric key, there&#39;s no need to say which key:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws kms decrypt --ciphertext-blob &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$CIPHER&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Plaintext &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; base64 -d&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Now see where the real control lies. Disable the key, and try again:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws kms disable-key --key-id &lt;span class=&quot;token variable&quot;&gt;$KEY_ID&lt;/span&gt;

aws kms decrypt --ciphertext-blob &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$CIPHER&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Plaintext &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text

aws kms enable-key --key-id &lt;span class=&quot;token variable&quot;&gt;$KEY_ID&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;You&#39;ll get a &lt;code&gt;DisabledException&lt;/code&gt;. The data hasn&#39;t changed, but it&#39;s useless without the key. Now keep a password in Parameter Store, encrypted with the same key, and read it with and without decryption:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws ssm put-parameter &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; /series/prod/db-password &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--type&lt;/span&gt; SecureString --key-id alias/series-demo &lt;span class=&quot;token parameter variable&quot;&gt;--value&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;S3cret-pass&quot;&lt;/span&gt;

aws ssm get-parameter &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; /series/prod/db-password &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Parameter.Value &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text

aws ssm get-parameter &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; /series/prod/db-password --with-decryption &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Parameter.Value &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text

aws ssm get-parameters-by-path &lt;span class=&quot;token parameter variable&quot;&gt;--path&lt;/span&gt; /series/prod &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Parameters[].Name&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;And a secret in Secrets Manager, in the way your application would read it:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws secretsmanager create-secret &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; series/api-key &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --secret-string &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;key&quot;:&quot;abc123&quot;}&#39;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Name &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text

aws secretsmanager get-secret-value --secret-id series/api-key &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; SecretString &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Finally, what did all of this leave behind? &lt;a href=&quot;/en/posts/aws-25-monitoring-auditing/&quot;&gt;CloudTrail&lt;/a&gt; has recorded who used the key, though it can take a few minutes:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws cloudtrail lookup-events &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --lookup-attributes &lt;span class=&quot;token assign-left variable&quot;&gt;AttributeKey&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;EventName,AttributeValue&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;Decrypt &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --max-results &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Events[].[EventName,Username,EventTime]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; table&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A key costs $1 per month, prorated by the hour, and stops being charged once it&#39;s scheduled for deletion, so this costs under a cent or two:&lt;/p&gt;
&lt;/aside&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws secretsmanager delete-secret --secret-id series/api-key &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --force-delete-without-recovery
aws ssm delete-parameter &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; /series/prod/db-password
aws kms delete-alias --alias-name alias/series-demo
aws kms schedule-key-deletion --key-id &lt;span class=&quot;token variable&quot;&gt;$KEY_ID&lt;/span&gt; --pending-window-in-days &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;KMS&lt;/strong&gt; keeps your keys safe, uses envelope encryption, and records every use.&lt;/li&gt;
&lt;li&gt;Keys are &lt;strong&gt;Regional&lt;/strong&gt;, and AWS managed keys can&#39;t be shared across accounts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parameter Store&lt;/strong&gt; for settings, and &lt;strong&gt;Secrets Manager&lt;/strong&gt; for what must rotate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ACM&lt;/strong&gt; certificates are free and renew themselves, and CloudFront needs them in &lt;code&gt;us-east-1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WAF&lt;/strong&gt; and &lt;strong&gt;Shield&lt;/strong&gt; stop attacks, and &lt;strong&gt;GuardDuty&lt;/strong&gt;, &lt;strong&gt;Inspector&lt;/strong&gt; and &lt;strong&gt;Macie&lt;/strong&gt; detect what gets through.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 7&lt;/p&gt;
&lt;p&gt;An application&#39;s database password must change every 30 days, both in the database and where the application reads it, with no code release each time. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Secrets Manager, with rotation turned on&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Parameter Store, with a &lt;code&gt;SecureString&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;KMS automatic key rotation&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;An environment variable on the server&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Secrets Manager changes the password on a schedule and updates the database too. The application asks for the current value each time, so it doesn&#39;t notice.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This stores the value encrypted, but has no built-in rotation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This rotates an encryption key, not a database password.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Someone would have to change it by hand on every server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#secrets-manager&quot;&gt;Secrets Manager&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html&quot;&gt;Rotate AWS Secrets Manager secrets&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 7&lt;/p&gt;
&lt;p&gt;A team wants to share an encrypted EBS snapshot with another account, but the snapshot is encrypted with the &lt;code&gt;aws/ebs&lt;/code&gt; key. What should it do?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Add the other account to the &lt;code&gt;aws/ebs&lt;/code&gt; key&#39;s policy&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Share the snapshot publicly&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Copy it with a customer managed key, then share it and allow the account in that key&#39;s policy&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Turn off encryption on the snapshot&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AWS managed keys can&#39;t be shared, so the snapshot has to be re-encrypted with your own key first. The other account then needs access to both the snapshot and the key.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; AWS managed keys can&#39;t be shared with other accounts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; Only unencrypted snapshots can be shared publicly, and this would expose the data to anyone.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; An encrypted snapshot can&#39;t simply be switched to unencrypted.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#key-policies&quot;&gt;Key policies&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/ebs/latest/userguide/ebs-modifying-snapshot-permissions.html&quot;&gt;Share an Amazon EBS snapshot with other AWS accounts&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 7&lt;/p&gt;
&lt;p&gt;A site runs on an ALB in Frankfurt with CloudFront in front of it. The team requested an ACM certificate in Frankfurt, but can&#39;t select it in CloudFront. What should it do?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Export the certificate, and upload it to CloudFront&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Move the ALB to &lt;code&gt;us-east-1&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Wait for the certificate&#39;s next renewal&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Request a certificate in &lt;code&gt;us-east-1&lt;/code&gt; for CloudFront&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CloudFront needs its certificate in &lt;code&gt;us-east-1&lt;/code&gt;, wherever your application is. The ALB keeps using the one in its own Region.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; A normal ACM certificate can&#39;t be exported.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; The application can stay where it is, and only CloudFront&#39;s certificate has to be there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; A renewal doesn&#39;t change a certificate&#39;s Region.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#acm-certificates-without-the-hassle&quot;&gt;ACM: certificates without the hassle&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cnames-and-https-requirements.html&quot;&gt;Requirements for using SSL/TLS certificates with CloudFront&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 7&lt;/p&gt;
&lt;p&gt;A site sits behind CloudFront, and one address is flooding it with requests. Where should the team block that address?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A network ACL on the load balancer&#39;s subnet&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A WAF rule on the CloudFront distribution&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;A deny rule in the security group&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Shield Standard&#39;s settings&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CloudFront is the first to see the visitor&#39;s address, so the block belongs there. An IP set or a rate-based rule in WAF does the job.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Requests reach the subnet from CloudFront&#39;s addresses, so the attacker&#39;s address never appears there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; A security group only allows, and can&#39;t deny.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This is automatic protection from common network attacks, with no address lists of your own.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#blocking-one-address-where&quot;&gt;Blocking one address: where?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/waf/latest/developerguide/cloudfront-features.html&quot;&gt;Using AWS WAF with Amazon CloudFront&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 7&lt;/p&gt;
&lt;p&gt;A company wants to find known software vulnerabilities in its EC2 servers and ECR images, and to find personal data sitting in its S3 buckets. Which &lt;strong&gt;two&lt;/strong&gt; services fit? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Amazon Inspector&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Amazon GuardDuty&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;AWS Shield&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;AWS WAF&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Amazon Macie&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Inspector scans what you run for known vulnerabilities, and Macie finds sensitive data in S3.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This detects suspicious activity in an account, such as stolen credentials being used.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This protects against DDoS attacks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This filters web requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#detecting-threats&quot;&gt;Detecting threats&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/inspector/latest/user/what-is-inspector.html&quot;&gt;What is Amazon Inspector?&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/macie/latest/user/what-is-macie.html&quot;&gt;What is Amazon Macie?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 6 of 7&lt;/p&gt;
&lt;p&gt;A regulator requires a bank&#39;s encryption keys to live in a hardware security module dedicated to it, validated to FIPS, that only the bank controls. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;KMS with an AWS managed key&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;KMS with a customer managed key&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;AWS CloudHSM&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Secrets Manager&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CloudHSM gives you a cluster of HSMs dedicated to you, and you control the keys and users yourself.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; AWS manages this key and the hardware, and you can&#39;t change its permissions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; You control this key&#39;s policy, but AWS manages the hardware behind it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This stores secrets such as passwords, and isn&#39;t a hardware module.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#cloudhsm-your-own-hardware&quot;&gt;CloudHSM: your own hardware&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/cloudhsm/latest/userguide/introduction.html&quot;&gt;What is AWS CloudHSM?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 7 of 7&lt;/p&gt;
&lt;p&gt;An auditor asks a company for AWS&#39;s own PCI compliance report. Separately, the security team needs to investigate the root cause of a GuardDuty finding. Which &lt;strong&gt;two&lt;/strong&gt; services fit? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;AWS Artifact&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Amazon Macie&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;AWS Config&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Amazon Detective&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Amazon Inspector&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A + D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Artifact gives you AWS&#39;s compliance reports on demand, and Detective links the logs together to find the root cause of a finding.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This finds sensitive data in S3.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This records and judges your own resources&#39; settings, not AWS&#39;s compliance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E:&lt;/strong&gt; This looks for known vulnerabilities in what you run.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#compliance-documents-aws-artifact&quot;&gt;Compliance documents: AWS Artifact&lt;/a&gt; and &lt;a href=&quot;#detecting-threats&quot;&gt;Detecting threats&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/artifact/latest/ug/what-is-aws-artifact.html&quot;&gt;What is AWS Artifact?&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/detective/latest/userguide/what-is-detective.html&quot;&gt;What is Amazon Detective?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;You&#39;ve protected yourself from people. What about a whole Region going down, or having to bring a data center over to AWS? In &lt;a href=&quot;/en/posts/aws-28-disaster-recovery-migration/&quot;&gt;&lt;strong&gt;part twenty-eight&lt;/strong&gt;&lt;/a&gt; we cover disaster recovery and migration.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Advanced Identity: Organizations and Identity Center</title>
    <link href="https://blog.sultanops.com/en/posts/aws-26-organizations-identity-center/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-26-organizations-identity-center/</id>
    <summary>Managing many accounts with Organizations and SCPs, conditions in IAM policies, roles versus resource policies, permissions boundaries and how AWS makes a decision, single sign-on with Identity Center, and a hands-on simulating policies.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-02-iam/&quot;&gt;part two&lt;/a&gt; we had one account and a few users. Now imagine a company with fifty accounts and five hundred employees: creating a user in each account for each person would be a nightmare, and one mistake could reach everything.&lt;/p&gt;
&lt;p&gt;This part covers the tools for that scale, and it completes &lt;a href=&quot;/en/posts/aws-02-iam/&quot;&gt;IAM&lt;/a&gt; with what we left out at the start.&lt;/p&gt;
&lt;h2 id=&quot;aws-organizations&quot; tabindex=&quot;-1&quot;&gt;AWS Organizations &lt;a class=&quot;heading-anchor&quot; href=&quot;#aws-organizations&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Organizations&lt;/strong&gt; gathers many accounts under one &lt;strong&gt;management account&lt;/strong&gt;, arranged in &lt;strong&gt;organizational units (OUs)&lt;/strong&gt;.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 246&quot; role=&quot;img&quot; aria-labelledby=&quot;org-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;org-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;250&quot; y=&quot;14&quot; width=&quot;140&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;41&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Root&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;92&quot; width=&quot;180&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;110&quot; y=&quot;119&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Security OU&lt;/text&gt;
&lt;rect x=&quot;230&quot; y=&quot;92&quot; width=&quot;180&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;119&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Production OU&lt;/text&gt;
&lt;rect x=&quot;440&quot; y=&quot;92&quot; width=&quot;180&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;530&quot; y=&quot;119&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Development OU&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;172&quot; width=&quot;85&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;62.5&quot; y=&quot;207&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Logs&lt;/text&gt;
&lt;rect x=&quot;115&quot; y=&quot;172&quot; width=&quot;85&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;157.5&quot; y=&quot;207&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Audit&lt;/text&gt;
&lt;rect x=&quot;230&quot; y=&quot;172&quot; width=&quot;85&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;272.5&quot; y=&quot;207&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Store&lt;/text&gt;
&lt;rect x=&quot;325&quot; y=&quot;172&quot; width=&quot;85&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;367.5&quot; y=&quot;207&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;API&lt;/text&gt;
&lt;rect x=&quot;440&quot; y=&quot;172&quot; width=&quot;85&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;482.5&quot; y=&quot;207&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Team A&lt;/text&gt;
&lt;rect x=&quot;535&quot; y=&quot;172&quot; width=&quot;85&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;577.5&quot; y=&quot;207&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Team B&lt;/text&gt;
&lt;line x1=&quot;320&quot; y1=&quot;58&quot; x2=&quot;110&quot; y2=&quot;90&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#org-arrow)&quot;/&gt;
&lt;line x1=&quot;320&quot; y1=&quot;58&quot; x2=&quot;320&quot; y2=&quot;90&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#org-arrow)&quot;/&gt;
&lt;line x1=&quot;320&quot; y1=&quot;58&quot; x2=&quot;530&quot; y2=&quot;90&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#org-arrow)&quot;/&gt;
&lt;line x1=&quot;110&quot; y1=&quot;136&quot; x2=&quot;62&quot; y2=&quot;170&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#org-arrow)&quot;/&gt;
&lt;line x1=&quot;110&quot; y1=&quot;136&quot; x2=&quot;157&quot; y2=&quot;170&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#org-arrow)&quot;/&gt;
&lt;line x1=&quot;320&quot; y1=&quot;136&quot; x2=&quot;272&quot; y2=&quot;170&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#org-arrow)&quot;/&gt;
&lt;line x1=&quot;320&quot; y1=&quot;136&quot; x2=&quot;367&quot; y2=&quot;170&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#org-arrow)&quot;/&gt;
&lt;line x1=&quot;530&quot; y1=&quot;136&quot; x2=&quot;482&quot; y2=&quot;170&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#org-arrow)&quot;/&gt;
&lt;line x1=&quot;530&quot; y1=&quot;136&quot; x2=&quot;577&quot; y2=&quot;170&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#org-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;org-caption&quot;&gt;Accounts sit in organizational units under one root, and a policy attached to a unit applies to every account beneath it.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Why many accounts, not one big account?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Isolation:&lt;/strong&gt; a mistake or breach in the development account doesn&#39;t reach production.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clear costs:&lt;/strong&gt; each account shows its team&#39;s bill.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limits:&lt;/strong&gt; each account has its own service quotas.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And what do you get from Organizations?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Consolidated billing:&lt;/strong&gt; one invoice, and combined usage reaches volume discounts faster. Savings Plans and Reserved Instances can also be shared across accounts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Centralized management:&lt;/strong&gt; creating accounts by API, and one &lt;a href=&quot;/en/posts/aws-25-monitoring-auditing/&quot;&gt;CloudTrail trail&lt;/a&gt; for everyone.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Policies:&lt;/strong&gt; rules applying to whole groups of accounts.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;organization-policies&quot; tabindex=&quot;-1&quot;&gt;Organization policies &lt;a class=&quot;heading-anchor&quot; href=&quot;#organization-policies&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Policy&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sets the maximum for what users and roles in an account can do&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sets the maximum for what can be done to resources in an account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Declarative policies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fix a service&#39;s baseline settings across accounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tag policies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Standardize tags, such as requiring a particular spelling for &lt;code&gt;CostCenter&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;service-control-policies-scps&quot; tabindex=&quot;-1&quot;&gt;Service Control Policies (SCPs) &lt;a class=&quot;heading-anchor&quot; href=&quot;#service-control-policies-scps&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The key point: &lt;strong&gt;an SCP doesn&#39;t grant anything&lt;/strong&gt;. It only sets a limit, and each user still needs an IAM permission. It&#39;s a ceiling on what&#39;s allowed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attached to an OU, it applies to everything beneath it, and each level must allow the action.&lt;/li&gt;
&lt;li&gt;It doesn&#39;t affect the &lt;strong&gt;management account&lt;/strong&gt;, so don&#39;t run workloads there.&lt;/li&gt;
&lt;li&gt;It applies to everyone in a member account, including that account&#39;s root user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, this SCP blocks work outside two Regions, except for global services:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;JSON&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2012-10-17&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Statement&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Sid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;OnlyTwoRegions&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Deny&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;NotAction&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;iam:*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;organizations:*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;route53:*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cloudfront:*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;support:*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Condition&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;StringNotEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;aws:RequestedRegion&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;me-central-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eu-west-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;conditions-in-iam-policies&quot; tabindex=&quot;-1&quot;&gt;Conditions in IAM policies &lt;a class=&quot;heading-anchor&quot; href=&quot;#conditions-in-iam-policies&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A policy&#39;s &lt;strong&gt;Condition&lt;/strong&gt; element narrows when a permission applies. Some common ones:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Condition&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws:SourceIp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only from the office network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws:RequestedRegion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only in specific Regions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws:MultiFactorAuthPresent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only if signed in with MFA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws:ResourceTag&lt;/code&gt; and &lt;code&gt;aws:PrincipalTag&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A user&#39;s tag must match a resource&#39;s tag&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws:PrincipalOrgID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only from accounts in your organization&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The last one is a gift for shared buckets. Instead of listing fifty accounts in a bucket policy, one line allows your whole organization:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;JSON&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Principal&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s3:GetObject&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:s3:::shared-files/*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Condition&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;StringEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;aws:PrincipalOrgID&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;o-a1b2c3d4e5&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;a-classic-s3-mistake&quot; tabindex=&quot;-1&quot;&gt;A classic S3 mistake &lt;a class=&quot;heading-anchor&quot; href=&quot;#a-classic-s3-mistake&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;S3 actions work at two levels, and each needs its own ARN:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Applies to&lt;/th&gt;
&lt;th&gt;ARN&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s3:ListBucket&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The bucket&lt;/td&gt;
&lt;td&gt;&lt;code&gt;arn:aws:s3:::my-bucket&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s3:GetObject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The object&lt;/td&gt;
&lt;td&gt;&lt;code&gt;arn:aws:s3:::my-bucket/*&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Put the wrong one in and you get &lt;code&gt;AccessDenied&lt;/code&gt;, however right the policy looks. We&#39;ll test this in the hands-on.&lt;/p&gt;
&lt;h2 id=&quot;a-role-or-a-resource-policy&quot; tabindex=&quot;-1&quot;&gt;A role or a resource policy? &lt;a class=&quot;heading-anchor&quot; href=&quot;#a-role-or-a-resource-policy&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To let a user in account A reach something in account B, you have two ways:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Assuming a role&lt;/th&gt;
&lt;th&gt;A resource policy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;How&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The user becomes the role in B&lt;/td&gt;
&lt;td&gt;The resource in B allows the user directly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Their original permissions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;They give them up while in the role&lt;/td&gt;
&lt;td&gt;They keep them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Suits&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Working entirely inside the other account&lt;/td&gt;
&lt;td&gt;Reading from a table in A and writing to a bucket in B at once&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Available on&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All services&lt;/td&gt;
&lt;td&gt;Only those supporting it, such as S3, SNS, SQS and Lambda&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Behind every assumed role is &lt;strong&gt;AWS STS&lt;/strong&gt; (Security Token Service). It hands out the temporary credentials, which expire by themselves. This is how cross-account access works without sharing long-term keys: a user or service calls &lt;code&gt;AssumeRole&lt;/code&gt;, STS checks the role&#39;s trust policy, and returns keys that work for a limited time.&lt;/p&gt;
&lt;h2 id=&quot;permissions-boundaries&quot; tabindex=&quot;-1&quot;&gt;Permissions boundaries &lt;a class=&quot;heading-anchor&quot; href=&quot;#permissions-boundaries&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You want team leads to create roles for their services, without being able to give anyone more than they should have. A &lt;strong&gt;permissions boundary&lt;/strong&gt; sets the maximum for a particular user or role, and like an SCP, it grants nothing.&lt;/p&gt;
&lt;p&gt;The effective permissions are what&#39;s allowed by the identity policy &lt;strong&gt;and&lt;/strong&gt; the boundary &lt;strong&gt;and&lt;/strong&gt; the SCP together. It&#39;s a good way to delegate safely.&lt;/p&gt;
&lt;h3 id=&quot;how-does-aws-decide&quot; tabindex=&quot;-1&quot;&gt;How does AWS decide? &lt;a class=&quot;heading-anchor&quot; href=&quot;#how-does-aws-decide&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Every request goes through this reasoning. This is a simplified version:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 344&quot; role=&quot;img&quot; aria-labelledby=&quot;evalflow-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;evalflow-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;14&quot; width=&quot;400&quot; height=&quot;48&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;220&quot; y=&quot;43&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Is there an explicit Deny anywhere?&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;82&quot; width=&quot;400&quot; height=&quot;48&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;220&quot; y=&quot;111&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Do the SCPs and RCPs allow it?&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;150&quot; width=&quot;400&quot; height=&quot;48&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;220&quot; y=&quot;179&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Does an identity or resource policy allow it?&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;218&quot; width=&quot;400&quot; height=&quot;48&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;220&quot; y=&quot;247&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Does the permissions boundary allow it?&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;286&quot; width=&quot;400&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;220&quot; y=&quot;313&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Allowed&lt;/text&gt;
&lt;rect x=&quot;480&quot; y=&quot;14&quot; width=&quot;140&quot; height=&quot;252&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-danger)&quot;/&gt;
&lt;text x=&quot;550&quot; y=&quot;145&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Denied&lt;/text&gt;
&lt;line x1=&quot;420&quot; y1=&quot;38&quot; x2=&quot;478&quot; y2=&quot;38&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#evalflow-arrow)&quot;/&gt;
&lt;line x1=&quot;420&quot; y1=&quot;106&quot; x2=&quot;478&quot; y2=&quot;106&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#evalflow-arrow)&quot;/&gt;
&lt;line x1=&quot;420&quot; y1=&quot;174&quot; x2=&quot;478&quot; y2=&quot;174&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#evalflow-arrow)&quot;/&gt;
&lt;line x1=&quot;420&quot; y1=&quot;242&quot; x2=&quot;478&quot; y2=&quot;242&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#evalflow-arrow)&quot;/&gt;
&lt;text x=&quot;449&quot; y=&quot;30&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Yes&lt;/text&gt;
&lt;text x=&quot;449&quot; y=&quot;98&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;No&lt;/text&gt;
&lt;text x=&quot;449&quot; y=&quot;166&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;No&lt;/text&gt;
&lt;text x=&quot;449&quot; y=&quot;234&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;No&lt;/text&gt;
&lt;line x1=&quot;220&quot; y1=&quot;62&quot; x2=&quot;220&quot; y2=&quot;80&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#evalflow-arrow)&quot;/&gt;
&lt;line x1=&quot;220&quot; y1=&quot;130&quot; x2=&quot;220&quot; y2=&quot;148&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#evalflow-arrow)&quot;/&gt;
&lt;line x1=&quot;220&quot; y1=&quot;198&quot; x2=&quot;220&quot; y2=&quot;216&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#evalflow-arrow)&quot;/&gt;
&lt;line x1=&quot;220&quot; y1=&quot;266&quot; x2=&quot;220&quot; y2=&quot;284&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#evalflow-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;evalflow-caption&quot;&gt;A simplified picture of how AWS decides: any explicit Deny ends it, and every layer that applies has to allow the action.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Remember three rules: an &lt;strong&gt;explicit Deny always wins&lt;/strong&gt;, &lt;strong&gt;anything not allowed is denied&lt;/strong&gt;, and within one account, a resource policy can grant access by itself in many cases.&lt;/p&gt;
&lt;h2 id=&quot;iam-identity-center-one-sign-in&quot; tabindex=&quot;-1&quot;&gt;IAM Identity Center: one sign-in &lt;a class=&quot;heading-anchor&quot; href=&quot;#iam-identity-center-one-sign-in&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Instead of a user in every account, &lt;strong&gt;IAM Identity Center&lt;/strong&gt; gives each employee one sign-in and a portal listing the accounts and roles available to them, and they get temporary credentials with no permanent keys.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Identity source&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Its own directory, Active Directory, or an external provider such as Okta or Microsoft Entra ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Permission sets&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A set of policies that becomes a role in each account you assign it to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Assignment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;quot;The developers group gets the Admin set on the dev account, and ReadOnly on production&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Applications&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Single sign-on to SAML applications too&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For the CLI, &lt;code&gt;aws configure sso&lt;/code&gt; signs you in through your browser and gives you temporary credentials. This is the recommended way for people to work with AWS these days, in place of IAM users with long-term keys.&lt;/p&gt;
&lt;h3 id=&quot;federation-identities-from-outside&quot; tabindex=&quot;-1&quot;&gt;Federation: identities from outside &lt;a class=&quot;heading-anchor&quot; href=&quot;#federation-identities-from-outside&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Federation&lt;/strong&gt; means people or systems sign in with an identity that lives outside AWS and receive temporary credentials, with no IAM user to create. Your choice depends on who&#39;s signing in:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Who&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Employees across many accounts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Identity Center, as above, which is what AWS recommends&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;One standalone account, or systems such as GitHub Actions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An identity provider in IAM using SAML 2.0 or OIDC, with a role to assume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Your application&#39;s users&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-22-serverless-design/&quot;&gt;Cognito identity pools&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;active-directory-on-aws&quot; tabindex=&quot;-1&quot;&gt;Active Directory on AWS &lt;a class=&quot;heading-anchor&quot; href=&quot;#active-directory-on-aws&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Many companies keep their users in &lt;strong&gt;Microsoft Active Directory&lt;/strong&gt;. &lt;strong&gt;AWS Directory Service&lt;/strong&gt; connects it to AWS:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;th&gt;Suits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Managed Microsoft AD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A real AD managed in AWS, and it can trust yours&lt;/td&gt;
&lt;td&gt;AD-dependent applications running on AWS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AD Connector&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A proxy that passes requests to your AD and stores nothing&lt;/td&gt;
&lt;td&gt;Keeping the users in your own AD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Simple AD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A small Samba-based directory&lt;/td&gt;
&lt;td&gt;Closed to new customers since July 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;aws-control-tower&quot; tabindex=&quot;-1&quot;&gt;AWS Control Tower &lt;a class=&quot;heading-anchor&quot; href=&quot;#aws-control-tower&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Setting all of this up by hand takes weeks. &lt;strong&gt;Control Tower&lt;/strong&gt; builds a best-practice &lt;strong&gt;landing zone&lt;/strong&gt; over Organizations, including log and audit accounts, and it adds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Account Factory:&lt;/strong&gt; creating new accounts with ready settings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Controls:&lt;/strong&gt; preventive through SCPs, detective through &lt;a href=&quot;/en/posts/aws-25-monitoring-auditing/&quot;&gt;Config&lt;/a&gt;, and proactive that check resources before they&#39;re created.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A dashboard:&lt;/strong&gt; showing who&#39;s compliant at a glance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&#39;re starting a multi-account environment from scratch, start here.&lt;/p&gt;
&lt;h2 id=&quot;hands-on-testing-policies-without-touching-anything&quot; tabindex=&quot;-1&quot;&gt;Hands-on: testing policies without touching anything &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-testing-policies-without-touching-anything&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;policy simulator&lt;/strong&gt; evaluates a policy without creating anything or running the action, which is great for learning. From CloudShell, write a policy allowing S3 and EC2, and a boundary allowing S3 only:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; identity.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [{
    &quot;Effect&quot;: &quot;Allow&quot;,
    &quot;Action&quot;: [&quot;s3:*&quot;, &quot;ec2:*&quot;],
    &quot;Resource&quot;: &quot;*&quot;
  }]
}
EOF&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; boundary.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [{
    &quot;Effect&quot;: &quot;Allow&quot;,
    &quot;Action&quot;: &quot;s3:*&quot;,
    &quot;Resource&quot;: &quot;*&quot;
  }]
}
EOF&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Test three actions with the policy alone:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws iam simulate-custom-policy --policy-input-list file://identity.json &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --action-names s3:GetObject ec2:RunInstances iam:CreateUser &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;EvaluationResults[].[EvalActionName,EvalDecision]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; table&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;S3 and EC2 show &lt;code&gt;allowed&lt;/code&gt;, and IAM shows &lt;code&gt;implicitDeny&lt;/code&gt;, because nothing allows it. Now add the boundary:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws iam simulate-custom-policy --policy-input-list file://identity.json &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --permissions-boundary-policy-input-list file://boundary.json &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --action-names s3:GetObject ec2:RunInstances &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;EvaluationResults[].[EvalActionName,EvalDecision]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; table&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;EC2 has now become &lt;code&gt;implicitDeny&lt;/code&gt;, even though the policy allows it. Now see that &lt;strong&gt;Deny always wins&lt;/strong&gt;, by adding an explicit deny on deleting buckets:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; deny.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [{
    &quot;Effect&quot;: &quot;Deny&quot;,
    &quot;Action&quot;: &quot;s3:DeleteBucket&quot;,
    &quot;Resource&quot;: &quot;*&quot;
  }]
}
EOF&lt;/span&gt;

aws iam simulate-custom-policy &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-input-list file://identity.json file://deny.json &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --action-names s3:GetObject s3:DeleteBucket &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;EvaluationResults[].[EvalActionName,EvalDecision]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; table&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;code&gt;s3:GetObject&lt;/code&gt; stays &lt;code&gt;allowed&lt;/code&gt;, and &lt;code&gt;s3:DeleteBucket&lt;/code&gt; shows &lt;code&gt;explicitDeny&lt;/code&gt;, even though the first policy allows &lt;code&gt;s3:*&lt;/code&gt;. Try a condition next: access from the office network only, testing from two addresses:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; office.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [{
    &quot;Effect&quot;: &quot;Allow&quot;,
    &quot;Action&quot;: &quot;s3:GetObject&quot;,
    &quot;Resource&quot;: &quot;*&quot;,
    &quot;Condition&quot;: { &quot;IpAddress&quot;: { &quot;aws:SourceIp&quot;: &quot;203.0.113.0/24&quot; } }
  }]
}
EOF&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token for-or-select variable&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;203.0&lt;/span&gt;.113.10 &lt;span class=&quot;token number&quot;&gt;198.51&lt;/span&gt;.100.7&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
  aws iam simulate-custom-policy --policy-input-list file://office.json &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    --action-names s3:GetObject &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    --context-entries &lt;span class=&quot;token string&quot;&gt;&quot;ContextKeyName=aws:SourceIp,ContextKeyValues=&lt;span class=&quot;token variable&quot;&gt;$ip&lt;/span&gt;,ContextKeyType=ip&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;EvaluationResults[0].EvalDecision&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text
&lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The first address is &lt;code&gt;allowed&lt;/code&gt;, and the second is &lt;code&gt;implicitDeny&lt;/code&gt;. Finally, the classic S3 mistake, a list permission with the object&#39;s ARN:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; list.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [{
    &quot;Effect&quot;: &quot;Allow&quot;,
    &quot;Action&quot;: &quot;s3:ListBucket&quot;,
    &quot;Resource&quot;: &quot;arn:aws:s3:::shop/*&quot;
  }]
}
EOF&lt;/span&gt;

aws iam simulate-custom-policy --policy-input-list file://list.json &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --action-names s3:ListBucket --resource-arns arn:aws:s3:::shop &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;EvaluationResults[0].EvalDecision&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;It gives &lt;code&gt;implicitDeny&lt;/code&gt;. The policy looks right, but the permission applies to the bucket, not to what&#39;s in it. Change the resource to &lt;code&gt;arn:aws:s3:::shop&lt;/code&gt; and try again, and you&#39;ll get &lt;code&gt;allowed&lt;/code&gt;.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Nothing to delete&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The simulator creates nothing and costs nothing. You can test any policy this way before applying it, and the console has a visual version too, called &lt;strong&gt;IAM Policy Simulator&lt;/strong&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Organizations&lt;/strong&gt; gathers accounts under one bill, and &lt;strong&gt;SCPs&lt;/strong&gt; set a ceiling that grants nothing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conditions&lt;/strong&gt; narrow permissions by network, Region, MFA and tags, and &lt;code&gt;aws:PrincipalOrgID&lt;/code&gt; opens access to your organization only.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;role&lt;/strong&gt; gives up your original permissions, and a &lt;strong&gt;resource policy&lt;/strong&gt; keeps them.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;permissions boundary&lt;/strong&gt; delegates safely, and an &lt;strong&gt;explicit Deny always wins&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Identity Center&lt;/strong&gt; gives one sign-in with temporary credentials, and &lt;strong&gt;Control Tower&lt;/strong&gt; builds it all from best practices.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 7&lt;/p&gt;
&lt;p&gt;A company wants to make sure nobody in its development accounts can launch anything outside two Regions, not even those accounts&#39; administrators. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;An IAM policy on each user&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A permissions boundary on each role&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An SCP on the development OU&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A Config rule that reports other Regions&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An SCP sets a ceiling for every user and role in the accounts beneath it, including the root user. It grants nothing, so people still need their own IAM permissions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; An account&#39;s administrators could simply change these.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This limits one user or role at a time, and an administrator could remove it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This marks resources as non-compliant, and stops nothing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#service-control-policies-scps&quot;&gt;Service Control Policies (SCPs)&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html&quot;&gt;Service control policies (SCPs)&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 7&lt;/p&gt;
&lt;p&gt;A company wants team leads to create roles for their own services, without being able to hand out more than S3 and DynamoDB access. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A permissions boundary on the roles they create&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;An SCP on the team&#39;s account&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Administrator access, with a written rule&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Identity Center permission sets&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A permissions boundary sets the maximum for a user or role and grants nothing itself, so a role can never go beyond it, whatever policy it&#39;s given.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This limits the whole account, while other work in it may need other services.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; A written rule stops nobody.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; These give people access to accounts, and don&#39;t limit the roles they create.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#permissions-boundaries&quot;&gt;Permissions boundaries&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html&quot;&gt;Permissions boundaries for IAM entities&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 7&lt;/p&gt;
&lt;p&gt;A company with 50 accounts and 500 employees keeps its users in Microsoft Entra ID. It wants one sign-in, no long-term keys, and different access per account. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;An IAM user per employee in each account&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;One shared IAM user per team&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;AWS Control Tower, with Account Factory&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;IAM Identity Center, with permission sets&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Employees sign in once and see the accounts and roles available to them, with temporary credentials. A permission set becomes a role in each account you assign it to.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This means thousands of users and long-term keys to manage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This loses track of who did what, and shares long-term keys.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This builds a landing zone and creates accounts, and doesn&#39;t give people their sign-in by itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#iam-identity-center-one-sign-in&quot;&gt;IAM Identity Center: one sign-in&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/singlesignon/latest/userguide/permissionsetsconcept.html&quot;&gt;Manage AWS accounts with permission sets&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 7&lt;/p&gt;
&lt;p&gt;An application in account A must read from a DynamoDB table in account A and write to an S3 bucket in account B at the same time, using one identity. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Assuming a role in account B&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A bucket policy in account B that allows the application&#39;s role&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An SCP that allows the action&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A permissions boundary that allows the action&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With a resource policy the application keeps its own permissions, so it can use the table in A and the bucket in B at once.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; While in that role it gives up its original permissions, so it loses the table in A.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; An SCP grants nothing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; A boundary grants nothing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#a-role-or-a-resource-policy&quot;&gt;A role or a resource policy?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_compare-resource-policies.html&quot;&gt;Cross account resource access in IAM&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 7&lt;/p&gt;
&lt;p&gt;A role must list the objects in a bucket named &lt;code&gt;reports&lt;/code&gt; and read them. Which &lt;strong&gt;two&lt;/strong&gt; statements belong in its policy? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;&lt;code&gt;s3:ListBucket&lt;/code&gt; on &lt;code&gt;arn:aws:s3:::reports/*&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;&lt;code&gt;s3:ListBucket&lt;/code&gt; on &lt;code&gt;arn:aws:s3:::reports&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;&lt;code&gt;s3:GetObject&lt;/code&gt; on &lt;code&gt;arn:aws:s3:::reports&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;&lt;code&gt;s3:GetObject&lt;/code&gt; on &lt;code&gt;arn:aws:s3:::reports/*&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;&lt;code&gt;s3:*&lt;/code&gt; on &lt;code&gt;*&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B + D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;S3 actions work at two levels: listing applies to the bucket and reading applies to the objects, so each needs its own ARN.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Listing applies to the bucket, so this ARN gives &lt;code&gt;AccessDenied&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; Reading applies to objects, so this ARN gives &lt;code&gt;AccessDenied&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E:&lt;/strong&gt; This works, but it gives far more than needed, on every bucket.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#a-classic-s3-mistake&quot;&gt;A classic S3 mistake&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_s3_rw-bucket.html&quot;&gt;Grant read and write access to Amazon S3 bucket objects&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 6 of 7&lt;/p&gt;
&lt;p&gt;A nightly job in account A must work entirely inside account B for a few minutes. The security team forbids long-term keys. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;An IAM user in account B, with its keys stored in the job&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Copying the job&#39;s role to account B&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An SCP that allows the job&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A role in account B that trusts account A, which the job assumes through STS&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The job calls &lt;code&gt;AssumeRole&lt;/code&gt;, and STS checks the role&#39;s trust policy and returns temporary credentials, so there are no long-term keys to store.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; These are the long-term keys the team forbids.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; Roles aren&#39;t copied between accounts, and access still needs a trust policy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; An SCP grants nothing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#a-role-or-a-resource-policy&quot;&gt;A role or a resource policy?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html&quot;&gt;Temporary security credentials in IAM&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 7 of 7&lt;/p&gt;
&lt;p&gt;A GitHub Actions pipeline deploys to one AWS account, and its access keys are stored as repository secrets. The team wants to stop storing keys. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Rotating the access keys every week&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;An OIDC identity provider in IAM, with a role the pipeline assumes&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;IAM Identity Center, with a user for the pipeline&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A Cognito User Pool for the pipeline&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The pipeline proves who it is with a token from GitHub and gets temporary credentials through the role, so there are no keys to store.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This shortens the keys&#39; life, and they&#39;re still stored.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This is for people signing in, not for systems such as a pipeline.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This is for your application&#39;s users, not for access to your AWS account.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#federation-identities-from-outside&quot;&gt;Federation: identities from outside&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers.html&quot;&gt;Identity providers and federation into AWS&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;You&#39;ve controlled who reaches your data. What if someone reaches it anyway, or attacks your site from outside? In &lt;a href=&quot;/en/posts/aws-27-encryption-secrets-protection/&quot;&gt;&lt;strong&gt;part twenty-seven&lt;/strong&gt;&lt;/a&gt; we cover encryption, secrets and threat protection.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Monitoring and Auditing: CloudWatch, CloudTrail and Config</title>
    <link href="https://blog.sultanops.com/en/posts/aws-25-monitoring-auditing/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-25-monitoring-auditing/</id>
    <summary>How do you know your application is healthy, who changed what, and whether your settings are still as they should be? Metrics, logs and alarms in CloudWatch, EventBridge, CloudTrail and Config, with a hands-on alarm that emails you.</summary>
    <content type="html">&lt;p&gt;Over the previous parts we built an application with many pieces. Building it is the easy half. The hard half comes at three in the morning: is it down? Since when? And who changed that setting yesterday?&lt;/p&gt;
&lt;p&gt;This last section is about running what you&#39;ve built, and it starts with three questions, each with its own service:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;The question&lt;/th&gt;
&lt;th&gt;The service&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Is it healthy right now?&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CloudWatch&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who did this, and when?&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CloudTrail&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Are the settings as they should be, and how have they changed?&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Config&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;And a fourth service reacts to all of them: &lt;strong&gt;EventBridge&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;cloudwatch-metrics&quot; tabindex=&quot;-1&quot;&gt;CloudWatch metrics &lt;a class=&quot;heading-anchor&quot; href=&quot;#cloudwatch-metrics&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;metric&lt;/strong&gt; is a number measured over time, such as CPU usage or the count of errors. Most AWS services send their metrics by themselves, grouped in &lt;strong&gt;namespaces&lt;/strong&gt; and distinguished by &lt;strong&gt;dimensions&lt;/strong&gt;, such as the server ID.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Point&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EC2 default&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Every 5 minutes, or every minute if you turn on detailed monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Custom metrics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You send what you like, such as the number of failed orders, down to one-second resolution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;History&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One-minute data stays for 15 days, 5-minute data for 63 days, and hourly data for 455 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Metric Streams&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sends metrics continuously through Firehose to S3 or another monitoring tool&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;aside class=&quot;callout callout-warning&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-alert&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 4l9 16H3L12 4z&quot;/&gt;&lt;path d=&quot;M12 10v4M12 17h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;EC2 doesn&#39;t report memory&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The default metrics come from outside the server, so they don&#39;t include &lt;strong&gt;memory&lt;/strong&gt; or &lt;strong&gt;disk space&lt;/strong&gt;. To get them, install the &lt;strong&gt;CloudWatch agent&lt;/strong&gt; on the server. Many people find this out while trying to work out why their server slowed down.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;&lt;strong&gt;Dashboards&lt;/strong&gt; put the charts you care about on one page, and they can gather metrics across Regions and accounts.&lt;/p&gt;
&lt;h2 id=&quot;cloudwatch-logs&quot; tabindex=&quot;-1&quot;&gt;CloudWatch Logs &lt;a class=&quot;heading-anchor&quot; href=&quot;#cloudwatch-logs&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Everything your application prints can land here, organized into &lt;strong&gt;log groups&lt;/strong&gt; that usually represent one application, and within them &lt;strong&gt;log streams&lt;/strong&gt;. Lambda, ECS, API Gateway, &lt;a href=&quot;/en/posts/aws-13-vpc/&quot;&gt;VPC Flow Logs&lt;/a&gt; and others send logs directly, and on EC2 or on-premises servers you use the same agent.&lt;/p&gt;
&lt;p&gt;Logs are kept &lt;strong&gt;forever by default&lt;/strong&gt;, and you pay for that. Set a retention period on each group, from one day to ten years.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Logs Insights&lt;/strong&gt; searches through them with a simple query language. This one gets the latest errors:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Output&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
| limit 20&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;To send logs elsewhere you have two routes:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;Timing&lt;/th&gt;
&lt;th&gt;Suits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Export to S3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A batch job, and not immediate&lt;/td&gt;
&lt;td&gt;Cheap long-term archiving&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Subscription filter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Near real time&lt;/td&gt;
&lt;td&gt;Sending to Lambda, Kinesis or Firehose, such as for &lt;a href=&quot;/en/posts/aws-23-athena-redshift-glue/&quot;&gt;OpenSearch&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;cloudwatch-alarms&quot; tabindex=&quot;-1&quot;&gt;CloudWatch alarms &lt;a class=&quot;heading-anchor&quot; href=&quot;#cloudwatch-alarms&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A chart nobody&#39;s looking at is no use. An &lt;strong&gt;alarm&lt;/strong&gt; watches a metric and does something when it crosses a limit.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 170&quot; role=&quot;img&quot; aria-labelledby=&quot;alarm-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;alarm-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;54&quot; width=&quot;140&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;90&quot; y=&quot;80&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Metric&lt;/text&gt;
&lt;text x=&quot;90&quot; y=&quot;100&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;CPU, errors&lt;/text&gt;
&lt;rect x=&quot;230&quot; y=&quot;54&quot; width=&quot;140&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;300&quot; y=&quot;80&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Alarm&lt;/text&gt;
&lt;text x=&quot;300&quot; y=&quot;100&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Above 80%?&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;12&quot; width=&quot;150&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;39&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;SNS&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;63&quot; width=&quot;150&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;90&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Auto Scaling&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;114&quot; width=&quot;150&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;141&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;EC2 action&lt;/text&gt;
&lt;line x1=&quot;160&quot; y1=&quot;85&quot; x2=&quot;228&quot; y2=&quot;85&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#alarm-arrow)&quot;/&gt;
&lt;line x1=&quot;370&quot; y1=&quot;85&quot; x2=&quot;468&quot; y2=&quot;34&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#alarm-arrow)&quot;/&gt;
&lt;line x1=&quot;370&quot; y1=&quot;85&quot; x2=&quot;468&quot; y2=&quot;85&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#alarm-arrow)&quot;/&gt;
&lt;line x1=&quot;370&quot; y1=&quot;85&quot; x2=&quot;468&quot; y2=&quot;136&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#alarm-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;alarm-caption&quot;&gt;An alarm watches a metric, and when it crosses the limit, it notifies someone, adds capacity or acts on the server.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;An alarm is in one of three states: &lt;code&gt;OK&lt;/code&gt;, &lt;code&gt;ALARM&lt;/code&gt; or &lt;code&gt;INSUFFICIENT_DATA&lt;/code&gt;. Some useful additions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;EC2 actions:&lt;/strong&gt; stop, reboot, terminate or &lt;strong&gt;recover&lt;/strong&gt;. Recovery moves the server to new hardware if the underlying host fails, keeping its IP addresses and settings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Composite alarms:&lt;/strong&gt; one alarm for &amp;quot;high CPU &lt;strong&gt;and&lt;/strong&gt; many errors&amp;quot;, which reduces false alerts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testing:&lt;/strong&gt; &lt;code&gt;set-alarm-state&lt;/code&gt; puts an alarm in any state, so you can check the alert path without breaking anything. We&#39;ll try it in the hands-on.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ready-made-insights&quot; tabindex=&quot;-1&quot;&gt;Ready-made insights &lt;a class=&quot;heading-anchor&quot; href=&quot;#ready-made-insights&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it shows&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Container Insights&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Metrics and logs from ECS and EKS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lambda Insights&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Function performance, including memory and cold starts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Contributor Insights&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Top contributors, such as the IP addresses sending the most requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Application Insights&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sets up monitoring for a whole application and points out likely problems&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;eventbridge-reacting-to-events&quot; tabindex=&quot;-1&quot;&gt;EventBridge: reacting to events &lt;a class=&quot;heading-anchor&quot; href=&quot;#eventbridge-reacting-to-events&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Almost everything that happens in AWS is an &lt;strong&gt;event&lt;/strong&gt;: a server changed state, a bucket was created, or an alarm went off. &lt;strong&gt;EventBridge&lt;/strong&gt; receives these events on a &lt;strong&gt;bus&lt;/strong&gt;, and &lt;strong&gt;rules&lt;/strong&gt; send matching ones to a target.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 214&quot; role=&quot;img&quot; aria-labelledby=&quot;eventbridge-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;eventbridge-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;14&quot; width=&quot;140&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;90&quot; y=&quot;44&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;AWS services&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;80&quot; width=&quot;140&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;90&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Your apps&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;146&quot; width=&quot;140&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;90&quot; y=&quot;176&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;A schedule&lt;/text&gt;
&lt;rect x=&quot;230&quot; y=&quot;46&quot; width=&quot;170&quot; height=&quot;118&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;315&quot; y=&quot;100&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Event bus&lt;/text&gt;
&lt;text x=&quot;315&quot; y=&quot;120&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Rules filter events&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;14&quot; width=&quot;150&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;44&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Lambda&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;80&quot; width=&quot;150&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;SQS&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;146&quot; width=&quot;150&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;176&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Step Functions&lt;/text&gt;
&lt;line x1=&quot;160&quot; y1=&quot;39&quot; x2=&quot;228&quot; y2=&quot;80&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#eventbridge-arrow)&quot;/&gt;
&lt;line x1=&quot;160&quot; y1=&quot;105&quot; x2=&quot;228&quot; y2=&quot;105&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#eventbridge-arrow)&quot;/&gt;
&lt;line x1=&quot;160&quot; y1=&quot;171&quot; x2=&quot;228&quot; y2=&quot;130&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#eventbridge-arrow)&quot;/&gt;
&lt;line x1=&quot;400&quot; y1=&quot;80&quot; x2=&quot;468&quot; y2=&quot;39&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#eventbridge-arrow)&quot;/&gt;
&lt;line x1=&quot;400&quot; y1=&quot;105&quot; x2=&quot;468&quot; y2=&quot;105&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#eventbridge-arrow)&quot;/&gt;
&lt;line x1=&quot;400&quot; y1=&quot;130&quot; x2=&quot;468&quot; y2=&quot;171&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#eventbridge-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;eventbridge-caption&quot;&gt;Events arrive on a bus from anywhere, and rules send each one that matches to the service that handles it.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reacting to a change&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A server stopped, so notify the team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A schedule&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Run a function every night; &lt;strong&gt;EventBridge Scheduler&lt;/strong&gt; is the service for this now&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Connecting your services&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The orders service publishes an event, and whoever&#39;s interested takes it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Partner events&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Events arriving from SaaS applications on a partner bus&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Features worth knowing: &lt;strong&gt;archive and replay&lt;/strong&gt; to send old events again, the &lt;strong&gt;schema registry&lt;/strong&gt; that describes the shape of events, and &lt;strong&gt;resource policies&lt;/strong&gt; so that another account can send to your bus.&lt;/p&gt;
&lt;p&gt;For most targets, such as Lambda, SQS and SNS, access is granted by a resource policy on the target. For others, such as starting an ECS task, EventBridge uses an IAM role.&lt;/p&gt;
&lt;h2 id=&quot;cloudtrail-who-did-what&quot; tabindex=&quot;-1&quot;&gt;CloudTrail: who did what &lt;a class=&quot;heading-anchor&quot; href=&quot;#cloudtrail-who-did-what&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every call to AWS, from the console, the CLI or a service, gets recorded by &lt;strong&gt;CloudTrail&lt;/strong&gt;: who, what, when, and from where. It&#39;s on by default, and it&#39;s the first place to look when something changes mysteriously or disappears.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event type&lt;/th&gt;
&lt;th&gt;What it covers&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Management events&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Changes to resources, such as creating a server or changing a policy&lt;/td&gt;
&lt;td&gt;On, with 90 days free in Event history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data events&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Operations inside resources, such as reading from S3 or invoking Lambda&lt;/td&gt;
&lt;td&gt;Off, because of their volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Insights events&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Unusual activity, such as a sudden burst of delete calls&lt;/td&gt;
&lt;td&gt;Off, at additional cost&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;To keep them longer than 90 days, create a &lt;strong&gt;trail&lt;/strong&gt; that writes to S3, across all Regions and even the whole organization, and analyze it with &lt;a href=&quot;/en/posts/aws-23-athena-redshift-glue/&quot;&gt;Athena&lt;/a&gt;. Note that &lt;strong&gt;CloudTrail Lake&lt;/strong&gt; closed to new customers in 2026, so a trail is the way to go.&lt;/p&gt;
&lt;p&gt;A powerful pattern combines it with EventBridge: anyone deleting a table, or a sign-in with the root user, immediately triggers an alert. CloudTrail records it, EventBridge matches it, and SNS tells you.&lt;/p&gt;
&lt;h2 id=&quot;aws-config-your-settings-over-time&quot; tabindex=&quot;-1&quot;&gt;AWS Config: your settings over time &lt;a class=&quot;heading-anchor&quot; href=&quot;#aws-config-your-settings-over-time&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CloudTrail tells you who called what. &lt;strong&gt;Config&lt;/strong&gt; tells you what a resource looks like: it records the configuration of your resources and every change to it, so you can ask what a security group looked like last Tuesday.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Config rules&lt;/strong&gt; then judge these settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rules:&lt;/strong&gt; managed ones ready to use, such as &amp;quot;no public S3 buckets&amp;quot;, or custom ones.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prevention:&lt;/strong&gt; it doesn&#39;t stop anything. It marks a resource as non-compliant, and that&#39;s it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remediation:&lt;/strong&gt; a rule can run a Systems Manager Automation document to fix the problem automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notifications:&lt;/strong&gt; through EventBridge or SNS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scope and cost:&lt;/strong&gt; it works per Region, and you pay per recorded item and per rule evaluation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;x-ray-following-one-request&quot; tabindex=&quot;-1&quot;&gt;X-Ray: following one request &lt;a class=&quot;heading-anchor&quot; href=&quot;#x-ray-following-one-request&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A request in a modern application can pass through an API, three functions and a database. Metrics tell you something is slow, and &lt;strong&gt;AWS X-Ray&lt;/strong&gt; tells you where. It collects &lt;strong&gt;traces&lt;/strong&gt; of each request as it passes through your services, including its calls to databases and other APIs, and shows you which step is slow or failing.&lt;/p&gt;
&lt;h2 id=&quot;other-views&quot; tabindex=&quot;-1&quot;&gt;Other views &lt;a class=&quot;heading-anchor&quot; href=&quot;#other-views&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it shows&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Health Dashboard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Whether AWS itself has a problem affecting your services and resources, with no setup and at no cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Managed Grafana&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dashboards for metrics, logs and traces from several sources, using the popular Grafana tool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Managed Service for Prometheus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Container metrics through the open-source Prometheus tools, with no servers to run&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;which-one-when&quot; tabindex=&quot;-1&quot;&gt;Which one, when? &lt;a class=&quot;heading-anchor&quot; href=&quot;#which-one-when&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s take one load balancer:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CloudWatch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Number of requests, 5xx errors, and a dashboard or an alarm on them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CloudTrail&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Who changed its listener rules, and when&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Config&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Its current security group, its certificate, and how they&#39;ve changed; and is it following your rules?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;hands-on-an-alarm-that-emails-you&quot; tabindex=&quot;-1&quot;&gt;Hands-on: an alarm that emails you &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-an-alarm-that-emails-you&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll watch a made-up metric for failed orders. From CloudShell, replace the email address with yours:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;EMAIL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;you@example.com

&lt;span class=&quot;token assign-left variable&quot;&gt;TOPIC_ARN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws sns create-topic &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; series-alerts &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; TopicArn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws sns subscribe --topic-arn &lt;span class=&quot;token variable&quot;&gt;$TOPIC_ARN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--protocol&lt;/span&gt; email --notification-endpoint &lt;span class=&quot;token variable&quot;&gt;$EMAIL&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Open your email and press &lt;strong&gt;Confirm subscription&lt;/strong&gt;. Then create an alarm that goes off if more than five orders fail in a minute:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws cloudwatch put-metric-alarm --alarm-name series-failed-orders &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--namespace&lt;/span&gt; Series/Shop --metric-name FailedOrders &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--statistic&lt;/span&gt; Sum &lt;span class=&quot;token parameter variable&quot;&gt;--period&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; --evaluation-periods &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--threshold&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; --comparison-operator GreaterThanThreshold &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --treat-missing-data notBreaching &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --alarm-actions &lt;span class=&quot;token variable&quot;&gt;$TOPIC_ARN&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Now send the application&#39;s reading, as if 12 orders had just failed:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws cloudwatch put-metric-data &lt;span class=&quot;token parameter variable&quot;&gt;--namespace&lt;/span&gt; Series/Shop &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --metric-name FailedOrders &lt;span class=&quot;token parameter variable&quot;&gt;--value&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Wait two or three minutes and check the alarm&#39;s state. An email should arrive at the same time:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws cloudwatch describe-alarms --alarm-names series-failed-orders &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MetricAlarms[0].[StateValue,StateReason]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;You don&#39;t have to break anything to test an alert path. Try it when the alarm has gone back to &lt;code&gt;OK&lt;/code&gt;, and another email arrives:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws cloudwatch set-alarm-state --alarm-name series-failed-orders &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --state-value ALARM --state-reason &lt;span class=&quot;token string&quot;&gt;&quot;Testing the alert&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Finally, play detective. Who created this alarm? CloudTrail knows, though events can take a few minutes to appear:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws cloudtrail lookup-events &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --lookup-attributes &lt;span class=&quot;token assign-left variable&quot;&gt;AttributeKey&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;EventName,AttributeValue&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;PutMetricAlarm &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --max-results &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Events[0].[EventName,Username,EventTime]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This stays within the free tier or costs next to nothing. The custom metric expires by itself:&lt;/p&gt;
&lt;/aside&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws cloudwatch delete-alarms --alarm-names series-failed-orders
aws sns delete-topic --topic-arn &lt;span class=&quot;token variable&quot;&gt;$TOPIC_ARN&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CloudWatch&lt;/strong&gt; for metrics, logs and alarms, and memory needs the agent.&lt;/li&gt;
&lt;li&gt;Set a &lt;strong&gt;retention period&lt;/strong&gt; on your logs, because they&#39;re kept forever by default.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EventBridge&lt;/strong&gt; routes events to whoever handles them, and runs things on a schedule.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CloudTrail&lt;/strong&gt; records who did what, and &lt;strong&gt;Config&lt;/strong&gt; records the settings and judges them.&lt;/li&gt;
&lt;li&gt;Test your &lt;strong&gt;alert path&lt;/strong&gt; before you need it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 7&lt;/p&gt;
&lt;p&gt;A team wants an alarm when memory on its EC2 servers passes 90%, but it can&#39;t find a memory metric in CloudWatch. What should it do?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Turn on detailed monitoring&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Install the CloudWatch agent on the servers&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Create a CloudTrail trail&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Turn on AWS Config&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The default metrics come from outside the server, so they don&#39;t include memory. The agent sends it from inside, and then you can put an alarm on it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This sends the same metrics more often, and memory still isn&#39;t among them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This records who called what, not how a server is performing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This records resource settings, not what&#39;s happening inside a server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#cloudwatch-metrics&quot;&gt;CloudWatch metrics&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/metrics-collected-by-CloudWatch-agent.html&quot;&gt;Metrics collected by the CloudWatch agent&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 7&lt;/p&gt;
&lt;p&gt;An outage began right after someone changed a security group last night. The team wants to know who made the change, and from where. Where should it look first?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;CloudWatch metrics&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;VPC Flow Logs&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;CloudWatch Logs Insights&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;CloudTrail Event history&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CloudTrail records who called what, when and from where. Management events like this one stay there for 90 days, with nothing to set up.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; These show numbers over time, not who did anything.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; These show the traffic that was accepted or rejected, not who changed a rule.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This searches logs your applications send, not the calls made to AWS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#cloudtrail-who-did-what&quot;&gt;CloudTrail: who did what&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/awscloudtrail/latest/userguide/view-cloudtrail-events.html&quot;&gt;Working with CloudTrail event history&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 7&lt;/p&gt;
&lt;p&gt;A company wants to notice when any S3 bucket becomes public, and to fix it automatically. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A Config rule, with automatic remediation&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A CloudWatch alarm on the bucket&#39;s size&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;CloudTrail Insights events&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A Logs Insights query&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A Config rule judges each bucket&#39;s settings and marks it as non-compliant, and a remediation can run a Systems Manager Automation document to fix it. On its own, a rule prevents nothing.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; Size says nothing about who can reach the bucket.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This spots unusual activity, and doesn&#39;t judge or fix settings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This searches logs when you ask, and fixes nothing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#aws-config-your-settings-over-time&quot;&gt;AWS Config: your settings over time&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/remediation.html&quot;&gt;Remediating Noncompliant Resources with AWS Config&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 7&lt;/p&gt;
&lt;p&gt;The security team wants an immediate alert whenever someone deletes a DynamoDB table or signs in with the root user. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A weekly Athena query over the CloudTrail logs&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A CloudWatch dashboard&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An EventBridge rule matching those CloudTrail events, with an SNS target&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A Config rule on each table&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CloudTrail records the call, EventBridge matches it, and SNS tells you right away.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This finds them eventually, which could be days too late.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; A dashboard nobody&#39;s looking at alerts nobody.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This judges settings, and doesn&#39;t react to a deleted table or a sign-in.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#cloudtrail-who-did-what&quot;&gt;CloudTrail: who did what&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-service-event-cloudtrail.html&quot;&gt;AWS service events delivered via AWS CloudTrail&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 7&lt;/p&gt;
&lt;p&gt;A team&#39;s CloudWatch Logs bill keeps growing because old logs are never removed, and another system must receive error lines within seconds. Which &lt;strong&gt;two&lt;/strong&gt; changes fit? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Set a retention period on the log groups&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Export the logs to S3 every night&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Turn on detailed monitoring&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Add a subscription filter that sends error lines to Lambda&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Turn on CloudTrail data events&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A + D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Logs are kept forever by default, so a retention period removes the old ones. A subscription filter delivers matching lines in near real time.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This is a batch job that isn&#39;t immediate, and the originals stay and keep costing money.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This sends EC2 metrics more often, and has nothing to do with logs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E:&lt;/strong&gt; This records operations inside resources, and has nothing to do with your log bill or error lines.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#cloudwatch-logs&quot;&gt;CloudWatch Logs&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Working-with-log-groups-and-streams.html&quot;&gt;Working with log groups and log streams&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Subscriptions.html&quot;&gt;Real-time processing of log data with subscriptions&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 6 of 7&lt;/p&gt;
&lt;p&gt;A checkout request passes through API Gateway, three Lambda functions and a DynamoDB table, and sometimes takes five seconds. Each service&#39;s metrics look normal on their own. What shows which step is slow?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;CloudTrail&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;AWS Config&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;AWS X-Ray&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;CloudWatch Contributor Insights&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;X-Ray follows each request across your services and their calls, and shows which step is slow or failing.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This records who called which API, not how long each step of a request took.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This records resource settings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This shows top contributors, such as the addresses sending the most requests, not a request&#39;s path.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#x-ray-following-one-request&quot;&gt;X-Ray: following one request&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html&quot;&gt;What is AWS X-Ray?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 7 of 7&lt;/p&gt;
&lt;p&gt;Errors suddenly rise on an application in one Region, with nothing changed on the team&#39;s side. They want to know quickly whether AWS itself has a problem affecting their resources. Where should they look?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;CloudTrail Event history&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;AWS Health Dashboard&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;AWS Config&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Trusted Advisor&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It shows the events affecting AWS services and your resources, with no setup and at no cost.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This shows the calls made in your account, and those didn&#39;t change here.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This shows how your settings changed, and those didn&#39;t change here.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This checks your account against best practices, and doesn&#39;t report outages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#other-views&quot;&gt;Other views&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/health/latest/ug/what-is-aws-health.html&quot;&gt;What is AWS Health?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;You now know what&#39;s happening in one account. But companies have dozens of accounts and hundreds of employees. In &lt;a href=&quot;/en/posts/aws-26-organizations-identity-center/&quot;&gt;&lt;strong&gt;part twenty-six&lt;/strong&gt;&lt;/a&gt; we manage them with Organizations and Identity Center.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Ready-Made AI Services</title>
    <link href="https://blog.sultanops.com/en/posts/aws-24-ai-services/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-24-ai-services/</id>
    <summary>Add AI to your application without a machine learning team. Services for images, speech, translation and documents, generative models on Bedrock, building your own with SageMaker AI, which ones support Arabic, and a hands-on chaining several of them.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-23-athena-redshift-glue/&quot;&gt;part twenty-three&lt;/a&gt; we got answers from data that&#39;s already organized. But a lot of your data isn&#39;t: photos, voice calls and scanned invoices. Understanding them used to need a machine learning team. Today, much of it is one API call.&lt;/p&gt;
&lt;p&gt;AWS offers three levels, and most people should start from the top:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 212&quot; role=&quot;img&quot; aria-labelledby=&quot;ailayers-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;ailayers-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;text x=&quot;45&quot; y=&quot;18&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Easier&lt;/text&gt;
&lt;line x1=&quot;45&quot; y1=&quot;28&quot; x2=&quot;45&quot; y2=&quot;176&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#ailayers-arrow)&quot;/&gt;
&lt;text x=&quot;45&quot; y=&quot;196&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;More control&lt;/text&gt;
&lt;rect x=&quot;100&quot; y=&quot;14&quot; width=&quot;520&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;360&quot; y=&quot;37&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Ready-made services&lt;/text&gt;
&lt;text x=&quot;360&quot; y=&quot;57&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Rekognition, Polly, Textract and others: one API call&lt;/text&gt;
&lt;rect x=&quot;100&quot; y=&quot;78&quot; width=&quot;520&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;360&quot; y=&quot;101&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Amazon Bedrock&lt;/text&gt;
&lt;text x=&quot;360&quot; y=&quot;121&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Ready models you guide with prompts and your data&lt;/text&gt;
&lt;rect x=&quot;100&quot; y=&quot;142&quot; width=&quot;520&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;360&quot; y=&quot;165&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Amazon SageMaker AI&lt;/text&gt;
&lt;text x=&quot;360&quot; y=&quot;185&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Train and run your own models&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;ailayers-caption&quot;&gt;The further down you go, the more control you get over the model, and the more expertise and work it takes.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You want&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Understanding images and video&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Rekognition&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speech to text&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Transcribe&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text to speech&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Polly&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Translation&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Translate&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A chatbot or a phone system&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Lex&lt;/strong&gt; and &lt;strong&gt;Connect&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Understanding text: sentiment and entities&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Comprehend&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extracting text and tables from documents&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Textract&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recommendations&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Personalize&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generative models over your data&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Bedrock&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Training a model of your own&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;SageMaker AI&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;images-rekognition&quot; tabindex=&quot;-1&quot;&gt;Images: Rekognition &lt;a class=&quot;heading-anchor&quot; href=&quot;#images-rekognition&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Rekognition&lt;/strong&gt; analyzes images and video without any training on your part:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Labels:&lt;/strong&gt; what&#39;s in the image, such as a car, a beach or a crowd.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text:&lt;/strong&gt; reading words in images, such as signs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content moderation:&lt;/strong&gt; catching inappropriate images before they&#39;re published, and you can train it further on your own examples.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faces:&lt;/strong&gt; detecting, comparing and searching for them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that the &lt;strong&gt;Streaming Video&lt;/strong&gt; and &lt;strong&gt;Batch Image Content Moderation&lt;/strong&gt; features closed to new customers on April 30, 2026. Other features aren&#39;t affected, and you can process frames or batches yourself through the image API.&lt;/p&gt;
&lt;aside class=&quot;callout callout-warning&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-alert&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 4l9 16H3L12 4z&quot;/&gt;&lt;path d=&quot;M12 10v4M12 17h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Be careful with faces&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Identifying people has legal and ethical consequences that vary by country. Get consent, and check the regulations that apply to you before using it.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;speech-transcribe-and-polly&quot; tabindex=&quot;-1&quot;&gt;Speech: Transcribe and Polly &lt;a class=&quot;heading-anchor&quot; href=&quot;#speech-transcribe-and-polly&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Transcribe&lt;/strong&gt; turns speech into text, from a file in S3 or a live stream. It can tell speakers apart, add your own vocabulary such as product names, and hide personal data on supported languages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Polly&lt;/strong&gt; does the opposite, turning text into speech. You can control pronunciation in two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lexicons:&lt;/strong&gt; teach it to read &lt;code&gt;AWS&lt;/code&gt; as &amp;quot;Amazon Web Services&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSML:&lt;/strong&gt; tags in the text that add pauses, emphasis or even a whisper.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;translate&quot; tabindex=&quot;-1&quot;&gt;Translate &lt;a class=&quot;heading-anchor&quot; href=&quot;#translate&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Amazon Translate&lt;/strong&gt; translates between 75 languages, in real time or in batches from S3. Add &lt;strong&gt;custom terminology&lt;/strong&gt; to keep your brand names and terms as they are. Pairing it with Polly and Transcribe gets you a whole translated conversation.&lt;/p&gt;
&lt;h2 id=&quot;conversation-lex-and-connect&quot; tabindex=&quot;-1&quot;&gt;Conversation: Lex and Connect &lt;a class=&quot;heading-anchor&quot; href=&quot;#conversation-lex-and-connect&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Lex&lt;/strong&gt; builds chatbots and voice bots. You define what the user may want, an &lt;strong&gt;intent&lt;/strong&gt;, and the details you need to carry it out, called &lt;strong&gt;slots&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Connect&lt;/strong&gt; is a contact center in the cloud: phone numbers, queues, flows and agents, with no equipment, and you pay by usage. Together they might work like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A customer calls the number on &lt;strong&gt;Connect&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;They say &amp;quot;I want to change my appointment&amp;quot;, and &lt;strong&gt;Lex&lt;/strong&gt; understands the intent and asks for the date.&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;/en/posts/aws-21-lambda-api-dynamodb/&quot;&gt;Lambda&lt;/a&gt; function updates the appointment in your system.&lt;/li&gt;
&lt;li&gt;If the bot gets stuck, Connect transfers the call to an agent.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;text-comprehend&quot; tabindex=&quot;-1&quot;&gt;Text: Comprehend &lt;a class=&quot;heading-anchor&quot; href=&quot;#text-comprehend&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Comprehend&lt;/strong&gt; reads text and extracts its meaning: language, &lt;strong&gt;sentiment&lt;/strong&gt;, entities such as people and places, key phrases and personal data. And you can train it to classify your own categories, such as the type of support ticket.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Comprehend Medical&lt;/strong&gt; does this for clinical text: conditions, medications, doses and tests, and it detects protected health information.&lt;/p&gt;
&lt;p&gt;Its &lt;strong&gt;Topic Modeling&lt;/strong&gt;, &lt;strong&gt;Event Detection&lt;/strong&gt; and &lt;strong&gt;Prompt Safety Classification&lt;/strong&gt; features closed to new customers on April 30, 2026.&lt;/p&gt;
&lt;h2 id=&quot;documents-textract&quot; tabindex=&quot;-1&quot;&gt;Documents: Textract &lt;a class=&quot;heading-anchor&quot; href=&quot;#documents-textract&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Textract&lt;/strong&gt; goes beyond reading text from a scanned file: it understands structure, so it returns &lt;strong&gt;forms&lt;/strong&gt; as field-and-value pairs, and &lt;strong&gt;tables&lt;/strong&gt; as rows and columns. It also has dedicated paths for invoices, receipts and identity documents.&lt;/p&gt;
&lt;h2 id=&quot;recommendations-personalize&quot; tabindex=&quot;-1&quot;&gt;Recommendations: Personalize &lt;a class=&quot;heading-anchor&quot; href=&quot;#recommendations-personalize&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Personalize&lt;/strong&gt; builds &amp;quot;you might also like&amp;quot; from your users&#39; behavior: you give it who viewed or bought what, and you get an API that returns recommendations in real time, or in batches for email campaigns. You don&#39;t need to design a model yourself.&lt;/p&gt;
&lt;h2 id=&quot;search-over-your-documents-what-about-kendra&quot; tabindex=&quot;-1&quot;&gt;Search over your documents: what about Kendra? &lt;a class=&quot;heading-anchor&quot; href=&quot;#search-over-your-documents-what-about-kendra&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You may read about &lt;strong&gt;Amazon Kendra&lt;/strong&gt;, an intelligent search service for internal documents. It stopped accepting new customers on July 30, 2026, and AWS points to &lt;strong&gt;Bedrock Knowledge Bases&lt;/strong&gt; as the alternative, which brings us to the next section.&lt;/p&gt;
&lt;h2 id=&quot;generative-models-amazon-bedrock&quot; tabindex=&quot;-1&quot;&gt;Generative models: Amazon Bedrock &lt;a class=&quot;heading-anchor&quot; href=&quot;#generative-models-amazon-bedrock&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Bedrock&lt;/strong&gt; gives you foundation models from many providers, such as Anthropic, Amazon, Meta and Mistral, through one API, with no servers. You pay per token, meaning by the amount of text going in and out. The &lt;strong&gt;Converse&lt;/strong&gt; API has a single form across models, so changing a model is a matter of changing one parameter.&lt;/p&gt;
&lt;p&gt;You no longer need to enable models one at a time, since access is now controlled with IAM. The exception is Anthropic&#39;s models, which need a one-time form before first use.&lt;/p&gt;
&lt;h3 id=&quot;knowledge-bases-answers-from-your-documents&quot; tabindex=&quot;-1&quot;&gt;Knowledge Bases: answers from your documents &lt;a class=&quot;heading-anchor&quot; href=&quot;#knowledge-bases-answers-from-your-documents&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A model doesn&#39;t know your company&#39;s policies. Instead of training it, you find the relevant passages and hand them to it with the question. This is called &lt;strong&gt;RAG&lt;/strong&gt;, and &lt;strong&gt;Knowledge Bases&lt;/strong&gt; handles it for you:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 204&quot; role=&quot;img&quot; aria-labelledby=&quot;rag-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;rag-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;14&quot; width=&quot;126&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;83&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Question&lt;/text&gt;
&lt;rect x=&quot;178&quot; y=&quot;14&quot; width=&quot;126&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;241&quot; y=&quot;44&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Knowledge Base&lt;/text&gt;
&lt;text x=&quot;241&quot; y=&quot;64&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Finds passages&lt;/text&gt;
&lt;rect x=&quot;336&quot; y=&quot;14&quot; width=&quot;126&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;399&quot; y=&quot;44&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Model&lt;/text&gt;
&lt;text x=&quot;399&quot; y=&quot;64&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Answers from them&lt;/text&gt;
&lt;rect x=&quot;494&quot; y=&quot;14&quot; width=&quot;126&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;557&quot; y=&quot;44&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Answer&lt;/text&gt;
&lt;text x=&quot;557&quot; y=&quot;64&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;With its sources&lt;/text&gt;
&lt;line x1=&quot;146&quot; y1=&quot;49&quot; x2=&quot;176&quot; y2=&quot;49&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#rag-arrow)&quot;/&gt;
&lt;line x1=&quot;304&quot; y1=&quot;49&quot; x2=&quot;334&quot; y2=&quot;49&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#rag-arrow)&quot;/&gt;
&lt;line x1=&quot;462&quot; y1=&quot;49&quot; x2=&quot;492&quot; y2=&quot;49&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#rag-arrow)&quot;/&gt;
&lt;rect x=&quot;178&quot; y=&quot;124&quot; width=&quot;126&quot; height=&quot;66&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;241&quot; y=&quot;152&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Your documents&lt;/text&gt;
&lt;text x=&quot;241&quot; y=&quot;172&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;In S3 and others&lt;/text&gt;
&lt;line x1=&quot;241&quot; y1=&quot;124&quot; x2=&quot;241&quot; y2=&quot;86&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#rag-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;rag-caption&quot;&gt;The Knowledge Base finds the passages closest to the question in your documents, and the model answers from them instead of from its memory.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;the-rest-of-the-toolbox&quot; tabindex=&quot;-1&quot;&gt;The rest of the toolbox &lt;a class=&quot;heading-anchor&quot; href=&quot;#the-rest-of-the-toolbox&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Guardrails&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Blocks unwanted topics, hides personal data and helps reduce made-up answers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AgentCore&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Runs and manages agents that take actions, with any framework and model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Batch and caching&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lower the cost of large workloads and repeated prompts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Bedrock Agents Classic&lt;/strong&gt; closed to new customers in favor of AgentCore, so don&#39;t start with it if you see it in an older article.&lt;/p&gt;
&lt;h2 id=&quot;your-own-model-sagemaker-ai&quot; tabindex=&quot;-1&quot;&gt;Your own model: SageMaker AI &lt;a class=&quot;heading-anchor&quot; href=&quot;#your-own-model-sagemaker-ai&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When ready-made isn&#39;t enough, such as predicting risks from data only you have, &lt;strong&gt;Amazon SageMaker AI&lt;/strong&gt; (formerly SageMaker) covers the journey: notebooks, data preparation, training, then an endpoint serving predictions. &lt;strong&gt;JumpStart&lt;/strong&gt; gives you hundreds of ready models to start from.&lt;/p&gt;
&lt;p&gt;Don&#39;t confuse it with the new &lt;strong&gt;Amazon SageMaker&lt;/strong&gt;, an umbrella that gathers data, analytics and AI in one studio. Also, several of its add-ons, such as Ground Truth, Clarify and Model Monitor, closed to new customers in mid-2026, so check a feature&#39;s status before relying on it.&lt;/p&gt;
&lt;h3 id=&quot;bedrock-or-sagemaker-ai&quot; tabindex=&quot;-1&quot;&gt;Bedrock or SageMaker AI? &lt;a class=&quot;heading-anchor&quot; href=&quot;#bedrock-or-sagemaker-ai&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Bedrock&lt;/th&gt;
&lt;th&gt;SageMaker AI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Starts from&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A ready model&lt;/td&gt;
&lt;td&gt;Your data, or a model you customize&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Serverless&lt;/td&gt;
&lt;td&gt;You choose the compute, or use serverless customization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;You pay&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Per token&lt;/td&gt;
&lt;td&gt;Mostly for compute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Expertise&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A developer is enough&lt;/td&gt;
&lt;td&gt;Machine learning helps a lot&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;AWS&#39;s own advice: start with Bedrock using prompts and Knowledge Bases, and move to SageMaker AI when you need to change the model&#39;s behavior.&lt;/p&gt;
&lt;h2 id=&quot;and-arabic&quot; tabindex=&quot;-1&quot;&gt;And Arabic? &lt;a class=&quot;heading-anchor&quot; href=&quot;#and-arabic&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If your application serves Arabic speakers, check this first, because not all services are equal:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Arabic support&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Translate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Comprehend&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes, including sentiment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transcribe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gulf (&lt;code&gt;ar-AE&lt;/code&gt;) and Modern Standard (&lt;code&gt;ar-SA&lt;/code&gt;), though hiding personal data isn&#39;t supported for them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Polly&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zeina in Modern Standard, and Hala and Zayd in Gulf&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Textract&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No: English, French, German, Italian, Portuguese and Spanish only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bedrock&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Depends on the model, so try yours on your own text&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;chaining-services&quot; tabindex=&quot;-1&quot;&gt;Chaining services &lt;a class=&quot;heading-anchor&quot; href=&quot;#chaining-services&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The real strength lies in connecting them with what you&#39;ve already learned. Imagine call recordings landing in S3, where each step triggers the next through &lt;a href=&quot;/en/posts/aws-22-serverless-design/&quot;&gt;events or Step Functions&lt;/a&gt;:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 118&quot; role=&quot;img&quot; aria-labelledby=&quot;chain-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;chain-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;28&quot; width=&quot;126&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;83&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Call recording&lt;/text&gt;
&lt;text x=&quot;83&quot; y=&quot;74&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;In S3&lt;/text&gt;
&lt;rect x=&quot;178&quot; y=&quot;28&quot; width=&quot;126&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;241&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Transcribe&lt;/text&gt;
&lt;text x=&quot;241&quot; y=&quot;74&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;To text&lt;/text&gt;
&lt;rect x=&quot;336&quot; y=&quot;28&quot; width=&quot;126&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;399&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Comprehend&lt;/text&gt;
&lt;text x=&quot;399&quot; y=&quot;74&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Sentiment&lt;/text&gt;
&lt;rect x=&quot;494&quot; y=&quot;28&quot; width=&quot;126&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;557&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Bedrock&lt;/text&gt;
&lt;text x=&quot;557&quot; y=&quot;74&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;A summary&lt;/text&gt;
&lt;line x1=&quot;146&quot; y1=&quot;59&quot; x2=&quot;176&quot; y2=&quot;59&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#chain-arrow)&quot;/&gt;
&lt;line x1=&quot;304&quot; y1=&quot;59&quot; x2=&quot;334&quot; y2=&quot;59&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#chain-arrow)&quot;/&gt;
&lt;line x1=&quot;462&quot; y1=&quot;59&quot; x2=&quot;492&quot; y2=&quot;59&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#chain-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;chain-caption&quot;&gt;Each service does one job and hands its result to the next, without any model to train.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Without any machine learning, a manager now reads a summary of every call and sees which ones ended badly.&lt;/p&gt;
&lt;h2 id=&quot;hands-on-a-review-passes-through-four-services&quot; tabindex=&quot;-1&quot;&gt;Hands-on: a review passes through four services &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-a-review-passes-through-four-services&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll take a customer review, analyze it, translate it, voice it and reply to it. Everything is a direct call with nothing to set up. These services aren&#39;t in every Region, so if a command reports that it can&#39;t connect, add &lt;code&gt;--region us-east-1&lt;/code&gt; to it. From CloudShell:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;REVIEW&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;The app is great, but delivery was very slow and support never replied.&quot;&lt;/span&gt;

aws comprehend detect-dominant-language &lt;span class=&quot;token parameter variable&quot;&gt;--text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$REVIEW&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Languages[0]&quot;&lt;/span&gt;

aws comprehend detect-sentiment --language-code en &lt;span class=&quot;token parameter variable&quot;&gt;--text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$REVIEW&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[Sentiment,SentimentScore]&quot;&lt;/span&gt;

aws comprehend detect-key-phrases --language-code en &lt;span class=&quot;token parameter variable&quot;&gt;--text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$REVIEW&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;KeyPhrases[].Text&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;You&#39;ll see the language, the sentiment with its scores, and the key phrases. Now translate it to Arabic, then check that Comprehend understands the translation too:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;ARABIC&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws translate translate-text &lt;span class=&quot;token parameter variable&quot;&gt;--text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$REVIEW&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --source-language-code en --target-language-code ar &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; TranslatedText &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$ARABIC&lt;/span&gt;&quot;&lt;/span&gt;

aws comprehend detect-sentiment --language-code ar &lt;span class=&quot;token parameter variable&quot;&gt;--text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$ARABIC&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Sentiment &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Voice the translation with Polly:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws polly synthesize-speech --voice-id Zeina --output-format mp3 &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$ARABIC&lt;/span&gt;&quot;&lt;/span&gt; review.mp3

&lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-lh&lt;/span&gt; review.mp3&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;To listen, from the CloudShell &lt;strong&gt;Actions&lt;/strong&gt; menu choose &lt;strong&gt;Download file&lt;/strong&gt;, and enter &lt;code&gt;review.mp3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, ask a model on Bedrock to reply to the customer. The first command looks up the identifier of a low-cost Amazon Nova Lite model in your Region. If it prints &lt;code&gt;None&lt;/code&gt;, add &lt;code&gt;--region us-east-1&lt;/code&gt; to both commands:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;MODEL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws bedrock list-inference-profiles &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;inferenceProfileSummaries[?contains(inferenceProfileId,&#39;nova&#39;) &amp;amp;&amp;amp; contains(inferenceProfileId,&#39;lite&#39;)].inferenceProfileId | [0]&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$MODEL&lt;/span&gt;

aws bedrock-runtime converse --model-id &lt;span class=&quot;token variable&quot;&gt;$MODEL&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--messages&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[{&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;role&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;:&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;user&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;,&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;content&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;:[{&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;text&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;:&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Reply to this customer in two short sentences: &lt;span class=&quot;token variable&quot;&gt;$REVIEW&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;}]}]&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;output.message.content[0].text&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Got a photo? Upload it from &lt;strong&gt;Actions&lt;/strong&gt;, then &lt;strong&gt;Upload file&lt;/strong&gt;, and ask Rekognition what&#39;s in it:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws rekognition detect-labels --image-bytes fileb://photo.jpg &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --max-labels &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Labels[].[Name,Confidence]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; table&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Nothing to delete&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;These calls create no resources, and they cost a small fraction of a cent. But note that your text goes to these services, so review the data rules for each one before sending your customers&#39; real data.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Start from the &lt;strong&gt;ready-made services&lt;/strong&gt;, then &lt;strong&gt;Bedrock&lt;/strong&gt;, and only then &lt;strong&gt;SageMaker AI&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rekognition&lt;/strong&gt; for images, &lt;strong&gt;Transcribe&lt;/strong&gt; and &lt;strong&gt;Polly&lt;/strong&gt; for speech, &lt;strong&gt;Translate&lt;/strong&gt; for translation, and &lt;strong&gt;Comprehend&lt;/strong&gt; for text.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Textract&lt;/strong&gt; reads structured documents, but it doesn&#39;t support Arabic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Knowledge Bases&lt;/strong&gt; answers from your documents without training a model, and it&#39;s the alternative to Kendra.&lt;/li&gt;
&lt;li&gt;Connecting these services with events is where the real value is.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 5&lt;/p&gt;
&lt;p&gt;An insurer receives thousands of scanned claim forms in English. It wants each form&#39;s fields, values and tables in its database, with no model to train. Which service fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Amazon Rekognition&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Amazon Textract&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Amazon Comprehend&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Amazon Transcribe&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Textract understands a document&#39;s structure, so it returns forms as field-and-value pairs, and tables as rows and columns.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This can read words in an image, but it doesn&#39;t understand forms and tables.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This extracts meaning from text you already have, and doesn&#39;t read scanned files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This turns speech into text.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#documents-textract&quot;&gt;Documents: Textract&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/textract/latest/dg/what-is.html&quot;&gt;What is Amazon Textract?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 5&lt;/p&gt;
&lt;p&gt;A company new to AWS wants an assistant that answers employees&#39; questions from its internal policy documents. It has no machine learning team. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Amazon Kendra&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A model trained on the documents in SageMaker AI&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Amazon Lex on its own&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Amazon Bedrock Knowledge Bases&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Knowledge Bases finds the relevant passages and hands them to a model along with the question, so there&#39;s nothing to train.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This no longer accepts new customers, and AWS points to Knowledge Bases instead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This needs machine learning expertise, and answering from documents doesn&#39;t need a trained model.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This builds bots around intents you define, and doesn&#39;t answer from documents by itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#knowledge-bases-answers-from-your-documents&quot;&gt;Knowledge Bases: answers from your documents&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base.html&quot;&gt;Retrieve data and generate AI responses with Amazon Bedrock Knowledge Bases&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 5&lt;/p&gt;
&lt;p&gt;A bank&#39;s data scientists want to predict loan risk from years of its own repayment records, and no ready-made service does this. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Amazon SageMaker AI&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Amazon Bedrock, using prompts&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Amazon Personalize&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Amazon Comprehend&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is predicting from data only the bank has, which needs a model of its own. SageMaker AI covers preparing the data, training, then serving predictions from an endpoint.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This starts from a ready model, and doesn&#39;t train a prediction model on the bank&#39;s records.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This builds recommendations from user behavior, such as &amp;quot;you might also like&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This extracts meaning from text, such as sentiment and entities.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#your-own-model-sagemaker-ai&quot;&gt;Your own model: SageMaker AI&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/decision-guides/latest/bedrock-or-sagemaker/bedrock-or-sagemaker.html&quot;&gt;Amazon Bedrock or Amazon SageMaker AI?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 5&lt;/p&gt;
&lt;p&gt;A call center stores its recordings in S3, in English. A manager wants to know which calls ended badly, without any machine learning work. Which chain fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Polly, then Comprehend&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Rekognition, then Translate&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Transcribe, then Comprehend&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Textract, then Personalize&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Transcribe turns each recording into text, and Comprehend&#39;s sentiment analysis shows which calls were negative.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Polly does the opposite of what&#39;s needed, turning text into speech.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; Rekognition analyzes images and video, and Translate only changes the language.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Textract reads documents, and Personalize builds recommendations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#chaining-services&quot;&gt;Chaining services&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/transcribe/latest/dg/what-is.html&quot;&gt;What is Amazon Transcribe?&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/comprehend/latest/dg/how-sentiment.html&quot;&gt;Sentiment&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 5&lt;/p&gt;
&lt;p&gt;A Saudi online store wants to detect the sentiment of its Arabic reviews directly, and translate them into English for its head office. Which &lt;strong&gt;two&lt;/strong&gt; services fit? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Amazon Textract&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Amazon Polly&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Amazon Comprehend&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Amazon Rekognition&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Amazon Translate&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Comprehend supports Arabic, including sentiment, and Translate handles the translation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This reads documents, and it doesn&#39;t support Arabic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This voices text, and doesn&#39;t analyze or translate it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This analyzes images and video.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#and-arabic&quot;&gt;And Arabic?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/comprehend/latest/dg/supported-languages.html&quot;&gt;Languages supported in Amazon Comprehend&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/translate/latest/dg/what-is-languages.html&quot;&gt;Supported languages and language codes&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;This completes the data and AI section. Your application is big now, and it has a lot running in it. How do you know it&#39;s healthy, and who changed what? In &lt;a href=&quot;/en/posts/aws-25-monitoring-auditing/&quot;&gt;&lt;strong&gt;part twenty-five&lt;/strong&gt;&lt;/a&gt; we start the final section, with monitoring and auditing through CloudWatch, CloudTrail and Config.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Analyzing Data: Athena, Redshift and Glue</title>
    <link href="https://blog.sultanops.com/en/posts/aws-23-athena-redshift-glue/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-23-athena-redshift-glue/</id>
    <summary>Getting answers from your data. Querying S3 with SQL in Athena, a data warehouse with Redshift, preparing data with Glue, plus search, big jobs, dashboards and streams, with a hands-on where Parquet cuts what a query reads.</summary>
    <content type="html">&lt;p&gt;The application we finished designing in &lt;a href=&quot;/en/posts/aws-22-serverless-design/&quot;&gt;part twenty-two&lt;/a&gt; produces a lot of data: orders, logs and events. Then someone asks: &amp;quot;Which city grew the most this year?&amp;quot;&lt;/p&gt;
&lt;p&gt;You could run that on your production database and slow it down for your customers. Instead, AWS has a set of services built for analysis, and this part is a guide to them.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You want&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SQL on files in S3, with no servers&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Athena&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A data warehouse for heavy, frequent reports&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Redshift&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A catalog of your data, and cleaning and converting it&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Glue&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permissions over a whole data lake&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Lake Formation&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text search and log analysis&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OpenSearch&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Big Spark or Hadoop jobs&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;EMR&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dashboards for your team&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Quick Sight&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Analyzing a stream as it arrives&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Managed Flink&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Managed Apache Kafka&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;MSK&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;two-kinds-of-work&quot; tabindex=&quot;-1&quot;&gt;Two kinds of work &lt;a class=&quot;heading-anchor&quot; href=&quot;#two-kinds-of-work&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The questions an application asks are different from the questions a business asks:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Running the application (OLTP)&lt;/th&gt;
&lt;th&gt;Analysis (OLAP)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fetch order 1001&lt;/td&gt;
&lt;td&gt;Total sales per city over three years&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rows touched&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A few&lt;/td&gt;
&lt;td&gt;Millions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Who asks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Millions of customers&lt;/td&gt;
&lt;td&gt;A few analysts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Services&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-08-rds-aurora/&quot;&gt;RDS&lt;/a&gt; and &lt;a href=&quot;/en/posts/aws-21-lambda-api-dynamodb/&quot;&gt;DynamoDB&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Athena and Redshift&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The secret of analytics services is storing data &lt;strong&gt;by column&lt;/strong&gt;. To add up one column, there&#39;s no need to read the rest:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 196&quot; role=&quot;img&quot; aria-labelledby=&quot;warehouse-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;warehouse-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;text x=&quot;165&quot; y=&quot;22&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;By row: reads everything&lt;/text&gt;
&lt;text x=&quot;75&quot; y=&quot;48&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;id&lt;/text&gt;
&lt;rect x=&quot;30&quot; y=&quot;58&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;rect x=&quot;30&quot; y=&quot;92&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;rect x=&quot;30&quot; y=&quot;126&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;165&quot; y=&quot;48&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;city&lt;/text&gt;
&lt;rect x=&quot;120&quot; y=&quot;58&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;rect x=&quot;120&quot; y=&quot;92&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;rect x=&quot;120&quot; y=&quot;126&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;255&quot; y=&quot;48&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;amount&lt;/text&gt;
&lt;rect x=&quot;210&quot; y=&quot;58&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;rect x=&quot;210&quot; y=&quot;92&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;rect x=&quot;210&quot; y=&quot;126&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;475&quot; y=&quot;22&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;By column: reads one column&lt;/text&gt;
&lt;text x=&quot;385&quot; y=&quot;48&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;id&lt;/text&gt;
&lt;rect x=&quot;340&quot; y=&quot;58&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;rect x=&quot;340&quot; y=&quot;92&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;rect x=&quot;340&quot; y=&quot;126&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;475&quot; y=&quot;48&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;city&lt;/text&gt;
&lt;rect x=&quot;430&quot; y=&quot;58&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;rect x=&quot;430&quot; y=&quot;92&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;rect x=&quot;430&quot; y=&quot;126&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;565&quot; y=&quot;48&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;amount&lt;/text&gt;
&lt;rect x=&quot;520&quot; y=&quot;58&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;rect x=&quot;520&quot; y=&quot;92&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;rect x=&quot;520&quot; y=&quot;126&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;182&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;The query: SUM(amount)&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;warehouse-caption&quot;&gt;To add up the amount column, row storage goes through every field, while column storage reads that column alone.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;amazon-athena-sql-on-s3&quot; tabindex=&quot;-1&quot;&gt;Amazon Athena: SQL on S3 &lt;a class=&quot;heading-anchor&quot; href=&quot;#amazon-athena-sql-on-s3&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Athena&lt;/strong&gt; lets you query files in S3 directly with SQL. There&#39;s nothing to run: you describe the files as a table, and the data stays where it is.&lt;/p&gt;
&lt;p&gt;You pay about &lt;strong&gt;$5 per TB of data scanned&lt;/strong&gt;, with a 10 MB minimum per query. Creating tables and failed queries cost nothing. It suits occasional questions and analyzing logs, such as those from a load balancer or &lt;a href=&quot;/en/posts/aws-17-s3-security/&quot;&gt;S3&lt;/a&gt;, and it&#39;s also where AWS points you now that &lt;strong&gt;S3 Select&lt;/strong&gt; is closed to new customers.&lt;/p&gt;
&lt;h3 id=&quot;read-less-pay-less&quot; tabindex=&quot;-1&quot;&gt;Read less, pay less &lt;a class=&quot;heading-anchor&quot; href=&quot;#read-less-pay-less&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Since the price depends on what&#39;s read, reading less means both a lower bill and a faster answer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Columnar formats:&lt;/strong&gt; convert files to &lt;strong&gt;Parquet&lt;/strong&gt; or ORC, so a query reads only its columns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partitions:&lt;/strong&gt; split the data into paths such as &lt;code&gt;year=2025/&lt;/code&gt;, so a query skips the rest.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compression:&lt;/strong&gt; the smaller the data, the less gets scanned.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Larger files:&lt;/strong&gt; thousands of tiny files slow things down, so merge them.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 188&quot; role=&quot;img&quot; aria-labelledby=&quot;partition-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;partition-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;52&quot; width=&quot;230&quot; height=&quot;84&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;135&quot; y=&quot;89&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Athena&lt;/text&gt;
&lt;text x=&quot;135&quot; y=&quot;109&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;WHERE year = 2025&lt;/text&gt;
&lt;rect x=&quot;370&quot; y=&quot;14&quot; width=&quot;250&quot; height=&quot;48&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-dasharray=&quot;5 5&quot;/&gt;
&lt;text x=&quot;495&quot; y=&quot;33&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;year=2024/&lt;/text&gt;
&lt;text x=&quot;495&quot; y=&quot;53&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Skipped&lt;/text&gt;
&lt;rect x=&quot;370&quot; y=&quot;70&quot; width=&quot;250&quot; height=&quot;48&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;495&quot; y=&quot;89&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;year=2025/&lt;/text&gt;
&lt;text x=&quot;495&quot; y=&quot;109&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Read&lt;/text&gt;
&lt;rect x=&quot;370&quot; y=&quot;126&quot; width=&quot;250&quot; height=&quot;48&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-dasharray=&quot;5 5&quot;/&gt;
&lt;text x=&quot;495&quot; y=&quot;145&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;year=2026/&lt;/text&gt;
&lt;text x=&quot;495&quot; y=&quot;165&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Skipped&lt;/text&gt;
&lt;line x1=&quot;250&quot; y1=&quot;94&quot; x2=&quot;368&quot; y2=&quot;94&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#partition-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;partition-caption&quot;&gt;With the data split by year, a query about 2025 reads one folder and skips the others, so you pay only for what it read.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;federated-queries&quot; tabindex=&quot;-1&quot;&gt;Federated queries &lt;a class=&quot;heading-anchor&quot; href=&quot;#federated-queries&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Your data isn&#39;t all in S3? &lt;strong&gt;Federated Query&lt;/strong&gt; lets Athena reach other sources, such as DynamoDB or RDS, through a connector that runs as a Lambda function in your account. One query can even join them with your files.&lt;/p&gt;
&lt;h2 id=&quot;amazon-redshift-the-warehouse&quot; tabindex=&quot;-1&quot;&gt;Amazon Redshift: the warehouse &lt;a class=&quot;heading-anchor&quot; href=&quot;#amazon-redshift-the-warehouse&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When reports become heavy and frequent, with many joins and many users, you need a &lt;strong&gt;data warehouse&lt;/strong&gt;. &lt;strong&gt;Redshift&lt;/strong&gt; is based on PostgreSQL, stores data by column, and splits a query across many nodes in parallel.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Serverless&lt;/th&gt;
&lt;th&gt;Provisioned&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;You choose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nothing; capacity adjusts itself&lt;/td&gt;
&lt;td&gt;The type and number of nodes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;You pay for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compute time when queries run&lt;/td&gt;
&lt;td&gt;Each node per hour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Suits&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Changing or intermittent load&lt;/td&gt;
&lt;td&gt;Steady load, or needing Multi-AZ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;getting-data-in&quot; tabindex=&quot;-1&quot;&gt;Getting data in &lt;a class=&quot;heading-anchor&quot; href=&quot;#getting-data-in&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;COPY&lt;/code&gt; from S3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The usual way: loads in bulk and in parallel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Firehose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A &lt;a href=&quot;/en/posts/aws-19-sqs-sns-kinesis/&quot;&gt;stream&lt;/a&gt; that lands in S3, then gets loaded with &lt;code&gt;COPY&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Zero-ETL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatically replicating from sources like Aurora, RDS and DynamoDB, with no pipeline to build&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;INSERT&lt;/code&gt; row by row&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Avoid it for large amounts; it&#39;s very slow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;things-worth-knowing&quot; tabindex=&quot;-1&quot;&gt;Things worth knowing &lt;a class=&quot;heading-anchor&quot; href=&quot;#things-worth-knowing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Redshift Spectrum:&lt;/strong&gt; query files in S3 from Redshift without loading them, and join them with your tables.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Snapshots:&lt;/strong&gt; automatic and incremental, and you can copy them to another Region to recover from a disaster.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-AZ:&lt;/strong&gt; available on provisioned RA3 clusters, with nodes in two Availability Zones behind one endpoint.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;athena-or-redshift&quot; tabindex=&quot;-1&quot;&gt;Athena or Redshift? &lt;a class=&quot;heading-anchor&quot; href=&quot;#athena-or-redshift&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Athena&lt;/th&gt;
&lt;th&gt;Redshift&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;The data is in&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;S3&lt;/td&gt;
&lt;td&gt;The warehouse, plus S3 with Spectrum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Setup&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Little, with Serverless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;You pay for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data scanned&lt;/td&gt;
&lt;td&gt;Compute time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Suits&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Occasional questions and logs&lt;/td&gt;
&lt;td&gt;Heavy, repeated reports and dashboards&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Start with Athena, and move to Redshift when your queries become frequent enough for it to pay off.&lt;/p&gt;
&lt;h2 id=&quot;aws-glue-preparing-the-data&quot; tabindex=&quot;-1&quot;&gt;AWS Glue: preparing the data &lt;a class=&quot;heading-anchor&quot; href=&quot;#aws-glue-preparing-the-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Analysis assumes the data is clean and organized, which is rarely the case. &lt;strong&gt;Glue&lt;/strong&gt; is a serverless set of tools for that:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Catalog&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A central list of your tables and their columns, used by Athena, Redshift Spectrum and EMR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Crawlers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Scan S3 and work out the columns, then add them to the catalog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ETL jobs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Spark code that extracts, transforms and loads data, such as CSV to Parquet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Job bookmarks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Remember what&#39;s been processed, so a job doesn&#39;t repeat old files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DataBrew&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cleans data visually, with no code&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A common pattern: a file lands in S3, an event starts a Glue job, and it converts the file to Parquet in another folder. Note that &lt;strong&gt;Glue Ray jobs&lt;/strong&gt; closed to new customers on April 30, 2026, while Spark jobs carry on as usual.&lt;/p&gt;
&lt;p&gt;You may also read about &lt;strong&gt;AWS Data Pipeline&lt;/strong&gt;, an older service for moving and processing data on a schedule. It&#39;s closed to new customers and in maintenance mode, so use Glue or Step Functions for new work.&lt;/p&gt;
&lt;h2 id=&quot;lake-formation-permissions-for-the-lake&quot; tabindex=&quot;-1&quot;&gt;Lake Formation: permissions for the lake &lt;a class=&quot;heading-anchor&quot; href=&quot;#lake-formation-permissions-for-the-lake&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;S3 with Parquet files and a catalog is what&#39;s called a &lt;strong&gt;data lake&lt;/strong&gt;. As it grows, managing access through &lt;a href=&quot;/en/posts/aws-15-s3-basics/&quot;&gt;bucket policies&lt;/a&gt; gets hard, because S3 knows about files, not columns.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lake Formation&lt;/strong&gt; gives you one place to grant access by database, table, column and even row: the sales team sees orders without card numbers, for example. These permissions apply through services like Athena, Redshift and EMR.&lt;/p&gt;
&lt;h2 id=&quot;search-big-jobs-and-dashboards&quot; tabindex=&quot;-1&quot;&gt;Search, big jobs and dashboards &lt;a class=&quot;heading-anchor&quot; href=&quot;#search-big-jobs-and-dashboards&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;opensearch&quot; tabindex=&quot;-1&quot;&gt;OpenSearch &lt;a class=&quot;heading-anchor&quot; href=&quot;#opensearch&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A database is good at finding by key. &lt;strong&gt;OpenSearch&lt;/strong&gt; is good at finding by any word in any field, and at analyzing logs. It comes as &lt;strong&gt;managed clusters&lt;/strong&gt; where you control the sizes, or as &lt;strong&gt;Serverless&lt;/strong&gt; for changing load.&lt;/p&gt;
&lt;p&gt;It&#39;s usually a copy of your data, not the source. Two common patterns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Search over a table:&lt;/strong&gt; DynamoDB Streams, then Lambda, then OpenSearch. You search there, then fetch the full item from the table.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Log analysis:&lt;/strong&gt; CloudWatch Logs, then Firehose, then OpenSearch.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;amazon-emr&quot; tabindex=&quot;-1&quot;&gt;Amazon EMR &lt;a class=&quot;heading-anchor&quot; href=&quot;#amazon-emr&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Do you have existing &lt;strong&gt;Spark&lt;/strong&gt; or &lt;strong&gt;Hadoop&lt;/strong&gt; jobs? &lt;strong&gt;EMR&lt;/strong&gt; runs them, and you can choose to run it on EC2, on EKS or as Serverless. On EC2 there are three kinds of nodes:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Node&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Purchase option&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Coordinates the cluster&lt;/td&gt;
&lt;td&gt;On-Demand or Reserved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Runs tasks and stores data&lt;/td&gt;
&lt;td&gt;On-Demand or Reserved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Task&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Runs tasks only, and is optional&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-04-ec2-pricing-networking/&quot;&gt;Spot&lt;/a&gt; is ideal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;quick-sight&quot; tabindex=&quot;-1&quot;&gt;Quick Sight &lt;a class=&quot;heading-anchor&quot; href=&quot;#quick-sight&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Amazon Quick Sight&lt;/strong&gt; builds dashboards from Athena, Redshift, RDS, S3 and others. Its name was QuickSight, and since October 2025 it has been part of a broader suite called Amazon Quick, though the API still uses the old name.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SPICE:&lt;/strong&gt; an in-memory engine that makes dashboards fast, without burdening the source on every view.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An analysis or a dashboard:&lt;/strong&gt; you edit in an analysis, and publish it as a read-only dashboard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Row-level security:&lt;/strong&gt; each manager sees only their own region&#39;s data.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;streams-flink-and-kafka&quot; tabindex=&quot;-1&quot;&gt;Streams: Flink and Kafka &lt;a class=&quot;heading-anchor&quot; href=&quot;#streams-flink-and-kafka&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/en/posts/aws-19-sqs-sns-kinesis/&quot;&gt;Kinesis and Firehose&lt;/a&gt; deliver the data. What if you want to analyze it as it arrives, such as spotting a suspicious pattern within seconds?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Managed Service for Apache Flink&lt;/strong&gt; (formerly Kinesis Data Analytics) runs Flink applications that read from a Kinesis stream or from MSK, without you managing the cluster.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Amazon MSK&lt;/strong&gt; is a managed &lt;strong&gt;Apache Kafka&lt;/strong&gt;, the most popular streaming platform in the open-source world. It comes as provisioned clusters with Standard or Express brokers, or as Serverless.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Kinesis Data Streams&lt;/th&gt;
&lt;th&gt;Amazon MSK&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Split into&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shards&lt;/td&gt;
&lt;td&gt;Topics and partitions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;APIs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS&#39;s own&lt;/td&gt;
&lt;td&gt;Standard Kafka&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Record size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1 MiB by default, up to 10 MiB&lt;/td&gt;
&lt;td&gt;1 MB by default, and configurable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Choose it if&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You want the simplest option on AWS&lt;/td&gt;
&lt;td&gt;You have Kafka applications and tools&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;how-does-the-data-arrive&quot; tabindex=&quot;-1&quot;&gt;How does the data arrive? &lt;a class=&quot;heading-anchor&quot; href=&quot;#how-does-the-data-arrive&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Choosing a way in starts with how often the data arrives, and how large it is:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;The data&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Files from a server or NAS, on a schedule&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-18-storage-transfer/&quot;&gt;DataSync&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Files from partners over SFTP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-18-storage-transfer/&quot;&gt;Transfer Family&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Small records, continuously, with several readers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-19-sqs-sns-kinesis/&quot;&gt;Kinesis Data Streams&lt;/a&gt; or MSK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Small records, continuously, landing in storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;/en/posts/aws-19-sqs-sns-kinesis/&quot;&gt;Data Firehose&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rows changing in a database&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zero-ETL or &lt;a href=&quot;/en/posts/aws-28-disaster-recovery-migration/&quot;&gt;DMS&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data sets from other companies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Data Exchange&lt;/strong&gt;, where you subscribe to them&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Secure each way in the same manner: least-privilege IAM roles, encryption in transit and at rest, and private paths such as &lt;a href=&quot;/en/posts/aws-14-vpc-connectivity/&quot;&gt;VPC endpoints&lt;/a&gt; instead of the public internet where you can.&lt;/p&gt;
&lt;h2 id=&quot;the-complete-picture&quot; tabindex=&quot;-1&quot;&gt;The complete picture &lt;a class=&quot;heading-anchor&quot; href=&quot;#the-complete-picture&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here&#39;s how the pieces meet in a typical pipeline:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 208&quot; role=&quot;img&quot; aria-labelledby=&quot;pipeline-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;pipeline-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;14&quot; width=&quot;126&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;83&quot; y=&quot;44&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Sources&lt;/text&gt;
&lt;text x=&quot;83&quot; y=&quot;64&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Apps and logs&lt;/text&gt;
&lt;rect x=&quot;178&quot; y=&quot;14&quot; width=&quot;126&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;241&quot; y=&quot;44&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Firehose&lt;/text&gt;
&lt;text x=&quot;241&quot; y=&quot;64&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Collects&lt;/text&gt;
&lt;rect x=&quot;336&quot; y=&quot;14&quot; width=&quot;126&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;399&quot; y=&quot;44&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;S3&lt;/text&gt;
&lt;text x=&quot;399&quot; y=&quot;64&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Raw data&lt;/text&gt;
&lt;rect x=&quot;494&quot; y=&quot;14&quot; width=&quot;126&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;557&quot; y=&quot;44&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Glue&lt;/text&gt;
&lt;text x=&quot;557&quot; y=&quot;64&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Cleans, converts&lt;/text&gt;
&lt;rect x=&quot;494&quot; y=&quot;124&quot; width=&quot;126&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;557&quot; y=&quot;154&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;S3&lt;/text&gt;
&lt;text x=&quot;557&quot; y=&quot;174&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Parquet&lt;/text&gt;
&lt;rect x=&quot;336&quot; y=&quot;124&quot; width=&quot;126&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;399&quot; y=&quot;154&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Athena&lt;/text&gt;
&lt;text x=&quot;399&quot; y=&quot;174&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Answers with SQL&lt;/text&gt;
&lt;rect x=&quot;178&quot; y=&quot;124&quot; width=&quot;126&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;241&quot; y=&quot;154&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Quick Sight&lt;/text&gt;
&lt;text x=&quot;241&quot; y=&quot;174&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Dashboards&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;124&quot; width=&quot;126&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;83&quot; y=&quot;154&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Your team&lt;/text&gt;
&lt;text x=&quot;83&quot; y=&quot;174&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Decides&lt;/text&gt;
&lt;line x1=&quot;146&quot; y1=&quot;49&quot; x2=&quot;176&quot; y2=&quot;49&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#pipeline-arrow)&quot;/&gt;
&lt;line x1=&quot;304&quot; y1=&quot;49&quot; x2=&quot;334&quot; y2=&quot;49&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#pipeline-arrow)&quot;/&gt;
&lt;line x1=&quot;462&quot; y1=&quot;49&quot; x2=&quot;492&quot; y2=&quot;49&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#pipeline-arrow)&quot;/&gt;
&lt;line x1=&quot;557&quot; y1=&quot;84&quot; x2=&quot;557&quot; y2=&quot;122&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#pipeline-arrow)&quot;/&gt;
&lt;line x1=&quot;494&quot; y1=&quot;159&quot; x2=&quot;464&quot; y2=&quot;159&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#pipeline-arrow)&quot;/&gt;
&lt;line x1=&quot;336&quot; y1=&quot;159&quot; x2=&quot;306&quot; y2=&quot;159&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#pipeline-arrow)&quot;/&gt;
&lt;line x1=&quot;178&quot; y1=&quot;159&quot; x2=&quot;148&quot; y2=&quot;159&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#pipeline-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;pipeline-caption&quot;&gt;Data lands raw in S3, Glue converts it to Parquet, Athena answers from it and Quick Sight displays the result. Redshift can take Athena&#39;s place for heavy reports.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;hands-on-parquet-cuts-what-a-query-reads&quot; tabindex=&quot;-1&quot;&gt;Hands-on: Parquet cuts what a query reads &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-parquet-cuts-what-a-query-reads&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll generate a file of 200,000 orders and put the same question to it twice. From CloudShell:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;BUCKET&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;series-data-&lt;span class=&quot;token environment constant&quot;&gt;$RANDOM&lt;/span&gt;&lt;span class=&quot;token environment constant&quot;&gt;$RANDOM&lt;/span&gt;
aws s3 mb s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;BEGIN {
  srand(7)
  split(&quot;Riyadh Jeddah Dammam Abha Tabuk&quot;, city, &quot; &quot;)
  for (i = 1; i &amp;lt;= 200000; i++)
    printf &quot;%d,%s,%d,%.2f&#92;n&quot;, i, city[int(rand()*5)+1], 2024+int(rand()*3), rand()*500
}&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; sales.csv

&lt;span class=&quot;token function&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-3&lt;/span&gt; sales.csv
aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; sales.csv s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/raw/sales.csv&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;This function runs a query, waits for it, then prints its state, the bytes it scanned and its result:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function-name function&quot;&gt;run_sql&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token assign-left variable&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws athena start-query-execution --query-string &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    --result-configuration &lt;span class=&quot;token assign-left variable&quot;&gt;OutputLocation&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;s3://$BUCKET/results/ &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; QueryExecutionId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;token assign-left variable&quot;&gt;STATE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws athena get-query-execution --query-execution-id $ID &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
      &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; QueryExecution.Status.State &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$STATE&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; QUEUED &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$STATE&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RUNNING &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;break&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;
  aws athena get-query-execution --query-execution-id &lt;span class=&quot;token variable&quot;&gt;$ID&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;QueryExecution.[Status.State,Statistics.DataScannedInBytes]&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text
  aws athena get-query-results --query-execution-id &lt;span class=&quot;token variable&quot;&gt;$ID&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ResultSet.Rows[*].Data[*].VarCharValue&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Describe the file as a table. Nothing moves, and the data stays in S3:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;run_sql &lt;span class=&quot;token string&quot;&gt;&quot;CREATE DATABASE series_data&quot;&lt;/span&gt;

run_sql &lt;span class=&quot;token string&quot;&gt;&quot;CREATE EXTERNAL TABLE series_data.sales_csv (
  order_id INT, city STRING, year INT, amount DOUBLE
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY &#39;,&#39;
LOCATION &#39;s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/raw/&#39;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Ask the question:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;run_sql &lt;span class=&quot;token string&quot;&gt;&quot;SELECT city, ROUND(SUM(amount)) AS total
FROM series_data.sales_csv WHERE year = 2025
GROUP BY city ORDER BY total DESC&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;You get the total for each city, and the first line shows the whole file was scanned, a little over 5 MB, even though the question concerns one year and two columns. Now create a partitioned Parquet copy with one query:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;run_sql &lt;span class=&quot;token string&quot;&gt;&quot;CREATE TABLE series_data.sales_parquet WITH (
  format = &#39;PARQUET&#39;,
  external_location = &#39;s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/parquet/&#39;,
  partitioned_by = ARRAY[&#39;year&#39;]
) AS SELECT order_id, city, amount, year FROM series_data.sales_csv&quot;&lt;/span&gt;

aws s3 &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/parquet/&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;You&#39;ll see a folder for each year. Ask the same question of the new table:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;run_sql &lt;span class=&quot;token string&quot;&gt;&quot;SELECT city, ROUND(SUM(amount)) AS total
FROM series_data.sales_parquet WHERE year = 2025
GROUP BY city ORDER BY total DESC&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The numbers match, but the scanned bytes are a small fraction of the first figure. On terabytes, that difference is your bill.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This experiment costs a tiny fraction of a cent. Delete the tables and the bucket:&lt;/p&gt;
&lt;/aside&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;run_sql &lt;span class=&quot;token string&quot;&gt;&quot;DROP TABLE series_data.sales_parquet&quot;&lt;/span&gt;
run_sql &lt;span class=&quot;token string&quot;&gt;&quot;DROP TABLE series_data.sales_csv&quot;&lt;/span&gt;
run_sql &lt;span class=&quot;token string&quot;&gt;&quot;DROP DATABASE series_data&quot;&lt;/span&gt;
aws s3 rb s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--force&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Separate &lt;strong&gt;analysis&lt;/strong&gt; from your production database, and store data &lt;strong&gt;by column&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Athena&lt;/strong&gt; queries S3 with no servers, and Parquet and partitions lower its cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redshift&lt;/strong&gt; is for heavy, repeated reports, and &lt;strong&gt;Serverless&lt;/strong&gt; is an easy start.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Glue&lt;/strong&gt; catalogs and converts your data, and &lt;strong&gt;Lake Formation&lt;/strong&gt; controls who sees which column.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenSearch&lt;/strong&gt; is for search, &lt;strong&gt;EMR&lt;/strong&gt; for Spark jobs, &lt;strong&gt;Quick Sight&lt;/strong&gt; for dashboards, and &lt;strong&gt;Flink&lt;/strong&gt; and &lt;strong&gt;MSK&lt;/strong&gt; for streams.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 6&lt;/p&gt;
&lt;p&gt;A retail chain&#39;s analysts run heavy reports all day, with many joins across years of sales, and dozens of dashboards refresh from them. Which service was built for this?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Amazon Athena, querying CSV files in S3&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;An RDS read replica&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Amazon Redshift&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Amazon OpenSearch Service&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is a data warehouse&#39;s job. Redshift stores data by column and splits each query across many nodes, so heavy, repeated reports run fast.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This suits occasional questions, and with this many queries you&#39;d pay for every scan.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This takes load off production, but it still stores data by row and isn&#39;t built for this scale of analysis.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This is for text search and log analysis.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#athena-or-redshift&quot;&gt;Athena or Redshift?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/redshift/latest/mgmt/welcome.html&quot;&gt;What is Amazon Redshift?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 6&lt;/p&gt;
&lt;p&gt;Partners drop CSV files into an S3 bucket every day. A team wants them converted to Parquet on a schedule, with no servers to run and without reprocessing files already converted. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A Glue ETL job, with job bookmarks turned on&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A Glue crawler that runs every day&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An EMR cluster running on EC2&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A lifecycle rule moving the files to a cheaper class&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A Glue ETL job runs Spark with no servers to manage, and job bookmarks remember what&#39;s been processed, so each run handles only the new files.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; A crawler works out the columns and updates the catalog, and doesn&#39;t convert anything.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This could do the conversion, but it&#39;s a cluster you&#39;d have to run.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This moves files between classes, and doesn&#39;t change their format.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#aws-glue-preparing-the-data&quot;&gt;AWS Glue: preparing the data&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/glue/latest/dg/monitor-continuations.html&quot;&gt;Tracking processed data using job bookmarks&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 6&lt;/p&gt;
&lt;p&gt;A company&#39;s data lake holds an orders table in S3, queried through Athena. The sales team must see the table, but not its card number column. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A bucket policy that hides that column from the team&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A Glue crawler that skips that column&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An S3 Access Point for the sales team&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Lake Formation, with a column-level permission&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lake Formation grants access down to the column and row, and those permissions apply through services like Athena.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; S3 knows about files, not the columns inside them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; A crawler only describes the data, and controls nobody&#39;s access.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This gives a team its own door to a bucket, and still works at the level of files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#lake-formation-permissions-for-the-lake&quot;&gt;Lake Formation: permissions for the lake&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/lake-formation/latest/dg/data-filtering.html&quot;&gt;Data filtering and cell-level security in Lake Formation&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 6&lt;/p&gt;
&lt;p&gt;A store keeps its products in DynamoDB. Customers want to search for any word in a product&#39;s name or description, and the table must stay the source of truth. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A global secondary index on the description&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;DynamoDB Streams and Lambda, feeding a copy into OpenSearch&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Scanning the table with a filter on each search&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;DAX in front of the table&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OpenSearch finds any word in any field. Streams and Lambda keep it up to date, so you search there, then fetch the full item from the table.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; An index finds items by key, not by any word inside a long text.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This reads the whole table for every search, so it&#39;s slow and costly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This speeds up reads by key, and adds no text search.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#opensearch&quot;&gt;OpenSearch&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/opensearch-service/latest/developerguide/integrations.html&quot;&gt;Loading streaming data into Amazon OpenSearch Service&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 6&lt;/p&gt;
&lt;p&gt;A team&#39;s Athena bill is high. Its queries usually read two columns from one month of data, but everything sits in S3 as one big folder of CSV files. Which &lt;strong&gt;two&lt;/strong&gt; changes lower the cost? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Moving the files to Glacier Deep Archive&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Converting the files to Parquet&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Running the queries at night&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Turning on S3 Versioning&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Partitioning the data by month&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Athena charges for the data it scans. Parquet lets a query read only its columns, and partitions let it skip the other months.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Files in this class have to be restored before they can be read.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; The price depends on what&#39;s read, not on when.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This keeps old versions, and changes nothing about what a query reads.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#read-less-pay-less&quot;&gt;Read less, pay less&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/athena/latest/ug/columnar-storage.html&quot;&gt;Use columnar storage formats&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/athena/latest/ug/partitions.html&quot;&gt;Partition your data&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 6 of 6&lt;/p&gt;
&lt;p&gt;An analytics team wants weather data from a commercial provider in its data lake, kept current through a subscription, without building a custom feed. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;AWS Data Exchange&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;AWS Transfer Family&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Glue crawlers&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Kinesis Data Streams&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Data Exchange is where you find other companies&#39; data sets and subscribe to them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This receives files over SFTP and the like, so the provider would still have to send them to you.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This describes data you already have, and doesn&#39;t bring in new data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; You&#39;d have to write what feeds it, which is the work the team wants to avoid.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#how-does-the-data-arrive&quot;&gt;How does the data arrive?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/data-exchange/latest/userguide/what-is.html&quot;&gt;What is AWS Data Exchange?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;You now understand the data you hold. Can you get more out of it, such as reading documents, understanding speech or generating text? In &lt;a href=&quot;/en/posts/aws-24-ai-services/&quot;&gt;&lt;strong&gt;part twenty-four&lt;/strong&gt;&lt;/a&gt; we go through AWS&#39;s ready-made AI services.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Designing Serverless Applications</title>
    <link href="https://blog.sultanops.com/en/posts/aws-22-serverless-design/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-22-serverless-design/</id>
    <summary>Putting the pieces together. Long workflows with Step Functions, users with Cognito, two complete application designs, microservices and a cheap win with CloudFront, with hands-ons on a file that triggers a function and a workflow that decides.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-21-lambda-api-dynamodb/&quot;&gt;part twenty-one&lt;/a&gt; we built an API from three pieces. A real application needs more: a process with several steps that can fail halfway through, users who sign in, and things that should happen after a request without keeping anyone waiting.&lt;/p&gt;
&lt;p&gt;This part completes the picture with two more services, then applies everything to two designs.&lt;/p&gt;
&lt;h2 id=&quot;step-functions-workflows&quot; tabindex=&quot;-1&quot;&gt;Step Functions: workflows &lt;a class=&quot;heading-anchor&quot; href=&quot;#step-functions-workflows&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An order involves checking stock, then taking payment, then shipping. You could have each function call the next, but then where do retries live? What happens if the payment fails after the stock was reserved? And who can tell you where order 1001 is right now?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step Functions&lt;/strong&gt; moves that logic out of your code, into a &lt;strong&gt;state machine&lt;/strong&gt;: a definition of the steps and what happens after each one, which you can see as a drawing in the console.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 200&quot; role=&quot;img&quot; aria-labelledby=&quot;steps-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;steps-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;20&quot; width=&quot;150&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;95&quot; y=&quot;55&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Check stock&lt;/text&gt;
&lt;rect x=&quot;245&quot; y=&quot;20&quot; width=&quot;150&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;45&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Take payment&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;65&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Retries itself&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;20&quot; width=&quot;150&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;55&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Ship&lt;/text&gt;
&lt;line x1=&quot;170&quot; y1=&quot;50&quot; x2=&quot;243&quot; y2=&quot;50&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#steps-arrow)&quot;/&gt;
&lt;line x1=&quot;395&quot; y1=&quot;50&quot; x2=&quot;468&quot; y2=&quot;50&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#steps-arrow)&quot;/&gt;
&lt;rect x=&quot;245&quot; y=&quot;128&quot; width=&quot;150&quot; height=&quot;58&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-danger)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;162&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Cancel and notify&lt;/text&gt;
&lt;line x1=&quot;95&quot; y1=&quot;80&quot; x2=&quot;243&quot; y2=&quot;150&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#steps-arrow)&quot;/&gt;
&lt;text x=&quot;120&quot; y=&quot;130&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Out of stock&lt;/text&gt;
&lt;line x1=&quot;320&quot; y1=&quot;80&quot; x2=&quot;320&quot; y2=&quot;126&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#steps-arrow)&quot;/&gt;
&lt;text x=&quot;365&quot; y=&quot;108&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Declined&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;steps-caption&quot;&gt;The workflow knows the order of the steps and where each failure goes, while each step stays small and simple.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Each step can call a Lambda function or many AWS services directly, and the definition handles what you&#39;d otherwise write by hand:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ability&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Retry&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Retries a failed step, waiting longer each time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Catch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sends a failure to a step that handles it, such as a refund&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Choice&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Picks a path according to the data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Parallel and Map&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Runs branches together, or one step for each item in a list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wait&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pauses for a period, or for a human approval that takes days&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This is what retrying the payment and catching its failure looks like:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;JSON&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;TakePayment&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Task&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:states:::lambda:invoke&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Parameters&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;FunctionName&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;take-payment&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;Payload.$&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Retry&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ErrorEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;States.TaskFailed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;IntervalSeconds&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;BackoffRate&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;MaxAttempts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Catch&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;ErrorEquals&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;States.ALL&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CancelOrder&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Next&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ship&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Standard&lt;/th&gt;
&lt;th&gt;Express&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Maximum duration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One year&lt;/td&gt;
&lt;td&gt;Five minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Execution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Exactly once&lt;/td&gt;
&lt;td&gt;At least once&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Billed by&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;State transition, with 4,000 free each month&lt;/td&gt;
&lt;td&gt;Number of requests, duration and memory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Suits&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Long processes such as orders and approvals&lt;/td&gt;
&lt;td&gt;Short, very frequent events&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;cognito-your-users&quot; tabindex=&quot;-1&quot;&gt;Cognito: your users &lt;a class=&quot;heading-anchor&quot; href=&quot;#cognito-your-users&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/en/posts/aws-02-iam/&quot;&gt;IAM&lt;/a&gt; is for your team and your services, not for a million people using your application. &lt;strong&gt;Amazon Cognito&lt;/strong&gt; gives your application its own users, and it has two parts that are easy to confuse:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;User Pool&lt;/th&gt;
&lt;th&gt;Identity Pool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Question it answers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Who is this user?&lt;/td&gt;
&lt;td&gt;What can they do in AWS?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gives&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A token after signing in&lt;/td&gt;
&lt;td&gt;Temporary AWS keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Used for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your application and your API&lt;/td&gt;
&lt;td&gt;Direct access to S3 or DynamoDB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;User Pools&lt;/strong&gt; handle sign-up and sign-in, password resets, multi-factor authentication, and signing in with accounts like Google or a corporate identity. API Gateway and the Application Load Balancer can check its tokens directly. New pools use the &lt;strong&gt;Essentials&lt;/strong&gt; plan by default, and there&#39;s also a cheaper &lt;strong&gt;Lite&lt;/strong&gt; with fewer features, and &lt;strong&gt;Plus&lt;/strong&gt; with advanced protection.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Identity Pools&lt;/strong&gt; exchange a token for temporary keys tied to an IAM role, and a policy variable limits them to the user&#39;s own data. For example, each user reaches only their folder in S3:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;JSON&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;s3:GetObject&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s3:PutObject&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:s3:::recipe-photos/users/${cognito-identity.amazonaws.com:sub}/*&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;design-one-a-mobile-app&quot; tabindex=&quot;-1&quot;&gt;Design one: a mobile app &lt;a class=&quot;heading-anchor&quot; href=&quot;#design-one-a-mobile-app&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s design an app for sharing recipes: users sign in, write recipes, upload photos, and popular recipes get read many times more often than they&#39;re written. Each requirement has its piece:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Users sign in&lt;/td&gt;
&lt;td&gt;A Cognito &lt;strong&gt;User Pool&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An API for reading and writing recipes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;API Gateway&lt;/strong&gt;, &lt;strong&gt;Lambda&lt;/strong&gt; and &lt;strong&gt;DynamoDB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uploading photos directly&lt;/td&gt;
&lt;td&gt;An &lt;strong&gt;Identity Pool&lt;/strong&gt; with temporary keys to S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Huge numbers of reads on the same recipes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DAX&lt;/strong&gt; in front of the table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeated identical requests&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;API Gateway caching&lt;/strong&gt;, on a REST API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 250&quot; role=&quot;img&quot; aria-labelledby=&quot;cognito-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;cognito-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;60&quot; width=&quot;100&quot; height=&quot;130&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;70&quot; y=&quot;130&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;App&lt;/text&gt;
&lt;rect x=&quot;170&quot; y=&quot;14&quot; width=&quot;140&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;240&quot; y=&quot;37&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;User Pool&lt;/text&gt;
&lt;text x=&quot;240&quot; y=&quot;57&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Sign-in and token&lt;/text&gt;
&lt;rect x=&quot;170&quot; y=&quot;97&quot; width=&quot;140&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;240&quot; y=&quot;120&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;API Gateway&lt;/text&gt;
&lt;text x=&quot;240&quot; y=&quot;140&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Checks the token&lt;/text&gt;
&lt;rect x=&quot;350&quot; y=&quot;97&quot; width=&quot;110&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;405&quot; y=&quot;130&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Lambda&lt;/text&gt;
&lt;rect x=&quot;500&quot; y=&quot;97&quot; width=&quot;120&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;560&quot; y=&quot;130&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;DynamoDB&lt;/text&gt;
&lt;rect x=&quot;170&quot; y=&quot;180&quot; width=&quot;140&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;240&quot; y=&quot;203&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Identity Pool&lt;/text&gt;
&lt;text x=&quot;240&quot; y=&quot;223&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Temporary keys&lt;/text&gt;
&lt;rect x=&quot;350&quot; y=&quot;180&quot; width=&quot;270&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;485&quot; y=&quot;203&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;S3&lt;/text&gt;
&lt;text x=&quot;485&quot; y=&quot;223&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;users/ID/&lt;/text&gt;
&lt;line x1=&quot;120&quot; y1=&quot;80&quot; x2=&quot;168&quot; y2=&quot;42&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#cognito-arrow)&quot;/&gt;
&lt;line x1=&quot;120&quot; y1=&quot;125&quot; x2=&quot;168&quot; y2=&quot;125&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#cognito-arrow)&quot;/&gt;
&lt;line x1=&quot;120&quot; y1=&quot;170&quot; x2=&quot;168&quot; y2=&quot;208&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#cognito-arrow)&quot;/&gt;
&lt;line x1=&quot;310&quot; y1=&quot;125&quot; x2=&quot;348&quot; y2=&quot;125&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#cognito-arrow)&quot;/&gt;
&lt;line x1=&quot;460&quot; y1=&quot;125&quot; x2=&quot;498&quot; y2=&quot;125&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#cognito-arrow)&quot;/&gt;
&lt;line x1=&quot;310&quot; y1=&quot;208&quot; x2=&quot;348&quot; y2=&quot;208&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#cognito-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;cognito-caption&quot;&gt;The User Pool signs the user in and issues a token. API Gateway checks it, and the Identity Pool exchanges it for temporary keys limited to the user&#39;s own folder.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Why does the photo go directly to S3, instead of through the API? Because API Gateway has a 10 MB limit, and because you&#39;d pay for Lambda&#39;s time just to pass bytes along. Signed links from &lt;a href=&quot;/en/posts/aws-17-s3-security/&quot;&gt;part seventeen&lt;/a&gt; are another good option here, when you don&#39;t need Identity Pools.&lt;/p&gt;
&lt;p&gt;And notice where each cache sits: API Gateway&#39;s stops the request before it reaches the function, so it suits responses that don&#39;t change per user. DAX lets the function run, then spares the table from the read.&lt;/p&gt;
&lt;h2 id=&quot;design-two-a-global-website&quot; tabindex=&quot;-1&quot;&gt;Design two: a global website &lt;a class=&quot;heading-anchor&quot; href=&quot;#design-two-a-global-website&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now a travel guide read around the world: static pages, a small API, a welcome email when someone registers, and thumbnails for the photos users upload.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 248&quot; role=&quot;img&quot; aria-labelledby=&quot;site-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;site-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;14&quot; width=&quot;100&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;70&quot; y=&quot;47&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Visitors&lt;/text&gt;
&lt;rect x=&quot;160&quot; y=&quot;14&quot; width=&quot;110&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;215&quot; y=&quot;47&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;CloudFront&lt;/text&gt;
&lt;rect x=&quot;310&quot; y=&quot;14&quot; width=&quot;150&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;385&quot; y=&quot;37&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;S3&lt;/text&gt;
&lt;text x=&quot;385&quot; y=&quot;57&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Pages and images&lt;/text&gt;
&lt;rect x=&quot;500&quot; y=&quot;14&quot; width=&quot;120&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;560&quot; y=&quot;37&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Lambda&lt;/text&gt;
&lt;text x=&quot;560&quot; y=&quot;57&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Thumbnails&lt;/text&gt;
&lt;rect x=&quot;160&quot; y=&quot;96&quot; width=&quot;110&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;215&quot; y=&quot;129&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;API Gateway&lt;/text&gt;
&lt;rect x=&quot;310&quot; y=&quot;96&quot; width=&quot;150&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;385&quot; y=&quot;119&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Lambda&lt;/text&gt;
&lt;text x=&quot;385&quot; y=&quot;139&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Your logic&lt;/text&gt;
&lt;rect x=&quot;500&quot; y=&quot;96&quot; width=&quot;120&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;560&quot; y=&quot;119&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;DynamoDB&lt;/text&gt;
&lt;text x=&quot;560&quot; y=&quot;139&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Global Tables&lt;/text&gt;
&lt;rect x=&quot;500&quot; y=&quot;178&quot; width=&quot;120&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;560&quot; y=&quot;211&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Streams&lt;/text&gt;
&lt;rect x=&quot;310&quot; y=&quot;178&quot; width=&quot;150&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;385&quot; y=&quot;201&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Lambda&lt;/text&gt;
&lt;text x=&quot;385&quot; y=&quot;221&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Welcome email&lt;/text&gt;
&lt;rect x=&quot;160&quot; y=&quot;178&quot; width=&quot;110&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;215&quot; y=&quot;211&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;SES&lt;/text&gt;
&lt;line x1=&quot;120&quot; y1=&quot;42&quot; x2=&quot;158&quot; y2=&quot;42&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#site-arrow)&quot;/&gt;
&lt;line x1=&quot;270&quot; y1=&quot;42&quot; x2=&quot;308&quot; y2=&quot;42&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#site-arrow)&quot;/&gt;
&lt;line x1=&quot;460&quot; y1=&quot;42&quot; x2=&quot;498&quot; y2=&quot;42&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#site-arrow)&quot;/&gt;
&lt;line x1=&quot;215&quot; y1=&quot;70&quot; x2=&quot;215&quot; y2=&quot;94&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#site-arrow)&quot;/&gt;
&lt;line x1=&quot;270&quot; y1=&quot;124&quot; x2=&quot;308&quot; y2=&quot;124&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#site-arrow)&quot;/&gt;
&lt;line x1=&quot;460&quot; y1=&quot;124&quot; x2=&quot;498&quot; y2=&quot;124&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#site-arrow)&quot;/&gt;
&lt;line x1=&quot;560&quot; y1=&quot;152&quot; x2=&quot;560&quot; y2=&quot;176&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#site-arrow)&quot;/&gt;
&lt;line x1=&quot;500&quot; y1=&quot;206&quot; x2=&quot;462&quot; y2=&quot;206&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#site-arrow)&quot;/&gt;
&lt;line x1=&quot;310&quot; y1=&quot;206&quot; x2=&quot;272&quot; y2=&quot;206&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#site-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;site-caption&quot;&gt;CloudFront serves the pages and passes API calls along. Everything after a write happens through events: a new user triggers the email, and a new image triggers the thumbnail.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Follow it piece by piece:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pages:&lt;/strong&gt; a private S3 bucket with &lt;a href=&quot;/en/posts/aws-12-cloudfront-global-accelerator/&quot;&gt;CloudFront and OAC&lt;/a&gt; in front of it, so the bucket stays closed and the site is fast everywhere.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API:&lt;/strong&gt; API Gateway, Lambda and DynamoDB, and &lt;strong&gt;Global Tables&lt;/strong&gt; place data close to users in each Region.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Welcome email:&lt;/strong&gt; the API doesn&#39;t send it. A new user is written to the table, &lt;strong&gt;DynamoDB Streams&lt;/strong&gt; triggers a function, and it sends through &lt;strong&gt;SES&lt;/strong&gt;. If email fails, registration isn&#39;t affected.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thumbnails:&lt;/strong&gt; a photo landing in S3 triggers a Lambda function that writes a smaller copy. To handle bursts, or to reach several services, put &lt;a href=&quot;/en/posts/aws-19-sqs-sns-kinesis/&quot;&gt;SQS or SNS&lt;/a&gt; in between.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&#39;s not a single server here, and when no one&#39;s visiting, the bill is close to storage costs alone. The point in the last two flows is the same: &lt;strong&gt;the request finishes quickly, and everything else happens through events.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;microservices&quot; tabindex=&quot;-1&quot;&gt;Microservices &lt;a class=&quot;heading-anchor&quot; href=&quot;#microservices&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When an application grows, teams split it into small services, each with its own job, database and release schedule. There are two ways for them to talk:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Style&lt;/th&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;th&gt;Suits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Synchronous&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;API Gateway or a load balancer&lt;/td&gt;
&lt;td&gt;You need the answer now, such as a price&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Asynchronous&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SQS, SNS, Kinesis and Lambda triggers&lt;/td&gt;
&lt;td&gt;The work can come later, such as an invoice&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;And each service can choose what suits it: Lambda for scattered requests, Fargate for steady load, and EC2 for special requirements. All of this has a price, though: more deployments, more to monitor, and failures harder to trace across services. So don&#39;t start here for a small application, and split only when you really need to.&lt;/p&gt;
&lt;h2 id=&quot;a-cheap-win-cloudfront-in-front-of-what-you-have&quot; tabindex=&quot;-1&quot;&gt;A cheap win: CloudFront in front of what you have &lt;a class=&quot;heading-anchor&quot; href=&quot;#a-cheap-win-cloudfront-in-front-of-what-you-have&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not every improvement needs a rewrite. Imagine an application on an Auto Scaling group that distributes large update files. On release day, all your users download at once: servers multiply, and your data transfer bill jumps.&lt;/p&gt;
&lt;p&gt;Put &lt;strong&gt;CloudFront&lt;/strong&gt; in front of it, and change nothing else. The files don&#39;t change, so they suit caching very well: most requests stop at the edge, the group barely has to grow, and data going out through CloudFront costs less than going out directly. A few minutes&#39; work can pay back more than a redesign.&lt;/p&gt;
&lt;h2 id=&quot;design-principles&quot; tabindex=&quot;-1&quot;&gt;Design principles &lt;a class=&quot;heading-anchor&quot; href=&quot;#design-principles&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Principle&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Make processing safe to repeat&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SQS, SNS and asynchronous Lambda deliver at least once&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A dead-letter queue for anything asynchronous&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A silent failure is the worst kind&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;One role per function, with the least privilege&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A flaw in one doesn&#39;t open everything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Small functions with one job&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Easier to test, and quicker to start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Calculate the cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;With heavy, constant load, containers can come out cheaper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Observe everything&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requests pass through many services, and we cover the tools in &lt;a href=&quot;/en/posts/aws-25-monitoring-auditing/&quot;&gt;part twenty-five&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;You also don&#39;t have to start from nothing. The &lt;strong&gt;AWS Serverless Application Repository&lt;/strong&gt; lets you find ready-made serverless applications, set a few values, and deploy them in a few clicks.&lt;/p&gt;
&lt;h2 id=&quot;hands-on-a-file-triggers-a-function&quot; tabindex=&quot;-1&quot;&gt;Hands-on: a file triggers a function &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-a-file-triggers-a-function&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-15-s3-basics/&quot;&gt;part fifteen&lt;/a&gt; we promised to apply S3 events. We&#39;ll make the thumbnail flow, with one simplification: instead of an image library, the function converts a text file to capitals. The flow is exactly the same. From CloudShell:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;BUCKET&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;series-events-&lt;span class=&quot;token environment constant&quot;&gt;$RANDOM&lt;/span&gt;&lt;span class=&quot;token environment constant&quot;&gt;$RANDOM&lt;/span&gt;
aws s3 mb s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; trust.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [{
    &quot;Effect&quot;: &quot;Allow&quot;,
    &quot;Principal&quot;: {&quot;Service&quot;: &quot;lambda.amazonaws.com&quot;},
    &quot;Action&quot;: &quot;sts:AssumeRole&quot;
  }]
}
EOF&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;ROLE_ARN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws iam create-role --role-name series-events-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --assume-role-policy-document file://trust.json &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Role.Arn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws iam attach-role-policy --role-name series-events-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

aws iam put-role-policy --role-name series-events-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-name bucket-access --policy-document &lt;span class=&quot;token string&quot;&gt;&quot;{
    &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Version&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;: &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;2012-10-17&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;,
    &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Statement&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;: [{
      &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Effect&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;: &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Allow&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;,
      &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Action&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;: [&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;s3:GetObject&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;, &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;s3:PutObject&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;],
      &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Resource&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;: &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;arn:aws:s3:::&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/*&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;
    }]
  }&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Write the function, and create it. If you get an error about the role, wait a few seconds and repeat the command:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; app.py &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
from urllib.parse import unquote_plus
import boto3

s3 = boto3.client(&quot;s3&quot;)

def handler(event, context):
    for record in event[&quot;Records&quot;]:
        bucket = record[&quot;s3&quot;][&quot;bucket&quot;][&quot;name&quot;]
        key = unquote_plus(record[&quot;s3&quot;][&quot;object&quot;][&quot;key&quot;])
        body = s3.get_object(Bucket=bucket, Key=key)[&quot;Body&quot;].read().decode()
        name = key.split(&quot;/&quot;)[-1]
        s3.put_object(Bucket=bucket, Key=f&quot;processed/{name}&quot;, Body=body.upper())
EOF&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;zip&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-q&lt;/span&gt; function.zip app.py

&lt;span class=&quot;token assign-left variable&quot;&gt;FN_ARN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws lambda create-function --function-name series-events &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--runtime&lt;/span&gt; python3.13 &lt;span class=&quot;token parameter variable&quot;&gt;--handler&lt;/span&gt; app.handler &lt;span class=&quot;token parameter variable&quot;&gt;--role&lt;/span&gt; $ROLE_ARN &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --zip-file fileb://function.zip &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; FunctionArn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws lambda &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt; function-active-v2 --function-name series-events&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Allow S3 to invoke the function, then tell the bucket to send it events from the &lt;code&gt;uploads/&lt;/code&gt; folder only:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws lambda add-permission --function-name series-events &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --statement-id s3-trigger &lt;span class=&quot;token parameter variable&quot;&gt;--action&lt;/span&gt; lambda:InvokeFunction &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--principal&lt;/span&gt; s3.amazonaws.com --source-arn arn:aws:s3:::&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Statement &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /dev/null

&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; notify.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;EOF
{
  &quot;LambdaFunctionConfigurations&quot;: [{
    &quot;LambdaFunctionArn&quot;: &quot;&lt;span class=&quot;token variable&quot;&gt;$FN_ARN&lt;/span&gt;&quot;,
    &quot;Events&quot;: [&quot;s3:ObjectCreated:*&quot;],
    &quot;Filter&quot;: {&quot;Key&quot;: {&quot;FilterRules&quot;: [{&quot;Name&quot;: &quot;prefix&quot;, &quot;Value&quot;: &quot;uploads/&quot;}]}}
  }]
}
EOF&lt;/span&gt;

aws s3api put-bucket-notification-configuration &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --notification-configuration file://notify.json&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Upload a file, wait a few seconds, then read the result:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hello from s3&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; note.txt
aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; note.txt s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/uploads/note.txt&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/processed/note.txt -&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;It prints &lt;code&gt;HELLO FROM S3&lt;/code&gt;. You uploaded a file, and code ran by itself.&lt;/p&gt;
&lt;aside class=&quot;callout callout-warning&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-alert&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 4l9 16H3L12 4z&quot;/&gt;&lt;path d=&quot;M12 10v4M12 17h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Beware of an endless loop&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Here the function writes to &lt;code&gt;processed/&lt;/code&gt; and listens to &lt;code&gt;uploads/&lt;/code&gt;. If it wrote to the same folder it listens to, each output would trigger it again, and your bill would climb with it. Always separate the two with a prefix, or with two buckets.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;Clean up before moving on:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws s3 rb s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--force&lt;/span&gt;
aws lambda delete-function --function-name series-events
aws logs delete-log-group --log-group-name /aws/lambda/series-events
aws iam delete-role-policy --role-name series-events-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-name bucket-access
aws iam detach-role-policy --role-name series-events-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
aws iam delete-role --role-name series-events-role&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;hands-on-a-workflow-that-decides&quot; tabindex=&quot;-1&quot;&gt;Hands-on: a workflow that decides &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-a-workflow-that-decides&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll write a state machine that looks at an order&#39;s amount: a negative amount fails, a large amount goes to review, and the rest is approved. It only uses internal steps, so it needs a role with no permissions:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; trust.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [{
    &quot;Effect&quot;: &quot;Allow&quot;,
    &quot;Principal&quot;: {&quot;Service&quot;: &quot;states.amazonaws.com&quot;},
    &quot;Action&quot;: &quot;sts:AssumeRole&quot;
  }]
}
EOF&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;FLOW_ROLE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws iam create-role --role-name series-flow-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --assume-role-policy-document file://trust.json &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Role.Arn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; flow.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
{
  &quot;StartAt&quot;: &quot;CheckAmount&quot;,
  &quot;States&quot;: {
    &quot;CheckAmount&quot;: {
      &quot;Type&quot;: &quot;Choice&quot;,
      &quot;Choices&quot;: [
        {&quot;Variable&quot;: &quot;$.amount&quot;, &quot;NumericLessThanEquals&quot;: 0, &quot;Next&quot;: &quot;Rejected&quot;},
        {&quot;Variable&quot;: &quot;$.amount&quot;, &quot;NumericGreaterThan&quot;: 1000, &quot;Next&quot;: &quot;NeedsReview&quot;}
      ],
      &quot;Default&quot;: &quot;Approved&quot;
    },
    &quot;NeedsReview&quot;: {&quot;Type&quot;: &quot;Pass&quot;, &quot;Result&quot;: {&quot;status&quot;: &quot;review&quot;}, &quot;End&quot;: true},
    &quot;Approved&quot;: {&quot;Type&quot;: &quot;Pass&quot;, &quot;Result&quot;: {&quot;status&quot;: &quot;approved&quot;}, &quot;End&quot;: true},
    &quot;Rejected&quot;: {&quot;Type&quot;: &quot;Fail&quot;, &quot;Error&quot;: &quot;InvalidAmount&quot;, &quot;Cause&quot;: &quot;The amount must be positive&quot;}
  }
}
EOF&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Create it. Here too, if you get an error about the role, wait a few seconds and repeat:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;FLOW_ARN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws stepfunctions create-state-machine &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; series-order &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--definition&lt;/span&gt; file://flow.json --role-arn $FLOW_ROLE &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; stateMachineArn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Run it with three orders:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function-name function&quot;&gt;try_order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token assign-left variable&quot;&gt;RUN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws stepfunctions start-execution --state-machine-arn $FLOW_ARN &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token parameter variable&quot;&gt;--input&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; executionArn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
  aws stepfunctions describe-execution --execution-arn &lt;span class=&quot;token variable&quot;&gt;$RUN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[status,output]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

try_order &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;amount&quot;: 250}&#39;&lt;/span&gt;
try_order &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;amount&quot;: 5000}&#39;&lt;/span&gt;
try_order &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;amount&quot;: -5}&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;You&#39;ll get &lt;code&gt;approved&lt;/code&gt;, then &lt;code&gt;review&lt;/code&gt;, then &lt;code&gt;FAILED&lt;/code&gt;. Now open &lt;strong&gt;Step Functions&lt;/strong&gt; in the console, choose &lt;code&gt;series-order&lt;/code&gt;, then any of the executions. You&#39;ll see the drawing with the path taken in color, which is what you&#39;d look at when an order gets stuck in production.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A few transitions fall within the 4,000 free each month. Delete the machine and its role:&lt;/p&gt;
&lt;/aside&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws stepfunctions delete-state-machine --state-machine-arn &lt;span class=&quot;token variable&quot;&gt;$FLOW_ARN&lt;/span&gt;
aws iam delete-role --role-name series-flow-role&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Step Functions&lt;/strong&gt; takes steps, retries and failures out of your code into a visible workflow.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;User Pool&lt;/strong&gt; answers who the user is, and an &lt;strong&gt;Identity Pool&lt;/strong&gt; gives them temporary keys to AWS.&lt;/li&gt;
&lt;li&gt;A good design &lt;strong&gt;finishes the request quickly&lt;/strong&gt;, and leaves everything else to events.&lt;/li&gt;
&lt;li&gt;Have large files go &lt;strong&gt;directly to S3&lt;/strong&gt;, and put &lt;strong&gt;caching&lt;/strong&gt; where it stops the most work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microservices&lt;/strong&gt; have a price, so split only when you really need to.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 5&lt;/p&gt;
&lt;p&gt;An order goes through stock, payment and shipping. Failed steps must retry, a failed payment must trigger a refund, and large orders wait days for a manager&#39;s approval. The team also wants to see where each order is. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Step Functions, with an Express workflow&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Lambda functions that call each other&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An SNS topic with a subscriber for each step&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Step Functions, with a Standard workflow&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A Standard workflow can last up to a year, its definition holds the retries, failures and waiting, and the console shows you each execution&#39;s path as a drawing.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; These run for at most five minutes, so they can&#39;t wait for days.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; The retries and failure handling end up in your code, and nothing shows you where an order is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This delivers to every subscriber at once, with no order between the steps.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#step-functions-workflows&quot;&gt;Step Functions: workflows&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/step-functions/latest/dg/choosing-workflow-type.html&quot;&gt;Choosing workflow type in Step Functions&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 5&lt;/p&gt;
&lt;p&gt;Users sign in to a mobile app through a Cognito User Pool. They should upload photos directly to S3, and each must only reach their own folder. What gives the app access to S3?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;An Identity Pool, with temporary keys and a policy variable&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;The User Pool token, sent directly to S3&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An IAM user for each person using the app&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Access keys built into the app&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Identity Pool swaps the token for temporary keys tied to an IAM role, and a policy variable limits them to that user&#39;s folder.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; A User Pool token says who the user is, and it isn&#39;t a set of AWS keys.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; IAM is for your team and services, not for huge numbers of app users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Anyone could pull these keys out of the app, and they&#39;d work for everyone&#39;s folders.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#cognito-your-users&quot;&gt;Cognito: your users&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html&quot;&gt;Amazon Cognito identity pools&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/cognito/latest/developerguide/iam-roles.html&quot;&gt;IAM roles&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 5&lt;/p&gt;
&lt;p&gt;A sign-up API sends a welcome email before it responds. When the email service is slow, sign-ups are slow too, and when it fails, sign-ups fail. New users are written to DynamoDB. What&#39;s the best design?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Raising the function&#39;s timeout&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;DynamoDB Streams triggering a separate function that sends the email&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Provisioned Concurrency on the API&#39;s function&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Retrying the email inside the API&#39;s function&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The request finishes once the user is written, and the email happens through an event, so a failed email doesn&#39;t affect the sign-up.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Users would wait even longer, and failures would still reach them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This removes cold starts, and the slowness comes from the email.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Retrying inside the request makes users wait even longer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#design-two-a-global-website&quot;&gt;Design two: a global website&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.Lambda.html&quot;&gt;DynamoDB Streams and AWS Lambda triggers&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 5&lt;/p&gt;
&lt;p&gt;An application on an Auto Scaling group distributes large update files. On release day the group grows sharply and the data transfer bill jumps. What gives the biggest improvement with the &lt;strong&gt;least change&lt;/strong&gt;?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Moving the servers to larger instance types&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Rewriting the downloads with Lambda and API Gateway&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Putting CloudFront in front of the application&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Putting Global Accelerator in front of the application&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The files don&#39;t change, so they suit caching very well. Most requests stop at the edge, the group barely has to grow, and data going out through CloudFront costs less than going out directly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; The servers would still handle every download, and the same data would still go out.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This is a rewrite, and API Gateway&#39;s 10 MB limit is too small for large files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This shortens the road but doesn&#39;t cache, so every download still reaches the servers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#a-cheap-win-cloudfront-in-front-of-what-you-have&quot;&gt;A cheap win: CloudFront in front of what you have&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&quot;&gt;What is Amazon CloudFront?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 5&lt;/p&gt;
&lt;p&gt;An SNS topic invokes a Lambda function asynchronously. Some customers were charged twice, and events that failed repeatedly vanished with no trace. Which &lt;strong&gt;two&lt;/strong&gt; changes address these? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Make the charge safe to repeat, for example by checking the order number first&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Give the function more memory&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Turn on SnapStart&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Use Provisioned Concurrency&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Send failed events to a dead-letter queue or a failure destination&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An event can be delivered more than once, so a duplicate has to be harmless. And a dead-letter queue keeps what failed so you can inspect it, rather than losing it silently.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This makes the function faster, and duplicates still arrive.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This eases cold starts, and has nothing to do with either problem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This keeps environments ready, and has nothing to do with either problem.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#design-principles&quot;&gt;Design principles&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/invocation-async-error-handling.html&quot;&gt;How Lambda handles errors and retries with asynchronous invocation&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/invocation-async-retain-records.html&quot;&gt;Capturing records of Lambda asynchronous invocations&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;This completes the modern applications section. Your application now generates a lot of data, but what does it tell you? In &lt;a href=&quot;/en/posts/aws-23-athena-redshift-glue/&quot;&gt;&lt;strong&gt;part twenty-three&lt;/strong&gt;&lt;/a&gt; we start the data and AI section, analyzing data with Athena, Redshift and Glue.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Serverless: Lambda, API Gateway and DynamoDB</title>
    <link href="https://blog.sultanops.com/en/posts/aws-21-lambda-api-dynamodb/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-21-lambda-api-dynamodb/</id>
    <summary>Run code without servers and pay only when it runs. How Lambda works and what limits it, cold starts, DynamoDB tables and their keys, API Gateway as the front door, and a hands-on where you build a working API.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-20-ecs-fargate-eks/&quot;&gt;part twenty&lt;/a&gt; we stopped managing servers, but tasks still run around the clock, waiting for visitors who may never come. What if your code only ran when a request arrived, and you paid nothing otherwise?&lt;/p&gt;
&lt;p&gt;That&#39;s &lt;strong&gt;serverless&lt;/strong&gt;. There are still servers, of course, but provisioning, updating and scaling them are no longer your problem.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;EC2&lt;/th&gt;
&lt;th&gt;Fargate&lt;/th&gt;
&lt;th&gt;Lambda&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;You manage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The system and the application&lt;/td&gt;
&lt;td&gt;The image and the application&lt;/td&gt;
&lt;td&gt;The code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;You pay for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Running time&lt;/td&gt;
&lt;td&gt;Running time&lt;/td&gt;
&lt;td&gt;Each request and its duration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;When idle&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You pay&lt;/td&gt;
&lt;td&gt;You pay&lt;/td&gt;
&lt;td&gt;Almost nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You set it up&lt;/td&gt;
&lt;td&gt;You set it up&lt;/td&gt;
&lt;td&gt;By itself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Runs for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;As long as you like&lt;/td&gt;
&lt;td&gt;As long as you like&lt;/td&gt;
&lt;td&gt;Up to 15 minutes per request&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;aws-lambda&quot; tabindex=&quot;-1&quot;&gt;AWS Lambda &lt;a class=&quot;heading-anchor&quot; href=&quot;#aws-lambda&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Lambda&lt;/strong&gt; runs a &lt;strong&gt;function&lt;/strong&gt; you write when an &lt;strong&gt;event&lt;/strong&gt; triggers it. It does its work, then stops.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 240&quot; role=&quot;img&quot; aria-labelledby=&quot;lambda-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;lambda-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;14&quot; width=&quot;150&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;95&quot; y=&quot;41&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;S3 upload&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;70&quot; width=&quot;150&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;95&quot; y=&quot;97&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;SQS message&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;126&quot; width=&quot;150&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;95&quot; y=&quot;153&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;API request&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;182&quot; width=&quot;150&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;95&quot; y=&quot;209&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Schedule&lt;/text&gt;
&lt;rect x=&quot;245&quot; y=&quot;74&quot; width=&quot;150&quot; height=&quot;92&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;115&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Lambda&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;135&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Your code runs&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;28&quot; width=&quot;150&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;55&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;DynamoDB&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;98&quot; width=&quot;150&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;125&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;S3&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;168&quot; width=&quot;150&quot; height=&quot;44&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;195&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;SNS&lt;/text&gt;
&lt;line x1=&quot;170&quot; y1=&quot;36&quot; x2=&quot;243&quot; y2=&quot;96&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#lambda-arrow)&quot;/&gt;
&lt;line x1=&quot;170&quot; y1=&quot;92&quot; x2=&quot;243&quot; y2=&quot;112&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#lambda-arrow)&quot;/&gt;
&lt;line x1=&quot;170&quot; y1=&quot;148&quot; x2=&quot;243&quot; y2=&quot;128&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#lambda-arrow)&quot;/&gt;
&lt;line x1=&quot;170&quot; y1=&quot;204&quot; x2=&quot;243&quot; y2=&quot;144&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#lambda-arrow)&quot;/&gt;
&lt;line x1=&quot;395&quot; y1=&quot;120&quot; x2=&quot;468&quot; y2=&quot;50&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#lambda-arrow)&quot;/&gt;
&lt;line x1=&quot;395&quot; y1=&quot;120&quot; x2=&quot;468&quot; y2=&quot;120&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#lambda-arrow)&quot;/&gt;
&lt;line x1=&quot;395&quot; y1=&quot;120&quot; x2=&quot;468&quot; y2=&quot;190&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#lambda-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;lambda-caption&quot;&gt;An event starts the function, it does its work and stops. You pay only for the time it ran.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It supports Python, Node.js, Java, .NET and Ruby directly, and any other language through a custom runtime or a container image. This is what a function looks like in Python:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Python&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;world&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;code&gt;event&lt;/code&gt; carries the details of what happened, and its shape depends on the source: an S3 event contains the bucket and the key, for example, and an API event contains the path and the headers.&lt;/p&gt;
&lt;h3 id=&quot;what-does-it-cost&quot; tabindex=&quot;-1&quot;&gt;What does it cost? &lt;a class=&quot;heading-anchor&quot; href=&quot;#what-does-it-cost&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You pay for the number of requests, and for the duration multiplied by memory, in &lt;strong&gt;GB-seconds&lt;/strong&gt;. Prices below are for x86 in US Regions, and the free tier covers 1 million requests and 400,000 GB-seconds every month.&lt;/p&gt;
&lt;p&gt;An example: a function with 512 MB of memory that runs for 200 milliseconds, 5 million times a month:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Calculation&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Duration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5,000,000 x 0.2 s x 0.5 GB = 500,000 GB-s, minus 400,000 free&lt;/td&gt;
&lt;td&gt;$1.67&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Requests&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5 million minus 1 million free, at $0.20 per million&lt;/td&gt;
&lt;td&gt;$0.80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;about $2.47&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Five million requests for less than a coffee. But the calculation can flip: with heavy, constant load, a server or container can come out cheaper, so do the math.&lt;/p&gt;
&lt;h3 id=&quot;limits-to-know&quot; tabindex=&quot;-1&quot;&gt;Limits to know &lt;a class=&quot;heading-anchor&quot; href=&quot;#limits-to-know&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;128 MB to 10,240 MB, and CPU rises with it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Duration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15 minutes per request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Temporary storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/tmp&lt;/code&gt;, from 512 MB to 10 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Package size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;50 MB zipped, 250 MB unzipped, or a 10 GB container image&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Concurrency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1,000 per Region by default, and it may be lower in new accounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Payload&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;6 MB for synchronous calls, 1 MB for asynchronous&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If your work takes longer than 15 minutes, split it up with &lt;a href=&quot;/en/posts/aws-22-serverless-design/&quot;&gt;Step Functions&lt;/a&gt;, or use a container.&lt;/p&gt;
&lt;h3 id=&quot;concurrency&quot; tabindex=&quot;-1&quot;&gt;Concurrency &lt;a class=&quot;heading-anchor&quot; href=&quot;#concurrency&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each execution environment serves one request at a time, so 100 simultaneous requests need 100 environments. That number is your &lt;strong&gt;concurrency&lt;/strong&gt;, and all functions in a Region share one limit. What happens when you reach it?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Synchronous calls,&lt;/strong&gt; as from an API, get a &lt;code&gt;429&lt;/code&gt; error.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Asynchronous calls,&lt;/strong&gt; as from S3, are held and retried for up to 6 hours, then sent to a dead-letter queue or a failure destination if you&#39;ve set one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The hidden trap is that one busy function can consume the whole limit and throttle your others. &lt;strong&gt;Reserved concurrency&lt;/strong&gt; sets aside a share for a function, which is also a ceiling for it, so it neither gets starved nor starves others.&lt;/p&gt;
&lt;h3 id=&quot;cold-starts&quot; tabindex=&quot;-1&quot;&gt;Cold starts &lt;a class=&quot;heading-anchor&quot; href=&quot;#cold-starts&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When a request arrives with no environment ready, Lambda creates one and loads your code first. This is a &lt;strong&gt;cold start&lt;/strong&gt;, and it may add from a fraction of a second to several seconds, depending on the language and the size of the code. Then the environment stays around for a while and serves later requests quickly. This setup time is billed too, since August 2025.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Provisioned Concurrency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Keeps a number of environments ready at all times, so there&#39;s no cold start for them&lt;/td&gt;
&lt;td&gt;You pay for them while ready&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SnapStart&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Saves a snapshot after setup and restores from it, for Java 11+, Python 3.12+ and .NET 8+&lt;/td&gt;
&lt;td&gt;Free for Java; charged for Python and .NET&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The two can&#39;t be combined on one function. SnapStart lowers startup time but doesn&#39;t guarantee to remove it, so if you need very low, steady latency, use Provisioned Concurrency.&lt;/p&gt;
&lt;h3 id=&quot;lambda-inside-a-vpc&quot; tabindex=&quot;-1&quot;&gt;Lambda inside a VPC &lt;a class=&quot;heading-anchor&quot; href=&quot;#lambda-inside-a-vpc&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By default a function runs outside your VPC, so it can reach the internet and public AWS services, but not your private RDS. Attach it to your &lt;a href=&quot;/en/posts/aws-13-vpc/&quot;&gt;VPC&lt;/a&gt; and it can reach them, with two things to note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It loses its internet access, unless the subnet goes through a NAT gateway or you use &lt;a href=&quot;/en/posts/aws-14-vpc-connectivity/&quot;&gt;endpoints&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A thousand environments can open a thousand connections to the database. This is what &lt;a href=&quot;/en/posts/aws-08-rds-aurora/&quot;&gt;RDS Proxy&lt;/a&gt; solves, by reusing a few connections.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;code-at-the-edge&quot; tabindex=&quot;-1&quot;&gt;Code at the edge &lt;a class=&quot;heading-anchor&quot; href=&quot;#code-at-the-edge&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We mentioned two ways of running short code on &lt;a href=&quot;/en/posts/aws-12-cloudfront-global-accelerator/&quot;&gt;CloudFront&lt;/a&gt;. Here&#39;s the difference:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;CloudFront Functions&lt;/th&gt;
&lt;th&gt;Lambda@Edge&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Languages&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;td&gt;Node.js and Python&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Duration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Under a millisecond&lt;/td&gt;
&lt;td&gt;Up to 30 seconds on origin events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Network access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Events&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Viewer request and response&lt;/td&gt;
&lt;td&gt;Those, plus origin request and response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Good for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Redirects, headers and cache keys&lt;/td&gt;
&lt;td&gt;Heavier logic and calling other services&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;amazon-dynamodb&quot; tabindex=&quot;-1&quot;&gt;Amazon DynamoDB &lt;a class=&quot;heading-anchor&quot; href=&quot;#amazon-dynamodb&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Lambda scales in seconds to thousands of copies, and a traditional database doesn&#39;t like that. &lt;strong&gt;DynamoDB&lt;/strong&gt; is a serverless key-value database: no servers, no connections to manage, millisecond responses at any size, and data replicated across several Availability Zones automatically.&lt;/p&gt;
&lt;h3 id=&quot;tables-items-and-keys&quot; tabindex=&quot;-1&quot;&gt;Tables, items and keys &lt;a class=&quot;heading-anchor&quot; href=&quot;#tables-items-and-keys&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A table contains &lt;strong&gt;items&lt;/strong&gt;, each with &lt;strong&gt;attributes&lt;/strong&gt;, and two items don&#39;t need to have the same attributes. The maximum size of an item is 400 KB. What&#39;s fixed is the &lt;strong&gt;primary key&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;customer&lt;/code&gt; (partition key)&lt;/th&gt;
&lt;th&gt;&lt;code&gt;order_id&lt;/code&gt; (sort key)&lt;/th&gt;
&lt;th&gt;&lt;code&gt;total&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;status&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;coupon&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;sara&lt;/td&gt;
&lt;td&gt;1001&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;shipped&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sara&lt;/td&gt;
&lt;td&gt;1002&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;new&lt;/td&gt;
&lt;td&gt;SAVE10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;omar&lt;/td&gt;
&lt;td&gt;1003&lt;/td&gt;
&lt;td&gt;75&lt;/td&gt;
&lt;td&gt;new&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Partition key:&lt;/strong&gt; decides where the item is stored. Choose one with many varied values, so that the load spreads out.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sort key:&lt;/strong&gt; optional, and it orders items sharing the same partition key, so you can ask for &amp;quot;Sara&#39;s latest orders&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the big difference from &lt;a href=&quot;/en/posts/aws-10-choosing-database/&quot;&gt;relational databases&lt;/a&gt;: there are no joins, and you fetch items by their key. So &lt;strong&gt;start from your queries&lt;/strong&gt; and design the table to suit them. If you need to query by another attribute, such as &lt;code&gt;status&lt;/code&gt;, add a &lt;strong&gt;global secondary index&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;capacity-modes&quot; tabindex=&quot;-1&quot;&gt;Capacity modes &lt;a class=&quot;heading-anchor&quot; href=&quot;#capacity-modes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;On-demand&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Scales by itself, and you pay per request&lt;/td&gt;
&lt;td&gt;Unknown or changing load; start here&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Provisioned&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You set reads and writes per second, optionally with auto scaling&lt;/td&gt;
&lt;td&gt;Steady, predictable load, which comes out cheaper&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Provisioned capacity is counted in units. One &lt;strong&gt;read capacity unit (RCU)&lt;/strong&gt; is one strongly consistent read per second of an item up to 4 KB, or two eventually consistent ones. One &lt;strong&gt;write capacity unit (WCU)&lt;/strong&gt; is one write per second of an item up to 1 KB. So reading 80 items of 3 KB per second with strong consistency needs 80 RCUs, and writing 100 items of 512 bytes per second needs 100 WCUs.&lt;/p&gt;
&lt;h3 id=&quot;additions-worth-knowing&quot; tabindex=&quot;-1&quot;&gt;Additions worth knowing &lt;a class=&quot;heading-anchor&quot; href=&quot;#additions-worth-knowing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DAX&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A cache in front of the table, taking reads from milliseconds to microseconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Streams&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A log of every change, kept for 24 hours, which can trigger Lambda&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Global Tables&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Copies in several Regions, all accepting writes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TTL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatically deletes items after a time you set, such as old sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Point-in-time recovery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Restores the table to any second within the last 1 to 35 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;S3 integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Exports a table to S3 for analysis, or imports from S3 into a new table&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Where does &lt;strong&gt;DAX&lt;/strong&gt; stand against &lt;a href=&quot;/en/posts/aws-09-elasticache/&quot;&gt;ElastiCache&lt;/a&gt;? DAX is a transparent cache for DynamoDB, with almost no code change. ElastiCache is more general, for example for storing calculated results that your application manages itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Global Tables&lt;/strong&gt; are eventually consistent by default, so a write in one Region reaches the others after a short delay. If you need a read in any Region to see the latest write, there&#39;s a &lt;strong&gt;strong consistency&lt;/strong&gt; mode, which needs exactly three Regions and has some limitations.&lt;/p&gt;
&lt;h2 id=&quot;api-gateway-the-front-door&quot; tabindex=&quot;-1&quot;&gt;API Gateway: the front door &lt;a class=&quot;heading-anchor&quot; href=&quot;#api-gateway-the-front-door&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A function has no web address by default. &lt;strong&gt;API Gateway&lt;/strong&gt; receives the request over HTTPS and passes it on to the function, handling on your behalf what you don&#39;t want to write yourself: authentication, throttling, versions and more.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 118&quot; role=&quot;img&quot; aria-labelledby=&quot;api-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;api-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;28&quot; width=&quot;126&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;83&quot; y=&quot;64&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;App&lt;/text&gt;
&lt;rect x=&quot;178&quot; y=&quot;28&quot; width=&quot;126&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;241&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;API Gateway&lt;/text&gt;
&lt;text x=&quot;241&quot; y=&quot;74&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Auth, throttling&lt;/text&gt;
&lt;rect x=&quot;336&quot; y=&quot;28&quot; width=&quot;126&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;399&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Lambda&lt;/text&gt;
&lt;text x=&quot;399&quot; y=&quot;74&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Your logic&lt;/text&gt;
&lt;rect x=&quot;494&quot; y=&quot;28&quot; width=&quot;126&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;557&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;DynamoDB&lt;/text&gt;
&lt;text x=&quot;557&quot; y=&quot;74&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Your data&lt;/text&gt;
&lt;line x1=&quot;146&quot; y1=&quot;59&quot; x2=&quot;176&quot; y2=&quot;59&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#api-arrow)&quot;/&gt;
&lt;line x1=&quot;304&quot; y1=&quot;59&quot; x2=&quot;334&quot; y2=&quot;59&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#api-arrow)&quot;/&gt;
&lt;line x1=&quot;462&quot; y1=&quot;59&quot; x2=&quot;492&quot; y2=&quot;59&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#api-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;api-caption&quot;&gt;The classic serverless API: every part scales with requests, and with no traffic you pay almost nothing.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Suits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTTP API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Most APIs: simpler and cheaper, with a fixed 30-second limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;REST API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;More features: caching, API keys and request validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WebSocket API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Two-way connections, such as chat&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A REST API also comes in three kinds: &lt;strong&gt;Edge-optimized&lt;/strong&gt; through CloudFront for users around the world, &lt;strong&gt;Regional&lt;/strong&gt; for users close by, and &lt;strong&gt;Private&lt;/strong&gt; for inside your VPC only.&lt;/p&gt;
&lt;p&gt;Behind it you can put a Lambda function, any HTTP address, or an AWS service directly. For instance, it can send a request straight to SQS, with no function in between. And for a single simple endpoint, Lambda also offers &lt;strong&gt;function URLs&lt;/strong&gt;: a direct HTTPS link to the function, without these extras.&lt;/p&gt;
&lt;h3 id=&quot;who-can-call-your-api&quot; tabindex=&quot;-1&quot;&gt;Who can call your API? &lt;a class=&quot;heading-anchor&quot; href=&quot;#who-can-call-your-api&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Suits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IAM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your own services and applications inside AWS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cognito&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your application&#39;s users; we&#39;ll cover it in the next part&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lambda authorizer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your own logic, such as a token from another system&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;aside class=&quot;callout callout-warning&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-alert&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 4l9 16H3L12 4z&quot;/&gt;&lt;path d=&quot;M12 10v4M12 17h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Watch the time and size limits&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A REST API waits 29 seconds for a response by default, and you can raise this on Regional and Private APIs, though that may lower your request quota. Both types have a 10 MB payload limit, so have large files go directly to S3 with &lt;a href=&quot;/en/posts/aws-17-s3-security/&quot;&gt;signed links&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h3 id=&quot;throttling&quot; tabindex=&quot;-1&quot;&gt;Throttling &lt;a class=&quot;heading-anchor&quot; href=&quot;#throttling&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;API Gateway protects what&#39;s behind it by limiting requests, and it applies its limits from the most specific down: per client, per method, then for the whole account in the Region. Past the limit, the client gets a &lt;code&gt;429&lt;/code&gt; and can retry. On a REST API, &lt;strong&gt;usage plans&lt;/strong&gt; with API keys give each client its own rate and quota, which suits an API you sell.&lt;/p&gt;
&lt;h2 id=&quot;hands-on-a-working-api&quot; tabindex=&quot;-1&quot;&gt;Hands-on: a working API &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-a-working-api&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll build a page visit counter from the diagram&#39;s three pieces. Everything here falls within the free tier for an experiment like this. From CloudShell, create the table:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws dynamodb create-table --table-name series-visits &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --attribute-definitions &lt;span class=&quot;token assign-left variable&quot;&gt;AttributeName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;page,AttributeType&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;S &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --key-schema &lt;span class=&quot;token assign-left variable&quot;&gt;AttributeName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;page,KeyType&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;HASH &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --billing-mode PAY_PER_REQUEST &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; TableDescription.TableStatus

aws dynamodb &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt; table-exists --table-name series-visits

&lt;span class=&quot;token assign-left variable&quot;&gt;TABLE_ARN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws dynamodb describe-table --table-name series-visits &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Table.TableArn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Give the function a role that can write logs and update this table only:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; trust.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [{
    &quot;Effect&quot;: &quot;Allow&quot;,
    &quot;Principal&quot;: {&quot;Service&quot;: &quot;lambda.amazonaws.com&quot;},
    &quot;Action&quot;: &quot;sts:AssumeRole&quot;
  }]
}
EOF&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;ROLE_ARN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws iam create-role --role-name series-visits-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --assume-role-policy-document file://trust.json &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Role.Arn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws iam attach-role-policy --role-name series-visits-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

aws iam put-role-policy --role-name series-visits-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-name table-access --policy-document &lt;span class=&quot;token string&quot;&gt;&quot;{
    &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Version&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;: &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;2012-10-17&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;,
    &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Statement&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;: [{
      &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Effect&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;: &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Allow&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;,
      &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Action&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;: &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;dynamodb:UpdateItem&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;,
      &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;Resource&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;: &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$TABLE_ARN&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;
    }]
  }&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Write the function. It adds one to the counter for the requested path, and an update like this is safe even with simultaneous requests:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; app.py &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
import json
import os
import boto3

table = boto3.resource(&quot;dynamodb&quot;).Table(os.environ[&quot;TABLE&quot;])

def handler(event, context):
    page = event.get(&quot;rawPath&quot;, &quot;/&quot;)
    result = table.update_item(
        Key={&quot;page&quot;: page},
        UpdateExpression=&quot;ADD visits :one&quot;,
        ExpressionAttributeValues={&quot;:one&quot;: 1},
        ReturnValues=&quot;UPDATED_NEW&quot;,
    )
    visits = int(result[&quot;Attributes&quot;][&quot;visits&quot;])
    return {
        &quot;statusCode&quot;: 200,
        &quot;headers&quot;: {&quot;content-type&quot;: &quot;application/json&quot;},
        &quot;body&quot;: json.dumps({&quot;page&quot;: page, &quot;visits&quot;: visits}),
    }
EOF&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;zip&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-q&lt;/span&gt; function.zip app.py&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Create the function. A new role takes a few seconds to take effect, so if you get an error about the role, wait a little and repeat the command:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;FN_ARN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws lambda create-function --function-name series-visits &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--runtime&lt;/span&gt; python3.13 &lt;span class=&quot;token parameter variable&quot;&gt;--handler&lt;/span&gt; app.handler &lt;span class=&quot;token parameter variable&quot;&gt;--role&lt;/span&gt; $ROLE_ARN &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --zip-file fileb://function.zip &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--environment&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Variables={TABLE=series-visits}&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; FunctionArn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws lambda &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt; function-active-v2 --function-name series-visits&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Now the front door. This command creates an HTTP API that sends every path to the function, and then we allow it to invoke the function:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;API_ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws apigatewayv2 create-api &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; series-visits &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --protocol-type HTTP &lt;span class=&quot;token parameter variable&quot;&gt;--target&lt;/span&gt; $FN_ARN &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; ApiId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;ACCOUNT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws sts get-caller-identity &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Account &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws lambda add-permission --function-name series-visits &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --statement-id api-gateway &lt;span class=&quot;token parameter variable&quot;&gt;--action&lt;/span&gt; lambda:InvokeFunction &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--principal&lt;/span&gt; apigateway.amazonaws.com &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --source-arn &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:execute-api:&lt;span class=&quot;token variable&quot;&gt;$AWS_REGION&lt;/span&gt;:&lt;span class=&quot;token variable&quot;&gt;$ACCOUNT&lt;/span&gt;:&lt;span class=&quot;token variable&quot;&gt;$API_ID&lt;/span&gt;/*&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Statement &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /dev/null

&lt;span class=&quot;token assign-left variable&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws apigatewayv2 get-api --api-id $API_ID &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; ApiEndpoint &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$URL&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Try it. You can also open the link in your browser:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$URL&lt;/span&gt;/home&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$URL&lt;/span&gt;/home&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$URL&lt;/span&gt;/about&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The counter goes up: &lt;code&gt;home&lt;/code&gt; reaches 2 and &lt;code&gt;about&lt;/code&gt; is at 1. Look at the data in the table:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws dynamodb scan --table-name series-visits &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Items[].[page.S,visits.N]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; table&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Finally, see the cold start in the function&#39;s logs:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws logs &lt;span class=&quot;token function&quot;&gt;tail&lt;/span&gt; /aws/lambda/series-visits &lt;span class=&quot;token parameter variable&quot;&gt;--since&lt;/span&gt; 10m &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; REPORT&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Only the first request has an &lt;code&gt;Init Duration&lt;/code&gt; field, which is the time taken to set up the environment, and the requests after it are much faster. If the logs are empty, wait a few seconds and try again.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A resource that isn&#39;t being used costs nothing here, which is the point of serverless. But clean up anyway, including the role and its permissions:&lt;/p&gt;
&lt;/aside&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws apigatewayv2 delete-api --api-id &lt;span class=&quot;token variable&quot;&gt;$API_ID&lt;/span&gt;
aws lambda delete-function --function-name series-visits
aws dynamodb delete-table --table-name series-visits &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; TableDescription.TableStatus
aws logs delete-log-group --log-group-name /aws/lambda/series-visits

aws iam delete-role-policy --role-name series-visits-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-name table-access
aws iam detach-role-policy --role-name series-visits-role &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
aws iam delete-role --role-name series-visits-role&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Serverless&lt;/strong&gt; means you write code and data, and pay only for use.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lambda&lt;/strong&gt; runs up to 15 minutes, and you pay per request and per GB-second.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cold starts&lt;/strong&gt; are eased with Provisioned Concurrency or SnapStart, and &lt;strong&gt;reserved concurrency&lt;/strong&gt; protects functions from each other.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DynamoDB&lt;/strong&gt; fetches items by key, so design the table around your queries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API Gateway&lt;/strong&gt; is the front door, handling authentication and throttling; start with an HTTP API.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 6&lt;/p&gt;
&lt;p&gt;A Lambda function is attached to a VPC so it can reach a private RDS database. That works, but now its calls to a payment provider on the internet time out. What fixes this?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Attaching the function to a public subnet&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Raising the function&#39;s timeout&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Routing the function&#39;s private subnet through a NAT gateway&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Putting RDS Proxy between the function and the database&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once attached to a VPC, a function loses its internet access unless its subnet goes through a NAT gateway.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; A public subnet gives the function neither internet access nor a public address.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; There&#39;s no path to the internet, so more time won&#39;t help.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This handles database connections, and the problem is the path out.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#lambda-inside-a-vpc&quot;&gt;Lambda inside a VPC&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc-internet.html&quot;&gt;Enable internet access for VPC-connected Lambda Event Functions&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 6&lt;/p&gt;
&lt;p&gt;An orders table has &lt;code&gt;customer&lt;/code&gt; as its partition key and &lt;code&gt;order_id&lt;/code&gt; as its sort key. The team now needs all orders whose &lt;code&gt;status&lt;/code&gt; is &lt;code&gt;new&lt;/code&gt;, quickly and often. What should it do?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Scan the whole table for each request&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Join the table with a &lt;code&gt;status&lt;/code&gt; table&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Put DAX in front of the table&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Add a global secondary index on &lt;code&gt;status&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A global secondary index organizes the data by a different key, so you can query by &lt;code&gt;status&lt;/code&gt; directly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This reads every item each time, so it gets slower and costlier as the table grows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; DynamoDB has no joins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This speeds up reads you can already do, and doesn&#39;t add a new way to query.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#tables-items-and-keys&quot;&gt;Tables, items and keys&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html&quot;&gt;Using Global Secondary Indexes in DynamoDB&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 6&lt;/p&gt;
&lt;p&gt;A product page reads the same DynamoDB items millions of times a day. The team wants reads to take microseconds, with the &lt;strong&gt;fewest code changes&lt;/strong&gt;. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;DynamoDB Accelerator (DAX)&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;ElastiCache, with the application managing the cache&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;DynamoDB Global Tables&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;DynamoDB Streams&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;DAX is a cache in front of the table that works with DynamoDB&#39;s API, so it takes only minimal changes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This can be fast too, but your application has to manage what goes in and out of the cache.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This places copies in several Regions, and doesn&#39;t bring reads down to microseconds.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This is a log of changes, and doesn&#39;t speed up reads.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#additions-worth-knowing&quot;&gt;Additions worth knowing&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DAX.html&quot;&gt;In-memory acceleration with DynamoDB Accelerator (DAX)&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 6&lt;/p&gt;
&lt;p&gt;A company is selling access to its API. It needs API keys for each customer, throttling per client, and cached responses. Which option fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;HTTP API&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;REST API&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;WebSocket API&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A Lambda function URL&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;REST APIs have all of these. HTTP APIs are simpler and cheaper because they leave such features out.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This has neither API keys nor caching.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This is for two-way connections, such as chat.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This is a direct link to a function, without any of these extras.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#api-gateway-the-front-door&quot;&gt;API Gateway: the front door&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html&quot;&gt;Choose between REST APIs and HTTP APIs&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 6&lt;/p&gt;
&lt;p&gt;A report function sometimes uses up the Region&#39;s whole concurrency limit, and the checkout function starts returning &lt;code&gt;429&lt;/code&gt;. Checkout also has to answer with steady, very low latency. Which &lt;strong&gt;two&lt;/strong&gt; settings fit the checkout function? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Reserved concurrency&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;SnapStart&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Provisioned Concurrency&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;More &lt;code&gt;/tmp&lt;/code&gt; storage&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Less memory&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A + C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Reserved concurrency sets aside a share for checkout that no other function can take, and Provisioned Concurrency keeps environments ready so they have no cold start.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This lowers startup time without guaranteeing to remove it, and can&#39;t be combined with Provisioned Concurrency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This adds temporary disk space, and has nothing to do with either problem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E:&lt;/strong&gt; CPU rises with memory, so this would make responses slower.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#concurrency&quot;&gt;Concurrency&lt;/a&gt; and &lt;a href=&quot;#cold-starts&quot;&gt;Cold starts&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html&quot;&gt;Configuring reserved concurrency for an Event Function&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/provisioned-concurrency.html&quot;&gt;Configuring provisioned concurrency for an Event Function&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 6 of 6&lt;/p&gt;
&lt;p&gt;An application reads 50 items per second from a DynamoDB table in provisioned mode. Each item is 6 KB, and the reads must be strongly consistent. How many read capacity units does it need?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;25&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;300&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One RCU covers one strongly consistent read per second of up to 4 KB, so a 6 KB item needs two. Fifty reads per second need 100.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This counts each read as half a unit, which doesn&#39;t cover a 6 KB item.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This would be enough if the same reads were eventually consistent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This multiplies by the item&#39;s size, while units are counted per 4 KB.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#capacity-modes&quot;&gt;Capacity modes&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/provisioned-capacity-mode.html&quot;&gt;DynamoDB provisioned capacity mode&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;You now have the building blocks. How do you build a complete application from them, with users, long workflows and events flowing between the services? That&#39;s what we&#39;ll cover in &lt;a href=&quot;/en/posts/aws-22-serverless-design/&quot;&gt;&lt;strong&gt;part twenty-two&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Containers: ECS, Fargate and EKS</title>
    <link href="https://blog.sultanops.com/en/posts/aws-20-ecs-fargate-eks/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-20-ecs-fargate-eks/</id>
    <summary>What a container is and how it differs from a virtual machine, storing images in ECR, running them with ECS on Fargate, the difference between the two IAM roles, when to choose EKS, and a hands-on where a service replaces a stopped task.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-19-sqs-sns-kinesis/&quot;&gt;part nineteen&lt;/a&gt; we separated the services from each other. Each service still needs somewhere to run, and on an EC2 server that means an image, updates, libraries and the famous sentence: &amp;quot;it works on my machine&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Containers&lt;/strong&gt; solve this: you package the application with everything it needs in one unit, and it runs the same way on your laptop and in production.&lt;/p&gt;
&lt;h2 id=&quot;whats-a-container&quot; tabindex=&quot;-1&quot;&gt;What&#39;s a container? &lt;a class=&quot;heading-anchor&quot; href=&quot;#whats-a-container&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A container is an isolated process with its own files and libraries, which shares the host&#39;s operating system instead of carrying its own.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 220&quot; role=&quot;img&quot; aria-labelledby=&quot;vmcontainer-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;vmcontainer-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;text x=&quot;165&quot; y=&quot;22&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Virtual machines&lt;/text&gt;
&lt;rect x=&quot;30&quot; y=&quot;36&quot; width=&quot;130&quot; height=&quot;36&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;95&quot; y=&quot;59&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;App&lt;/text&gt;
&lt;rect x=&quot;170&quot; y=&quot;36&quot; width=&quot;130&quot; height=&quot;36&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;235&quot; y=&quot;59&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;App&lt;/text&gt;
&lt;rect x=&quot;30&quot; y=&quot;80&quot; width=&quot;130&quot; height=&quot;36&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;95&quot; y=&quot;103&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Full OS&lt;/text&gt;
&lt;rect x=&quot;170&quot; y=&quot;80&quot; width=&quot;130&quot; height=&quot;36&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;235&quot; y=&quot;103&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Full OS&lt;/text&gt;
&lt;rect x=&quot;30&quot; y=&quot;124&quot; width=&quot;270&quot; height=&quot;36&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;165&quot; y=&quot;147&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Hypervisor&lt;/text&gt;
&lt;rect x=&quot;30&quot; y=&quot;168&quot; width=&quot;270&quot; height=&quot;36&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;165&quot; y=&quot;191&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Hardware&lt;/text&gt;
&lt;text x=&quot;475&quot; y=&quot;22&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Containers&lt;/text&gt;
&lt;rect x=&quot;340&quot; y=&quot;36&quot; width=&quot;85&quot; height=&quot;36&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;382.5&quot; y=&quot;59&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;App&lt;/text&gt;
&lt;rect x=&quot;433&quot; y=&quot;36&quot; width=&quot;85&quot; height=&quot;36&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;475.5&quot; y=&quot;59&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;App&lt;/text&gt;
&lt;rect x=&quot;525&quot; y=&quot;36&quot; width=&quot;85&quot; height=&quot;36&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;567.5&quot; y=&quot;59&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;App&lt;/text&gt;
&lt;rect x=&quot;340&quot; y=&quot;80&quot; width=&quot;270&quot; height=&quot;36&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;475&quot; y=&quot;103&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Container engine&lt;/text&gt;
&lt;rect x=&quot;340&quot; y=&quot;124&quot; width=&quot;270&quot; height=&quot;36&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;475&quot; y=&quot;147&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Shared OS&lt;/text&gt;
&lt;rect x=&quot;340&quot; y=&quot;168&quot; width=&quot;270&quot; height=&quot;36&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;475&quot; y=&quot;191&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Hardware&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;vmcontainer-caption&quot;&gt;Each virtual machine carries a full operating system. Containers share the host&#39;s system, so they are lighter and start in seconds.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Virtual machine&lt;/th&gt;
&lt;th&gt;Container&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Contains&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A full operating system and the application&lt;/td&gt;
&lt;td&gt;The application and its libraries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gigabytes&lt;/td&gt;
&lt;td&gt;Often megabytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Startup&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Minutes&lt;/td&gt;
&lt;td&gt;Seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Isolation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stronger, with a separate system&lt;/td&gt;
&lt;td&gt;Lighter, with a shared kernel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;image-container-and-registry&quot; tabindex=&quot;-1&quot;&gt;Image, container and registry &lt;a class=&quot;heading-anchor&quot; href=&quot;#image-container-and-registry&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Three words you&#39;ll keep hearing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Image:&lt;/strong&gt; a read-only package of the application and its libraries, like a recipe.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Container:&lt;/strong&gt; a running copy of an image. One image can run as a thousand containers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Registry:&lt;/strong&gt; where images are stored, such as Docker Hub or Amazon ECR.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The most common tool for building images is &lt;strong&gt;Docker&lt;/strong&gt;. You write what the image contains in a &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;dockerfile&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-dockerfile&quot;&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; nginx:alpine&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;COPY&lt;/span&gt; index.html /usr/share/nginx/html/&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Then you build it, try it on your machine, and push it to a registry:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; build &lt;span class=&quot;token parameter variable&quot;&gt;-t&lt;/span&gt; shop &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; run &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8080&lt;/span&gt;:80 shop
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; push &lt;span class=&quot;token number&quot;&gt;123456789012&lt;/span&gt;.dkr.ecr.us-east-1.amazonaws.com/shop&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;amazon-ecr-your-images-home&quot; tabindex=&quot;-1&quot;&gt;Amazon ECR: your images&#39; home &lt;a class=&quot;heading-anchor&quot; href=&quot;#amazon-ecr-your-images-home&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;ECR&lt;/strong&gt; (Elastic Container Registry) is AWS&#39;s image registry, with storage on S3 behind the scenes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Private repositories:&lt;/strong&gt; access to them goes through &lt;a href=&quot;/en/posts/aws-02-iam/&quot;&gt;IAM&lt;/a&gt;, so a server or task needs permission to pull.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Public repositories:&lt;/strong&gt; anyone can pull from them, through the ECR Public Gallery.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extras:&lt;/strong&gt; image scanning for vulnerabilities, versions with tags, and lifecycle rules that delete old images.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;amazon-ecs-awss-way-of-running-containers&quot; tabindex=&quot;-1&quot;&gt;Amazon ECS: AWS&#39;s way of running containers &lt;a class=&quot;heading-anchor&quot; href=&quot;#amazon-ecs-awss-way-of-running-containers&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;ECS&lt;/strong&gt; (Elastic Container Service) takes your images and runs them, keeps them running, and places them behind a load balancer. It&#39;s AWS&#39;s own service, simpler than Kubernetes, and the service itself has no extra charge. You pay for the capacity it runs on.&lt;/p&gt;
&lt;p&gt;Four terms cover the whole service:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Comparable to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cluster&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A logical group that tasks run in&lt;/td&gt;
&lt;td&gt;Your fleet of servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Task definition&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A recipe: the image, CPU, memory, ports and roles&lt;/td&gt;
&lt;td&gt;A launch template&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Task&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One or more running containers from that recipe&lt;/td&gt;
&lt;td&gt;A server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Service&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Keeps a set number of tasks running, and replaces failed ones&lt;/td&gt;
&lt;td&gt;An Auto Scaling group&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 256&quot; role=&quot;img&quot; aria-labelledby=&quot;ecs-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;ecs-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;98&quot; width=&quot;110&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;75&quot; y=&quot;123&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;ALB&lt;/text&gt;
&lt;text x=&quot;75&quot; y=&quot;143&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Load balancer&lt;/text&gt;
&lt;rect x=&quot;170&quot; y=&quot;14&quot; width=&quot;450&quot; height=&quot;228&quot; rx=&quot;14&quot; fill=&quot;none&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;6 6&quot;/&gt;
&lt;text x=&quot;395&quot; y=&quot;38&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;ECS cluster&lt;/text&gt;
&lt;text x=&quot;395&quot; y=&quot;60&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Service: keep 3 tasks running&lt;/text&gt;
&lt;rect x=&quot;190&quot; y=&quot;74&quot; width=&quot;200&quot; height=&quot;152&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;290&quot; y=&quot;94&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Availability Zone A&lt;/text&gt;
&lt;rect x=&quot;205&quot; y=&quot;106&quot; width=&quot;170&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;290&quot; y=&quot;136&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Task 1&lt;/text&gt;
&lt;rect x=&quot;205&quot; y=&quot;164&quot; width=&quot;170&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;290&quot; y=&quot;194&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Task 2&lt;/text&gt;
&lt;rect x=&quot;400&quot; y=&quot;74&quot; width=&quot;200&quot; height=&quot;152&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;500&quot; y=&quot;94&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Availability Zone B&lt;/text&gt;
&lt;rect x=&quot;415&quot; y=&quot;106&quot; width=&quot;170&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;500&quot; y=&quot;136&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Task 3&lt;/text&gt;
&lt;rect x=&quot;415&quot; y=&quot;164&quot; width=&quot;170&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-dasharray=&quot;5 5&quot;/&gt;
&lt;text x=&quot;500&quot; y=&quot;194&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;New when load grows&lt;/text&gt;
&lt;line x1=&quot;130&quot; y1=&quot;128&quot; x2=&quot;188&quot; y2=&quot;128&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#ecs-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;ecs-caption&quot;&gt;The service keeps the number of tasks you asked for across Availability Zones, and the load balancer sends visitors to whichever tasks are healthy.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;who-runs-the-containers&quot; tabindex=&quot;-1&quot;&gt;Who runs the containers? &lt;a class=&quot;heading-anchor&quot; href=&quot;#who-runs-the-containers&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Containers need computing capacity, and you have three options:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Who manages the servers&lt;/th&gt;
&lt;th&gt;Suits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fargate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS entirely, with no servers to see&lt;/td&gt;
&lt;td&gt;Most applications; start here&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Managed Instances&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS manages them, and you choose the instance types&lt;/td&gt;
&lt;td&gt;Needing GPUs or specific instances without the management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EC2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You, through an Auto Scaling group&lt;/td&gt;
&lt;td&gt;Full control, or reducing the cost of steady load&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;With &lt;strong&gt;Fargate&lt;/strong&gt; you state the CPU and memory for a task, and pay for those while it runs. &lt;strong&gt;Fargate Spot&lt;/strong&gt; cuts the price sharply for tasks that can tolerate interruption, in the same way as &lt;a href=&quot;/en/posts/aws-04-ec2-pricing-networking/&quot;&gt;Spot&lt;/a&gt; servers.&lt;/p&gt;
&lt;h3 id=&quot;two-iam-roles-and-confusing-them-is-a-classic&quot; tabindex=&quot;-1&quot;&gt;Two IAM roles, and confusing them is a classic &lt;a class=&quot;heading-anchor&quot; href=&quot;#two-iam-roles-and-confusing-them-is-a-classic&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Every Fargate task can have two roles, and they do different jobs:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Who uses it&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Task execution role&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ECS itself, to prepare the task&lt;/td&gt;
&lt;td&gt;Pulling the image from ECR and sending logs to CloudWatch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Task role&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your code inside the container&lt;/td&gt;
&lt;td&gt;Reading from S3 or writing to DynamoDB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If the task fails at startup with a pull error, look at the execution role. If your code gets &lt;code&gt;AccessDenied&lt;/code&gt; while it&#39;s running, look at the task role. And give each service its own task role, not one shared role.&lt;/p&gt;
&lt;h3 id=&quot;network-and-load-balancing&quot; tabindex=&quot;-1&quot;&gt;Network and load balancing &lt;a class=&quot;heading-anchor&quot; href=&quot;#network-and-load-balancing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On Fargate each task gets its own network interface and private IP, so it has its own &lt;strong&gt;security group&lt;/strong&gt; like a server. Put an &lt;a href=&quot;/en/posts/aws-06-load-balancers/&quot;&gt;Application Load Balancer&lt;/a&gt; in front of the service, and it registers new tasks automatically and removes failed ones. It suits most web applications, and you&#39;d choose a Network Load Balancer for very high throughput or fixed IP addresses.&lt;/p&gt;
&lt;h3 id=&quot;storage&quot; tabindex=&quot;-1&quot;&gt;Storage &lt;a class=&quot;heading-anchor&quot; href=&quot;#storage&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A container&#39;s disk disappears with it. To share files between tasks, mount &lt;a href=&quot;/en/posts/aws-05-ec2-storage/&quot;&gt;EFS&lt;/a&gt;, which works on both Fargate and EC2. And for anything that matters, store it outside the container in S3 or a database.&lt;/p&gt;
&lt;h3 id=&quot;scaling&quot; tabindex=&quot;-1&quot;&gt;Scaling &lt;a class=&quot;heading-anchor&quot; href=&quot;#scaling&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Service Auto Scaling&lt;/strong&gt; changes the number of tasks based on average CPU or memory, requests per task from the load balancer, or a schedule. The policies are the same ones we saw in &lt;a href=&quot;/en/posts/aws-07-auto-scaling/&quot;&gt;part seven&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On Fargate that&#39;s all you need. With EC2 there&#39;s a second layer, because you need servers for the new tasks to land on. A &lt;strong&gt;capacity provider&lt;/strong&gt; links the service to an Auto Scaling group and adds servers when tasks need them.&lt;/p&gt;
&lt;h3 id=&quot;not-just-web-services&quot; tabindex=&quot;-1&quot;&gt;Not just web services &lt;a class=&quot;heading-anchor&quot; href=&quot;#not-just-web-services&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Tasks don&#39;t have to stay running. Three common patterns:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reacting to an event&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A file lands in S3, EventBridge starts a Fargate task to process it, and it stops when done&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scheduled work&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;EventBridge Scheduler starts a task every night for a batch job&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Queue workers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A service pulls from &lt;a href=&quot;/en/posts/aws-19-sqs-sns-kinesis/&quot;&gt;SQS&lt;/a&gt;, and scales by the number of messages waiting&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;ecs-express-mode-the-short-way&quot; tabindex=&quot;-1&quot;&gt;ECS Express Mode: the short way &lt;a class=&quot;heading-anchor&quot; href=&quot;#ecs-express-mode-the-short-way&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Just want a web application from an image, without setting up every piece? &lt;strong&gt;ECS Express Mode&lt;/strong&gt; takes an image and two roles, and creates the Fargate service, load balancer, health checks, scaling and a link. All of it stays in your account, so you can customize it later.&lt;/p&gt;
&lt;aside class=&quot;callout callout-note&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-info&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;circle cx=&quot;12&quot; cy=&quot;12&quot; r=&quot;8.5&quot;/&gt;&lt;path d=&quot;M12 11v5M12 8h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;What about App Runner?&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;You may read about &lt;strong&gt;AWS App Runner&lt;/strong&gt;, which did something similar. It stopped accepting new customers on April 30, 2026, though it keeps running for existing customers, and AWS points new customers to ECS Express Mode.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;amazon-eks-kubernetes&quot; tabindex=&quot;-1&quot;&gt;Amazon EKS: Kubernetes &lt;a class=&quot;heading-anchor&quot; href=&quot;#amazon-eks-kubernetes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt; is an open-source system for running containers, widely used across clouds and data centers. &lt;strong&gt;EKS&lt;/strong&gt; (Elastic Kubernetes Service) runs its &lt;strong&gt;control plane&lt;/strong&gt; for you, across several Availability Zones, at $0.10 per hour per cluster for versions under standard support, on top of the capacity. A version that&#39;s past that period costs $0.60 per hour.&lt;/p&gt;
&lt;p&gt;Terms differ from ECS: a task is a &lt;strong&gt;Pod&lt;/strong&gt;, and a server is a &lt;strong&gt;Node&lt;/strong&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Node option&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EKS Auto Mode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS provisions, updates and scales the nodes; it&#39;s what AWS recommends going forward&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Managed node groups&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS creates and updates the servers, and you choose them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Self-managed nodes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You handle everything, for special requirements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fargate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Each Pod runs in isolation without nodes; still available, though Auto Mode is preferred&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For storage, EKS uses &lt;strong&gt;CSI drivers&lt;/strong&gt; to mount EBS, EFS or FSx.&lt;/p&gt;
&lt;h3 id=&quot;ecs-or-eks&quot; tabindex=&quot;-1&quot;&gt;ECS or EKS? &lt;a class=&quot;heading-anchor&quot; href=&quot;#ecs-or-eks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ECS&lt;/th&gt;
&lt;th&gt;EKS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Complexity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fewer concepts, and quick to learn&lt;/td&gt;
&lt;td&gt;A big system with a lot to learn&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Portability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS only&lt;/td&gt;
&lt;td&gt;The same tools work elsewhere&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ecosystem&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Close integration with AWS&lt;/td&gt;
&lt;td&gt;A huge open-source ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost of the service itself&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Per hour per cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Choose it if&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You&#39;re starting out, and your work is on AWS&lt;/td&gt;
&lt;td&gt;Your team knows Kubernetes, or you run across several clouds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If nothing is pushing you toward Kubernetes, start with &lt;strong&gt;ECS on Fargate&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;containers-on-your-own-servers&quot; tabindex=&quot;-1&quot;&gt;Containers on your own servers &lt;a class=&quot;heading-anchor&quot; href=&quot;#containers-on-your-own-servers&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Need the same tools outside AWS, such as in your data center?&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ECS Anywhere&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Registers your own servers or virtual machines in an ECS cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EKS Hybrid Nodes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Adds your own servers as nodes in an EKS cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EKS Anywhere&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Runs Kubernetes clusters on your own infrastructure, for isolated environments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EKS Distro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The Kubernetes components behind EKS, for you to run and support yourself&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;hands-on-a-service-replaces-a-stopped-task&quot; tabindex=&quot;-1&quot;&gt;Hands-on: a service replaces a stopped task &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-a-service-replaces-a-stopped-task&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll run a public Nginx image on Fargate, with no build needed. From CloudShell, create the cluster and write the recipe. An image from a public registry with no logs doesn&#39;t need an execution role:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws ecs create-cluster --cluster-name series-cluster &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; cluster.status

&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; task.json &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;
{
  &quot;family&quot;: &quot;web&quot;,
  &quot;requiresCompatibilities&quot;: [&quot;FARGATE&quot;],
  &quot;networkMode&quot;: &quot;awsvpc&quot;,
  &quot;cpu&quot;: &quot;256&quot;,
  &quot;memory&quot;: &quot;512&quot;,
  &quot;containerDefinitions&quot;: [{
    &quot;name&quot;: &quot;web&quot;,
    &quot;image&quot;: &quot;public.ecr.aws/nginx/nginx:latest&quot;,
    &quot;portMappings&quot;: [{&quot;containerPort&quot;: 80}],
    &quot;essential&quot;: true
  }]
}
EOF&lt;/span&gt;

aws ecs register-task-definition --cli-input-json file://task.json &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; taskDefinition.family&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Prepare the network: the default VPC, a subnet, and a security group that allows port 80 from your CloudShell only:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;VPC&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 describe-vpcs &lt;span class=&quot;token parameter variable&quot;&gt;--filters&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;isDefault,Values&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Vpcs[0].VpcId&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;SUBNET&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 describe-subnets &lt;span class=&quot;token parameter variable&quot;&gt;--filters&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;vpc-id,Values&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;$VPC &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Subnets[0].SubnetId&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;SG&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 create-security-group --group-name series-web &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--description&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Series web task&quot;&lt;/span&gt; --vpc-id $VPC &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; GroupId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
aws ec2 authorize-security-group-ingress --group-id &lt;span class=&quot;token variable&quot;&gt;$SG&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--protocol&lt;/span&gt; tcp &lt;span class=&quot;token parameter variable&quot;&gt;--port&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--cidr&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; https://checkip.amazonaws.com&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;/32

&lt;span class=&quot;token assign-left variable&quot;&gt;NET&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;awsvpcConfiguration={subnets=[&lt;span class=&quot;token variable&quot;&gt;$SUBNET&lt;/span&gt;],securityGroups=[&lt;span class=&quot;token variable&quot;&gt;$SG&lt;/span&gt;],assignPublicIp=ENABLED}&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Run a single task. If this is your first use of ECS and you get an error about the service-linked role, wait a little and repeat the command:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;TASK&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ecs run-task &lt;span class=&quot;token parameter variable&quot;&gt;--cluster&lt;/span&gt; series-cluster --task-definition web &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --launch-type FARGATE --network-configuration &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$NET&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tasks[0].taskArn&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws ecs &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt; tasks-running &lt;span class=&quot;token parameter variable&quot;&gt;--cluster&lt;/span&gt; series-cluster &lt;span class=&quot;token parameter variable&quot;&gt;--tasks&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$TASK&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Get its address and try it:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;ENI&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ecs describe-tasks &lt;span class=&quot;token parameter variable&quot;&gt;--cluster&lt;/span&gt; series-cluster &lt;span class=&quot;token parameter variable&quot;&gt;--tasks&lt;/span&gt; $TASK &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tasks[0].attachments[0].details[?name==&#39;networkInterfaceId&#39;].value&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;IP&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 describe-network-interfaces --network-interface-ids $ENI &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NetworkInterfaces[0].Association.PublicIp&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; http://&lt;span class=&quot;token variable&quot;&gt;$IP&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;title&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;You&#39;ll see &lt;code&gt;&amp;lt;title&amp;gt;Welcome to nginx!&amp;lt;/title&amp;gt;&lt;/code&gt;. Your first container is running, with no server you can see. Now stop it, and it stays stopped, because nothing is looking after it:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws ecs stop-task &lt;span class=&quot;token parameter variable&quot;&gt;--cluster&lt;/span&gt; series-cluster &lt;span class=&quot;token parameter variable&quot;&gt;--task&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$TASK&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; task.lastStatus&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Create a &lt;strong&gt;service&lt;/strong&gt; that keeps one task running:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws ecs create-service &lt;span class=&quot;token parameter variable&quot;&gt;--cluster&lt;/span&gt; series-cluster --service-name web &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --task-definition web --desired-count &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; --launch-type FARGATE &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --network-configuration &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$NET&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; service.status

aws ecs &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt; services-stable &lt;span class=&quot;token parameter variable&quot;&gt;--cluster&lt;/span&gt; series-cluster &lt;span class=&quot;token parameter variable&quot;&gt;--services&lt;/span&gt; web

&lt;span class=&quot;token assign-left variable&quot;&gt;FIRST&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ecs list-tasks &lt;span class=&quot;token parameter variable&quot;&gt;--cluster&lt;/span&gt; series-cluster --service-name web &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;taskArns[0]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$FIRST&lt;/span&gt;

aws ecs stop-task &lt;span class=&quot;token parameter variable&quot;&gt;--cluster&lt;/span&gt; series-cluster &lt;span class=&quot;token parameter variable&quot;&gt;--task&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$FIRST&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; task.lastStatus&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Wait a minute, then list the tasks:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws ecs list-tasks &lt;span class=&quot;token parameter variable&quot;&gt;--cluster&lt;/span&gt; series-cluster --service-name web &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; taskArns&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The ID has changed. The service noticed the task was gone and started another without you lifting a finger.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This task costs about a cent or two per hour, but it carries on as long as the service exists. If a command complains that something is still in use, wait a minute and repeat it:&lt;/p&gt;
&lt;/aside&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws ecs delete-service &lt;span class=&quot;token parameter variable&quot;&gt;--cluster&lt;/span&gt; series-cluster &lt;span class=&quot;token parameter variable&quot;&gt;--service&lt;/span&gt; web &lt;span class=&quot;token parameter variable&quot;&gt;--force&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; service.status
aws ecs &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt; services-inactive &lt;span class=&quot;token parameter variable&quot;&gt;--cluster&lt;/span&gt; series-cluster &lt;span class=&quot;token parameter variable&quot;&gt;--services&lt;/span&gt; web
aws ecs delete-cluster &lt;span class=&quot;token parameter variable&quot;&gt;--cluster&lt;/span&gt; series-cluster &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; cluster.status
aws ecs deregister-task-definition --task-definition web:1 &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; taskDefinition.status
aws ec2 delete-security-group --group-id &lt;span class=&quot;token variable&quot;&gt;$SG&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;container&lt;/strong&gt; packages the application and its libraries, and shares the host&#39;s system, so it&#39;s light and fast.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ECR&lt;/strong&gt; stores images, and &lt;strong&gt;ECS&lt;/strong&gt; runs them through a task definition, tasks and a service.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fargate&lt;/strong&gt; spares you from managing servers, and it&#39;s the best starting point.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;execution role&lt;/strong&gt; belongs to ECS, and the &lt;strong&gt;task role&lt;/strong&gt; belongs to your code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EKS&lt;/strong&gt; is for those who need Kubernetes, and &lt;strong&gt;ECS Express Mode&lt;/strong&gt; is the short way for a web application.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 6&lt;/p&gt;
&lt;p&gt;A Fargate task starts normally and serves traffic, but when its code writes to DynamoDB it gets &lt;code&gt;AccessDenied&lt;/code&gt;. Where should the team add the permission?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;The task execution role&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;The task&#39;s security group&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An instance profile on the cluster&#39;s servers&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;The task role&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The task role belongs to your code inside the container. The task&#39;s normal start shows the execution role is already doing its job.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; ECS uses this one to prepare the task, such as pulling the image and sending logs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; A security group controls network traffic, and this error is about permissions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; Fargate has no servers for you to attach anything to, so instance profiles aren&#39;t available.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#two-iam-roles-and-confusing-them-is-a-classic&quot;&gt;Two IAM roles, and confusing them is a classic&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html&quot;&gt;Amazon ECS task IAM role&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 6&lt;/p&gt;
&lt;p&gt;A company runs its applications on Kubernetes in its own data center and on another cloud. Its team knows the Kubernetes tools well and wants to keep using them on AWS. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;ECS on Fargate&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Amazon EKS&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;ECS Express Mode&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Lambda, with container images&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;EKS runs the Kubernetes control plane for you, and the team&#39;s tools keep working, here and elsewhere.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This is a fine start for most applications, but it&#39;s AWS&#39;s own system, not Kubernetes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This builds an ECS web service from an image, and it isn&#39;t Kubernetes either.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This runs functions in response to events, and has no Kubernetes in it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#ecs-or-eks&quot;&gt;ECS or EKS?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/eks/latest/userguide/what-is-eks.html&quot;&gt;What is Amazon EKS?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 6&lt;/p&gt;
&lt;p&gt;A batch job runs in a container every night for about two hours, and nothing needs to run for the rest of the day. What fits at the &lt;strong&gt;lowest cost&lt;/strong&gt;?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;An ECS service keeping one task running all day&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A Lambda function that runs the job&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;EventBridge Scheduler starting a Fargate task each night&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;An EC2 server kept running for the job&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The schedule starts a task that stops when it&#39;s done, and on Fargate you pay only while it runs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; You&#39;d pay for a task 24 hours a day, for two hours of work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; A Lambda run ends at 15 minutes, far short of two hours.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; You&#39;d pay for the server around the clock, and have to manage it too.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#not-just-web-services&quot;&gt;Not just web services&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/tasks-scheduled-eventbridge-scheduler.html&quot;&gt;Using Amazon EventBridge Scheduler to schedule Amazon ECS tasks&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 6&lt;/p&gt;
&lt;p&gt;Several Fargate tasks in one service need to read and write the same uploaded files, and the files must survive when a task stops. What should the team mount?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;An EFS file system&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Each task&#39;s own ephemeral storage&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An Instance Store volume&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;An ECR repository&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;EFS is a shared file system that tasks can mount on both Fargate and EC2, and the files live outside any one task.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; A container&#39;s disk disappears with it, and isn&#39;t shared with other tasks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This is a temporary disk on a server, and Fargate gives you no server to attach it to.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This stores container images, not application files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#storage&quot;&gt;Storage&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html&quot;&gt;Use Amazon EFS volumes with Amazon ECS&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 6&lt;/p&gt;
&lt;p&gt;An ECS service runs on EC2 servers in an Auto Scaling group. At peak times the service needs more tasks, and those new tasks need servers to land on. Which &lt;strong&gt;two&lt;/strong&gt; features handle this? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Service Auto Scaling&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A task execution role&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Image scanning in ECR&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A Network Load Balancer&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;A capacity provider linked to the group&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Service Auto Scaling changes the number of tasks, and a capacity provider adds servers when tasks need them. On EC2 you need both layers.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This lets ECS pull images and send logs, and has nothing to do with scaling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This looks for vulnerabilities in images.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This spreads traffic across the tasks that exist, and doesn&#39;t add any.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#scaling&quot;&gt;Scaling&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-auto-scaling.html&quot;&gt;Automatically scale your Amazon ECS service&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/asg-capacity-providers.html&quot;&gt;Amazon ECS capacity providers for EC2 workloads&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 6 of 6&lt;/p&gt;
&lt;p&gt;A company runs its containers on ECS in AWS. Some must now run on servers in its own factory, and the team wants to keep using the same ECS tools. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;EKS Distro&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;ECS Anywhere&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Fargate Spot&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;AWS App Runner&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ECS Anywhere registers your own servers or virtual machines in an ECS cluster, so the team keeps its tools.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; These are Kubernetes components to run and support yourself, and the team uses ECS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This runs tasks on AWS capacity at a lower price, not on your servers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This runs in AWS, and no longer accepts new customers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#containers-on-your-own-servers&quot;&gt;Containers on your own servers&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-anywhere.html&quot;&gt;Amazon ECS clusters for external instances&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;Containers still run and cost money while waiting. What if your code only ran when there was something to do, and you paid nothing otherwise? In &lt;a href=&quot;/en/posts/aws-21-lambda-api-dynamodb/&quot;&gt;&lt;strong&gt;part twenty-one&lt;/strong&gt;&lt;/a&gt; we build an API with Lambda, API Gateway and DynamoDB.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Connecting Services: SQS, SNS and Kinesis</title>
    <link href="https://blog.sultanops.com/en/posts/aws-19-sqs-sns-kinesis/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-19-sqs-sns-kinesis/</id>
    <summary>Why services should not call each other directly, how an SQS queue absorbs load, how SNS sends one message to many, when you need a Kinesis stream, and a hands-on where you build a fan-out with a filter.</summary>
    <content type="html">&lt;p&gt;So far the pieces of our application &lt;a href=&quot;/en/posts/aws-07-auto-scaling/&quot;&gt;call each other directly&lt;/a&gt;. That&#39;s fine until a sale starts and the invoice service can&#39;t keep up, and suddenly the customer is staring at a spinner because of a service they&#39;ve never heard of.&lt;/p&gt;
&lt;p&gt;This section is about modern applications, and it starts with the idea behind most of them: &lt;strong&gt;separate the services&lt;/strong&gt;, so that each one works at its own pace and a failure in one doesn&#39;t bring down the others.&lt;/p&gt;
&lt;p&gt;Here&#39;s a map of this part:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You want&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A job taken by one worker, with nothing lost&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;SQS&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One event reaching many parties at once&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;SNS&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A continuous stream that several parties read and replay&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Kinesis Data Streams&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A stream loaded into S3 or similar without writing code&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Data Firehose&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An existing application built on RabbitMQ or ActiveMQ&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon MQ&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;why-separate-services&quot; tabindex=&quot;-1&quot;&gt;Why separate services? &lt;a class=&quot;heading-anchor&quot; href=&quot;#why-separate-services&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 212&quot; role=&quot;img&quot; aria-labelledby=&quot;decouple-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;decouple-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;text x=&quot;320&quot; y=&quot;22&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Direct call: the customer waits for the invoice service&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;34&quot; width=&quot;170&quot; height=&quot;58&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;105&quot; y=&quot;68&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Store app&lt;/text&gt;
&lt;rect x=&quot;450&quot; y=&quot;34&quot; width=&quot;170&quot; height=&quot;58&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-danger)&quot;/&gt;
&lt;text x=&quot;535&quot; y=&quot;58&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Invoice service&lt;/text&gt;
&lt;text x=&quot;535&quot; y=&quot;78&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Slow or down&lt;/text&gt;
&lt;line x1=&quot;190&quot; y1=&quot;63&quot; x2=&quot;448&quot; y2=&quot;63&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#decouple-arrow)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;130&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;With a queue: the customer gets a response right away&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;142&quot; width=&quot;170&quot; height=&quot;58&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;105&quot; y=&quot;176&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Store app&lt;/text&gt;
&lt;rect x=&quot;235&quot; y=&quot;142&quot; width=&quot;170&quot; height=&quot;58&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;166&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;SQS queue&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;186&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Holds the message&lt;/text&gt;
&lt;rect x=&quot;450&quot; y=&quot;142&quot; width=&quot;170&quot; height=&quot;58&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;535&quot; y=&quot;166&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Invoice service&lt;/text&gt;
&lt;text x=&quot;535&quot; y=&quot;186&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;At its own pace&lt;/text&gt;
&lt;line x1=&quot;190&quot; y1=&quot;171&quot; x2=&quot;233&quot; y2=&quot;171&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#decouple-arrow)&quot;/&gt;
&lt;line x1=&quot;405&quot; y1=&quot;171&quot; x2=&quot;448&quot; y2=&quot;171&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#decouple-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;decouple-caption&quot;&gt;When services call each other directly, one slow service holds up the customer. A queue lets each side work at its own pace.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A direct call means both sides must be up, and fast, at the same moment. With a queue in between you get three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Failures stay contained.&lt;/strong&gt; If the invoice service stops, messages wait in the queue until it comes back.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Peaks are absorbed.&lt;/strong&gt; A thousand orders in a minute don&#39;t reach the database all at once.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Each side scales alone.&lt;/strong&gt; You add invoice workers without touching the store.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;sqs-the-queue&quot; tabindex=&quot;-1&quot;&gt;SQS: the queue &lt;a class=&quot;heading-anchor&quot; href=&quot;#sqs-the-queue&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;SQS&lt;/strong&gt; (Simple Queue Service) is a fully managed queue with no servers to run. A &lt;strong&gt;producer&lt;/strong&gt; sends messages, they wait in the queue, and a &lt;strong&gt;consumer&lt;/strong&gt; pulls them, works on them, then deletes them.&lt;/p&gt;
&lt;p&gt;Note the direction: consumers ask the queue for messages. The queue doesn&#39;t push them to anyone.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Throughput&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No practical limit on a standard queue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Message size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Up to 1 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Retention&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4 days by default, from one minute to 14 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Delivery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;At least once, so a message can arrive twice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Order&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Best effort, not guaranteed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The last two points affect your code. Since a message can arrive twice, make processing it twice harmless. An order number you check before charging is enough.&lt;/p&gt;
&lt;p&gt;For anything larger than a message, store the file in S3 and send its path in the message.&lt;/p&gt;
&lt;h3 id=&quot;visibility-timeout&quot; tabindex=&quot;-1&quot;&gt;Visibility timeout &lt;a class=&quot;heading-anchor&quot; href=&quot;#visibility-timeout&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;What stops two consumers taking the same message? When one receives it, SQS hides it from the others for a period, called the &lt;strong&gt;visibility timeout&lt;/strong&gt;. The consumer must delete it before that period ends.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 154&quot; role=&quot;img&quot; aria-labelledby=&quot;visibility-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;visibility-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;49&quot; width=&quot;150&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;95&quot; y=&quot;72&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Received&lt;/text&gt;
&lt;text x=&quot;95&quot; y=&quot;92&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Hidden from others&lt;/text&gt;
&lt;rect x=&quot;245&quot; y=&quot;49&quot; width=&quot;150&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;72&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Processing&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;92&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;30 seconds by default&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;14&quot; width=&quot;150&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;37&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Deleted&lt;/text&gt;
&lt;text x=&quot;545&quot; y=&quot;57&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;The job is done&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;84&quot; width=&quot;150&quot; height=&quot;56&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-danger)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;107&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Not deleted&lt;/text&gt;
&lt;text x=&quot;545&quot; y=&quot;127&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Appears again&lt;/text&gt;
&lt;line x1=&quot;170&quot; y1=&quot;77&quot; x2=&quot;243&quot; y2=&quot;77&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#visibility-arrow)&quot;/&gt;
&lt;line x1=&quot;395&quot; y1=&quot;77&quot; x2=&quot;468&quot; y2=&quot;42&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#visibility-arrow)&quot;/&gt;
&lt;line x1=&quot;395&quot; y1=&quot;77&quot; x2=&quot;468&quot; y2=&quot;112&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#visibility-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;visibility-caption&quot;&gt;A received message is hidden, not removed. If the consumer doesn&#39;t delete it before the timeout ends, it appears again for another consumer.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This is the mechanism that keeps you from losing work: if the server crashes halfway through, the message comes back by itself.&lt;/p&gt;
&lt;p&gt;Choose the period to suit your processing time. It&#39;s 30 seconds by default, and it can go up to 12 hours:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Too short:&lt;/strong&gt; the message appears again while it&#39;s still being worked on, and it gets processed twice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Too long:&lt;/strong&gt; if a consumer fails, the message waits a long time before anyone retries it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If a job takes longer than usual, the consumer can extend the period for that message with &lt;code&gt;ChangeMessageVisibility&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;long-polling&quot; tabindex=&quot;-1&quot;&gt;Long polling &lt;a class=&quot;heading-anchor&quot; href=&quot;#long-polling&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By default, asking an empty queue returns an empty response right away, so your consumers fill your bill with pointless requests. With &lt;strong&gt;long polling&lt;/strong&gt;, the request waits up to 20 seconds for a message. That means fewer requests, a lower cost and faster delivery, so always turn it on.&lt;/p&gt;
&lt;h3 id=&quot;dead-letter-queues&quot; tabindex=&quot;-1&quot;&gt;Dead-letter queues &lt;a class=&quot;heading-anchor&quot; href=&quot;#dead-letter-queues&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;What about a message that always fails, because of a bug or bad data? It will come back forever. Attach a &lt;strong&gt;dead-letter queue (DLQ)&lt;/strong&gt;: after a number of failed attempts you choose, the message moves there, so you can inspect it without it blocking anything. Then you can &lt;strong&gt;redrive&lt;/strong&gt; it to the original queue once you&#39;ve fixed the problem.&lt;/p&gt;
&lt;p&gt;Keep the retention in the dead-letter queue longer than the original, so messages don&#39;t expire before you see them.&lt;/p&gt;
&lt;h3 id=&quot;fifo-queues&quot; tabindex=&quot;-1&quot;&gt;FIFO queues &lt;a class=&quot;heading-anchor&quot; href=&quot;#fifo-queues&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When order matters, as with transactions on one account, use a &lt;strong&gt;FIFO&lt;/strong&gt; queue. Its name must end in &lt;code&gt;.fifo&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Standard&lt;/th&gt;
&lt;th&gt;FIFO&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Order&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not guaranteed&lt;/td&gt;
&lt;td&gt;Guaranteed within a message group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Duplicates&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Possible&lt;/td&gt;
&lt;td&gt;Removed within a 5-minute window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Throughput&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No practical limit&lt;/td&gt;
&lt;td&gt;300 messages per second, or 3,000 with batching&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The order is per &lt;strong&gt;message group&lt;/strong&gt;, so with one group for each customer, different customers&#39; messages can be processed in parallel. If you need more throughput, &lt;strong&gt;high throughput mode&lt;/strong&gt; raises the limit by far, and the figure varies by Region.&lt;/p&gt;
&lt;h3 id=&quot;scaling-with-the-queue&quot; tabindex=&quot;-1&quot;&gt;Scaling with the queue &lt;a class=&quot;heading-anchor&quot; href=&quot;#scaling-with-the-queue&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A classic pattern: an &lt;a href=&quot;/en/posts/aws-07-auto-scaling/&quot;&gt;Auto Scaling group&lt;/a&gt; of workers grows and shrinks according to the queue&#39;s length. The &lt;code&gt;ApproximateNumberOfMessagesVisible&lt;/code&gt; metric tells you how many messages are waiting, so a growing queue adds workers.&lt;/p&gt;
&lt;p&gt;It also protects your database. Instead of a spike of orders hitting RDS directly, they go into a queue, and workers write them at a pace the database can handle. This only suits work that doesn&#39;t need an immediate answer, so the customer is told &amp;quot;we received your order&amp;quot;, not &amp;quot;your order is complete&amp;quot;.&lt;/p&gt;
&lt;h3 id=&quot;security&quot; tabindex=&quot;-1&quot;&gt;Security &lt;a class=&quot;heading-anchor&quot; href=&quot;#security&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Messages are encrypted in transit over HTTPS, and at rest with SSE-SQS by default, or with your own KMS key. Who can reach the queue is decided by IAM policies, plus an &lt;strong&gt;access policy&lt;/strong&gt; on the queue itself, which you need for other accounts or for services like SNS and S3 to send to it. We&#39;ll write one in the hands-on.&lt;/p&gt;
&lt;h2 id=&quot;sns-one-message-to-many&quot; tabindex=&quot;-1&quot;&gt;SNS: one message to many &lt;a class=&quot;heading-anchor&quot; href=&quot;#sns-one-message-to-many&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A queue suits a job that one party does. But when a customer places an order, the shipping, invoicing and analytics services all want to know. You don&#39;t want your application to know about each of them, and to change every time you add one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SNS&lt;/strong&gt; (Simple Notification Service) works by &lt;strong&gt;publishing and subscribing&lt;/strong&gt;: your application publishes one message to a &lt;strong&gt;topic&lt;/strong&gt;, and SNS delivers it to every subscriber, right away. A standard topic can have up to 12.5 million subscriptions.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Subscriber type&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A service that processes at its own pace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lambda&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A small function that runs per message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTTP or HTTPS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A webhook in another system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Firehose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Storing every message in S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Email, SMS, mobile push&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Notifying people directly&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Unlike a queue, SNS doesn&#39;t store messages. If a subscriber is down it retries for a while, but it&#39;s not somewhere messages wait.&lt;/p&gt;
&lt;p&gt;Message size is 256 KiB by default, and you can raise it on a topic up to 1 MiB, though this limits the topic to 100 subscriptions and to SQS, Lambda and Firehose subscribers only.&lt;/p&gt;
&lt;h3 id=&quot;fan-out-sns-with-sqs&quot; tabindex=&quot;-1&quot;&gt;Fan-out: SNS with SQS &lt;a class=&quot;heading-anchor&quot; href=&quot;#fan-out-sns-with-sqs&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The most important pattern here combines the two services: SNS spreads the message, and a queue for each service keeps it until that service is ready.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 246&quot; role=&quot;img&quot; aria-labelledby=&quot;fanout-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;fanout-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;93&quot; width=&quot;130&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;85&quot; y=&quot;118&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Store app&lt;/text&gt;
&lt;text x=&quot;85&quot; y=&quot;138&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Publishes once&lt;/text&gt;
&lt;rect x=&quot;200&quot; y=&quot;93&quot; width=&quot;130&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;265&quot; y=&quot;118&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;SNS topic&lt;/text&gt;
&lt;text x=&quot;265&quot; y=&quot;138&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;orders&lt;/text&gt;
&lt;rect x=&quot;380&quot; y=&quot;14&quot; width=&quot;120&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;440&quot; y=&quot;39&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Shipping&lt;/text&gt;
&lt;text x=&quot;440&quot; y=&quot;59&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Physical only&lt;/text&gt;
&lt;rect x=&quot;380&quot; y=&quot;93&quot; width=&quot;120&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;440&quot; y=&quot;118&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Invoices&lt;/text&gt;
&lt;text x=&quot;440&quot; y=&quot;138&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;All orders&lt;/text&gt;
&lt;rect x=&quot;380&quot; y=&quot;172&quot; width=&quot;120&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;440&quot; y=&quot;197&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Analytics&lt;/text&gt;
&lt;text x=&quot;440&quot; y=&quot;217&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;All orders&lt;/text&gt;
&lt;rect x=&quot;530&quot; y=&quot;14&quot; width=&quot;90&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;575&quot; y=&quot;49&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;EC2&lt;/text&gt;
&lt;rect x=&quot;530&quot; y=&quot;93&quot; width=&quot;90&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;575&quot; y=&quot;128&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Lambda&lt;/text&gt;
&lt;rect x=&quot;530&quot; y=&quot;172&quot; width=&quot;90&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;575&quot; y=&quot;207&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Fargate&lt;/text&gt;
&lt;line x1=&quot;150&quot; y1=&quot;123&quot; x2=&quot;198&quot; y2=&quot;123&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#fanout-arrow)&quot;/&gt;
&lt;line x1=&quot;330&quot; y1=&quot;123&quot; x2=&quot;378&quot; y2=&quot;44&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#fanout-arrow)&quot;/&gt;
&lt;line x1=&quot;330&quot; y1=&quot;123&quot; x2=&quot;378&quot; y2=&quot;123&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#fanout-arrow)&quot;/&gt;
&lt;line x1=&quot;330&quot; y1=&quot;123&quot; x2=&quot;378&quot; y2=&quot;202&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#fanout-arrow)&quot;/&gt;
&lt;line x1=&quot;500&quot; y1=&quot;44&quot; x2=&quot;528&quot; y2=&quot;44&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#fanout-arrow)&quot;/&gt;
&lt;line x1=&quot;500&quot; y1=&quot;123&quot; x2=&quot;528&quot; y2=&quot;123&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#fanout-arrow)&quot;/&gt;
&lt;line x1=&quot;500&quot; y1=&quot;202&quot; x2=&quot;528&quot; y2=&quot;202&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#fanout-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;fanout-caption&quot;&gt;The app publishes once, SNS copies the message to every queue, and each service reads from its own queue. The filter sends only physical orders to shipping.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Why this combination?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nothing is lost:&lt;/strong&gt; if the shipping service stops, its messages wait in its queue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Each service has its own pace,&lt;/strong&gt; retries and dead-letter queue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adding a service is easy:&lt;/strong&gt; a new queue subscribes to the topic, with no change to the publisher.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The same goes for &lt;a href=&quot;/en/posts/aws-15-s3-basics/&quot;&gt;S3 events&lt;/a&gt;: S3 doesn&#39;t accept two rules with overlapping prefixes for the same event type. So to reach several destinations, send the event to one SNS topic and fan it out from there.&lt;/p&gt;
&lt;h3 id=&quot;filtering-messages&quot; tabindex=&quot;-1&quot;&gt;Filtering messages &lt;a class=&quot;heading-anchor&quot; href=&quot;#filtering-messages&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By default every subscriber receives everything. A &lt;strong&gt;filter policy&lt;/strong&gt; on the subscription lets the shipping queue receive only what concerns it:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;JSON&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;physical&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Messages with &lt;code&gt;type&lt;/code&gt; set to &lt;code&gt;digital&lt;/code&gt; won&#39;t reach it, and you don&#39;t pay to process them.&lt;/p&gt;
&lt;h3 id=&quot;fifo-topics&quot; tabindex=&quot;-1&quot;&gt;FIFO topics &lt;a class=&quot;heading-anchor&quot; href=&quot;#fifo-topics&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For order across a fan-out, SNS has &lt;strong&gt;FIFO&lt;/strong&gt; topics, whose names also end in &lt;code&gt;.fifo&lt;/code&gt;, with order and duplicate removal like FIFO queues. These are limited to 100 subscriptions per topic, and they suit cases like sending the same sequence of updates to several queues.&lt;/p&gt;
&lt;h2 id=&quot;kinesis-data-streams-a-stream-that-stays&quot; tabindex=&quot;-1&quot;&gt;Kinesis Data Streams: a stream that stays &lt;a class=&quot;heading-anchor&quot; href=&quot;#kinesis-data-streams-a-stream-that-stays&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Imagine a million sensors sending readings every second, and three parties who want to read them: one for instant alerts, one for dashboards, and one for archiving. A queue doesn&#39;t suit this, because a message is gone once it&#39;s processed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kinesis Data Streams&lt;/strong&gt; is a stream: records stay in it for the retention period, whether they&#39;ve been read or not, and each consumer reads from its own position, so it can go back and &lt;strong&gt;replay&lt;/strong&gt; them.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 232&quot; role=&quot;img&quot; aria-labelledby=&quot;kinesis-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;kinesis-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;24&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;75&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;App&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;91&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;75&quot; y=&quot;121&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Sensors&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;158&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;75&quot; y=&quot;188&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Logs&lt;/text&gt;
&lt;rect x=&quot;180&quot; y=&quot;14&quot; width=&quot;280&quot; height=&quot;204&quot; rx=&quot;14&quot; fill=&quot;none&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;6 6&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;38&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Kinesis Data Stream&lt;/text&gt;
&lt;rect x=&quot;200&quot; y=&quot;50&quot; width=&quot;240&quot; height=&quot;40&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;75&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Shard 1&lt;/text&gt;
&lt;rect x=&quot;200&quot; y=&quot;98&quot; width=&quot;240&quot; height=&quot;40&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;123&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Shard 2&lt;/text&gt;
&lt;rect x=&quot;200&quot; y=&quot;146&quot; width=&quot;240&quot; height=&quot;40&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;171&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Shard 3&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;206&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Kept from 24 hours to 365 days&lt;/text&gt;
&lt;rect x=&quot;510&quot; y=&quot;24&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;565&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Lambda&lt;/text&gt;
&lt;rect x=&quot;510&quot; y=&quot;91&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;565&quot; y=&quot;121&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Your app&lt;/text&gt;
&lt;rect x=&quot;510&quot; y=&quot;158&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;565&quot; y=&quot;188&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Firehose&lt;/text&gt;
&lt;line x1=&quot;130&quot; y1=&quot;49&quot; x2=&quot;178&quot; y2=&quot;70&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#kinesis-arrow)&quot;/&gt;
&lt;line x1=&quot;130&quot; y1=&quot;116&quot; x2=&quot;178&quot; y2=&quot;116&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#kinesis-arrow)&quot;/&gt;
&lt;line x1=&quot;130&quot; y1=&quot;183&quot; x2=&quot;178&quot; y2=&quot;162&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#kinesis-arrow)&quot;/&gt;
&lt;line x1=&quot;460&quot; y1=&quot;70&quot; x2=&quot;508&quot; y2=&quot;49&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#kinesis-arrow)&quot;/&gt;
&lt;line x1=&quot;460&quot; y1=&quot;116&quot; x2=&quot;508&quot; y2=&quot;116&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#kinesis-arrow)&quot;/&gt;
&lt;line x1=&quot;460&quot; y1=&quot;162&quot; x2=&quot;508&quot; y2=&quot;183&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#kinesis-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;kinesis-caption&quot;&gt;Producers write to shards, records with the same key stay in order inside one shard, and several consumers read the same data, each at its own position.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Shards:&lt;/strong&gt; the stream is split into shards. With provisioned capacity, each one takes 1 MB per second of writes and 2 MB per second of reads.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partition key:&lt;/strong&gt; decides which shard a record goes to. Records with the same key stay in order, so a sensor&#39;s number works well as a key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retention:&lt;/strong&gt; 24 hours by default, up to 365 days.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Record size:&lt;/strong&gt; 1 MiB by default, and you can raise it up to 10 MiB per stream.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;capacity-modes&quot; tabindex=&quot;-1&quot;&gt;Capacity modes &lt;a class=&quot;heading-anchor&quot; href=&quot;#capacity-modes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;On-demand&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Starts at 4 MB per second of writes and scales by itself, and you pay for the data&lt;/td&gt;
&lt;td&gt;Unknown or changing load; start here&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Provisioned&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You set the number of shards and pay for each per hour&lt;/td&gt;
&lt;td&gt;Steady, known load, which can be cheaper&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The ceiling for on-demand depends on the Region: up to 10 GB per second of writes in the largest Regions, and 200 MB per second in others.&lt;/p&gt;
&lt;p&gt;Video has its own service: &lt;strong&gt;Kinesis Video Streams&lt;/strong&gt; takes live video from devices such as cameras, stores it, and lets you watch it or process it, live or later.&lt;/p&gt;
&lt;h2 id=&quot;data-firehose-to-storage-with-no-code&quot; tabindex=&quot;-1&quot;&gt;Data Firehose: to storage with no code &lt;a class=&quot;heading-anchor&quot; href=&quot;#data-firehose-to-storage-with-no-code&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Very often all you want is for the stream to land somewhere. &lt;strong&gt;Amazon Data Firehose&lt;/strong&gt; (formerly Kinesis Data Firehose) takes data, collects it, and delivers it with no code or servers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sources:&lt;/strong&gt; your application directly, a Kinesis stream, or others like SNS and CloudWatch Logs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Processing:&lt;/strong&gt; optionally transforms records with a Lambda function, and can convert them to Parquet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Destinations:&lt;/strong&gt; S3, Redshift, OpenSearch, Snowflake, Apache Iceberg tables, or an HTTP endpoint.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Buffering:&lt;/strong&gt; it collects data until it reaches a size or a period, such as 5 MiB or 5 minutes for S3, and whichever comes first triggers delivery. So it suits near-real-time loading, not an instant reaction.&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Kinesis Data Streams&lt;/th&gt;
&lt;th&gt;Data Firehose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A stream your consumers read&lt;/td&gt;
&lt;td&gt;A pipe that delivers to storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Consumers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You write them&lt;/td&gt;
&lt;td&gt;The destination is managed for you&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Replay&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes, within the retention period&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Timing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Immediate&lt;/td&gt;
&lt;td&gt;Depends on the buffering you set&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;which-one-do-i-choose&quot; tabindex=&quot;-1&quot;&gt;Which one do I choose? &lt;a class=&quot;heading-anchor&quot; href=&quot;#which-one-do-i-choose&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;SQS&lt;/th&gt;
&lt;th&gt;SNS&lt;/th&gt;
&lt;th&gt;Kinesis Data Streams&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Consumers pull&lt;/td&gt;
&lt;td&gt;Pushes to subscribers&lt;/td&gt;
&lt;td&gt;Consumers pull&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Readers of a message&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One, then it&#39;s deleted&lt;/td&gt;
&lt;td&gt;Every subscriber&lt;/td&gt;
&lt;td&gt;Everyone, within the retention period&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stored?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Up to 14 days&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Up to 365 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Order&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;With FIFO&lt;/td&gt;
&lt;td&gt;With FIFO&lt;/td&gt;
&lt;td&gt;Within a shard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Typical use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Background jobs&lt;/td&gt;
&lt;td&gt;Notifications and fan-out&lt;/td&gt;
&lt;td&gt;Analytics, logs and streaming data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A quick rule: a &lt;strong&gt;job&lt;/strong&gt;? SQS. An &lt;strong&gt;event&lt;/strong&gt; many want to know about? SNS. A &lt;strong&gt;stream of data&lt;/strong&gt; many read and replay? Kinesis.&lt;/p&gt;
&lt;p&gt;There&#39;s also &lt;strong&gt;EventBridge&lt;/strong&gt;, which routes events by rules from AWS services and other applications, and we&#39;ll cover it in &lt;a href=&quot;/en/posts/aws-25-monitoring-auditing/&quot;&gt;part twenty-five&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;amazon-mq-for-what-already-exists&quot; tabindex=&quot;-1&quot;&gt;Amazon MQ: for what already exists &lt;a class=&quot;heading-anchor&quot; href=&quot;#amazon-mq-for-what-already-exists&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SQS and SNS are AWS&#39;s own services with their own APIs. If you&#39;re moving an application built on open protocols such as &lt;strong&gt;AMQP&lt;/strong&gt;, &lt;strong&gt;MQTT&lt;/strong&gt; or &lt;strong&gt;STOMP&lt;/strong&gt;, you won&#39;t want to rewrite it. &lt;strong&gt;Amazon MQ&lt;/strong&gt; runs a familiar broker as a managed service, in two engines:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Engine&lt;/th&gt;
&lt;th&gt;High availability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ActiveMQ&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Two brokers in two Availability Zones, active and standby, with shared storage on EFS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A cluster of three nodes across Availability Zones, behind one endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Note that it runs on brokers you choose the size of, so it doesn&#39;t scale without limit like SQS and SNS. For a new application, start with those two.&lt;/p&gt;
&lt;h2 id=&quot;hands-on-a-fan-out-with-a-filter&quot; tabindex=&quot;-1&quot;&gt;Hands-on: a fan-out with a filter &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-a-fan-out-with-a-filter&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll build the design from the diagram with two queues. From CloudShell, create the topic and the queues:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;TOPIC_ARN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws sns create-topic &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; orders &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; TopicArn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;SHIP_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws sqs create-queue --queue-name shipping &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; QueueUrl &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;BILL_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws sqs create-queue --queue-name billing &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; QueueUrl &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;SHIP_ARN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws sqs get-queue-attributes --queue-url $SHIP_URL &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --attribute-names QueueArn &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Attributes.QueueArn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;BILL_ARN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws sqs get-queue-attributes --queue-url $BILL_URL &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --attribute-names QueueArn &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Attributes.QueueArn &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Queues are private, so allow only this topic to send to them:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function-name function&quot;&gt;allow_topic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token assign-left variable&quot;&gt;POLICY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;jq &lt;span class=&quot;token parameter variable&quot;&gt;-nc&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--arg&lt;/span&gt; q &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$2&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--arg&lt;/span&gt; t &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$TOPIC_ARN&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;{
    Version: &quot;2012-10-17&quot;,
    Statement: [{
      Effect: &quot;Allow&quot;,
      Principal: {Service: &quot;sns.amazonaws.com&quot;},
      Action: &quot;sqs:SendMessage&quot;,
      Resource: $q,
      Condition: {ArnEquals: {&quot;aws:SourceArn&quot;: $t}}
    }]
  }&#39;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
  aws sqs set-queue-attributes --queue-url &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token parameter variable&quot;&gt;--attributes&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;jq &lt;span class=&quot;token parameter variable&quot;&gt;-nc&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--arg&lt;/span&gt; p &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$POLICY&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;{Policy: $p}&#39;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

allow_topic &lt;span class=&quot;token variable&quot;&gt;$SHIP_URL&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$SHIP_ARN&lt;/span&gt;
allow_topic &lt;span class=&quot;token variable&quot;&gt;$BILL_URL&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BILL_ARN&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Subscribe the queues to the topic: billing gets everything, and shipping gets physical orders only:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws sns subscribe --topic-arn &lt;span class=&quot;token variable&quot;&gt;$TOPIC_ARN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--protocol&lt;/span&gt; sqs --notification-endpoint &lt;span class=&quot;token variable&quot;&gt;$BILL_ARN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--attributes&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;RawMessageDelivery&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true

aws sns subscribe --topic-arn &lt;span class=&quot;token variable&quot;&gt;$TOPIC_ARN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--protocol&lt;/span&gt; sqs --notification-endpoint &lt;span class=&quot;token variable&quot;&gt;$SHIP_ARN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--attributes&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;RawMessageDelivery&quot;:&quot;true&quot;,&quot;FilterPolicy&quot;:&quot;{&#92;&quot;type&#92;&quot;:[&#92;&quot;physical&#92;&quot;]}&quot;}&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Publish two orders, one physical and one digital:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws sns publish --topic-arn &lt;span class=&quot;token variable&quot;&gt;$TOPIC_ARN&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--message&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order 1: a book&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --message-attributes &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;type&quot;:{&quot;DataType&quot;:&quot;String&quot;,&quot;StringValue&quot;:&quot;physical&quot;}}&#39;&lt;/span&gt;

aws sns publish --topic-arn &lt;span class=&quot;token variable&quot;&gt;$TOPIC_ARN&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--message&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;order 2: an e-book&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --message-attributes &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;type&quot;:{&quot;DataType&quot;:&quot;String&quot;,&quot;StringValue&quot;:&quot;digital&quot;}}&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Give it a few seconds, then count the messages in each queue:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token for-or-select variable&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BILL_URL&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$SHIP_URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
  aws sqs get-queue-attributes --queue-url &lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    --attribute-names ApproximateNumberOfMessages &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Attributes.ApproximateNumberOfMessages &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text
&lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;You&#39;ll see &lt;code&gt;2&lt;/code&gt; for billing and &lt;code&gt;1&lt;/code&gt; for shipping, so the filter worked. Now try the visibility timeout. Receive the shipping message, then try again straight away:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws sqs receive-message --queue-url &lt;span class=&quot;token variable&quot;&gt;$SHIP_URL&lt;/span&gt; --wait-time-seconds &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Messages[0].Body&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text

aws sqs receive-message --queue-url &lt;span class=&quot;token variable&quot;&gt;$SHIP_URL&lt;/span&gt; --wait-time-seconds &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Messages[0].Body&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The first prints &lt;code&gt;order 1: a book&lt;/code&gt;, and the second waits five seconds and prints &lt;code&gt;None&lt;/code&gt;, because the message is hidden. We didn&#39;t delete it, so wait 30 seconds and receive it again, this time deleting it to finish the job:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;HANDLE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws sqs receive-message --queue-url $SHIP_URL --wait-time-seconds &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Messages[0].ReceiptHandle&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws sqs delete-message --queue-url &lt;span class=&quot;token variable&quot;&gt;$SHIP_URL&lt;/span&gt; --receipt-handle &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$HANDLE&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Now the message is gone for good.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This experiment costs practically nothing, but clean up anyway. Deleting a topic also deletes its subscriptions:&lt;/p&gt;
&lt;/aside&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws sns delete-topic --topic-arn &lt;span class=&quot;token variable&quot;&gt;$TOPIC_ARN&lt;/span&gt;
aws sqs delete-queue --queue-url &lt;span class=&quot;token variable&quot;&gt;$SHIP_URL&lt;/span&gt;
aws sqs delete-queue --queue-url &lt;span class=&quot;token variable&quot;&gt;$BILL_URL&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Separating services&lt;/strong&gt; contains failures, absorbs peaks and lets each side scale alone.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQS&lt;/strong&gt; is a queue: a message goes to one consumer, who must delete it before the visibility timeout ends.&lt;/li&gt;
&lt;li&gt;Always add &lt;strong&gt;long polling&lt;/strong&gt; and a &lt;strong&gt;dead-letter queue&lt;/strong&gt;, and make processing safe to repeat.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SNS&lt;/strong&gt; delivers one message to many, and &lt;strong&gt;fan-out&lt;/strong&gt; with SQS guarantees none of them miss it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kinesis Data Streams&lt;/strong&gt; keeps data for several readers to replay, and &lt;strong&gt;Firehose&lt;/strong&gt; delivers it to storage without code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 6&lt;/p&gt;
&lt;p&gt;A ticket site&#39;s order page writes straight to RDS. When a big concert goes on sale, the database overloads and orders fail. Customers can accept seeing &amp;quot;we received your order&amp;quot;, with the confirmation following a minute later. What absorbs the peak?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A read replica for the database&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;An SQS queue, with workers writing at a pace the database can handle&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An SNS topic that pushes each order to the database&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Multi-AZ on the database&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The queue holds the orders, and workers write them at a pace the database can handle. It suits this case because the customer doesn&#39;t need the final answer immediately.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Replicas serve reads, and the overload here comes from writes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; SNS delivers right away and doesn&#39;t store messages, so the peak would still arrive all at once.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; The standby takes no load, so the overload stays.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#scaling-with-the-queue&quot;&gt;Scaling with the queue&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html&quot;&gt;What is Amazon Simple Queue Service?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 6&lt;/p&gt;
&lt;p&gt;A worker takes about two minutes to produce each invoice, and the queue&#39;s visibility timeout is still at its default. Customers are receiving the same invoice several times. What should the team change?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Raise the visibility timeout above the processing time&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Turn on long polling&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Attach a dead-letter queue&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Add more workers&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After 30 seconds the message reappears while the first worker is still on it, so another worker takes it too. The timeout has to be longer than the work.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This cuts empty responses, and doesn&#39;t change when a message reappears.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This catches messages that keep failing, and these ones are succeeding, repeatedly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; More workers would only pick up the reappearing messages faster.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#visibility-timeout&quot;&gt;Visibility timeout&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html&quot;&gt;Amazon SQS visibility timeout&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 6&lt;/p&gt;
&lt;p&gt;When an order is placed, the shipping, billing and analytics services all need to know. Any of them may be down for hours, and adding a new service shouldn&#39;t mean changing the publisher. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;One SQS queue that all three services read from&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;The publisher sending directly to a queue for each service&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An SNS topic with an HTTP subscriber for each service&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;An SNS topic, with an SQS queue for each service subscribed to it&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SNS delivers one message to every subscriber, and each service&#39;s queue holds it until that service is ready. A new service simply subscribes a new queue.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Each message goes to only one consumer, so the other services would miss it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; The publisher would need changing with every new service.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; SNS only retries for a while and doesn&#39;t store messages, so a long outage could lose them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#fan-out-sns-with-sqs&quot;&gt;Fan-out: SNS with SQS&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/sns/latest/dg/welcome.html&quot;&gt;What is Amazon SNS?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 6&lt;/p&gt;
&lt;p&gt;A wind farm&#39;s sensors send readings every second. Three separate applications read the same data in real time, and after fixing a bug, one of them must re-read the last three days. Which option fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;An SQS standard queue&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;An SNS standard topic&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Kinesis Data Streams, with its retention raised to at least three days&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Data Firehose, delivering to S3&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Records stay in the stream for the retention period whether they&#39;ve been read or not, and each consumer reads from its own position, so one can go back without disturbing the others. The default retention is only 24 hours.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; A message goes to one consumer, and it&#39;s gone once deleted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; SNS doesn&#39;t store messages, so there&#39;s nothing to re-read.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This buffers data and delivers it to storage, so it offers neither instant reads nor replay.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#kinesis-data-streams-a-stream-that-stays&quot;&gt;Kinesis Data Streams: a stream that stays&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/streams/latest/dev/kinesis-extended-retention.html&quot;&gt;Change the data retention period&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 6&lt;/p&gt;
&lt;p&gt;A bank processes transactions through a queue. Within each account they must run in order with duplicates removed, while different accounts should be processed in parallel. Which &lt;strong&gt;two&lt;/strong&gt; choices fit? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A standard queue&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A FIFO queue&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;One message group for all accounts&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A message group for each account&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;A longer visibility timeout&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B + D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A FIFO queue keeps order within a message group and removes duplicates within a 5-minute window, and a group for each account lets different accounts run in parallel.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This doesn&#39;t guarantee order, and a message can arrive twice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This forces every transaction into one line, so nothing runs in parallel.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E:&lt;/strong&gt; This gives workers more time, and has no effect on order.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#fifo-queues&quot;&gt;FIFO queues&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues-understanding-logic.html&quot;&gt;FIFO queue delivery logic in Amazon SQS&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 6 of 6&lt;/p&gt;
&lt;p&gt;A factory wants to send live video from its security cameras to AWS, store it, and analyze it later. Which service was built for this?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Data Firehose&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;An SQS queue&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;SNS&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Kinesis Video Streams&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It takes live video from devices, stores it, and lets you watch or process it, live or later.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This delivers records to storage, and isn&#39;t built for live video from devices.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; A message holds up to 1 MiB, which doesn&#39;t suit video.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This pushes short messages to subscribers, and stores nothing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#kinesis-data-streams-a-stream-that-stays&quot;&gt;Kinesis Data Streams: a stream that stays&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/what-is-kinesis-video.html&quot;&gt;What is Amazon Kinesis Video Streams?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;The services are now separated, but where does the code itself run? So far our answer has been an EC2 server, with all the setup that entails. In &lt;a href=&quot;/en/posts/aws-20-ecs-fargate-eks/&quot;&gt;&lt;strong&gt;part twenty&lt;/strong&gt;&lt;/a&gt; we package applications in containers and run them with ECS, Fargate and EKS.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>More Storage and Transfer Services</title>
    <link href="https://blog.sultanops.com/en/posts/aws-18-storage-transfer/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-18-storage-transfer/</id>
    <summary>Ready-made file systems in FSx, linking your office to cloud storage with Storage Gateway, moving data with DataSync and Transfer Family, what to do when your data outgrows the internet, and a full comparison of storage services.</summary>
    <content type="html">&lt;p&gt;In the &lt;a href=&quot;/en/posts/aws-17-s3-security/&quot;&gt;previous parts&lt;/a&gt; we covered S3 in detail. But there are cases it doesn&#39;t solve: a Windows application needing a shared folder, servers in your office wanting to reach the cloud, a partner sending files over SFTP, or huge data that has to move.&lt;/p&gt;
&lt;p&gt;Here&#39;s this part&#39;s map:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You want&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A Windows file system or very high performance&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon FSx&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Your office servers reaching cloud storage&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Storage Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moving and syncing large data on a schedule&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DataSync&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partners uploading files over SFTP&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Transfer Family&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Physically moving massive amounts&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Data Transfer Terminal&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;amazon-fsx-ready-made-file-systems&quot; tabindex=&quot;-1&quot;&gt;Amazon FSx: ready-made file systems &lt;a class=&quot;heading-anchor&quot; href=&quot;#amazon-fsx-ready-made-file-systems&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve seen &lt;a href=&quot;/en/posts/aws-05-ec2-storage/&quot;&gt;EFS&lt;/a&gt; for a shared Linux file system. &lt;strong&gt;FSx&lt;/strong&gt; runs well-known file systems for you as a managed service, so you don&#39;t have to manage them yourself:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FSx for Windows&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SMB&lt;/td&gt;
&lt;td&gt;Windows applications and shared folders, tied into Active Directory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FSx for Lustre&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lustre&lt;/td&gt;
&lt;td&gt;High-performance computing and model training, integrates with S3, Linux devices only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FSx for NetApp ONTAP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;NFS, SMB and iSCSI&lt;/td&gt;
&lt;td&gt;Moving NetApp systems, and different operating systems on the same data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FSx for OpenZFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;NFS&lt;/td&gt;
&lt;td&gt;Linux workloads, moving ZFS systems, instant snapshots and clones&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;FSx for Lustre&lt;/strong&gt; has two options: &lt;strong&gt;Scratch&lt;/strong&gt; is cheap and fast for temporary data, but the data has no copies, so a failed disk loses it. &lt;strong&gt;Persistent&lt;/strong&gt; is for long-term data, with copies inside the Availability Zone.&lt;/p&gt;
&lt;h2 id=&quot;storage-gateway-your-office-and-the-cloud&quot; tabindex=&quot;-1&quot;&gt;Storage Gateway: your office and the cloud &lt;a class=&quot;heading-anchor&quot; href=&quot;#storage-gateway-your-office-and-the-cloud&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Have servers in your office and want to benefit from the cloud without changing your applications? &lt;strong&gt;Storage Gateway&lt;/strong&gt; is software you run on-site as a virtual machine. It presents ordinary storage to your applications, while the data actually lives in AWS, with a local cache for recent files.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 230&quot; role=&quot;img&quot; aria-labelledby=&quot;gateway-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;gw-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;14&quot; y=&quot;14&quot; width=&quot;300&quot; height=&quot;202&quot; rx=&quot;14&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;164&quot; y=&quot;42&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Your office&lt;/text&gt;
&lt;rect x=&quot;34&quot; y=&quot;70&quot; width=&quot;110&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;89&quot; y=&quot;105&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Your apps&lt;/text&gt;
&lt;rect x=&quot;180&quot; y=&quot;70&quot; width=&quot;118&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;239&quot; y=&quot;96&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Gateway&lt;/text&gt;
&lt;text x=&quot;239&quot; y=&quot;116&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;With a local cache&lt;/text&gt;
&lt;text x=&quot;164&quot; y=&quot;168&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;NFS, SMB, iSCSI or tape&lt;/text&gt;
&lt;rect x=&quot;400&quot; y=&quot;14&quot; width=&quot;226&quot; height=&quot;202&quot; rx=&quot;14&quot; fill=&quot;none&quot; stroke=&quot;var(--color-accent)&quot; stroke-dasharray=&quot;6 6&quot;/&gt;
&lt;text x=&quot;513&quot; y=&quot;34&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;AWS&lt;/text&gt;
&lt;rect x=&quot;416&quot; y=&quot;44&quot; width=&quot;190&quot; height=&quot;44&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;511&quot; y=&quot;71&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;S3&lt;/text&gt;
&lt;rect x=&quot;416&quot; y=&quot;100&quot; width=&quot;190&quot; height=&quot;44&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;511&quot; y=&quot;127&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;EBS snapshots&lt;/text&gt;
&lt;rect x=&quot;416&quot; y=&quot;156&quot; width=&quot;190&quot; height=&quot;44&quot; rx=&quot;8&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;511&quot; y=&quot;183&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Glacier&lt;/text&gt;
&lt;line x1=&quot;144&quot; y1=&quot;100&quot; x2=&quot;178&quot; y2=&quot;100&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#gw-arrow)&quot;/&gt;
&lt;line x1=&quot;298&quot; y1=&quot;90&quot; x2=&quot;414&quot; y2=&quot;66&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#gw-arrow)&quot;/&gt;
&lt;line x1=&quot;298&quot; y1=&quot;100&quot; x2=&quot;414&quot; y2=&quot;122&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#gw-arrow)&quot;/&gt;
&lt;line x1=&quot;298&quot; y1=&quot;110&quot; x2=&quot;414&quot; y2=&quot;178&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#gw-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;gateway-caption&quot;&gt;Applications in your office see ordinary storage through the gateway, which keeps the data in S3, EBS snapshots or Glacier.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Your apps see it as&lt;/th&gt;
&lt;th&gt;Where the data is&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;S3 File Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An NFS or SMB folder&lt;/td&gt;
&lt;td&gt;Objects in S3&lt;/td&gt;
&lt;td&gt;Shared folders and file backups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Volume Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An iSCSI disk&lt;/td&gt;
&lt;td&gt;S3 with EBS snapshots&lt;/td&gt;
&lt;td&gt;Disks for existing servers, cached or with a full local copy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tape Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A virtual tape library&lt;/td&gt;
&lt;td&gt;S3, then Glacier&lt;/td&gt;
&lt;td&gt;Backup software that relies on tape&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;There&#39;s a fourth type called &lt;strong&gt;FSx File Gateway&lt;/strong&gt; that&#39;s no longer available to new customers, and AWS advises connecting to FSx directly.&lt;/p&gt;
&lt;h2 id=&quot;moving-data&quot; tabindex=&quot;-1&quot;&gt;Moving data &lt;a class=&quot;heading-anchor&quot; href=&quot;#moving-data&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;datasync&quot; tabindex=&quot;-1&quot;&gt;DataSync &lt;a class=&quot;heading-anchor&quot; href=&quot;#datasync&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;DataSync&lt;/strong&gt; moves and syncs large data on a schedule:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;From where to where:&lt;/strong&gt; from NFS, SMB or HDFS servers or object storage, to S3, EFS or FSx, and between AWS services themselves.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent:&lt;/strong&gt; you run an agent on-site to move from your office, and don&#39;t need one between AWS services.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It moves only what changed&lt;/strong&gt; on each run, preserves permissions and dates, and verifies data integrity.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;transfer-family&quot; tabindex=&quot;-1&quot;&gt;Transfer Family &lt;a class=&quot;heading-anchor&quot; href=&quot;#transfer-family&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Have partners or older systems sending files over &lt;strong&gt;SFTP&lt;/strong&gt;, &lt;strong&gt;FTPS&lt;/strong&gt;, &lt;strong&gt;FTP&lt;/strong&gt; or &lt;strong&gt;AS2&lt;/strong&gt;, and don&#39;t want to run a server for them? &lt;strong&gt;Transfer Family&lt;/strong&gt; gives you a managed receiving endpoint, and the files go to S3 or EFS. Users come from within the service, Active Directory or your own identity system.&lt;/p&gt;
&lt;p&gt;Note that FTP is unencrypted, so it&#39;s available only inside a VPC. You pay by the hour for each endpoint, even without use.&lt;/p&gt;
&lt;h3 id=&quot;when-your-data-outgrows-the-internet&quot; tabindex=&quot;-1&quot;&gt;When your data outgrows the internet &lt;a class=&quot;heading-anchor&quot; href=&quot;#when-your-data-outgrows-the-internet&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before choosing how to move data, do the math. These are theoretical times at the line&#39;s full speed, and reality is slower:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;100 Mbps&lt;/th&gt;
&lt;th&gt;1 Gbps&lt;/th&gt;
&lt;th&gt;10 Gbps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1 TB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;22 hours&lt;/td&gt;
&lt;td&gt;2 hours&lt;/td&gt;
&lt;td&gt;13 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;10 TB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9 days&lt;/td&gt;
&lt;td&gt;22 hours&lt;/td&gt;
&lt;td&gt;2 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;100 TB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;93 days&lt;/td&gt;
&lt;td&gt;9 days&lt;/td&gt;
&lt;td&gt;22 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1 PB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.5 years&lt;/td&gt;
&lt;td&gt;93 days&lt;/td&gt;
&lt;td&gt;9 days&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;You have these options for large amounts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DataSync&lt;/strong&gt; if your line can take it, with ongoing sync.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Direct Connect&lt;/strong&gt; if the transfer is large and continuous, as explained in &lt;a href=&quot;/en/posts/aws-14-vpc-connectivity/&quot;&gt;part fourteen&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Transfer Terminal:&lt;/strong&gt; physical sites you visit with your own storage devices, connecting them to AWS&#39;s network at high speed.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;callout callout-note&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-info&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;circle cx=&quot;12&quot; cy=&quot;12&quot; r=&quot;8.5&quot;/&gt;&lt;path d=&quot;M12 11v5M12 8h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;What about Snowball?&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;You may read about &lt;strong&gt;AWS Snowball Edge&lt;/strong&gt;, devices AWS ships to you to fill and send back. But the service has been closed to new customers since November 2025, and &lt;a href=&quot;https://aws.amazon.com/snowball/&quot;&gt;AWS has announced&lt;/a&gt; the end of support in its commercial Regions on December 31, 2026. For computing at remote sites, AWS points to &lt;strong&gt;Outposts&lt;/strong&gt;. If you&#39;re studying for the Solutions Architect exam, its guide still lists the Snow Family, so remember the idea: move the data on a device when the line would take too long.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;comparing-storage-services&quot; tabindex=&quot;-1&quot;&gt;Comparing storage services &lt;a class=&quot;heading-anchor&quot; href=&quot;#comparing-storage-services&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;S3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Object&lt;/td&gt;
&lt;td&gt;Files, photos, backups and static sites&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;S3 Glacier&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Object archive&lt;/td&gt;
&lt;td&gt;Data that&#39;s rarely requested&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EBS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Network disk&lt;/td&gt;
&lt;td&gt;A disk for one server, and databases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Instance Store&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Temporary local disk&lt;/td&gt;
&lt;td&gt;Top speed for temporary data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Linux files&lt;/td&gt;
&lt;td&gt;A folder shared between several servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FSx for Windows&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SMB files&lt;/td&gt;
&lt;td&gt;Shared folders for Windows applications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FSx for Lustre&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High-performance files&lt;/td&gt;
&lt;td&gt;High-performance computing and model training&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FSx for ONTAP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-protocol files&lt;/td&gt;
&lt;td&gt;Moving NetApp systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FSx for OpenZFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;NFS files&lt;/td&gt;
&lt;td&gt;Linux workloads and moving ZFS systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bridge&lt;/td&gt;
&lt;td&gt;Your office reaching cloud storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DataSync&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Transfer&lt;/td&gt;
&lt;td&gt;Scheduled sync&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transfer Family&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Transfer&lt;/td&gt;
&lt;td&gt;Receiving files over SFTP and friends&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;hands-on-syncing-with-datasync&quot; tabindex=&quot;-1&quot;&gt;Hands-on: syncing with DataSync &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-syncing-with-datasync&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll move files between two buckets, which needs no agent. From CloudShell, prepare two buckets and some files:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;SRC&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;series-src-&lt;span class=&quot;token environment constant&quot;&gt;$RANDOM&lt;/span&gt;&lt;span class=&quot;token environment constant&quot;&gt;$RANDOM&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;DST&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;series-dst-&lt;span class=&quot;token environment constant&quot;&gt;$RANDOM&lt;/span&gt;&lt;span class=&quot;token environment constant&quot;&gt;$RANDOM&lt;/span&gt;

aws s3 mb s3://&lt;span class=&quot;token variable&quot;&gt;$SRC&lt;/span&gt;
aws s3 mb s3://&lt;span class=&quot;token variable&quot;&gt;$DST&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token for-or-select variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;file &lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt;.txt
  aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt;.txt s3://&lt;span class=&quot;token variable&quot;&gt;$SRC&lt;/span&gt;/
&lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;

&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;source: &lt;span class=&quot;token variable&quot;&gt;$SRC&lt;/span&gt;  destination: &lt;span class=&quot;token variable&quot;&gt;$DST&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Open &lt;strong&gt;DataSync&lt;/strong&gt; in the console and choose &lt;strong&gt;Create task&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Source:&lt;/strong&gt; create a new location of type S3, select the &lt;code&gt;series-src-...&lt;/code&gt; bucket, and choose to create an IAM role automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Destination:&lt;/strong&gt; the same with the &lt;code&gt;series-dst-...&lt;/code&gt; bucket.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Settings:&lt;/strong&gt; name the task &lt;code&gt;series-sync&lt;/code&gt;, choose &lt;strong&gt;Enhanced&lt;/strong&gt; if a mode option appears, and leave the rest as it is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run:&lt;/strong&gt; create the task, then choose &lt;strong&gt;Start&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When it finishes, check the destination:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws s3 &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; s3://&lt;span class=&quot;token variable&quot;&gt;$DST&lt;/span&gt;/&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Now add one file and run the task again:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;file 4&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; file4.txt
aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; file4.txt s3://&lt;span class=&quot;token variable&quot;&gt;$SRC&lt;/span&gt;/&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;On the new run&#39;s page you&#39;ll find one file transferred, because DataSync moves only what changed. That&#39;s what sets it apart from a full copy every time.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The cost here is a few cents. Delete the task and both locations from DataSync, then the roles it created in IAM. Finally delete the two buckets:&lt;/p&gt;
&lt;/aside&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws s3 rb s3://&lt;span class=&quot;token variable&quot;&gt;$SRC&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--force&lt;/span&gt;
aws s3 rb s3://&lt;span class=&quot;token variable&quot;&gt;$DST&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--force&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FSx&lt;/strong&gt; offers ready-made file systems: Windows, Lustre, ONTAP and OpenZFS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage Gateway&lt;/strong&gt; lets your office see the cloud as ordinary storage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DataSync&lt;/strong&gt; is for scheduled sync, and &lt;strong&gt;Transfer Family&lt;/strong&gt; for receiving over SFTP.&lt;/li&gt;
&lt;li&gt;Work out the transfer time before deciding, and note that Snowball is closed to new customers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 5&lt;/p&gt;
&lt;p&gt;A company is moving a Windows application that keeps its files on a shared SMB folder, with users signing in through Active Directory. It wants a managed service with no file servers to run. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;FSx for Windows File Server&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Amazon EFS&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;FSx for Lustre&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Amazon S3&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This gives Windows applications a real SMB file share tied into Active Directory, and AWS runs it for you.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; EFS is a shared file system for Linux, over NFS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This is for high-performance computing, and works with Linux devices only.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; S3 is reached through an API, and isn&#39;t a folder an application can open over SMB.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#amazon-fsx-ready-made-file-systems&quot;&gt;Amazon FSx: ready-made file systems&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/fsx/latest/WindowsGuide/what-is.html&quot;&gt;What is FSx for Windows File Server?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 5&lt;/p&gt;
&lt;p&gt;A research team runs a three-day simulation on a Linux cluster. It reads its input from S3, needs very high throughput, and saves its results back to S3, so a failed file system would only mean a re-run. Which option costs the least?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;FSx for Windows File Server&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;FSx for Lustre, with a Persistent file system&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;FSx for Lustre, with a Scratch file system&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Amazon EFS&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lustre is built for this speed and integrates with S3, and Scratch is the cheap option for temporary data, since nothing here depends on the data surviving a failure.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This is for SMB file shares, not high-performance Linux clusters.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This suits long-term data, and you&#39;d pay for copies the team doesn&#39;t need.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This is a general shared folder, and isn&#39;t built for this level of performance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#amazon-fsx-ready-made-file-systems&quot;&gt;Amazon FSx: ready-made file systems&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/fsx/latest/LustreGuide/using-fsx-lustre.html&quot;&gt;Deployment and storage class options for FSx for Lustre file systems&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 5&lt;/p&gt;
&lt;p&gt;A hospital&#39;s backup software writes to physical tapes, and staff are tired of storing and shipping them. It wants the backups in AWS, without changing the backup software. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;S3 File Gateway&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Tape Gateway&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Volume Gateway&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Transfer Family&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This presents a virtual tape library to the backup software, and the data goes to S3 and then Glacier.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This shows applications an NFS or SMB folder, while this software writes to tape.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This shows servers an iSCSI disk, not a tape library.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This receives files over protocols such as SFTP, which tape-based software doesn&#39;t use.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#storage-gateway-your-office-and-the-cloud&quot;&gt;Storage Gateway: your office and the cloud&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/storagegateway/latest/tgw/WhatIsStorageGateway.html&quot;&gt;What is Tape Gateway?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 5&lt;/p&gt;
&lt;p&gt;A new AWS customer has 100 TB on its own storage devices, which must be in S3 within two weeks. Its only line runs at 100 Mbps. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;DataSync over the current line&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Snowball Edge devices shipped by AWS&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;A new Direct Connect line&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Data Transfer Terminal&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The team takes its own storage devices to a physical AWS site with a high-speed connection and uploads from there, so the slow line no longer matters.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; At full speed, 100 TB over this line takes about 93 days.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This is closed to new customers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; Setting it up takes weeks and sometimes months, so it could miss the deadline.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#when-your-data-outgrows-the-internet&quot;&gt;When your data outgrows the internet&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/datatransferterminal/latest/userguide/what-is-dtt.html&quot;&gt;What is Data Transfer Terminal?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 5&lt;/p&gt;
&lt;p&gt;A company is leaving its data center. Its 30 TB NFS server must be copied to AWS and kept in sync until the cutover, and its partners send daily files over SFTP and can&#39;t change how they do it. Which &lt;strong&gt;two&lt;/strong&gt; services fit? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Tape Gateway&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;DataSync&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;FSx for Lustre&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Volume Gateway&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Transfer Family&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;DataSync copies the NFS data, and on each later run moves only what changed. Transfer Family gives partners a managed SFTP endpoint, with their files going to S3 or EFS.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This is for backup software that writes to tape.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This is a high-performance file system, and doesn&#39;t move data out of a data center.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This shows on-site servers an iSCSI disk, and the company is leaving its site.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#datasync&quot;&gt;DataSync&lt;/a&gt; and &lt;a href=&quot;#transfer-family&quot;&gt;Transfer Family&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/datasync/latest/userguide/how-datasync-transfer-works.html&quot;&gt;How AWS DataSync works&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/transfer/latest/userguide/what-is-aws-transfer-family.html&quot;&gt;What is AWS Transfer Family?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;That completes the storage section. You now have a strong application with a database, a network and storage, but its pieces are all wired directly together. In &lt;a href=&quot;/en/posts/aws-19-sqs-sns-kinesis/&quot;&gt;&lt;strong&gt;part nineteen&lt;/strong&gt;&lt;/a&gt; we start the modern applications section, separating them with SQS, SNS and Kinesis.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>S3: Security and Encryption</title>
    <link href="https://blog.sultanops.com/en/posts/aws-17-s3-security/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-17-s3-security/</id>
    <summary>How to encrypt your data in S3 and who holds the keys, enforcing HTTPS, sharing a private file with a signed link, understanding CORS, and protecting data from deletion with MFA Delete and Object Lock, with a hands-on.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-15-s3-basics/&quot;&gt;part fifteen&lt;/a&gt; we learned that everything is private by default, and that Block Public Access protects you from opening things by mistake. This part covers the remaining layers: encryption, sharing files safely, and protecting data even from the account&#39;s own administrators.&lt;/p&gt;
&lt;h2 id=&quot;encryption-at-rest&quot; tabindex=&quot;-1&quot;&gt;Encryption at rest &lt;a class=&quot;heading-anchor&quot; href=&quot;#encryption-at-rest&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You have two questions: &lt;strong&gt;where does encryption happen?&lt;/strong&gt; and &lt;strong&gt;who holds the key?&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 214&quot; role=&quot;img&quot; aria-labelledby=&quot;enc-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;enc-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;text x=&quot;320&quot; y=&quot;22&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Server-side encryption (SSE): S3 encrypts the file when it arrives&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;34&quot; width=&quot;150&quot; height=&quot;58&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;95&quot; y=&quot;58&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Your app&lt;/text&gt;
&lt;text x=&quot;95&quot; y=&quot;78&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;A plain file&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;34&quot; width=&quot;150&quot; height=&quot;58&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;58&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;S3&lt;/text&gt;
&lt;text x=&quot;545&quot; y=&quot;78&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Encrypts, then stores&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Encrypted in transit with TLS&lt;/text&gt;
&lt;line x1=&quot;170&quot; y1=&quot;64&quot; x2=&quot;468&quot; y2=&quot;64&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#enc-arrow)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;130&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Client-side encryption: you encrypt before sending&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;144&quot; width=&quot;150&quot; height=&quot;58&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;95&quot; y=&quot;168&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Your app&lt;/text&gt;
&lt;text x=&quot;95&quot; y=&quot;188&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Encrypts first&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;144&quot; width=&quot;150&quot; height=&quot;58&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;168&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;S3&lt;/text&gt;
&lt;text x=&quot;545&quot; y=&quot;188&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Stores it as received&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;164&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Encrypted before it leaves, with TLS on top&lt;/text&gt;
&lt;line x1=&quot;170&quot; y1=&quot;174&quot; x2=&quot;468&quot; y2=&quot;174&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#enc-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;enc-caption&quot;&gt;With SSE, S3 encrypts the file after it arrives; with client-side encryption, S3 never sees the file unencrypted.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Who holds the key&lt;/th&gt;
&lt;th&gt;When to choose it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SSE-S3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;S3 entirely&lt;/td&gt;
&lt;td&gt;The default for every new object, and enough for most cases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SSE-KMS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;KMS, with you controlling its permissions&lt;/td&gt;
&lt;td&gt;You want a record of every use of the key, and finer control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DSSE-KMS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;KMS, with two layers of encryption&lt;/td&gt;
&lt;td&gt;Regulations requiring two layers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SSE-C&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You, sending it with every request&lt;/td&gt;
&lt;td&gt;Blocked by default on new buckets since April 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Client-side&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You entirely&lt;/td&gt;
&lt;td&gt;You never want AWS to see the data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;watch-out-with-sse-kms&quot; tabindex=&quot;-1&quot;&gt;Watch out with SSE-KMS &lt;a class=&quot;heading-anchor&quot; href=&quot;#watch-out-with-sse-kms&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Every read or write calls KMS, and KMS has a limit on requests per second depending on the Region. If you have heavy load, turn on &lt;strong&gt;S3 Bucket Keys&lt;/strong&gt;: an intermediate key at the bucket level that greatly reduces KMS requests, and with them the cost.&lt;/p&gt;
&lt;p&gt;Anyone reading the object also needs permission on S3 &lt;strong&gt;and on the KMS key&lt;/strong&gt; together. This is a well-known cause of &lt;code&gt;AccessDenied&lt;/code&gt; errors even when the S3 policy is right.&lt;/p&gt;
&lt;h2 id=&quot;encryption-in-transit&quot; tabindex=&quot;-1&quot;&gt;Encryption in transit &lt;a class=&quot;heading-anchor&quot; href=&quot;#encryption-in-transit&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;S3 accepts both HTTP and HTTPS. To enforce HTTPS, deny any unencrypted request using the &lt;code&gt;aws:SecureTransport&lt;/code&gt; condition:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;JSON&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2012-10-17&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Statement&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Deny&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Principal&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s3:*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:s3:::my-bucket&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:s3:::my-bucket/*&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Condition&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;Bool&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;aws:SecureTransport&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;In the same way you can enforce a particular type of encryption on every upload. The policy is evaluated before default encryption, so a denied request never reaches it.&lt;/p&gt;
&lt;h2 id=&quot;sharing-a-private-file-signed-links&quot; tabindex=&quot;-1&quot;&gt;Sharing a private file: signed links &lt;a class=&quot;heading-anchor&quot; href=&quot;#sharing-a-private-file-signed-links&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Want a customer to download their invoice without opening the bucket or giving them an account? A &lt;strong&gt;pre-signed URL&lt;/strong&gt; is a link carrying a signature and an expiry:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It carries the &lt;strong&gt;signer&#39;s permissions&lt;/strong&gt;, so if they can&#39;t read the file, the link won&#39;t work.&lt;/li&gt;
&lt;li&gt;It works for &lt;strong&gt;downloads and uploads&lt;/strong&gt;, such as sending a photo from the browser directly to S3 without going through your server.&lt;/li&gt;
&lt;li&gt;Its lifetime is limited, and if signed with a temporary role it ends when the session does.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;cors-when-the-browser-stops-you&quot; tabindex=&quot;-1&quot;&gt;CORS: when the browser stops you &lt;a class=&quot;heading-anchor&quot; href=&quot;#cors-when-the-browser-stops-you&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;CORS&lt;/strong&gt; is a protection in the browser, not in S3. An &lt;strong&gt;origin&lt;/strong&gt; is the protocol, domain and port. So if a page at &lt;code&gt;https://app.example.com&lt;/code&gt; requests a file from &lt;code&gt;https://my-bucket.s3.amazonaws.com&lt;/code&gt;, the browser treats them as two different origins, and asks the bucket: do you allow this?&lt;/p&gt;
&lt;p&gt;If you get a CORS error in the browser, add the settings to the bucket:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;JSON&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;AllowedOrigins&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://app.example.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;AllowedMethods&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;GET&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;PUT&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;AllowedHeaders&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;MaxAgeSeconds&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;protection-from-deletion&quot; tabindex=&quot;-1&quot;&gt;Protection from deletion &lt;a class=&quot;heading-anchor&quot; href=&quot;#protection-from-deletion&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Even correct permissions don&#39;t protect you from a mistake, a compromised account or ransomware. You have three layers:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MFA Delete&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires an MFA code to permanently delete a version or suspend versioning&lt;/td&gt;
&lt;td&gt;Only the root user can enable it, through commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Object Lock&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Blocks deleting or changing a version for a period&lt;/td&gt;
&lt;td&gt;Versioning must be on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Glacier Vault Lock&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Locks the policy of an older Glacier vault for good&lt;/td&gt;
&lt;td&gt;For older vaults; Object Lock is better for anything new&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;object-lock-modes&quot; tabindex=&quot;-1&quot;&gt;Object Lock modes &lt;a class=&quot;heading-anchor&quot; href=&quot;#object-lock-modes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Who can delete before the period ends&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Governance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only users with a special permission&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compliance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nobody, not even the root user&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;There&#39;s also &lt;strong&gt;Legal Hold&lt;/strong&gt;: a lock with no set period that stays until you remove it, useful for legal cases.&lt;/p&gt;
&lt;aside class=&quot;callout callout-warning&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-alert&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 4l9 16H3L12 4z&quot;/&gt;&lt;path d=&quot;M12 10v4M12 17h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Compliance has no way back&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Lock a file in Compliance mode for ten years and you&#39;ll pay for it for ten years, and nobody can delete it, not even AWS support. Try Governance mode with a short period first.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;logs-and-monitoring&quot; tabindex=&quot;-1&quot;&gt;Logs and monitoring &lt;a class=&quot;heading-anchor&quot; href=&quot;#logs-and-monitoring&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Access logs:&lt;/strong&gt; record every request in a &lt;strong&gt;different&lt;/strong&gt; bucket. Don&#39;t use the same bucket, because every log entry generates another, growing endlessly and growing your bill.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CloudTrail:&lt;/strong&gt; records management operations, plus data operations if you turn them on. We cover it in &lt;a href=&quot;/en/posts/aws-25-monitoring-auditing/&quot;&gt;part twenty-five&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;access-points-a-door-for-each-team&quot; tabindex=&quot;-1&quot;&gt;Access Points: a door for each team &lt;a class=&quot;heading-anchor&quot; href=&quot;#access-points-a-door-for-each-team&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If many teams use one big bucket, the bucket policy becomes long and risky. &lt;strong&gt;Access Points&lt;/strong&gt; give each team a door with its own name and policy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;finance&lt;/code&gt; access point allows the finance team on &lt;code&gt;finance/*&lt;/code&gt; only.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;sales&lt;/code&gt; access point allows the sales team on &lt;code&gt;sales/*&lt;/code&gt; only.&lt;/li&gt;
&lt;li&gt;You can also make an access point accept traffic only from inside one VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;hands-on-encryption-a-signed-link-and-enforcing-https&quot; tabindex=&quot;-1&quot;&gt;Hands-on: encryption, a signed link and enforcing HTTPS &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-encryption-a-signed-link-and-enforcing-https&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll carry on with the same bucket in &lt;code&gt;BUCKET&lt;/code&gt;. Upload a file and check its default encryption, then upload one with KMS:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;secret invoice&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; invoice.txt
aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; invoice.txt s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/invoice.txt

aws s3api head-object &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--key&lt;/span&gt; invoice.txt &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; ServerSideEncryption

aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; invoice.txt s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/invoice-kms.txt &lt;span class=&quot;token parameter variable&quot;&gt;--sse&lt;/span&gt; aws:kms

aws s3api head-object &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--key&lt;/span&gt; invoice-kms.txt &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[ServerSideEncryption,SSEKMSKeyId]&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The first shows &lt;code&gt;AES256&lt;/code&gt;, meaning SSE-S3, and the second &lt;code&gt;aws:kms&lt;/code&gt; with the key&#39;s ID.&lt;/p&gt;
&lt;p&gt;Now create a signed link valid for 60 seconds, and try it:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws s3 presign s3://$BUCKET/invoice.txt --expires-in &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$URL&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;It prints the file&#39;s contents, even though the bucket is private. Wait a minute and repeat the same &lt;code&gt;curl&lt;/code&gt; command, and it returns &lt;code&gt;AccessDenied&lt;/code&gt; with a message that the request has expired.&lt;/p&gt;
&lt;p&gt;Now enforce HTTPS on the bucket:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws s3api put-bucket-policy &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--policy&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [{
    &quot;Sid&quot;: &quot;DenyHttp&quot;,
    &quot;Effect&quot;: &quot;Deny&quot;,
    &quot;Principal&quot;: &quot;*&quot;,
    &quot;Action&quot;: &quot;s3:*&quot;,
    &quot;Resource&quot;: [&quot;arn:aws:s3:::&#39;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&quot;, &quot;arn:aws:s3:::&#39;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/*&quot;],
    &quot;Condition&quot;: {&quot;Bool&quot;: {&quot;aws:SecureTransport&quot;: &quot;false&quot;}}
  }]
}&#39;&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws s3 presign s3://$BUCKET/invoice.txt --expires-in &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; /dev/null &lt;span class=&quot;token parameter variable&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https: %{http_code}&lt;span class=&quot;token entity&quot; title=&quot;&#92;n&quot;&gt;&#92;n&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$URL&lt;/span&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; /dev/null &lt;span class=&quot;token parameter variable&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;http: %{http_code}&lt;span class=&quot;token entity&quot; title=&quot;&#92;n&quot;&gt;&#92;n&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;${URL&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;https&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;http&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;}&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The same link returns &lt;code&gt;200&lt;/code&gt; over HTTPS and &lt;code&gt;403&lt;/code&gt; over HTTP.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We no longer need this bucket. From the S3 page select it and choose &lt;strong&gt;Empty&lt;/strong&gt;, then &lt;strong&gt;Delete&lt;/strong&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Every new object is encrypted with &lt;strong&gt;SSE-S3&lt;/strong&gt; automatically; choose &lt;strong&gt;SSE-KMS&lt;/strong&gt; for control and a record, along with &lt;strong&gt;Bucket Keys&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enforce &lt;strong&gt;HTTPS&lt;/strong&gt; with the &lt;code&gt;aws:SecureTransport&lt;/code&gt; condition.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Signed links&lt;/strong&gt; share a private file temporarily without opening the bucket.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CORS&lt;/strong&gt; comes from the browser, and you solve it in the bucket&#39;s settings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Object Lock&lt;/strong&gt; protects you from deletion, even from root in Compliance mode.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 5&lt;/p&gt;
&lt;p&gt;A role has &lt;code&gt;s3:GetObject&lt;/code&gt; on a bucket. It can read objects encrypted with SSE-S3, but gets &lt;code&gt;AccessDenied&lt;/code&gt; on those encrypted with SSE-KMS and a customer managed key. What&#39;s missing?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;S3 Bucket Keys on the bucket&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;The &lt;code&gt;kms:Decrypt&lt;/code&gt; permission on that key&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;A CORS rule on the bucket&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;The &lt;code&gt;aws:SecureTransport&lt;/code&gt; condition&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Reading an SSE-KMS object needs permission on S3 and on the KMS key together, which is why this error appears even when the S3 policy is right.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; These lower the number of KMS requests and the cost, and don&#39;t grant any permission.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; CORS is a browser rule, and has nothing to do with a role&#39;s permissions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This enforces HTTPS, and it denies rather than grants.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#watch-out-with-sse-kms&quot;&gt;Watch out with SSE-KMS&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html&quot;&gt;Using server-side encryption with AWS KMS keys&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 5&lt;/p&gt;
&lt;p&gt;An online store wants each customer to download their invoice from a private bucket, using a link that stops working after 15 minutes. Customers have no AWS accounts. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A bucket policy allowing public reads on &lt;code&gt;invoices/*&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;An IAM user for each customer&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;A CORS rule allowing the store&#39;s domain&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A pre-signed URL created by the store&#39;s backend&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A pre-signed URL carries a signature and an expiry and works with the signer&#39;s permissions, so the bucket stays private.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Anyone could read any invoice this way, at any time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; Creating and managing users for customers is heavy, and there&#39;s no need for it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This is a browser permission between sites, and doesn&#39;t open private files to anyone.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#sharing-a-private-file-signed-links&quot;&gt;Sharing a private file: signed links&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html&quot;&gt;Download and upload objects with presigned URLs&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 5&lt;/p&gt;
&lt;p&gt;A page at &lt;code&gt;https://app.example.com&lt;/code&gt; loads JSON from a bucket using JavaScript. The browser console shows a CORS error, yet the same request from &lt;code&gt;curl&lt;/code&gt; succeeds. What should the team do?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Add a CORS rule on the bucket allowing that origin&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Turn off Block Public Access&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Encrypt the file with SSE-KMS&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Turn on versioning&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CORS is a browser protection. The browser asks the bucket whether this origin is allowed, while &lt;code&gt;curl&lt;/code&gt; doesn&#39;t ask, which is why only the browser complained.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; The request already succeeds from &lt;code&gt;curl&lt;/code&gt;, so access isn&#39;t the problem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; Encryption has nothing to do with the origins a browser accepts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This keeps old versions, and changes nothing the browser checks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#cors-when-the-browser-stops-you&quot;&gt;CORS: when the browser stops you&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/cors.html&quot;&gt;Using cross-origin resource sharing (CORS)&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 5&lt;/p&gt;
&lt;p&gt;A bank must keep records for seven years in a way that nobody can delete them during that time, not even the root user. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;MFA Delete&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Object Lock in Governance mode&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Object Lock in Compliance mode&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A bucket policy denying &lt;code&gt;s3:DeleteObject&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In Compliance mode, no user can delete or overwrite a locked version until its period ends, including the root user, and the period can&#39;t be shortened.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This only asks for an MFA code, so the root user holding that device can still delete.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; Users with a special permission can still delete in this mode.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Someone with enough permissions can simply change the policy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#object-lock-modes&quot;&gt;Object Lock modes&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html&quot;&gt;Locking objects with Object Lock&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 5&lt;/p&gt;
&lt;p&gt;An audit sets two requirements for a bucket: requests must only be accepted over HTTPS, and there must be a record of every use of the encryption key. Which &lt;strong&gt;two&lt;/strong&gt; changes meet these? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Keep Block Public Access on&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Set default encryption to SSE-S3&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Add a bucket policy denying requests when &lt;code&gt;aws:SecureTransport&lt;/code&gt; is false&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Turn on Object Lock&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Set default encryption to SSE-KMS&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The policy rejects any unencrypted request, and with SSE-KMS you can audit the use of the key in CloudTrail.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This stops public access, and doesn&#39;t look at HTTP or HTTPS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; S3 holds the key entirely here, so you get no record of each use.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This protects against deletion, and meets neither requirement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#encryption-at-rest&quot;&gt;Encryption at rest&lt;/a&gt; and &lt;a href=&quot;#encryption-in-transit&quot;&gt;Encryption in transit&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/security-best-practices.html&quot;&gt;Security best practices for Amazon S3&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html&quot;&gt;Using server-side encryption with AWS KMS keys&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;S3 isn&#39;t the only option. What if you have a Windows system, an office wanting to reach cloud storage, or millions of files to move? In &lt;a href=&quot;/en/posts/aws-18-storage-transfer/&quot;&gt;&lt;strong&gt;part eighteen&lt;/strong&gt;&lt;/a&gt; we cover the remaining storage and transfer services.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>S3: Storage Classes and Lifecycle</title>
    <link href="https://blog.sultanops.com/en/posts/aws-16-s3-classes-lifecycle/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-16-s3-classes-lifecycle/</id>
    <summary>Not every file deserves the same price. Get to know S3&#39;s storage classes from Standard to Deep Archive, when to choose each, how lifecycle rules move your files automatically, and how much you can save on your bill.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-15-s3-basics/&quot;&gt;part fifteen&lt;/a&gt; we stored everything the default way. But think about your application: a product photo is requested every second, while a five-year-old invoice is opened only during an audit. Why pay the same for both?&lt;/p&gt;
&lt;p&gt;Storage classes give you that choice: the less a file is accessed, the less it costs to store, and the more it costs or the longer it takes to retrieve.&lt;/p&gt;
&lt;h2 id=&quot;durability-and-availability&quot; tabindex=&quot;-1&quot;&gt;Durability and availability &lt;a class=&quot;heading-anchor&quot; href=&quot;#durability-and-availability&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Two terms you need to tell apart:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Durability:&lt;/strong&gt; will the file be lost? 99.999999999% for all classes, noting that classes in a single Availability Zone lose their data if that zone is destroyed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Availability:&lt;/strong&gt; can you reach it right now? This varies by class, such as 99.99% for Standard.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-classes&quot; tabindex=&quot;-1&quot;&gt;The classes &lt;a class=&quot;heading-anchor&quot; href=&quot;#the-classes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Suits&lt;/th&gt;
&lt;th&gt;Retrieval&lt;/th&gt;
&lt;th&gt;Minimum period&lt;/th&gt;
&lt;th&gt;Approx. price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Standard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Frequently requested data&lt;/td&gt;
&lt;td&gt;Instant&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;0.023&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Intelligent-Tiering&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Unknown access patterns&lt;/td&gt;
&lt;td&gt;Instant in the automatic tiers&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;By tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Standard-IA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;About once a month&lt;/td&gt;
&lt;td&gt;Instant, with a retrieval fee&lt;/td&gt;
&lt;td&gt;30 days&lt;/td&gt;
&lt;td&gt;0.0125&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;One Zone-IA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data you can recreate&lt;/td&gt;
&lt;td&gt;Instant, with a fee&lt;/td&gt;
&lt;td&gt;30 days&lt;/td&gt;
&lt;td&gt;0.01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Glacier Instant Retrieval&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Once every three months&lt;/td&gt;
&lt;td&gt;Instant, with a higher fee&lt;/td&gt;
&lt;td&gt;90 days&lt;/td&gt;
&lt;td&gt;0.004&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Glacier Flexible Retrieval&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Once or twice a year&lt;/td&gt;
&lt;td&gt;Minutes to hours&lt;/td&gt;
&lt;td&gt;90 days&lt;/td&gt;
&lt;td&gt;0.0036&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Glacier Deep Archive&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Less than once a year&lt;/td&gt;
&lt;td&gt;12 to 48 hours&lt;/td&gt;
&lt;td&gt;180 days&lt;/td&gt;
&lt;td&gt;0.00099&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Prices are in dollars per gigabyte per month, approximate for US Regions, so check the pricing page for yours.&lt;/p&gt;
&lt;p&gt;All these classes keep data in three or more Availability Zones, except &lt;strong&gt;One Zone-IA&lt;/strong&gt;. There&#39;s also &lt;strong&gt;S3 Express One Zone&lt;/strong&gt;: very high performance with single-digit millisecond latency, in one Availability Zone, using a special type of bucket, at a higher price. It suits analytics and model training that need great speed.&lt;/p&gt;
&lt;h3 id=&quot;intelligent-tiering-when-you-dont-know&quot; tabindex=&quot;-1&quot;&gt;Intelligent-Tiering: when you don&#39;t know &lt;a class=&quot;heading-anchor&quot; href=&quot;#intelligent-tiering-when-you-dont-know&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you can&#39;t tell how often a file will be requested, this class moves it by itself according to use:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;th&gt;Retrieval&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Frequent Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;At the start&lt;/td&gt;
&lt;td&gt;Instant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Infrequent Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;After 30 days without access&lt;/td&gt;
&lt;td&gt;Instant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Archive Instant Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;After 90 days without access&lt;/td&gt;
&lt;td&gt;Instant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Archive Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Optional, from 90 days&lt;/td&gt;
&lt;td&gt;Hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deep Archive Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Optional, from 180 days&lt;/td&gt;
&lt;td&gt;Up to 12 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;You pay a small monitoring fee per object with no retrieval fees, and if a file is requested it returns to the first tier.&lt;/p&gt;
&lt;h3 id=&quot;glacier-flexible-and-deep-archive-request-before-reading&quot; tabindex=&quot;-1&quot;&gt;Glacier Flexible and Deep Archive: request before reading &lt;a class=&quot;heading-anchor&quot; href=&quot;#glacier-flexible-and-deep-archive-request-before-reading&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In these classes you can&#39;t read a file directly. You must first request its &lt;strong&gt;restore&lt;/strong&gt;, choosing a speed:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Expedited&lt;/th&gt;
&lt;th&gt;Standard&lt;/th&gt;
&lt;th&gt;Bulk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flexible Retrieval&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1 to 5 minutes&lt;/td&gt;
&lt;td&gt;3 to 5 hours&lt;/td&gt;
&lt;td&gt;5 to 12 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deep Archive&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not available&lt;/td&gt;
&lt;td&gt;12 hours&lt;/td&gt;
&lt;td&gt;48 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;aside class=&quot;callout callout-warning&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-alert&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 4l9 16H3L12 4z&quot;/&gt;&lt;path d=&quot;M12 10v4M12 17h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Three traps in the cheap classes&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Minimum storage period:&lt;/strong&gt; delete a file from Glacier Deep Archive after a month, and you pay for the full 180 days.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimum billable size:&lt;/strong&gt; the IA classes and Glacier Instant bill any object as at least 128 KB, so thousands of small files can cost more than Standard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retrieval fees:&lt;/strong&gt; if you read data a lot, Standard-IA can end up pricier than Standard.&lt;/li&gt;
&lt;/ul&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;lifecycle&quot; tabindex=&quot;-1&quot;&gt;Lifecycle &lt;a class=&quot;heading-anchor&quot; href=&quot;#lifecycle&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You don&#39;t need to move files by hand. &lt;strong&gt;Lifecycle&lt;/strong&gt; rules do it automatically according to a file&#39;s age. Take an application&#39;s logs, for example:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 170&quot; role=&quot;img&quot; aria-labelledby=&quot;lifecycle-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;life-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;text x=&quot;70&quot; y=&quot;34&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Day 0&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;46&quot; width=&quot;100&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;70&quot; y=&quot;82&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Standard&lt;/text&gt;
&lt;text x=&quot;195&quot; y=&quot;34&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Day 30&lt;/text&gt;
&lt;rect x=&quot;145&quot; y=&quot;46&quot; width=&quot;100&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;195&quot; y=&quot;82&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Standard-IA&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;34&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Day 90&lt;/text&gt;
&lt;rect x=&quot;270&quot; y=&quot;46&quot; width=&quot;100&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;72&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Glacier&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;92&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Flexible&lt;/text&gt;
&lt;text x=&quot;445&quot; y=&quot;34&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Day 365&lt;/text&gt;
&lt;rect x=&quot;395&quot; y=&quot;46&quot; width=&quot;100&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;445&quot; y=&quot;72&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Deep&lt;/text&gt;
&lt;text x=&quot;445&quot; y=&quot;92&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Archive&lt;/text&gt;
&lt;text x=&quot;570&quot; y=&quot;34&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Day 2555&lt;/text&gt;
&lt;rect x=&quot;520&quot; y=&quot;46&quot; width=&quot;100&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-dasharray=&quot;5 5&quot;/&gt;
&lt;text x=&quot;570&quot; y=&quot;82&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Delete&lt;/text&gt;
&lt;line x1=&quot;120&quot; y1=&quot;77&quot; x2=&quot;143&quot; y2=&quot;77&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#life-arrow)&quot;/&gt;
&lt;line x1=&quot;245&quot; y1=&quot;77&quot; x2=&quot;268&quot; y2=&quot;77&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#life-arrow)&quot;/&gt;
&lt;line x1=&quot;370&quot; y1=&quot;77&quot; x2=&quot;393&quot; y2=&quot;77&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#life-arrow)&quot;/&gt;
&lt;line x1=&quot;495&quot; y1=&quot;77&quot; x2=&quot;518&quot; y2=&quot;77&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#life-arrow)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;136&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Cheaper storage; slower, pricier retrieval&lt;/text&gt;
&lt;line x1=&quot;20&quot; y1=&quot;150&quot; x2=&quot;618&quot; y2=&quot;150&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#life-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;lifecycle-caption&quot;&gt;A single rule moves the file through the classes as it ages, then deletes it after seven years.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A rule has two kinds of action, and you apply it to a specific prefix or tag:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transition&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Move the file to a cheaper class after a number of days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Expiration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Delete the file after a period, or old versions, or uploads that never finished&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A few things to watch for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Moves only go down&lt;/strong&gt; the stairs, and the minimum before Standard-IA is 30 days.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Files smaller than 128 KB&lt;/strong&gt; don&#39;t move by default, because moving them costs more than it saves.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The move itself has a fee&lt;/strong&gt; per thousand objects, so watch out for millions of small files.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;callout callout-tip&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-bulb&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M9 18h6M10 21h4M12 3a6 6 0 0 0-3.5 10.9c.6.45 1 1.15 1 1.9V16h5v-.2c0-.75.4-1.45 1-1.9A6 6 0 0 0 12 3z&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Two rules to add to any bucket&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Delete &lt;strong&gt;incomplete multipart uploads&lt;/strong&gt; after a week, since they&#39;re billed and don&#39;t appear in listings. And if versioning is on, delete &lt;strong&gt;old versions&lt;/strong&gt; after a period that suits you.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;how-do-you-know-what-to-choose&quot; tabindex=&quot;-1&quot;&gt;How do you know what to choose? &lt;a class=&quot;heading-anchor&quot; href=&quot;#how-do-you-know-what-to-choose&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You don&#39;t need to guess. You have tools that read your actual use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Storage Class Analysis:&lt;/strong&gt; watches access to a prefix or bucket, and suggests when to move from Standard to Standard-IA.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage Lens:&lt;/strong&gt; a dashboard across all your accounts: sizes, growth, and buckets with incomplete uploads or no encryption. It has free metrics and paid advanced ones.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have millions of files and want to do something to all of them at once, such as changing class or copying, &lt;strong&gt;S3 Batch Operations&lt;/strong&gt; runs it on a list from &lt;strong&gt;S3 Inventory&lt;/strong&gt;, with a report of the results.&lt;/p&gt;
&lt;p&gt;On the other side, if you share huge data with another party, &lt;strong&gt;Requester Pays&lt;/strong&gt; has them pay the request and download costs instead of you.&lt;/p&gt;
&lt;p&gt;And if you upload millions of small files you won&#39;t read one by one, such as logs, bundle them into one archive first. Every &lt;code&gt;PUT&lt;/code&gt; is a paid request, so one large upload can cost far less than a million small ones.&lt;/p&gt;
&lt;h2 id=&quot;hands-on-classes-and-a-lifecycle-rule&quot; tabindex=&quot;-1&quot;&gt;Hands-on: classes and a lifecycle rule &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-classes-and-a-lifecycle-rule&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll carry on with the bucket from the previous part. If your CloudShell session ended, set its name in &lt;code&gt;BUCKET&lt;/code&gt; again. Upload a file to a specific class, and check the class:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;monthly report&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; report.txt

aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; report.txt s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/reports/report.txt --storage-class STANDARD_IA

aws s3api head-object &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--key&lt;/span&gt; reports/report.txt &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; StorageClass&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Now add the lifecycle rule from the diagram to the &lt;code&gt;logs/&lt;/code&gt; prefix:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws s3api put-bucket-lifecycle-configuration &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --lifecycle-configuration &lt;span class=&quot;token string&quot;&gt;&#39;{
  &quot;Rules&quot;: [{
    &quot;ID&quot;: &quot;logs-rule&quot;,
    &quot;Status&quot;: &quot;Enabled&quot;,
    &quot;Filter&quot;: {&quot;Prefix&quot;: &quot;logs/&quot;},
    &quot;Transitions&quot;: [
      {&quot;Days&quot;: 30, &quot;StorageClass&quot;: &quot;STANDARD_IA&quot;},
      {&quot;Days&quot;: 90, &quot;StorageClass&quot;: &quot;GLACIER&quot;},
      {&quot;Days&quot;: 365, &quot;StorageClass&quot;: &quot;DEEP_ARCHIVE&quot;}
    ],
    &quot;Expiration&quot;: {&quot;Days&quot;: 2555},
    &quot;AbortIncompleteMultipartUpload&quot;: {&quot;DaysAfterInitiation&quot;: 7}
  }]
}&#39;&lt;/span&gt;

aws s3api get-bucket-lifecycle-configuration &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Rules[0].Transitions&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; table&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Here&#39;s the fun part: upload a file to Glacier and try to read it:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;old invoice&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; old.txt
aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; old.txt s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/archive/old.txt --storage-class GLACIER

aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/archive/old.txt -&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;It returns an &lt;code&gt;InvalidObjectState&lt;/code&gt; error, because the file is stored but can&#39;t be read directly. Request a restore:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws s3api restore-object &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--key&lt;/span&gt; archive/old.txt &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --restore-request &lt;span class=&quot;token string&quot;&gt;&#39;{&quot;Days&quot;: 1, &quot;GlacierJobParameters&quot;: {&quot;Tier&quot;: &quot;Standard&quot;}}&#39;&lt;/span&gt;

aws s3api head-object &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--key&lt;/span&gt; archive/old.txt &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[StorageClass,Restore]&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;You&#39;ll see &lt;code&gt;ongoing-request=&amp;quot;true&amp;quot;&lt;/code&gt;. After 3 to 5 hours it becomes &lt;code&gt;false&lt;/code&gt;, and a temporary copy is available to read for one day.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;The cost of this experiment&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The files are tiny, so they cost less than a cent, even with Glacier&#39;s minimum period. Keep the bucket if you&#39;re carrying on to the next part.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The less the access, the lower the storage price&lt;/strong&gt;, and the higher the cost or time of retrieval.&lt;/li&gt;
&lt;li&gt;If you don&#39;t know the access pattern, &lt;strong&gt;Intelligent-Tiering&lt;/strong&gt; moves files by itself.&lt;/li&gt;
&lt;li&gt;Watch out for the &lt;strong&gt;minimum storage period&lt;/strong&gt;, the &lt;strong&gt;minimum billable size&lt;/strong&gt; and &lt;strong&gt;retrieval fees&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lifecycle&lt;/strong&gt; rules move and delete files automatically, and always add a rule for incomplete uploads.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage Lens and Storage Class Analysis&lt;/strong&gt; let you decide with numbers, not guesses.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 5&lt;/p&gt;
&lt;p&gt;A startup is launching a new data platform. Some files may sit untouched for months and then be read heavily, and nobody can predict which. It wants lower storage costs, with no retrieval fees and no rules to maintain. Which class fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Standard-IA&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;One Zone-IA&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Glacier Flexible Retrieval&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Intelligent-Tiering&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It watches each file&#39;s use and moves it between tiers by itself, for a small monitoring fee and with no retrieval fees.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This charges for every retrieval, so a heavily read file can end up costing more.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This also charges for retrieval, and keeps data in a single Availability Zone.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; Files here need a restore before reading, which can take hours.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#intelligent-tiering-when-you-dont-know&quot;&gt;Intelligent-Tiering: when you don&#39;t know&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/intelligent-tiering.html&quot;&gt;Managing storage costs with Amazon S3 Intelligent-Tiering&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 5&lt;/p&gt;
&lt;p&gt;A video service keeps low-resolution copies of its films, which it can regenerate from the originals at any time. Each is read about once a month and must open instantly. Which class costs the least while meeting this?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Standard&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;One Zone-IA&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Glacier Deep Archive&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Glacier Flexible Retrieval&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The copies can be regenerated, so losing them with a zone isn&#39;t a disaster, and there&#39;s no need to pay for three zones. Retrieval stays instant.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This works, but at a higher price for protection this data doesn&#39;t need.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; A restore here takes 12 to 48 hours.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Files here need a restore before reading, which takes minutes to hours.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#the-classes&quot;&gt;The classes&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.html&quot;&gt;Understanding and managing Amazon S3 storage classes&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 5&lt;/p&gt;
&lt;p&gt;A company&#39;s application logs must stay instantly readable for 30 days, then be archived cheaply for a year, then be removed. The team doesn&#39;t want any scripts to run. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A lifecycle rule on the &lt;code&gt;logs/&lt;/code&gt; prefix, with a transition and an expiration&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A scheduled Lambda function that moves and deletes the files&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Storage Lens, with its advanced metrics&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Cross-Region Replication to a cheaper Region&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A lifecycle rule moves files to a cheaper class at the age you set and deletes them later, with nothing for you to run.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This works, but it&#39;s code you have to write and maintain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This shows you numbers, and doesn&#39;t move or delete anything.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This makes more copies, and neither archives nor removes the originals.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#lifecycle&quot;&gt;Lifecycle&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html&quot;&gt;Managing the lifecycle of objects&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 5&lt;/p&gt;
&lt;p&gt;An auditor&#39;s script tries to read a 20 MB file stored in Glacier Flexible Retrieval, and gets an &lt;code&gt;InvalidObjectState&lt;/code&gt; error. The auditor needs the file within 10 minutes. What should the team do?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Give the script&#39;s role the &lt;code&gt;s3:GetObject&lt;/code&gt; permission&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Request a restore with the Bulk option&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Request a restore with the Expedited option&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Add a lifecycle rule moving the file back to Standard&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this class a file has to be restored before it can be read, and Expedited typically makes a file this size available in 1 to 5 minutes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; A missing permission returns &lt;code&gt;AccessDenied&lt;/code&gt;, not this error.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This is the cheapest option, but it takes 5 to 12 hours.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Lifecycle moves only go down the stairs, never back up to Standard.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#glacier-flexible-and-deep-archive-request-before-reading&quot;&gt;Glacier Flexible and Deep Archive: request before reading&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/restoring-objects-retrieval-options.html&quot;&gt;Understanding archive retrieval options&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 5&lt;/p&gt;
&lt;p&gt;To save money, a team uploaded millions of 10 KB images to Standard-IA. The application reads them all day, and the bill went up. Which &lt;strong&gt;two&lt;/strong&gt; reasons explain this? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Standard-IA charges a monitoring fee per object&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Each object is billed as at least 128 KB&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Every read carries a retrieval fee&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Standard-IA costs more per gigabyte than Standard&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Standard-IA stores an extra copy in a fourth Availability Zone&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B + C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A 10 KB image is billed as 128 KB in this class, and its low storage price only pays off for data that&#39;s rarely read. Data this small and this busy belongs in Standard.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; The monitoring fee belongs to Intelligent-Tiering.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; It costs less per gigabyte, which is why it looks attractive.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E:&lt;/strong&gt; It uses three or more zones just like Standard, so the extra cost doesn&#39;t come from there.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#the-classes&quot;&gt;The classes&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.html&quot;&gt;Understanding and managing Amazon S3 storage classes&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;Your data is now in the right place at the right price, but who can reach it? In &lt;a href=&quot;/en/posts/aws-17-s3-security/&quot;&gt;&lt;strong&gt;part seventeen&lt;/strong&gt;&lt;/a&gt; we cover encryption, signed links and locks against deletion.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>S3: Object Storage Basics</title>
    <link href="https://blog.sultanops.com/en/posts/aws-15-s3-basics/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-15-s3-basics/</id>
    <summary>What object storage is and how it differs from disks, buckets and objects, who can reach them, versioning and replication, hosting a static site, and a hands-on where you watch versioning rescue a deleted file.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-05-ec2-storage/&quot;&gt;part five&lt;/a&gt; we saw storage tied to servers. But photos, videos, backups and logs don&#39;t need a server at all. They need somewhere that keeps them safe and delivers them on request, however large they get. That&#39;s &lt;strong&gt;S3&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;S3&lt;/strong&gt; (Simple Storage Service) is one of AWS&#39;s oldest and most used services. There&#39;s no space to reserve, and you pay for what you store. AWS designs it for 99.999999999% durability, meaning the chance of losing a file is close to nil.&lt;/p&gt;
&lt;p&gt;You&#39;ll see it everywhere: backups, user files, static sites, logs and data lakes for analysis.&lt;/p&gt;
&lt;h2 id=&quot;object-storage-versus-disks&quot; tabindex=&quot;-1&quot;&gt;Object storage versus disks &lt;a class=&quot;heading-anchor&quot; href=&quot;#object-storage-versus-disks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Block (EBS)&lt;/th&gt;
&lt;th&gt;File (EFS)&lt;/th&gt;
&lt;th&gt;Object (S3)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Looks like&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A disk&lt;/td&gt;
&lt;td&gt;A shared folder&lt;/td&gt;
&lt;td&gt;A key and a file through an API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reached by&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Usually one server&lt;/td&gt;
&lt;td&gt;Several servers&lt;/td&gt;
&lt;td&gt;Anyone allowed, over HTTP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Changing a file&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Part of it&lt;/td&gt;
&lt;td&gt;Part of it&lt;/td&gt;
&lt;td&gt;You replace the whole object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You reserve it&lt;/td&gt;
&lt;td&gt;Grows by itself&lt;/td&gt;
&lt;td&gt;No practical limit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The point that matters for design: S3 isn&#39;t a disk you mount and run a database from, but it&#39;s ideal for any file you read or write as a whole.&lt;/p&gt;
&lt;h2 id=&quot;buckets-and-objects&quot; tabindex=&quot;-1&quot;&gt;Buckets and objects &lt;a class=&quot;heading-anchor&quot; href=&quot;#buckets-and-objects&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 250&quot; role=&quot;img&quot; aria-labelledby=&quot;s3-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;s3-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;14&quot; width=&quot;290&quot; height=&quot;222&quot; rx=&quot;14&quot; fill=&quot;none&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;6 6&quot;/&gt;
&lt;text x=&quot;165&quot; y=&quot;40&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;series-files-12345&lt;/text&gt;
&lt;text x=&quot;165&quot; y=&quot;62&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;A bucket in one Region&lt;/text&gt;
&lt;rect x=&quot;40&quot; y=&quot;78&quot; width=&quot;250&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;165&quot; y=&quot;102&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;index.html&lt;/text&gt;
&lt;rect x=&quot;40&quot; y=&quot;126&quot; width=&quot;250&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;165&quot; y=&quot;150&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;photos/2026/trip.jpg&lt;/text&gt;
&lt;rect x=&quot;40&quot; y=&quot;174&quot; width=&quot;250&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;165&quot; y=&quot;198&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;logs/app.log&lt;/text&gt;
&lt;rect x=&quot;370&quot; y=&quot;14&quot; width=&quot;250&quot; height=&quot;222&quot; rx=&quot;14&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;495&quot; y=&quot;40&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;One object&lt;/text&gt;
&lt;text x=&quot;410&quot; y=&quot;78&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Key&lt;/text&gt;
&lt;text x=&quot;530&quot; y=&quot;78&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;photos/2026/trip.jpg&lt;/text&gt;
&lt;text x=&quot;410&quot; y=&quot;112&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Data&lt;/text&gt;
&lt;text x=&quot;530&quot; y=&quot;112&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;The file itself&lt;/text&gt;
&lt;text x=&quot;410&quot; y=&quot;146&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Metadata&lt;/text&gt;
&lt;text x=&quot;530&quot; y=&quot;146&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Type, size, date&lt;/text&gt;
&lt;text x=&quot;410&quot; y=&quot;180&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Tags&lt;/text&gt;
&lt;text x=&quot;530&quot; y=&quot;180&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;team=media&lt;/text&gt;
&lt;text x=&quot;410&quot; y=&quot;214&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Version&lt;/text&gt;
&lt;text x=&quot;530&quot; y=&quot;214&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;3sL4kq...&lt;/text&gt;
&lt;line x1=&quot;290&quot; y1=&quot;145&quot; x2=&quot;368&quot; y2=&quot;145&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#s3-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;s3-caption&quot;&gt;A bucket holds objects, and each object has a key, data, information about it, tags and a version.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;A bucket:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lives in one Region you choose, even though S3 appears as a global service in the console.&lt;/li&gt;
&lt;li&gt;Must have a name unique across all AWS accounts, using lowercase letters, numbers and hyphens.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;An object:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can be up to 50 TB.&lt;/li&gt;
&lt;li&gt;Its &lt;strong&gt;key&lt;/strong&gt; is its full path, such as &lt;code&gt;photos/2026/trip.jpg&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;There are no real folders.&lt;/strong&gt; &lt;code&gt;photos/2026/&lt;/code&gt; is part of the name, and the console merely displays it as a folder.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;who-can-reach-it&quot; tabindex=&quot;-1&quot;&gt;Who can reach it? &lt;a class=&quot;heading-anchor&quot; href=&quot;#who-can-reach-it&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Everything in S3 is &lt;strong&gt;private by default&lt;/strong&gt;. When someone requests an object, AWS combines all the rules: they get through if a rule allows them and no rule denies them.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Attached to&lt;/th&gt;
&lt;th&gt;Used for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IAM policy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The user or role&lt;/td&gt;
&lt;td&gt;Permissions for your people and services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bucket policy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The bucket&lt;/td&gt;
&lt;td&gt;Public access, other accounts and enforcing rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Block Public Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The bucket or account&lt;/td&gt;
&lt;td&gt;A safety lock that stops public access whatever the policies say&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For example: an EC2 server reading from S3? Give it an &lt;a href=&quot;/en/posts/aws-02-iam/&quot;&gt;IAM role&lt;/a&gt;. Another account reading? A bucket policy allows it. This policy makes a whole bucket publicly readable, which is what a static site needs:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;JSON&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2012-10-17&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;Statement&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Principal&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s3:GetObject&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:s3:::my-site-bucket/*&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;aside class=&quot;callout callout-warning&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-alert&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 4l9 16H3L12 4z&quot;/&gt;&lt;path d=&quot;M12 10v4M12 17h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Keep Block Public Access on&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s on by default, and many S3 data leaks came from buckets opened by mistake. Turn it off only for a bucket that&#39;s meant to be public. We cover security in detail in &lt;a href=&quot;/en/posts/aws-17-s3-security/&quot;&gt;part seventeen&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;versioning&quot; tabindex=&quot;-1&quot;&gt;Versioning &lt;a class=&quot;heading-anchor&quot; href=&quot;#versioning&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once it&#39;s on, replacing an object creates a new version rather than wiping the old one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Writing over a file:&lt;/strong&gt; the old version stays, and you can go back to it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deleting:&lt;/strong&gt; adds a delete marker, and the data stays. Remove the marker and the file returns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Suspending:&lt;/strong&gt; doesn&#39;t wipe existing versions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You pay for every version, so pair it with &lt;a href=&quot;/en/posts/aws-16-s3-classes-lifecycle/&quot;&gt;lifecycle rules&lt;/a&gt; to clean up old ones.&lt;/p&gt;
&lt;h2 id=&quot;replication&quot; tabindex=&quot;-1&quot;&gt;Replication &lt;a class=&quot;heading-anchor&quot; href=&quot;#replication&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;S3 automatically copies new objects to another bucket, even in another account. Versioning must be on at both ends.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Between Regions (CRR)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compliance, being close to users, and disaster recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Within a Region (SRR)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gathering logs in one place, or copying production to a test environment&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Note that existing objects move only with &lt;strong&gt;Batch Replication&lt;/strong&gt;, replication doesn&#39;t pass along a chain of buckets, and permanently deleting a version isn&#39;t replicated, which protects you from malicious deletes.&lt;/p&gt;
&lt;h2 id=&quot;hosting-a-static-site&quot; tabindex=&quot;-1&quot;&gt;Hosting a static site &lt;a class=&quot;heading-anchor&quot; href=&quot;#hosting-a-static-site&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;S3 can serve a complete HTML site: turn on &lt;strong&gt;Static website hosting&lt;/strong&gt;, set &lt;code&gt;index.html&lt;/code&gt;, and make the objects public with a policy like the one above.&lt;/p&gt;
&lt;p&gt;That website link only works over HTTP, though. The better choice in production is a private bucket with &lt;a href=&quot;/en/posts/aws-12-cloudfront-global-accelerator/&quot;&gt;CloudFront&lt;/a&gt; and OAC in front of it, giving you HTTPS and higher speed without opening the bucket.&lt;/p&gt;
&lt;h2 id=&quot;reacting-to-events&quot; tabindex=&quot;-1&quot;&gt;Reacting to events &lt;a class=&quot;heading-anchor&quot; href=&quot;#reacting-to-events&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;S3 can send a notification when something happens, such as a photo being uploaded. It sends it to SQS, SNS or Lambda directly, or to &lt;strong&gt;EventBridge&lt;/strong&gt; if you want advanced filtering and more destinations. The classic example: for every photo uploaded, a Lambda function makes a thumbnail. We&#39;ll apply this in &lt;a href=&quot;/en/posts/aws-22-serverless-design/&quot;&gt;part twenty-two&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;performance&quot; tabindex=&quot;-1&quot;&gt;Performance &lt;a class=&quot;heading-anchor&quot; href=&quot;#performance&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;S3 handles at least &lt;strong&gt;3,500 writes and 5,500 reads per second per prefix&lt;/strong&gt;, so spreading keys across several prefixes increases capacity. You also have tools for large files and long distances:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multipart upload&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Uploads a file in parts in parallel, and if a part fails you repeat only that part. Preferred above 100 MB, required above 5 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transfer Acceleration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Uploads pass through the nearest edge location, then AWS&#39;s network, for long distances&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Byte-range fetches&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Download a specific part of a file, to speed up parallel downloads or fetch only what you need&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;hands-on-versioning-rescues-a-deleted-file&quot; tabindex=&quot;-1&quot;&gt;Hands-on: versioning rescues a deleted file &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-versioning-rescues-a-deleted-file&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;From CloudShell, create a bucket with a unique name and upload a page:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;BUCKET&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;series-files-&lt;span class=&quot;token environment constant&quot;&gt;$RANDOM&lt;/span&gt;&lt;span class=&quot;token environment constant&quot;&gt;$RANDOM&lt;/span&gt;
aws s3 mb s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;

&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;h1&gt;Version 1&amp;lt;/h1&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; index.html
aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; index.html s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/
aws s3 &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Try reaching the file from the internet. It returns &lt;code&gt;403&lt;/code&gt;, because everything is private:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; /dev/null &lt;span class=&quot;token parameter variable&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;%{http_code}&lt;span class=&quot;token entity&quot; title=&quot;&#92;n&quot;&gt;&#92;n&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  https://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;.s3.&lt;span class=&quot;token variable&quot;&gt;$AWS_REGION&lt;/span&gt;.amazonaws.com/index.html&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Now turn on versioning, write over the file, then delete it:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws s3api put-bucket-versioning &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --versioning-configuration &lt;span class=&quot;token assign-left variable&quot;&gt;Status&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;Enabled

&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;h1&gt;Version 2&amp;lt;/h1&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; index.html
aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; index.html s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/

aws s3 &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/index.html
aws s3 &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The file has gone from the list. But look at what really happened:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws s3api list-object-versions &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--prefix&lt;/span&gt; index.html &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{Versions:Versions[].[VersionId,IsLatest],Markers:DeleteMarkers[].[VersionId,IsLatest]}&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Both versions are there, with a delete marker on top. Delete the marker and the file returns:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;MARKER&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws s3api list-object-versions &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; $BUCKET &lt;span class=&quot;token parameter variable&quot;&gt;--prefix&lt;/span&gt; index.html &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;DeleteMarkers[0].VersionId&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws s3api delete-object &lt;span class=&quot;token parameter variable&quot;&gt;--bucket&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--key&lt;/span&gt; index.html --version-id &lt;span class=&quot;token variable&quot;&gt;$MARKER&lt;/span&gt;

aws s3 &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET&lt;/span&gt;/index.html -&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;It prints &lt;code&gt;Version 2&lt;/code&gt;. The file is back as if it had never been deleted.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A bucket with versions can&#39;t be deleted with a simple command. If you&#39;re carrying on with the next parts, keep it. Otherwise, from the S3 page select it and choose &lt;strong&gt;Empty&lt;/strong&gt;, then &lt;strong&gt;Delete&lt;/strong&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;S3&lt;/strong&gt; is object storage with no practical limit, and you pay for what you store.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;bucket&lt;/strong&gt; sits in one Region with a unique name, and a &lt;strong&gt;key&lt;/strong&gt; is an object&#39;s full path.&lt;/li&gt;
&lt;li&gt;Everything is &lt;strong&gt;private by default&lt;/strong&gt;, so keep Block Public Access on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Versioning&lt;/strong&gt; protects you from accidental deletes and overwrites, and &lt;strong&gt;replication&lt;/strong&gt; copies objects to another bucket.&lt;/li&gt;
&lt;li&gt;For a static site in production: a private bucket with CloudFront.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 5&lt;/p&gt;
&lt;p&gt;A design agency keeps client files in S3. Last week a staff member deleted some files by mistake, and a script overwrote others. The agency wants to be able to get both kinds back from now on, with the &lt;strong&gt;least effort&lt;/strong&gt;. What should it turn on?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Block Public Access&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Same-Region Replication&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Versioning&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Transfer Acceleration&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With versioning on, a delete only adds a marker and an overwrite creates a new version, so the old data stays and you can go back to it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This stops public access, and does nothing about deletes or overwrites.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This needs versioning on anyway, and adds a second bucket to pay for.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This speeds up uploads over long distances, and keeps no old copies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#versioning&quot;&gt;Versioning&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/Versioning.html&quot;&gt;Retaining multiple versions of objects with S3 Versioning&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 5&lt;/p&gt;
&lt;p&gt;A company keeps its marketing site in S3. It wants the site served over HTTPS on its own domain, with the bucket staying private. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A private bucket, with CloudFront and OAC in front of it&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Static website hosting, with a public bucket&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Static website hosting, with Block Public Access kept on&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;An EC2 server that copies the files from S3 and serves them&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CloudFront gives you HTTPS on your own domain, and OAC lets only CloudFront read from the bucket, so the bucket stays closed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; The website endpoint only works over HTTP, and the bucket has to be public.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; The website endpoint needs public objects, so with the lock on visitors get &lt;code&gt;403&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This adds a server to run and patch for a site that doesn&#39;t need one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#hosting-a-static-site&quot;&gt;Hosting a static site&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteEndpoints.html&quot;&gt;Website endpoints&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 5&lt;/p&gt;
&lt;p&gt;A film studio uploads 40 GB video files to S3 over an unstable connection. Uploads often fail near the end and have to start over. What solves this?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Byte-range fetches&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Transfer Acceleration alone&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Versioning on the bucket&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Multipart upload&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Multipart upload sends a file in parts, in parallel, and if one part fails you repeat only that part. It&#39;s also required for anything above 5 GB.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; These are for downloading part of a file, not for uploading.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This shortens the path over long distances, but a failed upload would still start over.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This keeps old versions, and doesn&#39;t help an upload finish.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#performance&quot;&gt;Performance&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html&quot;&gt;Uploading and copying objects using multipart upload&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 5&lt;/p&gt;
&lt;p&gt;A regulator requires a company to keep a copy of its records bucket in a second Region, including the files already in the bucket. Versioning is on at both ends. What should it set up?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Cross-Region Replication alone&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Cross-Region Replication, plus Batch Replication for the existing files&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Same-Region Replication, plus Batch Replication&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A lifecycle rule that moves the files to the second Region&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A replication rule copies only new objects, so existing ones need Batch Replication. Together they give you a full copy in the second Region that stays current.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This copies only the objects written after the rule is set.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This keeps the copy in the same Region, which doesn&#39;t meet the requirement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Lifecycle rules change a file&#39;s class or delete it, and don&#39;t move it between Regions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#replication&quot;&gt;Replication&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication.html&quot;&gt;Replicating objects within and across Regions&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 5&lt;/p&gt;
&lt;p&gt;A server on EC2 must read from a private bucket, and an analytics team in another AWS account must read from it too. Block Public Access has to stay on. Which &lt;strong&gt;two&lt;/strong&gt; steps fit? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Give the server an IAM role with read permission&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Store a user&#39;s access keys in a file on the server&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Make the bucket publicly readable&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Add a bucket policy that allows the other account&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Copy the objects to an EBS volume for the team to share&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A + D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A role gives the server temporary credentials with no keys to store, and a bucket policy is how you let another account in. Neither of them makes anything public.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; Keys in a file can leak, and a role avoids them altogether.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This exposes the data to everyone, and the lock would stop it anyway.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E:&lt;/strong&gt; This adds copies to manage, and a volume isn&#39;t how another account reads your data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#who-can-reach-it&quot;&gt;Who can reach it?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-walkthroughs-managing-access-example2.html&quot;&gt;Example 2: Bucket owner granting cross-account bucket permissions&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2.html&quot;&gt;Use an IAM role to grant permissions to applications running on Amazon EC2 instances&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;But does every file deserve the same price? A file untouched for two years shouldn&#39;t cost you the same as a photo requested every second. In &lt;a href=&quot;/en/posts/aws-16-s3-classes-lifecycle/&quot;&gt;&lt;strong&gt;part sixteen&lt;/strong&gt;&lt;/a&gt; we save a lot with storage classes and lifecycle rules.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>VPC: Connecting Networks</title>
    <link href="https://blog.sultanops.com/en/posts/aws-14-vpc-connectivity/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-14-vpc-connectivity/</id>
    <summary>How to connect VPCs with peering and Transit Gateway, reach AWS services privately through endpoints, link your office with VPN or Direct Connect, and control network costs, with a hands-on for the two most useful connections.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-13-vpc/&quot;&gt;part thirteen&lt;/a&gt; we built an isolated network. But real applications rarely stay alone: you have a second VPC for another team, servers that need S3 and an office that needs to reach the database.&lt;/p&gt;
&lt;p&gt;Here&#39;s this part&#39;s map, to come back to whenever you&#39;re unsure:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You want&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Two VPCs talking to each other&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VPC peering&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A private subnet reaching S3 or DynamoDB without NAT&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Gateway endpoint&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reaching other AWS services or a partner&#39;s service privately&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Interface endpoint&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Your office reaching AWS quickly over the internet&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Site-to-Site VPN&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Employees&#39; devices reaching the network&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Client VPN&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A steady, large line between your office and AWS&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Direct Connect&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Many networks and offices&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Transit Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;vpc-peering&quot; tabindex=&quot;-1&quot;&gt;VPC peering &lt;a class=&quot;heading-anchor&quot; href=&quot;#vpc-peering&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Peering&lt;/strong&gt; connects two VPCs directly, as if they were one network. It works even between different accounts or different Regions. Its rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ranges can&#39;t overlap.&lt;/strong&gt; This is what we warned you about in the previous part.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It isn&#39;t transitive.&lt;/strong&gt; If A connects to B and B connects to C, A can&#39;t reach C.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You need a route on both sides.&lt;/strong&gt; You add one in each network&#39;s route table.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&#39;s no hourly charge; you pay only for data transfer.&lt;/p&gt;
&lt;h2 id=&quot;vpc-endpoints-aws-services-without-the-internet&quot; tabindex=&quot;-1&quot;&gt;VPC endpoints: AWS services without the internet &lt;a class=&quot;heading-anchor&quot; href=&quot;#vpc-endpoints-aws-services-without-the-internet&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default, your private server&#39;s request to S3 goes out through NAT, and you pay for every gigabyte, even though the destination is already inside AWS. &lt;strong&gt;Endpoints&lt;/strong&gt; give you a private, direct path:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 210&quot; role=&quot;img&quot; aria-labelledby=&quot;endpoint-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;endpoint-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;60&quot; width=&quot;150&quot; height=&quot;90&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;95&quot; y=&quot;100&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Private server&lt;/text&gt;
&lt;text x=&quot;95&quot; y=&quot;122&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;In a private subnet&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;60&quot; width=&quot;150&quot; height=&quot;90&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;S3&lt;/text&gt;
&lt;rect x=&quot;245&quot; y=&quot;10&quot; width=&quot;150&quot; height=&quot;52&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-dasharray=&quot;5 5&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;32&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;NAT, then internet&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;52&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Paid per gigabyte&lt;/text&gt;
&lt;rect x=&quot;245&quot; y=&quot;148&quot; width=&quot;150&quot; height=&quot;52&quot; rx=&quot;8&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;170&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Gateway endpoint&lt;/text&gt;
&lt;text x=&quot;320&quot; y=&quot;190&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Free&lt;/text&gt;
&lt;line x1=&quot;170&quot; y1=&quot;85&quot; x2=&quot;243&quot; y2=&quot;40&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;4 4&quot;/&gt;
&lt;line x1=&quot;395&quot; y1=&quot;40&quot; x2=&quot;470&quot; y2=&quot;85&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;4 4&quot;/&gt;
&lt;line x1=&quot;170&quot; y1=&quot;125&quot; x2=&quot;243&quot; y2=&quot;170&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#endpoint-arrow)&quot;/&gt;
&lt;line x1=&quot;395&quot; y1=&quot;170&quot; x2=&quot;468&quot; y2=&quot;125&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#endpoint-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;endpoint-caption&quot;&gt;Instead of the paid path through NAT, the private server reaches S3 through a free gateway endpoint, without going out to the internet.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Gateway endpoint&lt;/th&gt;
&lt;th&gt;Interface endpoint&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Services&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;S3 and DynamoDB only&lt;/td&gt;
&lt;td&gt;Most AWS services, and partners&#39; services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;How it works&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A route in the route table&lt;/td&gt;
&lt;td&gt;A network interface with a private address in your subnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Per hour per zone, and per gigabyte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;From your office&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reachable&lt;/td&gt;
&lt;td&gt;Reachable through VPN or Direct Connect&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;aside class=&quot;callout callout-tip&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-bulb&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M9 18h6M10 21h4M12 3a6 6 0 0 0-3.5 10.9c.6.45 1 1.15 1 1.9V16h5v-.2c0-.75.4-1.45 1-1.9A6 6 0 0 0 12 3z&quot;/&gt;&lt;/svg&gt;&lt;span&gt;The easiest saving on your bill&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Turn on a gateway endpoint for S3 in every VPC. It&#39;s free, and it takes S3 traffic out of NAT&#39;s bill.&lt;/p&gt;
&lt;/aside&gt;
&lt;p&gt;An &lt;strong&gt;interface endpoint&lt;/strong&gt; is built on &lt;strong&gt;PrivateLink&lt;/strong&gt;, which also lets you offer your own service to other networks through an NLB, with no peering and even if their ranges overlap.&lt;/p&gt;
&lt;h2 id=&quot;connecting-your-office-site-to-site-vpn&quot; tabindex=&quot;-1&quot;&gt;Connecting your office: Site-to-Site VPN &lt;a class=&quot;heading-anchor&quot; href=&quot;#connecting-your-office-site-to-site-vpn&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Site-to-Site VPN&lt;/strong&gt; connects your office network to the VPC over the internet through an encrypted tunnel, and you can set it up quickly. It has three pieces:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Customer gateway:&lt;/strong&gt; represents your office device and its public address.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virtual private gateway:&lt;/strong&gt; the VPN gateway on AWS&#39;s side, attached to the VPC.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VPN connection:&lt;/strong&gt; the connection itself, which comes with two tunnels for availability.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Then turn on &lt;strong&gt;route propagation&lt;/strong&gt; in the route table so the VPC learns the office&#39;s routes. Each tunnel gives you up to 1.25 Gbps, or up to 5 with Transit Gateway.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;VPN CloudHub:&lt;/strong&gt; connects several offices to each other through the same gateway.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client VPN:&lt;/strong&gt; for employees&#39; devices rather than offices.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want a VPN fully under your control on your own server, see the &lt;a href=&quot;/en/posts/wireguard/&quot;&gt;WireGuard&lt;/a&gt; article.&lt;/p&gt;
&lt;h2 id=&quot;direct-connect-a-private-line&quot; tabindex=&quot;-1&quot;&gt;Direct Connect: a private line &lt;a class=&quot;heading-anchor&quot; href=&quot;#direct-connect-a-private-line&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Direct Connect&lt;/strong&gt; is a real private line between your site and AWS through a Direct Connect location, so it doesn&#39;t cross the public internet. Its speed is steady, and outgoing data transfer is cheaper.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dedicated:&lt;/strong&gt; a port just for you, from 1 to 400 Gbps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hosted:&lt;/strong&gt; through a partner, with speeds starting far lower.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Direct Connect Gateway:&lt;/strong&gt; connects you to VPCs in several Regions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Watch out for three things: &lt;strong&gt;setup takes weeks&lt;/strong&gt; and sometimes months, &lt;strong&gt;the line isn&#39;t encrypted automatically&lt;/strong&gt;, so use MACsec or a VPN on top, and &lt;strong&gt;one line is a single point of failure&lt;/strong&gt;, so for your most important systems have two lines in two locations, or a backup VPN.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Site-to-Site VPN&lt;/th&gt;
&lt;th&gt;Direct Connect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Path&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The internet, encrypted&lt;/td&gt;
&lt;td&gt;A private line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Setup&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Minutes or hours&lt;/td&gt;
&lt;td&gt;Weeks or months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.25 Gbps per tunnel, or 5 with Transit Gateway&lt;/td&gt;
&lt;td&gt;1 to 400 Gbps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Varies with the internet&lt;/td&gt;
&lt;td&gt;Steady&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Higher at first, cheaper for large transfers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;transit-gateway-one-hub&quot; tabindex=&quot;-1&quot;&gt;Transit Gateway: one hub &lt;a class=&quot;heading-anchor&quot; href=&quot;#transit-gateway-one-hub&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As networks multiply, peering becomes tiring: since it isn&#39;t transitive, you need a link for every pair:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 250&quot; role=&quot;img&quot; aria-labelledby=&quot;tgw-caption&quot;&gt;
&lt;text x=&quot;160&quot; y=&quot;28&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Peering: ten links&lt;/text&gt;
&lt;g stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot;&gt;
&lt;line x1=&quot;160&quot; y1=&quot;65&quot; x2=&quot;241&quot; y2=&quot;124&quot;/&gt;
&lt;line x1=&quot;160&quot; y1=&quot;65&quot; x2=&quot;210&quot; y2=&quot;219&quot;/&gt;
&lt;line x1=&quot;160&quot; y1=&quot;65&quot; x2=&quot;110&quot; y2=&quot;219&quot;/&gt;
&lt;line x1=&quot;160&quot; y1=&quot;65&quot; x2=&quot;79&quot; y2=&quot;124&quot;/&gt;
&lt;line x1=&quot;241&quot; y1=&quot;124&quot; x2=&quot;210&quot; y2=&quot;219&quot;/&gt;
&lt;line x1=&quot;241&quot; y1=&quot;124&quot; x2=&quot;110&quot; y2=&quot;219&quot;/&gt;
&lt;line x1=&quot;241&quot; y1=&quot;124&quot; x2=&quot;79&quot; y2=&quot;124&quot;/&gt;
&lt;line x1=&quot;210&quot; y1=&quot;219&quot; x2=&quot;110&quot; y2=&quot;219&quot;/&gt;
&lt;line x1=&quot;210&quot; y1=&quot;219&quot; x2=&quot;79&quot; y2=&quot;124&quot;/&gt;
&lt;line x1=&quot;110&quot; y1=&quot;219&quot; x2=&quot;79&quot; y2=&quot;124&quot;/&gt;
&lt;/g&gt;
&lt;rect x=&quot;134&quot; y=&quot;50&quot; width=&quot;52&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;160&quot; y=&quot;70&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;VPC&lt;/text&gt;
&lt;rect x=&quot;215&quot; y=&quot;109&quot; width=&quot;52&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;241&quot; y=&quot;129&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;VPC&lt;/text&gt;
&lt;rect x=&quot;184&quot; y=&quot;204&quot; width=&quot;52&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;210&quot; y=&quot;224&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;VPC&lt;/text&gt;
&lt;rect x=&quot;84&quot; y=&quot;204&quot; width=&quot;52&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;110&quot; y=&quot;224&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;VPC&lt;/text&gt;
&lt;rect x=&quot;53&quot; y=&quot;109&quot; width=&quot;52&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;79&quot; y=&quot;129&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;VPC&lt;/text&gt;
&lt;text x=&quot;480&quot; y=&quot;28&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Transit Gateway: five links&lt;/text&gt;
&lt;g stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot;&gt;
&lt;line x1=&quot;480&quot; y1=&quot;150&quot; x2=&quot;480&quot; y2=&quot;65&quot;/&gt;
&lt;line x1=&quot;480&quot; y1=&quot;150&quot; x2=&quot;561&quot; y2=&quot;124&quot;/&gt;
&lt;line x1=&quot;480&quot; y1=&quot;150&quot; x2=&quot;530&quot; y2=&quot;219&quot;/&gt;
&lt;line x1=&quot;480&quot; y1=&quot;150&quot; x2=&quot;430&quot; y2=&quot;219&quot;/&gt;
&lt;line x1=&quot;480&quot; y1=&quot;150&quot; x2=&quot;399&quot; y2=&quot;124&quot;/&gt;
&lt;/g&gt;
&lt;rect x=&quot;454&quot; y=&quot;50&quot; width=&quot;52&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;480&quot; y=&quot;70&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;VPC&lt;/text&gt;
&lt;rect x=&quot;535&quot; y=&quot;109&quot; width=&quot;52&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;561&quot; y=&quot;129&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;VPC&lt;/text&gt;
&lt;rect x=&quot;504&quot; y=&quot;204&quot; width=&quot;52&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;530&quot; y=&quot;224&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;VPC&lt;/text&gt;
&lt;rect x=&quot;404&quot; y=&quot;204&quot; width=&quot;52&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;430&quot; y=&quot;224&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;VPC&lt;/text&gt;
&lt;rect x=&quot;373&quot; y=&quot;109&quot; width=&quot;52&quot; height=&quot;30&quot; rx=&quot;6&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;399&quot; y=&quot;129&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;VPC&lt;/text&gt;
&lt;rect x=&quot;432&quot; y=&quot;130&quot; width=&quot;96&quot; height=&quot;40&quot; rx=&quot;8&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;480&quot; y=&quot;155&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Transit GW&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;tgw-caption&quot;&gt;Five networks need ten peering links, or only five links to a single Transit Gateway hub.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Transit Gateway&lt;/strong&gt; is a central hub you connect networks to, and each one reaches the others through it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It connects everything:&lt;/strong&gt; VPCs, VPN connections, Direct Connect and Transit Gateways in other Regions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Its own route tables:&lt;/strong&gt; you decide who talks to whom, for example separating production from development.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Across accounts:&lt;/strong&gt; you share it with other accounts through the RAM service.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Higher VPN speed:&lt;/strong&gt; it spreads traffic across several tunnels.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You pay by the hour for each attachment, and for data. For two or three networks, peering is simpler and cheaper.&lt;/p&gt;
&lt;h2 id=&quot;network-costs&quot; tabindex=&quot;-1&quot;&gt;Network costs &lt;a class=&quot;heading-anchor&quot; href=&quot;#network-costs&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Data transfer is the item that most often surprises people. These are approximate rates for US Regions, so check yours:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Traffic&lt;/th&gt;
&lt;th&gt;Cost per gigabyte&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Into AWS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Within one Availability Zone, by private address&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Between Availability Zones&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;About $0.01 in each direction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Between Regions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;About $0.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Out to the internet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;About $0.09, falling with volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Through a NAT Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;About $0.045 extra&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;S3 through a gateway endpoint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;How to save:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;private addresses&lt;/strong&gt; between servers, not public ones.&lt;/li&gt;
&lt;li&gt;Keep services that talk a lot in the &lt;strong&gt;same Availability Zone&lt;/strong&gt;, if your availability design allows it.&lt;/li&gt;
&lt;li&gt;Turn on a &lt;strong&gt;gateway endpoint&lt;/strong&gt; for S3.&lt;/li&gt;
&lt;li&gt;Serve content through &lt;strong&gt;CloudFront&lt;/strong&gt;, since transfer from your origin to it is free.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;layers-of-protection&quot; tabindex=&quot;-1&quot;&gt;Layers of protection &lt;a class=&quot;heading-anchor&quot; href=&quot;#layers-of-protection&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Protects against&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Subnet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;NACL&lt;/td&gt;
&lt;td&gt;Addresses you want to block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Server&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Security group&lt;/td&gt;
&lt;td&gt;Any port and source you didn&#39;t allow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web application&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;WAF&lt;/td&gt;
&lt;td&gt;Web attacks such as SQL injection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Large attacks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shield&lt;/td&gt;
&lt;td&gt;DDoS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;The whole VPC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Network Firewall&lt;/td&gt;
&lt;td&gt;Inspecting traffic and domains at the boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As for &lt;strong&gt;IPv6&lt;/strong&gt;: you can add it to a VPC, but all its addresses are public. If you want servers to go out with nobody coming in, use an &lt;strong&gt;egress-only internet gateway&lt;/strong&gt;, which is like NAT for IPv6.&lt;/p&gt;
&lt;h2 id=&quot;hands-on-an-endpoint-and-peering&quot; tabindex=&quot;-1&quot;&gt;Hands-on: an endpoint and peering &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-an-endpoint-and-peering&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll continue with the network from &lt;a href=&quot;/en/posts/aws-13-vpc/&quot;&gt;part thirteen&lt;/a&gt;, after deleting the NAT Gateway, so &lt;code&gt;private-server&lt;/code&gt; has no route to the internet. The commands use the variables &lt;code&gt;VPC&lt;/code&gt; and &lt;code&gt;RT_PRIVATE&lt;/code&gt;; if your CloudShell session ended, set them by hand from the VPC page.&lt;/p&gt;
&lt;h3 id=&quot;gateway-endpoint&quot; tabindex=&quot;-1&quot;&gt;Gateway endpoint &lt;a class=&quot;heading-anchor&quot; href=&quot;#gateway-endpoint&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Give &lt;code&gt;private-server&lt;/code&gt; an IAM role with &lt;code&gt;AmazonS3ReadOnlyAccess&lt;/code&gt;, as we explained in &lt;a href=&quot;/en/posts/aws-02-iam/&quot;&gt;part two&lt;/a&gt;. On the server, try:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws s3 &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; --cli-connect-timeout &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;It times out after several attempts, because there&#39;s no route to S3. Now add an endpoint from CloudShell:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws ec2 create-vpc-endpoint --vpc-id &lt;span class=&quot;token variable&quot;&gt;$VPC&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --service-name com.amazonaws.&lt;span class=&quot;token variable&quot;&gt;$AWS_REGION&lt;/span&gt;.s3 &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --route-table-ids &lt;span class=&quot;token variable&quot;&gt;$RT_PRIVATE&lt;/span&gt;

aws ec2 describe-route-tables --route-table-ids &lt;span class=&quot;token variable&quot;&gt;$RT_PRIVATE&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;RouteTables[0].Routes[].[DestinationCidrBlock,DestinationPrefixListId,GatewayId]&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; table&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;You&#39;ll see a new route starting with &lt;code&gt;pl-&lt;/code&gt; and pointing to &lt;code&gt;vpce-&lt;/code&gt;. Repeat &lt;code&gt;aws s3 ls&lt;/code&gt; on the server, and it returns at once with your buckets, or empty if you have none, with no internet at all.&lt;/p&gt;
&lt;h3 id=&quot;vpc-peering-1&quot; tabindex=&quot;-1&quot;&gt;VPC peering &lt;a class=&quot;heading-anchor&quot; href=&quot;#vpc-peering-1&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now we&#39;ll connect this network to the default one, which holds &lt;code&gt;web-1&lt;/code&gt; from &lt;a href=&quot;/en/posts/aws-03-ec2-first-server/&quot;&gt;part three&lt;/a&gt;. Get its private address:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws ec2 describe-instances &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--filters&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Name=tag:Name,Values=web-1&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Name=instance-state-name,Values=running&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Reservations[0].Instances[0].PrivateIpAddress&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;From &lt;code&gt;private-server&lt;/code&gt;, try &lt;code&gt;curl -m 5 http://WEB-PRIVATE-IP&lt;/code&gt;, and it times out. Now create the connection and accept it:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;DEFAULT_VPC&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 describe-vpcs &lt;span class=&quot;token parameter variable&quot;&gt;--filters&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;isDefault,Values&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Vpcs[0].VpcId&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;PEER&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 create-vpc-peering-connection &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --vpc-id $VPC --peer-vpc-id $DEFAULT_VPC &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; VpcPeeringConnection.VpcPeeringConnectionId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws ec2 accept-vpc-peering-connection --vpc-peering-connection-id &lt;span class=&quot;token variable&quot;&gt;$PEER&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The connection alone isn&#39;t enough, so add a route on both sides:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws ec2 create-route --route-table-id &lt;span class=&quot;token variable&quot;&gt;$RT_PRIVATE&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --destination-cidr-block &lt;span class=&quot;token number&quot;&gt;172.31&lt;/span&gt;.0.0/16 --vpc-peering-connection-id &lt;span class=&quot;token variable&quot;&gt;$PEER&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;DEFAULT_RT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 describe-route-tables &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--filters&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;vpc-id,Values&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;$DEFAULT_VPC &lt;span class=&quot;token assign-left variable&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;association.main,Values&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;RouteTables[0].RouteTableId&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws ec2 create-route --route-table-id &lt;span class=&quot;token variable&quot;&gt;$DEFAULT_RT&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --destination-cidr-block &lt;span class=&quot;token number&quot;&gt;10.0&lt;/span&gt;.0.0/16 --vpc-peering-connection-id &lt;span class=&quot;token variable&quot;&gt;$PEER&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Repeat &lt;code&gt;curl&lt;/code&gt; from &lt;code&gt;private-server&lt;/code&gt;, and &lt;code&gt;web-1&lt;/code&gt;&#39;s page comes back over the private address.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Delete the default network&#39;s route and the connection with the commands below. Then from their pages delete the two servers, the entry point and the role, and finally select &lt;code&gt;series-vpc&lt;/code&gt; and choose &lt;strong&gt;Actions&lt;/strong&gt; and &lt;strong&gt;Delete VPC&lt;/strong&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws ec2 delete-route --route-table-id &lt;span class=&quot;token variable&quot;&gt;$DEFAULT_RT&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --destination-cidr-block &lt;span class=&quot;token number&quot;&gt;10.0&lt;/span&gt;.0.0/16

aws ec2 delete-vpc-peering-connection --vpc-peering-connection-id &lt;span class=&quot;token variable&quot;&gt;$PEER&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Peering&lt;/strong&gt; is for two networks and isn&#39;t transitive; &lt;strong&gt;Transit Gateway&lt;/strong&gt; is for when networks multiply.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;gateway endpoint&lt;/strong&gt; is free for S3 and DynamoDB; an &lt;strong&gt;interface endpoint&lt;/strong&gt; covers the other services.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VPN&lt;/strong&gt; is quick to set up over the internet; &lt;strong&gt;Direct Connect&lt;/strong&gt; is a private line that takes time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data transfer&lt;/strong&gt; is among the biggest surprises on a bill, so plan for it from the start.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 5&lt;/p&gt;
&lt;p&gt;An order-processing application in a private subnet writes heavily to DynamoDB, and the team finds most of its NAT Gateway bill comes from this traffic. What cuts this cost with the &lt;strong&gt;least effort&lt;/strong&gt;?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Moving the servers to a public subnet&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A peering connection to DynamoDB&#39;s VPC&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;A gateway endpoint for DynamoDB&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A Direct Connect line to the Region&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A gateway endpoint adds a route to DynamoDB that skips NAT, with no extra charge and no code changes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This exposes servers that should stay private, and public addresses cost money too.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; DynamoDB isn&#39;t a VPC you can peer with.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This links your own site to AWS, and has nothing to do with traffic inside the VPC.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#vpc-endpoints-aws-services-without-the-internet&quot;&gt;VPC endpoints: AWS services without the internet&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints-ddb.html&quot;&gt;Gateway endpoints for Amazon DynamoDB&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 5&lt;/p&gt;
&lt;p&gt;A payments team runs an internal API behind a Network Load Balancer. Forty other VPCs need to call it, some of their ranges overlap with its own, and they mustn&#39;t reach anything else on its network. What fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;VPC peering with each of the forty&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;PrivateLink, with an interface endpoint in each VPC&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;A gateway endpoint in each VPC&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A public address on the load balancer, with firewall rules&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With PrivateLink, each consumer gets a private interface in its own subnet that leads only to that service, so overlapping ranges cause no conflict.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Peering doesn&#39;t work with overlapping ranges, and it connects whole networks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; Gateway endpoints are only for S3 and DynamoDB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This puts an internal API on the internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#vpc-endpoints-aws-services-without-the-internet&quot;&gt;VPC endpoints: AWS services without the internet&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/whitepapers/latest/building-scalable-secure-multi-vpc-network-infrastructure/aws-privatelink.html&quot;&gt;AWS PrivateLink&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 5&lt;/p&gt;
&lt;p&gt;A small company must connect its office network to a VPC by next week. Traffic is light, the budget is tight, and the data has to be encrypted. Which option fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Site-to-Site VPN&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Direct Connect, with a dedicated port&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Client VPN&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;VPC peering&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Site-to-Site VPN crosses the internet through an encrypted tunnel, and can be set up quickly at low cost.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; Setting it up takes weeks or months, and it costs more at first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This is for individual employees&#39; devices, rather than a whole office network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This connects VPCs to each other, and can&#39;t reach an office.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#connecting-your-office-site-to-site-vpn&quot;&gt;Connecting your office: Site-to-Site VPN&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/vpn/latest/s2svpn/VPC_VPN.html&quot;&gt;What is AWS Site-to-Site VPN?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 5&lt;/p&gt;
&lt;p&gt;A company is growing to 30 VPCs across several accounts, plus three offices connected by VPN. It wants every network to connect in one place, with production kept apart from development. What fits with the &lt;strong&gt;least operational overhead&lt;/strong&gt;?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;VPC peering between every pair of VPCs&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;VPN CloudHub&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;One shared VPC peered with all the others&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Transit Gateway, with separate route tables&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Transit Gateway is a central hub for VPCs and VPNs, its route tables decide who talks to whom, and it can be shared across accounts through RAM.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Thirty networks would need 435 connections, each with its own routes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This connects offices to each other through one gateway, not a set of VPCs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; Peering isn&#39;t transitive, so the others couldn&#39;t reach each other through it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#transit-gateway-one-hub&quot;&gt;Transit Gateway: one hub&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/tgw/what-is-transit-gateway.html&quot;&gt;What is AWS Transit Gateway for Amazon VPC?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 5&lt;/p&gt;
&lt;p&gt;A bank reaches AWS over a single 10 Gbps Direct Connect line. An audit finds two problems: the line is a single point of failure, and its traffic isn&#39;t encrypted. Which &lt;strong&gt;two&lt;/strong&gt; actions address these? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Add a second connection at a second Direct Connect location&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Upgrade the line to 100 Gbps&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Turn on MACsec on the line, or run a VPN over it&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Add a gateway endpoint to the VPC&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Move to a hosted connection through a partner&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A + C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A second line in a second location keeps the bank connected if a line or a whole location fails. MACsec or a VPN on top adds the encryption the line doesn&#39;t have by default.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; A faster line is still one line, and still unencrypted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This reaches S3 and DynamoDB from inside a VPC, and has nothing to do with the line.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E:&lt;/strong&gt; This is still one line, and a partner doesn&#39;t encrypt it for you.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#direct-connect-a-private-line&quot;&gt;Direct Connect: a private line&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/directconnect/latest/UserGuide/encryption-in-transit.html&quot;&gt;Encryption in AWS Direct Connect&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/directconnect/latest/UserGuide/resiliency_toolkit.html&quot;&gt;AWS Direct Connect Resiliency Toolkit&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;That completes the networking section. You now know the visitor&#39;s path from your site&#39;s name to its data, and what&#39;s left is a place to store anything at any size. That&#39;s the next section&#39;s subject, starting in &lt;a href=&quot;/en/posts/aws-15-s3-basics/&quot;&gt;&lt;strong&gt;part fifteen&lt;/strong&gt;&lt;/a&gt; with the basics of S3.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>VPC: Your Private Network</title>
    <link href="https://blog.sultanops.com/en/posts/aws-13-vpc/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-13-vpc/</id>
    <summary>Open up the network your servers have been running in, and understand address ranges, subnets, internet and NAT gateways, route tables, safe access, two firewalls and flow logs, then build a VPC from scratch.</summary>
    <content type="html">&lt;p&gt;Every server we&#39;ve launched in this series has been inside a network you didn&#39;t build: the default VPC that AWS creates in each Region. It&#39;s fine for experiments, but a real application needs a design where the database stays hidden and each layer has its own place.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-vpc&quot; tabindex=&quot;-1&quot;&gt;What is a VPC? &lt;a class=&quot;heading-anchor&quot; href=&quot;#what-is-a-vpc&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;VPC&lt;/strong&gt; (Virtual Private Cloud) is your private network within one Region. It spans all of that Region&#39;s Availability Zones, and nothing gets in or out unless you allow it. This is the common design:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 356&quot; role=&quot;img&quot; aria-labelledby=&quot;vpc-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;vpc-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;14&quot; y=&quot;28&quot; width=&quot;612&quot; height=&quot;320&quot; rx=&quot;14&quot; fill=&quot;none&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;6 6&quot;/&gt;
&lt;text x=&quot;110&quot; y=&quot;54&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;VPC 10.0.0.0/16&lt;/text&gt;
&lt;rect x=&quot;30&quot; y=&quot;66&quot; width=&quot;280&quot; height=&quot;268&quot; rx=&quot;12&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;170&quot; y=&quot;86&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Availability Zone A&lt;/text&gt;
&lt;rect x=&quot;44&quot; y=&quot;96&quot; width=&quot;252&quot; height=&quot;88&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;117&quot; y=&quot;130&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Public subnet&lt;/text&gt;
&lt;text x=&quot;117&quot; y=&quot;152&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;10.0.1.0/24&lt;/text&gt;
&lt;rect x=&quot;190&quot; y=&quot;116&quot; width=&quot;96&quot; height=&quot;48&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;238&quot; y=&quot;145&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;NAT&lt;/text&gt;
&lt;rect x=&quot;44&quot; y=&quot;214&quot; width=&quot;252&quot; height=&quot;104&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;117&quot; y=&quot;258&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Private subnet&lt;/text&gt;
&lt;text x=&quot;117&quot; y=&quot;280&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;10.0.11.0/24&lt;/text&gt;
&lt;rect x=&quot;190&quot; y=&quot;240&quot; width=&quot;96&quot; height=&quot;52&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;238&quot; y=&quot;271&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Servers&lt;/text&gt;
&lt;rect x=&quot;330&quot; y=&quot;66&quot; width=&quot;280&quot; height=&quot;268&quot; rx=&quot;12&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;470&quot; y=&quot;86&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Availability Zone B&lt;/text&gt;
&lt;rect x=&quot;344&quot; y=&quot;96&quot; width=&quot;252&quot; height=&quot;88&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;523&quot; y=&quot;130&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Public subnet&lt;/text&gt;
&lt;text x=&quot;523&quot; y=&quot;152&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;10.0.2.0/24&lt;/text&gt;
&lt;rect x=&quot;354&quot; y=&quot;116&quot; width=&quot;96&quot; height=&quot;48&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;402&quot; y=&quot;145&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;NAT&lt;/text&gt;
&lt;rect x=&quot;344&quot; y=&quot;214&quot; width=&quot;252&quot; height=&quot;104&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;523&quot; y=&quot;258&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Private subnet&lt;/text&gt;
&lt;text x=&quot;523&quot; y=&quot;280&quot; text-anchor=&quot;middle&quot; class=&quot;d-code&quot;&gt;10.0.12.0/24&lt;/text&gt;
&lt;rect x=&quot;354&quot; y=&quot;240&quot; width=&quot;96&quot; height=&quot;52&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;402&quot; y=&quot;271&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Servers&lt;/text&gt;
&lt;line x1=&quot;238&quot; y1=&quot;240&quot; x2=&quot;238&quot; y2=&quot;166&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#vpc-arrow)&quot;/&gt;
&lt;line x1=&quot;402&quot; y1=&quot;240&quot; x2=&quot;402&quot; y2=&quot;166&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#vpc-arrow)&quot;/&gt;
&lt;line x1=&quot;238&quot; y1=&quot;116&quot; x2=&quot;238&quot; y2=&quot;46&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#vpc-arrow)&quot;/&gt;
&lt;line x1=&quot;402&quot; y1=&quot;116&quot; x2=&quot;402&quot; y2=&quot;46&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#vpc-arrow)&quot;/&gt;
&lt;rect x=&quot;210&quot; y=&quot;6&quot; width=&quot;220&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;30&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Internet gateway&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;vpc-caption&quot;&gt;Servers sit in private subnets and go out to the internet through NAT in the public subnet, then the internet gateway, and nobody outside can start a connection to them.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;address-ranges-how-to-read-cidr&quot; tabindex=&quot;-1&quot;&gt;Address ranges: how to read CIDR &lt;a class=&quot;heading-anchor&quot; href=&quot;#address-ranges-how-to-read-cidr&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You write an address range in &lt;strong&gt;CIDR&lt;/strong&gt; form, such as &lt;code&gt;10.0.0.0/16&lt;/code&gt;. The number after the slash says how many of the 32 bits are fixed, so the smaller the number, the bigger the range:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CIDR&lt;/th&gt;
&lt;th&gt;Addresses&lt;/th&gt;
&lt;th&gt;Common use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;A single address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/28&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;The smallest VPC or subnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;256&lt;/td&gt;
&lt;td&gt;A subnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;65,536&lt;/td&gt;
&lt;td&gt;The largest VPC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All addresses&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0.0.0.0/0&lt;/code&gt; means anywhere&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use the private ranges: &lt;code&gt;10.0.0.0/8&lt;/code&gt;, &lt;code&gt;172.16.0.0/12&lt;/code&gt; or &lt;code&gt;192.168.0.0/16&lt;/code&gt;. The default VPC uses &lt;code&gt;172.31.0.0/16&lt;/code&gt;.&lt;/p&gt;
&lt;aside class=&quot;callout callout-warning&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-alert&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 4l9 16H3L12 4z&quot;/&gt;&lt;path d=&quot;M12 10v4M12 17h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Choose a range that won&#39;t clash&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If your range overlaps another network, you can&#39;t easily connect them later. Think about your office and any other networks you might connect to, which is the subject of &lt;a href=&quot;/en/posts/aws-14-vpc-connectivity/&quot;&gt;part fourteen&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;subnets&quot; tabindex=&quot;-1&quot;&gt;Subnets &lt;a class=&quot;heading-anchor&quot; href=&quot;#subnets&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A subnet is a slice of the VPC&#39;s range, and here&#39;s what matters most:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It lives in one Availability Zone.&lt;/strong&gt; For high availability you need subnets in at least two zones.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AWS reserves 5 addresses&lt;/strong&gt; in each one: the first four and the last. So &lt;code&gt;/24&lt;/code&gt; gives you 251 addresses, not 256.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;Public&amp;quot; and &amp;quot;private&amp;quot; aren&#39;t settings.&lt;/strong&gt; A subnet becomes public when its route table has a route to an internet gateway.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;route-tables-and-the-internet-gateway&quot; tabindex=&quot;-1&quot;&gt;Route tables and the internet gateway &lt;a class=&quot;heading-anchor&quot; href=&quot;#route-tables-and-the-internet-gateway&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An &lt;strong&gt;internet gateway&lt;/strong&gt; connects the VPC to the internet. A &lt;strong&gt;route table&lt;/strong&gt; decides where each packet goes. A public subnet&#39;s table looks like this:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Destination&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;10.0.0.0/16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;local&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inside the VPC, which is always there&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0.0.0.0/0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;igw-...&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Everything else goes to the internet&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For anyone to reach the server from outside, it also needs a public address. Remember from &lt;a href=&quot;/en/posts/aws-04-ec2-pricing-networking/&quot;&gt;part four&lt;/a&gt; that all public IPv4 addresses cost money.&lt;/p&gt;
&lt;h2 id=&quot;nat-gateway-out-without-in&quot; tabindex=&quot;-1&quot;&gt;NAT Gateway: out without in &lt;a class=&quot;heading-anchor&quot; href=&quot;#nat-gateway-out-without-in&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A server in a private subnet sometimes needs to go out, for example to download updates, but you don&#39;t want anyone coming in. That&#39;s the job of a &lt;strong&gt;NAT Gateway&lt;/strong&gt;: it sits in the public subnet, sends the private servers&#39; requests out under its own address, and accepts no connection started from outside.&lt;/p&gt;
&lt;p&gt;The private subnet&#39;s table has &lt;code&gt;0.0.0.0/0&lt;/code&gt; pointing to &lt;code&gt;nat-...&lt;/code&gt; instead of the internet gateway. There are a few forms:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Form&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Zonal NAT Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You need one in each Availability Zone, otherwise private subnets elsewhere lose access if its zone fails&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Regional NAT Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Newer. It expands automatically to the zones holding your servers, and is billed for each active zone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NAT instance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An EC2 server you manage yourself: you pay for the server instead of per gigabyte, its bandwidth depends on its size, it has no automatic failover, and you must turn off its source/destination check. It can be cheaper for very small workloads, but AWS recommends NAT gateways&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;aside class=&quot;callout callout-warning&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-alert&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 4l9 16H3L12 4z&quot;/&gt;&lt;path d=&quot;M12 10v4M12 17h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;The bill&#39;s surprise&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A NAT Gateway is billed by the hour and for every gigabyte passing through it. Many people discover it late on their bill. In the next part we&#39;ll see how to reduce this cost.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;how-do-you-reach-a-private-server&quot; tabindex=&quot;-1&quot;&gt;How do you reach a private server? &lt;a class=&quot;heading-anchor&quot; href=&quot;#how-do-you-reach-a-private-server&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It has no public address, so how do you get in?&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;How&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bastion host&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A public server you SSH through&lt;/td&gt;
&lt;td&gt;Old: keys, an open port and an extra server to secure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EC2 Instance Connect Endpoint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A point inside your network that connects you with no public address&lt;/td&gt;
&lt;td&gt;Free, and we&#39;ll use it in the hands-on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Session Manager&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A terminal through the SSM service, with no port 22&lt;/td&gt;
&lt;td&gt;Needs an IAM role, and logs sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;two-firewalls-security-groups-and-nacls&quot; tabindex=&quot;-1&quot;&gt;Two firewalls: security groups and NACLs &lt;a class=&quot;heading-anchor&quot; href=&quot;#two-firewalls-security-groups-and-nacls&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You know the &lt;a href=&quot;/en/posts/aws-03-ec2-first-server/&quot;&gt;security group&lt;/a&gt;, which surrounds the server. There&#39;s a second firewall called a &lt;strong&gt;NACL&lt;/strong&gt; that surrounds the subnet:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Security group&lt;/th&gt;
&lt;th&gt;NACL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Level&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The server&lt;/td&gt;
&lt;td&gt;The subnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Allow only&lt;/td&gt;
&lt;td&gt;Allow and deny&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Remembers the connection, so the reply goes out automatically&lt;/td&gt;
&lt;td&gt;Doesn&#39;t remember, so you must allow the reply too&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Evaluation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All rules&lt;/td&gt;
&lt;td&gt;In order, and the first match decides&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Default&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;In blocked, out allowed&lt;/td&gt;
&lt;td&gt;The default allows everything; a new one denies everything&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Since a NACL doesn&#39;t remember connections, you must allow the server&#39;s replies through &lt;strong&gt;ephemeral ports&lt;/strong&gt; (usually &lt;code&gt;1024-65535&lt;/code&gt;), and this causes a lot of mistakes.&lt;/p&gt;
&lt;p&gt;The practical rule: leave the default NACL alone and work with security groups. Use a NACL when you want to &lt;strong&gt;block&lt;/strong&gt; an address range quickly, since a security group can&#39;t deny.&lt;/p&gt;
&lt;h2 id=&quot;flow-logs&quot; tabindex=&quot;-1&quot;&gt;Flow Logs &lt;a class=&quot;heading-anchor&quot; href=&quot;#flow-logs&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When a request doesn&#39;t arrive and you don&#39;t know why, &lt;strong&gt;Flow Logs&lt;/strong&gt; record the details of each connection at the VPC, subnet or interface level, and send them to CloudWatch Logs or S3. A line looks like this:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Output&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;2 123456789012 eni-0abc 203.0.113.7 10.0.1.5 49152 22 6 5 300 1730000000 1730000060 REJECT OK&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;That means: from &lt;code&gt;203.0.113.7&lt;/code&gt; to &lt;code&gt;10.0.1.5&lt;/code&gt; on port &lt;code&gt;22&lt;/code&gt;, and it was rejected. How to diagnose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Inbound rejected:&lt;/strong&gt; the problem is the security group or the NACL.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inbound accepted and outbound rejected:&lt;/strong&gt; the problem is the NACL, because a security group allows the reply automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;hands-on-build-a-vpc-from-scratch&quot; tabindex=&quot;-1&quot;&gt;Hands-on: build a VPC from scratch &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-build-a-vpc-from-scratch&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll build a network with public and private subnets, and see for ourselves that the whole difference is in the route table. All commands are from CloudShell. First, the network and subnets:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;VPC&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 create-vpc --cidr-block &lt;span class=&quot;token number&quot;&gt;10.0&lt;/span&gt;.0.0/16 &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --tag-specifications &lt;span class=&quot;token string&quot;&gt;&#39;ResourceType=vpc,Tags=[{Key=Name,Value=series-vpc}]&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Vpc.VpcId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;AZ&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 describe-availability-zones &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AvailabilityZones[0].ZoneName&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;PUBLIC&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 create-subnet --vpc-id $VPC --cidr-block &lt;span class=&quot;token number&quot;&gt;10.0&lt;/span&gt;.1.0/24 &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --availability-zone $AZ &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Subnet.SubnetId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;PRIVATE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 create-subnet --vpc-id $VPC --cidr-block &lt;span class=&quot;token number&quot;&gt;10.0&lt;/span&gt;.11.0/24 &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --availability-zone $AZ &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Subnet.SubnetId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Now the internet gateway, and a route table for the public subnet only:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;IGW&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 create-internet-gateway &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; InternetGateway.InternetGatewayId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
aws ec2 attach-internet-gateway --vpc-id &lt;span class=&quot;token variable&quot;&gt;$VPC&lt;/span&gt; --internet-gateway-id &lt;span class=&quot;token variable&quot;&gt;$IGW&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;RT_PUBLIC&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 create-route-table --vpc-id $VPC &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; RouteTable.RouteTableId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
aws ec2 create-route --route-table-id &lt;span class=&quot;token variable&quot;&gt;$RT_PUBLIC&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --destination-cidr-block &lt;span class=&quot;token number&quot;&gt;0.0&lt;/span&gt;.0.0/0 --gateway-id &lt;span class=&quot;token variable&quot;&gt;$IGW&lt;/span&gt;
aws ec2 associate-route-table --route-table-id &lt;span class=&quot;token variable&quot;&gt;$RT_PUBLIC&lt;/span&gt; --subnet-id &lt;span class=&quot;token variable&quot;&gt;$PUBLIC&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;A security group allowing traffic only from inside the network, and an entry point so we can reach the servers without opening a port to the world:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;SG&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 create-security-group --group-name series-sg &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--description&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SSH and ping from inside the VPC&quot;&lt;/span&gt; --vpc-id $VPC &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; GroupId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
aws ec2 authorize-security-group-ingress --group-id &lt;span class=&quot;token variable&quot;&gt;$SG&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--protocol&lt;/span&gt; tcp &lt;span class=&quot;token parameter variable&quot;&gt;--port&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;22&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--cidr&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10.0&lt;/span&gt;.0.0/16
aws ec2 authorize-security-group-ingress --group-id &lt;span class=&quot;token variable&quot;&gt;$SG&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--protocol&lt;/span&gt; icmp &lt;span class=&quot;token parameter variable&quot;&gt;--port&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-1&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--cidr&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10.0&lt;/span&gt;.0.0/16

aws ec2 create-instance-connect-endpoint --subnet-id &lt;span class=&quot;token variable&quot;&gt;$PRIVATE&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --security-group-ids &lt;span class=&quot;token variable&quot;&gt;$SG&lt;/span&gt; --no-preserve-client-ip&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;And a server in each subnet:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;AMI&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ssm get-parameter &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Parameter.Value &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws ec2 run-instances --image-id &lt;span class=&quot;token variable&quot;&gt;$AMI&lt;/span&gt; --instance-type t3.micro &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --subnet-id &lt;span class=&quot;token variable&quot;&gt;$PUBLIC&lt;/span&gt; --security-group-ids &lt;span class=&quot;token variable&quot;&gt;$SG&lt;/span&gt; --associate-public-ip-address &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --tag-specifications &lt;span class=&quot;token string&quot;&gt;&#39;ResourceType=instance,Tags=[{Key=Name,Value=public-server}]&#39;&lt;/span&gt;

aws ec2 run-instances --image-id &lt;span class=&quot;token variable&quot;&gt;$AMI&lt;/span&gt; --instance-type t3.micro &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --subnet-id &lt;span class=&quot;token variable&quot;&gt;$PRIVATE&lt;/span&gt; --security-group-ids &lt;span class=&quot;token variable&quot;&gt;$SG&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --tag-specifications &lt;span class=&quot;token string&quot;&gt;&#39;ResourceType=instance,Tags=[{Key=Name,Value=private-server}]&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Wait a few minutes for the entry point to be ready. Then in EC2 select a server, choose &lt;strong&gt;Connect&lt;/strong&gt;, and under &lt;strong&gt;EC2 Instance Connect&lt;/strong&gt; pick the option that connects through the endpoint. On each server, try:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; https://checkip.amazonaws.com&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;public-server&lt;/code&gt;:&lt;/strong&gt; prints its public address.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;private-server&lt;/code&gt;:&lt;/strong&gt; times out with no answer, because it has no route to the internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From the private server, try &lt;code&gt;ping&lt;/code&gt; on the public server&#39;s private address, and it replies, because the &lt;code&gt;local&lt;/code&gt; route connects them.&lt;/p&gt;
&lt;h3 id=&quot;add-a-nat-gateway&quot; tabindex=&quot;-1&quot;&gt;Add a NAT Gateway &lt;a class=&quot;heading-anchor&quot; href=&quot;#add-a-nat-gateway&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now let the private server go out. This step is billed by the hour, so delete it after experimenting:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;ALLOC&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 allocate-address &lt;span class=&quot;token parameter variable&quot;&gt;--domain&lt;/span&gt; vpc &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; AllocationId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;NAT&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 create-nat-gateway --subnet-id $PUBLIC --allocation-id $ALLOC &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; NatGateway.NatGatewayId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
aws ec2 &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt; nat-gateway-available --nat-gateway-ids &lt;span class=&quot;token variable&quot;&gt;$NAT&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;RT_PRIVATE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 create-route-table --vpc-id $VPC &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; RouteTable.RouteTableId &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
aws ec2 create-route --route-table-id &lt;span class=&quot;token variable&quot;&gt;$RT_PRIVATE&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --destination-cidr-block &lt;span class=&quot;token number&quot;&gt;0.0&lt;/span&gt;.0.0/0 --nat-gateway-id &lt;span class=&quot;token variable&quot;&gt;$NAT&lt;/span&gt;
aws ec2 associate-route-table --route-table-id &lt;span class=&quot;token variable&quot;&gt;$RT_PRIVATE&lt;/span&gt; --subnet-id &lt;span class=&quot;token variable&quot;&gt;$PRIVATE&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Repeat the same &lt;code&gt;curl&lt;/code&gt; command on &lt;code&gt;private-server&lt;/code&gt;. This time it prints an address, which is the NAT Gateway&#39;s, not the server&#39;s. The server went out to the internet, and still nobody can start a connection to it.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Delete the NAT Gateway from its page in VPC, and once it&#39;s gone release the Elastic IP from its page in EC2. If you&#39;re carrying on straight to &lt;a href=&quot;/en/posts/aws-14-vpc-connectivity/&quot;&gt;part fourteen&lt;/a&gt;, keep the VPC and servers. Otherwise delete the servers and the entry point, then select the VPC and choose &lt;strong&gt;Actions&lt;/strong&gt; and &lt;strong&gt;Delete VPC&lt;/strong&gt;, which removes the rest with it.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;VPC&lt;/strong&gt; is your private network in a Region, split into subnets across Availability Zones.&lt;/li&gt;
&lt;li&gt;A subnet is &lt;strong&gt;public&lt;/strong&gt; if its table has a route to an internet gateway, otherwise it&#39;s &lt;strong&gt;private&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;NAT Gateway&lt;/strong&gt; lets private subnets go out with nobody coming in, but watch its cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security groups&lt;/strong&gt; remember connections and only allow; &lt;strong&gt;NACLs&lt;/strong&gt; don&#39;t remember and can deny.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flow Logs&lt;/strong&gt; tell you where a connection was rejected.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 6&lt;/p&gt;
&lt;p&gt;A new server has a public address, and its security group allows HTTPS from anywhere, yet nobody can reach it from the internet. The VPC has an internet gateway attached, and the subnet&#39;s route table has only the &lt;code&gt;local&lt;/code&gt; route. What&#39;s missing?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A &lt;code&gt;0.0.0.0/0&lt;/code&gt; route to the internet gateway in the subnet&#39;s route table&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A NAT Gateway in the same subnet&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;An outbound rule in the security group for the replies&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A peering connection to the default VPC&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A subnet becomes public when its route table points to an internet gateway. Without that route, packets have no way out, even with a public address.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; NAT lets private servers go out, and accepts no connection started from outside.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; A security group remembers the connection, so the reply goes out automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Peering connects two VPCs, and gives no path to the internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#route-tables-and-the-internet-gateway&quot;&gt;Route tables and the internet gateway&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html&quot;&gt;Enable internet access for a VPC using an internet gateway&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 6&lt;/p&gt;
&lt;p&gt;A team is planning a subnet that must hold 30 servers. Address space is tight, so it wants the smallest block that fits. Which one should it pick?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;&lt;code&gt;/29&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;&lt;code&gt;/28&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;&lt;code&gt;/27&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;&lt;code&gt;/26&lt;/code&gt;&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AWS reserves 5 addresses in every subnet. A &lt;code&gt;/27&lt;/code&gt; has 32, which leaves 27, so it falls short. A &lt;code&gt;/26&lt;/code&gt; has 64, which leaves 59.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; The smallest subnet AWS allows is &lt;code&gt;/28&lt;/code&gt;, so this can&#39;t even be created.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This leaves only 11 usable addresses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This leaves 27 usable addresses, three short of what&#39;s needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#subnets&quot;&gt;Subnets&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/subnet-sizing.html&quot;&gt;Subnet CIDR blocks&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 6&lt;/p&gt;
&lt;p&gt;An application runs in private subnets across two Availability Zones, sharing one zonal NAT Gateway in the first zone. In an outage of that zone, the servers in the second zone stayed healthy but lost internet access. What fixes this?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;An extra internet gateway for the second zone&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A NAT Gateway in the second zone, with each private subnet routing to the one in its own zone&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;A second Elastic IP on the existing NAT Gateway&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Moving the NAT Gateway to a private subnet&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A zonal NAT Gateway lives in one zone, so that zone&#39;s failure cuts off everyone relying on it. With one in each zone, a failure stays in its own zone. A Regional NAT Gateway gets you the same result automatically.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; A VPC has one internet gateway, and private subnets don&#39;t route to it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; More addresses don&#39;t move it out of the failed zone.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; A NAT Gateway sits in a public subnet, and this would cut it off from the internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#nat-gateway-out-without-in&quot;&gt;NAT Gateway: out without in&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/nat-gateway-basics.html&quot;&gt;NAT gateway basics&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 6&lt;/p&gt;
&lt;p&gt;To block an abusive address range, a team creates a new NACL with a deny rule for that range and an inbound allow rule for port 443. Now no visitor can load the site. Flow Logs show the requests as &lt;code&gt;ACCEPT&lt;/code&gt; and the replies as &lt;code&gt;REJECT&lt;/code&gt;. What should the team do?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Add a deny rule for the range to the security group&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Add an outbound rule for the replies to the security group&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Add an outbound NACL rule allowing the ephemeral ports&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Delete the inbound allow rule from the NACL&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A NACL doesn&#39;t remember connections, and a new one denies everything you haven&#39;t allowed, so the replies need their own rule. Inbound accepted with outbound rejected points straight at the NACL.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; A security group can only allow, so it can&#39;t hold a deny rule.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; A security group remembers the connection, so it was already letting the reply out.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This would block the requests as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#two-firewalls-security-groups-and-nacls&quot;&gt;Two firewalls: security groups and NACLs&lt;/a&gt; and &lt;a href=&quot;#flow-logs&quot;&gt;Flow Logs&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/custom-network-acl.html&quot;&gt;Custom network ACLs for your VPC&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 6&lt;/p&gt;
&lt;p&gt;Engineers need a terminal on servers in a private subnet. The servers must keep having no public addresses, and the team doesn&#39;t want another server to patch and secure. Which &lt;strong&gt;two&lt;/strong&gt; options fit? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A bastion host in a public subnet&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;A NAT Gateway, with an SSH rule&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Session Manager, with an IAM role on the servers&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;An Elastic IP on each server&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;An EC2 Instance Connect Endpoint in the VPC&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Both reach the server with no public address and no extra server to run. Session Manager also needs no port 22, and it logs sessions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This is the extra server the team wants to avoid.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; A NAT Gateway only lets traffic out, and accepts no connection started from outside.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This gives the servers public addresses, which is what must be avoided.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#how-do-you-reach-a-private-server&quot;&gt;How do you reach a private server?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html&quot;&gt;Session Manager&lt;/a&gt; and &lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-with-ec2-instance-connect-endpoint.html&quot;&gt;EC2 Instance Connect Endpoint&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 6 of 6&lt;/p&gt;
&lt;p&gt;A team sets up a NAT instance in a public subnet and points the private subnet&#39;s route table to it, yet private servers still can&#39;t reach the internet. The security groups allow the traffic. What did it most likely forget?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;An Elastic IP on each private server&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Turning off the source/destination check on the NAT instance&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;A second route table for the public subnet&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A gateway endpoint for the internet&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An EC2 server normally has to be the source or destination of its traffic. A NAT instance passes on traffic for others, so this check has to be off.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; Private servers go out through the NAT instance&#39;s address, and don&#39;t need their own.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; The public subnet only needs its route to the internet gateway, and this adds nothing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Gateway endpoints reach S3 and DynamoDB, not the internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#nat-gateway-out-without-in&quot;&gt;NAT Gateway: out without in&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/work-with-nat-instances.html&quot;&gt;Enable private resources to communicate outside the VPC&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;Your network is now ready, but isolated. In &lt;a href=&quot;/en/posts/aws-14-vpc-connectivity/&quot;&gt;&lt;strong&gt;part fourteen&lt;/strong&gt;&lt;/a&gt; we connect it to other networks, to AWS services and to your office.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>CloudFront and Global Accelerator: Closer to Your Visitors</title>
    <link href="https://blog.sultanops.com/en/posts/aws-12-cloudfront-global-accelerator/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-12-cloudfront-global-accelerator/</id>
    <summary>Why distance slows your site, how CloudFront keeps copies near your visitors, how to protect your origin and clear the cache, what Global Accelerator does for traffic that can&#39;t be cached, and when to choose each.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-11-dns-route53/&quot;&gt;part eleven&lt;/a&gt; your site got a name, but its server is still in one place. A distant visitor&#39;s request crosses continents and many networks on the public internet, and every request takes time.&lt;/p&gt;
&lt;p&gt;You have two services for this problem: &lt;strong&gt;CloudFront&lt;/strong&gt; keeps a copy near the visitor, and &lt;strong&gt;Global Accelerator&lt;/strong&gt; shortens the road itself.&lt;/p&gt;
&lt;h2 id=&quot;cloudfront-a-copy-near-every-visitor&quot; tabindex=&quot;-1&quot;&gt;CloudFront: a copy near every visitor &lt;a class=&quot;heading-anchor&quot; href=&quot;#cloudfront-a-copy-near-every-visitor&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;CloudFront&lt;/strong&gt; is a content delivery network (CDN). It uses the &lt;a href=&quot;/en/posts/aws-01-global-infrastructure/&quot;&gt;edge locations&lt;/a&gt; spread around the world: the first visitor to request a file makes CloudFront fetch it from your origin and keep it, and later visitors in the same area get it directly from the edge location.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 220&quot; role=&quot;img&quot; aria-labelledby=&quot;cf-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;cf-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;24&quot; width=&quot;130&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;85&quot; y=&quot;50&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Visitor&lt;/text&gt;
&lt;text x=&quot;85&quot; y=&quot;70&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;in Asia&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;136&quot; width=&quot;130&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;85&quot; y=&quot;162&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Visitor&lt;/text&gt;
&lt;text x=&quot;85&quot; y=&quot;182&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;in Europe&lt;/text&gt;
&lt;rect x=&quot;235&quot; y=&quot;24&quot; width=&quot;150&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;310&quot; y=&quot;50&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Edge location&lt;/text&gt;
&lt;text x=&quot;310&quot; y=&quot;70&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Keeps a copy&lt;/text&gt;
&lt;rect x=&quot;235&quot; y=&quot;136&quot; width=&quot;150&quot; height=&quot;60&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;310&quot; y=&quot;162&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Edge location&lt;/text&gt;
&lt;text x=&quot;310&quot; y=&quot;182&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Keeps a copy&lt;/text&gt;
&lt;rect x=&quot;470&quot; y=&quot;64&quot; width=&quot;150&quot; height=&quot;92&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;545&quot; y=&quot;96&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Origin&lt;/text&gt;
&lt;text x=&quot;545&quot; y=&quot;118&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;ALB, S3 or a server&lt;/text&gt;
&lt;text x=&quot;545&quot; y=&quot;138&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;In one Region&lt;/text&gt;
&lt;line x1=&quot;150&quot; y1=&quot;54&quot; x2=&quot;233&quot; y2=&quot;54&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#cf-arrow)&quot;/&gt;
&lt;line x1=&quot;150&quot; y1=&quot;166&quot; x2=&quot;233&quot; y2=&quot;166&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#cf-arrow)&quot;/&gt;
&lt;line x1=&quot;385&quot; y1=&quot;54&quot; x2=&quot;468&quot; y2=&quot;94&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;4 4&quot;/&gt;
&lt;line x1=&quot;385&quot; y1=&quot;166&quot; x2=&quot;468&quot; y2=&quot;126&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;4 4&quot;/&gt;
&lt;text x=&quot;412&quot; y=&quot;115&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;If missing&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;cf-caption&quot;&gt;Each visitor reaches the nearest edge location, which goes back to the origin only if it has no valid copy.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;What do you gain?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Higher speed:&lt;/strong&gt; the answer comes from somewhere close.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Less load on the origin:&lt;/strong&gt; most requests end at the edge.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protection:&lt;/strong&gt; it comes with Shield Standard against DDoS attacks, and you can add WAF.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Free HTTPS:&lt;/strong&gt; with an ACM certificate, and TLS handled at the edge.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;origins&quot; tabindex=&quot;-1&quot;&gt;Origins &lt;a class=&quot;heading-anchor&quot; href=&quot;#origins&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The origin is where the content originally lives. The key point is that visitors shouldn&#39;t be able to skip CloudFront and reach it directly:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Origin&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;th&gt;How to keep it private&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;S3 bucket&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Static sites and files&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OAC&lt;/strong&gt; lets only CloudFront read from it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ALB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dynamic applications&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VPC origins&lt;/strong&gt; keep the load balancer in a private network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EC2 server&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An application on a server&lt;/td&gt;
&lt;td&gt;VPC origins, or a security group allowing only CloudFront&#39;s ranges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Any HTTP server&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Even outside AWS&lt;/td&gt;
&lt;td&gt;A secret header the server checks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;We cover S3 in detail in the &lt;a href=&quot;/en/series/aws/#section-6&quot;&gt;object storage section&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what-gets-cached-and-for-how-long&quot; tabindex=&quot;-1&quot;&gt;What gets cached, and for how long? &lt;a class=&quot;heading-anchor&quot; href=&quot;#what-gets-cached-and-for-how-long&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cache key:&lt;/strong&gt; the URL by default. The more headers or cookies you add to it, the lower the chance of finding a ready copy, so keep it minimal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lifetime:&lt;/strong&gt; from the origin&#39;s &lt;code&gt;Cache-Control&lt;/code&gt; header, or from CloudFront&#39;s settings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Behaviors:&lt;/strong&gt; rules by path, such as &lt;code&gt;/images/*&lt;/code&gt; with a long lifetime and &lt;code&gt;/api/*&lt;/code&gt; with no caching. One domain can serve both static and dynamic content.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;clearing-the-cache&quot; tabindex=&quot;-1&quot;&gt;Clearing the cache &lt;a class=&quot;heading-anchor&quot; href=&quot;#clearing-the-cache&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you change a file, the old copy stays until it expires. You have two solutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Invalidation:&lt;/strong&gt; you ask CloudFront to clear paths, such as &lt;code&gt;/*&lt;/code&gt;. The first 1,000 paths each month are free.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A version in the file name:&lt;/strong&gt; such as &lt;code&gt;main.css?v=12&lt;/code&gt;, so a new version is a new URL. This is the better solution for static files.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;callout callout-note&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-info&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;circle cx=&quot;12&quot; cy=&quot;12&quot; r=&quot;8.5&quot;/&gt;&lt;path d=&quot;M12 11v5M12 8h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;A real example&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The CSS and JavaScript links on this blog carry a version that changes with every deploy, so visitors get the new copy without any clearing.&lt;/p&gt;
&lt;/aside&gt;
&lt;h3 id=&quot;extra-features&quot; tabindex=&quot;-1&quot;&gt;Extra features &lt;a class=&quot;heading-anchor&quot; href=&quot;#extra-features&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Geo restriction:&lt;/strong&gt; allow or block certain countries, for example for content licensed to one country.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Signed URLs:&lt;/strong&gt; for paid or private content, with a link that expires.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CloudFront Functions and Lambda@Edge:&lt;/strong&gt; short code running at the edge, such as redirects and header changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;pricing&quot; tabindex=&quot;-1&quot;&gt;Pricing &lt;a class=&quot;heading-anchor&quot; href=&quot;#pricing&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You have two options, and prices can change, so check them before deciding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pay as you go:&lt;/strong&gt; you pay for outgoing data and requests, at rates that vary by area. Each month you get 1 TB and 10 million requests free. &lt;strong&gt;Price classes&lt;/strong&gt; let you leave out the most expensive areas in exchange for less coverage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flat-rate plans:&lt;/strong&gt; Free, Pro, Business and Premium, with a monthly price per distribution and no surprises, including other services such as WAF.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Data moving from S3 or an ALB to CloudFront is free.&lt;/p&gt;
&lt;h3 id=&quot;cloudfront-or-s3-replication-between-regions&quot; tabindex=&quot;-1&quot;&gt;CloudFront or S3 replication between Regions? &lt;a class=&quot;heading-anchor&quot; href=&quot;#cloudfront-or-s3-replication-between-regions&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;CloudFront&lt;/th&gt;
&lt;th&gt;S3 Cross-Region Replication&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Coverage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All edge locations&lt;/td&gt;
&lt;td&gt;The Regions you choose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Temporary copies until they expire&lt;/td&gt;
&lt;td&gt;Full copies kept continuously up to date&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Good for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Static content for the whole world&lt;/td&gt;
&lt;td&gt;Changing data you want close in specific Regions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;global-accelerator-a-faster-road&quot; tabindex=&quot;-1&quot;&gt;Global Accelerator: a faster road &lt;a class=&quot;heading-anchor&quot; href=&quot;#global-accelerator-a-faster-road&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some traffic can&#39;t be cached: a game over UDP, a voice call or a payment request. It has to reach your application itself, and on the public internet it passes through many networks with unsteady delays.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Global Accelerator&lt;/strong&gt; brings the visitor onto AWS&#39;s private network at the nearest edge location, and carries on along it to your application.&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 220&quot; role=&quot;img&quot; aria-labelledby=&quot;ga-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;ga-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;text x=&quot;320&quot; y=&quot;22&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Without it: many networks and unsteady delays&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;36&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;75&quot; y=&quot;66&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Visitor&lt;/text&gt;
&lt;rect x=&quot;510&quot; y=&quot;36&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;565&quot; y=&quot;66&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Your app&lt;/text&gt;
&lt;polyline points=&quot;130,61 190,44 250,76 320,46 390,78 450,48 508,61&quot; fill=&quot;none&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;4 4&quot;/&gt;
&lt;circle cx=&quot;190&quot; cy=&quot;44&quot; r=&quot;5&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;circle cx=&quot;250&quot; cy=&quot;76&quot; r=&quot;5&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;circle cx=&quot;320&quot; cy=&quot;46&quot; r=&quot;5&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;circle cx=&quot;390&quot; cy=&quot;78&quot; r=&quot;5&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;circle cx=&quot;450&quot; cy=&quot;48&quot; r=&quot;5&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;320&quot; y=&quot;128&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;With it: AWS&#39;s private network from the nearest edge location&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;146&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;75&quot; y=&quot;176&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Visitor&lt;/text&gt;
&lt;rect x=&quot;170&quot; y=&quot;146&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;225&quot; y=&quot;176&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Edge&lt;/text&gt;
&lt;rect x=&quot;510&quot; y=&quot;146&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;565&quot; y=&quot;176&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Your app&lt;/text&gt;
&lt;line x1=&quot;130&quot; y1=&quot;171&quot; x2=&quot;168&quot; y2=&quot;171&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#ga-arrow)&quot;/&gt;
&lt;line x1=&quot;280&quot; y1=&quot;171&quot; x2=&quot;508&quot; y2=&quot;171&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;3&quot; marker-end=&quot;url(#ga-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;ga-caption&quot;&gt;Instead of crossing the whole public internet, the request enters AWS&#39;s network at the nearest edge location and carries on along it.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;two-static-addresses-through-anycast&quot; tabindex=&quot;-1&quot;&gt;Two static addresses through Anycast &lt;a class=&quot;heading-anchor&quot; href=&quot;#two-static-addresses-through-anycast&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On the ordinary internet (&lt;strong&gt;Unicast&lt;/strong&gt;), each address has one machine. With &lt;strong&gt;Anycast&lt;/strong&gt;, several places share the same address, and the network takes you to the nearest.&lt;/p&gt;
&lt;p&gt;Global Accelerator gives you &lt;strong&gt;two static addresses&lt;/strong&gt; of this kind, pointing at ALBs, NLBs, EC2 servers or Elastic IPs, even across Regions. That gives you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Addresses that don&#39;t change:&lt;/strong&gt; your customers can allow them in their firewalls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fast failover:&lt;/strong&gt; it follows the application&#39;s health and moves traffic, with no waiting for DNS caches on people&#39;s devices.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traffic control:&lt;/strong&gt; you set each Region&#39;s share, so you can try a new version in one of them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protection:&lt;/strong&gt; Shield Standard, and your application isn&#39;t exposed directly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It costs a fixed hourly fee plus an extra data charge, so it has no free allowance like CloudFront&#39;s.&lt;/p&gt;
&lt;h3 id=&quot;which-should-you-choose&quot; tabindex=&quot;-1&quot;&gt;Which should you choose? &lt;a class=&quot;heading-anchor&quot; href=&quot;#which-should-you-choose&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;CloudFront&lt;/th&gt;
&lt;th&gt;Global Accelerator&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Protocols&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HTTP and HTTPS&lt;/td&gt;
&lt;td&gt;Any TCP or UDP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Caches?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No, it only carries the request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Addresses&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Change, so you use a domain name&lt;/td&gt;
&lt;td&gt;Two static addresses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Good for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sites, images, video and APIs&lt;/td&gt;
&lt;td&gt;Games, calls and IoT, or a need for static addresses&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If your application is HTTP, start with CloudFront.&lt;/p&gt;
&lt;h2 id=&quot;the-full-picture-so-far&quot; tabindex=&quot;-1&quot;&gt;The full picture so far &lt;a class=&quot;heading-anchor&quot; href=&quot;#the-full-picture-so-far&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The visitor&#39;s path now looks like this: &lt;strong&gt;Route 53&lt;/strong&gt; gives them the address, then &lt;strong&gt;CloudFront&lt;/strong&gt; answers from the nearest location if it has a copy, otherwise it passes the request to the &lt;strong&gt;ALB&lt;/strong&gt;, which spreads it across &lt;strong&gt;Auto Scaling&lt;/strong&gt; servers that read from &lt;strong&gt;ElastiCache&lt;/strong&gt; and &lt;strong&gt;RDS&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;hands-on-see-the-cache-for-yourself&quot; tabindex=&quot;-1&quot;&gt;Hands-on: see the cache for yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-see-the-cache-for-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ll put CloudFront in front of your &lt;code&gt;web-1&lt;/code&gt; server from &lt;a href=&quot;/en/posts/aws-03-ec2-first-server/&quot;&gt;part three&lt;/a&gt;, since it allows HTTP from anywhere. From CloudShell:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;ORIGIN&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 describe-instances &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--filters&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Name=tag:Name,Values=web-1&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Name=instance-state-name,Values=running&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Reservations[0].Instances[0].PublicDnsName&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

aws cloudfront create-distribution &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --origin-domain-name &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$ORIGIN&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Distribution.[Id,DomainName]&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; table&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Note the ID and domain from the table, and wait until it&#39;s ready, which takes a few minutes:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws cloudfront &lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt; distribution-deployed &lt;span class=&quot;token parameter variable&quot;&gt;--id&lt;/span&gt; YOUR-DISTRIBUTION-ID&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Now request the page three times and look at the headers:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token for-or-select variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; /dev/null &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; - https://YOUR-DOMAIN.cloudfront.net &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-iE&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^(x-cache|age|x-amz-cf-pop)&quot;&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;The first request returns &lt;code&gt;Miss from cloudfront&lt;/code&gt;, and later ones &lt;code&gt;Hit from cloudfront&lt;/code&gt; with a growing &lt;code&gt;age&lt;/code&gt;. &lt;code&gt;x-amz-cf-pop&lt;/code&gt; shows the edge location that answered you.&lt;/p&gt;
&lt;p&gt;Now change the page on the server through EC2 Instance Connect:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;h1&gt;New version&amp;lt;/h1&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tee&lt;/span&gt; /usr/share/nginx/html/index.html&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Open the CloudFront link and you&#39;ll find the old page, because it&#39;s still cached. Clear it from CloudShell:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws cloudfront create-invalidation &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --distribution-id YOUR-DISTRIBUTION-ID &lt;span class=&quot;token parameter variable&quot;&gt;--paths&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/*&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Moments later the new page appears.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A distribution can&#39;t be deleted straight away. On its page in the console choose &lt;strong&gt;Disable&lt;/strong&gt;, wait for that to finish, then &lt;strong&gt;Delete&lt;/strong&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CloudFront&lt;/strong&gt; keeps copies near visitors, so the site gets faster and the origin gets less load.&lt;/li&gt;
&lt;li&gt;Keep your origin &lt;strong&gt;private&lt;/strong&gt; through OAC or VPC origins, so nobody can skip CloudFront.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;version in the file name&lt;/strong&gt; beats clearing the cache every time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Global Accelerator&lt;/strong&gt; doesn&#39;t cache, but carries any TCP or UDP over AWS&#39;s network with two static addresses.&lt;/li&gt;
&lt;li&gt;If your application is HTTP, start with CloudFront.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 5&lt;/p&gt;
&lt;p&gt;A multiplayer game sends its traffic over UDP to servers in two Regions. Players complain of unsteady delays, and some partners can only allow fixed addresses through their firewalls. Which service fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Amazon CloudFront, using all edge locations&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;AWS Global Accelerator&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Route 53, with Latency records&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;S3 Cross-Region Replication&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Global Accelerator carries any TCP or UDP over AWS&#39;s network from the nearest edge location, and gives you two static addresses that can go in a firewall.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; CloudFront serves HTTP and HTTPS, not a game&#39;s UDP traffic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This only picks a Region, so the traffic still crosses the public internet, and the addresses aren&#39;t static.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This copies S3 objects, and has nothing to do with live game traffic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#global-accelerator-a-faster-road&quot;&gt;Global Accelerator: a faster road&lt;/a&gt; in this part, and &lt;a href=&quot;https://aws.amazon.com/global-accelerator/faqs/&quot;&gt;AWS Global Accelerator FAQs&lt;/a&gt; on the AWS site.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 5&lt;/p&gt;
&lt;p&gt;An online academy keeps its course files in S3 and serves them through CloudFront. Visitors can still open the files directly from the bucket&#39;s URL, skipping CloudFront altogether. What closes this gap?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Geo restriction on the distribution&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Signed URLs on the distribution&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;OAC, with a bucket policy that only allows CloudFront&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;An invalidation of &lt;code&gt;/*&lt;/code&gt; on the distribution&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With OAC, CloudFront signs its requests to S3 and the bucket policy accepts only those, so the bucket stays closed to everyone else.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This limits countries inside CloudFront, and the bucket&#39;s URL stays open.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This controls who gets through CloudFront, and the bucket&#39;s URL stays open.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This clears copies from the cache, and changes nothing about who can reach the bucket.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#origins&quot;&gt;Origins&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html&quot;&gt;Restrict access to an Amazon S3 origin&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 5&lt;/p&gt;
&lt;p&gt;One domain serves product images under &lt;code&gt;/images/*&lt;/code&gt; and a live API under &lt;code&gt;/api/*&lt;/code&gt;. The images should stay cached for a month, while API responses must never be cached. What&#39;s the simplest way to do this with CloudFront?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Two distributions, each with its own domain&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;An invalidation of &lt;code&gt;/api/*&lt;/code&gt; after every request&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Global Accelerator in front of the API&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;One distribution, with a behavior for each path&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A behavior applies its own rules to a path pattern, so one distribution on one domain can keep images for a long time and pass the API straight through.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This splits the site across two domains for no need.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; Invalidations take time and aren&#39;t made for every request, and the paths stop being free after the monthly allowance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This doesn&#39;t cache anything, so it does nothing for the images.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#what-gets-cached-and-for-how-long&quot;&gt;What gets cached, and for how long?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesCacheBehavior.html&quot;&gt;Cache behavior settings&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 5&lt;/p&gt;
&lt;p&gt;A team changes &lt;code&gt;main.css&lt;/code&gt; several times a day. Visitors sometimes see old styles, and the team is tired of invalidating the cache after each release. What&#39;s the better long-term solution?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Put a version in the file&#39;s URL, and change it with each release&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Give the file a one-year lifetime, with no version&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Remove CloudFront, and serve the file from the origin&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Replicate the file to a bucket in each Region&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A new version means a new URL, so visitors get the new copy at once, with no waiting for the old one to expire and no invalidations to run.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; Visitors would keep the old copy for even longer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This gives up the speed, and puts the load back on the origin.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This adds more copies to keep in sync, and the old one stays in the cache.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#clearing-the-cache&quot;&gt;Clearing the cache&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/UpdatingExistingObjects.html&quot;&gt;Use file versioning to update or remove content&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 5&lt;/p&gt;
&lt;p&gt;A news site finds that most CloudFront requests still reach its origin, even for articles that rarely change. The cache key includes all cookies and headers, and the origin sends &lt;code&gt;Cache-Control: max-age=60&lt;/code&gt;. Which &lt;strong&gt;two&lt;/strong&gt; changes raise the share of requests answered from the edge? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Invalidate &lt;code&gt;/*&lt;/code&gt; every hour&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Remove the cookies and headers the pages don&#39;t depend on from the cache key&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Put Global Accelerator in front of the origin&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Have the origin send a longer &lt;code&gt;max-age&lt;/code&gt; for articles&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Add a second distribution for the same content&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B + D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every extra value in the key splits one page into many copies, and a short lifetime sends requests back to the origin soon after. With both fixed, more visitors find a ready copy.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This empties the cache, so the problem gets worse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This doesn&#39;t cache, so requests would still reach the origin.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E:&lt;/strong&gt; It would have the same key and lifetime, so the same problem would repeat.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#what-gets-cached-and-for-how-long&quot;&gt;What gets cached, and for how long?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cache-hit-ratio.html&quot;&gt;Increase the proportion of requests that are served directly from the CloudFront caches&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;All this brings the visitor to your network&#39;s door, but how is the network itself built? In &lt;a href=&quot;/en/posts/aws-13-vpc/&quot;&gt;&lt;strong&gt;part thirteen&lt;/strong&gt;&lt;/a&gt; we open up the VPC and build one from scratch.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>DNS and Route 53: Your Site&#39;s Address</title>
    <link href="https://blog.sultanops.com/en/posts/aws-11-dns-route53/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-11-dns-route53/</id>
    <summary>How a name like example.com turns into an address, what the record types mean, the difference between CNAME and Alias, Route 53&#39;s routing policies and health checks, and a hands-on that doesn&#39;t require buying a domain.</summary>
    <content type="html">&lt;p&gt;The load balancer in our application from &lt;a href=&quot;/en/posts/aws-07-auto-scaling/&quot;&gt;part seven&lt;/a&gt; has a name like &lt;code&gt;web-alb-1234567890.eu-central-1.elb.amazonaws.com&lt;/code&gt;. Nobody is going to type that. Visitors want &lt;code&gt;shop.example.com&lt;/code&gt;, and what connects the two is &lt;strong&gt;DNS&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This section is about the visitor&#39;s path to your application: the name in this part, speed in the next, then the private network everything lives in.&lt;/p&gt;
&lt;h2 id=&quot;how-dns-works&quot; tabindex=&quot;-1&quot;&gt;How DNS works &lt;a class=&quot;heading-anchor&quot; href=&quot;#how-dns-works&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DNS is the internet&#39;s phone book: you ask with a name and it answers with an address. No single server knows everything, so the answer comes through a chain:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 300&quot; role=&quot;img&quot; aria-labelledby=&quot;dns-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;dns-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;110&quot; width=&quot;120&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;80&quot; y=&quot;150&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Browser&lt;/text&gt;
&lt;rect x=&quot;220&quot; y=&quot;110&quot; width=&quot;130&quot; height=&quot;70&quot; rx=&quot;10&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;285&quot; y=&quot;140&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Resolver&lt;/text&gt;
&lt;text x=&quot;285&quot; y=&quot;162&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Asks for you&lt;/text&gt;
&lt;rect x=&quot;450&quot; y=&quot;14&quot; width=&quot;170&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;535&quot; y=&quot;40&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Root servers&lt;/text&gt;
&lt;text x=&quot;535&quot; y=&quot;62&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Go ask .com&lt;/text&gt;
&lt;rect x=&quot;450&quot; y=&quot;116&quot; width=&quot;170&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;535&quot; y=&quot;142&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;.com servers&lt;/text&gt;
&lt;text x=&quot;535&quot; y=&quot;164&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Go ask Route 53&lt;/text&gt;
&lt;rect x=&quot;450&quot; y=&quot;218&quot; width=&quot;170&quot; height=&quot;62&quot; rx=&quot;10&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;535&quot; y=&quot;244&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Route 53&lt;/text&gt;
&lt;text x=&quot;535&quot; y=&quot;266&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;The address is 192.0.2.10&lt;/text&gt;
&lt;line x1=&quot;140&quot; y1=&quot;145&quot; x2=&quot;218&quot; y2=&quot;145&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-start=&quot;url(#dns-arrow)&quot; marker-end=&quot;url(#dns-arrow)&quot;/&gt;
&lt;text x=&quot;179&quot; y=&quot;135&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;1&lt;/text&gt;
&lt;text x=&quot;179&quot; y=&quot;168&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;5&lt;/text&gt;
&lt;line x1=&quot;350&quot; y1=&quot;130&quot; x2=&quot;448&quot; y2=&quot;45&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-start=&quot;url(#dns-arrow)&quot; marker-end=&quot;url(#dns-arrow)&quot;/&gt;
&lt;text x=&quot;386&quot; y=&quot;76&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;2&lt;/text&gt;
&lt;line x1=&quot;350&quot; y1=&quot;145&quot; x2=&quot;448&quot; y2=&quot;147&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-start=&quot;url(#dns-arrow)&quot; marker-end=&quot;url(#dns-arrow)&quot;/&gt;
&lt;text x=&quot;399&quot; y=&quot;136&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;3&lt;/text&gt;
&lt;line x1=&quot;350&quot; y1=&quot;160&quot; x2=&quot;448&quot; y2=&quot;249&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-start=&quot;url(#dns-arrow)&quot; marker-end=&quot;url(#dns-arrow)&quot;/&gt;
&lt;text x=&quot;386&quot; y=&quot;222&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;4&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;dns-caption&quot;&gt;The resolver goes through the root servers, then the .com servers, then the domain&#39;s name servers, and brings the address back to the browser.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ol&gt;
&lt;li&gt;Your browser asks the &lt;strong&gt;resolver&lt;/strong&gt;, usually from your internet provider or a public service such as &lt;code&gt;1.1.1.1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The resolver asks the &lt;strong&gt;root servers&lt;/strong&gt;, which point it to the &lt;code&gt;.com&lt;/code&gt; servers.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;.com&lt;/code&gt; servers point it to the domain&#39;s name servers.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;domain&#39;s name servers&lt;/strong&gt; give the final answer.&lt;/li&gt;
&lt;li&gt;The resolver returns the address to the browser and keeps it for the &lt;strong&gt;TTL&lt;/strong&gt;, so the next person asking gets an instant answer.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These are the terms you&#39;ll come across:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Domain&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;example.com&lt;/code&gt;: the name you own&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Subdomain&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;blog.example.com&lt;/code&gt;: a name under it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Registrar&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The company you buy the name from&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hosted zone&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The container holding a domain&#39;s records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Record&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One entry: a name pointing to a value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TTL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;How long a resolver may remember the answer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;route-53&quot; tabindex=&quot;-1&quot;&gt;Route 53 &lt;a class=&quot;heading-anchor&quot; href=&quot;#route-53&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Route 53&lt;/strong&gt; is AWS&#39;s DNS service, named after DNS&#39;s port 53. It has three jobs: holding your domain&#39;s records and answering for them, registering domains, and watching your application&#39;s health and directing visitors accordingly. AWS commits to 100% availability for it.&lt;/p&gt;
&lt;h3 id=&quot;hosted-zones&quot; tabindex=&quot;-1&quot;&gt;Hosted zones &lt;a class=&quot;heading-anchor&quot; href=&quot;#hosted-zones&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Answers whom&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Public&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Anyone on the internet&lt;/td&gt;
&lt;td&gt;&lt;code&gt;example.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Private&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only inside the VPCs you choose&lt;/td&gt;
&lt;td&gt;&lt;code&gt;db.series.internal&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each costs about half a dollar a month, plus a small charge for queries.&lt;/p&gt;
&lt;h3 id=&quot;record-types&quot; tabindex=&quot;-1&quot;&gt;Record types &lt;a class=&quot;heading-anchor&quot; href=&quot;#record-types&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Points to&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An IPv4 address&lt;/td&gt;
&lt;td&gt;&lt;code&gt;blog.example.com&lt;/code&gt; to &lt;code&gt;192.0.2.10&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AAAA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An IPv6 address&lt;/td&gt;
&lt;td&gt;&lt;code&gt;blog.example.com&lt;/code&gt; to &lt;code&gt;2001:db8::10&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CNAME&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Another name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;www.example.com&lt;/code&gt; to &lt;code&gt;example.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The domain&#39;s name servers&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ns-1.awsdns-01.org&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MX&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mail servers&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mail.example.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TXT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free text, such as proof of domain ownership&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v=spf1 ...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;cname-or-alias&quot; tabindex=&quot;-1&quot;&gt;CNAME or Alias? &lt;a class=&quot;heading-anchor&quot; href=&quot;#cname-or-alias&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here&#39;s a common problem: a CNAME can&#39;t be used on the root domain &lt;code&gt;example.com&lt;/code&gt;, yet you want it to point at your load balancer. The solution is an &lt;strong&gt;Alias&lt;/strong&gt;, a special type in Route 53:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;CNAME&lt;/th&gt;
&lt;th&gt;Alias&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Points to&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Any name&lt;/td&gt;
&lt;td&gt;AWS resources such as ALB, CloudFront and API Gateway&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Root domain&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not allowed&lt;/td&gt;
&lt;td&gt;Allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Queries&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Charged&lt;/td&gt;
&lt;td&gt;Free for AWS resources&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TTL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You set it&lt;/td&gt;
&lt;td&gt;Route 53 sets it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Target health&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not followed&lt;/td&gt;
&lt;td&gt;Can be followed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The rule is simple: if the target is on AWS, use an Alias. Note that it can&#39;t point to an EC2 server&#39;s DNS name.&lt;/p&gt;
&lt;h3 id=&quot;choosing-a-ttl&quot; tabindex=&quot;-1&quot;&gt;Choosing a TTL &lt;a class=&quot;heading-anchor&quot; href=&quot;#choosing-a-ttl&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A long TTL:&lt;/strong&gt; fewer queries and lower cost, but any change takes time to spread.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A short TTL:&lt;/strong&gt; changes spread quickly, but queries increase.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;callout callout-tip&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-bulb&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M9 18h6M10 21h4M12 3a6 6 0 0 0-3.5 10.9c.6.45 1 1.15 1 1.9V16h5v-.2c0-.75.4-1.45 1-1.9A6 6 0 0 0 12 3z&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Before any move&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If you&#39;re moving your site to another server, lower the TTL to 60 seconds a day beforehand. Make the move, confirm all is well, then raise it again.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;routing-policies&quot; tabindex=&quot;-1&quot;&gt;Routing policies &lt;a class=&quot;heading-anchor&quot; href=&quot;#routing-policies&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&amp;quot;Routing&amp;quot; here doesn&#39;t mean traffic passes through Route 53. It only chooses which answer to give, and the visitor then connects directly to that address.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Policy&lt;/th&gt;
&lt;th&gt;How it answers&lt;/th&gt;
&lt;th&gt;Common use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Simple&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One record, which can hold several values&lt;/td&gt;
&lt;td&gt;A single server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Weighted&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;By percentages you set&lt;/td&gt;
&lt;td&gt;Trying a new version on 10% of visitors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The Region with the lowest delay for the visitor&lt;/td&gt;
&lt;td&gt;An application in several Regions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Failover&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The primary while it&#39;s healthy, otherwise the secondary&lt;/td&gt;
&lt;td&gt;Disaster recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Geolocation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;By the visitor&#39;s country or continent&lt;/td&gt;
&lt;td&gt;Language or content by country&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Geoproximity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;By distance, with each site&#39;s reach grown or shrunk&lt;/td&gt;
&lt;td&gt;Gradually shifting traffic between areas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IP-based&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;By the visitor&#39;s IP range&lt;/td&gt;
&lt;td&gt;Networks you know about&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multivalue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Up to 8 healthy records&lt;/td&gt;
&lt;td&gt;Simple spreading, not a replacement for a load balancer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;aside class=&quot;callout callout-note&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-info&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;circle cx=&quot;12&quot; cy=&quot;12&quot; r=&quot;8.5&quot;/&gt;&lt;path d=&quot;M12 11v5M12 8h.01&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Nearest isn&#39;t always fastest&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Geolocation&lt;/strong&gt; chooses by where the visitor is, even if another site would be faster for them, so it suits legal and language needs. If your goal is speed, choose &lt;strong&gt;Latency&lt;/strong&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id=&quot;health-checks&quot; tabindex=&quot;-1&quot;&gt;Health checks &lt;a class=&quot;heading-anchor&quot; href=&quot;#health-checks&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For Failover and the others to work, Route 53 has to know who&#39;s healthy:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;How it checks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Endpoint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Checkers around the world request your address over HTTP, HTTPS or TCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Calculated&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Combines the results of several checks into one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CloudWatch alarm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Relies on an alarm, which is the solution for private resources&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The checkers come from the internet, so they can&#39;t reach a server in a private network, and your security group has to allow their ranges if you&#39;re checking a public target.&lt;/p&gt;
&lt;h2 id=&quot;a-domain-bought-elsewhere&quot; tabindex=&quot;-1&quot;&gt;A domain bought elsewhere &lt;a class=&quot;heading-anchor&quot; href=&quot;#a-domain-bought-elsewhere&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Buying a domain and managing its records are two separate things. If you bought yours from another company and want Route 53 to answer for it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a public &lt;strong&gt;hosted zone&lt;/strong&gt; with the domain&#39;s name.&lt;/li&gt;
&lt;li&gt;Copy the four name servers from its &lt;strong&gt;NS&lt;/strong&gt; record.&lt;/li&gt;
&lt;li&gt;Paste them into the domain&#39;s settings at the company you bought it from.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the change spreads, Route 53 is the one answering.&lt;/p&gt;
&lt;p&gt;If you have a network in your office, you can connect its DNS with AWS through &lt;strong&gt;Resolver endpoints&lt;/strong&gt;: inbound lets your network ask about AWS&#39;s private names, and outbound lets AWS ask about your network&#39;s names. This needs a connection between the two networks, which is the subject of &lt;a href=&quot;/en/posts/aws-14-vpc-connectivity/&quot;&gt;part fourteen&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;hands-on-weighted-routing-without-buying-a-domain&quot; tabindex=&quot;-1&quot;&gt;Hands-on: weighted routing without buying a domain &lt;a class=&quot;heading-anchor&quot; href=&quot;#hands-on-weighted-routing-without-buying-a-domain&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A private hosted zone lets you try all this without a real domain. We&#39;ll use your &lt;code&gt;web-1&lt;/code&gt; server from &lt;a href=&quot;/en/posts/aws-03-ec2-first-server/&quot;&gt;part three&lt;/a&gt;, inside the default network. From CloudShell, create the private domain:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;VPC_ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws ec2 describe-vpcs &lt;span class=&quot;token parameter variable&quot;&gt;--filters&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;isDefault,Values&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Vpcs[0].VpcId&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;ZONE_ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;aws route53 create-hosted-zone &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; series.internal &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --caller-reference &lt;span class=&quot;token string&quot;&gt;&quot;demo-&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt; +%s&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--vpc&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;VPCRegion&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;$AWS_REGION,VPCId&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;$VPC_ID &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; HostedZone.Id &lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Now add two records for the same name, 80% for the old version and 20% for the new. The addresses are made up, because DNS only answers and doesn&#39;t connect to them:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;CHANGES&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;{&quot;Changes&quot;:[
  {&quot;Action&quot;:&quot;CREATE&quot;,&quot;ResourceRecordSet&quot;:{&quot;Name&quot;:&quot;app.series.internal&quot;,&quot;Type&quot;:&quot;A&quot;,&quot;TTL&quot;:5,
    &quot;SetIdentifier&quot;:&quot;old&quot;,&quot;Weight&quot;:80,&quot;ResourceRecords&quot;:[{&quot;Value&quot;:&quot;10.0.0.80&quot;}]}},
  {&quot;Action&quot;:&quot;CREATE&quot;,&quot;ResourceRecordSet&quot;:{&quot;Name&quot;:&quot;app.series.internal&quot;,&quot;Type&quot;:&quot;A&quot;,&quot;TTL&quot;:5,
    &quot;SetIdentifier&quot;:&quot;new&quot;,&quot;Weight&quot;:20,&quot;ResourceRecords&quot;:[{&quot;Value&quot;:&quot;10.0.0.20&quot;}]}}
]}&#39;&lt;/span&gt;

aws route53 change-resource-record-sets &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --hosted-zone-id &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$ZONE_ID&lt;/span&gt;&quot;&lt;/span&gt; --change-batch &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$CHANGES&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;Sign in to the server through EC2 Instance Connect and ask 20 times. It takes two minutes, because we wait for the TTL to expire each time:&lt;/p&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dnf &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt; bind-utils

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token for-or-select variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;seq&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;dig&lt;/span&gt; +short app.series.internal
  &lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;uniq&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;You&#39;ll see a split close to 16 and 4. Try &lt;code&gt;dig +trace aws.amazon.com&lt;/code&gt; as well, and you&#39;ll see the chain from the diagram step by step.&lt;/p&gt;
&lt;p&gt;If you have a domain, add an &lt;strong&gt;A&lt;/strong&gt; record of the &lt;strong&gt;Alias&lt;/strong&gt; kind pointing at your load balancer, and your site now has your name.&lt;/p&gt;
&lt;aside class=&quot;callout callout-security&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-shield&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M12 3l7.5 3v5.5c0 4.6-3.2 8.3-7.5 9.5-4.3-1.2-7.5-4.9-7.5-9.5V6L12 3z&quot;/&gt;&lt;path d=&quot;M9 12l2 2 4-4&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Delete after experimenting&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A hosted zone deleted within 12 hours of creation isn&#39;t charged. You have to delete the records first, then the zone:&lt;/p&gt;
&lt;/aside&gt;
&lt;figure class=&quot;code-block&quot; dir=&quot;ltr&quot;&gt;
&lt;figcaption class=&quot;code-bar&quot;&gt;&lt;span class=&quot;code-lang&quot; lang=&quot;en&quot;&gt;Bash&lt;/span&gt;&lt;button type=&quot;button&quot; class=&quot;copy-btn&quot; data-copy hidden&gt;&lt;svg class=&quot;icon icon-copy&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;rect x=&quot;8.5&quot; y=&quot;8.5&quot; width=&quot;11.5&quot; height=&quot;11.5&quot; rx=&quot;2&quot;/&gt;&lt;path d=&quot;M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5&quot;/&gt;&lt;/svg&gt;&lt;svg class=&quot;icon icon-check&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M5 12.5l4.5 4.5L19 7.5&quot;/&gt;&lt;/svg&gt;&lt;span class=&quot;copy-label&quot;&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/figcaption&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;aws route53 change-resource-record-sets &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  --hosted-zone-id &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$ZONE_ID&lt;/span&gt;&quot;&lt;/span&gt; --change-batch &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;${CHANGES&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;CREATE&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;DELETE}&lt;/span&gt;&quot;&lt;/span&gt;

aws route53 delete-hosted-zone &lt;span class=&quot;token parameter variable&quot;&gt;--id&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$ZONE_ID&lt;/span&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DNS&lt;/strong&gt; turns a name into an address through a chain, and the answer is kept for the &lt;strong&gt;TTL&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Route 53&lt;/strong&gt; holds your records, and a hosted zone can be public or private.&lt;/li&gt;
&lt;li&gt;If the target is on AWS, use an &lt;strong&gt;Alias&lt;/strong&gt;, which works on the root domain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Routing policies&lt;/strong&gt; only choose the answer; traffic doesn&#39;t pass through them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Health checks&lt;/strong&gt; are what make Failover work.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 5&lt;/p&gt;
&lt;p&gt;A bakery&#39;s site runs behind an Application Load Balancer, and the owner wants anyone typing the bare domain &lt;code&gt;example.com&lt;/code&gt; to reach it. The load balancer&#39;s addresses can change at any time. Which record fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;A CNAME record on &lt;code&gt;example.com&lt;/code&gt;, pointing to the load balancer&#39;s name&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;An A record holding the load balancer&#39;s current addresses&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;A TXT record holding the load balancer&#39;s name&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;An A record of the Alias kind, pointing to the load balancer&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An Alias works on the root domain and follows the load balancer&#39;s changing addresses for you, and queries to AWS resources like this one are free.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; A CNAME isn&#39;t allowed on the root domain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; Once the addresses change, the record points to the wrong place.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; A TXT record holds free text, and browsers don&#39;t use it to find a server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#cname-or-alias&quot;&gt;CNAME or Alias?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-choosing-alias-non-alias.html&quot;&gt;Choosing between alias and non-alias records&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 5&lt;/p&gt;
&lt;p&gt;A streaming service runs in two Regions, Frankfurt and Bahrain. Its license requires visitors from Saudi Arabia to always get the Bahrain copy, even when Frankfurt would answer them faster. Which routing policy fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Geolocation&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Latency&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Weighted&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Multivalue&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Geolocation chooses by where the visitor is rather than by speed, which is what a licensing rule needs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This sends the visitor to the fastest Region, which could be Frankfurt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This splits traffic by percentages, whatever the visitor&#39;s country.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This returns several healthy records, with no regard for country.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#routing-policies&quot;&gt;Routing policies&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy-geo.html&quot;&gt;Geolocation routing&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 5&lt;/p&gt;
&lt;p&gt;An internal application uses a Failover record in a private hosted zone. Its primary servers have only private addresses, and must stay that way. How should Route 53 learn whether the primary is healthy?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;An endpoint health check on the servers&#39; private addresses&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Public addresses on the servers, for the checkers to reach&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;A health check based on a CloudWatch alarm watching the primary&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;A calculated health check combining endpoint checks on the servers&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Route 53&#39;s checkers come from the internet, so they can&#39;t reach a private address. A CloudWatch alarm can watch a metric from the servers, and the health check follows the alarm.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; The checkers are outside the network, and can&#39;t reach a private address.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This breaks the requirement that the servers stay private.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This only combines other checks, and those still can&#39;t reach the servers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#health-checks&quot;&gt;Health checks&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-failover-private-hosted-zones.html&quot;&gt;Configuring failover in a private hosted zone&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 5&lt;/p&gt;
&lt;p&gt;A startup bought its domain from another company and wants to keep the registration there, while Route 53 answers for the domain&#39;s records. What does it need to do?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Transfer the domain&#39;s registration to Route 53 first&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Create a public hosted zone, and put its name servers in the domain&#39;s settings at the registrar&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Create a private hosted zone, and associate the VPC with it&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Create an inbound Resolver endpoint in the VPC&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Buying a name and answering for it are separate things. Once the registrar lists Route 53&#39;s name servers, Route 53 is the one answering.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; A transfer is optional, and isn&#39;t needed to manage the records.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; A private zone only answers inside the VPCs you choose, not for the public.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This lets an office network ask about private names, and has nothing to do with public answers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#a-domain-bought-elsewhere&quot;&gt;A domain bought elsewhere&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/migrate-dns-domain-in-use.html&quot;&gt;Making Route 53 the DNS service for a domain that&#39;s in use&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 5&lt;/p&gt;
&lt;p&gt;A team wants to send 10% of visitors to a new version of its application, and to pull that traffic back within minutes if anything goes wrong. Which &lt;strong&gt;two&lt;/strong&gt; steps fit? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Create two Weighted records with the same name, weighted 90 and 10&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Create Geolocation records for one country&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Raise the records&#39; TTL to a full day before starting&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Put both versions&#39; addresses in one Simple record&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Use a short TTL on those records, such as 60 seconds&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Weighted records split the answers by the shares you set, and a short TTL means a change reaches visitors quickly, since resolvers only remember an answer for that long.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This chooses by place, not by a share of visitors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; Resolvers would keep the old answer for up to a day, so going back would be slow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; A Simple record gives you no way to set a share.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#routing-policies&quot;&gt;Routing policies&lt;/a&gt; and &lt;a href=&quot;#choosing-a-ttl&quot;&gt;Choosing a TTL&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy-weighted.html&quot;&gt;Weighted routing&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;Your site now has a name, but its server is still in one place and the distant visitor is still waiting. In &lt;a href=&quot;/en/posts/aws-12-cloudfront-global-accelerator/&quot;&gt;&lt;strong&gt;part twelve&lt;/strong&gt;&lt;/a&gt; we bring it closer with CloudFront and Global Accelerator.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Which Database Should You Choose?</title>
    <link href="https://blog.sultanops.com/en/posts/aws-10-choosing-database/"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <id>https://blog.sultanops.com/en/posts/aws-10-choosing-database/</id>
    <summary>Relational, key-value, document, graph, time series or search. What each kind is good for, how to choose among AWS&#39;s many databases with a few simple questions, and how a real application&#39;s data layer grows step by step.</summary>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;/en/posts/aws-08-rds-aurora/&quot;&gt;part eight&lt;/a&gt; and &lt;a href=&quot;/en/posts/aws-09-elasticache/&quot;&gt;part nine&lt;/a&gt; we covered RDS, Aurora and ElastiCache. But open the AWS menu and you&#39;ll find more than ten database services, and that&#39;s where people get lost.&lt;/p&gt;
&lt;p&gt;The right question isn&#39;t &amp;quot;what&#39;s the best database?&amp;quot;, because there&#39;s no single answer. The question is: &lt;strong&gt;what suits this particular data?&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;questions-to-start-with&quot; tabindex=&quot;-1&quot;&gt;Questions to start with &lt;a class=&quot;heading-anchor&quot; href=&quot;#questions-to-start-with&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before opening any service, answer these:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What shape is the data?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Linked tables, varied documents, relationships or readings over time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;How will you read it?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;By key, with complex queries joining tables, by searching text or by aggregating millions of rows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;How much reading versus writing?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Heavy reads can be solved with a cache and replicas; heavy writes need a different design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;How big, and how fast is it growing?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ordinary gigabytes, or data that grows without a ceiling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;How accurate must it be?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A money transfer needs strict transactions; a like count can tolerate delay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;How much can you manage?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A small team prefers a service that scales by itself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What does your team know?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Existing knowledge spares you many mistakes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;types-of-database&quot; tabindex=&quot;-1&quot;&gt;Types of database &lt;a class=&quot;heading-anchor&quot; href=&quot;#types-of-database&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Shape of the data&lt;/th&gt;
&lt;th&gt;AWS service&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Relational&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Linked tables and transactions&lt;/td&gt;
&lt;td&gt;RDS and Aurora&lt;/td&gt;
&lt;td&gt;Orders, accounts, invoices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Key-value&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A value fetched by its key, at huge scale&lt;/td&gt;
&lt;td&gt;DynamoDB&lt;/td&gt;
&lt;td&gt;Carts and user profiles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Document&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;JSON with varied fields&lt;/td&gt;
&lt;td&gt;DocumentDB and DynamoDB&lt;/td&gt;
&lt;td&gt;Catalogs and content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;In-memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fast data&lt;/td&gt;
&lt;td&gt;ElastiCache and MemoryDB&lt;/td&gt;
&lt;td&gt;Caching and sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wide-column&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cassandra-style rows with heavy writes&lt;/td&gt;
&lt;td&gt;Keyspaces&lt;/td&gt;
&lt;td&gt;Existing Cassandra systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Graph&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Connections between things&lt;/td&gt;
&lt;td&gt;Neptune&lt;/td&gt;
&lt;td&gt;Social networks and fraud detection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Time series&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Readings over time&lt;/td&gt;
&lt;td&gt;Timestream for InfluxDB&lt;/td&gt;
&lt;td&gt;Sensors and metrics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Search&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Text you search inside&lt;/td&gt;
&lt;td&gt;OpenSearch&lt;/td&gt;
&lt;td&gt;Site search and logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Analytics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Aggregation over huge data&lt;/td&gt;
&lt;td&gt;Redshift&lt;/td&gt;
&lt;td&gt;Management reports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Files&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Files of any kind&lt;/td&gt;
&lt;td&gt;S3 with Athena&lt;/td&gt;
&lt;td&gt;Logs and archives&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;relational-or-nosql&quot; tabindex=&quot;-1&quot;&gt;Relational or NoSQL? &lt;a class=&quot;heading-anchor&quot; href=&quot;#relational-or-nosql&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is the first decision, and the real difference is in how you think:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Relational (SQL)&lt;/th&gt;
&lt;th&gt;NoSQL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Design&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Design the tables, then write any query&lt;/td&gt;
&lt;td&gt;Define the queries first, then design around them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Queries&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Flexible, with table joins&lt;/td&gt;
&lt;td&gt;Limited, and fast along the path you designed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transactions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strong&lt;/td&gt;
&lt;td&gt;Varies by service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reads are easy; writes usually mean a bigger server&lt;/td&gt;
&lt;td&gt;Horizontal, with steady performance as it grows&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;aside class=&quot;callout callout-tip&quot;&gt;&lt;p class=&quot;callout-title&quot;&gt;&lt;svg class=&quot;icon icon-bulb&quot; viewBox=&quot;0 0 24 24&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.75&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M9 18h6M10 21h4M12 3a6 6 0 0 0-3.5 10.9c.6.45 1 1.15 1 1.9V16h5v-.2c0-.75.4-1.45 1-1.9A6 6 0 0 0 12 3z&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Start relational unless you have a reason&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Most applications suit a relational database, especially if you don&#39;t know all your queries from the start. Choose NoSQL for a clear reason, not just because it &amp;quot;scales&amp;quot;.&lt;/p&gt;
&lt;/aside&gt;
&lt;h3 id=&quot;services-youll-come-across&quot; tabindex=&quot;-1&quot;&gt;Services you&#39;ll come across &lt;a class=&quot;heading-anchor&quot; href=&quot;#services-youll-come-across&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DynamoDB:&lt;/strong&gt; serverless key-value with steady performance at any size. We cover it in &lt;a href=&quot;/en/posts/aws-21-lambda-api-dynamodb/&quot;&gt;part twenty-one&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DocumentDB:&lt;/strong&gt; documents compatible with MongoDB, which suits you if you&#39;re moving an existing MongoDB application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MemoryDB:&lt;/strong&gt; fast memory like Valkey but with durable data, so you can use it as a primary database and not just a cache.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keyspaces:&lt;/strong&gt; compatible with Apache Cassandra, with no servers to manage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Neptune:&lt;/strong&gt; for data whose value lies in relationships, such as &amp;quot;friends of my friends who bought this&amp;quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timestream for InfluxDB:&lt;/strong&gt; for sensor readings and metrics. The older LiveAnalytics edition is closed to new customers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenSearch:&lt;/strong&gt; text search and log analysis, usually a copy of your data rather than the main source.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redshift:&lt;/strong&gt; a data warehouse for huge reports. We cover it in &lt;a href=&quot;/en/posts/aws-23-athena-redshift-glue/&quot;&gt;part twenty-three&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-to-decide&quot; tabindex=&quot;-1&quot;&gt;How to decide &lt;a class=&quot;heading-anchor&quot; href=&quot;#how-to-decide&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Go through the questions from top to bottom, and the first &amp;quot;yes&amp;quot; is your starting point:&lt;/p&gt;
&lt;figure class=&quot;diagram&quot;&gt;
&lt;svg viewBox=&quot;0 0 640 406&quot; role=&quot;img&quot; aria-labelledby=&quot;choose-caption&quot;&gt;
&lt;defs&gt;
&lt;marker id=&quot;choose-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
&lt;path d=&quot;M0 0L10 5L0 10z&quot; fill=&quot;var(--color-accent)&quot;/&gt;
&lt;/marker&gt;
&lt;/defs&gt;
&lt;rect x=&quot;20&quot; y=&quot;10&quot; width=&quot;400&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;220&quot; y=&quot;34&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;A temporary copy to speed up reads?&lt;/text&gt;
&lt;rect x=&quot;480&quot; y=&quot;10&quot; width=&quot;140&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;550&quot; y=&quot;34&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;ElastiCache&lt;/text&gt;
&lt;line x1=&quot;420&quot; y1=&quot;29&quot; x2=&quot;478&quot; y2=&quot;29&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#choose-arrow)&quot;/&gt;
&lt;text x=&quot;449&quot; y=&quot;23&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Yes&lt;/text&gt;
&lt;line x1=&quot;220&quot; y1=&quot;48&quot; x2=&quot;220&quot; y2=&quot;66&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot;/&gt;
&lt;text x=&quot;238&quot; y=&quot;62&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;No&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;68&quot; width=&quot;400&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;220&quot; y=&quot;92&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Searching inside text or logs?&lt;/text&gt;
&lt;rect x=&quot;480&quot; y=&quot;68&quot; width=&quot;140&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;550&quot; y=&quot;92&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;OpenSearch&lt;/text&gt;
&lt;line x1=&quot;420&quot; y1=&quot;87&quot; x2=&quot;478&quot; y2=&quot;87&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#choose-arrow)&quot;/&gt;
&lt;text x=&quot;449&quot; y=&quot;81&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Yes&lt;/text&gt;
&lt;line x1=&quot;220&quot; y1=&quot;106&quot; x2=&quot;220&quot; y2=&quot;124&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot;/&gt;
&lt;text x=&quot;238&quot; y=&quot;120&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;No&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;126&quot; width=&quot;400&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;220&quot; y=&quot;150&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Reports across huge volumes of data?&lt;/text&gt;
&lt;rect x=&quot;480&quot; y=&quot;126&quot; width=&quot;140&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;550&quot; y=&quot;150&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Redshift, Athena&lt;/text&gt;
&lt;line x1=&quot;420&quot; y1=&quot;145&quot; x2=&quot;478&quot; y2=&quot;145&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#choose-arrow)&quot;/&gt;
&lt;text x=&quot;449&quot; y=&quot;139&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Yes&lt;/text&gt;
&lt;line x1=&quot;220&quot; y1=&quot;164&quot; x2=&quot;220&quot; y2=&quot;182&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot;/&gt;
&lt;text x=&quot;238&quot; y=&quot;178&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;No&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;184&quot; width=&quot;400&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;220&quot; y=&quot;208&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Is the value in links between things?&lt;/text&gt;
&lt;rect x=&quot;480&quot; y=&quot;184&quot; width=&quot;140&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;550&quot; y=&quot;208&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Neptune&lt;/text&gt;
&lt;line x1=&quot;420&quot; y1=&quot;203&quot; x2=&quot;478&quot; y2=&quot;203&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#choose-arrow)&quot;/&gt;
&lt;text x=&quot;449&quot; y=&quot;197&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Yes&lt;/text&gt;
&lt;line x1=&quot;220&quot; y1=&quot;222&quot; x2=&quot;220&quot; y2=&quot;240&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot;/&gt;
&lt;text x=&quot;238&quot; y=&quot;236&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;No&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;242&quot; width=&quot;400&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;220&quot; y=&quot;266&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Readings over time, from sensors say?&lt;/text&gt;
&lt;rect x=&quot;480&quot; y=&quot;242&quot; width=&quot;140&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;550&quot; y=&quot;266&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Timestream&lt;/text&gt;
&lt;line x1=&quot;420&quot; y1=&quot;261&quot; x2=&quot;478&quot; y2=&quot;261&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#choose-arrow)&quot;/&gt;
&lt;text x=&quot;449&quot; y=&quot;255&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Yes&lt;/text&gt;
&lt;line x1=&quot;220&quot; y1=&quot;280&quot; x2=&quot;220&quot; y2=&quot;298&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot;/&gt;
&lt;text x=&quot;238&quot; y=&quot;294&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;No&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;300&quot; width=&quot;400&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-surface)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;220&quot; y=&quot;324&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Simple key lookups at huge scale?&lt;/text&gt;
&lt;rect x=&quot;480&quot; y=&quot;300&quot; width=&quot;140&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-sunken)&quot; stroke=&quot;var(--color-line-strong)&quot;/&gt;
&lt;text x=&quot;550&quot; y=&quot;324&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;DynamoDB&lt;/text&gt;
&lt;line x1=&quot;420&quot; y1=&quot;319&quot; x2=&quot;478&quot; y2=&quot;319&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#choose-arrow)&quot;/&gt;
&lt;text x=&quot;449&quot; y=&quot;313&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;Yes&lt;/text&gt;
&lt;line x1=&quot;220&quot; y1=&quot;338&quot; x2=&quot;220&quot; y2=&quot;356&quot; stroke=&quot;var(--color-line-strong)&quot; stroke-width=&quot;2&quot;/&gt;
&lt;text x=&quot;238&quot; y=&quot;352&quot; text-anchor=&quot;middle&quot; class=&quot;d-small&quot;&gt;No&lt;/text&gt;
&lt;rect x=&quot;20&quot; y=&quot;358&quot; width=&quot;400&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;220&quot; y=&quot;382&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;Ordinary application data&lt;/text&gt;
&lt;rect x=&quot;480&quot; y=&quot;358&quot; width=&quot;140&quot; height=&quot;38&quot; rx=&quot;8&quot; fill=&quot;var(--color-accent-soft)&quot; stroke=&quot;var(--color-accent)&quot;/&gt;
&lt;text x=&quot;550&quot; y=&quot;382&quot; text-anchor=&quot;middle&quot; class=&quot;d-label&quot;&gt;RDS, Aurora&lt;/text&gt;
&lt;line x1=&quot;420&quot; y1=&quot;377&quot; x2=&quot;478&quot; y2=&quot;377&quot; stroke=&quot;var(--color-accent)&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#choose-arrow)&quot;/&gt;
&lt;/svg&gt;
&lt;figcaption id=&quot;choose-caption&quot;&gt;Start at the top: each &quot;yes&quot; gives you a service to begin with, and if nothing applies, a relational database is the default.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This is a starting guide, not a law. One application usually uses more than one type, with each kind of data going where it fits.&lt;/p&gt;
&lt;h2 id=&quot;a-data-layer-that-grows-with-your-application&quot; tabindex=&quot;-1&quot;&gt;A data layer that grows with your application &lt;a class=&quot;heading-anchor&quot; href=&quot;#a-data-layer-that-grows-with-your-application&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You don&#39;t need all this from day one. Imagine an online store growing over time:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Launch:&lt;/strong&gt; a single RDS database is enough. Once you take real orders, turn on &lt;strong&gt;Multi-AZ&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More visitors, heavier reads:&lt;/strong&gt; add &lt;strong&gt;ElastiCache&lt;/strong&gt; for main pages and sessions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reports start slowing the site:&lt;/strong&gt; send them to a &lt;strong&gt;read replica&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Product search is weak:&lt;/strong&gt; add &lt;strong&gt;OpenSearch&lt;/strong&gt; and fill it from the database.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Management wants years of analysis:&lt;/strong&gt; move the data to &lt;strong&gt;S3 with Athena&lt;/strong&gt; or &lt;strong&gt;Redshift&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visitors from around the world:&lt;/strong&gt; move to &lt;strong&gt;Aurora Global Database&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each step came after a real problem you measured, not before it. Every extra service means more cost, more complexity and one more thing that can fail.&lt;/p&gt;
&lt;h3 id=&quot;common-mistakes&quot; tabindex=&quot;-1&quot;&gt;Common mistakes &lt;a class=&quot;heading-anchor&quot; href=&quot;#common-mistakes&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Choosing NoSQL because it &amp;quot;scales&amp;quot;:&lt;/strong&gt; then discovering you need queries you didn&#39;t design for.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Running reports on the production database:&lt;/strong&gt; one heavy query slows the whole site.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storing files inside the database:&lt;/strong&gt; put them in S3 and keep the link in the database.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Treating the cache as a source of truth:&lt;/strong&gt; if it&#39;s lost, nothing important should go with it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-AZ in development:&lt;/strong&gt; double the cost, usually for no benefit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary &lt;a class=&quot;heading-anchor&quot; href=&quot;#summary&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Ask about the &lt;strong&gt;shape of the data and how you&#39;ll read it&lt;/strong&gt; before any service name.&lt;/li&gt;
&lt;li&gt;Start &lt;strong&gt;relational&lt;/strong&gt; unless you have a clear reason not to.&lt;/li&gt;
&lt;li&gt;One application uses more than one type, with each kind of data going where it fits.&lt;/li&gt;
&lt;li&gt;Add each service when you &lt;strong&gt;measure a real problem&lt;/strong&gt;, not before.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;test-yourself&quot; tabindex=&quot;-1&quot;&gt;Test yourself &lt;a class=&quot;heading-anchor&quot; href=&quot;#test-yourself&quot; aria-hidden=&quot;true&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p class=&quot;quiz-intro&quot;&gt;Before you move on, try these questions to check you&#39;ve got this part. Each one is a practical scenario, and the explanation appears once you answer.&lt;/p&gt;
&lt;div class=&quot;quiz-deck&quot; data-quiz-deck data-next=&quot;Next&quot; data-previous=&quot;Previous&quot; data-finish=&quot;See your score&quot; data-right=&quot;Correct&quot; data-wrong=&quot;Not quite&quot; data-score=&quot;Your score: {score} of {total}&quot; data-retry=&quot;Try again&quot;&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 1 of 5&lt;/p&gt;
&lt;p&gt;A clinic is building a booking system with appointments, patients and payments. The data is linked, payments need strict transactions, and the small team doesn&#39;t yet know all the reports it will need. Where should it start?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;DynamoDB, because it scales without limit&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;RDS or Aurora, with a relational schema&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;ElastiCache, because memory is the fastest&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Neptune, because the data has relationships&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Linked data, transactions and queries you can&#39;t fully predict all point to a relational database. It&#39;s the sensible default unless there&#39;s a clear reason otherwise.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; You&#39;d design around known queries up front, and new reports would be hard to add.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; A cache isn&#39;t a source of truth, so it can&#39;t be where payments live.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; Neptune suits deep webs of connections, not ordinary linked tables.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#relational-or-nosql&quot;&gt;Relational or NoSQL?&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/decision-guides/latest/databases-on-aws-how-to-choose/databases-on-aws-how-to-choose.html&quot;&gt;Choosing an AWS database service&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 2 of 5&lt;/p&gt;
&lt;p&gt;A social app wants to suggest &amp;quot;people you may know&amp;quot; by following friends of friends across several hops, with fast responses. Which service fits best?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;RDS, with a table join for each hop&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;ElastiCache, with a list for each user&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Timestream for InfluxDB&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Amazon Neptune&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The value here is in the relationships themselves, and Neptune is built to walk through large numbers of them with low latency.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This works for one or two hops, but joins get heavy as the hops increase.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; You could store ready-made lists, but something still has to work them out.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This is for readings over time, and has nothing to do with relationships.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#services-youll-come-across&quot;&gt;Services you&#39;ll come across&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/decision-guides/latest/databases-on-aws-how-to-choose/databases-on-aws-how-to-choose.html&quot;&gt;Choosing an AWS database service&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 3 of 5&lt;/p&gt;
&lt;p&gt;Ten thousand sensors send a temperature reading every minute, and engineers want hourly averages for each sensor over the last week. Which service was built for this?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Timestream for InfluxDB&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Amazon Neptune&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Amazon DocumentDB&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Amazon OpenSearch Service&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;A&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;These are readings over time, which is what a time series database is built to store and aggregate.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This is for connections between things.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; This is for JSON documents with varied fields.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This is mainly for searching text and analyzing logs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#types-of-database&quot;&gt;Types of database&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/timestream/latest/developerguide/timestream-for-influxdb.html&quot;&gt;What is Timestream for InfluxDB?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;1&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 4 of 5&lt;/p&gt;
&lt;p&gt;A company wants to move an existing MongoDB application to a managed AWS service with the &lt;strong&gt;fewest code changes&lt;/strong&gt;. Which service fits?&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Amazon DynamoDB&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Amazon Keyspaces&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Amazon DocumentDB&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Amazon Aurora&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;C&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;DocumentDB is compatible with MongoDB, so the application&#39;s document model and much of its code can stay as they are.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; This has a different API and data model, so the data access code would be rewritten.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B:&lt;/strong&gt; This is compatible with Cassandra, not MongoDB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; This is relational, so the documents would need redesigning as tables.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#services-youll-come-across&quot;&gt;Services you&#39;ll come across&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/documentdb/latest/developerguide/what-is.html&quot;&gt;What is Amazon DocumentDB?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;section class=&quot;quiz&quot; data-quiz data-pick=&quot;2&quot; tabindex=&quot;-1&quot;&gt;
&lt;p class=&quot;quiz-number&quot;&gt;Question 5 of 5&lt;/p&gt;
&lt;p&gt;A sales team wants reports across five years of orders, which means billions of rows, and the queries must not slow down the production database. Which &lt;strong&gt;two&lt;/strong&gt; approaches fit? (Choose two.)&lt;/p&gt;
&lt;ul class=&quot;quiz-options&quot;&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;A&lt;/span&gt;&lt;span&gt;Run the reports on the production database at night&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;B&lt;/span&gt;&lt;span&gt;Load the data into Amazon Redshift&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;C&lt;/span&gt;&lt;span&gt;Store the orders in ElastiCache&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;D&lt;/span&gt;&lt;span&gt;Run the reports on the Multi-AZ standby&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;button type=&quot;button&quot; class=&quot;quiz-option&quot; data-correct disabled&gt;&lt;span class=&quot;quiz-letter&quot; lang=&quot;en&quot;&gt;E&lt;/span&gt;&lt;span&gt;Export the data to S3, and query it with Athena&lt;/span&gt;&lt;/button&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;quiz-result&quot; role=&quot;status&quot;&gt;&lt;/p&gt;
&lt;details class=&quot;quiz-answer&quot;&gt;&lt;summary&gt;Show the answer&lt;/summary&gt;
&lt;p class=&quot;quiz-correct&quot;&gt;Correct answer: &lt;strong lang=&quot;en&quot;&gt;B + E&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Both move heavy analysis away from production. Redshift suits frequent, heavy reports, and Athena suits occasional questions without any servers to run.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A:&lt;/strong&gt; One heavy query can still hurt anything else running then, and it&#39;s a relational database that isn&#39;t built for this scale of analysis.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C:&lt;/strong&gt; A cache is a temporary copy, and far too small and costly for five years of data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D:&lt;/strong&gt; The standby in a Multi-AZ instance can&#39;t be read from.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Review: &lt;a href=&quot;#common-mistakes&quot;&gt;Common mistakes&lt;/a&gt; in this part, and &lt;a href=&quot;https://docs.aws.amazon.com/athena/latest/ug/what-is.html&quot;&gt;What is Amazon Athena?&lt;/a&gt; in the AWS docs.&lt;/p&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;That completes the databases section. Your application now runs, scales and keeps its data safe, but how do visitors reach it by your site&#39;s name? That&#39;s the next section&#39;s subject, starting in &lt;a href=&quot;/en/posts/aws-11-dns-route53/&quot;&gt;&lt;strong&gt;part eleven&lt;/strong&gt;&lt;/a&gt; with DNS and Route 53.&lt;/p&gt;
</content>
  </entry>
</feed>
