<?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: David Omokhodion</title>
    <description>The latest articles on Forem by David Omokhodion (@nobleman97).</description>
    <link>https://forem.com/nobleman97</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%2F947671%2Fb7a13967-7755-46fe-a433-02f0b8300036.jpeg</url>
      <title>Forem: David Omokhodion</title>
      <link>https://forem.com/nobleman97</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nobleman97"/>
    <language>en</language>
    <item>
      <title>Stop Getting 'Access Denied': Fixing Cross-Account Access in AWS with IAM STS</title>
      <dc:creator>David Omokhodion</dc:creator>
      <pubDate>Tue, 03 Mar 2026 23:56:18 +0000</pubDate>
      <link>https://forem.com/nobleman97/stop-getting-access-denied-fixing-cross-account-access-in-aws-with-iam-sts-1d1m</link>
      <guid>https://forem.com/nobleman97/stop-getting-access-denied-fixing-cross-account-access-in-aws-with-iam-sts-1d1m</guid>
      <description>&lt;p&gt;If you've ever worked in a multi-account AWS environment, you've probably hit the dreaded &lt;code&gt;AccessDenied&lt;/code&gt; error when trying to access resources across accounts. Whether it's sharing data between dev and prod accounts, aggregating logs to a central security account, or enabling cross-team collaboration, cross-account access is essential—but it's also where many engineers struggle.&lt;/p&gt;

&lt;p&gt;In this post, I'll show you exactly how to implement secure cross-account resource access using &lt;strong&gt;AWS Identity &amp;amp; Access Management (IAM)&lt;/strong&gt; with &lt;strong&gt;AWS Security Token Service (STS)&lt;/strong&gt; with a real-world example: a Lambda function that tracks the International Space Station's location and stores the data in an S3 bucket in a different AWS account.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Have Terraform installed&lt;/li&gt;
&lt;li&gt;Have access to 2 AWS accounts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🏗️ The Architecture
&lt;/h2&gt;

