<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Otu Udo</title>
    <description>The latest articles on DEV Community by Otu Udo (@otumiky).</description>
    <link>https://dev.to/otumiky</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%2F2508076%2F76ee425c-a3e4-4596-84c6-574d844b9adc.jpg</url>
      <title>DEV Community: Otu Udo</title>
      <link>https://dev.to/otumiky</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/otumiky"/>
    <language>en</language>
    <item>
      <title>Deploying PrestaShop on AWS</title>
      <dc:creator>Otu Udo</dc:creator>
      <pubDate>Mon, 20 Jan 2025 01:13:56 +0000</pubDate>
      <link>https://dev.to/otumiky/deploying-prestashop-on-aws-24lb</link>
      <guid>https://dev.to/otumiky/deploying-prestashop-on-aws-24lb</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this project, we deployed a PrestaShop server on AWS using a modular Terraform approach. By separating the infrastructure into three distinct modules &lt;strong&gt;VPC&lt;/strong&gt;, &lt;strong&gt;EC2&lt;/strong&gt;, and &lt;strong&gt;RDS&lt;/strong&gt; we achieve better scalability, reusability, and maintainability of our Terraform code.&lt;/p&gt;

&lt;p&gt;The following sections provide a step-by-step guide to setting up this infrastructure and installing PrestaShop on an Ubuntu-based EC2 instance connected to an RDS MySQL database. Screenshots from the AWS console will demonstrate the results of our deployment.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Modules Overview&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. VPC Module&lt;/strong&gt;&lt;br&gt;
The VPC module handles the networking layer for our infrastructure. It creates the Virtual Private Cloud, subnets, route tables, internet gateway, and necessary security groups. Kindly check the &lt;a href="https://github.com/Otumiky/PrestaShop.git" rel="noopener noreferrer"&gt;source code&lt;/a&gt; for more info&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Code Snippet for VPC Module&lt;/strong&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"vpc"&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;"./modules/vpc"&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_name&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_cidr&lt;/span&gt;
  &lt;span class="nx"&gt;public_subnets&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnets&lt;/span&gt;
  &lt;span class="nx"&gt;private_subnets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnets&lt;/span&gt;
  &lt;span class="nx"&gt;enable_nat_gateway&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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;Outputs from the VPC Module&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VPC ID&lt;/li&gt;
&lt;li&gt;Public and private subnet IDs&lt;/li&gt;
&lt;li&gt;Route table IDs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. EC2 Module&lt;/strong&gt;&lt;br&gt;
The EC2 module provisions an Ubuntu-based instance, installs Apache, PHP, and PrestaShop dependencies, and configures the server. It also includes a security group to allow HTTP and SSH traffic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Snippet for EC2 Module&lt;/strong&gt;&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;module&lt;/span&gt; &lt;span class="s2"&gt;"ec2"&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;"./modules/ec2"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_type&lt;/span&gt;
  &lt;span class="nx"&gt;ami_id&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ami_id&lt;/span&gt;
  &lt;span class="nx"&gt;key_name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key_name&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_id&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;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnet_ids&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;security_groups&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;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2_sg_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;user_data&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"user_data.sh"&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;The &lt;code&gt;user_data.sh&lt;/code&gt; script automates the installation of PrestaShop and its dependencies during instance initialization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. RDS Module&lt;/strong&gt;&lt;br&gt;
The RDS module provisions a MySQL database instance for PrestaShop. It includes a security group that allows access only from the EC2 instance's security group.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Snippet for RDS Module&lt;/strong&gt;&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;module&lt;/span&gt; &lt;span class="s2"&gt;"rds"&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;"./modules/rds"&lt;/span&gt;
  &lt;span class="nx"&gt;engine&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"mysql"&lt;/span&gt;
  &lt;span class="nx"&gt;engine_version&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"8.0"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_class&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"db.t3.micro"&lt;/span&gt;
  &lt;span class="nx"&gt;allocated_storage&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
  &lt;span class="nx"&gt;username&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db_username&lt;/span&gt;
  &lt;span class="nx"&gt;password&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db_password&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_ids&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;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet_ids&lt;/span&gt;
  &lt;span class="nx"&gt;security_group_ids&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;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rds_sg_id&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;Outputs from the RDS Module&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database endpoint&lt;/li&gt;
&lt;li&gt;Security group ID&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Deploying the Infrastructure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Initialize Terraform&lt;/strong&gt;&lt;br&gt;
Run the following command to initialize your Terraform project:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Plan the Deployment&lt;/strong&gt;&lt;br&gt;
Generate an execution plan to verify the resources to be created:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Apply the Configuration&lt;/strong&gt;&lt;br&gt;
Apply the configuration to provision the resources:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Approve the changes when prompted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Verify Resource Creation&lt;/strong&gt;&lt;br&gt;
Once the resources are created, use the AWS console to verify the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;VPC and subnets&lt;/li&gt;
&lt;li&gt;EC2 instance status&lt;/li&gt;
&lt;li&gt;RDS instance status and endpoint&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;&lt;strong&gt;Post-Deployment Configuration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Accessing the PrestaShop Server&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to the EC2 instance’s public IP or DNS in your browser.&lt;/li&gt;
&lt;li&gt;Verify the PrestaShop installation page appears.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Connecting to the Database&lt;/strong&gt;&lt;br&gt;
Use the RDS endpoint and credentials specified in your Terraform variables to connect the EC2 instance to the database.&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%2Foyc5d0aaqb82ka4y2b49.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%2Foyc5d0aaqb82ka4y2b49.png" alt="Image description" width="800" height="432"&gt;&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%2Fphap5vbt0zlncsypayxu.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%2Fphap5vbt0zlncsypayxu.png" alt="Image description" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Replacing Default Apache Page&lt;/strong&gt;&lt;br&gt;
Ensure the Apache default page is replaced by PrestaShop:&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="nb"&gt;sudo rm&lt;/span&gt; /var/www/html/index.html
&lt;span class="nb"&gt;sudo mv&lt;/span&gt; /var/www/html/prestashop/&lt;span class="k"&gt;*&lt;/span&gt; /var/www/html/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Apache:&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="nb"&gt;sudo &lt;/span&gt;systemctl restart apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Adjusting PHP Version&lt;/strong&gt;&lt;br&gt;
PrestaShop requires PHP 7.4. Use the following commands to install PHP 7.4:&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="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; software-properties-common
&lt;span class="nb"&gt;sudo &lt;/span&gt;add-apt-repository ppa:ondrej/php &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; php7.4 libapache2-mod-php7.4 php7.4-mysql
&lt;span class="nb"&gt;sudo &lt;/span&gt;update-alternatives &lt;span class="nt"&gt;--set&lt;/span&gt; php /usr/bin/php7.4
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Screenshots of Created Resources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. VPC Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VPC details (Route tables, subnets)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagl1anu4dlxjnk32fm0e.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%2Fagl1anu4dlxjnk32fm0e.png" alt="Image description" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. EC2 Instance&lt;/strong&gt;&lt;br&gt;
Show:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EC2 instance details (public IP, security group)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxl1jip1i2p2cltrbweak.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%2Fxl1jip1i2p2cltrbweak.png" alt="Image description" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. RDS Instance&lt;/strong&gt;&lt;br&gt;
Include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RDS instance details (endpoint, security group)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzhhog3912c5f3linsf2.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%2Fqzhhog3912c5f3linsf2.png" alt="Image description" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connectivity test from EC2 instance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fri05jqbfmgzmmafjzzp0.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%2Fri05jqbfmgzmmafjzzp0.png" alt="Image description" width="800" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing EC2 DNS&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%2F3fn1p7mldfymchr6men8.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%2F3fn1p7mldfymchr6men8.png" alt="Image description" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
By following this modular approach, we successfully deployed a scalable and maintainable PrestaShop server on AWS. The use of Terraform modules ensures the infrastructure is reusable and easy to manage. Screenshots from the AWS console validate the successful creation of resources.&lt;/p&gt;

&lt;p&gt;Feel free to share your feedback or enhancements for this project in the comments section!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building a Two-Tier Architecture with Terraform: My Hands-On Experience</title>
      <dc:creator>Otu Udo</dc:creator>
      <pubDate>Mon, 13 Jan 2025 16:09:29 +0000</pubDate>
      <link>https://dev.to/otumiky/two-tier-architecture-with-terraform-1epp</link>
      <guid>https://dev.to/otumiky/two-tier-architecture-with-terraform-1epp</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
As a Cloud Engineer delving into Infrastructure as Code (IaC), I recently embarked on creating a two-tier architecture using Terraform. This project was both a challenge and a valuable learning experience, teaching me about efficient infrastructure design, optimizing Terraform modules, and securing cloud resources. In this blog, I’ll walk you through my journey, highlighting the challenges, solutions, and insights I gained along the way.  &lt;/p&gt;



