<?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: Anton Poriadin</title>
    <description>The latest articles on Forem by Anton Poriadin (@aporiadin).</description>
    <link>https://forem.com/aporiadin</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%2F1115910%2F49b33f3e-fd28-4cfd-8fa7-e3b104480f86.jpg</url>
      <title>Forem: Anton Poriadin</title>
      <link>https://forem.com/aporiadin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/aporiadin"/>
    <language>en</language>
    <item>
      <title>Cross-Account CodeCommit Access from EC2</title>
      <dc:creator>Anton Poriadin</dc:creator>
      <pubDate>Tue, 07 Nov 2023 05:26:42 +0000</pubDate>
      <link>https://forem.com/aporiadin/cross-account-codecommit-access-from-ec2-51bn</link>
      <guid>https://forem.com/aporiadin/cross-account-codecommit-access-from-ec2-51bn</guid>
      <description>&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;
Cross-Account CodeCommit Access from EC2

&lt;ul&gt;
&lt;li&gt;Step 1: Create an IAM role in Account A&lt;/li&gt;
&lt;li&gt;Step 2: Create a policy in Account B&lt;/li&gt;
&lt;li&gt;Step 3: Create an IAM role in Account B&lt;/li&gt;
&lt;li&gt;Step 4: Create a CodeCommit repository in Account A&lt;/li&gt;
&lt;li&gt;Step 5: Create an EC2 instance in Account B&lt;/li&gt;
&lt;li&gt;Step 6: Connect to the instance and checkout files&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Lessons learned&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this two-part series, I will guide you on how to access an &lt;a href="https://aws.amazon.com/codecommit/" rel="noopener noreferrer"&gt;AWS CodeCommit&lt;/a&gt; repository using &lt;a href="https://github.com/aws/git-remote-codecommit" rel="noopener noreferrer"&gt;git-remote-codecommit&lt;/a&gt;. This tutorial will specifically focus on accessing a repository from a different account. In contrast, &lt;a href="https://dev.to/aporiadin/codecommit-access-from-ec2-2h8j"&gt;the first part&lt;/a&gt; of this series explains how to access a repository from the same account.&lt;/p&gt;

&lt;p&gt;While working on a project, I came across a situation where a client was using SSH keys to interact with CodeCommit on their EC2 server. In my opinion, this approach is not secure, as there is a risk of the key being leaked, and it is difficult to keep track of who has access to it. I believe a more secure and transparent approach should be adopted to ensure better security.&lt;/p&gt;

&lt;p&gt;My client might be one of many using this method to interact with CodeCommit. Therefore, I wrote a tutorial to help others secure their repository interactions.&lt;/p&gt;

&lt;p&gt;While I suggest going through the tutorial to consolidate your knowledge, you can also see the entire process through the numerous screenshots I have provided to make the tutorial more straightforward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-Account CodeCommit Access from EC2
&lt;/h2&gt;

&lt;p&gt;To complete this tutorial, we need to create certain resources in two AWS accounts. In Account A, we need to create an IAM role and a CodeCommit repository. In Account B, we need to create an IAM policy, an IAM role, and an EC2 instance.&lt;/p&gt;

&lt;p&gt;Additionally, after completing the tutorial, it's recommended to delete these resources to avoid unnecessary AWS charges.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create an IAM role in Account A
&lt;/h3&gt;

&lt;p&gt;Let's start by creating the first role. Go to the console and search for &lt;strong&gt;Identity and Access Management&lt;/strong&gt;. Then, select &lt;strong&gt;Roles&lt;/strong&gt; from the left-hand menu and click &lt;strong&gt;Create Role&lt;/strong&gt;. This time, we will allow a different account to use our role from Account A. Therefore, we will choose &lt;strong&gt;AWS Account&lt;/strong&gt; as the use case. In the section below, select &lt;strong&gt;Another AWS Account&lt;/strong&gt; and provide the account ID.&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%2Fafnty6lmnhv3vak0xidy.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%2Fafnty6lmnhv3vak0xidy.png" alt="A step-by-step guide showing the initial phase of creating a new role in the AWS Management Console, starting with selecting the appropriate use case from the list provided." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Afterward, click &lt;strong&gt;Next&lt;/strong&gt; and attach the &lt;strong&gt;AWSCodeCommitReadOnly&lt;/strong&gt; permission. This will ensure that the other account can't push any changes to our repository.&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%2F1vddaxfl5zuptfj3rrfo.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%2F1vddaxfl5zuptfj3rrfo.png" alt="A step-by-step guide showing the second step of creating a new role in the AWS Management Console, highlighting the permissions selection process for role configuration." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, name the role &lt;strong&gt;account_a_cross_account_role&lt;/strong&gt;. Scroll down and click &lt;strong&gt;Create Role&lt;/strong&gt;.&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%2Fiwr3ji1h9sxvuf4qsmdg.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%2Fiwr3ji1h9sxvuf4qsmdg.png" alt="A step-by-step guide showing the third step of creating a new role in the AWS Management Console, highlighting the role configuration details section." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! You have successfully created a role for cross-account access. Let's move on to the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create a policy in Account B
&lt;/h3&gt;

&lt;p&gt;It's time to switch to Account B. To proceed, let's create a policy first. Go to the console and search for &lt;strong&gt;Identity and Access Management&lt;/strong&gt;. From the left-hand menu, select &lt;strong&gt;Policies&lt;/strong&gt;, then create a policy.&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%2F9bflsdmif41qis0p5nt6.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%2F9bflsdmif41qis0p5nt6.png" alt="A step-by-step guide showing the initial phase of creating a new policy in the AWS Management Console, starting with selecting the appropriate service from the list provided." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select &lt;strong&gt;STS&lt;/strong&gt; from the service dropdown. In the actions section, we need to configure granular access. To do this, expand options under the Write access level and select the &lt;strong&gt;AssumeRole&lt;/strong&gt; option. &lt;/p&gt;