&lt;p&gt;Here's what we're building:&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%2F8txamjff6phymwi0zdzs.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%2F8txamjff6phymwi0zdzs.png" alt="Cross-Account Architecture" width="672" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Account A&lt;/strong&gt; (Source):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lambda function that fetches ISS position data&lt;/li&gt;
&lt;li&gt;IAM execution role with permission to assume a role in Account B&lt;/li&gt;
&lt;li&gt;EventBridge trigger (runs every 5 minutes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Account B&lt;/strong&gt; (Target):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 bucket for storing ISS position logs&lt;/li&gt;
&lt;li&gt;IAM role that trusts Account A's Lambda role&lt;/li&gt;
&lt;li&gt;Policies granting S3 access to the trusted role&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Flow&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;EventBridge triggers Lambda in Account A&lt;/li&gt;
&lt;li&gt;Lambda calls &lt;code&gt;sts:AssumeRole&lt;/code&gt; to get temporary credentials for Account B&lt;/li&gt;
&lt;li&gt;Lambda uses temporary credentials to read/write to S3 bucket in Account B&lt;/li&gt;
&lt;li&gt;Lambda fetches ISS position from public API and appends it to a file pulled from s3&lt;/li&gt;
&lt;li&gt;Lambda pushes the update file back to s3&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🛠️ Let's Implement the Trust Chain
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Configure the Terraform Providers
&lt;/h3&gt;

&lt;p&gt;Configure you cli with credentials from account A. Then run &lt;code&gt;aws sts get-caller-identity&lt;/code&gt; to get your identity.&lt;br&gt;
e.g&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;"UserId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;redacted&amp;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;"Account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;redacted&amp;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;"Arn"&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:iam::&amp;lt;redacted&amp;gt;:user/nobleman"&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;Next, create a role (called terraform, for example) in account B. In its trust relationship, allow the previous identity to assume it.&lt;/p&gt;

&lt;p&gt;For example...&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="err"&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="err"&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;"Principal"&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;"AWS"&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;"arn:aws:iam::&amp;lt;redacted&amp;gt;:user/nobleman"&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;"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;"sts:AssumeRole"&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;Next, configure Terraform providers for both accounts like this...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 1.0.0"&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hashicorp/aws"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 6.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
  &lt;span class="c1"&gt;# role_arn is set in ~/.aws/config&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
  &lt;span class="nx"&gt;alias&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"account_b"&lt;/span&gt;

  &lt;span class="nx"&gt;assume_role&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;role_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:iam::${var.account_b_id}:role/terraform"&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;h3&gt;
  
  
  Step 2: Lambda's Execution Role (Account A)
&lt;/h3&gt;

&lt;p&gt;Next, create a role that Lambda can assume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Account A: Role that Lambda assumes&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s2"&gt;"cross_account_role"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"connect-to-bridge"&lt;/span&gt;
  &lt;span class="nx"&gt;assume_role_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_policy_document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2_assume_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Trust policy: Allow Lambda service to assume this role&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_policy_document"&lt;/span&gt; &lt;span class="s2"&gt;"ec2_assume_role"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;effect&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
    &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="nx"&gt;principals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Service"&lt;/span&gt;
      &lt;span class="nx"&gt;identifiers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lambda.amazonaws.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&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;What this means&lt;/strong&gt;: The Lambda service can wear this role like a badge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Grant Role Permission to Assume Cross-Account Role
&lt;/h3&gt;

&lt;p&gt;Now we give this role permission to assume another role in Account B:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Account A: Policy that allows assuming role in Account B&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_policy_document"&lt;/span&gt; &lt;span class="s2"&gt;"assume_cross_account_role"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;effect&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
    &lt;span class="nx"&gt;actions&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Role in Account B&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy_attachment"&lt;/span&gt; &lt;span class="s2"&gt;"ec2_assume_cross_account"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cross_account_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assume_cross_account_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&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;What this means&lt;/strong&gt;: "Hey Lambda role, you're allowed to assume the &lt;code&gt;access_s3_bucket&lt;/code&gt; role in Account B."&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: The Target Role in Account B
&lt;/h3&gt;

&lt;p&gt;Here's the role in Account B with the crucial trust policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Account B: Role that grants S3 access&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s2"&gt;"access_s3_bucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account_b&lt;/span&gt;  &lt;span class="c1"&gt;# Important: This is in Account B&lt;/span&gt;

  &lt;span class="nx"&gt;name&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"access-s3-bucket"&lt;/span&gt;
  &lt;span class="nx"&gt;assume_role_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_policy_document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allow_role_assumption_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Trust policy: Allow Account A's role to assume this role&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_policy_document"&lt;/span&gt; &lt;span class="s2"&gt;"allow_role_assumption_a"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;effect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;

    &lt;span class="nx"&gt;principals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AWS"&lt;/span&gt;
      &lt;span class="nx"&gt;identifiers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cross_account_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Account A role ARN&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;&lt;span class="p"&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;This is the key&lt;/strong&gt;: Account B explicitly trusts Account A's role. Without this trust relationship, the assume role call will fail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Grant S3 Permissions to the Account B Role
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_policy_document"&lt;/span&gt; &lt;span class="s2"&gt;"s3_bucket_access"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;effect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;

    &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"s3:PutObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"s3:DeleteObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"s3:ListBucket"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reporting-bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket_arn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"${module.reporting-bucket.s3_bucket_arn}/*"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy_attachment"&lt;/span&gt; &lt;span class="s2"&gt;"s3_bucket_access_attachment"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account_b&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_bucket_access&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&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;The complete trust chain&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;→ Lambda Service assumes Lambda Execution Role (Account A) 
→ Lambda Execution Role (Account A) assumes S3 Access Role (Account B) 
→ S3 Access Role (Account B) has permission to S3 Bucket (Account B)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  💻 The Lambda Implementation
&lt;/h2&gt;

&lt;p&gt;Now let's look at how the Lambda function uses STS to assume the cross-account role:&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;boto3&lt;/span&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;urllib3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&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="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Environment variables from Terraform
&lt;/span&gt;    &lt;span class="n"&gt;account2_role_arn&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ACCOUNT2_ROLE_ARN&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;bucket_name&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;BUCKET_NAME&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;bucket_region&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;BUCKET_REGION&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;object_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;iss_position.txt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 1: Assume the role in Account B using STS
&lt;/span&gt;    &lt;span class="n"&gt;sts_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;sts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;assumed_role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sts_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assume_role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;RoleArn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;account2_role_arn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;RoleSessionName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LambdaCrossAccountS3Access&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 2: Extract temporary credentials
&lt;/span&gt;    &lt;span class="n"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assumed_role&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Credentials&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 3: Create S3 client with temporary credentials
&lt;/span&gt;    &lt;span class="n"&gt;s3_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;s3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AccessKeyId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SecretAccessKey&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;aws_session_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SessionToken&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bucket_region&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 4: Read existing file from S3
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bucket_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;object_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;read&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;span class="c1"&gt;# Step 5: Fetch ISS position from public API
&lt;/span&gt;    &lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PoolManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&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="s"&gt;http://api.open-notify.org/iss-now.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&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;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromtimestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 6: Append new data
&lt;/span&gt;    &lt;span class="n"&gt;new_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Time: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
Latitude: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;iss_position&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="s"&gt;latitude&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
Longitude: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;iss_position&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="s"&gt;longitude&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 7: Write back to S3 using temporary credentials
&lt;/span&gt;    &lt;span class="n"&gt;s3_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bucket_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;object_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;new_content&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&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="s"&gt;Cross-account S3 access successful&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;p&gt;&lt;strong&gt;Key Points&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;sts_client.assume_role()&lt;/code&gt;&lt;/strong&gt;: This is where the magic happens. Lambda uses its execution role to request temporary credentials for the Account B role.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Temporary Credentials&lt;/strong&gt;: STS returns short-lived credentials (valid for 1 hour by default). These credentials have all the permissions of the assumed role.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Session Name&lt;/strong&gt;: The &lt;code&gt;RoleSessionName&lt;/code&gt; appears in CloudTrail logs, making it easier to audit who assumed the role and when.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Explicit Credential Usage&lt;/strong&gt;: We explicitly pass the temporary credentials to the S3 client. This is different from the default boto3 behavior which uses the Lambda's execution role.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  📦 Deployment
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two AWS accounts (A &amp;amp; B)&lt;/li&gt;
&lt;li&gt;AWS CLI configured with access to Account A&lt;/li&gt;
&lt;li&gt;Terraform &amp;gt;= 1.0&lt;/li&gt;
&lt;li&gt;A pre-existing &lt;code&gt;terraform&lt;/code&gt; role in Account B that Account A can assume&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Steps&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/nobleman97/cross-account-iam.git
&lt;span class="nb"&gt;cd &lt;/span&gt;cross-account-iam
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;dev.tfvars&lt;/code&gt; file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;account_b_id&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"123456789012"&lt;/span&gt;  &lt;span class="c1"&gt;# Replace with your Account B ID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Deploy the infrastructure:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;infra
terraform init
terraform plan &lt;span class="nt"&gt;-var-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev.tfvars
terraform apply &lt;span class="nt"&gt;-var-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev.tfvars
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Watch it work:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check Lambda logs&lt;/span&gt;
aws logs &lt;span class="nb"&gt;tail&lt;/span&gt; /aws/lambda/write-report-to-crossaccount-s3 &lt;span class="nt"&gt;--follow&lt;/span&gt;

&lt;span class="c"&gt;# After 5-10 minutes, check the S3 file in Account B&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;s3://iss-reporting-24534576df/iss_position.txt - &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--profile&lt;/span&gt; account-b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If setup properly, the file should look 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;ISS Location Logs
===================


Time: 2025-12-06 17:19:45
Latitude: -50.5587
Longitude: 122.1887

Time: 2025-12-06 17:29:07
Latitude: -32.9030
Longitude: 163.3656

...

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Common Pitfalls and Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Problem 1: "User is not authorized to perform: sts:AssumeRole"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cause&lt;/strong&gt;: The role in Account A doesn't have permission to assume the role in Account B.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Verify the policy attachment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws iam list-attached-role-policies &lt;span class="nt"&gt;--role-name&lt;/span&gt; connect-to-bridge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Problem 2: "AccessDenied" when accessing S3
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Causes&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The trust policy in Account B doesn't trust Account A's role&lt;/li&gt;
&lt;li&gt;The role in Account B doesn't have S3 permissions&lt;/li&gt;
&lt;li&gt;The S3 bucket has a restrictive bucket policy&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Debug&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check trust policy&lt;/span&gt;
aws iam get-role &lt;span class="nt"&gt;--role-name&lt;/span&gt; access-s3-bucket &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--profile&lt;/span&gt; account-b &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'Role.AssumeRolePolicyDocument'&lt;/span&gt;

&lt;span class="c"&gt;# Check attached policies&lt;/span&gt;
aws iam list-attached-role-policies &lt;span class="nt"&gt;--role-name&lt;/span&gt; access-s3-bucket &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--profile&lt;/span&gt; account-b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Problem 3: Terraform Can't Create Resources in Account B
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cause&lt;/strong&gt;: Terraform doesn't have permission to assume the role in Account B.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Ensure you have a &lt;code&gt;terraform&lt;/code&gt; role in Account B with this trust policy:&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="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;"Principal"&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;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;arn_of_cli_identity&amp;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;"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;"sts:AssumeRole"&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;
  
  
  🎓 Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Two-Way Trust&lt;/strong&gt;: Cross-account access requires both accounts to cooperate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Account A must be allowed to assume roles in Account B&lt;/li&gt;
&lt;li&gt;Account B must trust Account A's role&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;STS is Your Friend&lt;/strong&gt;: Temporary credentials are more secure than permanent access keys. They expire automatically and can be audited.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Cross-account IAM access doesn't have to be scary. By understanding the trust relationships, using STS for temporary credentials, and following least privilege principles, you can securely share resources across AWS accounts.&lt;/p&gt;

&lt;p&gt;The pattern I've shown here—Lambda in Account A assuming a role in Account B to access S3—applies to many other scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EC2 instances accessing DynamoDB in another account&lt;/li&gt;
&lt;li&gt;Step Functions orchestrating resources across accounts&lt;/li&gt;
&lt;li&gt;EventBridge forwarding events between accounts&lt;/li&gt;
&lt;li&gt;Centralized logging and monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Have you implemented cross-account access in your AWS environment? What challenges did you face? Drop a comment below!&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/nobleman97/cross-account-iam" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html" rel="noopener noreferrer"&gt;AWS STS Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html" rel="noopener noreferrer"&gt;AWS IAM Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;If you found this helpful, consider starring the &lt;a href="https://github.com/nobleman97/cross-account-iam" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; and sharing it with your team!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>sts</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>Docker Networking 101: A Blueprint for Seamless Container Connectivity</title>
      <dc:creator>David Omokhodion</dc:creator>
      <pubDate>Wed, 13 Dec 2023 14:05:42 +0000</pubDate>
      <link>https://forem.com/nobleman97/docker-networking-101-a-blueprint-for-seamless-container-connectivity-3i5b</link>
      <guid>https://forem.com/nobleman97/docker-networking-101-a-blueprint-for-seamless-container-connectivity-3i5b</guid>
      <description>&lt;p&gt;Docker is a platform for developing, shipping, and running applications in containers. Containers are lightweight, standalone, and executable software packages that include everything needed to run a piece of software, including the code, runtime, libraries, and system tools. Docker provides a consistent and reproducible environment across different environments, making it easier to build, deploy, and scale applications.&lt;/p&gt;

&lt;p&gt;To enable communication between containers, your host and the outside world, docker implements an interesting networking system. It is this system that bridges the gap between isolated containers, allowing them to function as well-coordinated services.&lt;/p&gt;

&lt;p&gt;In this article, you will learn about the basics of the different network types and how to use them in development or deployment.&lt;/p&gt;

&lt;p&gt;We will cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker Network Types&lt;/li&gt;
&lt;li&gt;Using Docker Networks&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-22-04" rel="noopener noreferrer"&gt;Have Docker Engine Installed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Have a basic understanding of Docker&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Docker Network Types
&lt;/h2&gt;

&lt;p&gt;Docker comes with 7 (rumours say there are more) network types. However, we will discuss the most important four. They are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None&lt;/li&gt;
&lt;li&gt;Bridge (default)&lt;/li&gt;
&lt;li&gt;Bridge (user-defined)&lt;/li&gt;
&lt;li&gt;Host&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you already have Docker setup on your host machine, and you run the command &lt;strong&gt;"docker network list"&lt;/strong&gt;, you should get an output similar to this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;docker network list
NETWORK ID     NAME      DRIVER    SCOPE
6f23ed77734d   bridge    bridge    &lt;span class="nb"&gt;local
&lt;/span&gt;3bbca0d09738   host      host      &lt;span class="nb"&gt;local
&lt;/span&gt;a67ca10d6dfd   none      null      &lt;span class="nb"&gt;local&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;"Driver" in this list, tells us the &lt;em&gt;network type&lt;/em&gt;, and by default, docker creates one &lt;strong&gt;bridge&lt;/strong&gt;, &lt;strong&gt;host&lt;/strong&gt; and &lt;strong&gt;null&lt;/strong&gt;(none) network each.&lt;/p&gt;

&lt;p&gt;Let's discuss each network type in more detail...&lt;/p&gt;

&lt;h3&gt;
  
  
  1. None
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.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%2F7xszaoi4zir8x7ygv7ow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F7xszaoi4zir8x7ygv7ow.png" alt="None network type"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;None&lt;/em&gt; is a docker network-type where the container is not attached to any network. As a result, the container is unable to communicate with any external network or other containers. It is isolated from every other network. &lt;/p&gt;

&lt;p&gt;You can run an nginx container in a "none" network type using the following command:&lt;/p&gt;

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

docker run -d --network none --name my_nginx nginx


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  2. Bridge (default)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.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%2F4prii12z3v8r1x8et54r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F4prii12z3v8r1x8et54r.png" alt="Default bridge network"&gt;&lt;/a&gt;&lt;br&gt;
The bridge network mode sets up an internal private network within the host. This allows communication between containers within such network, but isolates them from the host's network. &lt;/p&gt;

&lt;p&gt;When docker containers are created without specifying a network, they are automatically placed in the &lt;em&gt;default bridge&lt;/em&gt; network.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# running a container in the default bridge network&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;-dit&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; Rock nginx


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  3. Bridge (user-defined)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fskgslqwgc5kt84mxxrwx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fskgslqwgc5kt84mxxrwx.png" alt="User-defined bridge network"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This network type is similar to the &lt;em&gt;user-defined bridge&lt;/em&gt; network. It also creates an internal private network within the host, but it does not come already created by Docker. You have to create it yourself. &lt;/p&gt;

&lt;p&gt;Here's how you create a user-defined bridge network called "demo_net":&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# create a user-defined bridge network&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker network create &lt;span class="nt"&gt;-d&lt;/span&gt; bridge demo_net

&lt;span class="c"&gt;# list all your docker networks&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker network list
NETWORK ID     NAME       DRIVER    SCOPE
6f23ed77734d   bridge     bridge    &lt;span class="nb"&gt;local
&lt;/span&gt;7a824036d47a   demo_net   bridge    &lt;span class="nb"&gt;local
&lt;/span&gt;3bbca0d09738   host       host      &lt;span class="nb"&gt;local
&lt;/span&gt;a67ca10d6dfd   none       null      &lt;span class="nb"&gt;local&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;Here's how to attach a container to the user-defined bridge network you just created...&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Attaching containers to bridged network&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;-dit&lt;/span&gt; &lt;span class="nt"&gt;--network&lt;/span&gt; demo_net &lt;span class="nt"&gt;--name&lt;/span&gt; service_A nginx

&lt;span class="c"&gt;# create another container and publish a port&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;-dit&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:80 &lt;span class="nt"&gt;--network&lt;/span&gt; demo_net &lt;span class="nt"&gt;--name&lt;/span&gt; service_B nginx


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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;service_A&lt;/em&gt; and &lt;em&gt;service_B&lt;/em&gt; containers are now attached to the 'demo_net' network. By default, all containers within the same network can communicate with one another freely but are isolated from the host network and other user-defined networks.  &lt;/p&gt;

&lt;p&gt;In order to access applications running on these containers from the host network, we have to publish (or expose) ports from the containers. In the snippet above, port 80 on &lt;em&gt;service_B&lt;/em&gt; container is mapped to port 8000 on the host, allowing access to an application running on service_B's container port 80 to be accessed from port 8000 on the host.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Host
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fwdsc9kpo0kpg73dn838y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fwdsc9kpo0kpg73dn838y.png" alt="Host network"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Containers in host network mode directly utilize your host's network stack, lacking isolation. They do not receive separate IP addresses, and any port bindings are directly exposed on your host's network interface. In practical terms, if a container process is configured to listen on port 80, it will bind to your host machine's IP address on port 80.&lt;/p&gt;

&lt;p&gt;Here's an example of a container that binds nginx  to a host network:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# bind container to host network&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--network&lt;/span&gt; host &lt;span class="nt"&gt;--name&lt;/span&gt; my_nginx nginx


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

&lt;/div&gt;

&lt;p&gt;If you're using the host's network for your web container (like Nginx), it means you can't run multiple web containers on the same host and port. This is because they would all share the same network settings, causing conflicts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Docker Networks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Testing Communications Within and Between Networks
&lt;/h3&gt;

&lt;p&gt;In an earlier step, we attached two containers (service_A and service_B) to the &lt;em&gt;demo_net&lt;/em&gt; network. Let's confirm that they can communicate with one another within the same network and whether they can communicate with a container in a different network(e.g the "Rock" container in the default bridge network).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# open a shell into service_A container&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; service_A /bin/bash

&lt;span class="c"&gt;# when inside service_A container update its apt repos and install ping&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt &lt;span class="nb"&gt;install &lt;/span&gt;iputils-ping &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Then ping service_B using the container name because name resolution is automatically enabled within the network &lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;ping service_B

root@06dbaea8c2a2:/# ping service_B
PING service_B &lt;span class="o"&gt;(&lt;/span&gt;172.18.0.3&lt;span class="o"&gt;)&lt;/span&gt; 56&lt;span class="o"&gt;(&lt;/span&gt;84&lt;span class="o"&gt;)&lt;/span&gt; bytes of data.
64 bytes from service_B.demo_net &lt;span class="o"&gt;(&lt;/span&gt;172.18.0.3&lt;span class="o"&gt;)&lt;/span&gt;: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.086 ms
64 bytes from service_B.demo_net &lt;span class="o"&gt;(&lt;/span&gt;172.18.0.3&lt;span class="o"&gt;)&lt;/span&gt;: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.154 ms
64 bytes from service_B.demo_net &lt;span class="o"&gt;(&lt;/span&gt;172.18.0.3&lt;span class="o"&gt;)&lt;/span&gt;: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.119 ms
64 bytes from service_B.demo_net &lt;span class="o"&gt;(&lt;/span&gt;172.18.0.3&lt;span class="o"&gt;)&lt;/span&gt;: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.121 ms
...


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

&lt;/div&gt;

&lt;p&gt;The results are similar when you exec into service_B and ping service_A container. However, none of the containers can reach the "Rock" container which is in the default bridge network because they exist in different virtual networks.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Inside service_A&lt;/span&gt;
root@06dbaea8c2a2:/# ping Rock
ping: Rock: Temporary failure &lt;span class="k"&gt;in &lt;/span&gt;name resolution


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Reaching Apps Running in Containers via Published Ports
&lt;/h3&gt;

&lt;p&gt;When creating &lt;em&gt;service_B&lt;/em&gt; in an earlier step, we ran the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;-dit&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:80 &lt;span class="nt"&gt;--network&lt;/span&gt; demo_net &lt;span class="nt"&gt;--name&lt;/span&gt; service_B nginx


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

&lt;/div&gt;

&lt;p&gt;This command mapped port 80 within the container to port 8000 on the host machine. Hence, when we visit localhost:8000 in our browser, we see the web server running in &lt;em&gt;service_B&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fmtk8emmt81xsrmfqok9c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fmtk8emmt81xsrmfqok9c.png" alt="localhost:8000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Manipulating Network Connections
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Disconnect service_A&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker network disconnect demo_net service_A

&lt;span class="c"&gt;# Reconnect service_A to default "bridge" network&lt;/span&gt;
docker network connect bridge service_A

&lt;span class="c"&gt;#Next, use `docker inspect` to get the ip of the Rock container and try pinging it.&lt;/span&gt;

root@06dbaea8c2a2:/# ping 172.17.0.2
PING 172.17.0.2 &lt;span class="o"&gt;(&lt;/span&gt;172.17.0.2&lt;span class="o"&gt;)&lt;/span&gt; 56&lt;span class="o"&gt;(&lt;/span&gt;84&lt;span class="o"&gt;)&lt;/span&gt; bytes of data.
64 bytes from 172.17.0.2: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.093 ms
64 bytes from 172.17.0.2: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.186 ms
64 bytes from 172.17.0.2: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.149 ms

&lt;span class="c"&gt;# It works!&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  List Docker Networks
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;docker network &lt;span class="nb"&gt;ls
&lt;/span&gt;NETWORK ID     NAME       DRIVER    SCOPE
a87871978d59   bridge     bridge    &lt;span class="nb"&gt;local
&lt;/span&gt;747d0aff98fc   demo_net   bridge    &lt;span class="nb"&gt;local
&lt;/span&gt;3bbca0d09738   host       host      &lt;span class="nb"&gt;local
&lt;/span&gt;a67ca10d6dfd   none       null      &lt;span class="nb"&gt;local&lt;/span&gt;



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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Deleting Docker Networks
&lt;/h3&gt;

&lt;p&gt;To delete a custom network, you must first stop or disconnect all running containers attached to the network. When that's done, proceed to delete the network by running the &lt;strong&gt;docker network rm&lt;/strong&gt; command like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;docker network &lt;span class="nb"&gt;rm &lt;/span&gt;demo_net

&lt;span class="c"&gt;# Confirm that the demo_net network has been removed&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker network &lt;span class="nb"&gt;ls
&lt;/span&gt;NETWORK ID     NAME      DRIVER    SCOPE
a87871978d59   bridge    bridge    &lt;span class="nb"&gt;local
&lt;/span&gt;3bbca0d09738   host      host      &lt;span class="nb"&gt;local
&lt;/span&gt;a67ca10d6dfd   none      null      &lt;span class="nb"&gt;local&lt;/span&gt;


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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Docker's networking system gives you different choices for handling communication between containers, their nearby containers, and your Docker host. In a network, containers can connect with each other using their names or IP addresses.&lt;/p&gt;

&lt;p&gt;User-defined bridge networks work well when you want various containers to talk to each other on the same Docker host. On the flip side, host networks are more suitable when you don't want the network stack to be separate from the Docker host, but you still want other parts of the container to be isolated.&lt;/p&gt;

&lt;p&gt;Docker's networking system could initially feel overwhelming, but I hope this gives you some clarity. &lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;If you have any questions or comments, you can leave them below, or reach out to me on &lt;a href="https://www.linkedin.com/in/davidomokhodion/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;. Till we meet again...&lt;/p&gt;

&lt;p&gt;Stay awesome!&lt;br&gt;
~ David Omokhodion&lt;/p&gt;



&lt;h2&gt;
  
  
  Attributions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://spacelift.io/blog/docker-networking#how-docker-networking-works" rel="noopener noreferrer"&gt;Docker Networking – Basics, Network Types &amp;amp; Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tonylixu.medium.com/docker-container-network-basics-2d7d0e45ccf8" rel="noopener noreferrer"&gt;Docker — Container Network Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kodekloud.com/blog/networking-docker-containers/" rel="noopener noreferrer"&gt;A Quick Guide to Docker Network Types&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>kubernetes</category>
      <category>linux</category>
    </item>
    <item>
      <title>How to Provision a Linux EC2 Instance (server) on AWS Step-by-step</title>
      <dc:creator>David Omokhodion</dc:creator>
      <pubDate>Sun, 30 Oct 2022 17:58:52 +0000</pubDate>
      <link>https://forem.com/nobleman97/how-to-provision-a-linux-ec2-instance-server-on-aws-step-by-step-44o2</link>
      <guid>https://forem.com/nobleman97/how-to-provision-a-linux-ec2-instance-server-on-aws-step-by-step-44o2</guid>
      <description>&lt;p&gt;Have you ever needed a server to deploy a web app, complete a lab or something else? I have had need to do both, and AWS always came through for me.&lt;/p&gt;

&lt;p&gt;In this tutorial, you will learn how to set up and connect to your own AWS Linux EC2 instance to meet your needs for a server.&lt;/p&gt;

&lt;p&gt;Let's go...&lt;/p&gt;

&lt;h3&gt;
  
  
  What is an EC2 Instance?
&lt;/h3&gt;

&lt;p&gt;An Amazon EC2 &lt;em&gt;instance&lt;/em&gt; is a virtual server in the AWS cloud. With the Amazon EC2 service, you can configure your instance to run operating system or applications of your choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;When launching an instance, you have to secure it using security groups(which acts like a virtual firewall to control traffic to and from your instance) and key pairs(a proof of identity).&lt;/p&gt;

&lt;p&gt;Here is an architectural diagram of what we will be setting up:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0V9MRPtY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jcqogj2i5yre7uh0o0eg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0V9MRPtY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jcqogj2i5yre7uh0o0eg.png" alt="ec2 setup architecture" width="409" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;An AWS account&lt;/li&gt;
&lt;li&gt;Create key pair and security group by following instructions found &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/get-set-up-for-amazon-ec2.html"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;To avoid being billed unnecessarily, please ensure to terminate you instance when you complete this tutorial. Instructions for that are included in the last step here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 1: Launch Your Instance
&lt;/h3&gt;

&lt;p&gt;There are several ways to launch an EC2 instance, but in this tutorial, we will use the AWS console.&lt;/p&gt;

&lt;p&gt;Here are the steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open the EC2 console at &lt;a href="https://console.aws.amazon.com/ec2/"&gt;AWS console link&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From the dashboard, click on &lt;strong&gt;Launch instance&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h1KIJ6xM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5e1w3e8fdr3vcflcpyfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h1KIJ6xM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5e1w3e8fdr3vcflcpyfn.png" alt="Launch Instance" width="617" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Next, enter a name for your server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under the &lt;strong&gt;Application and OS Images (Amazon Machine Image)&lt;/strong&gt;, select the "Quick Start" tab and select the Ubuntu image. This will be the OS for your instance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under the Amazon Machine Images(AMI) section, pick an option with the "free tier eligible" label for now.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xcbKcTu6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/65cnne6gq7q9xbrf16uf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xcbKcTu6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/65cnne6gq7q9xbrf16uf.png" alt="Select image and AMIs" width="775" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Next, under &lt;strong&gt;Instance type&lt;/strong&gt;, choose an option that has "free tier eligible" too. These instance types are hardware configurations for your server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under &lt;strong&gt;Key pair(login)&lt;/strong&gt; choose a key pair you create before, or create one at this step.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Warning: If you launch your instance without a key pair, then you can't connect to it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--02eWDfS0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5u4i8th6ovqc70i9eyso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--02eWDfS0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5u4i8th6ovqc70i9eyso.png" alt="Instance type and key pair" width="599" height="581"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Next, we have to configure &lt;strong&gt;Network settings&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose "select existing security group"&lt;/li&gt;
&lt;li&gt;From the "Common security groups" dropdown, pick the security group you configured earlier from the &lt;strong&gt;Prerequisites&lt;/strong&gt; section of this blog. If you didn't do that, go &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/get-set-up-for-amazon-ec2.html"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In order to easily access your access your instance, check to see whether the "Auto-assign public ip" is enabled. If not, enable it to allow a public Ip to be associated with your instance when it is launched.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bjEdhdT3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ogpr8q9uaslb7ygml95f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bjEdhdT3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ogpr8q9uaslb7ygml95f.png" alt="security group and public IP" width="786" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Keep the other default selections, review the configurations for your instance and confirm instance launch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the &lt;strong&gt;Instances&lt;/strong&gt; screen, you could monitor the status of your instance. It may take some time for the instance to launch. Just wait until the &lt;strong&gt;state&lt;/strong&gt; changes to "running."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Also wait for the &lt;strong&gt;Status check&lt;/strong&gt; to pass before attempting to connect to it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Connect to Your Instance (via SSH)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;You can't connect to your instance unless:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have the

&lt;code&gt;.pem&lt;/code&gt;

file for the key pair you used to create the instance.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
&lt;li&gt;Your security group is configured to allow you to connect via SSH from your computer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...so ensure that you have these setup correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;In the &lt;strong&gt;Instances&lt;/strong&gt; page, select your instance and copy the Public IP address.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6p_gzg5O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h9tqmu8dyt85qgxq5n5a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6p_gzg5O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h9tqmu8dyt85qgxq5n5a.png" alt="Copy public IP Address" width="880" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Head over to your terminal and let's connect to our instance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The syntax for connecting to the instance is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; &amp;lt;path_to_pem_file&amp;gt; user@&amp;lt;Instance_public_ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case, it was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; ~/Downloads/Davi-test.pem ubuntu@54.175.160.84
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Successful connection should look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4L0WLYyv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cp36g2ou87ipvmhr0h1z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4L0WLYyv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cp36g2ou87ipvmhr0h1z.png" alt="SSH connection successful" width="597" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If ssh complains about the key permission, ensure to change the permission of the .pem file to 400, using chmod. For example, by running:&lt;br&gt;
&lt;br&gt;
&lt;code&gt;sudo chmod 400 &amp;lt;path_to_pem_file&amp;gt;)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you still can't connect to your instance, see &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/TroubleshootingInstancesConnecting.html"&gt;Troubleshoot Connecting to Your Instance&lt;/a&gt; for assistance.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 3: Clean Up Your Instance
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Head over to your EC2 instances page and select the instance you just created.&lt;/li&gt;
&lt;li&gt;Click on the "Instance state" dropdown and select &lt;strong&gt;Terminate instance&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Amazon will then shutdown and terminate your instance. You will no longer be able to connect to it after termination.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Congratulations! You just provisioned a server in the AWS cloud.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed the tutorial.&lt;/p&gt;

