<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Rishi</title>
    <description>The latest articles on Forem by Rishi (@rishi123).</description>
    <link>https://forem.com/rishi123</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2815367%2Fe0f6fad6-212e-4a62-8376-8b56cc04b325.png</url>
      <title>Forem: Rishi</title>
      <link>https://forem.com/rishi123</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rishi123"/>
    <language>en</language>
    <item>
      <title>Complete Guide to AWS KMS: Encryption, Key Management &amp; Serverless Projects</title>
      <dc:creator>Rishi</dc:creator>
      <pubDate>Mon, 07 Jul 2025 05:51:56 +0000</pubDate>
      <link>https://forem.com/aws-builders/complete-guide-to-aws-kms-encryption-key-management-serverless-projects-37ce</link>
      <guid>https://forem.com/aws-builders/complete-guide-to-aws-kms-encryption-key-management-serverless-projects-37ce</guid>
      <description>&lt;p&gt;AWS Key Management Service (KMS) is used to create, manage, and audit cryptographic keys. In this hands-on course, we'll break down core KMS concepts and implement two mini projects to bring theory into practice.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/gMB-NKNilQU"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow the mini-projects confidently, you should know how to build a basic serverless CRUD app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=AmjPN3dWt1E" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=AmjPN3dWt1E&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=KoY6fS77pDc" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=KoY6fS77pDc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Course Structure – What Will You Learn? 🌿
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Encryption Fundamentals&lt;br&gt;
What is encryption, and types of encryption?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;KMS Key Types&lt;br&gt;
KMS keys are categorized based on structure (symmetric/asymmetric) and ownership (AWS-owned, AWS-managed, customer-managed).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Envelope Encryption&lt;br&gt;
What is envelope encryption, and why is it essential for &lt;a href="https://dev.to/aws-builders/aws-kms-deep-dive-the-mystery-of-envelope-encryption-2lc8"&gt;scalable secure storage&lt;/a&gt;? &lt;br&gt;
How is envelope encryption used with AWS customer-managed symmetric keys?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;KMS Access Control &amp;amp; Service Integration&lt;br&gt;
How KMS integrates with AWS services like S3, Lambda, and Secrets Manager.&lt;br&gt;&lt;br&gt;
How to control access using IAM policies, key policy, and grants.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Key Rotation &amp;amp; Auditing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mini Projects &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔐Password Manager – Encrypt and store credentials in DynamoDB using KMS
&lt;/li&gt;
&lt;li&gt;🔑JWT Auth Server – Use KMS asymmetric keys to sign and verify JWTs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>kms</category>
    </item>
    <item>
      <title>Chatlings🐾 AI Moderated Serverless Chat App For Kids!🌿</title>
      <dc:creator>Rishi</dc:creator>
      <pubDate>Tue, 01 Jul 2025 14:33:41 +0000</pubDate>
      <link>https://forem.com/aws-builders/chatlings-ai-moderated-serverless-chat-app-for-kids-15lp</link>
      <guid>https://forem.com/aws-builders/chatlings-ai-moderated-serverless-chat-app-for-kids-15lp</guid>
      <description>&lt;p&gt;Chatlings 🐾 is a serverless, real-time chat platform designed for children aged 8–14. It ensures content safety using AI moderation and a delightful, kid-friendly design.&lt;/p&gt;

&lt;p&gt;Just like ducklings 🦆 follow their guide while learning to explore the world, Chatlings helps young users explore digital conversations safely and responsibly.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/40b4k37BM9M"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨ Key Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;💬 Real-time Group Chat&lt;/strong&gt;&lt;br&gt;
Users can create or join public or private groups. Seamless text and image messages using WebSocket and serverless architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧠 Smart Moderation with AI&lt;/strong&gt;&lt;br&gt;
All text messages are moderated by Amazon Bedrock's Nova model for abuse and toxic language. Using AWS Rekognition, uploaded images are scanned for safety, instantly blocking unsafe or adult content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🤖 AskBot The Friendly Chat Assistant&lt;/strong&gt;&lt;br&gt;
Got a question or stuck on something? Just tag @askbot in your group chat. AskBot uses the latest AWS Nova model to help kids solve doubts safely and quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chatlings🐾 Architecture
&lt;/h2&gt;

&lt;p&gt;Chatlings is a serverless app built using:-&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Lambda, DynamoDB, S3, Bedrock, Rekognition and API Gateway for backend.&lt;/li&gt;
&lt;li&gt;Cognito userpool and Lambda authorizer for authentication.&lt;/li&gt;
&lt;li&gt;React, Zustand and other frontend tools for delightful interface.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The application is exposed using CloudFront CDN. The default CDN behaviour points to the React frontend. React app redirects the user to the Cognito login page, and after successful OAuth2.0 login flow, getSignedCookies API call happens to get CloudFront signed cookies. These cookies are used to access images handled by “/media*” behaviour.&lt;/p&gt;

&lt;p&gt;After that app loads and websocket connection ($connect) is established. ACCESS_TOKEN verification is done in the same step with the help of Lambda authorizer. Then, depending on user interaction, action messages are sent to the Websockets API gateway, and processing happens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Create/Join Group action&lt;/strong&gt;&lt;br&gt;
When any user creates a group, the lambda function is triggered, and group metadata is stored in DynamoDB. On join group action, groupCode is verified and records are created.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Text Message Moderation&lt;/strong&gt;&lt;br&gt;
When user sends message using sendMessage action, first of all, lambda verifies if user belongs to the group. After that, message is stored in DynamoDB and user receives immediate feedback.&lt;/p&gt;

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

&lt;p&gt;Then DynamoDB stream triggers another lambda that looks for new INSERT message operations and uses Bedrock Nova model to moderate the message. If the message is toxic, content is removed from DynamoDB. The same lambda function notifies all active connections (that are part of this group) about this message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Image Message Moderation&lt;/strong&gt;&lt;br&gt;
User triggers generateS3PreSignedURL action and uploads image file to S3. File upload to S3 triggers the imageAnalyzer Lambda function that uses Rekognition to verify image content. If the image is not suitable for kids, it is deleted immediately and only flag is stored in DynamoDB. Else, image URL is stored in DynamoDB.&lt;/p&gt;