&lt;p&gt;Next, let's specify a resource under the resource section. Choose the specific option and click on &lt;strong&gt;Add ARNs&lt;/strong&gt;. Set the ARN of the role that we created in the previous step, which should look like &lt;code&gt;arn:aws:iam:123456789012:role/account_a_cross_account_role&lt;/code&gt;.&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%2Fe6dbl09n0nfgoqu61r40.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%2Fe6dbl09n0nfgoqu61r40.png" alt="A step-by-step guide showing the first step of creating a new policy in the AWS Management Console, highlighting the access level selection process for policy configuration." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate to the next screen and name the policy &lt;strong&gt;account_b_cross_account_access_policy&lt;/strong&gt;. &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%2Fduhxnxrjqdodppmo8eh2.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%2Fduhxnxrjqdodppmo8eh2.png" alt="A step-by-step guide showing the second step of creating a new policy in the AWS Management Console, highlighting the policy configuration details section." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Create an IAM role in Account B
&lt;/h3&gt;

&lt;p&gt;It's time to create a classic EC2 role and attach the policy we previously created. From the left-hand menu, select &lt;strong&gt;Roles&lt;/strong&gt; and then create a role. Ensure that &lt;strong&gt;AWS service&lt;/strong&gt; is selected. Next, select &lt;strong&gt;EC2&lt;/strong&gt; under &lt;strong&gt;Common Use Cases&lt;/strong&gt; and click &lt;strong&gt;Next&lt;/strong&gt;.&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%2Fs8j2pe8fwscgp6yzi6nk.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%2Fs8j2pe8fwscgp6yzi6nk.png" alt="A step-by-step guide showing the initial phase of creating a new role in the AWS Management Console, starting with selecting the appropriate use case from the list provided." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we will add the managed policy we previously created to our role. Search for &lt;strong&gt;account_b_cross_account_access_policy&lt;/strong&gt; and press "Enter". You will find the managed policy that provides the necessary permissions to assume the role from Account A on your EC2 instance. Select the policy and click &lt;strong&gt;Next&lt;/strong&gt;.&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%2Fqykmh5je75t97c0bfagr.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%2Fqykmh5je75t97c0bfagr.png" alt="A step-by-step guide showing the second step of creating a new role in the AWS Management Console, highlighting the permissions selection process for role configuration." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will name our role &lt;strong&gt;account_b_ec2_role&lt;/strong&gt;, and then scroll down to click the &lt;strong&gt;Create Role&lt;/strong&gt; button.&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%2Fw9k36gcwj70yo2cbgoad.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%2Fw9k36gcwj70yo2cbgoad.png" alt="A step-by-step guide showing the third step of creating a new role in the AWS Management Console, highlighting the role configuration details section." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Create a CodeCommit repository in Account A
&lt;/h3&gt;

&lt;p&gt;If you've completed the previous tutorial and haven't deleted the repo, you can skip this step. Otherwise, let's create a new repository. For this demo, I have created a repository named &lt;strong&gt;repository&lt;/strong&gt;.&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%2Foliuzhec0cqh4ypdstxj.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%2Foliuzhec0cqh4ypdstxj.png" alt="Screenshot of Amazon Web Services (AWS) Management Console displaying the 'Create new repository' form." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have created the repository, you'll see a screen with different connection options. We will use the recommended &lt;strong&gt;HTTPS (GRC)&lt;/strong&gt; method to support connections made with federated access, identity providers, and temporary credentials.&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%2Fzewtwdt5ra7flosna8s9.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%2Fzewtwdt5ra7flosna8s9.png" alt="Newly created empty AWS CodeCommit repository with three connection options: HTTPS, SSH, and HTTPS (GRC)." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To add content to the repository, we need to create a simple text file. Firstly, scroll down to the section that says "empty repository" and click on the center button that says &lt;strong&gt;Create File&lt;/strong&gt;.&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%2F9vl2x70zr7z0srs3pfhr.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%2F9vl2x70zr7z0srs3pfhr.png" alt="Empty AWS CodeCommit repository interface showcasing the 'Create file' button." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, put "Hello World!" as the content and "file.txt" as the file name to match the file created in the previous tutorial. You also must put your author name and email, and then click on &lt;strong&gt;Commit Changes&lt;/strong&gt; to complete the process.&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%2F0rn8iv9qmba442dffb3z.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%2F0rn8iv9qmba442dffb3z.png" alt="Screenshot of AWS Console with 'Create a file' form for CodeCommit repository." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all for this step. You can move on to the next one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Create an EC2 instance in Account B
&lt;/h3&gt;

&lt;p&gt;Let's move forward to the next step. We need to create an EC2 instance and name it &lt;strong&gt;account_b_instance&lt;/strong&gt;. We'll use Amazon Linux 2023, which is the perfect fit for our needs.&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%2F4eashm1r8bxm7k0a7knb.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%2F4eashm1r8bxm7k0a7knb.png" alt="Screenshot of AWS EC2 instance launch screen with instance name input box and a selection menu of operating systems featuring Amazon Linux among others." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Regarding hardware, we'll select the latest toys and choose an arm-based image. For our demo, t4g.nano is more than enough. This time, we'll proceed without a keypair.&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%2Fzfw4ewe6axdmsg84249t.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%2Fzfw4ewe6axdmsg84249t.png" alt="Screenshot of AWS EC2 instance launch screen displaying 'Instance Type' selection dropdown and 'Key Pair' field with 'Proceed without a Key Pair' option highlighted." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, expand the &lt;strong&gt;Advanced details&lt;/strong&gt; tab and select the IAM instance profile we created earlier.&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%2Ft68solya2k50dkybbqun.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%2Ft68solya2k50dkybbqun.png" alt="Screenshot of AWS EC2 instance launch screen with a highlighted instance profile field." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To ensure that we have all the necessary tools, we will install them with the User Data script. Here is the script we will use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
dnf install git -y
curl -O https://bootstrap.pypa.io/get-pip.py
python3 get-pip.py
pip install git-remote-codecommit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me explain what we'll do here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, we'll install git as we can't interact with our repository without it.&lt;/li&gt;
&lt;li&gt;We need to download PIP, which is a package manager for Python packages.&lt;/li&gt;
&lt;li&gt;After downloading, we'll install PIP.&lt;/li&gt;
&lt;li&gt;Finally, we'll install &lt;strong&gt;git-remote-codecommit&lt;/strong&gt; using pip.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a screenshot that shows how the field appears in the console.&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%2Fahajvlrm5luzehcs44h3.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%2Fahajvlrm5luzehcs44h3.png" alt="Screenshot of AWS EC2 instance launch screen with a highlighted User Data script field." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all we need to do. Let's wait for a moment while AWS creates an instance for us.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Connect to the instance and checkout files
&lt;/h3&gt;