&lt;p&gt;If you have any questions or had any difficulty following along, kindly drop a comment below or reached out to me on &lt;a href="https://www.linkedin.com/in/davidomokhodion"&gt;LinkedIn&lt;/a&gt;. Till we meet again...&lt;/p&gt;

&lt;p&gt;Stay awesome!&lt;br&gt;
~ David Omokhodion.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Configure Remote Linux Servers Using Ansible</title>
      <dc:creator>David Omokhodion</dc:creator>
      <pubDate>Tue, 18 Oct 2022 09:04:55 +0000</pubDate>
      <link>https://forem.com/nobleman97/how-to-configure-remote-linux-servers-using-ansible-1912</link>
      <guid>https://forem.com/nobleman97/how-to-configure-remote-linux-servers-using-ansible-1912</guid>
      <description>&lt;p&gt;Imagine that you were asked to install a piece of software (e.g apache2) on 250 different Linux servers. &lt;/p&gt;

&lt;p&gt;How would you go about it?&lt;/p&gt;

&lt;p&gt;Well, you could decide to ssh (open a secure connection) into the servers one after the other, and install the software, but that would take an awefully long time to complete.&lt;/p&gt;

&lt;p&gt;A more efficient approach will be to use a configuration management tool like Ansible to automate the process.&lt;/p&gt;