&lt;p&gt;&lt;strong&gt;What is a Two-Tier Architecture?&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;A two-tier architecture separates the application layer from the database layer, enhancing scalability, security, and maintainability. For this project, I focused on creating:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Application Layer:&lt;/strong&gt; Hosted by an Auto Scaling Group (ASG) managing EC2 instances.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load Balancer Layer:&lt;/strong&gt; An Application Load Balancer (ALB) directing incoming traffic to healthy instances.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This setup ensures high availability and scalability while maintaining a simple architecture.  &lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Project Overview&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Here’s a snapshot of my architecture:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S3 Backend:&lt;/strong&gt; Used for Terraform state management.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VPC with Public Subnets:&lt;/strong&gt; All resources were deployed in public subnets, secured through well-configured security groups.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load Balancer:&lt;/strong&gt; An ALB distributing traffic to application servers.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Scaling Group:&lt;/strong&gt; Dynamically managing application servers to ensure consistent performance. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Architectural Diagram&lt;/strong&gt; &lt;br&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%2Frna10nrylz788h7d27vd.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%2Frna10nrylz788h7d27vd.png" alt="diagram" width="800" height="625"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Initially, I incorporated four Terraform modules, including a standalone EC2 module. However, I later optimized the design by removing the EC2 module, realizing that the ASG already managed instance creation effectively.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use both EC2 and ASG modules when you need extensive customization for EC2 instances while leveraging ASG's auto-scaling.
&lt;/li&gt;
&lt;li&gt;Use only the ASG module for a streamlined, scalable solution when EC2 configuration is straightforward.
&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Step-by-Step Implementation&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Setting Up the Network&lt;/strong&gt; &lt;br&gt;
The first step was creating an s3 backend for storing states securely for this project. Kindly follow the procedue by clicking &lt;a href="https://dev.to/otumiky/managing-terraform-state-best-practices-for-devops-5cll"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next we move to creating a VPC with two public subnets, each in a separate availability zone:&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;#Create VPC&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc"&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr_block&lt;/span&gt;
  &lt;span class="nx"&gt;enable_dns_support&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;enable_dns_hostnames&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&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="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;#Create Subnets&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_subnet"&lt;/span&gt; &lt;span class="s2"&gt;"public"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;availability_zone&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;availability_zones&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;map_public_ip_on_launch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&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;"${var.vpc_name}-public-${count.index}"&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;The configuration included an internet gateway and route tables to enable internet access.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Configuring the Auto Scaling Group (ASG)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The ASG dynamically created and managed EC2 instances, simplifying scaling:&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;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_launch_template"&lt;/span&gt; &lt;span class="s2"&gt;"lt"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name_prefix&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name_prefix&lt;/span&gt;
  &lt;span class="nx"&gt;image_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image_id&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_type&lt;/span&gt;

  &lt;span class="nx"&gt;network_interfaces&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;associate_public_ip_address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;security_groups&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;security_groups&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;user_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;base64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user_data&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_autoscaling_group"&lt;/span&gt; &lt;span class="s2"&gt;"asg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;desired_capacity&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;desired_capacity&lt;/span&gt;
  &lt;span class="nx"&gt;min_size&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min_size&lt;/span&gt;
  &lt;span class="nx"&gt;max_size&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;max_size&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_zone_identifier&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnets&lt;/span&gt;

  &lt;span class="nx"&gt;launch_template&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_launch_template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;"$Latest"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;target_group_arns&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target_group_arn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;tag&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt;                 &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Name"&lt;/span&gt;
    &lt;span class="nx"&gt;value&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name_prefix&lt;/span&gt;
    &lt;span class="nx"&gt;propagate_at_launch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To ensure optimal resource utilization, I incorporated lifecycle policies and auto-scaling configurations into the architecture. These measures automatically adjust the number of EC2 instances based on workload demands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Adding a Load Balancer&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The ALB ensured efficient traffic distribution and health monitoring:&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;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lb"&lt;/span&gt; &lt;span class="s2"&gt;"alb"&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="nx"&gt;var&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;internal&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;load_balancer_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application"&lt;/span&gt;
  &lt;span class="nx"&gt;security_groups&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;security_groups&lt;/span&gt;
  &lt;span class="nx"&gt;subnets&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnets&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;Step 4: Securing Resources&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Security groups restricted access to critical resources:&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;#Create Security Group for ALB&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"alb_sg"&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;"alb-sg"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Security group for the Application Load Balancer"&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Allow HTTP traffic from the internet&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;
  &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;
  &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-1"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&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;"sg-alb"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;#Create Security Group for ASG&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"asg_sg"&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;"asg-sg"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Security group for EC2 instances in the ASG"&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow HTTP traffic from ALB"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;security_groups&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_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alb_sg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Reference ALB SG&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow all outbound traffic"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-1"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&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;"asg-sg"&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;The ALB accepted HTTP traffic, while EC2 instances only allowed traffic from the ALB.  &lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step 5: Deploying the Infrastructure&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;While the above codes are just snippets.&lt;a href="https://github.com/Otumiky/scalable-web-app" rel="noopener noreferrer"&gt;Clone&lt;/a&gt; the main repo to proceed with the steps below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;change directory to dev and configure the root main.tf&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="nb"&gt;cd &lt;/span&gt;envs/dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I used the following commands to deploy the setup:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initialize Terraform:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Plan the Infrastructure:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Apply the Configuration:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;p&gt;The output included the ALB DNS name, which was used for testing.  &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%2F8bb29050xdc9qa3pp7sf.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%2F8bb29050xdc9qa3pp7sf.png" alt="DNS output" width="800" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6: Testing the Setup&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
To confirm the setup's functionality and security, I tested the ALB DNS name:&lt;br&gt;
Copied the DNS name from the Terraform output.&lt;br&gt;
Pasted it into a browser to verify the connection to the web server.&lt;br&gt;
Security Confirmation&lt;br&gt;
I also verified that the EC2 instances were only accessible via the ALB DNS. Directly attempting to connect to the EC2 instances using their public IPs resulted in denied access. This was achieved by configuring security groups &lt;strong&gt;to accept traffic only from the ALB&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This step reassured me that:&lt;/p&gt;

&lt;p&gt;Traffic routing: All incoming requests were routed exclusively through the ALB.&lt;br&gt;
Access control: No unauthorized traffic could directly reach the EC2 instances, &lt;strong&gt;ensuring a secure environment&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%2Fztz6ajvquqtgth3av8u9.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%2Fztz6ajvquqtgth3av8u9.png" alt="test" width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Screenshots of AWS Components&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;The screenshot below showcases the VPC, public subnets, route table and internet gateway created using Terraform. Each subnet in it's respective availability zone. This highlights the network's readiness for internet-facing resources.&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%2Fiiba8kkwu2akknn7lky6.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%2Fiiba8kkwu2akknn7lky6.png" alt="vpc" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This screenshot displays the target group attached to the ALB, showing the registered EC2 instances and their health status. The "healthy" status indicates that the ALB can successfully route traffic to these instances.&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%2Fed97p1fts7qosxwkkxmu.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%2Fed97p1fts7qosxwkkxmu.png" alt="target group" width="800" height="430"&gt;&lt;/a&gt; &lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Challenges and Solutions&lt;/strong&gt;  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Redundant EC2 Module:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Initially, I used a standalone EC2 module alongside the ASG, which caused redundancy. Removing it simplified the design and avoided potential conflicts.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security Concerns with Public Subnets:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Deploying resources in public subnets required meticulous security group configurations to balance accessibility and security.  &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Key Learnings&lt;/strong&gt;  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Optimize Module Usage:&lt;/strong&gt; Avoid redundancy by understanding each module's functionality.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Matters:&lt;/strong&gt; Even in public subnets, effective security group configuration can ensure safety.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterate and Improve:&lt;/strong&gt; Testing and refining designs are critical for effective infrastructure management.
&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Building this two-tier architecture with Terraform was a rewarding journey that enhanced my understanding of cloud architecture and IaC best practices. I hope this blog inspires you to take on similar projects and simplifies your path to mastering Terraform.  &lt;/p&gt;

&lt;p&gt;Find the complete Terraform code in my &lt;a href="https://github.com/Otumiky/scalable-web-app" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;. Feel free to connect on LinkedIn or leave a comment below with any questions or feedback!  &lt;/p&gt;




</description>
    </item>
    <item>
      <title>Deploying a Static Website on AWS S3 with Terraform: A Beginner's Guide</title>
      <dc:creator>Otu Udo</dc:creator>
      <pubDate>Fri, 03 Jan 2025 09:49:10 +0000</pubDate>
      <link>https://dev.to/otumiky/deploying-a-static-website-on-aws-s3-with-terraform-a-beginners-guide-4edh</link>
      <guid>https://dev.to/otumiky/deploying-a-static-website-on-aws-s3-with-terraform-a-beginners-guide-4edh</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Terraform is a powerful Infrastructure as Code (IaC) tool that simplifies the provisioning of cloud resources. In this blog post, I will guide you through the process of deploying a static website on AWS using Terraform. This involves creating an S3 bucket for hosting the website, making it publicly accessible, uploading the website files, and configuring CloudFront to securely serve the content. Along the way, I’ll share some of the challenges I encountered and how I overcame them.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Project Structure&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The project follows a modular structure to ensure reusability and maintainability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project-root/
