<?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>DEV Community: Scott Burgholzer</title>
    <description>The latest articles on DEV Community by Scott Burgholzer (@scottburgholzer).</description>
    <link>https://dev.to/scottburgholzer</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%2F1330421%2F89798e2c-9a46-4840-89f7-c347ed7fc8d6.jpg</url>
      <title>DEV Community: Scott Burgholzer</title>
      <link>https://dev.to/scottburgholzer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/scottburgholzer"/>
    <language>en</language>
    <item>
      <title>The InvalidCiphertextException Mystery: Decrypting Cognito's Encrypted OTP Codes</title>
      <dc:creator>Scott Burgholzer</dc:creator>
      <pubDate>Thu, 01 Jan 2026 05:05:01 +0000</pubDate>
      <link>https://dev.to/aws-builders/the-invalidciphertextexception-mystery-decrypting-cognitos-encrypted-otp-codes-jg8</link>
      <guid>https://dev.to/aws-builders/the-invalidciphertextexception-mystery-decrypting-cognitos-encrypted-otp-codes-jg8</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;You're building a custom email sender for Cognito because the default emails are pretty basic. In this case you want branded HTML emails for a One Time Password code that actually explain what the code is for and when it expires. Sounds straightforward, right?&lt;/p&gt;

&lt;p&gt;Then you hit the encryption wall. Cognito encrypts those OTP codes for security (which is great), but when you try to decrypt them in your Lambda function using standard KMS operations, you get this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;InvalidCiphertextException: An error occurred (InvalidCiphertextException) when calling the Decrypt operation:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No helpful details, no explanation of what went wrong. The error message makes it seem like there's something fundamentally wrong with the ciphertext, but even after triple-checking your KMS permissions, it still doesn't work. Here's why, and more importantly, how to fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR - The Solution
&lt;/h2&gt;

&lt;p&gt;Cognito doesn't use regular KMS encryption. It uses the &lt;strong&gt;AWS Encryption SDK&lt;/strong&gt;, which creates a completely different data structure. You need to use the same AWS Encryption SDK (v4 with Material Providers Library) to decrypt the codes. Jump to the working code if you just want the fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Everyone Tries First, Including Myself (And Why It Fails)
&lt;/h2&gt;

&lt;p&gt;When you think AWS encryption, you think KMS. So naturally, you try the standard approaches:&lt;/p&gt;

&lt;h3&gt;
  
  
  Attempt 1: Basic KMS Decryption
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This seems logical but doesn't work
&lt;/span&gt;&lt;span class="n"&gt;kms_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;kms&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;decrypt_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kms_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CiphertextBlob&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;encrypted_blob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; &lt;code&gt;InvalidCiphertextException&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Attempt 2: Adding Encryption Context
&lt;/h3&gt;

&lt;p&gt;Maybe it needs the user pool ID as context?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Still doesn't work
&lt;/span&gt;&lt;span class="n"&gt;decrypt_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kms_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CiphertextBlob&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;encrypted_blob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;EncryptionContext&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;userpool-id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;userPoolId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Same error&lt;/p&gt;

&lt;h3&gt;
  
  
  Attempt 3: AWS-Prefixed Context
&lt;/h3&gt;

&lt;p&gt;Perhaps it needs the AWS service prefix?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Nope, still fails
&lt;/span&gt;&lt;span class="n"&gt;decrypt_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kms_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CiphertextBlob&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;encrypted_blob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;EncryptionContext&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aws:cognito:userpool-id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;userPoolId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Still the same error&lt;/p&gt;

&lt;p&gt;At this point, you start questioning everything. Your KMS permissions look right, the key exists, but nothing works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Issue: It's Not Actually KMS Ciphertext
&lt;/h2&gt;

&lt;p&gt;Here's the key insight that changes everything: &lt;strong&gt;Cognito doesn't use direct KMS encryption&lt;/strong&gt;. Instead, it uses something called the AWS Encryption SDK, which creates a completely different type of encrypted data.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the Difference?
&lt;/h3&gt;