&lt;p&gt;In this tutorial, you will learn how to use Ansible to target your servers and:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Apache web server and&lt;/li&gt;
&lt;li&gt;Change the default timezone of your servers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here, we will use two servers, but the procedure is similar when configuring 250 (or more) servers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;An AWS account&lt;/li&gt;
&lt;li&gt;A linux machine (could be a VM)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's go...&lt;/p&gt;

&lt;p&gt;From an Architectural standpoint, this is how Ansible works:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--N7bVEnyF--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880%2Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F33ympesmiwld52do90ji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--N7bVEnyF--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880%2Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F33ympesmiwld52do90ji.png" alt="Ansible Architecture"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Install Dependencies
&lt;/h3&gt;

&lt;p&gt;For Ansible to function properly you need to ensure you have Python and softwares-properties-common installed. Run the following commands to install them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo apt install software-properties-common
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo apt install python3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then install ansible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$sudo apt install ansible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm Ansible installation:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ ansible-playbook -v&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Provision servers on AWS
&lt;/h3&gt;

&lt;p&gt;For this tutorial, I will provision two Ubuntu servers(EC2 instances on AWS). If you don't already know how to do that, follow the instruction &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html" rel="noopener noreferrer"&gt;here.&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; &lt;br&gt;
When you provision your servers, ensure that you download the privatekey file(the file with the ".pem" extension), and that you note down the &lt;em&gt;public ip addresses&lt;/em&gt; of the provisioned EC2 instances. &lt;br&gt;
Also, for ease, I like to move my privatekeys to my ~/.ssh/ folder. So mine is located at &lt;strong&gt;~/.ssh/Davi-test.pem&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also ensure that your security group allows ssh and web traffic into the server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ft1d381ovmhty8sv5l4fn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ft1d381ovmhty8sv5l4fn.png" alt="security group settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Setup host-inventory
&lt;/h3&gt;