&lt;p&gt;Once the instance is ready, let's proceed with the next steps. To connect through the console, switch to the EC2 console, where you will see a page similar to the screenshot below.&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%2Fi41vc4l13rd7o7ccfixt.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%2Fi41vc4l13rd7o7ccfixt.png" alt="Screenshot of Amazon Web Services (AWS) EC2 console dashboard displaying a list of running instances, their respective statuses, types, and key metrics." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the instance and click the &lt;strong&gt;Connect&lt;/strong&gt; button at the top right corner. Then, click &lt;strong&gt;Connect&lt;/strong&gt; again on the next screen.&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%2Fyodluul9hp169b9civoq.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%2Fyodluul9hp169b9civoq.png" alt="Screenshot of AWS Management Console showing the process of establishing a secure connection to an EC2 instance." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After logging in, we can start with the necessary actions. The first step is to set up a profile based on the assumed role from account A. You will need to replace the ARN of the role with your own ARN in the first line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws configure set role_arn arn:aws:iam::123456789012:role/account_a_cross_account_role --profile CodeAccess
aws configure set credential_source Ec2InstanceMetadata --profile CodeAccess
aws configure set role_session_name "code_access" --profile CodeAccess
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By following these commands, you will create a profile. There should be no output.&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%2Flgnb1yafz8yzwps7pdyh.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%2Flgnb1yafz8yzwps7pdyh.png" alt="Screenshot of a computer terminal showing the command line interface with a list of commands for creating a profile." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have created a profile, but tools like the CLI can't predict whether to use the default profile or any named profile you created, so you need to specify it if you don't want to use default. Let's try to list repositories. First, we will use a simple AWS CLI command without the profile parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws codecommit list-repositories
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we do not have permissions with the default role, this call will result in an error. However, we can specify the profile we created with the &lt;code&gt;--profile&lt;/code&gt; parameter, and the command will return our repository from account A. So let's try that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws codecommit list-repositories --profile CodeAccess
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the result in the screenshot below if you don't want to follow along in your console.&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%2Fza6bwca8c6b2s3gprtwe.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%2Fza6bwca8c6b2s3gprtwe.png" alt="Screenshot of a terminal displaying a list of repositories retrieved using the AWS CLI command." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have confirmed that we have access to the repository in Account A, and now it's time to check it out. To do this, we need to specify the profile for git-remote-codecommit. You can find the documentation for this process &lt;a href="https://github.com/aws/git-remote-codecommit" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Let's attempt to run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone codecommit::us-east-1://CodeAccess@repository
&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%2F1ryp042cwyxl0i0p99z2.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%2F1ryp042cwyxl0i0p99z2.png" alt="Screenshot showing successful Git checkout command output in terminal." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have successfully checked out the repository. Now, let's test our read-only permissions. We will attempt to modify the file and push the changes. These are the steps we need to follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd repository/
nano file.txt
git add file.txt
git commit -m "Second release of Hello World!"
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me explain the commands above in detail. Firstly, go to the "repository" directory. Once you're there, use a text editor such as Nano or any other editor you prefer to make changes to the file. After making the changes, add the modified file to Git. Then, create a new commit and push the changes to the repository.&lt;/p&gt;

&lt;p&gt;However, we encountered a 403 error due to our limited read-only permissions.&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%2Fwkfyq9ilj81kj38yj7lt.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%2Fwkfyq9ilj81kj38yj7lt.png" alt="Screenshot showing a 403 Forbidden Error message, resulting from an attempted 'git push' command in a terminal without the necessary write permissions, indicating the user does not have authorization to push changes to the git repository." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you need to push changes from a different account, you can jump to Account A and replace the &lt;strong&gt;AWSCodeCommitReadOnly&lt;/strong&gt; policy with &lt;strong&gt;AWSCodeCommitFullAccess&lt;/strong&gt; for the &lt;strong&gt;account_a_cross_account_role&lt;/strong&gt; role to grant full access.&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%2Fb1gwr2sqib5r4r7juiql.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%2Fb1gwr2sqib5r4r7juiql.png" alt="Screenshot of AWS IAM console showing the policy change process from AWSCodeCommitReadOnly to AWSCodeCommitFullAccess, enabling a user to gain full access permissions to push changes to a CodeCommit repository." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And push the changes after that without any errors.&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%2Fva8gcd8nz3qrjwjihze6.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%2Fva8gcd8nz3qrjwjihze6.png" alt="Screenshot of a computer terminal displaying the successful execution of a 'git push' command." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons learned
&lt;/h2&gt;

&lt;p&gt;I hope you found the article about accessing a CodeCommit repository from a different account using git-remote-codecommit helpful. Perhaps you even learned something new!&lt;/p&gt;

&lt;p&gt;To summarize, you now have the skills to securely access a CodeCommit repository from a different account using the recommended approach. Additionally, you have learned how to create roles for cross-account access, which is quite useful.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed reading the article and gained valuable insights from it. If you found it helpful, please feel free to share, ask questions, or share your thoughts. Let's continue the conversation. Until next time, happy coding!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>tutorial</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>CodeCommit Access from EC2</title>
      <dc:creator>Anton Poriadin</dc:creator>
      <pubDate>Mon, 23 Oct 2023 20:10:31 +0000</pubDate>
      <link>https://forem.com/aporiadin/codecommit-access-from-ec2-2h8j</link>
      <guid>https://forem.com/aporiadin/codecommit-access-from-ec2-2h8j</guid>
      <description>&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;
CodeCommit Access from EC2

&lt;ul&gt;
&lt;li&gt;Step 1: Create an IAM role&lt;/li&gt;
&lt;li&gt;Step 2: Create a CodeCommit repository&lt;/li&gt;
&lt;li&gt;Step 3: Create an EC2 instance&lt;/li&gt;
&lt;li&gt;Step 4: Connect to the instance and commit a file&lt;/li&gt;
&lt;li&gt;Step 5: Check the file in the CodeCommit console&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Lessons learned&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this two-part series, I will show you how to access an &lt;a href="https://aws.amazon.com/codecommit/" rel="noopener noreferrer"&gt;AWS CodeCommit&lt;/a&gt; repository using &lt;a href="https://github.com/aws/git-remote-codecommit" rel="noopener noreferrer"&gt;git-remote-codecommit&lt;/a&gt;. The first part focuses on accessing a repository from the same account, while the second covers accessing a repository from a different account.&lt;/p&gt;