&lt;p&gt;Think of it this way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Regular KMS encryption&lt;/strong&gt; = A locked box&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Encryption SDK&lt;/strong&gt; = A locked box inside a shipping container with labels, tracking info, and handling instructions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you try to use KMS to "unlock" the shipping container, KMS says "I don't know what this is - this isn't a box I locked!"&lt;/p&gt;

&lt;h3&gt;
  
  
  The Technical Details
&lt;/h3&gt;

&lt;p&gt;When Cognito encrypts an OTP code, here's what actually happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cognito uses the AWS Encryption SDK&lt;/strong&gt; (not direct KMS)&lt;/li&gt;
&lt;li&gt;The SDK creates an "envelope" containing:

&lt;ul&gt;
&lt;li&gt;Algorithm information&lt;/li&gt;
&lt;li&gt;An encrypted data key (this part uses KMS)&lt;/li&gt;
&lt;li&gt;The actual encrypted OTP code&lt;/li&gt;
&lt;li&gt;Integrity checks and metadata&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This entire envelope gets passed to your Lambda function&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;encrypted_blob&lt;/code&gt; you receive isn't simple KMS ciphertext - it's this complex envelope structure. That's why KMS can't decrypt it directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why the Error Message is Confusing
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;InvalidCiphertextException&lt;/code&gt; error just says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;An error occurred (InvalidCiphertextException) when calling the Decrypt operation:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No details, no explanation. This generic message makes you think the ciphertext is corrupted or you have permission issues, but the real problem is that KMS is saying "I can't even parse this data structure." &lt;/p&gt;

&lt;p&gt;It's like trying to open a ZIP file with a text editor - the format is just wrong, but the error message doesn't tell you that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution: AWS Encryption SDK Implementation
&lt;/h2&gt;

&lt;p&gt;Once you understand the problem, the solution becomes clear. You need to use the same AWS Encryption SDK that Cognito uses to create the encrypted data.&lt;/p&gt;

&lt;h3&gt;
  
  
  What You Need
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS Encryption SDK v4&lt;/strong&gt; - The encryption library&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Material Providers Library (MPL)&lt;/strong&gt; - Required for v4&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proper KMS permissions&lt;/strong&gt; - Your Lambda still needs to access the KMS key&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The right Python packages&lt;/strong&gt; - Install them as a Lambda layer&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Working Code
&lt;/h3&gt;

&lt;p&gt;Here's the code that actually works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;aws_encryption_sdk&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_encryption_sdk&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CommitmentPolicy&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_cryptographic_material_providers.mpl&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AwsCryptographicMaterialProviders&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_cryptographic_material_providers.mpl.config&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MaterialProvidersConfig&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_cryptographic_material_providers.mpl.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CreateAwsKmsKeyringInput&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decrypt_cognito_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_blob&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Set up the encryption client
&lt;/span&gt;    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aws_encryption_sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EncryptionSDKClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;commitment_policy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CommitmentPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REQUIRE_ENCRYPT_ALLOW_DECRYPT&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Create the material providers
&lt;/span&gt;    &lt;span class="n"&gt;mat_prov&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AwsCryptographicMaterialProviders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;MaterialProvidersConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Set up the KMS keyring
&lt;/span&gt;    &lt;span class="n"&gt;kms_key_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;KMS_KEY_ID&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;keyring_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CreateAwsKmsKeyringInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;kms_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;kms_key_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;kms_client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;kms&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;kms_keyring&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mat_prov&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_aws_kms_keyring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;keyring_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Now this actually works!
&lt;/span&gt;    &lt;span class="n"&gt;plaintext_bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decryption_header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;encrypted_blob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;keyring&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;kms_keyring&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Convert to string and return
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;plaintext_bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting It Up
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Install the packages:&lt;/strong&gt;&lt;br&gt;
Create a Lambda layer with these dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"aws-encryption-sdk[MPL]"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;4.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Set your environment variable:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KMS_KEY_ID=your-kms-key-id-here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Update your IAM role:&lt;/strong&gt;&lt;br&gt;
Your Lambda execution role needs &lt;code&gt;kms:Decrypt&lt;/code&gt; permission for your KMS key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kms:Decrypt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:kms:region:account:key/your-key-id"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why This Matters Beyond Cognito
&lt;/h2&gt;