&lt;p&gt;Create a directory for my this project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir ansible_proj &amp;amp;&amp;amp; cd ansible_proj
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create your host-inventory file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ touch host-inventory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, using your favourite text editor (vi, nano or even VScode) add the ip addresses (or hostnames) of your servers. Like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F5ybl1pak7bz4jybrp2sg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F5ybl1pak7bz4jybrp2sg.png" alt="host-inventory image"&gt;&lt;/a&gt;&lt;br&gt;
and save.&lt;/p&gt;

&lt;p&gt;You would notice that I grouped all my servers under "webservers."&lt;/p&gt;

&lt;p&gt;Grouping targets like this makes it easy to separate different groups of machines and this often comes in handy.&lt;/p&gt;

&lt;p&gt;Next, you need to tell ansible how to locate your host-inventory file. If you don't, ansible will try to get it from /etc/ansible/hosts.&lt;/p&gt;

&lt;p&gt;But since we have the file at ~/ansible_proj, go ahead and do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export ANSIBLE_INVENTORY=~/ansible_proj/host-inventory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and we're ready to go.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Create the Ansible Playbook
&lt;/h3&gt;



&lt;p&gt;&lt;code&gt;touch test.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;And then, using your favourite text editor, paste in the following code in the test.yaml file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Web Server&lt;/span&gt;
    &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webservers&lt;/span&gt;
    &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;become_method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sudo&lt;/span&gt;
    &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Apache Server&lt;/span&gt;
        &lt;span class="na"&gt;apt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;name=apache2 state=present&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set timezone to Africa/Lagos&lt;/span&gt;
        &lt;span class="na"&gt;timezone&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Africa/Lagos&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and save.&lt;/p&gt;