&lt;p&gt;While working on a project, I came across a situation where a client was using SSH keys to interact with CodeCommit on their EC2 server. In my opinion, this approach is not secure, as there is a risk of the key being leaked, and it is difficult to keep track of who has access to it. I believe a more secure and transparent approach should be adopted to ensure better security.&lt;/p&gt;

&lt;p&gt;My client might be one of many using this method to interact with CodeCommit. Therefore, I wrote a tutorial to help others secure their repository interactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  CodeCommit Access from EC2
&lt;/h2&gt;

&lt;p&gt;In order to complete this tutorial, we will need to create a few resources: an IAM role, a CodeCommit repository, and an EC2 instance. It's important to note that these resources should all be created within the same AWS account. Additionally, after completing the tutorial, it's recommended to delete these resources to avoid unnecessary AWS charges.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create an IAM role
&lt;/h3&gt;

&lt;p&gt;To get started, we need to create a role. Go to IAM Roles and click &lt;strong&gt;Create role&lt;/strong&gt;. Under the Trusted entity type section, select &lt;strong&gt;AWS Service&lt;/strong&gt;. Since we'll be using EC2, select it as a use case.&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%2Fgprfm8psmronj1oz5pas.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%2Fgprfm8psmronj1oz5pas.png" alt="The process of creating a role. Step 1: Selecting a use case." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next screen will require us to add a policy. We need to select &lt;strong&gt;AWSCodeCommitFullAccess&lt;/strong&gt; for demo purposes as we want to commit a file. However, on a real server, choosing &lt;strong&gt;AWSCodeCommitReadonly&lt;/strong&gt; or even a stricter role is recommended to stick to the &lt;a href="https://en.wikipedia.org/wiki/Principle_of_least_privilege" rel="noopener noreferrer"&gt;principle of least privilege&lt;/a&gt;.&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%2Fc7pkatrn8ssdtpdl32w6.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%2Fc7pkatrn8ssdtpdl32w6.png" alt="The process of creating a role. Step 2: Adding permissions." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To keep things simple, name the role &lt;strong&gt;account_a_ec2_role&lt;/strong&gt;. Scroll down and click &lt;strong&gt;Create Role&lt;/strong&gt;.&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%2Fiyf1zljfedpsf7nws8au.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%2Fiyf1zljfedpsf7nws8au.png" alt="The process of creating a role. Step 3: Defining role details." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perfect! This is all we need for this role. Now, let's move on to the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create a CodeCommit repository
&lt;/h3&gt;

&lt;p&gt;To keep things simple for the demo, I have created a repository named &lt;strong&gt;repository&lt;/strong&gt;, which perfectly describes its purpose.&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%2Fw9zbf8kpcjmuh9mj49f2.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%2Fw9zbf8kpcjmuh9mj49f2.png" alt="The process of creating a repository" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating the repository, you'll see a screen with various connection options. We will be using the third option, which is &lt;strong&gt;HTTPS (GRC)&lt;/strong&gt;. According to AWS, this is the recommended method for supporting connections made with federated access, identity providers, and temporary credentials.&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%2F075qlvwfwumm1me46koq.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%2F075qlvwfwumm1me46koq.png" alt="Overview of various connection methods" width="800" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all for this step. We can move on to the next one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Create an EC2 instance
&lt;/h3&gt;

&lt;p&gt;Let's move on to the next step, which is the most interesting one. We need to create an EC2 instance and name it &lt;strong&gt;account_a_instance&lt;/strong&gt;. We just want to keep the naming simple. We'll go with Amazon Linux 2023, which works great for us.&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%2Fya0bf8bvhu4l1ybfcdmk.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%2Fya0bf8bvhu4l1ybfcdmk.png" alt="The process of creating an instance. Setting a name for the instance." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Regarding hardware, we'll select the latest toys and choose an arm-based image. For our demo, t4g.nano is more than enough. This time, we'll proceed without a keypair.&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%2F8gpe7mbf1bck6jnclbe4.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%2F8gpe7mbf1bck6jnclbe4.png" alt="The process of creating an instance. Setting an instance type." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's expand the advanced details tab and select the IAM instance profile we created earlier.&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%2Ftevxzqw1im1vm6b0ynud.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%2Ftevxzqw1im1vm6b0ynud.png" alt="The process of creating an instance. Setting an instance profile." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make sure we have all the necessary tools, we'll install them with the User Data script. Here is the script we'll use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
dnf install git -y
curl -O https://bootstrap.pypa.io/get-pip.py
python3 get-pip.py
pip install git-remote-codecommit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me explain what we'll do here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, we'll install git as we can't interact with our repository without it.&lt;/li&gt;
&lt;li&gt;We need to download PIP, which is a package manager for Python packages.&lt;/li&gt;
&lt;li&gt;After downloading, we'll install PIP.&lt;/li&gt;
&lt;li&gt;Finally, we'll install "git-remote-codecommit" using pip.&lt;/li&gt;
&lt;/ol&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%2F7zq0edyi9y1yne55bu7m.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%2F7zq0edyi9y1yne55bu7m.png" alt="The process of creating an instance. Setting a User Data script." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all we need to do. Let's wait for a moment while AWS creates an instance for us.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Connect to the instance and commit a file
&lt;/h3&gt;