&lt;p&gt;This isn't just a Cognito quirk. Other AWS services also use the AWS Encryption SDK instead of direct KMS encryption:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Systems Manager Parameter Store&lt;/strong&gt; (SecureString parameters)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some S3 client-side encryption&lt;/strong&gt; scenarios&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom applications&lt;/strong&gt; that need to encrypt large amounts of data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern is becoming more common because the AWS Encryption SDK offers benefits that direct KMS doesn't:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No size limits&lt;/strong&gt; (KMS is limited to 4KB)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better performance&lt;/strong&gt; for large data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Additional security features&lt;/strong&gt; like key commitment&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Key Takeaway
&lt;/h3&gt;

&lt;p&gt;When you see an AWS service that says it "uses KMS encryption," don't assume it's using direct KMS calls. It might be using the AWS Encryption SDK under the hood, which changes everything about how you decrypt the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting Tips
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If you're still getting errors:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Check your Lambda layer&lt;/strong&gt; - Make sure you have the right packages installed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify your KMS key ID&lt;/strong&gt; - It should be the same one configured in your Cognito user pool&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test your IAM permissions&lt;/strong&gt; - Try a simple KMS decrypt operation to verify access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the commitment policy&lt;/strong&gt; - Use &lt;code&gt;REQUIRE_ENCRYPT_ALLOW_DECRYPT&lt;/code&gt; for compatibility&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Common mistakes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using the wrong version of the AWS Encryption SDK (you need v4)&lt;/li&gt;
&lt;li&gt;Forgetting to install the Material Providers Library&lt;/li&gt;
&lt;li&gt;Using the wrong KMS key (it must match what Cognito is configured to use)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Error message reference:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;InvalidCiphertextException&lt;/code&gt; with no details = You're trying to decrypt AWS Encryption SDK data with direct KMS&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;IncorrectKeyException&lt;/code&gt; = You're using the wrong KMS key for real KMS ciphertext&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AccessDeniedException&lt;/code&gt; = Actual permissions problem&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This problem can stump a lot of developers because the error message is so generic and unhelpful. When you see &lt;code&gt;InvalidCiphertextException&lt;/code&gt; with no details, it's usually a sign that you're trying to decrypt AWS Encryption SDK data with direct KMS calls.&lt;/p&gt;

&lt;p&gt;Once you understand that Cognito uses the AWS Encryption SDK instead of direct KMS, everything clicks into place. The extra complexity is worth it - you get better security, no size limits, and future-proof encryption. Plus, now you know how to handle this pattern when you encounter it in other AWS services.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-sender-triggers.html" rel="noopener noreferrer"&gt;AWS Cognito Custom Sender Lambda Triggers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/" rel="noopener noreferrer"&gt;AWS Encryption SDK Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/python-example-code.html" rel="noopener noreferrer"&gt;AWS Encryption SDK Python Examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>encryption</category>
      <category>lambda</category>
      <category>kms</category>
    </item>
    <item>
      <title>Understanding Amazon CloudFront's New Flat-Rate Pricing</title>
      <dc:creator>Scott Burgholzer</dc:creator>
      <pubDate>Thu, 27 Nov 2025 00:45:35 +0000</pubDate>
      <link>https://dev.to/aws-builders/understanding-amazon-cloudfronts-new-flat-rate-pricing-e9k</link>
      <guid>https://dev.to/aws-builders/understanding-amazon-cloudfronts-new-flat-rate-pricing-e9k</guid>
      <description>&lt;p&gt;On November 18th, AWS introduced new flat‑rate pricing plans for Amazon CloudFront designed to make content delivery and security costs more predictable for teams of all sizes. These plans sit alongside the existing pay‑as‑you‑go model and bundle multiple services into a single monthly price per distribution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Flat-Rate Pricing Matters
