<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Klenam Fiah</title>
    <description>The latest articles on Forem by Klenam Fiah (@klenam_).</description>
    <link>https://forem.com/klenam_</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%2F604086%2F214cdbda-37a3-4b0e-ab97-e727786c7c25.jpeg</url>
      <title>Forem: Klenam Fiah</title>
      <link>https://forem.com/klenam_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/klenam_"/>
    <language>en</language>
    <item>
      <title>Working with Workspaces and Backends in Terraform</title>
      <dc:creator>Klenam Fiah</dc:creator>
      <pubDate>Fri, 30 Apr 2021 21:02:08 +0000</pubDate>
      <link>https://forem.com/klenam_/working-with-workspaces-and-backends-in-terraform-2ja2</link>
      <guid>https://forem.com/klenam_/working-with-workspaces-and-backends-in-terraform-2ja2</guid>
      <description>&lt;p&gt;Terraform manages infrastructure with state files. By default you have a single workspace, default. So when you run &lt;code&gt;terraform plan&lt;/code&gt; and &lt;code&gt;terraform apply&lt;/code&gt; you are working the default workspace prepared by terraform.&lt;br&gt;
But with workspaces we can have multiple states. What this means, we can have different server setup with different state files managing that server setup(keep records of what has been deployed at every time). Also it cuts down the amount of copy and paste you will be doing.&lt;/p&gt;

&lt;p&gt;To set up workspaces in terraform is very easy. The command &lt;code&gt;terraform workspace new &amp;lt;name of workspace&amp;gt;&lt;/code&gt; does that. Assuming I needed different workspaces to keep tabs on my deployment for DEV, QA and PROD. This will be simply achieved by running-&lt;br&gt;
&lt;code&gt;terraform workspace new DEV&lt;/code&gt;, &lt;code&gt;terraform workspace new QA&lt;/code&gt; and &lt;code&gt;terraform workspace new PROD&lt;/code&gt;. This creates three different sub-folders under the &lt;em&gt;terraform.tfstate.d&lt;/em&gt; folder&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fycxmyg9q1tc4gn3u25lo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fycxmyg9q1tc4gn3u25lo.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Workspace created! How do we run our Terraform code in a specific workspace? Simply run &lt;code&gt;terraform workspace select &amp;lt;name of workspace&amp;gt;&lt;/code&gt;. Terraform will throw you a prompt on what workspace you are working in. Go head and run &lt;code&gt;terraform plan&lt;/code&gt; and &lt;code&gt;terraform apply&lt;/code&gt;&lt;/p&gt;



&lt;p&gt;This is all well and good if you are building infrastructure alone because you are an amazing engineer. More often than not, tasks are performed in teams and we need some collaboration to get things done effectively. How do we achieve this with workspaces🤔? We should use some backend to store these state files✨😎.&lt;/p&gt;

&lt;p&gt;Using AWS as our provider, I'll demonstrate &lt;/p&gt;



&lt;p&gt;We create an S3 bucket to store the state files.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; bucket name must be unique because the s3 namespace is a shared one. You get an error like &lt;br&gt;
&lt;code&gt;Error: Error creating S3 bucket: BucketAlreadyExists: The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again.&lt;br&gt;
        status code: 409, request id: EMBTK255FN7K3QDT, host id: 20vAPtmPGrMG/2tec=&lt;/code&gt; &lt;br&gt;
if the bucket name has been taken.&lt;/p&gt;

&lt;p&gt;Now we need some way to lock our file when we are deploying to avoid your team from walking over each other. This way just one person can deploy at a time. We will use AWS DynamoDB to achieve this&lt;br&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The table must have a primary key named &lt;em&gt;"LockID"&lt;/em&gt; and type &lt;em&gt;"S"&lt;/em&gt; (type &lt;em&gt;string&lt;/em&gt;). You get an error if this isn't so. Error below:&lt;br&gt;
&lt;code&gt;Error: Error locking destination state: Error acquiring the state lock: 2 errors occurred:&lt;br&gt;
        * ValidationException: One or more parameter values were invalid: Missing the key Locker in the item&lt;br&gt;
        status code: 400, request id: 7BRN5V5Q92K0393GO5AEMVJF66Q9ASUAAJG&lt;br&gt;
        * ValidationException: The provided key element does not match the schema&lt;br&gt;
        status code: 400, request id: KDJ19AI5UB2TJBSQ9ASUAAJG&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With all this in place we can now &lt;code&gt;terraform init&lt;/code&gt; -&amp;gt; &lt;code&gt;terraform plan&lt;/code&gt; -&amp;gt; &lt;code&gt;terraform apply&lt;/code&gt;.&lt;/p&gt;