&lt;p&gt;When the instance is ready, let's continue. To connect through the console, switch to the EC2 console, where you see something like the image below.&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%2Fyo4u4k0d5o5mnr27n6so.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%2Fyo4u4k0d5o5mnr27n6so.png" alt="EC2 console" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the instance and click the &lt;strong&gt;Connect&lt;/strong&gt; button located at the top right section with buttons. Then click &lt;strong&gt;Connect&lt;/strong&gt; again on the next screen.&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%2Fdp7gykuct1y713z00hek.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%2Fdp7gykuct1y713z00hek.png" alt="Establish a connection with an instance" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see something like the image below once you have successfully connected to the 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%2Fpa1slbt892vwuvtkve94.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%2Fpa1slbt892vwuvtkve94.png" alt="EC2 Instance Connect console" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the first step, let's check out the repository. Open the tab with the repository if it's still open, or go to CodeCommit and select our repository. You basically need to copy a command from the bottom of the &lt;strong&gt;HTTPS (GRC)&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;An example command from my console would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone codecommit::us-east-1://repository
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this command on the instance. The output will say&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cloning into 'repository'...
warning: You appear to have cloned an empty repository.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is perfectly fine since it's an empty repository, and we will commit our first file in a few steps.&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%2Fdzpg72ji7b3cmqfdfjbn.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%2Fdzpg72ji7b3cmqfdfjbn.png" alt="Cloning the repository" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's type a few more commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd repository/
echo 'Hello World!' &amp;gt; file.txt
git add file.txt
git commit -m "First release of Hello World!"
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we need to go to the directory with our repository. Then, we want to create a file that contains the string "Hello World!" Next, we add the file to git, create a commit and push the changes. If everything runs successfully, you will see output that looks like the image below.&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%2Fwo8cqsy9xjerfub7lubq.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%2Fwo8cqsy9xjerfub7lubq.png" alt="Committing to the repository" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This way we created a file and committed it to the repo. Let's jump to the final step of this quick demo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Check the file in the CodeCommit console
&lt;/h3&gt;

&lt;p&gt;Open the tab with our repository where you found the connection instructions earlier and refresh the page.&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%2Fhfxe8pieao4h9g9ud6xs.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%2Fhfxe8pieao4h9g9ud6xs.png" alt="Checking the repository via the AWS console" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see the file we created on our EC2 instance. This indicates that we can access our repository without using long-term personal credentials.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons learned
&lt;/h2&gt;

&lt;p&gt;I hope you found the article on accessing a CodeCommit repository using git-remote-codecommit helpful. Perhaps you even learned something new.&lt;/p&gt;

&lt;p&gt;To sum up, you now have the skills to enable secure access to CodeCommit from your computing resources. In my experience, I haven't come across a project where using personal or long-term credentials was advantageous.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed reading this article and gained valuable insights from it. Feel free to share it, ask questions, or share your thoughts if you found it helpful. Let's continue the conversation. Until next time, happy coding!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>tutorial</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>The Magical City Behind the NAT Gateway: An AWS Adventure</title>
      <dc:creator>Anton Poriadin</dc:creator>
      <pubDate>Wed, 12 Jul 2023 22:39:42 +0000</pubDate>
      <link>https://forem.com/aporiadin/the-magical-city-behind-the-nat-gateway-an-aws-adventure-475o</link>
      <guid>https://forem.com/aporiadin/the-magical-city-behind-the-nat-gateway-an-aws-adventure-475o</guid>
      <description>&lt;p&gt;This article is inspired by a brilliant &lt;a href="https://start.jcolemorrison.com/aws-vpc-core-concepts-analogy-guide/" rel="noopener noreferrer"&gt;article&lt;/a&gt; I came across a few years ago. Since then, it has become a cornerstone of my recommendations, as it beautifully illustrates the core &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html" rel="noopener noreferrer"&gt;AWS Virtual Private Cloud (VPC)&lt;/a&gt; concepts.&lt;/p&gt;

&lt;p&gt;Each project's infrastructure functions like a living organism — constantly evolving, expanding, and adapting to accommodate distinct needs throughout its lifecycle. This dynamic character of project infrastructure represents a reality we often overlook.&lt;/p&gt;

&lt;p&gt;This post delves into a &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html" rel="noopener noreferrer"&gt;Network Address Translation (NAT) gateway&lt;/a&gt; and attempts to illustrate various infrastructure configurations across projects of varying scales. To help illustrate this concept, we will use a whimsical analogy of a magical city.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a NAT gateway?
&lt;/h2&gt;

&lt;p&gt;In simple terms, a NAT gateway is a service that helps your resources in a private subnet of your VPC communicate with the internet.&lt;/p&gt;

&lt;p&gt;When you create a VPC in AWS, you can have both public and private subnets. The public subnets can directly access the internet, but the private subnets are isolated and can't directly connect to the internet. This is where the NAT Gateway comes into play.&lt;/p&gt;

&lt;h2&gt;
  
  
  The City
&lt;/h2&gt;

&lt;p&gt;Imagine a vast, bustling, and magical city. This city is akin to your private subnets in AWS. This city's buildings, parks, and roads represent your EC2 instances, database services, application services, and other resources you're running within your subnet. Each distinct area in the city is like a different availability zone. Some zones may be residential, some commercial, some industrial, and others purely magical – in AWS, these could represent different application tiers or functions like web servers, application servers, and databases.&lt;/p&gt;

&lt;p&gt;For sure, we want to protect our magical city from unwanted visitors - those from the outer world who may mean harm or disruption. This is where the castle walls with magical portals to the external world or the NAT gateway come into the picture. These walls and portals prevent strangers (unsolicited inbound traffic) from entering the city directly while allowing the residents (private subnet resources) to go outside and return safely (outbound internet access). It ensures only authorized entities can get in, like knights returning from a quest.&lt;/p&gt;

&lt;p&gt;Certainly, as our city's architects and overseers, predicting its growth and expansion will be an enthralling journey. Like a living, breathing entity, the city will evolve, with new districts emerging, the city walls expanding, and the population growing. We'll face unexpected challenges. Let's gear up for this adventure, because with every sunrise, our magical city holds a promise of novel experiences and learning opportunities. I bet it's going to be an exciting ride, don't you?&lt;/p&gt;

&lt;h2&gt;
  
  
  Village (Single NAT Gateway)
&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%2Frcnka76fp5fm6f3o0bqo.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%2Frcnka76fp5fm6f3o0bqo.png" alt="Single NAT Gateway" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole city is surrounded by a wall and there is only one magical portal to the outside world. All the traffic from the different districts has to pass through this portal to reach the world beyond.&lt;/p&gt;