&lt;/h3&gt;

&lt;p&gt;Traditionally, CloudFront has used pay‑as‑you‑go pricing, which is great for starting at $0, scaling with actual usage, and only paying for what you consume. The tradeoff is that estimating costs can be difficult, especially when you also depend on AWS WAF, DDoS protection, Route 53, CloudWatch Logs, and S3 for a single application. You end up stitching together multiple pricing pages and trying to map them to your traffic patterns just to get a reasonable forecast of your monthly bill.&lt;/p&gt;

&lt;p&gt;The new flat‑rate plans aim to simplify this. Instead of tracking every request, rule, and log line, you choose a plan tier per distribution and pay a fixed monthly fee that includes a defined bundle of features and usage allowances.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's Included in the New Plans
&lt;/h3&gt;

&lt;p&gt;Each flat‑rate plan bundles the following into one monthly price per CloudFront distribution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon CloudFront CDN&lt;/li&gt;
&lt;li&gt;AWS WAF and DDoS protection&lt;/li&gt;
&lt;li&gt;Bot management and analytics&lt;/li&gt;
&lt;li&gt;Amazon Route 53 DNS&lt;/li&gt;
&lt;li&gt;Amazon CloudWatch Logs ingestion&lt;/li&gt;
&lt;li&gt;Serverless edge compute (via CloudFront Functions)&lt;/li&gt;
&lt;li&gt;Monthly Amazon S3 storage credits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because everything is packaged together, you get a predictable bill for that distribution with no overage charges. There are no surprises at the end of the month.&lt;/p&gt;

&lt;p&gt;A few structural details to keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plans are per distribution. If you put two distributions on the Business plan at $200 each, you will pay $400 per month for those two.&lt;/li&gt;
&lt;li&gt;You can upgrade at any time, but downgrades/cancellations or a move back to pay‑as‑you‑go only take effect at the start of the next billing cycle.&lt;/li&gt;
&lt;li&gt;There is a limit of three free plans per AWS account and a limit of 100 total plans per account, which matters if you run many environments or tenants.&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%2Fh2xx8sfav7ijcbwv7tzt.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%2Fh2xx8sfav7ijcbwv7tzt.png" alt="CloudFront flat-rate plans" width="800" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling Attacks and Traffic Spikes
&lt;/h3&gt;

&lt;p&gt;One of the more reassuring aspects of these plans is how they treat malicious traffic. DDoS attacks do not count against your usage allowance, and traffic blocked by AWS WAF or bot protections also does not consume your plan quota. That means an attack should not cause you to exceed your allowance.&lt;/p&gt;

&lt;p&gt;You will receive email notifications when you hit 50%, 80%, and 100% of your usage allowance for the month. If you exceed the allowance, AWS will not tack on overage fees, but you may experience reduced performance. That performance reduction is at AWS's discretion and depends on overall network conditions and other factors, so consistently bumping into your limits is a good signal that it is time to move to a higher‑tier plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  Edge Compute: CloudFront Functions vs. Lambda@Edge
&lt;/h3&gt;

&lt;p&gt;All of the flat‑rate plans include CloudFront Functions, which are ideal for lightweight JavaScript logic at the edge such as header manipulation, redirects, and simple request or response normalization. For many use cases, this will cover the bulk of what you might previously have used Lambda@Edge for.&lt;/p&gt;