&lt;p&gt;In the yaml, we target the webserver group using&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;hosts: webservers&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
, and we describe 2 tasks, using the apt and timezone modules respectively.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 5: Test the connection
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Before proceeding with this step, ensure that your $ANSIBLE_INVENTORY variable is set in your current bash as describe previously.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Based on the location of the key you got earlier, you will need to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible --private-key PRIVATEKEY_FILE -u USER HOST_GROUP -m ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want to connect as the "ubuntu" user and target the servers under "webservers" host group. So that will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible --private-key ~/.ssh/Davi-test.pem -u ubuntu webservers -m ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.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%2F4h53w76woieyookdfqq5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F4h53w76woieyookdfqq5.png" alt="ping success"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Test the Playbook
&lt;/h3&gt;

&lt;p&gt;Before we run our ansible playbook, it is important to test using the "--check" flag along with the ansible-playbook command. 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;$ ansible-playbook --private-key ~/.ssh/Davi-test.pem -u ubuntu test.yaml --check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output should look something like this:&lt;br&gt;
&lt;a href="https://media.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%2Fetuh1y6wdbm283ppll75.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fetuh1y6wdbm283ppll75.png" alt="ansible playbook check successful"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before you go ahead to finally run the playbook, ssh into any of the servers and check whether apache2 is running and confirm the timezone. If you don't know how to ssh into your server, go &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I checked inside one of my servers, and here is what I got:&lt;br&gt;
&lt;a href="https://media.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%2Ftasmhxow7ljra8l0pidh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ftasmhxow7ljra8l0pidh.png" alt="image showing apache2 is not installed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apache2 was not not installed and timezone was Etc/UTC.&lt;/p&gt;