&lt;p&gt;INSERT operation in DynamoDB table again triggers messageAnalyzer lambda, but it sends notification only for image files.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;4. CloudFront Signed Cookies&lt;/strong&gt;&lt;br&gt;
Access to image files is restricted with the help of CloudFront signed cookies that were created just after successful login.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. AskBot AI Assistant&lt;/strong&gt;&lt;br&gt;
When user mentions @askbot in the message, the askbot route is triggered, which calls Nova model to answer the question. Both user’s query and model’s response are stored in DynamoDB table. Again, the INSERT operation triggers moderation followed by notification of both messages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. DynamoDB Single Table Design&lt;/strong&gt;&lt;br&gt;
All data is stored in a single DynamoDB table that is designed keeping access pattern in mind instead of the structure of the data. Table schema is as follows:-&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Chatlings🐾 helps kids interact with friends while staying protected by cutting-edge AI moderation. All of this is powered by a fully serverless, event-driven architecture built on AWS.&lt;/p&gt;

&lt;p&gt;GitHub:- &lt;a href="https://github.com/TrickSumo/Chatlings" rel="noopener noreferrer"&gt;https://github.com/TrickSumo/Chatlings&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading, hope you enjoyed, Thanks 🌿&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Creating Fruit Tetris🍎Using Amazon Q Developer CLI</title>
      <dc:creator>Rishi</dc:creator>
      <pubDate>Sat, 14 Jun 2025 09:21:58 +0000</pubDate>
      <link>https://forem.com/rishi123/creating-fruit-tetrisusing-amazon-q-developer-cli-36a4</link>
      <guid>https://forem.com/rishi123/creating-fruit-tetrisusing-amazon-q-developer-cli-36a4</guid>
      <description>&lt;p&gt;This weekend I'm having fun with Amazon Q CLI. Using Q CLI, created this game called Fruit Tetris (one of first ever games that I played eons ago on a flip-flop mobile probably running on Symbian Java).&lt;/p&gt;

&lt;p&gt;It took me more time to install CLI itself than to create this awesome 2D game. Before we dive into the instructions, let's play the game. Use the up/down/arrow key to control, move and rotate the blocks.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/tricksumo/embed/NPqzvbL?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Amazon Q CLI
&lt;/h2&gt;

&lt;p&gt;There are already great tutorials available for &lt;a href="https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-installing.html" rel="noopener noreferrer"&gt;Linux&lt;/a&gt; and &lt;a href="https://community.aws/content/2v5PptEEYT2y0lRmZbFQtECA66M/the-essential-guide-to-installing-amazon-q-developer-cli-on-windows?lang=en" rel="noopener noreferrer"&gt;Windows&lt;/a&gt;, so I will not reiterate here. Make sure "Virtualization" is enabled in your computer (that is something you can look for in the boot menu settings) and just follow the instructions, it is easy peasy 🫛&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Create The Game
&lt;/h2&gt;

&lt;p&gt;Once Q CLI is installed and login is done, run "q chat" command (restart the terminal if "q" command is not recognized).&lt;/p&gt;

&lt;p&gt;Give instructions for your favorite game that you want to create and it will be ready within minutes! Reiterate, add, and improve after that🚀&lt;/p&gt;

&lt;p&gt;Here are the instructions that I gave:-&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I want to create a Tetris game where blocks are fruits, and when 3 fruits are accumulated, they are destroyed.&lt;/li&gt;
&lt;li&gt;Each block should be made of the same fruits. Also, blocks should be destroyed only when 6 fruits are the same.&lt;/li&gt;
&lt;li&gt;There is some bug... fruits are disappearing even if 6 are not touching each other. Even if the overall count is 6, fruits are being destroyed.&lt;/li&gt;
&lt;li&gt;Is it possible to support controls for Android?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should also try it out, it is fun😃&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Spring Pokédex - Explore! Identify! Appreciate!</title>
      <dc:creator>Rishi</dc:creator>
      <pubDate>Fri, 06 Jun 2025 14:24:07 +0000</pubDate>
      <link>https://forem.com/aws-builders/spring-pokedex-explore-identify-appreciate-4o7h</link>
      <guid>https://forem.com/aws-builders/spring-pokedex-explore-identify-appreciate-4o7h</guid>
      <description>&lt;p&gt;Spring is the season of nature’s greenery, blooming flowers, and buzzing insects. There are millions and trillions of species of flora and fauna. Often, we come across something mesmerizing but don’t know what it is!&lt;/p&gt;

&lt;p&gt;To solve this mystery, Spring Pokédex comes to the rescue. This blog post dives into how the Spring Pokédex works and the architecture behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  UX Workflow - A Magical Experience 🌿
&lt;/h2&gt;

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

&lt;p&gt;Ashley, a budding AWS engineer, went to the park on a beautiful spring day. While strolling around, she noticed a reddish-pink flower with a unique, shooting fragrance. She had never seen this flower and wondered what is the name of this species. Suddenly, she recalled that her friend Brock had once mentioned that an app named Spring Pokédex is handy in these situations.&lt;/p&gt;

&lt;p&gt;She quickly opened the application, created an account, and logged in without any issues. Thanks to &lt;strong&gt;AWS Cognito&lt;/strong&gt; for handling user management.&lt;/p&gt;

&lt;p&gt;After that, she clicked on the “Scan Now” button and took a photo of the plant. The image started uploading and a notification confirmed the successful upload. A short while later, a notification popped up: “Creature Identified!”. Ashley screamed with joy! As she tapped the notification, the screen displayed &lt;strong&gt;&lt;em&gt;🌸Frangipani (Plumeria)&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Behind the scenes, the image was securely uploaded using &lt;strong&gt;S3-Presigned URLs&lt;/strong&gt;, and a real-time notification system (powered by &lt;strong&gt;Momento Topics&lt;/strong&gt;) awaited the results.&lt;/p&gt;

&lt;p&gt;She clicked on the “Share” button and a unique shareable link was generated (powered by &lt;strong&gt;Momento Cache&lt;/strong&gt;) which she quickly sent to Brock.&lt;/p&gt;