&lt;p&gt;Using a single portal for your magical city can have its advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost Saving:&lt;/strong&gt; Maintaining one portal is less expensive than having multiple ones. After all, each portal requires its own magic (or in real terms, more resources) to function and keep it safe, right?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplicity:&lt;/strong&gt; One portal, one spell. It's easier to manage and less complicated to maintain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security and Control:&lt;/strong&gt; A single point of entry and exit allows the city's guardians to effectively monitor, filter, and control what comes in and out of the city.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, this one magical portal also carries potential risks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A single point of failure:&lt;/strong&gt; What if the magic fails or the guardians are distracted by a dragon attack? Well, then nobody can get in or out of the city. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bottleneck:&lt;/strong&gt; If your city grows and more people need to use the portal, it could lead to delays and frustrated citizens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This setup is ideal for new projects. It's essential to be aware of potential risks, but remember, this is likely the most cost-effective arrangement in the initial stages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Town (One NAT Gateway per availability zone)
&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%2Fm2lccjcbzu7iy3n2370o.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%2Fm2lccjcbzu7iy3n2370o.png" alt="One NAT Gateway per availability zone" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our city is flourishing and growing larger. We need to account for its ability to manage challenges like increased traffic or potential disruptions in any of the districts. Currently, each district has its own portal for reaching the outside world. This allows traffic from each area to flow easily through its specific gateway and access what lies beyond.&lt;/p&gt;

&lt;p&gt;Here's why this might be a good idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved Redundancy and Resilience:&lt;/strong&gt; If one portal is under a troll attack, the other portals aren't affected and can keep functioning. This reduces the risk of the whole city getting cut off from the outside world.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;High Availability:&lt;/strong&gt; With each district having its own portal, there's no worry if one portal goes down due to a curse or magical mishap. The other districts remain unaffected, and the citizens can continue their journey to and from the outside world.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Better Scalability:&lt;/strong&gt; With multiple portals, you effectively spread out the traffic, preventing any one portal from getting overcrowded. This helps avoid traffic jams and keeps everything moving smoothly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, just as with everything in magic and technology, there are trade-offs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased Cost:&lt;/strong&gt; More portals mean more magic, and more magic means more cost. You'll need to factor this into your city's treasury.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Management Complexity:&lt;/strong&gt; Each portal needs its own team of wizards for maintenance and its own set of security spells, which means more things to manage and keep track of.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security Challenges:&lt;/strong&gt; Having multiple access points requires diligent monitoring and security measures to prevent any dark forces from entering the city.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This stage effectively addresses the issues highlighted in the previous setup. Most projects maintain this arrangement for their entire lifespan. Although there's an additional cost involved, it successfully resolves all fundamental challenges. Therefore, it's a worthwhile stage for handling production workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  City (One NAT Gateway per subnet)
&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%2F8wmiuvg508pdyj3gzxnj.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%2F8wmiuvg508pdyj3gzxnj.png" alt="One NAT Gateway per subnet" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the twist: every neighborhood has its own portal. That means all the traffic from such neighborhood can independently zip through its own portal to reach the world beyond.&lt;/p&gt;

&lt;p&gt;Here's why having one NAT Gateway per subnet could be beneficial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance:&lt;/strong&gt; Each neighborhood managing its own traffic through a dedicated portal can help prevent congestion and ensure smooth data flow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability:&lt;/strong&gt; As your city grows, new neighborhoods with their own portals can be added. This means your city's capacity to handle traffic can increase as needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficiency:&lt;/strong&gt; Each portal only handles the traffic for its neighborhood, which can increase efficiency as traffic patterns can be more predictable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yet, we're faced with similar trade-offs, but they bear even more significance now.&lt;/p&gt;

&lt;p&gt;This stage could be particularly relevant for projects with heavy loads. It does offer performance enhancement. Here, your project is already up and running, and your primary goal is to ensure it operates as smoothly as possible. Your chief concern should be the quality of your service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;To wrap things up, let's think back to our magic city, a city that, like our project, started small and had a single protective wall and one magical portal. But as the city grew, it needed more protective barriers and magical gateways. This is much like the evolution of a project's infrastructure, beginning with one NAT gateway and eventually scaling up to have individual NAT gateways for high-loaded subnets.&lt;/p&gt;

&lt;p&gt;Our small, charming city once had only one wall and a magic portal that met everyone's needs. It's just like when a project is new; one NAT gateway can manage all the internet traffic for private subnets. But as our city got bigger and more people and areas needed to use the magic door, it became clear that one door just wouldn't be enough. This is where the idea of staying strong, or resilience, becomes important.&lt;/p&gt;

&lt;p&gt;Imagine if the only magical portal in the city was blocked or failed for some reason. The whole city would be stuck, unable to move in or out. It's the same with a project. If the only NAT gateway in a project breaks down, it could cause big problems. So, having more magic doors, like having multiple NAT gateways, helps manage the increased flow of people and adds a layer of resilience. If one portal fails, there are other doors people can use. This is key to maintaining smooth operations and protecting the city, or project, from unexpected problems.&lt;/p&gt;

&lt;p&gt;As city planners carefully choose where to put extra walls and doors, we must also be wise about our project setup. It might be easy to follow a simple guide and use one NAT gateway for the whole project. But, we should always make sure our infrastructure fits our current needs and consider possible risks.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this journey with me. Feel free to share it, leave your thoughts, or ask questions if you found it helpful. Let's keep the conversation going. Until next time, happy coding!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Host a Secure Static Website using AWS S3 and CloudFront</title>
      <dc:creator>Anton Poriadin</dc:creator>
      <pubDate>Sun, 09 Jul 2023 19:11:32 +0000</pubDate>
      <link>https://forem.com/aporiadin/how-to-host-a-secure-static-website-using-aws-s3-and-cloudfront-mgc</link>
      <guid>https://forem.com/aporiadin/how-to-host-a-secure-static-website-using-aws-s3-and-cloudfront-mgc</guid>
      <description>&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;
How to host a static website in a secure way

&lt;ul&gt;
&lt;li&gt;Step 1: Create static website&lt;/li&gt;
&lt;li&gt;Step 2: Create S3 bucket&lt;/li&gt;
&lt;li&gt;Step 3: Upload our website to S3&lt;/li&gt;
&lt;li&gt;Step 4: Create CloudFront Distribution&lt;/li&gt;
&lt;li&gt;Step 5: Update bucket policy&lt;/li&gt;
&lt;li&gt;Step 6: Let’s check our site&lt;/li&gt;
&lt;li&gt;Step 7: Create custom error documents&lt;/li&gt;
&lt;li&gt;Step 8: Get real 404&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Lessons Learned&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this easy-to-follow guide, I will show you how to put your static website on the internet using Amazon's S3 and CloudFront. We'll keep things secure, sticking to a blend of best practices and AWS recommendations. We'll cover the basics and also get into some of the details, making it simple for you to host your website. Let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to host a static website in a secure way
&lt;/h2&gt;