&lt;p&gt;However, Lambda@Edge is not supported on the flat‑rate plans. If your distribution relies on Lambda@Edge, such as more complex request processing, integrations, or heavy transformations, you must keep that distribution on the pay‑as‑you‑go pricing model. This is an important constraint to verify before flipping an existing production distribution over to a flat‑rate plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pay-As-You-Go Is Still Available
&lt;/h3&gt;

&lt;p&gt;All of this arrives in addition to, not instead of, the existing pay‑as‑you‑go model. The traditional CloudFront pricing structure remains available with its free tier, which is still a solid option for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Very low‑traffic or experimental workloads&lt;/li&gt;
&lt;li&gt;Architectures that depend on Lambda@Edge or other features not supported in flat‑rate plans&lt;/li&gt;
&lt;li&gt;Teams that prefer pure usage‑based billing and are comfortable modeling and monitoring their costs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice, many organizations will likely end up with a mix: flat‑rate plans for high‑volume, business‑critical sites where predictability matters, and pay‑as‑you‑go for specialized or experimental distributions.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudfront</category>
      <category>cdn</category>
    </item>
    <item>
      <title>What is AWS Device Farm and Using it to Test a Simple Android App</title>
      <dc:creator>Scott Burgholzer</dc:creator>
      <pubDate>Sat, 23 Nov 2024 04:37:15 +0000</pubDate>
      <link>https://dev.to/aws-builders/what-is-aws-device-farm-and-using-it-to-test-a-simple-android-app-ah7</link>
      <guid>https://dev.to/aws-builders/what-is-aws-device-farm-and-using-it-to-test-a-simple-android-app-ah7</guid>
      <description>&lt;h4&gt;
  
  
  Introduction
&lt;/h4&gt;

&lt;p&gt;As I have been busy with my classes for my doctorate and work, I haven’t had much time to write articles like I had hoped. I was hoping to have a project done that I could discuss how I created a Web App using multiple AWS services for others to learn how they all can interact. As that project is still ongoing, I decided to focus on something else.&lt;/p&gt;

&lt;p&gt;I choose AWS Device Farm because eventually I would need to test that web app on mobile devices and on desktop browsers. Device Farm allows us to use physical devices to test our apps. Not only can we test web apps, we can also test Android and iOS apps on physical devices. There is a lot to learn for Device Farm, so I started very basic with using it, and hence this article was born. I hope, while this article just uses a simple app and the defaults, it can expose more people to this AWS service and see if it’ll work in their use cases.&lt;/p&gt;

&lt;p&gt;View this article as a “I’ve never heard or seen AWS Device Farm, so I want to start from the basics and work my way up” as that is exactly what I’m doing with you!&lt;/p&gt;




&lt;h4&gt;
  
  
  What is AWS Device Farm?
&lt;/h4&gt;

&lt;p&gt;AWS Device farm is a cloud-based testing platform that allows developers to test their mobile and web apps on physical devices instead of simulators. There are two main ways of using Device Farm: automated testing of apps and remote access of devices [1].&lt;/p&gt;

&lt;h4&gt;
  
  
  Automated app testing
&lt;/h4&gt;

&lt;p&gt;AWS Device Farm allows developers the ability to upload their own tests or to use built-in and script-free compatibility. AWS Device Farm performs testing in parallel, tests on multiple devices begin in minutes. As these tests are completed, a report is generated that contains high-level results, low-level logs, pixel-to-pixel screenshots and performance data. Device Farm supports the testing of native and hybrid Android and iOS Apps. Some frameworks that work with Device Farm are PhoneGap, Titanium, Xamarin, Unity, and others. You also get remote access of Android and iOS apps for interactive testing.&lt;/p&gt;

&lt;h4&gt;
  
  
  Remote access interaction
&lt;/h4&gt;

&lt;p&gt;This allows you to swipe, gesture and interact with a device through your web browser in real time. An example of where this is beneficial is a customer service rep can guide customers through the use or setup of their device. You have the ability to install apps on a device running in a remote access session and reproduce bugs or other issues. While the session is live, Device Farm will collect details about the actions that are completed on the device. Logs with those details and a video capture of the session are available at the end of the session [1].&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note about regions:&lt;/strong&gt; Per the documentation, Device Farm is only available in the us-west-2 (Oregon) region [1].&lt;/p&gt;