├── modules/
│   └── s3-static-website/
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
├── envs/
│   └── dev/
│       ├── main.tf
│       ├── variables.tf
│       ├── cloudfront.tf
│       ├── outputs.tf
│       ├── terraform.tfvars
│       └── backend.tf
├── website/
│   ├── index.html
│   ├── error.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Project Architecture&lt;/strong&gt;
&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%2Fk8y4hi34xa6z24b44w3r.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%2Fk8y4hi34xa6z24b44w3r.png" alt="Image description" width="800" height="651"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Module: &lt;code&gt;s3-static-website&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Defining the S3 Bucket&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The S3 bucket is configured to host the website and allow public access:&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;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_public_access_block"&lt;/span&gt; &lt;span class="s2"&gt;"wb"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;block_public_acls&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;block_public_policy&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;ignore_public_acls&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;restrict_public_buckets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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_s3_bucket_website_configuration"&lt;/span&gt; &lt;span class="s2"&gt;"wb"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;index_document&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;suffix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index_document&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;error_document&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error_document&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;
  
  
  &lt;strong&gt;2. Setting the Bucket Policy&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To make the bucket content publicly accessible, we define a bucket 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="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_policy"&lt;/span&gt; &lt;span class="s2"&gt;"wb"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&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;"2012-10-17"&lt;/span&gt;
    &lt;span class="nx"&gt;Statement&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;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;Principal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"*"&lt;/span&gt;
        &lt;span class="nx"&gt;Action&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;
        &lt;span class="nx"&gt;Resource&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${aws_s3_bucket.wb.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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;3. Uploading Website Files&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The website files are uploaded to the bucket:&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;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_object"&lt;/span&gt; &lt;span class="s2"&gt;"files"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fileset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source_directory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"**"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;key&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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;"${var.source_directory}/${each.value}"&lt;/span&gt;
  &lt;span class="nx"&gt;acl&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"public-read"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Environment: &lt;code&gt;dev&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Referencing the Module&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The root &lt;code&gt;main.tf&lt;/code&gt; in the &lt;code&gt;dev&lt;/code&gt; folder points to the S3 website module:&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;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="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"s3_website"&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;"../../modules/s3-static-website"&lt;/span&gt;
  &lt;span class="nx"&gt;bucket_name&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_name&lt;/span&gt;
  &lt;span class="nx"&gt;source_directory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../website"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;2. Configuring CloudFront&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;CloudFront is set up to securely front the S3 bucket:&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;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_cloudfront_distribution"&lt;/span&gt; &lt;span class="s2"&gt;"cdn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;origin_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"S3-${module.s3_website.bucket_name}"&lt;/span&gt;
    &lt;span class="nx"&gt;domain_name&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;s3_website&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regional_domain_name&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;enabled&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;is_ipv6_enabled&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;default_root_object&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"index.html"&lt;/span&gt;

  &lt;span class="nx"&gt;default_cache_behavior&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;allowed_methods&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"HEAD"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;cached_methods&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"HEAD"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;target_origin_id&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"S3-${module.s3_website.bucket_name}"&lt;/span&gt;
    &lt;span class="nx"&gt;viewer_protocol_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"redirect-to-https"&lt;/span&gt;
    &lt;span class="nx"&gt;min_ttl&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;default_ttl&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;
    &lt;span class="nx"&gt;max_ttl&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;

    &lt;span class="nx"&gt;forwarded_values&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;query_string&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="nx"&gt;cookies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;forward&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"none"&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;restrictions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;geo_restriction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;restriction_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"none"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;viewer_certificate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cloudfront_default_certificate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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;h2&gt;
  
  
  Steps to Deploy the Website
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Define the S3 Static Website Module
&lt;/h3&gt;

&lt;p&gt;Within the &lt;code&gt;modules/s3-static-website/&lt;/code&gt; directory:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;main.tf:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provisions the S3 bucket.&lt;/li&gt;
&lt;li&gt;Configures public access policies.&lt;/li&gt;
&lt;li&gt;Uploads website files (&lt;code&gt;index.html&lt;/code&gt; and &lt;code&gt;error.html&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;variables.tf:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accepts parameters like bucket name, source directory, and tags.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;outputs.tf:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exports the bucket name and website endpoint.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Website Files
&lt;/h3&gt;

&lt;p&gt;Ensure &lt;code&gt;index.html&lt;/code&gt; and &lt;code&gt;error.html&lt;/code&gt; are in the &lt;code&gt;website/&lt;/code&gt; directory to be uploaded to the S3 bucket.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run Terraform
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Change to the &lt;code&gt;dev&lt;/code&gt; directory:
&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;envs/dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Ensure &lt;code&gt;terraform.tfvars&lt;/code&gt; contains all required variables.&lt;/li&gt;
&lt;li&gt;Initialize and apply Terraform:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   terraform init
   terraform apply
&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%2Fth09gczo5hbjb40ygyrl.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%2Fth09gczo5hbjb40ygyrl.png" alt="Image description" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Applying..(wait for few minutes)&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%2Fc7da4t92myez2gvstu2f.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%2Fc7da4t92myez2gvstu2f.png" alt="Image description" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Voilà!! website successfully served on Cloudfront&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%2F8y74gaavf4pf2a0cfjhw.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%2F8y74gaavf4pf2a0cfjhw.png" alt="Image description" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Website up and running securely&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Challenges Faced&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Consuming Outputs from the Module&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Initially, I faced issues with accessing module outputs in the CloudFront configuration. The error arose because I incorrectly referenced the output variables. To resolve this, I ensured the outputs were properly defined in the module and referenced using the exact variable names. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Output Definition in &lt;code&gt;modules/s3-static-website/outputs.tf&lt;/code&gt;:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;  &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"bucket_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"regional_domain_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The regional domain name of the bucket."&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_regional_domain_name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reference in &lt;code&gt;dev/cloudfront.tf&lt;/code&gt;:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;  &lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;origin_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"S3-${module.s3_website.bucket_name}"&lt;/span&gt;
    &lt;span class="nx"&gt;domain_name&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;s3_website&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regional_domain_name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Otumiky/static-website" rel="noopener noreferrer"&gt;Link to git repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Handling Backend Configuration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;While setting up the Terraform backend for remote state management, I encountered permissions issues with the S3 bucket. This was resolved by reviewing the IAM policy and ensuring the required permissions (e.g., &lt;code&gt;s3:PutObject&lt;/code&gt; and &lt;code&gt;s3:GetObject&lt;/code&gt;) were granted to the Terraform user.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. CloudFront and S3 Integration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I initially misconfigured the &lt;code&gt;origin&lt;/code&gt; block in the CloudFront resource. The issue was traced to using an incorrect value for &lt;code&gt;domain_name&lt;/code&gt;. To fix this, I ensured that the &lt;code&gt;website_endpoint&lt;/code&gt; output from the module was used correctly.&lt;/p&gt;




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

&lt;p&gt;This project demonstrated how to deploy a static website on AWS with Terraform. The modular approach made it easier to reuse components and manage configurations across environments. Despite the challenges faced, such as consuming module outputs and configuring CloudFront, these hurdles provided valuable learning experiences.&lt;/p&gt;

&lt;p&gt;With this setup, the website is securely served through CloudFront while leveraging the scalability and cost-efficiency of S3. Terraform’s declarative nature ensured the process was repeatable and predictable, making it a great tool for managing cloud infrastructure.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>My Final Preparation for the Terraform Associate Exam</title>
      <dc:creator>Otu Udo</dc:creator>
      <pubDate>Thu, 02 Jan 2025 17:18:33 +0000</pubDate>
      <link>https://dev.to/otumiky/my-final-preparation-for-the-terraform-associate-exam-1inp</link>
      <guid>https://dev.to/otumiky/my-final-preparation-for-the-terraform-associate-exam-1inp</guid>
      <description>&lt;p&gt;&lt;strong&gt;Final Preparations for the Terraform Associate Exam: Time to Put Knowledge into Action&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The journey toward earning the Terraform Associate Certification has been as exciting as it has been challenging. This certification not only validates proficiency in Terraform but also opens doors to opportunities in cloud infrastructure management and automation. With the exam date approaching, it’s time to consolidate all the hard work and knowledge gained over the past few weeks.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Reflecting on the Learning Journey&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The preparation process has been a rewarding experience, full of valuable lessons and practical insights. Here are some of the highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Infrastructure as Code (IaC)&lt;/strong&gt;: Gaining a deeper understanding of how Terraform simplifies the provisioning and management of cloud resources was a key milestone. Writing clean, reusable, and modular code has been central to mastering IaC principles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;State Management&lt;/strong&gt;: Managing Terraform’s state file has been both enlightening and humbling. From understanding its role in tracking resources to configuring remote state storage for collaboration, every step has provided critical hands-on experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Building Real-World Projects&lt;/strong&gt;: Whether deploying S3 buckets for static websites, integrating CloudFront, or creating scalable infrastructure, practical projects were the cornerstone of this journey. Each project introduced new concepts and cemented foundational knowledge.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Troubleshooting Skills&lt;/strong&gt;: Errors are an inevitable part of working with any tool, and Terraform is no exception. Encountering and resolving issues—from dependency problems to configuration mismatches—was an invaluable learning experience.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Strategies for the Final Stretch&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In these last few days, the focus is on reinforcing understanding and building confidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reviewing Documentation&lt;/strong&gt;: Revisiting Terraform’s official documentation and best practices to ensure all foundational concepts are solidified.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mock Exams&lt;/strong&gt;: Practicing with mock tests and real-world scenarios to identify areas that need improvement and to become familiar with the exam’s structure and timing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Key Concepts&lt;/strong&gt;: Paying extra attention to essential topics, such as providers, modules, variables, outputs, state management, and resource lifecycle policies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hands-On Practice&lt;/strong&gt;: Continuing to apply knowledge through small but impactful configurations, ensuring that muscle memory is well-developed for the exam.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Looking Ahead&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Terraform Associate Certification is more than a credential—it’s a stepping stone toward expertise in cloud automation and DevOps. It reflects not only technical skills but also problem-solving abilities and a commitment to continuous learning.&lt;/p&gt;

&lt;p&gt;This journey has underscored the importance of perseverance, curiosity, and hands-on experience. The excitement of creating, managing, and scaling infrastructure with Terraform has been unparalleled. While the exam is a milestone, the real reward lies in the confidence and competence gained along the way.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;A Note to Fellow Learners&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For those on a similar path, embrace the challenges and celebrate the small victories. Every troubleshooting session, every successfully applied configuration, and every concept understood brings you closer to mastery. Let’s continue to learn, grow, and share knowledge as a community.&lt;/p&gt;

&lt;p&gt;Wish me luck as I take on this final step, and if you’re preparing too, feel free to connect. Together, we can achieve great things!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Preparing for the Terraform Associate Exam - Key Resources and Tips</title>
      <dc:creator>Otu Udo</dc:creator>
      <pubDate>Wed, 01 Jan 2025 15:12:09 +0000</pubDate>
      <link>https://dev.to/otumiky/preparing-for-the-terraform-associate-exam-key-resources-and-tips-4nkf</link>
      <guid>https://dev.to/otumiky/preparing-for-the-terraform-associate-exam-key-resources-and-tips-4nkf</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As the demand for Infrastructure as Code (IaC) grows, earning the HashiCorp Certified: Terraform Associate certification is an excellent way to validate your Terraform expertise. Whether you’re new to Terraform or looking to solidify your skills, this guide highlights key resources and actionable tips to help you prepare effectively for the exam.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why the Terraform Associate Certification Matters&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Terraform Associate certification is designed for cloud engineers and DevOps professionals who use Terraform in their workflows. It demonstrates your ability to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand core Terraform concepts like providers, state, and modules.&lt;/li&gt;
&lt;li&gt;Manage and provision infrastructure efficiently.&lt;/li&gt;
&lt;li&gt;Apply Terraform best practices in real-world scenarios.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Achieving this certification not only boosts your credentials but also enhances your confidence in managing infrastructure as code.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Key Resources for Exam Preparation&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Official Exam Guide&lt;/strong&gt;&lt;br&gt;
Start with the &lt;a href="https://developer.hashicorp.com/terraform/certification" rel="noopener noreferrer"&gt;Terraform Associate Exam guide&lt;/a&gt;. It outlines the objectives, exam format, and topics you’ll be tested on, such as resource management, state management, and workspace usage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Terraform Documentation&lt;/strong&gt;&lt;br&gt;
HashiCorp’s &lt;a href="https://developer.hashicorp.com/terraform/docs" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; is an essential resource. Focus on areas like providers, variables, modules, and debugging.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Terraform: Up &amp;amp; Running&lt;/strong&gt; by Yevgeniy Brikman&lt;br&gt;
This book provides practical, real-world examples and insights into Terraform. It’s an excellent resource for mastering both the basics and advanced concepts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Interactive Learning Platforms&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://learn.hashicorp.com/terraform" rel="noopener noreferrer"&gt;HashiCorp Learn&lt;/a&gt;: Offers step-by-step guides and tutorials tailored to the exam topics.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://katacoda.com/scenarios/terraform" rel="noopener noreferrer"&gt;Katacoda&lt;/a&gt;: Interactive scenarios that let you practice Terraform commands and concepts in a live environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Practice Exams&lt;/strong&gt;&lt;br&gt;
Mock exams help you familiarize yourself with the test format and question style. Platforms like &lt;a href="https://www.udemy.com/" rel="noopener noreferrer"&gt;Udemy&lt;/a&gt; and &lt;a href="https://www.whizlabs.com/" rel="noopener noreferrer"&gt;Whizlabs&lt;/a&gt; offer high-quality practice tests.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tips for Success&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Understand Core Concepts&lt;/strong&gt;&lt;br&gt;
Focus on the fundamentals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The purpose of &lt;code&gt;terraform plan&lt;/code&gt;, &lt;code&gt;apply&lt;/code&gt;, and &lt;code&gt;destroy&lt;/code&gt; commands.&lt;/li&gt;
&lt;li&gt;The role of the Terraform state and how to manage it.&lt;/li&gt;
&lt;li&gt;Dependency resolution and resource configurations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hands-On Practice&lt;/strong&gt;&lt;br&gt;
Apply what you learn by working on real projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create infrastructure for web applications.&lt;/li&gt;
&lt;li&gt;Use modules to structure reusable code.&lt;/li&gt;
&lt;li&gt;Experiment with multiple cloud providers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Learn Error Debugging&lt;/strong&gt;&lt;br&gt;
Be familiar with Terraform error messages and how to resolve them. This includes state lock issues, provider authentication errors, and syntax errors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Engage with the Community&lt;/strong&gt;&lt;br&gt;
Join Terraform forums, Reddit communities, or HashiCorp Slack channels. Interacting with peers helps you stay updated and gain valuable insights from their experiences.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stick to a Study Plan&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allocate time for each exam objective.&lt;/li&gt;
&lt;li&gt;Combine reading with hands-on practice.&lt;/li&gt;
&lt;li&gt;Test your knowledge with practice exams.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Common Pitfalls to Avoid&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Skipping foundational topics: Ensure you’re comfortable with core concepts before diving into advanced scenarios.&lt;/li&gt;
&lt;li&gt;Overlooking documentation: Terraform documentation is comprehensive and often clarifies key exam topics.&lt;/li&gt;
&lt;li&gt;Neglecting practice: The exam tests your practical knowledge, so hands-on experience is essential.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Preparing for the Terraform Associate exam is a rewarding journey that deepens your understanding of Terraform and its applications. By leveraging the right resources, practicing regularly, and engaging with the community, you can confidently tackle the exam and advance your career in cloud engineering and DevOps.&lt;/p&gt;

&lt;p&gt;Good luck, and happy Terraforming!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A Workflow for Deploying Application Code with Terraform</title>
      <dc:creator>Otu Udo</dc:creator>
      <pubDate>Mon, 30 Dec 2024 21:40:16 +0000</pubDate>
      <link>https://dev.to/otumiky/a-workflow-for-deploying-application-code-with-terraform-37ph</link>
      <guid>https://dev.to/otumiky/a-workflow-for-deploying-application-code-with-terraform-37ph</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;As infrastructure as code (IaC) continues to transform the way applications are managed and deployed, tools like &lt;strong&gt;Terraform&lt;/strong&gt; and &lt;strong&gt;Terraform Cloud&lt;/strong&gt; provide powerful solutions for managing cloud infrastructure and deploying application code efficiently. Let's walk through a step-by-step workflow for deploying application code using Terraform and integrating version control systems (VCS) while securing sensitive variables.&lt;/p&gt;

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

&lt;p&gt;Before diving into the workflow, ensure the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terraform is installed locally.&lt;/li&gt;
&lt;li&gt;A Terraform Cloud account is set up.&lt;/li&gt;
&lt;li&gt;A version control system (e.g., GitHub) is configured with your Terraform project.&lt;/li&gt;
&lt;li&gt;Necessary cloud provider credentials are available (e.g., AWS).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1: Set Up a Terraform Cloud Workspace
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Log into &lt;strong&gt;Terraform Cloud&lt;/strong&gt; and create a new workspace.&lt;/li&gt;
&lt;li&gt;Link the workspace to your version control system (e.g., GitHub repository).&lt;/li&gt;
&lt;li&gt;Select the desired branch to track (commonly &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;develop&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Terraform Cloud will now monitor this branch for changes and trigger runs accordingly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Write Terraform Configuration Files
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Define your infrastructure in &lt;code&gt;.tf&lt;/code&gt; files within the GitHub repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Example for deploying an AWS EC2 instance:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&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-west-2"&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_instance"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ami_id&lt;/span&gt;
    &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t3.micro"&lt;/span&gt;

    &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&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;"TerraformExampleInstance"&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;/li&gt;
&lt;li&gt;&lt;p&gt;Include a &lt;code&gt;variables.tf&lt;/code&gt; file to define input variables, such as AMI IDs or database credentials.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add a &lt;code&gt;terraform.tfvars&lt;/code&gt; or &lt;code&gt;.auto.tfvars&lt;/code&gt; file to supply default variable values, excluding sensitive ones.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 3: Secure Sensitive Variables
&lt;/h2&gt;

&lt;p&gt;Sensitive variables, such as API keys and passwords, should never be hardcoded in your configuration files. Instead, secure them in Terraform Cloud:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Variables&lt;/strong&gt; tab of your workspace.&lt;/li&gt;
&lt;li&gt;Add sensitive variables (e.g., &lt;code&gt;db_password&lt;/code&gt;) under &lt;strong&gt;Environment Variables&lt;/strong&gt; or &lt;strong&gt;Terraform Variables&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Ensure &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; and &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; are stored as environment variables for authentication.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 4: Push Changes to GitHub
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Commit your Terraform configuration to the GitHub repository:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add initial Terraform configuration"&lt;/span&gt;
git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Terraform Cloud automatically detects changes in the repository and initiates a &lt;strong&gt;Plan&lt;/strong&gt; run to evaluate the proposed changes.&lt;/p&gt;&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%2Fvwj4srongxvkb40htt11.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%2Fvwj4srongxvkb40htt11.png" alt="Image description" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Review and Approve Plan
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Runs&lt;/strong&gt; tab in Terraform Cloud.&lt;/li&gt;
&lt;li&gt;Review the plan to ensure the changes match your expectations.&lt;/li&gt;
&lt;li&gt;Approve the plan to apply the changes (if manual approval is enabled).&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 6: Deploy the Application
&lt;/h2&gt;

&lt;p&gt;Once the plan is approved, Terraform Cloud automatically applies the changes, provisioning the necessary infrastructure and deploying the application code.&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%2F07s9e0gazpkl2nv05y7p.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%2F07s9e0gazpkl2nv05y7p.png" alt="Image description" width="800" height="431"&gt;&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%2Fbxfd59lyl3akea5xl2cn.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%2Fbxfd59lyl3akea5xl2cn.png" alt="Image description" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&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%2F05ppnlzdy3rs0agk2ltr.png" alt="Image description" width="800" height="430"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Step 7: Manage Updates
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;To make updates, modify the Terraform configuration files locally.&lt;/li&gt;
&lt;li&gt;Push the changes to the tracked branch in the GitHub repository.&lt;/li&gt;
&lt;li&gt;Terraform Cloud triggers a new Plan and Apply cycle, reflecting the updates in your infrastructure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Don't forget to destroy the infrastructure after completing the task. Headover to settings&amp;gt;Destruction and deletion, then hit "Queue destroy plan"&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%2F0sbxju5la9pujleyw6sh.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%2F0sbxju5la9pujleyw6sh.png" alt="Image description" width="800" height="430"&gt;&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%2Fsf4yv3yexlhtueixfqdx.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%2Fsf4yv3yexlhtueixfqdx.png" alt="Image description" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Advantages of This Workflow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Version Control Integration&lt;/strong&gt;: GitHub acts as the single source of truth, ensuring a streamlined and auditable process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation&lt;/strong&gt;: Terraform Cloud automates infrastructure deployment, reducing manual intervention and errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: Sensitive variables are securely managed, avoiding exposure in code repositories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: The workflow supports a range of cloud providers and resource types, adapting to diverse infrastructure needs.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;By following this step-by-step workflow, teams can deploy application code efficiently and securely while leveraging the automation and collaborative capabilities of Terraform Cloud. Start incorporating this process into your DevOps pipeline and experience the benefits of infrastructure as code with Terraform!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Convince Your Team to Adopt Infrastructure as Code (IaC)</title>
      <dc:creator>Otu Udo</dc:creator>
      <pubDate>Sun, 29 Dec 2024 22:04:52 +0000</pubDate>
      <link>https://dev.to/otumiky/how-to-convince-your-team-to-adopt-infrastructure-as-code-iac-7ao</link>
      <guid>https://dev.to/otumiky/how-to-convince-your-team-to-adopt-infrastructure-as-code-iac-7ao</guid>
      <description>&lt;p&gt;&lt;strong&gt;How to Successfully Introduce Infrastructure as Code (IaC) to Your Team&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Infrastructure as Code (IaC) is revolutionizing how organizations manage and deploy infrastructure. However, adopting IaC isn’t just about picking the right tools; it’s about cultural shifts, new processes, and a willingness to embrace change. Whether you’re part of a startup or an established enterprise, here’s a practical guide to introducing IaC effectively within your team and organization.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1: Convince Your Boss&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The first step in adopting IaC is securing buy-in from leadership. This requires a clear understanding of costs, benefits, and alignment with business priorities.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Understand the Costs&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Adopting IaC comes with challenges that can create resistance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Skills Gap&lt;/strong&gt;: Moving from manual infrastructure management to coding requires upskilling operations teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool Adoption&lt;/strong&gt;: Teams accustomed to traditional tools might resist adopting new ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mindset Shift&lt;/strong&gt;: Transitioning from manual changes to automated, indirect processes can be frustrating at first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Opportunity Costs&lt;/strong&gt;: Implementing IaC requires time and resources, potentially diverting focus from other projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Speak Your Boss’s Language&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When pitching IaC to your boss, focus on the problems it solves rather than the technical features it offers. Identify key pain points, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frequent outages caused by manual errors.&lt;/li&gt;
&lt;li&gt;Difficulty scaling infrastructure efficiently.&lt;/li&gt;
&lt;li&gt;Slow deployment processes, hindering innovation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, demonstrate how IaC addresses these issues directly. For instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automation&lt;/strong&gt;: IaC reduces manual errors, minimizing outages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Infrastructure can be provisioned on demand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt;: Automated deployments save time and increase agility.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Sell a Vision&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Paint a compelling picture of the future:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Imagine automated deployments with fewer outages, improved reliability, and faster time-to-market."&lt;/li&gt;
&lt;li&gt;Highlight how these improvements align with business objectives like cost savings and improved customer satisfaction.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2: Work Incrementally&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Massive, "big bang" transitions often fail due to complexity and unforeseen challenges. Instead, adopt an incremental approach to IaC implementation.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Avoid Big Bang Projects&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Instead of overhauling all infrastructure at once, start small. Focus on automating a single process or managing one application’s infrastructure with IaC.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Deliver Value at Every Step&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Each step in your IaC journey should deliver independent, tangible benefits. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automate the deployment process for a specific application.&lt;/li&gt;
&lt;li&gt;Implement version control for configuration files.&lt;/li&gt;
&lt;li&gt;Introduce testing for infrastructure changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Build Momentum&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Quick wins help gain confidence from leadership and team members. Success in one area can inspire other teams to adopt IaC, creating a ripple effect across the organization.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3: Give Your Team the Time to Learn&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;IaC introduces new tools, languages, and workflows. It’s essential to allow your team the time and resources to adapt.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Acknowledge the Learning Curve&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Your team will need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Master new tools like Terraform, AWS CloudFormation, or Ansible.&lt;/li&gt;
&lt;li&gt;Learn to think programmatically about infrastructure.&lt;/li&gt;
&lt;li&gt;Adjust to processes like code reviews and automated testing for infrastructure changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Encourage Collaboration&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Foster a culture of collaboration and knowledge sharing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pair team members with varying levels of experience.&lt;/li&gt;
&lt;li&gt;Host regular knowledge-sharing sessions or workshops.&lt;/li&gt;
&lt;li&gt;Encourage team members to experiment and learn from mistakes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By investing in your team’s growth, you set the stage for long-term success.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Key Takeaways&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Adopting IaC is a journey that requires both technical and cultural transformation. Here’s how to ensure a smooth transition:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Strategic Alignment&lt;/strong&gt;: Focus on solving real problems that matter to your organization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental Progress&lt;/strong&gt;: Deliver immediate value with small, manageable changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team Empowerment&lt;/strong&gt;: Provide your team the time and resources to learn and grow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Infrastructure as Code has the power to transform your organization’s operations, but success depends on a thoughtful, step-by-step approach. By addressing both technical and human factors, you can lead your team to a more efficient, scalable, and reliable future.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What’s Next?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Are you ready to embark on your IaC journey? Start by identifying a small project to automate and involve your team in the process. Celebrate every milestone, and before you know it, IaC will become second nature across your organization.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deploying Multi-Cloud Infrastructure with Terraform Modules</title>
      <dc:creator>Otu Udo</dc:creator>
      <pubDate>Mon, 23 Dec 2024 09:57:23 +0000</pubDate>
      <link>https://dev.to/otumiky/deploying-multi-cloud-infrastructure-with-terraform-modules-2732</link>
      <guid>https://dev.to/otumiky/deploying-multi-cloud-infrastructure-with-terraform-modules-2732</guid>
      <description>&lt;p&gt;&lt;strong&gt;Building an Infrastructure-as-Code Solution with Terraform Modules: Deploying EKS Clusters and Kubernetes Applications&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Managing modern cloud infrastructures efficiently requires robust tools and practices. &lt;strong&gt;Terraform&lt;/strong&gt;, with its support for reusable modules, empowers engineers to create scalable, maintainable, and version-controlled cloud resources. In this blog post, I’ll share how I used Terraform to deploy an &lt;strong&gt;Amazon Elastic Kubernetes Service (EKS)&lt;/strong&gt; cluster and a Kubernetes application module into AWS, leveraging a default Virtual Private Cloud (VPC). This project highlights the advantages of modular Terraform configurations for infrastructure-as-code (IaC).&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;The Challenge&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Deploying and managing Kubernetes clusters in the cloud is a complex task. It involves provisioning the control plane, configuring worker nodes, managing networking, and ensuring compatibility with application workloads. To streamline this process, I:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Used Terraform’s &lt;strong&gt;EKS module&lt;/strong&gt; to provision an Amazon EKS cluster.&lt;/li&gt;
&lt;li&gt;Created a &lt;strong&gt;Kubernetes application module&lt;/strong&gt; for deploying workloads onto the EKS cluster.&lt;/li&gt;
&lt;li&gt;Integrated both modules with AWS’s default VPC, maintaining simplicity and scalability.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Why Terraform Modules?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Terraform modules help break down infrastructure code into smaller, reusable, and manageable units. Key benefits include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reusability&lt;/strong&gt;: Modules encapsulate common configurations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt;: Ensures resources are provisioned with standardized practices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified Maintenance&lt;/strong&gt;: Updates to a module automatically propagate to all instances.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Architecture Overview&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The infrastructure consists of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Terraform&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EKS Module: Provisions the Kubernetes cluster.&lt;/li&gt;
&lt;li&gt;Kubernetes App Module: Deploys workloads onto the EKS cluster.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AWS Cloud&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Default VPC with subnets and Internet Gateway.&lt;/li&gt;
&lt;li&gt;Amazon EKS Cluster: Managed control plane and worker nodes.&lt;/li&gt;
&lt;li&gt;Networking: Handles pod communication and external access.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Workloads deployed using Kubernetes manifests.&lt;/li&gt;
&lt;li&gt;Services exposing applications externally.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Implementation&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Terraform EKS Module&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The EKS module provisions the cluster, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Control Plane (managed by AWS).&lt;/li&gt;
&lt;li&gt;Worker Nodes in an Auto Scaling Group.&lt;/li&gt;
&lt;li&gt;Networking configuration to use the default VPC.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"eks_cluster"&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;"path/to/eks_cluster_module"&lt;/span&gt;


  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;

  &lt;span class="nx"&gt;min_size&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="nx"&gt;max_size&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="nx"&gt;desired_size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

  &lt;span class="nx"&gt;instance_types&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"t3.small"&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;h4&gt;
  
  
  &lt;strong&gt;2. Kubernetes App Module&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The Kubernetes app module deploys a simple web application into the EKS cluster. It defines the number of replicas, container image, and environment variables.&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;module&lt;/span&gt; &lt;span class="s2"&gt;"simple_webapp"&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;"path/to/k8s_app_module"&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;"simple-webapp"&lt;/span&gt;
  &lt;span class="nx"&gt;image&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"training/webapp"&lt;/span&gt;
  &lt;span class="nx"&gt;replicas&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="nx"&gt;container_port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;

  &lt;span class="nx"&gt;environment_variables&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="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"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;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Otumiky/Deploy-K8s-app-using-Terraform-Modular-approach" rel="noopener noreferrer"&gt;Link to git repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Default VPC&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Using AWS’s default VPC eliminates the need for custom VPC configurations. The modules are configured to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use public subnets for worker nodes and load balancers.&lt;/li&gt;
&lt;li&gt;Ensure pod-to-pod communication inside the cluster.&lt;/li&gt;
&lt;li&gt;Route ingress/egress traffic via an Internet Gateway.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Diagram&lt;/strong&gt;
&lt;/h3&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%2Fal9lgbeipro25c62cfvu.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%2Fal9lgbeipro25c62cfvu.png" alt="diagram" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s a high-level view of the architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Terraform&lt;/strong&gt; provisions:

&lt;ul&gt;
&lt;li&gt;EKS cluster in the default VPC.&lt;/li&gt;
&lt;li&gt;Kubernetes workloads using the Kubernetes app module.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;AWS Components&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Default VPC with subnets and Internet Gateway.&lt;/li&gt;
&lt;li&gt;EKS control plane and worker nodes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Kubernetes Layer&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Pods, Deployments, and Services.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Deployment Steps&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prepare the Environment&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Terraform and configure AWS credentials.&lt;/li&gt;
&lt;li&gt;Ensure kubectl is installed and configured for EKS access.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Provision Infrastructure&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execute &lt;code&gt;terraform init&lt;/code&gt; to initialize the modules.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;terraform apply&lt;/code&gt; to create resources.&lt;/li&gt;
&lt;/ul&gt;
&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%2F1bsg2gwj3rr1xg685fvy.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%2F1bsg2gwj3rr1xg685fvy.png" alt="Image description" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Verify Deployment&lt;/strong&gt;:
Wait a little while for the web app to spin up and pass health checks, and then test out
the service_endpoint:&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%2Fi1g8jk7k0v0v1hy87sfl.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%2Fi1g8jk7k0v0v1hy87sfl.png" alt="Image description" width="800" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check EKS cluster status using &lt;code&gt;kubectl get nodes&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Verify the Kubernetes application is running: &lt;code&gt;kubectl get pods&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Challenges and Lessons Learned&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes Version Compatibility&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure the EKS module uses a supported Kubernetes version (e.g., 1.27).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Image Deprecation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upgraded container images to comply with OCI standards.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Networking Configurations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Default VPC simplifies networking, but may need custom configurations for production-grade deployments.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;This project highlights the power of Terraform modules in managing cloud infrastructure efficiently. By modularizing configurations for EKS and Kubernetes apps, I achieved a scalable, reusable, and maintainable setup. The approach is ideal for teams looking to standardize IaC practices while leveraging AWS and Kubernetes capabilities.&lt;/p&gt;

&lt;p&gt;Have you implemented similar Terraform-based solutions? Share your experiences in the comments!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Handle Sensitive Data Securely in Terraform</title>
      <dc:creator>Otu Udo</dc:creator>
      <pubDate>Thu, 19 Dec 2024 15:22:18 +0000</pubDate>
      <link>https://dev.to/otumiky/how-to-handle-sensitive-data-securely-in-terraform-12n0</link>
      <guid>https://dev.to/otumiky/how-to-handle-sensitive-data-securely-in-terraform-12n0</guid>
      <description>&lt;p&gt;&lt;strong&gt;Managing Sensitive Data in Terraform with AWS Secrets Manager&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In modern DevOps practices, managing sensitive data securely is crucial for maintaining both operational efficiency and security. Hardcoding passwords or other sensitive information in your Terraform configurations can expose them to risks such as data breaches or unauthorized access. Fortunately, Terraform allows you to use secure services like &lt;strong&gt;AWS Secrets Manager&lt;/strong&gt; to securely manage secrets like EC2 admin passwords, database login credentials, preventing these risks.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore how to securely manage an EC2 admin password using Terraform and AWS Secrets Manager, following best practices for secret management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Manage Sensitive Data Securely?
&lt;/h3&gt;

&lt;p&gt;Sensitive data, such as passwords and access keys, must be protected both in transit and at rest. By storing these secrets in a service like &lt;strong&gt;AWS Secrets Manager&lt;/strong&gt; instead of directly in your Terraform configuration, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prevent accidental exposure&lt;/strong&gt; of secrets through version control systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leverage encryption&lt;/strong&gt; for added security.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rotate secrets&lt;/strong&gt; periodically to improve security hygiene.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enforce access control&lt;/strong&gt; using IAM policies to ensure only authorized users and services can access secrets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example Setup: Managing EC2 Admin Password
&lt;/h3&gt;

&lt;p&gt;Let’s break down the two Terraform files we will use: &lt;code&gt;main.tf&lt;/code&gt; and &lt;code&gt;variables.tf&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;variables.tf&lt;/code&gt; (Storing the EC2 Admin Password Securely)
&lt;/h4&gt;

&lt;p&gt;In &lt;code&gt;variables.tf&lt;/code&gt;, we define the EC2 admin password as a variable, allowing us to securely pass the value to Terraform without hardcoding it directly in the configuration.&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;variable&lt;/span&gt; &lt;span class="s2"&gt;"ec2_admin_password"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The admin password for the EC2 instance"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;sensitive&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;sensitive = true&lt;/code&gt; flag tells Terraform to treat this variable as sensitive, meaning it won't be displayed in the Terraform output or logs.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;main.tf&lt;/code&gt; (Configuring the EC2 Instance and Secret Manager)
&lt;/h4&gt;

&lt;p&gt;Now, let’s configure the resources. We'll create a secret in &lt;strong&gt;AWS Secrets Manager&lt;/strong&gt; to store the EC2 admin password securely. We'll also set up the EC2 instance and its SSH key pair.&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;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="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Create a Secret in AWS Secrets Manager&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_secretsmanager_secret"&lt;/span&gt; &lt;span class="s2"&gt;"ec2_admin_password_secret"&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;"EC2AdminPassword"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Admin password for the EC2 instance"&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_secretsmanager_secret_version"&lt;/span&gt; &lt;span class="s2"&gt;"ec2_admin_password_version"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;secret_id&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_secretsmanager_secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2_admin_password_secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;secret_string&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;admin_password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2_admin_password&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Create a Key Pair for SSH Access&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_key_pair"&lt;/span&gt; &lt;span class="s2"&gt;"key_pair"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;key_name&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-key"&lt;/span&gt;
  &lt;span class="nx"&gt;public_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"C:&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;Users&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;madus&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;.ssh&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;my-key.pub"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Security Group for EC2&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"ec2_security_group"&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;"ec2_security_group"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow SSH and HTTP access"&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Adjust for better security in production&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-1"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/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="c1"&gt;# Launch an EC2 Instance&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"web_server"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-0e2c8caa4b6378d8c"&lt;/span&gt; &lt;span class="c1"&gt;#Ubuntu AMI&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;

  &lt;span class="nx"&gt;key_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_key_pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key_pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key_name&lt;/span&gt;
  &lt;span class="nx"&gt;security_groups&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_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2_security_group&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="nx"&gt;user_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="no"&gt;EOT&lt;/span&gt;&lt;span class="sh"&gt;
              #!/bin/bash
              apt update -y
              apt install -y apache2
              systemctl start apache2
              systemctl enable apache2
              echo "Admin password is stored securely!" &amp;gt; /var/www/html/index.html
&lt;/span&gt;&lt;span class="no"&gt;              EOT

&lt;/span&gt;  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&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;"WebServer"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"instance_public_ip"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web_server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_ip&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Public IP of the EC2 instance"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just after initializing terraform,hit terraform apply. You'll see the prompt to enter admin password for the EC2 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%2F4odlwjq20pqno0nfxmyq.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%2F4odlwjq20pqno0nfxmyq.png" alt="prompt" width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Password for the EC2 instance successfully created an stored securely.&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%2F5anqkaqqj3cmgrf2gdvv.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%2F5anqkaqqj3cmgrf2gdvv.png" alt="secret" width="800" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Explanation of the Terraform Configuration:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS Secrets Manager&lt;/strong&gt;: We create a secret to store the EC2 admin password, which is then referenced by the &lt;code&gt;aws_secretsmanager_secret_version&lt;/code&gt; resource to securely store the password.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSH Key Pair&lt;/strong&gt;: A key pair is created to provide secure SSH access to the EC2 instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EC2 Instance&lt;/strong&gt;: The EC2 instance is launched with the &lt;code&gt;ami-0e2c8caa4b6378d8c&lt;/code&gt; (Ubuntu AMI) and configured with the provided key pair for SSH access. We also define the instance's &lt;code&gt;user_data&lt;/code&gt; to automatically install and start an HTTP server on the instance.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Benefits of Using Secrets Manager:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Encryption&lt;/strong&gt;: Secrets Manager automatically encrypts the password using AWS Key Management Service (KMS), ensuring that sensitive data is stored securely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Control&lt;/strong&gt;: Using AWS IAM, you can control who can access and manage the stored secret.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password Rotation&lt;/strong&gt;: Secrets Manager supports automatic password rotation, further enhancing security by ensuring passwords are regularly updated.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;By using Terraform alongside AWS Secrets Manager, we can securely manage sensitive data like EC2 admin passwords, preventing potential vulnerabilities. This approach adheres to best practices in secret management, ensuring our infrastructure remains both secure and compliant. Whether you're managing one EC2 instance or thousands, implementing secure secret management with AWS Secrets Manager is a critical step toward a more robust cloud infrastructure.&lt;/p&gt;

&lt;p&gt;Remember to always treat sensitive data with care, and leverage AWS services to secure and automate your cloud infrastructure management. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Mastering Zero-Downtime Deployments with Terraform</title>
      <dc:creator>Otu Udo</dc:creator>
      <pubDate>Wed, 18 Dec 2024 17:48:57 +0000</pubDate>
      <link>https://dev.to/otumiky/mastering-zero-downtime-deployments-with-terraform-14o</link>
      <guid>https://dev.to/otumiky/mastering-zero-downtime-deployments-with-terraform-14o</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In today's fast-paced digital world, ensuring your applications run with minimal disruptions is crucial. Zero downtime deployment is a powerful strategy that allows you to roll out updates to your systems without taking your services offline. One effective way to implement this strategy is through &lt;strong&gt;Blue-Green Deployment&lt;/strong&gt;. In this post, I’ll walk you through a simple Terraform configuration that demonstrates how you can set up a Blue-Green deployment using AWS services such as EC2, Load Balancers, and Auto Scaling Groups, ensuring zero downtime during your application updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Blue-Green Deployment?
&lt;/h3&gt;

&lt;p&gt;Blue-Green deployment is a strategy that reduces downtime by maintaining two identical environments: one active (Blue) and one idle (Green). When deploying a new version of an application:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The new version is deployed to the idle environment (Green).&lt;/li&gt;
&lt;li&gt;Once the new version is tested and verified, traffic is switched to the Green environment.&lt;/li&gt;
&lt;li&gt;The old environment (Blue) is then idle, and you can roll back to it if needed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This method ensures that there’s no downtime during the switch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Components in Our Setup
&lt;/h3&gt;

&lt;p&gt;To implement Blue-Green Deployment with Terraform, we’ll need a few key resources:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Elastic Load Balancer (ALB)&lt;/strong&gt;: The load balancer will distribute traffic between the Blue and Green environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target Groups&lt;/strong&gt;: We’ll set up two target groups—one for the Blue environment and one for the Green.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Scaling Groups&lt;/strong&gt;: These will manage the EC2 instances in each environment, scaling them based on demand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Launch Configurations&lt;/strong&gt;: These define the AMI, instance type, and other settings for the EC2 instances.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Terraform Setup
&lt;/h3&gt;

&lt;p&gt;Let's dive into the Terraform configuration, split into two files: &lt;code&gt;main.tf&lt;/code&gt; for the main resources and &lt;code&gt;variables.tf&lt;/code&gt; for input variables.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;variables.tf&lt;/code&gt; – Input Variables
&lt;/h4&gt;

&lt;p&gt;Here we define the input variables that make the setup flexible and customizable.&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;variable&lt;/span&gt; &lt;span class="s2"&gt;"environment"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Deployment environment (blue or green)"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"blue"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"app_port"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The port the application listens on"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"ami_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AMI ID for EC2 instances"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-0e2c8caa4b6378d8c"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"instance_type"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"EC2 instance type"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;environment&lt;/code&gt;&lt;/strong&gt;: Specifies whether the deployment is for the Blue or Green environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ami_id&lt;/code&gt;&lt;/strong&gt;: The AMI ID to be used for the EC2 instances.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;instance_type&lt;/code&gt;&lt;/strong&gt;: Defines the EC2 instance type.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;app_port&lt;/code&gt;&lt;/strong&gt;: The port on which your application listens (default is &lt;code&gt;8080&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;main.tf&lt;/code&gt; – Core Resources
&lt;/h4&gt;

&lt;p&gt;Now, let's define the core AWS resources that enable Blue-Green deployment.&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, &amp;lt; 2.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; 4.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="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"alb"&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;"bg-alb-sg"&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_security_group_rule"&lt;/span&gt; &lt;span class="s2"&gt;"allow_http_inbound"&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;"ingress"&lt;/span&gt;
  &lt;span class="nx"&gt;security_group_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;from_port&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
  &lt;span class="nx"&gt;to_port&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
  &lt;span class="nx"&gt;protocol&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc"&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_subnets"&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;filter&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;"vpc-id"&lt;/span&gt;
    &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="p"&gt;=&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_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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_lb"&lt;/span&gt; &lt;span class="s2"&gt;"example"&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;"blue-green-lb"&lt;/span&gt;
  &lt;span class="nx"&gt;internal&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;load_balancer_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application"&lt;/span&gt;
  &lt;span class="nx"&gt;security_groups&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_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;subnets&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_subnets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ids&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_lb_target_group"&lt;/span&gt; &lt;span class="s2"&gt;"blue"&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;"blue-target-group"&lt;/span&gt;
  &lt;span class="nx"&gt;port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
  &lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP"&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&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_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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_lb_target_group"&lt;/span&gt; &lt;span class="s2"&gt;"green"&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;"green-target-group"&lt;/span&gt;
  &lt;span class="nx"&gt;port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
  &lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP"&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&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_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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_lb_listener"&lt;/span&gt; &lt;span class="s2"&gt;"http"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;load_balancer_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="nx"&gt;port&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
  &lt;span class="nx"&gt;protocol&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP"&lt;/span&gt;

  &lt;span class="nx"&gt;default_action&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;"forward"&lt;/span&gt;
    &lt;span class="nx"&gt;target_group_arn&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"blue"&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;aws_lb_target_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;aws_lb_target_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;green&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="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_launch_configuration"&lt;/span&gt; &lt;span class="s2"&gt;"blue"&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;"blue-launch-configuration"&lt;/span&gt;
  &lt;span class="nx"&gt;image_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ami_id&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_type&lt;/span&gt;
  &lt;span class="nx"&gt;security_groups&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_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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_launch_configuration"&lt;/span&gt; &lt;span class="s2"&gt;"green"&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;"green-launch-configuration"&lt;/span&gt;
  &lt;span class="nx"&gt;image_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ami_id&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_type&lt;/span&gt;
  &lt;span class="nx"&gt;security_groups&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_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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_autoscaling_group"&lt;/span&gt; &lt;span class="s2"&gt;"blue"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;desired_capacity&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="nx"&gt;max_size&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="nx"&gt;min_size&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_zone_identifier&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_subnets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;
  &lt;span class="nx"&gt;launch_configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_launch_configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;target_group_arns&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_lb_target_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blue&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="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_autoscaling_group"&lt;/span&gt; &lt;span class="s2"&gt;"green"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;desired_capacity&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="nx"&gt;max_size&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="nx"&gt;min_size&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_zone_identifier&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_subnets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;
  &lt;span class="nx"&gt;launch_configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_launch_configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;target_group_arns&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_lb_target_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;green&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Breakdown of Key Resources
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Security Groups&lt;/strong&gt;: A security group is created to allow inbound HTTP traffic (port 80) to the Load Balancer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VPC and Subnets&lt;/strong&gt;: Data sources are used to get the default VPC and subnets in the region for the Load Balancer and EC2 instances.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load Balancer&lt;/strong&gt;: The Application Load Balancer (ALB) distributes traffic between the Blue and Green target groups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target Groups&lt;/strong&gt;: Two target groups are defined—one for each environment (Blue and Green).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Scaling Groups&lt;/strong&gt;: Each environment (Blue and Green) has its own Auto Scaling Group with launch configurations, ensuring the appropriate EC2 instances are deployed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Zero Downtime Deployment with Terraform
&lt;/h3&gt;

&lt;p&gt;The magic of Zero Downtime Deployment lies in the way we manage traffic and scaling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Traffic Switching&lt;/strong&gt;: By using the load balancer listener’s default action, traffic is routed to the active environment (Blue or Green). Once the new environment is ready, you can simply switch traffic from Blue to Green without downtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Scaling&lt;/strong&gt;: The Auto Scaling groups ensure that there are always the right number of instances running, scaling up or down based on demand.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;With this simple Terraform configuration, you can implement a Blue-Green deployment strategy on AWS, achieving zero downtime during your updates. By utilizing Terraform’s infrastructure-as-code approach, you can ensure your deployments are repeatable, reliable, and scalable, allowing you to focus on delivering value to your users rather than worrying about downtime. &lt;/p&gt;

&lt;p&gt;Let me know how you’ve implemented similar strategies, or if you have any questions about the code! Happy deploying! 🚀&lt;/p&gt;

</description>
    </item>
    <item>
      <title>State Isolation: Layout vs Workspace</title>
      <dc:creator>Otu Udo</dc:creator>
      <pubDate>Mon, 09 Dec 2024 21:32:12 +0000</pubDate>
      <link>https://dev.to/otumiky/state-isolation-layout-vs-workspace-1pce</link>
      <guid>https://dev.to/otumiky/state-isolation-layout-vs-workspace-1pce</guid>
      <description>&lt;h3&gt;
  
  
  Terraform State Isolation: Workspace
&lt;/h3&gt;

&lt;p&gt;Isolating state files ensures that changes to one part of your infrastructure does not affect another. Terraform offers two primary methods for state isolation: &lt;strong&gt;Layout-based Isolation&lt;/strong&gt; and &lt;strong&gt;Workspace-based Isolation&lt;/strong&gt;. In this blog post, we’ll focus on Workspace-based Isolation, providing examples to demonstrate its capabilities.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why Is State Isolation Important?
&lt;/h3&gt;

&lt;p&gt;Terraform uses a state file to track the real-world infrastructure it manages. Sharing a single state file across unrelated resources or environments can lead to issues such as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Accidental Changes:&lt;/strong&gt; Modifying unrelated infrastructure when applying changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency Issues:&lt;/strong&gt; Overwriting state files when multiple users or automation pipelines work simultaneously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poor Separation of Concerns:&lt;/strong&gt; Difficulty managing environments like development, staging, and production.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;State isolation avoids these problems by segmenting state files for different components or environments.&lt;/p&gt;




&lt;h3&gt;
  
  
  Workspace-Based Isolation
&lt;/h3&gt;

&lt;p&gt;Workspaces allow Terraform to maintain multiple state files for a single configuration by associating each workspace with its own state.&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%2F2x36vy1kwg1tqj8vwdgr.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%2F2x36vy1kwg1tqj8vwdgr.png" alt="Image description" width="800" height="525"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform_job/
└── main.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;main.tf&lt;/code&gt;&lt;/strong&gt;:&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;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="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket"&lt;/span&gt; &lt;span class="s2"&gt;"terraform_state"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"otu-bucket-state"&lt;/span&gt;
 &lt;span class="c1"&gt;# Prevent accidental deletion of this S3 bucket&lt;/span&gt;
 &lt;span class="nx"&gt;lifecycle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;prevent_destroy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Enable versioning so you can see the full revision history of your&lt;/span&gt;
&lt;span class="c1"&gt;# state files&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_versioning"&lt;/span&gt; &lt;span class="s2"&gt;"enabled"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terraform_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
 &lt;span class="nx"&gt;versioning_configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Enabled"&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Enable server-side encryption by default&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_server_side_encryption_configuration"&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terraform_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
 &lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;apply_server_side_encryption_by_default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;sse_algorithm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AES256"&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="c1"&gt;# Explicitly block all public access to the S3 bucket&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_public_access_block"&lt;/span&gt; &lt;span class="s2"&gt;"public_access"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terraform_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
 &lt;span class="nx"&gt;block_public_acls&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="nx"&gt;block_public_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="nx"&gt;ignore_public_acls&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="nx"&gt;restrict_public_buckets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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_dynamodb_table"&lt;/span&gt; &lt;span class="s2"&gt;"terraform_locks"&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;"state-lock"&lt;/span&gt;
 &lt;span class="nx"&gt;billing_mode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PAY_PER_REQUEST"&lt;/span&gt;
 &lt;span class="nx"&gt;hash_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"LockID"&lt;/span&gt;
 &lt;span class="nx"&gt;attribute&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;"LockID"&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;"S"&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;backend&lt;/span&gt; &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="c1"&gt;# Replace this with your bucket name!&lt;/span&gt;
 &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"otu-bucket-state"&lt;/span&gt;
 &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"workspaces-example/terraform.tfstate"&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;# Replace this with your DynamoDB table name!&lt;/span&gt;
 &lt;span class="nx"&gt;dynamodb_table&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"state-lock"&lt;/span&gt;
 &lt;span class="nx"&gt;encrypt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"s3_bucket_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terraform_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
 &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The ARN of the S3 bucket"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"dynamodb_table_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_dynamodb_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terraform_locks&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;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The name of the DynamoDB table"&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_instance"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nx"&gt;ami&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-0e86e20dae9224db8"&lt;/span&gt;
&lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Managing Workspaces
&lt;/h4&gt;

&lt;p&gt;You can create and switch between workspaces using Terraform commands:&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;# Create workspaces&lt;/span&gt;
terraform workspace new example1
terraform workspace new example2

&lt;span class="c"&gt;# Switch to a workspace&lt;/span&gt;
terraform workspace &lt;span class="k"&gt;select &lt;/span&gt;example1

&lt;span class="c"&gt;# Apply changes to the current workspace&lt;/span&gt;
terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Terraform creates a new EC2 instance different from the one in the default namespace because the state files in each workspace are isolated from one another. Since we’re now in the example1 workspace, Terraform will only make use of the state file from the example1 workspace. and doesn't recognize that the EC2 instance has already been created in the default workspace.&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%2F94g6ro52dew2aevr5dxm.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%2F94g6ro52dew2aevr5dxm.png" alt="Image description" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;example1&lt;/code&gt; workspace uses the state file &lt;code&gt;example1/terraform.tfstate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;example2&lt;/code&gt; workspace uses the state file &lt;code&gt;example2/terraform.tfstate&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fet1vqk2ueevanu1abbpo.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%2Fet1vqk2ueevanu1abbpo.png" alt="Image description" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Clean Up&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;To avoid unnecessary charges, delete the bucket by destroying the infrastructure:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Type &lt;code&gt;yes&lt;/code&gt; when prompted.&lt;/p&gt;

&lt;h4&gt;
  
  
  Advantages of Workspace-Based Isolation
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single Configuration:&lt;/strong&gt; Simplifies management by keeping configurations centralized.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Backend Configurations:&lt;/strong&gt; Automatically handles state files based on the active workspace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment-Specific Variables:&lt;/strong&gt; Easily manage variables unique to each environment using workspace-specific settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Challenges of Workspace-Based Isolation
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Workspace Context:&lt;/strong&gt; Requires users to verify the active workspace before applying changes to avoid accidental updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limited Use Cases:&lt;/strong&gt; Workspaces are less suited for isolating completely unrelated infrastructure components.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Best Practices for Using Workspaces
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set Clear Naming Conventions:&lt;/strong&gt; Use consistent naming for workspaces (e.g., &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;staging&lt;/code&gt;, &lt;code&gt;prod&lt;/code&gt;) to avoid confusion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leverage Variables:&lt;/strong&gt; Use workspace names in variable definitions to manage environment-specific configurations dynamically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate Workspace Selection:&lt;/strong&gt; Use scripts or CI/CD pipelines to automate workspace selection for specific environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor State Files:&lt;/strong&gt; Ensure that state files for each workspace are regularly backed up and monitored for concurrency issues.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  When to Use Workspace-Based Isolation
&lt;/h3&gt;

&lt;p&gt;Workspace-based isolation is ideal for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managing environments (e.g., &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;staging&lt;/code&gt;, &lt;code&gt;prod&lt;/code&gt;) that share similar infrastructure.&lt;/li&gt;
&lt;li&gt;Centralizing configurations for easier maintenance.&lt;/li&gt;
&lt;li&gt;Reducing redundancy while maintaining isolated state files.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Workspace-based isolation offers a flexible way to manage multiple environments with a shared Terraform configuration. By associating each workspace with its own state file, you can ensure environment-specific changes without interference. While it requires careful workspace management, its dynamic nature makes it a powerful tool for modern infrastructure teams.&lt;/p&gt;

&lt;p&gt;Let us know how you’re using Terraform workspaces in your projects! Happy Terraforming!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Managing Terraform State: Best Practices for DevOps</title>
      <dc:creator>Otu Udo</dc:creator>
      <pubDate>Sun, 08 Dec 2024 13:28:10 +0000</pubDate>
      <link>https://dev.to/otumiky/managing-terraform-state-best-practices-for-devops-5cll</link>
      <guid>https://dev.to/otumiky/managing-terraform-state-best-practices-for-devops-5cll</guid>
      <description>&lt;p&gt;When working with Terraform, managing the state file is crucial to ensuring the reliability and security of your infrastructure. The Terraform state file is the single source of truth for your infrastructure, storing information about the resources you've deployed. Let's explore best practices for managing Terraform state using S3 and DynamoDB and walk through a step-by-step implementation using the code provided below.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step-by-Step Guide to Managing Terraform State&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step 1: Set Up the AWS Provider&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The first step is to configure the AWS provider, specifying the region where resources will be created. In this example, the &lt;code&gt;us-east-1&lt;/code&gt; region is used:&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;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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Step 2: Create an S3 Bucket for Remote State Storage&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;An S3 bucket is configured to store the Terraform state file. The &lt;code&gt;prevent_destroy&lt;/code&gt; lifecycle rule ensures the bucket cannot be accidentally deleted:&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;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket"&lt;/span&gt; &lt;span class="s2"&gt;"terraform_state"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"otu-bucket-state"&lt;/span&gt;
  &lt;span class="nx"&gt;lifecycle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;prevent_destroy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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;h4&gt;
  
  
  &lt;strong&gt;Step 3: Enable Versioning on the S3 Bucket&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Versioning is enabled on the bucket to maintain a history of state file revisions. This allows recovery in case of accidental overwrites:&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;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_versioning"&lt;/span&gt; &lt;span class="s2"&gt;"enabled"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terraform_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;versioning_configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Enabled"&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;h4&gt;
  
  
  &lt;strong&gt;Step 4: Set Up Server-Side Encryption&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;To secure the state file, server-side encryption using the AES256 algorithm is enabled:&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;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_server_side_encryption_configuration"&lt;/span&gt; &lt;span class="s2"&gt;"default"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terraform_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;apply_server_side_encryption_by_default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;sse_algorithm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AES256"&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;h4&gt;
  
  
  &lt;strong&gt;Step 5: Block Public Access to the S3 Bucket&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Public access to the S3 bucket is explicitly blocked to protect sensitive information:&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;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_public_access_block"&lt;/span&gt; &lt;span class="s2"&gt;"public_access"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terraform_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;block_public_acls&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;block_public_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;ignore_public_acls&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;restrict_public_buckets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Step 6: Create a DynamoDB Table for State Locking&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;A DynamoDB table is configured to enable state locking, which prevents concurrent updates to the state file:preventing two team members from running terraform apply on the same state file at the same time.&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;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_dynamodb_table"&lt;/span&gt; &lt;span class="s2"&gt;"terraform_locks"&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;"state-locks"&lt;/span&gt;
  &lt;span class="nx"&gt;billing_mode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PAY_PER_REQUEST"&lt;/span&gt;
  &lt;span class="nx"&gt;hash_key&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"LockID"&lt;/span&gt;
  &lt;span class="nx"&gt;attribute&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;"LockID"&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;"S"&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;h4&gt;
  
  
  &lt;strong&gt;Step 7: Configure Terraform Backend&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The backend configuration connects Terraform to the S3 bucket and DynamoDB table, enabling remote state storage and locking:&lt;br&gt;
After you configure a remote backend, Terraform will automatically load the state file from that backend every time you run plan or apply, and it’ll automatically store the state file in that backend after each apply, so there’s no chance of manual error.&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;backend&lt;/span&gt; &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"otu-bucket-state"&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"global/s3/terraform.tfstate"&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;dynamodb_table&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"state-locks"&lt;/span&gt;
    &lt;span class="nx"&gt;encrypt&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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;h4&gt;
  
  
  &lt;strong&gt;Step 8: Output Key Resource Information&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;To easily reference key resources, outputs for the S3 bucket ARN and DynamoDB table name are defined:&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;output&lt;/span&gt; &lt;span class="s2"&gt;"s3_bucket_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terraform_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The ARN of the S3 bucket"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"dynamodb_table_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_dynamodb_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;terraform_locks&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;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The name of the DynamoDB table"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These variables will print out the Amazon Resource Name (ARN) of your S3 bucket&lt;br&gt;
and the name of your DynamoDB table. Run terraform apply to see it:&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%2Fw41rpy97uabyedilphu9.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%2Fw41rpy97uabyedilphu9.png" alt="Image description" width="800" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How Each Step Aligns with Best Practices&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Remote State Storage&lt;/strong&gt;: The S3 bucket ensures the state file is stored securely and accessible to the team.&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%2Fn0y8229p5tp6xwzl50mq.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%2Fn0y8229p5tp6xwzl50mq.png" alt="s3" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;State Locking&lt;/strong&gt;: The DynamoDB table prevents simultaneous state modifications, avoiding conflicts.&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%2Fod5yehyklnabp9j8v0zc.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%2Fod5yehyklnabp9j8v0zc.png" alt="state lock" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Versioning&lt;/strong&gt;: S3 versioning allows recovery from accidental state file overwrites. You can the state files stored in the &lt;strong&gt;global&lt;/strong&gt; workspace we created.&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%2F1na8wftkn8kqfblghy7o.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%2F1na8wftkn8kqfblghy7o.png" alt="Image description" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Encryption&lt;/strong&gt;: AES256 encryption secures the state file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Control&lt;/strong&gt;: Public access to the S3 bucket is restricted to protect sensitive data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lifecycle Management&lt;/strong&gt;: The &lt;code&gt;prevent_destroy&lt;/code&gt; rule ensures critical resources are not accidentally deleted.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Benefits of this Implementation&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: Protects sensitive information in the state file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaboration&lt;/strong&gt;: Enables teams to work on the same Terraform project without conflicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resilience&lt;/strong&gt;: Ensures recovery from accidental modifications or deletions.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;By following these steps and best practices, you can effectively manage Terraform state, enhancing the security, collaboration, and reliability of your infrastructure.&lt;/p&gt;

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