&lt;p&gt;In order to finish this tutorial, we need to create an S3 bucket and a CloudFront distribution. We will also explore the bucket policies and Origin Access Control (OAC). Once you're done with the tutorial, deleting these resources is a good idea to avoid unnecessary AWS charges.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create static website
&lt;/h3&gt;

&lt;p&gt;To host a static website, we need to do a few things before we can get started. We must create it first. Don't worry. Creating a static site can be complicated, but we'll keep things simple.&lt;/p&gt;

&lt;p&gt;To begin, we'll start with some basic HTML. We don't want to go into too much detail at this point. Let's focus on just a few files that are essential for now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.html&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;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=en&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=utf-8&amp;gt;
    &amp;lt;title&amp;gt;index&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;403.html&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;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=en&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=utf-8&amp;gt;
    &amp;lt;title&amp;gt;403&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;403&amp;lt;/h1&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;404.html&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;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=en&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=utf-8&amp;gt;
    &amp;lt;title&amp;gt;404&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;404&amp;lt;/h1&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Create S3 bucket
&lt;/h3&gt;

&lt;p&gt;Let's begin by navigating to the AWS Management Console. Take advantage of the search box positioned at the top of the screen for a faster route. By typing in "S3", you can quickly locate the S3 service amidst the numerous services AWS offers.&lt;/p&gt;

&lt;p&gt;Before we delve into creating a new S3 bucket, it's essential to remember a couple of crucial points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Each S3 bucket must be created in a specific geographical region. This region can be chosen based on factors such as data governance requirements, proximity to the majority of your users, or cost.&lt;/li&gt;
&lt;li&gt;Each bucket name must be globally unique across all existing bucket names in Amazon S3. This is because the bucket namespace is shared by all AWS accounts worldwide. Therefore, it's a good idea to devise a unique name that relates to its purpose.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this walkthrough, I've opted for the name "one-more-secure-website". This name encapsulates the purpose of our bucket - to hold assets for a secure website - and also adheres to the requirement of global uniqueness. Now, we're ready to create our S3 bucket using this name.&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%2Fe9bgrp39x94bzexijw53.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%2Fe9bgrp39x94bzexijw53.png" alt="S3 bucket creation screen" width="800" height="979"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now adjust various settings, including versioning, server-side encryption, and access permissions. However, you can leave these settings at their default values for this tutorial. Remember, these configurations can be modified later if required.&lt;/p&gt;

&lt;p&gt;Once you're satisfied with the settings, finalize the process by clicking on the "Create bucket" button at the bottom of the page. Your new bucket should now be successfully created in your designated AWS region.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Upload our website to S3
&lt;/h3&gt;

&lt;p&gt;We need to move some files to a place called an S3 bucket. You can do this two ways: using the AWS Management Console or running commands from your computer using CLI or Command-Line Interface.&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%2Ffph78qbej1nmvwv66ybq.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%2Ffph78qbej1nmvwv66ybq.png" alt="Files successfully uploaded to S3 bucket" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're okay with typing commands, it's pretty easy. Keep in mind that you need to install the AWS CLI in order to use it. For example, if you have a file called "index.html" and you want to put it in your bucket, you'd type something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws s3 cp index.html s3://{bucket}/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Create CloudFront Distribution
&lt;/h3&gt;

&lt;p&gt;This is the most exciting part. You might have noticed that we haven't made any changes to the S3 settings, yet we still want to host a static website. The reason is that CloudFront has all the necessary features to accomplish that.&lt;/p&gt;

&lt;p&gt;Open up the AWS console, the control panel for all Amazon's tools. Type "CloudFront" in the search box on top. It'll take you right to the CloudFront tool.&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%2Fzls1d57kca63eklvdi7y.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%2Fzls1d57kca63eklvdi7y.png" alt="Amazon CloudFront welcome screen" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's a button that says "Create a CloudFront distribution". Click it. This will start the process of setting up how your website data gets sent out.&lt;/p&gt;

&lt;p&gt;You'll be asked to select your "origin domain". That's where your website data is coming from - in our case, it's our S3 bucket, the storage space we mentioned earlier.&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%2Fp3brz5vq99ybi4b18es5.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%2Fp3brz5vq99ybi4b18es5.png" alt="CloudFront Distribution creation screen" width="800" height="979"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Look for the "Origin access control settings" area. Go for the "Origin access control settings (recommended)" option and click "Create control setting". It's okay to stick with what's already there, no need to change anything. Then click "Create".&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%2Ftfr3t9tbru1v8skk56i4.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%2Ftfr3t9tbru1v8skk56i4.png" alt="The Origin Access Control Creation Form" width="800" height="810"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we have to sort out the "Default cache behavior". This is how CloudFront stores and sends your website data. Make sure you change "Viewer protocol policy" to "Redirect HTTP to HTTPS". That's just a fancy way of saying it makes sure anyone visiting your site has a secure connection. Leave everything else as it is.&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%2Feicn4mh58x6bsduijudq.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%2Feicn4mh58x6bsduijudq.png" alt="Default cache behavior" width="800" height="979"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll see a "Web Application Firewall (WAF)" section. We're going to skip it, so select "Do not enable security protections".&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%2Fh1guvyepitujthwwdc14.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%2Fh1guvyepitujthwwdc14.png" alt="Web Application Firewall settings" width="800" height="979"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Almost there! In the "Settings" part at the bottom, make sure the "Default root object" says "index.html". That's just telling CloudFront what to show when someone visits your website.&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%2Fm7iwj279d8j5055secdk.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%2Fm7iwj279d8j5055secdk.png" alt="General CloudFront settings" width="800" height="979"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To finish off, scroll down and click "Create distribution". And there you go! You've set up how your website gets sent to viewers with CloudFront.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Update bucket policy
&lt;/h3&gt;