&lt;h4&gt;
  
  
  Walk-through
&lt;/h4&gt;

&lt;p&gt;I’m going to skip over the setting up section. If you wish to go through it in detail (signing up for an account, create or use an IAM user) you may read that &lt;a href="https://docs.aws.amazon.com/devicefarm/latest/developerguide/setting-up.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Below is an example IAM policy [1] to allow full access to Device Farm. For this walk-through, this is fine, but if you are going to implement this service, you are going to want to restrict it as much as you can to the least privilege access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"devicefarm:*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;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%2Fbuzi74i1y13x4f5rb9ho.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%2Fbuzi74i1y13x4f5rb9ho.png" alt="Device Farm Console" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Device Farm Console&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Create a project&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to Device Farm in the console
&lt;/li&gt;
&lt;li&gt;Expand the left hand navigation if necessary
&lt;/li&gt;
&lt;li&gt;Click on Projects underneath Mobile Device Testing
&lt;/li&gt;
&lt;li&gt;Click on Create mobile project
&lt;/li&gt;
&lt;li&gt;Enter a project name and assign any tags you wish the project to have
&lt;/li&gt;
&lt;li&gt;Click Create&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Create and start a run&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You will need an app in order to start the run. I have created a very simple Android App on my &lt;a href="https://github.com/sburgholzer/AWS-Device-Farm-Examples-for-Blog/blob/main/app-debug.apk" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Go ahead and download that if you do not have your own Android or Apple App (note in order to get an .ipa file for iOS you will need to have an Apple Developer Account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stay on the Automated tests page and click on Create Run  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Device Farm uses the app name as the default run name, feel free to choose your own name! Click Next  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You’ll be taken to a configure page to setup your test framework. You have the ability to choose one of the testing frameworks provided or built-in test suites. Since we are not worrying about our own tests for this example, we can use the Built-In: Fuzz for our case (can keep all the defaults). When you start writing your own test packages, you can choose the corresponding testing framework and upload the file with your tests. This is not applicable in our example. Click Next  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For our example, we will use the Top Devices Device pool. You do have the ability to create your own device pools, but for our simple app, Top Devices is just fine. Click Next  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We are going to keep the next page as is. You can read more about the options in the Developer Guide, which you can find at the end of this article tagged [1]. Click Next  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We will leave the execution timeout to the default value provided and will then click Confirm and start run. This can take a while, so wait patiently.&lt;/p&gt;&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%2Fwdmygejisgotr8twl5ih.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%2Fwdmygejisgotr8twl5ih.png" alt="Run Results" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run Results&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: View the run’s results&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
 — When the run is done, you will see the results of the runs. In my case 3 tests were ran and all passed.&lt;br&gt;&lt;br&gt;
 — The unique problems would list any problems that were discovered. A video can be downloaded to view the recording of the test that had the problem. There are additional data provided that I won’t get into detail in this article.&lt;br&gt;&lt;br&gt;
 — Screenshots will display any screenshots Device Farm took during the run.&lt;/p&gt;




&lt;h4&gt;
  
  
  Where to go from here?
&lt;/h4&gt;

&lt;p&gt;The next thing I personally would suggest, and plan on doing, is to learn more about test packages. There are frameworks that work with both iOS and Android, and some that only work for only Android or only iOS. This is where you are able to specify your tests the way you want them instead of using just the built-in tests AWS provides. This gives you complete control over how you want the tests done and what you want tested. This is where the real power of AWS Device Farm comes into play.&lt;/p&gt;

&lt;p&gt;The other thing to look into is the Desktop Browser Testing for any web apps. Personally for me, my project is going to start as just a web app, so Desktop Browser Testing is of personal importance. As always, you need to figure out your use cases and determine what your needs are.&lt;/p&gt;

&lt;p&gt;There is so much more to learn about AWS Device Farm, and I will continue posting about it as I go through it and learn it myself. For now, happy developing and testing!&lt;/p&gt;

&lt;p&gt;[1] &lt;a href="https://docs.aws.amazon.com/devicefarm/latest/developerguide/welcome.html" rel="noopener noreferrer"&gt;AWS Device Farm Developer Guide&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devicefarm</category>
      <category>testingtools</category>
    </item>
    <item>
      <title>Launching a simple EC2 Instance with Apache Web Server — Part 1</title>
      <dc:creator>Scott Burgholzer</dc:creator>
      <pubDate>Mon, 11 Mar 2024 02:06:15 +0000</pubDate>
      <link>https://dev.to/aws-builders/launching-a-simple-ec2-instance-with-apache-web-server-part-1-33nl</link>
      <guid>https://dev.to/aws-builders/launching-a-simple-ec2-instance-with-apache-web-server-part-1-33nl</guid>
      <description>&lt;p&gt;&lt;strong&gt;Little backstory:&lt;/strong&gt; I’ve had this in my drafts for a while, wanting to do it all as one article. I’ve decided that is not the best way of presenting this information. As a newer content creator, I’ve been playing with how I want my pages to look like, and have decided to go with how it looks right now.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this article, I will be doing what some call “click-ops” in AWS console as that is the easiest way to get started. If you want more challenges, I will also be posting on how to use AWS CLI (an article post on this will come at a later date, when completed, I will be updating this with a link to it!) to do the same thing. I will also show how to use a Cloud Development Kit (CDK). I will be using Python in my CDK examples. I will also use AWS CloudFormation. Finally, for an even more advanced challenge, I will be creating this process again using Terraform. If you are new, the console way will be the easiest, but I also want to introduce you to the CLI, CDK, CloudFormation and Terraform as these are advanced tools used!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Scope of this tutorial&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this multi-part tutorial, we are wanting to set up an EC2 instance, configure security group(s), create a key-pair SSH Key to remote into the instance, and install Apache Web Server.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Method 1:&lt;/strong&gt; Using AWS Console (without using userdata)&lt;/p&gt;

&lt;p&gt;There are actually two ways we can use the AWS console to create the EC2 instance, and install Apache and run it and create the test HTML file. This method will require us to use SSH to remote into our EC2 instance to preform some steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; When you are logged into the AWS Console, search for EC2 in the search bar.&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%2Fe4zyev7c4psyzew0g3qc.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%2Fe4zyev7c4psyzew0g3qc.png" alt="AWS Console and searching for EC2 via the search bar." width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Click on Launch Instance&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%2Foc5cveduvfa026ric38d.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%2Foc5cveduvfa026ric38d.png" alt="EC2 console dashboard with Launch Instance button shown" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Configure your instance and install Apache and test web page&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give the instance a name, I called mine “Web Server Test”    * Keep the application and OS Images as is&lt;/li&gt;
&lt;li&gt;Keep the instance type as t2.micro&lt;/li&gt;
&lt;li&gt;Click on new key par and give it a name, then click on Create key pair. It’ll download a file, move it to a safe location so you don’t loose it!&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%2F0hh4oktrmp3ybdz4tamw.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%2F0hh4oktrmp3ybdz4tamw.png" alt="Creating a Key Pair" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Under Network settings we will be keeping the selection Create Security Group. Allow SSH traffic from should be checked, and you’ll also want to check the Allow HTTP traffic from the internet. Next to SSH there is a dropdown menu that you can say any IP can connect to the instance, a custom IP or range, or your IP only. For this example, I’m keeping it as anywhere&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%2F0qkjbaspm7g42ml0noft.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%2F0qkjbaspm7g42ml0noft.png" alt="Creating the security group through the Launch Instance Wizard" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We will leave everything else as default&lt;/li&gt;
&lt;li&gt;Click on Launch Instance&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%2Fcdmu9ixhn5z1q1aojh66.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%2Fcdmu9ixhn5z1q1aojh66.png" alt="showing the instance was created successfully from the wizard with a green success box with a link to view that instance." width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the instance ID shown in the green success box&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%2F2f8tylkz28vctdvo66h7.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%2F2f8tylkz28vctdvo66h7.png" alt="Instance shown as running" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click the checkbox next to the instance, then go to actions and click on Connect&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%2Fu6heinfunm0n0qa33im0.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%2Fu6heinfunm0n0qa33im0.png" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You’ll see there are four options of connecting. The only two that will work with our instance, due to the way we set it up, is EC2 Instance Connect and SSH client. If on Mac or Linux you can use command line to SSH into the instance’s command line, on Windows it is easiest to use a tool such as Putty.&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%2Flz3upox6kyi44xmu35e7.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%2Flz3upox6kyi44xmu35e7.png" alt="Showing the connect options, and the EC2 Instance Connect we are using in our example" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We will be using EC2 Instance connect in our case, so click on that tab, then click on connect&lt;/li&gt;
&lt;li&gt;After waiting a few moments, you’ll see a command line terminal for our instance.&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%2Fu32gmo2qevknel0gch3g.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%2Fu32gmo2qevknel0gch3g.png" alt="The command line interface via EC2 Instance Connect" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We now want to install Apache and start the service. Run the following commands in the command prompt.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;yum update &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="c"&gt;# We are asking the packacge manager to install any updates&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;yum &lt;span class="nb"&gt;install &lt;/span&gt;httpd &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="c"&gt;# We are asking the package manager to install Apache&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;httpd &lt;span class="c"&gt;# We are telling the server to automatically start Apache upon start up&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start httpd &lt;span class="c"&gt;# we are telling the server to start the Apache Server&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status httpd &lt;span class="c"&gt;# we are telling the server to tell us the status of the Apache Server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fmvehd68fidaww8mxccfy.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%2Fmvehd68fidaww8mxccfy.png" alt="Results of some of the commands and showing that Apache is running" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We are going to create a simple HTML file, run the below command to open a new file using a command line text editor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;sudo nano /var/www/html/index.html&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Put the following code into the text editor
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Test Web Page&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Welcome to my website!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;I love AWS&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When you are done with the file, press ctl and x, it’ll prompt you if you want to save, type Y, press enter, then press enter again.&lt;/li&gt;
&lt;li&gt;Go back to the EC2 Instances page, click on your instance, then click on open address under the Public IPv4 address, change the HTTPS to HTTP&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%2F8ngmx3ft4etn2f5upp5t.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%2F8ngmx3ft4etn2f5upp5t.png" alt="You should see your test page" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you see your test page, you were successful!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Clean Up&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Close all windows except for the Instances window.&lt;/li&gt;
&lt;li&gt;Select it, then click on Instance state then click on Terminate instance so you don’t use up your free trial credits or get charged!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Congrats! You have just launched a simple EC2 Web server!&lt;/p&gt;




&lt;p&gt;&lt;a href="https://dev.to/aws-builders/launching-a-simple-ec2-instance-with-apache-web-server-part-1-33nl"&gt;Launching a simple EC2 Instance with Apache Web Server — Part 1 (AWS Console)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Launching a simple EC2 Instance with Apache Web Server — Part 2 (AWS Console with Userdata) (Coming Soon)&lt;/p&gt;

&lt;p&gt;Launching a simple EC2 Instance with Apache Web Server — Part 3 (AWS CLI with user data) (Coming Soon)&lt;/p&gt;

&lt;p&gt;Launching a simple EC2 Instance with Apache Web Server — Part 4 (Terraform with user data) (Coming Soon)&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ec2</category>
    </item>
  </channel>
</rss>