&lt;p&gt;Later that day, after reaching home, Ashley thought “What if other users could access the images she uploaded? 🤔”. Curious, she opened her laptop and tried to access the image she uploaded but this time as another user. To her surprise, it did not work, access was denied!&lt;br&gt;
Why? Because access to files has been protected using &lt;strong&gt;CloudFront signed cookies&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Ashley was seriously impressed. Her curiosity sparked, and she wanted to dive deeper into the architecture behind the application. She wondered if any documentation was available online — and luckily, there was.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spring Pokédex Architecture: High-Lvl Overview 🔮
&lt;/h2&gt;

&lt;p&gt;Let’s see what really powers the magic of Spring Pokédex🪄&lt;/p&gt;

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

&lt;p&gt;Bit Scary, isn’t it? Well, let us break it down into small workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. CloudFront CDN And Its Behaviours
&lt;/h2&gt;

&lt;p&gt;The application is delivered through AWS CloudFront distribution. And it has 3 behaviors pointing to 3 different origins.&lt;/p&gt;

&lt;p&gt;The first behaviour matches “/api*” in the URL and points to the AWS API gateway (protected by Cognito authorizer).&lt;/p&gt;

&lt;p&gt;The second behaviour looks for the path pattern “/images” and points to the “images” folder of the application bucket. This behaviour restricts view access using signedCookies and signedURLs.&lt;/p&gt;

&lt;p&gt;If none of the above behaviour match, the default behaviour serves the React application from the “dist” folder of the S3 bucket (using origin access identity OAI).&lt;/p&gt;

&lt;h2&gt;
  
  
  2. What Happens When App Loads?
&lt;/h2&gt;

&lt;p&gt;If the user is not authenticated, redirection happens to Cognito managed login. After successful authentication, the user is redirected to the callback URL of the application with &lt;em&gt;authorization_code&lt;/em&gt; that is used to request ACCESS_TOKEN (as part of the oAuth2.0 protocol).&lt;/p&gt;