&lt;p&gt;After setting things up, you'll get two messages from AWS. The first one basically says, "Good job! You've created the distribution successfully!" The second one suggests you update your S3 bucket policy, which is like a set of rules for your S3 bucket. This update is needed so CloudFront can read what's in your S3 bucket.&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%2Fs50ydyeamqwyjrhdmsrz.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%2Fs50ydyeamqwyjrhdmsrz.png" alt="CloudFront Distributions screen displays 2 messages: one confirming successful distribution creation, the second advising an S3 bucket policy update" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's how to do that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Look for and click on the "Copy Policy" button, then click on the "Go to S3 bucket permissions to update policy" button. When you click this, it'll take you directly to your S3 bucket's permissions tab.&lt;/li&gt;
&lt;li&gt;Find the "Bucket Policy" section and click "Edit". You'll see a field where you can paste the policy you got earlier.&lt;/li&gt;
&lt;li&gt;After inserting the policy, hit "Save changes" to lock in these new rules.&lt;/li&gt;
&lt;/ol&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%2Fdi0vmxn2oqsorn0no7nf.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%2Fdi0vmxn2oqsorn0no7nf.png" alt="S3 bucket policy enabling CloudFront distribution access to files" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once that's done, you'll have to wait a bit. The CloudFront distribution is getting ready, which is like preparing your content for delivery. You've created a strong base for hosting a safe, static site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Let’s check our site
&lt;/h3&gt;

&lt;p&gt;To check out the site we've set up, copy the distribution domain we've given and put it into browser's address bar. Upon opening it, you should see our index page.&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%2Frhrdu4xhovci1rbatldl.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%2Frhrdu4xhovci1rbatldl.png" alt="CloudFront distribution's domain displaying our index.html" width="800" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also try typing in the address without the "https://" part at the beginning, just using "http://" instead. If you do this, don't worry, CloudFront will automatically guide you to the secure version of the site (the one starting with "https://"). You might notice a message saying "301 Moved Permanently", that just means CloudFront moved you to the secure page, which is a good thing!&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%2Fp22fv72hoghw7mpm3x93.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%2Fp22fv72hoghw7mpm3x93.png" alt="A request was made to our CloudForm Distribution domain, which resulted in a 301 redirect from the HTTP version to the HTTPS version" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Create custom error documents
&lt;/h3&gt;

&lt;p&gt;Imagine you've got a bucket and it only contains three files: an index, a "403" item, and a "404" item. Now, pretend you're looking for something that isn't there, like a document called "another.html". You'd probably expect to be told, "Sorry, can't find that" – or in internet language, you'd expect a '404 error'. Let's check if that's what actually happens.&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%2Fgj3s1gtmxbagfe4nvbm9.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%2Fgj3s1gtmxbagfe4nvbm9.png" alt="A request to a missing file that displays an XML error message stating AccessDenied with error code 403" width="800" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oops! Instead of a simple "can't find that" message, we get a weird XML document and a 403 error. A bit strange, huh? You'd think we'd get a 404 error for something missing, not a 403 error. But let's not worry about that right now. Let's focus on making this whole thing less confusing for our users.&lt;/p&gt;

&lt;p&gt;First, click on the tab that says "Error Pages". Then select the option that says "Create custom error response", and fill in the information for the 403 error. Hit the Save button when you're done.&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%2Fmhz3xlg0n4uuox2ift2h.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%2Fmhz3xlg0n4uuox2ift2h.png" alt="Custom error page form for CloudFront distribution" width="800" height="979"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, try to open "another.html" again. This time, you should see our custom error page instead of that strange XML. Much better, right?&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%2F9do46fm0k1sxh3j84bze.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%2F9do46fm0k1sxh3j84bze.png" alt="A request to a missing file that displays a custom error page with code 403" width="800" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: Get real 404
&lt;/h3&gt;

&lt;p&gt;Ever wondered why you sometimes get a 403 error from S3 when a file isn't found? It's because of security reasons.&lt;/p&gt;

&lt;p&gt;Amazon S3 gives you an "AccessDenied" error when you ask for a file that doesn't exist, and you don't have the permission to see all the files in that bucket. It's a neat way of keeping things private, as it doesn't let anyone know if the file you're looking for actually exists or not.&lt;/p&gt;

&lt;p&gt;So, what if we allow CloudFront to have the "s3:ListBucket" permission? This lets it see all the files in the bucket. Here's how you do it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the permissions tab of the S3 bucket.&lt;/li&gt;
&lt;li&gt;Find the statement that you pasted previously and copy it.&lt;/li&gt;
&lt;li&gt;Please make a copy of that statement, but change it slightly. First, change the action to allow "s3:ListBucket". Then, make sure you remove "/*" from the end of the resource name. This new permission should be given to the bucket itself, not its contents.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Original policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::one-more-secure-website/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::{account_number}:distribution/E3QFHDB3Z8A00A"
                }
            }
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modified version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::one-more-secure-website/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::{account_number}:distribution/E3QFHDB3Z8A00A"
                }
            }
        }, {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::one-more-secure-website",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::{account_number}:distribution/E3QFHDB3Z8A00A"
                }
            }
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you've done that and refresh the page, you'll see a different error message - "NoSuchKey". This means that CloudFront can now tell us when the file we're looking for isn't in our bucket.&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%2Funyjui6hnt7v7whf7bnz.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%2Funyjui6hnt7v7whf7bnz.png" alt="A request to a missing file that displays an XML error message stating NoSuchKey with error code 404" width="800" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To finish things off, let's add another custom error page for when a 404 error occurs. Once you've done that and refresh the page, you'll see our custom HTML message instead of the standard error message.&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%2Fzzzws5bqoukiedtou7c6.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%2Fzzzws5bqoukiedtou7c6.png" alt="A request to a missing file that displays a custom error page with code 404" width="800" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;I hope you've found this article about hosting a static website using S3 and CloudFront helpful and perhaps even learned something extra. Let's sum it all up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You now have the skills to host a website securely without leaning on the S3 static website feature and making a bucket public.&lt;/li&gt;
&lt;li&gt;Every architectural choice has its pros and cons. Navigating through the world of AWS, you might find many paths leading to the same destination. The obvious path isn't always the wisest.&lt;/li&gt;
&lt;li&gt;In this tutorial, we've crafted a simple infrastructure. While it doesn't cover all the aspects of a real-world project, like versioning, logs, or complex topics such as CORS, it gives you a solid foundation to build upon.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you enjoyed this journey with me. Feel free to share it, leave your thoughts, or ask questions if you found it helpful. Let's keep the conversation going. Until next time, happy coding!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>s3</category>
      <category>cloudfront</category>
      <category>security</category>
    </item>
  </channel>
</rss>