&lt;p&gt;The final step to achieve our objective will be to declare our backend in terraform.&lt;br&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Again we need to initialize. &lt;code&gt;terraform init&lt;/code&gt;&lt;br&gt;
Done correctly Terraform will seek permission to make of a copy of your state to the backend.&lt;/p&gt;

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

Initializing the backend...
Acquiring state lock. This may take a few moments...
Do you want to copy existing state to the new backend?
Pre-existing state was found while migrating the previous "local" backend to the newly configured "s3" backend. No existing state was found in the newly configured "s3" backend. Do you want to copy this state to the new "s3" backend? Enter "yes" to copy and "no" to start with an empty state.

Enter a value:    


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

&lt;/div&gt;

&lt;p&gt;Real easy, huh?!🙃&lt;/p&gt;

&lt;p&gt;If you go into your S3 bucket you should see a path &lt;code&gt;env:/&lt;/code&gt; with  all your workspaces listed with each it's own state file.&lt;/p&gt;

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

&lt;p&gt;The terraform has good &lt;a href="https://www.terraform.io/docs/language/settings/backends/s3.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; on this.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;+++Header Photo credit: Pixabay's mozlase__+++&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                   Happy Computing!!💻✌️ 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>terraform</category>
      <category>devops</category>
      <category>aws</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Building a two tier infrastructure with Terraform in AWS</title>
      <dc:creator>Klenam Fiah</dc:creator>
      <pubDate>Fri, 26 Mar 2021 15:01:36 +0000</pubDate>
      <link>https://forem.com/klenam_/building-a-two-tier-infrastructure-with-terraform-in-aws-3cgh</link>
      <guid>https://forem.com/klenam_/building-a-two-tier-infrastructure-with-terraform-in-aws-3cgh</guid>
      <description>&lt;p&gt;During the lockdown I had an intriguing conversation with a close buddy of mine from the university. During our usual undirected and wild conversations I asked what's the newest tech he's been dabbling in. He mentioned Terraform and he spoke about how awesome it was . I was totally intrigued so set myself on this the path of discovering this amazing IaC (Infrastructure as Code) tool.&lt;/p&gt;

&lt;p&gt;I didn't know what to expect and I feared I wouldn't grasp the concepts because this was all new to me and I hadn't ever taken a swim in the DevOps pool, yada yada yada 😁. Down the rabbit hole I went.&lt;/p&gt;

&lt;p&gt;In this project I deployed a FastAPI in my first tier and a PostgreSQL and Ansible machines as my second tier. Could have designed a proper frontend but I am horrible with frontend😅 and all my pals had a ton of things to work on as well. I'll be focusing on the deployment of the infrastructure into AWS in this write-up.&lt;/p&gt;

&lt;p&gt;Let's get down to it!😎&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--76S1YowA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/op00xyrhytxxdmq861ki.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--76S1YowA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/op00xyrhytxxdmq861ki.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;To get started we need to prepare:&lt;br&gt;
*get yourself a AWS free tier account. this will give you limited but enough access to all AWS has to offer for a year&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;get AWS cli configured. Useful AWS doc to do this&lt;/li&gt;
&lt;li&gt;&lt;p&gt;get the Terraform CLI&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;get FastAPI installed in a virtual environment. Getting FastAPI installed &lt;strong&gt;(not necessary here so you could ignore)&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since the focus of this article isn't going to be on FastAPI, I'll won't be showing how to put it together. The FastAPI docs are one of the best and will give you a good guide on how to get something going in no time.&lt;/p&gt;



&lt;p&gt;To get the ball rolling, in AWS you need to create a VPC. What's a VPC you might be asking😳? A VPC(virtual private cloud) is your personal isolated corner within the AWS cloud. &lt;a href="https://www.infoq.com/articles/aws-vpc-explained/"&gt;Read more?&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You might want to ignore the data source defined above the resource definition. To read more about &lt;a href="https://www.terraform.io/docs/language/data-sources/index.html"&gt;Data Sources&lt;/a&gt;. It's beyond the scope. I'll love to define all the attributes but I'll only explain attributes that were a hell for me, mostly because I can be slow in the head sometimes🤣. &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs"&gt;Terraform docs&lt;/a&gt; for providers(AWS in this case) explain these attributes so well.&lt;/p&gt;




&lt;p&gt;The next thing to do do will be to divide this VPC CIDR block into smaller portions for our private and public subnets. The DB needs to be associated with a subnet. In here, I associate it with both subnets.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;p&gt;With the subnet provisioned we have to create security groups. Security groups are rules that govern what comes in and out of our instance.(An instance is virtual server in the AWS cloud).&lt;/p&gt;