&lt;p&gt;After that, a request to “&lt;em&gt;/api/getSignedCookies&lt;/em&gt;” is made to get CloudFront signed cookies for “/images/cognitoUserId/*” folder of S3, ie. users can access images uploaded by them only.&lt;/p&gt;

&lt;p&gt;Also, a request is made to “&lt;em&gt;/api/getDisposableToken&lt;/em&gt;” endpoint to get the Momento disposable token. Lambda function with valid Momento credentials sits behind the API and acts as a disposable token vending machine.&lt;/p&gt;

&lt;p&gt;Momento token contains view-only scopes for Momento Topic named “pubsub-cache:cogintoUserId” and cache named “shared-cache”. Frontend uses the Momento disposable token to subscribe to the topic.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Discover Nature - One Scan At A Time!
&lt;/h2&gt;

&lt;p&gt;The user clicks on the “Scan Now” button and selects (captures using the camera) an image to upload. Frontend makes a request to “&lt;em&gt;/api/getSignedURL&lt;/em&gt;” endpoint to get signedURL and upload the image. Once the image is uploaded, frontend reflects the status as “Processing” and waits for a status update message on the Momento topic.&lt;/p&gt;

&lt;p&gt;The image is uploaded to AWS S3 as “/images/cognito-user-id/image.png” and triggers the SpringScanner AWS Lambda function. The Lambda function generates a CloudFront signed URL for the image and calls OpenAI API using it.&lt;/p&gt;

&lt;p&gt;On success, lambda stores data in the DynamoDB table and also publishes a success message to the Momento topic. On failure or crash of lambda function, the event goes to SQS queue (Dead-Letter Queue) and triggers DLQ handler lambda function that publishes failure message to the topic.&lt;/p&gt;

&lt;p&gt;Frontend listens for these messages and shows details to the user in realtime. Mometo topic helps to achieve this without having any websockets connection.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  4. Check History Or Share Your Discovery
&lt;/h2&gt;

&lt;p&gt;At the time of the scan, data is stored in a &lt;strong&gt;DynamoDB&lt;/strong&gt; table where userId is the partition key and S3ObjectKey is the sort key. History of scans for a user can be fetched by querying dynamo table using userId (/scanHistory endpoint).&lt;/p&gt;

&lt;p&gt;When the user decides to share the scan with someone, api call to “/shareScan” endpoint is made. Using the userId from lambda event and scanId received as part of API payload, a DynamoDB call retrieves the scan details.&lt;/p&gt;

&lt;p&gt;Since image access is allowed only for the original uploader, the imageUrl can’t be shared directly. To solve this, a CloudFront signed URL is generated with a validity of 24 hours.&lt;/p&gt;

&lt;p&gt;This signed URL and the scan details are stored in a &lt;strong&gt;Momento cache&lt;/strong&gt; with a unique identifier. That identifier becomes part of the shareable URL. Both the cache entry and the signed URL have a TTL of 24 hours, so the shared scan remains accessible to others for one day only.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Rate Limiting The Scans
&lt;/h2&gt;

&lt;p&gt;Momento cache is also used to limit how many scan operations a user can perform in a single day.&lt;/p&gt;

&lt;p&gt;For each user, a cache key like “&lt;em&gt;userid-date-today&lt;/em&gt;” is created, and its value is incremented with every image upload (this logic is integrated into the getSignedURL Lambda function).&lt;/p&gt;

&lt;p&gt;Once the max threshold is reached, the API returns a 429 Too Many Requests, and the frontend blocks further uploads.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Securing The Secrets
&lt;/h2&gt;

&lt;p&gt;The Lambda functions use sensitive credentials like the Momento API key, OpenAI API key, and the CloudFront private key. These secrets should never be stored directly in code.&lt;/p&gt;

&lt;p&gt;One option is to store them in Lambda environment variables and encrypt them using a KMS customer-managed key for additional security. But a more secure and flexible approach is to store secrets in AWS SSM Parameter Store or AWS Secrets Manager.&lt;/p&gt;

&lt;p&gt;To simplify secret access in Lambda, &lt;strong&gt;middy middleware&lt;/strong&gt; is used. Middy helps to inject secrets from SSM or Secrets Manager into function’s context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🐼 Final Thoughts&lt;/strong&gt;&lt;br&gt;
Ashley closed her laptop with a smile. What started as a simple curiosity in the park turned into a deep dive into modern serverless event-driven architecture.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Jr84n3bz0Ps"&gt;
  &lt;/iframe&gt;
&lt;br&gt;
GitHub:- &lt;a href="https://github.com/TrickSumo/Spring-Pokedex" rel="noopener noreferrer"&gt;https://github.com/TrickSumo/Spring-Pokedex&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading, and I hope you enjoyed Spring Pokédex project 🌱&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>eventdriven</category>
      <category>aws</category>
    </item>
    <item>
      <title>AWS Serverless CRUD App Tutorial Using Lambda, API Gateway, DynamoDB, Cognito and Cloudfront CDN</title>
      <dc:creator>Rishi</dc:creator>
      <pubDate>Tue, 08 Apr 2025 14:40:16 +0000</pubDate>
      <link>https://forem.com/aws-builders/aws-serverless-crud-app-tutorial-using-lambda-api-gateway-dynamodb-cognito-and-cloudfront-cdn-139</link>
      <guid>https://forem.com/aws-builders/aws-serverless-crud-app-tutorial-using-lambda-api-gateway-dynamodb-cognito-and-cloudfront-cdn-139</guid>
      <description>&lt;p&gt;In this tutorial, we will use AWS services to create a serverless application for a coffee shop. The user (coffee shop owner in this case) can authenticate using AWS Cognito and manage inventory (perform CRUD operations).&lt;/p&gt;

&lt;p&gt;Github Repo: &lt;a href="https://github.com/TrickSumo/AWS-CRUD-Serverless" rel="noopener noreferrer"&gt;https://github.com/TrickSumo/AWS-CRUD-Serverless&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/KoY6fS77pDc"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

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

&lt;p&gt;We will use DynamoDB to store data and lambda functions (with lambda layer) to process API gateway requests. API gateway will be secured by Cognito and exposed with the help of Cloudfront CDN. React frontend will also be configured with Cognito UserPool and hosted on S3 and Cloudfront.&lt;/p&gt;

&lt;p&gt;Optionally, Cloudflare and AWS Certificate Manager can be used to add a custom domain to Cloudront distribution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 – Create DynamoDB Table
&lt;/h2&gt;

&lt;p&gt;Head over to the AWS console and navigate to the DynamoDB section. Then create a new table with table name as “CoffeeShop” and partiton key as “coffeeId”.&lt;/p&gt;

&lt;p&gt;Create a new item (coffee) in the table and fill attributes like coffeeId, name, price, and availability. It will be helpful to test connectivity to DynamoDB.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;{&lt;br&gt;
    "coffeeId": "c123",&lt;br&gt;
    "name": "new cold coffee",&lt;br&gt;
    "price": 456,&lt;br&gt;
    "available": true&lt;br&gt;
}&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 2 – Create IAM Role For Lambda Function
&lt;/h2&gt;

&lt;p&gt;Create a new IAM role with permissions to create CloudWatch logs and CRUD access to the “CoffeeShop” DynamoDB table. Let us call this IAM role as “CoffeeShopRole” and its a generic role for all our lambda functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "dynamodb:PutItem",
                "dynamodb:DeleteItem",
                "dynamodb:GetItem",
                "dynamodb:Scan",
                "dynamodb:UpdateItem"
            ],
            "Resource": "arn:aws:dynamodb::&amp;lt;DYNAMODB_TABLE_NAME&amp;gt;"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Create Lambda Layer And Lambda Functions
&lt;/h2&gt;

&lt;p&gt;First, create a Node.js Lambda layer that includes the DynamoDB library and common utility functions. It will help us avoid redundant installations of the same dependencies across multiple Lambdas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir nodejs
cd nodejs
npm init
npm i @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
touch utils.mjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now create a utils.mjs file to keep the code for DynamoDB client initialization and createResponse function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
    DynamoDBDocumentClient,
    ScanCommand,
    GetCommand,
    PutCommand,
    UpdateCommand,
    DeleteCommand
} from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);

const createResponse = (statusCode, body) =&amp;gt; {
    return {
        statusCode,
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body),
    };
};

export {
    docClient,
    createResponse,
    ScanCommand,
    GetCommand,
    PutCommand,
    UpdateCommand,
    DeleteCommand
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, create a zip of the content and upload it in a new lambda layer. According to convention, the folder where we keep all these dependencies must be named “nodejs”. Apart from that, the name of the zip file and lambda layer can be anything.&lt;/p&gt;

&lt;p&gt;In our case, let us create zip named “layer.zip” and upload it to the Lambda layer named “Dynamo-Layer”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ..
zip -r layer.zip nodejs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now create four lambda functions and attach this layer (Dynamo-Layer) and IAM Role (CoffeeShopRole) to them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// getCoffee Function

import { docClient, GetCommand, ScanCommand, createResponse } from '/opt/nodejs/utils.mjs'; // Import from Layer

const tableName = process.env.tableName || "CoffeeShop";

export const getCoffee = async (event) =&amp;gt; {
    const { pathParameters } = event;
    const { id } = pathParameters || {};

    try {
        let command;
        if (id) {
            command = new GetCommand({
                TableName: tableName,
                Key: {
                    "coffeeId": id,
                },
            });
        }
        else {
            command = new ScanCommand({
                TableName: tableName,
            });
        }
        const response = await docClient.send(command);
        return createResponse(200, response);
    }
    catch (err) {
        console.error("Error fetching data from DynamoDB:", err);
        return createResponse(500, { error: err.message });
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// createCoffee Function

import { docClient, PutCommand, createResponse } from '/opt/nodejs/utils.mjs'; // Import from Layer

const tableName = process.env.tableName || "CoffeeShop";

export const createCoffee = async (event) =&amp;gt; {
    const { body } = event;
    const { coffeeId, name, price, available } = JSON.parse(body || "{}");

    console.log("valuies", coffeeId, name, price, available);


    if (!coffeeId || !name || !price || available === undefined) {
        return createResponse(409, { error: "Missing required attributes for the item: coffeeId, name, price, or available." });
    }

    const command = new PutCommand({
        TableName: tableName,
        Item: {
            coffeeId,
            name,
            price,
            available
        },
        ConditionExpression: "attribute_not_exists(coffeeId)",
    });

    try {
        const response = await docClient.send(command);
        return createResponse(201, { message: "Item Created Successfully!", response });
    }
    catch (err) {
        if (err.message === "The conditional request failed")
            return createResponse(409, { error: "Item already exists!" });
        else
            return createResponse(500, {
                error: "Internal Server Error!",
                message: err.message,
            });
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// updateCoffee Function

import { docClient, UpdateCommand, createResponse } from '/opt/nodejs/utils.mjs'; // Import from Layer

const tableName = process.env.tableName || "CoffeeShop";

export const updateCoffee = async (event) =&amp;gt; {
    const { pathParameters, body } = event;

    const coffeeId = pathParameters?.id;
    if (!coffeeId)
        return createResponse(400, { error: "Missing coffeeId" });

    const { name, price, available } = JSON.parse(body || "{}");
    if (!name &amp;amp;&amp;amp; !price &amp;amp;&amp;amp; available === undefined)
        return createResponse(400, { error: "Nothing to update!" })

    let updateExpression = `SET  ${name ? "#name = :name, " : ""}${price ? "price = :price, " : ""}${available ? "available = :available, " : ""}`.slice(0, -2);

    try {

        const command = new UpdateCommand({
            TableName: tableName,
            Key: {
                coffeeId,
            },
            UpdateExpression: updateExpression,
            ...(name &amp;amp;&amp;amp; {
                ExpressionAttributeNames: {
                    "#name": "name", // name is a reserved keyword in DynamoDB
                },
            }),
            ExpressionAttributeValues: {
                ...(name &amp;amp;&amp;amp; { ":name": name }),
                ...(price &amp;amp;&amp;amp; { ":price": price }),
                ...(available &amp;amp;&amp;amp; { ":available": available }),
            },
            ReturnValues: "ALL_NEW", // returns updated value as response
            ConditionExpression: "attribute_exists(coffeeId)", // ensures the item exists before updating
        });

        const response = await docClient.send(command);
        console.log(response);
        return response;

    }
    catch (err) {
        if (err.message === "The conditional request failed")
            return createResponse(404, { error: "Item does not exists!" });
        return createResponse(500, {
            error: "Internal Server Error!",
            message: err.message,
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// deleteCoffee Function

import { docClient, DeleteCommand, createResponse } from '/opt/nodejs/utils.mjs'; // Import from Layer

const tableName = process.env.tableName || "CoffeeShop";

export const deleteCoffee = async (event) =&amp;gt; {
    const { pathParameters } = event;
    const coffeeId = pathParameters?.id;
    if (!coffeeId)
        return createResponse(400, { error: "Missing coffeeId" });

    try {
        const command = new DeleteCommand({
            TableName: tableName,
            Key: {
                coffeeId,
            },
            ReturnValues: "ALL_OLD", // returns deleted value as response
            ConditionExpression: "attribute_exists(coffeeId)", // ensures the item exists before deleting
        });

        const response = await docClient.send(command);
        return createResponse(200, { message: "Item Deleted Successfully!", response });
    }
    catch (err) {
        if (err.message === "The conditional request failed")
            return createResponse(404, { error: "Item does not exists!" });
        return createResponse(500, {
            error: "Internal Server Error!",
            message: err.message,
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Create API Gateway To Expose Lambda Functions
&lt;/h2&gt;

&lt;p&gt;Create an HTTP API Gateway and add five routes pointing to the above lambda functions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GET /coffee  -&amp;gt; getCoffee lambda function&lt;br&gt;
GET /coffee/{id}  -&amp;gt; getCoffee lambda function&lt;br&gt;
POST /coffee  -&amp;gt; createCoffee lambda function&lt;br&gt;
PUT /coffee/{id}  -&amp;gt; updateCoffee lambda function&lt;br&gt;
DELETE /coffee/{id}  -&amp;gt; deleteCoffee lambda function&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;At this point, you should be able to use all APIs using Postman or Thunderclient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Create Cognito UserPool And API Gateway Authorizer
&lt;/h2&gt;

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

&lt;p&gt;Create a cognito UserPool with a public client (SPA App) and use it as a JWT authorizer for API gateway for all the routes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Setup React Application And Upload Build To S3 Bucket
&lt;/h2&gt;

&lt;p&gt;Create a new React app and configure it with Cognito. You can copy files from here: &lt;a href="https://github.com/TrickSumo/AWS-CRUD-Serverless/tree/main/FrontendWithAuth" rel="noopener noreferrer"&gt;https://github.com/TrickSumo/AWS-CRUD-Serverless/tree/main/FrontendWithAuth&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new S3 bucket, build the React app, and upload the “dist” folder to the S3 bucket.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Create Cloudfront Distribution With Behaviors For S3 And API Gateway
&lt;/h2&gt;

&lt;p&gt;Create a new Cloudfront distribution with S3 as the origin and use OAC to access the private bucket (make sure to update bucket policy).&lt;/p&gt;

&lt;p&gt;Create another origin pointing to API gateway and create a new behaviour to redirect “/coffee*” routes to this new origin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Attach Custom Domain Name To CDN (Optional)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lsyrerc4onfa3vxqqyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lsyrerc4onfa3vxqqyw.png" alt="Create CNAME Record in Cloudflare"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Edit CDN settings to add an alternate domain name. Use AWS Certificate Manager to issue an SSL certificate (to verify domain ownership, CNAME record method can be used).&lt;/p&gt;

&lt;p&gt;Create a new CNAME record from the domain name control panel to point to the Cloudfront distribution URL.&lt;/p&gt;

&lt;p&gt;Done 🥳&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 9: Clean Up All Resources
&lt;/h2&gt;

&lt;p&gt;Now it’s time to clear all resources. Delete CDN, DynamoDB, API Gateway, Lambdas (with Layer), IAM Role, ACM certificate, and Cognito UserPool.&lt;/p&gt;

&lt;p&gt;Hope you enjoyed the tutorial! Thanks 🙂&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>lambda</category>
      <category>webdev</category>
    </item>
    <item>
      <title>AWS KMS Deep Dive - The Mystery Of Envelope Encryption</title>
      <dc:creator>Rishi</dc:creator>
      <pubDate>Sun, 23 Mar 2025 15:45:00 +0000</pubDate>
      <link>https://forem.com/aws-builders/aws-kms-deep-dive-the-mystery-of-envelope-encryption-2lc8</link>
      <guid>https://forem.com/aws-builders/aws-kms-deep-dive-the-mystery-of-envelope-encryption-2lc8</guid>
      <description>&lt;p&gt;AWS Key Management Service (&lt;a href="https://aws.amazon.com/kms/" rel="noopener noreferrer"&gt;KMS&lt;/a&gt;) allows you to create/manage encryption keys that are used to encrypt/decrypt and sign/verify data. AWS internally uses KMS across many services for encryption, so even if you’re not familiar with it, there’s a high chance you’ve already used it while working with other services (like while creating an S3 bucket!).&lt;/p&gt;

&lt;p&gt;In this post, we will explore how KMS uses envelope encryption, understand different KMS key types, and finally do hands-on with KMS using AWS CLI commands.&lt;/p&gt;

&lt;p&gt;Let’s start with the story of Pandora to get a gist of envelope encryption.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pandora And The Envelope Encryption
&lt;/h2&gt;

&lt;p&gt;The story goes like this, Zeus (king of Olympus) gave Pandora a box and asked her to never open it at any cost. But curious Pandora got curious and opened it anyway.&lt;/p&gt;

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

&lt;p&gt;Zeus could have given Pandora a locked box with a key and asked to not open it. In this scenario, Pandora might lose the key. Or she might open the locked box and claim she doesn’t know who did it.&lt;/p&gt;

&lt;p&gt;Zeus can also try to lock the box using his own key and give only the box to Pandora. In this case, Zeus would be responsible for keeping the key safe. Also, someone might steal the key from Zeus and open the box.&lt;/p&gt;

&lt;p&gt;To solve these problems, Zeus could have used &lt;a href="https://cloud.google.com/kms/docs/envelope-encryption" rel="noopener noreferrer"&gt;envelope encryption&lt;/a&gt;. First, he locks the box using a unique key. Then, instead of giving her the raw key, he encrypts it using his lightning bolt weapon⚡(his strongest secret). Now, he gives Pandora both the locked box and the encrypted key. This ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pandora can’t open the box without Zeus’ help (Zeus must decrypt the key first to unlock the box).&lt;/li&gt;
&lt;li&gt;If Pandora loses the key, no one else can use it.&lt;/li&gt;
&lt;li&gt;To unlock the box, Pandora must call Zeus to decrypt the key. Later, she can’t deny granting access by claiming she doesn’t know who opened the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Envelope Encryption
&lt;/h2&gt;

&lt;p&gt;The above story is an example of &lt;a href="https://docs.aws.amazon.com/kms/latest/cryptographic-details/crypto-primitives.html" rel="noopener noreferrer"&gt;envelope encryption&lt;/a&gt;, where the key used to encrypt the message (Pandora’s box of hope in our story) is encrypted itself (often using a more secret key ⚡). Then both the encrypted object (box) and encrypted key are stored together.&lt;/p&gt;

&lt;p&gt;It is called envelope encryption because the key used for locking the box is wrapped (enveloped/encrypted) by a super-secure master key. Then both locked object and encrypted key are packed into a single structure (thus forming an envelope).&lt;/p&gt;

&lt;p&gt;The purpose of encrypting a key with another key (multiple layers of keys) is to provide centralized key management and auditing while ensuring that the primary key is never exposed in an unencrypted form. Check out the article on FreeCodeCamp on &lt;a href="https://www.freecodecamp.org/news/envelope-encryption/" rel="noopener noreferrer"&gt;how envelope encryption helps to manage encryption at scale&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  KMS Key Types
&lt;/h2&gt;

&lt;p&gt;Based on ownership, KMS offers three key types –&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWS Owned Keys (free)&lt;/strong&gt; =&amp;gt;These keys provide default encryption for most of the services. You might have seen the SSE-S3 option while creating an S3 bucket. Everything is handled in the background and these keys are not visible anywhere. No visibility on audit trails or key rotation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWS Managed Keys (free)&lt;/strong&gt; =&amp;gt; These keys are also to be used by AWS services only (aws/s3 or aws/rds). However, customers can see key policies and CloudTrail events for AWS-managed keys. Everything else is managed by AWS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Customer Managed Keys ($1/month)&lt;/strong&gt; =&amp;gt; You (customer) own this key and can view audit trails and rotate on demand (Careful! Each key rotation adds $1/month to the bill since all versions are retained). If you want to call KMS API to create a key and use it in your applications, this is the type that you need.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on cryptographic structure, a key can be &lt;a href="https://docs.aws.amazon.com/kms/latest/cryptographic-details/crypto-primitives.html" rel="noopener noreferrer"&gt;symmetric or asymmetric&lt;/a&gt;. For the rest of the tutorial, we will focus on customer-managed symmetric KMS keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Envelope Encryption In Action – KMS Workflow
&lt;/h2&gt;

&lt;p&gt;Fair warning before we proceed forward, you are going to encounter a lot of keys. Be prepared!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step1: Key Creation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a customer-managed KMS key is created, AWS uses HSM (hardware security module) hardware to create &lt;em&gt;HSM Backing Key&lt;/em&gt; (HBK⚡). Since it’s not possible to keep HBK in memory of HSM forever, it must be exported to durable storage. But HBK cannot leave the HSM unencrypted. So, HBK is encrypted using HSM-managed domain keys to generate an EKT (&lt;em&gt;Exported Key Token&lt;/em&gt;) and stored in a database. Then our newly created KMS key points to this EKT.&lt;/p&gt;

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

&lt;p&gt;Yes, a KMS key (also called &lt;em&gt;customer master key&lt;/em&gt; CMK) does not contain actual key material. Instead, it acts as a pointer to the EKT (which is an encrypted version of the HBK itself)!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step2: Envelope Encryption&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the user (or services like S3) requests a data key (also called Data Encryption Key but we will call it data key because the term DEK is needed for another key – I promised too many keys ☺️) from KMS to encrypt an object, it also tells which KMS key to use (either by specifying key id or key alias). As we know, the KMS key serves as a pointer to the EKT. So EKT is taken to HSM and converted back to HBK (HSM Backing Key ⚡). After that, HBK is combined with Nonce (random number) to create a &lt;em&gt;Derived Encryption Key&lt;/em&gt; (DEK).&lt;/p&gt;

&lt;p&gt;Inside the HSM, a data key is also generated (also called &lt;em&gt;Customer Data Key&lt;/em&gt; CDK or &lt;em&gt;Data Encryption Key&lt;/em&gt;). This key will be used to lock the box (encrypt the object). Then the data key is encrypted using DEK (derived encryption key) and both the &lt;em&gt;plaintext data key&lt;/em&gt; and &lt;em&gt;encrypted data key&lt;/em&gt; are sent to the user (or service). For now, DEK will be discarded by HSM. Remember, the DEK encrypts the data key, which in turn encrypts the object.&lt;/p&gt;

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

&lt;p&gt;Now user can encrypt a file/object using the plaintext data key and immediately discard it. Then store the encrypted file and encrypted data key together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step3: Envelope Decryption?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In storage, we have an encrypted object and encrypted data key. To decrypt the object, we again need the plaintext data key but we deleted it just after encrypting the file/object (even S3 would also have done the same).&lt;/p&gt;

&lt;p&gt;To get the plaintext data key, we send the encrypted data key to KMS as part of the decrypt API. AWS HSM extracts the KMS key ID/alias and nonce from the encrypted data key. From the KMS key, EKT is traced and HBK is calculated.&lt;/p&gt;

&lt;p&gt;With HBK and nonce, the system regenerates the DEK (which was originally used to encrypt the data key). Then DEK is used to decrypt the data key and the plaintext data key is returned to the user.&lt;/p&gt;

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

&lt;p&gt;Finally, the plaintext data key can be utilized to decrypt the encrypted file/object.&lt;/p&gt;

&lt;h2&gt;
  
  
  KMS Hands-On Using AWS CLI – Less Than 4KB File Size
&lt;/h2&gt;

&lt;p&gt;For files smaller than 4KB, no need to request a data key. Just call encrypt/decrypt API and KMS will take care of all other things internally.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a symmetric KMS customer-managed key with Alias “learn”. Make sure to have encrypt and decrypt privileges for your AWS user.&lt;/li&gt;
&lt;li&gt;Open AWS CLI (top right in console), and create a file named myFile.txt.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Call KMS encrypt command&lt;br&gt;
&lt;code&gt;aws kms encrypt --key-id alias/learn --plaintext fileb://myFile.txt --output text --query CiphertextBlob --region ap-south-1 | base64 -d &amp;gt; myFile.encrypted&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now you should be able to see a new encrypted file myFile.encrypted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To decrypt the file, use the KMS decrypt command&lt;br&gt;
&lt;code&gt;aws kms decrypt --ciphertext-blob fileb://myFile.encrypted --output text --query Plaintext --region ap-south-1 | base64 -d&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In CLI, you should be able to see the original text of myFile.txt.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  KMS Hands-On Using AWS CLI – More Than 4KB File Size
&lt;/h2&gt;

&lt;p&gt;For files bigger than 4KB, we can call &lt;a href="https://docs.aws.amazon.com/kms/latest/cryptographic-details/generating-data-keys.html" rel="noopener noreferrer"&gt;GenerateDataKey&lt;/a&gt; API to get the data key and encrypted data key.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Get data key&lt;br&gt;
&lt;code&gt;aws kms generate-data-key --key-id alias/learn --key-spec AES_256  &amp;gt; data_key.json&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Store both data keys&lt;br&gt;
&lt;code&gt;jq -r '.Plaintext' data_key.json | base64 --decode &amp;gt; data_key_plaintext&lt;br&gt;
jq -r '.CiphertextBlob' data_key.json | base64 -d &amp;gt;  data_key_encrypted&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Encrypt the “test.txt” file and delete the plaintext data key&lt;br&gt;
&lt;code&gt;openssl enc -aes-256-cbc -pbkdf2 -salt -in test.txt -out test.encrypted -pass file:data_key_plaintext &amp;amp;&amp;amp; rm data_key_plaintext&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For decrypting the file, decrypt the encrypted data key&lt;br&gt;
&lt;code&gt;aws kms decrypt --ciphertext-blob fileb://data_key_encrypted  --output text --query Plaintext --region ap-south-1  | base64 --decode &amp;gt; data_key_plaintext&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then decrypt the locked file&lt;br&gt;
&lt;code&gt;openssl enc -d -aes-256-cbc -pbkdf2 -salt -in test.encrypted -out test.decrypted.txt -pass file:data_key_plaintext&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  KMS Use Cases – Project Ideas
&lt;/h2&gt;

&lt;p&gt;Here are a few ideas to play with KMS:-&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Password manager using KMS and DynamoDB.&lt;/li&gt;
&lt;li&gt;JWT-based authentication – KMS can be used to sign and verify JWTs.&lt;/li&gt;
&lt;li&gt;Use KMS to implement &lt;a href="https://github.com/aws-samples/amazon-cognito-passwordless-auth" rel="noopener noreferrer"&gt;passkeys using FIDO2.0&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Share your ideas in the comments!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion – KMS is Not Scary Anymore!
&lt;/h2&gt;

&lt;p&gt;Hope this tutorial helped you to understand the ins and outs of AWS KMS. Let me know your feedback and thoughts. Thanks 🙂&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gMB-NKNilQU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>aws</category>
      <category>programming</category>
      <category>cloudcomputing</category>
    </item>
    <item>
      <title>AWS Cognito Course For Beginners</title>
      <dc:creator>Rishi</dc:creator>
      <pubDate>Fri, 14 Mar 2025 15:30:00 +0000</pubDate>
      <link>https://forem.com/aws-builders/aws-cognito-course-for-beginners-ehb</link>
      <guid>https://forem.com/aws-builders/aws-cognito-course-for-beginners-ehb</guid>
      <description>&lt;p&gt;AWS Cognito is a robust tool for implementing an authentication and authorization layer on your application. In this course, we will understand Cognito offerings (User Pool and Identity Pool), different ways to use Cognito with your application (OAuth2.0 and SDK), and at the end will use our learnings to create a secure file sharing application (ShareMyFiles).&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/AmjPN3dWt1E"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Basic understanding of JavaScript, React, and NodeJS.&lt;/li&gt;
&lt;li&gt;Familiarity with core AWS services (S3, IAM, API Gateway) will be helpful.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Course Structure
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;AWS Cognito introduction

&lt;ul&gt;
&lt;li&gt;What is AWS Cognito?&lt;/li&gt;
&lt;li&gt;Difference between User Pool, ID Pool, and IAM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;User Pool overview

&lt;ul&gt;
&lt;li&gt;Users, Groups, MFA, Passkey &amp;amp; Managed Login&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;0Auth2.0 workflow with User Pool (Managed Login)

&lt;ul&gt;
&lt;li&gt;0Auth2.0 introduction, grant types, PKCE security, JWT authentication&lt;/li&gt;
&lt;li&gt;Public and Private OAuth2.0 clients&lt;/li&gt;
&lt;li&gt;User Pool with React (single page application), traditional backend and fullstack application&lt;/li&gt;
&lt;li&gt;Third-party (Google) login support&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;User Pool APIs and SDK (custom login page)&lt;/li&gt;
&lt;li&gt;Secure AWS API Gateway using Cognito User Pool (JWT Authorizer)&lt;/li&gt;
&lt;li&gt;Identity Pool

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Integration with User Pool and Google social login&lt;/li&gt;
&lt;li&gt;Role based access control&lt;/li&gt;
&lt;li&gt;APIs and SDK&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ShareMyFiles (Build a Secure File Sharing App with AWS Cognito &amp;amp; S3)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Github repo containing code and curl commands:- &lt;a href="https://github.com/TrickSumo/CognitoCourse" rel="noopener noreferrer"&gt;Cognito Course&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope people find it insightful. If there are any doubts, please let me know in the comments!&lt;/p&gt;

&lt;p&gt;Thanks ☺️&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What is So Special About Microsoft’s Majorana 1 Quantum Processor</title>
      <dc:creator>Rishi</dc:creator>
      <pubDate>Sun, 09 Mar 2025 09:30:00 +0000</pubDate>
      <link>https://forem.com/rishi123/what-is-so-special-about-microsofts-majorana-1-quantum-processor-59lc</link>
      <guid>https://forem.com/rishi123/what-is-so-special-about-microsofts-majorana-1-quantum-processor-59lc</guid>
      <description>&lt;p&gt;Recently, Microsoft announced &lt;a href="https://news.microsoft.com/source/features/innovation/microsofts-majorana-1-chip-carves-new-path-for-quantum-computing/" rel="noopener noreferrer"&gt;Majorana 1&lt;/a&gt; quantum processor that uses topological conductor to create quantum computers that can scale to a million qubits. In this post, we will decode why there is so much hype around Majorana 1 and understand how it works using simple analogies.&lt;/p&gt;

&lt;p&gt;Quantum computers utilize phenomena of quantum mechanics (ie, superposition, entanglement, and interference) for performing certain kinds of operations much faster than classical computers. However, we still do not have a working quantum computer (that can run Doom 😁) because of something called noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Noise?
&lt;/h2&gt;

&lt;p&gt;Like classical computers have bits, quantum equivalents are qubits. And these qubits utilize superposition (yes, yes, that both 0 and 1 at the same time thingy) to operate.&lt;/p&gt;

&lt;p&gt;But these qubits are generally very small subatomic particles (like an electron) and are susceptible to disturbances. Quantum state gets lost because of minute events like temperature change, electromagnetic interference, or even vibrations. Anything that affects the state of a qubit (and thus ultimately causes calculation error) is called Noise.&lt;/p&gt;

&lt;p&gt;No matter how much we shield our qubits, noise causes problems. And the time for which a quantum state can be maintained is measured as the &lt;a href="https://www.sciencedirect.com/topics/computer-science/decoherence-time#:~:text=Decoherence%20time%20refers%20to%20the,year%20for%20nuclear%20spin%20relaxation" rel="noopener noreferrer"&gt;Decoherence Time&lt;/a&gt;. So all quantum manufacturers work hard to increase this decoherence time.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Majorana Quasiparticles?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Quasiparticles&lt;/strong&gt; are not real fundamental particles but interactions of fundamental particles (emergent effects arising from the collective behavior of actual particles). And that interaction itself behaves as a particle and is hence called quasi-particle. It’s like an electron hole pair where if an electron moves from the valence band, leaving behind a void/space (or hole). This hole acts as a positively charged quasiparticle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Majorana quasiparticles&lt;/strong&gt; are those particles that are antimatter of their own (and they exist in pairs). If they touch each other, then destroy each other. However, when spatially separated, they can store quantum information in a way that resists noise.&lt;/p&gt;

&lt;p&gt;These Majorana quasiparticle pairs are analogous to mini water whirlpools. Like both vortices rotate in opposite directions and can destroy each other, they are also linked internally. &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/pnbJEg9r1o8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Check out above video from “Physics Girl” where she demonstrates formation of such vortices in a swimming pool.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Topological Conductor?
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/9SBVZr3lbS0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Similar to how conventional computation started with an Abacus, followed by vacuum tubes, electromagnetic relays, and transistors. Quantum computers are also on a hardware evolution journey. There are many modalities of quantum hardware like Google/IBM’s superconducting qubits, D-Wave’s trapped ion qubits, PsiQuantum’s photonic qubits. But all of them suffer from noise or information loss to some extent.&lt;/p&gt;

&lt;p&gt;To fix this noise issue, topological conductors use Majorana quasiparticles to distribute the quantum state across the surface. Now even if some noise enters the system, it is less likely to cause errors because the quantum information is spread out across a topological structure rather than being localized in a single particle.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/xr_izIthZWQ"&gt;
&lt;/iframe&gt;
&lt;br&gt;
Check out “Dr. Ben Miles” video on Topological Quantum Chips for an in-depth understanding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quantum Future is Exciting!
&lt;/h2&gt;

&lt;p&gt;However, some critics say that Microsoft still has not successfully created topological conductors that can scale. But even if there is some progress going on, that is good news.&lt;/p&gt;

&lt;p&gt;Also, Amazon announced they are working on Ocelot quantum processors that use &lt;a href="https://www.aboutamazon.com/news/aws/quantum-computing-aws-ocelot-chip" rel="noopener noreferrer"&gt;cat qubits&lt;/a&gt;🐈&lt;/p&gt;

&lt;p&gt;Overall, Majorana 1 is a good candidate to take us out of the NISQ (Noisy intermediate-scale quantum) era.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