&lt;p&gt;Now let's run the playbook:&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 7: Run the Ansible playbook
&lt;/h3&gt;

&lt;p&gt;Apply the intended changes to the servers by running the command we used to check, but without the "--check" flag. i.e&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-playbook --private-key ~/.ssh/Davi-test.pem -u ubuntu test.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there are no errors and everything goes well, then ssh into any of the servers and try check apache2 and timezone again. Here's what I got:&lt;br&gt;
&lt;a href="https://media.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%2F385an15sftkie3fxxxuu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F385an15sftkie3fxxxuu.png" alt="Ansible configured timezone and apache2 successfully"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Awesome!, right? Ansible did it's thing again!.&lt;/p&gt;

&lt;p&gt;Before you leave, here's a little exercise:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Try adjusting the timezone to a different one within the test.yaml and run it again to see what happens.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 8: Clean up
&lt;/h3&gt;

&lt;p&gt;Finally, if you don't need the servers for other reasons, ensure that you terminate them from the AWS console to avoid racking up unnecessary bills.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fq1z6jyee07x3zuoec2hr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fq1z6jyee07x3zuoec2hr.png" alt="ec2 instances terminated"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Hey,&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this tutorial, and I hope that you learned a thing or two about Ansible. &lt;/p&gt;

&lt;p&gt;As of the time of writing this tutorial, I just got started with Ansible myself, but I'll be using it a lot from now on because I think it's an awesome tool. &lt;/p&gt;

&lt;p&gt;If you have any questions, or comments, you can leave them below, or reach out to me on &lt;a href="https://www.linkedin.com/in/davidomokhodion" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;. Till we meet again...&lt;/p&gt;

&lt;p&gt;Stay awesome!&lt;br&gt;
~ David Omokhodion&lt;/p&gt;

</description>
      <category>ansible</category>
      <category>devops</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