&lt;p&gt;I have three Security groups to manage my instances -&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;aws_security_group.backend_security_groups&lt;/strong&gt; - to manage my FastAPI backend&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;aws_security_group.db_security_groups&lt;/strong&gt; - to manage my PostgreSQL server&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;aws_security_group.only_ssh_bastion&lt;/strong&gt; - to manage my Bastion server(What's this weird thing😭? A Bastion server? Will explain soon)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;p&gt;We need now need an internet gateway to communicate with the outside world&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;p&gt;With that done we need a way to direct traffic within our VPC. In walks routing tables🚶‍♂️. By default when you create a VPC it comes with a default route table but I will advise you create custom route tables. This helps in troubleshooting issues.&lt;/p&gt;

&lt;p&gt;We will create route tables that point to the &lt;em&gt;Internet Gateway, VPC Internet Gateway&lt;/em&gt; and one between our &lt;em&gt;FastAPI&lt;/em&gt; and &lt;em&gt;Database&lt;/em&gt; instances.&lt;/p&gt;

&lt;p&gt;Here I'll explain the attributes the best way I understand them.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Taking the &lt;strong&gt;aws_route_table.backend_route_table:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;vpc_id:&lt;/strong&gt; this associates the route table to our VPC&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;route:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;cidr_block = "0.0.0.0/0"&lt;/strong&gt; .&lt;em&gt;What this is saying is, when you see any IP that doesn't belong within our VPC IP range direct this towards the internet gateway. Same logic applies to &lt;strong&gt;aws_route_table.nat_route_table.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We then need to associate these routes to subnets. So we associate them to the public and private subnets&lt;/p&gt;




&lt;p&gt;We then need a way for our instances in the private subnet to communicate with the internet but not the internet getting to the them. A VPC NAT &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html"&gt;Network Address Translation&lt;/a&gt; Gateway will serve that purpose. This helps when we need our servers to pull updates and patches.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;p&gt;What next? This is taking forever to put together😡. I agree but remember when I said I went down the rabbit hole🤪?&lt;/p&gt;




&lt;p&gt;To be able to reach instances and resources in our public subnet from outside our VPC, we need to assign Elastic IP Addresses to them. AWS gives you five eips when you use the free tier and it's yours till you release them(destroy the build). &lt;em&gt;&lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html"&gt;Read more&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;We are almost there. Hold your focus for 10 more minutes!&lt;/p&gt;




&lt;p&gt;We need our instances now. AWS instances are best described by me as our virtual servers. We will need three (for the FastAPI backend, Bastion and Ansible control node). In the snips below you will see some other stuff like &lt;em&gt;provisioner&lt;/em&gt; and &lt;em&gt;connection&lt;/em&gt;. You can ignore these since they only help us perform some provisioning on our instances when we are spinning them up. It does this by using SSH. Not our focus for now.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;p&gt;Now to answer some questions👩‍🏫. "Chris, what's a Bastion Server?". A Bastion Server is a special server that reduces the attack vector of your infrastructure by limiting access to the restricted part of your setup. Some call it a jump sever. So to get to the instances in the private network(in this case my ansible control node) I need to SSH into the Bastion server then hop onto my Ansible control node by SSH from the Bastion. Super, right?🧑‍🚀&lt;/p&gt;




&lt;p&gt;We do the same for our database but amazon has special instances called RDS(Relational Database Server) that can be provisioned on build automatically.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;p&gt;Now to get it over with… I left this very important one for last to make sure you read to the end.😈. To tell Terraform what Provider you are going to be building your infrastructure we need a provider block.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Phwee! we are done. There are a couple of other nuances you will need to figure out. What's a lesson without an assignment?😂. You will need variables to provide your code with your &lt;em&gt;aws access key&lt;/em&gt;, &lt;em&gt;aws secret key&lt;/em&gt;, &lt;em&gt;instance type&lt;/em&gt;, provide tags, &lt;em&gt;path to private key(for SSH)&lt;/em&gt;, &lt;em&gt;database name&lt;/em&gt;, &lt;em&gt;database password&lt;/em&gt;. Notice in the code a lot of &lt;strong&gt;var.*&lt;/strong&gt;, it means I'm calling variable. You will need separate SSH keys for your Bastion Server and Ansible. Why would you use the same SSH key for both? Kinda forfeits the purpose security wise. You can find the codes &lt;a href="https://github.com/KlenamJohnson-Fiah/Terraform"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy Computing!✌️💻&lt;/p&gt;

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