{"id":146,"date":"2020-11-10T14:03:05","date_gmt":"2020-11-10T14:03:05","guid":{"rendered":"https:\/\/www.slowergram.com\/?p=146"},"modified":"2020-11-10T14:03:08","modified_gmt":"2020-11-10T14:03:08","slug":"terraform-adventures","status":"publish","type":"post","link":"https:\/\/www.slowergram.com\/index.php\/2020\/11\/10\/terraform-adventures\/","title":{"rendered":"Terraform Adventures"},"content":{"rendered":"\n<p>As you probably know there are hundreds of different posts about building Infrastructure as Code using Terraform, but this details some of my experience when coupled with AWS.<\/p>\n\n\n\n<p>The main aim of this demonstration is to stand up a single AWS EC2 instance, ready for logging into on its public IP, using Terraform. As a pre-requisite to this I need several things&#8230;<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>An AWS account<\/li><li>A Terraform installation<\/li><li>A permissioned IAM user and key-pair<\/li><\/ul>\n\n\n\n<p>The AWS account is easy, go and sign up and get free tier access, as this is invaluable in exploring AWS and learning by getting a hands-on feel for how things work and fit together.<\/p>\n\n\n\n<p>For the Terraform installation, I used my trusty RPi4 4GB workhorse running the 64-bit version of the Raspberry Pi OS. So I downloaded the <a rel=\"noreferrer noopener\" href=\"https:\/\/releases.hashicorp.com\/terraform\/0.13.5\/terraform_0.13.5_linux_arm64.zip\" target=\"_blank\">ARM64 version for Linux<\/a> from the Hashicorp website. Unpon extracting I was surprised (pleasently) to find a single binary, with no need for installation or dependencies.<\/p>\n\n\n\n<p>I created a seperate IAM user through the AWS console, ensuring to save the ACCESS KEY and SECRET KEY, as well as the ssh key pair file. Although I could have been more granular with the permissions I gave this user full access to EC2 and S3.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"717\" height=\"207\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/iam_user.png\" alt=\"\" class=\"wp-image-148\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/iam_user.png 717w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/iam_user-300x87.png 300w\" sizes=\"auto, (max-width: 717px) 100vw, 717px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"491\" height=\"172\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/key-pair.png\" alt=\"\" class=\"wp-image-149\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/key-pair.png 491w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/key-pair-300x105.png 300w\" sizes=\"auto, (max-width: 491px) 100vw, 491px\" \/><\/figure>\n\n\n\n<p>With all the pre-requisites in place I could start building up my desired Infrastructure as Code.<\/p>\n\n\n\n<p>I first added the AWS ACCESS and SECRET keys as OS environment variables:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"659\" height=\"34\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/aws-creds.png\" alt=\"\" class=\"wp-image-150\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/aws-creds.png 659w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/aws-creds-300x15.png 300w\" sizes=\"auto, (max-width: 659px) 100vw, 659px\" \/><\/figure>\n\n\n\n<p>In the same directory I extracted the terraform binary I created a main.tf file using vi. This file tells Terraform what environments it will be integrating with and what it will be provisioning.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"512\" height=\"289\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/main-tf.png\" alt=\"\" class=\"wp-image-151\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/main-tf.png 512w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/main-tf-300x169.png 300w\" sizes=\"auto, (max-width: 512px) 100vw, 512px\" \/><\/figure>\n\n\n\n<p>The beauty of Terraform is that it is so simple to get started and understand what its doing, going through the items in the main.tf file we have:<\/p>\n\n\n\n<p>provider: Obviously which environment we will be provisioning in, here we will be using AWS, and the US-East-1 region.<br>resource: An infrastructure element to deploy, containing a number of different parameters.<br>ami: Which Amazon Machine Image to use<br>instance type: Predefined Virtual machine sizing template<br>key_name: The ssh key pair we created when setting up the IAM user<br>tags: some distinguishing identification <\/p>\n\n\n\n<p>To get the AMI id I needed to look in the AWS console and start the process of launching an instance, this then gives a list of all available AMI&#8217;s to choose from along with the id.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"998\" height=\"458\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/AMI-ID-1.png\" alt=\"\" class=\"wp-image-152\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/AMI-ID-1.png 998w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/AMI-ID-1-300x138.png 300w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/AMI-ID-1-768x352.png 768w\" sizes=\"auto, (max-width: 998px) 100vw, 998px\" \/><\/figure>\n\n\n\n<p>With the main.tf file in place, the command terraform init is used to download the module relevant to the environment you will be deploying too.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"644\" height=\"452\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/terraform-init.png\" alt=\"\" class=\"wp-image-153\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/terraform-init.png 644w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/terraform-init-300x211.png 300w\" sizes=\"auto, (max-width: 644px) 100vw, 644px\" \/><\/figure>\n\n\n\n<p>The next step is to run a terraform plan which doesn&#8217;t actually do anything it just tells you what it will do.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"619\" height=\"511\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/terraform-plan.png\" alt=\"\" class=\"wp-image-154\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/terraform-plan.png 619w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/terraform-plan-300x248.png 300w\" sizes=\"auto, (max-width: 619px) 100vw, 619px\" \/><\/figure>\n\n\n\n<p>Assuming you are happy you can run the terraform apply command to actually start the deployment, which prompts for verification.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"468\" height=\"127\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/terraform-apply1.png\" alt=\"\" class=\"wp-image-155\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/terraform-apply1.png 468w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/terraform-apply1-300x81.png 300w\" sizes=\"auto, (max-width: 468px) 100vw, 468px\" \/><\/figure>\n\n\n\n<p>Oh no, an error! Thankfully the error is detailed in plain english and shows you where to look.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"705\" height=\"138\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/error1.png\" alt=\"\" class=\"wp-image-156\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/error1.png 705w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/error1-300x59.png 300w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure>\n\n\n\n<p>The eagle-eyed among you may have seen that I chose US-East-1 as my AWS region for provisioning, however AMI id&#8217;s differ between regions, and the id I used was from my default region EU-West-1 (Ireland).<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"986\" height=\"488\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/error2.png\" alt=\"\" class=\"wp-image-157\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/error2.png 986w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/error2-300x148.png 300w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/error2-768x380.png 768w\" sizes=\"auto, (max-width: 986px) 100vw, 986px\" \/><\/figure>\n\n\n\n<p>Back into the main.tf file, I simply change the region to be eu-west-1. Obviously I could have also changed the AMI ID to be the one from US-East-1 if I specifically wanted to deploy to that region.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"457\" height=\"283\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/error3-main-tf.png\" alt=\"\" class=\"wp-image-158\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/error3-main-tf.png 457w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/error3-main-tf-300x186.png 300w\" sizes=\"auto, (max-width: 457px) 100vw, 457px\" \/><\/figure>\n\n\n\n<p>I run the terraform apply again and this time it goes through successfully<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"658\" height=\"140\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/complete.png\" alt=\"\" class=\"wp-image-159\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/complete.png 658w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/complete-300x64.png 300w\" sizes=\"auto, (max-width: 658px) 100vw, 658px\" \/><\/figure>\n\n\n\n<p>This can also be seen through the AWS console, as a new running instance<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"767\" height=\"245\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/complete2.png\" alt=\"\" class=\"wp-image-160\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/complete2.png 767w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/complete2-300x96.png 300w\" sizes=\"auto, (max-width: 767px) 100vw, 767px\" \/><\/figure>\n\n\n\n<p>I now have a Linux VM running in the cloud, but I want to connect to it and use it. By default AWS does not permit inbound traffic over the public interface. Therefore we need to allow traffic, specifically on port 22 for SSH.<\/p>\n\n\n\n<p>Again we can use Terraform for this, creating a new security group and assigning our instance to it. Editing the main.tf file again we add a new resource element.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"498\" height=\"401\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/main-tf-sg.png\" alt=\"\" class=\"wp-image-161\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/main-tf-sg.png 498w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/main-tf-sg-300x242.png 300w\" sizes=\"auto, (max-width: 498px) 100vw, 498px\" \/><\/figure>\n\n\n\n<p>As before its pretty straightforward, a separate resource is declared, as type aws_security_group, with name of linuxsg. This opens up port 22 on all interfaces.<\/p>\n\n\n\n<p>In order for our newly created instance to use this security group, we add an extra parameter into the aws_instance resource declaration, vpc_security_group_ids = [aws_security_group.linuxsg.id]<\/p>\n\n\n\n<p>Running terraform apply again makes the new changes on the fly as it remembers what it has already created, only making the changes it needs too.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"660\" height=\"118\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/sg-complete.png\" alt=\"\" class=\"wp-image-162\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/sg-complete.png 660w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/sg-complete-300x54.png 300w\" sizes=\"auto, (max-width: 660px) 100vw, 660px\" \/><\/figure>\n\n\n\n<p>With the VM running, I cheated and got the Public IP and DNS name from the AWS console, but Terraform can output this information if needed.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"741\" height=\"183\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/public-ip.png\" alt=\"\" class=\"wp-image-164\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/public-ip.png 741w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/public-ip-300x74.png 300w\" sizes=\"auto, (max-width: 741px) 100vw, 741px\" \/><\/figure>\n\n\n\n<p>Now that port 22 is open we can use the .pem key-pair file we downloaded as part of the IAM user creation, and use it to ssh directly over the internet to the running VM.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"705\" height=\"181\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/ssh-success.png\" alt=\"\" class=\"wp-image-163\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/ssh-success.png 705w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/ssh-success-300x77.png 300w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure>\n\n\n\n<p>When you are finished with the deployed resources, a single terraform destroy command will tidy up and terminate all the resources it built as part of the deployment.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"680\" height=\"169\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/destroy2.png\" alt=\"\" class=\"wp-image-167\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/destroy2.png 680w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/destroy2-300x75.png 300w\" sizes=\"auto, (max-width: 680px) 100vw, 680px\" \/><\/figure>\n\n\n\n<p>This can also be seen in the AWS console&#8230;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"702\" height=\"75\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/terminate.png\" alt=\"\" class=\"wp-image-166\" srcset=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/terminate.png 702w, https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/11\/terminate-300x32.png 300w\" sizes=\"auto, (max-width: 702px) 100vw, 702px\" \/><\/figure>\n\n\n\n<p>Its really as simple as that. Obviously Terraform can be used in far more complicated scenarios, but this gives you a taste of how easy it is to stand up whole environments very easily or on demand when needed for a specific purpose or DR invocation. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>As you probably know there are hundreds of different posts about building Infrastructure as Code using Terraform, but this details some of my experience when coupled with AWS. The main aim of this demonstration is to stand up a single AWS EC2 instance, ready for logging into on its public <a href=\"https:\/\/www.slowergram.com\/index.php\/2020\/11\/10\/terraform-adventures\/\" class=\"btn btn-link continue-link\">Continue Reading<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[1],"tags":[26,27,25],"class_list":["post-146","post","type-post","status-publish","format-standard","hentry","category-uncategorised","tag-aws","tag-cloud","tag-terraform"],"_links":{"self":[{"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/posts\/146","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/comments?post=146"}],"version-history":[{"count":0,"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/posts\/146\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/media?parent=146"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/categories?post=146"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/tags?post=146"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}