<?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: Jean-Loup Adde</title>
    <description>The latest articles on DEV Community by Jean-Loup Adde (@juan__wolf).</description>
    <link>https://dev.to/juan__wolf</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%2F1630%2FhjpgPdlk.jpg</url>
      <title>DEV Community: Jean-Loup Adde</title>
      <link>https://dev.to/juan__wolf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/juan__wolf"/>
    <language>en</language>
    <item>
      <title>What is a NAT Gateway?</title>
      <dc:creator>Jean-Loup Adde</dc:creator>
      <pubDate>Thu, 20 Dec 2018 07:27:38 +0000</pubDate>
      <link>https://dev.to/juan__wolf/what-is-a-nat-gateway-5g2o</link>
      <guid>https://dev.to/juan__wolf/what-is-a-nat-gateway-5g2o</guid>
      <description>&lt;p&gt;Looking into designing platform and new architectures in the cloud can be quite intimidating especially when it’s your first time. Today I want to speak about the NAT Gateways, what is it? How it works? When to use it, etc…&lt;/p&gt;

&lt;h2&gt;
  
  
  What does NAT even mean?
&lt;/h2&gt;

&lt;p&gt;So first things first, what is actually a NAT?? If we listen to papy wikipedia:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Network address translation (NAT) is a method of remapping one IP address space into another by modifying network address information in the IP header of packets while they are in transit across a traffic routing device.[1] The technique was originally used as a shortcut to avoid the need to readdress every host when a network was moved. It has become a popular and essential tool in conserving global address space in the face of IPv4 address exhaustion. One Internet-routable IP address of a NAT gateway can be used for an entire private network. Sources: &lt;a href="https://en.wikipedia.org/wiki/Network_address_translation"&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s it! As Grandpa said, it’s pretty common to see an infrastructure using NAT Gateways, especially these days with the Cloud (because of the IPv4 exhaustion). In the cloud, there’s one rule. Keep everything private (at least as much as possible).&lt;/p&gt;

&lt;p&gt;Commonly when you start playing with the ☁️, you’ll create one instance, two, etc… but to access directly to these instances, you will setup those with a Public IP, it’s easier. Then your infra gets a bit more mature (and you as well) and you realize that using Public IPs might turn against you if you get a bit too permissive with firewall rules (or security groups). So you decide to move everything into a private subnet (only accessible inside your virtual private cloud) and use the protagonist of this article. THE NAT GATEWAY 🎉.&lt;/p&gt;

&lt;p&gt;We are quite lucky, cloud providers sells specific instances or services to take care of this for us. &lt;em&gt;Too handy&lt;/em&gt;. But at the end, how is this actually working? Let’s say you followed the instruction of your cloud providers to have a NAT.&lt;/p&gt;

&lt;p&gt;Then you have a platform like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QuGstAAI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.juanwolf.fr/post_content/2018-06-25/nat_vpc.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QuGstAAI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.juanwolf.fr/post_content/2018-06-25/nat_vpc.svg" alt="Schema of an architecture in the cloud with one VPC, one private subnet with four instances connected to the NAT gateway which is inside a public subnet and relay the traffic to the internet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the diagram, every outbound connection goes through the NAT Gateway and goes back to the specific instance. My question is how? The instance has no public IP, so the server on the internet when he does receive a packet, sees only the NAT instance’s IP. So how does a NAT gateway works?&lt;/p&gt;

&lt;h2&gt;
  
  
  How does a NAT gateway work?
&lt;/h2&gt;

&lt;p&gt;So as grandpa said, the NAT Gateway inject its own address inside each packet so the external server knows where to send back the packet ( &lt;strong&gt;Spoiler:&lt;/strong&gt; To the NAT Gateway).&lt;/p&gt;

&lt;p&gt;But how does the NAT knows where to send the packet back?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Normally you should see here an amazing SVG animation but dev.to does not look like to support it...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So what happen is:&lt;/p&gt;

&lt;p&gt;Your request goes to the NAT Gateway, It will receive the packet and store the localisation of the sender and the destination in what we call a &lt;em&gt;NAT table&lt;/em&gt;. The NAT will then change the &lt;em&gt;“from”&lt;/em&gt; header of your request to replace the source IP with the one of the NAT, send the packet to the proper destination, then your NAT gets the response back, change the destination of the packet/request for the instance that’s in your private subnet, and boom. Job done.&lt;/p&gt;

&lt;p&gt;You can imagine there could be some clash if the red and the blue instance queries the exact same endpoint, the NAT will not know where to redirect the response.&lt;/p&gt;

&lt;p&gt;So I was thinking to change the source port for a random one so we would know to which host redirect this request! I read a bit more on the internet that’s actually what’s happening (so pretty proud of myself there 😄)&lt;/p&gt;

&lt;p&gt;Let’s summarize:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your request/packet goes to the NAT&lt;/li&gt;
&lt;li&gt;The NAT register the source IP, source port, destination IP, destination port and get a random port available and put all this info in the translation table&lt;/li&gt;
&lt;li&gt;Modifies the source IP and the source port for the NAT public IP and the random port allocated to this request&lt;/li&gt;
&lt;li&gt;Send the request/packet to destination&lt;/li&gt;
&lt;li&gt;The destination server process the request and sends the request back to the NAT gateway (as it thinks it comes from it, lol, you fool)&lt;/li&gt;
&lt;li&gt;The NAT receives the packet/request, check its translation table, if there’s an entry for it, sends it in the private instance&lt;/li&gt;
&lt;li&gt;The private instance receives the packet.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;Using NATs allows us to keep our instances “&lt;em&gt;private&lt;/em&gt;” and still give us external traffic. But there must be some limitation to it. Of course there is. During the second step of the translation (aka registration of the packet in the NAT table), the NAT Gateway will allocate a random port for the response of the server. The problem is, let’s say you have 20 servers running 20 services that sends 10 requests per second to external services. Sadly those external services gets unreachable, the connection will wait for a timeout of… let’s say 15 seconds. In less than 10 seconds, the NAT gateway will report unhealthy or at least unable to process any more requests.&lt;/p&gt;

&lt;p&gt;Why is that?&lt;/p&gt;

&lt;p&gt;You used all the &lt;a href="https://www.ncftp.com/ncftpd/doc/misc/ephemeral_ports.html"&gt;ephemeral ports&lt;/a&gt; available on the NAT. 💥&lt;/p&gt;

&lt;p&gt;Let’s do some math. We create 20 * 20 * 10 requests per seconds aka 4000requests/s. So each requests open an ephemeral port in the NAT. 4000 ports opened. Second second 4000 others, third second you have already 12000 ephemeral ports opened. It will vary of your operating system but according to &lt;a href="https://en.wikipedia.org/wiki/Ephemeral_port#Range"&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Many Linux kernels use the port range 32768 to 61000. (The effective range is accessible via the /proc file system at node /proc/sys/net/ipv4/ip_local_port_range)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So roughly 28232 ports I would say (just guessing). That’s our maximum of ephemeral ports that can be opened. Well congratulations, we exploded the limit and we’ll have a lots of problems after that. Glad, it was just a role play and not an actual outage 😅.&lt;/p&gt;

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

&lt;p&gt;Et voila! We saw how a NAT Gateway behave and its limitation. They are one of the core components of an infrastructure in the ☁️ so it’s pretty important to have at least a basic knowledge of what they are used for. Sur ce, codez bien!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>cloud</category>
      <category>aws</category>
      <category>devops</category>
    </item>
    <item>
      <title>Introduction to Terraform</title>
      <dc:creator>Jean-Loup Adde</dc:creator>
      <pubDate>Fri, 05 Jan 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/juan__wolf/introduction-to-terraform-21cj</link>
      <guid>https://dev.to/juan__wolf/introduction-to-terraform-21cj</guid>
      <description>&lt;p&gt;With the massive adoption of the “Cloud”, different tools are borned to simplificate dev / sys. admins lifes. These tools created a new way of dealing with infra, the Infrastructure as Code aka IaC. To be honest, the cloud is a nice word but let’s face it, you just run vms on someone else servers. The big plus to use those is that with a simple API call you can provide, provision and destroy infrastructure at your glance. It would be great to write some scripts to auto populate your VPCs on AWS but as well calling azure to provision some storage etc… Well at the end you might get “curl sick”. Why not creating a tool that will deal with all the API calls for you instead? Well that’s what terraform is and let’s see how we can use this awesome tool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Yhh89qBz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.juanwolf.fr/post_preview/20180105_131244_terraform_logo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Yhh89qBz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.juanwolf.fr/post_preview/20180105_131244_terraform_logo.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclaimer: This tutorial will be using AWS as cloud provider. Any penny you’ll spend on the platform is in your entire responsability and you’re aware reading this article that you’ll have to spend some if you’re not eligible for the AWS free tier&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Starting baby steps
&lt;/h2&gt;

&lt;p&gt;What I find amazing in terraform is the flexibility that the tools give you. You can create 100 files, it will concatenate all of it, understanding which part is dependant to the other and so on, but before to have a funky project architecture let’s start simple.&lt;/p&gt;

&lt;p&gt;First of all, let’s install terraform&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Mac: &lt;code&gt;brew install terraform&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ubuntu: &lt;code&gt;sudo apt-get install terraform&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Windows: Download the binary on the terraform download page, and add it to your PATH.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Setup your AWS account
&lt;/h3&gt;

&lt;p&gt;You need to go in the aws console and setup a specific user to use terraform. Go into the &lt;code&gt;IAM&lt;/code&gt; panel and create a user. &lt;code&gt;my_terraform&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  First Project
&lt;/h3&gt;

&lt;p&gt;Let’s create a main.tf. If you’re eligible for the AWS free tier feel free to use that, if not, you’ll need to take some cash out (sorry). You need an IAM user as well to get an access key and a secret key.&lt;/p&gt;

&lt;p&gt;We will start from scratch so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir terraform_lab
cd terraform_lab
git init
git remote add origin git://my_git_repo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provider "aws" {
    access_key = "your_access_key"
    secret_key = "your_secret_key"
    region = "eu-west-1" # You can change the region for the one your prefer
}

# Nice copy pasta from the doc (https://www.terraform.io/docs/providers/aws/r/instance.html)
data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"]
  }

  filter {
    name = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_vpc" "default" {
    cidr_block = "172.16.0.0/16"
}

resource "aws_internet_gateway" "default"{
    vpc_id = "${aws_vpc.default.id}"
}

resource "aws_subnet" "default" {
    vpc_id = "${aws_vpc.default.id}"
    cidr_block = "172.16.0.0/16" # Just one big subnet covering the whole VPC. Of course do not use that in production.
}

resource "aws_security_group" "open_bar" {
    name = "open_bar"
    description = "Allow all connections inbound and outbound"
    vpc_id = "${aws_vpc.default.id}"
    ingress {
        from_port = "0"
        to_port = "0"
        protocol = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }
    egress {
        from_port = "0"
        to_port = "0"
        protocol = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

resource "aws_instance" "simple_instance" {
    ami = "${data.aws_ami.ubuntu.id}"
    instance_type = "t2.micro"
    subnet_id = "${aws_subnet.default.id}"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You see straight what components you’re creating with terraform, compared to a bash script full of curls, it’s more clear right?&lt;/p&gt;

&lt;p&gt;Now let’s see how to use this file and dismistied it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Planning
&lt;/h4&gt;

&lt;p&gt;Before doing anything regrettable, let’s see what terraform will do. For that:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform plan&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And you should have an output showing you every resource we gonna create.&lt;/p&gt;

&lt;p&gt;I advise you to save every plan you do before applying it. With this way to proceed, you are sure that what the plan planned will be applied and nothing more/less.&lt;/p&gt;

&lt;p&gt;For that, just specify the filename/path where you want to save your plan.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terarform plan -out ./my_aws_plan&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then after being happy with what the plan will do let’s apply it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform apply ./my_aws_plans&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And if you go in the console you should see that you have a brand new vpc, a subnet and an instance running.&lt;/p&gt;

&lt;p&gt;Let’s destroy all of these the time I explain you what we’ve just wrote in this main.tf file.&lt;/p&gt;

&lt;p&gt;For that: &lt;code&gt;terraform destroy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And tada, you come back to your original state, super easy isn’t it?&lt;/p&gt;

&lt;h3&gt;
  
  
  What just happened?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Terraform plan
&lt;/h4&gt;

&lt;p&gt;Planning in terraform is the best way to test, supervise and monitor what terraform will do. Everytime you want to test your terraform project -&amp;gt; plan, you’ll see syntax /logical errors. PLanning does not prevent on provider issues though. For example you create a subnet with a range like 172.0.0.&lt;sup&gt;1&lt;/sup&gt;⁄32 (this is just an example) and you define a ec2 instance inside the subnet with a private ip like 192.168.1.1, well terraform will only get the error once you apply your change as AWS will return an error when terraform will do the API call.&lt;/p&gt;

&lt;p&gt;So in our first try, the terraform plan created only stuff, which is normal as we started from scratch, but how do terraform will know how to modify some infra from the previous run? If you have a look in your project folder, you have a terraform.tfstate file. This is what terraform use to know the state of the components you defined in your main.tf in the cloud.&lt;/p&gt;

&lt;p&gt;When you do a plan if this terraform.tfstate file exists, terraform will pull the actual infrastructure configuration, update your tfstate file and compare what’s in the tfstate and what you defined in the main.tf and will prompt you what will change once you run the apply.&lt;/p&gt;

&lt;h4&gt;
  
  
  Terraform apply
&lt;/h4&gt;

&lt;p&gt;This action will actually do the API calls to your cloud provider, if no plan_file is specified terraform will update the state file &lt;strong&gt;before&lt;/strong&gt; the apply, and will update after. That’s why you better using a plan all the time in case your architecture gets modified between your plan and your apply.&lt;/p&gt;

&lt;h3&gt;
  
  
  The terraform syntax
&lt;/h3&gt;

&lt;p&gt;The terraform syntax is a common syntax if you used other hashicorps tools before. They use the .hcl format that they created which is JSON superpowered with comments and many other stuff (Ok, I can’t find anything else right now, you got a point).&lt;/p&gt;

&lt;p&gt;In Terraform, you have mostly two kind of definition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;terraform_keyword name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;terraform_keyword component_type component_id&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the first syntax, the &lt;code&gt;&amp;lt;terraform_keyword&amp;gt;&lt;/code&gt; can be :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provider : Will provide authentication to the cloud provider&lt;/li&gt;
&lt;li&gt;variable : Create a variable for the scope of your terraform apply&lt;/li&gt;
&lt;li&gt;configuration : Used to configure terraform, useful for backends configuration (we’ll see that later)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every things defined with terraform in your cloud provider will have the same structure&lt;code&gt;&amp;lt;terraform_keyword&amp;gt; &amp;lt;component_type&amp;gt; &amp;lt;component_id&amp;gt; { ... }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The terraform keyword can vary between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;resource : Create a new component in the cloud using the provider configured&lt;/li&gt;
&lt;li&gt;data : Will retrieve information about an existing component&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The components type will all be different regarding which cloud provider you’re using. The terraform documentation is your friend in this case (I’ll not enumerate all of it as there’s 100s)&lt;/p&gt;

&lt;p&gt;And to finish the component_id, can be everything you like, the time you understand what it is. It used by terraform to identify the different components created. For example, if we would have defined two different kind of aws_instance, it would have been great to use 2 different component_id such as “front_end” or “back_end” etc…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt; : If for any reason you’re changing this id, terraform will consider it as a new resource and will remove the exisiting one instead of modifying it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Provider section
&lt;/h4&gt;

&lt;p&gt;in terraform you’ll always need a provider section, you can consider this section as the authentication part of your terraform config. Here we did setup all the configuration, but you can set it up with env variables on the machine you’re running terraform.&lt;/p&gt;

&lt;p&gt;You can of course use multiple providers in case you write your terraform files for azure, aws, vmware, etc…&lt;/p&gt;

&lt;h4&gt;
  
  
  Resources sections
&lt;/h4&gt;

&lt;p&gt;This is where you define all the components you wants to &lt;strong&gt;create&lt;/strong&gt; in the cloud. They are provider specific and once they are created you can access to different variables that this ressource will provide you. For example, creating the ec2 instance, we reuse the id of the subnets we created earlier.&lt;/p&gt;

&lt;p&gt;Once again, everything is detailed for every resource in the terraform documentation.&lt;/p&gt;

&lt;h4&gt;
  
  
  Interpolation
&lt;/h4&gt;

&lt;p&gt;If you read what I wrote just above in the resources section, you understood that the barbaric syntax used for defining the subnets of our aws_instance is a variable value. In terraform you can use strings with \${} to give some logic to the attributes you define. You can reuse ids of components you created (as we did), you can even use loops, conditions, maps, and even some mathematics function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Raffined our project
&lt;/h3&gt;

&lt;p&gt;With the time, your project might get bigger, by that I mean, your main.tf file might contains thousands of line, which make it tough to maintain. Let’s start with an intuitive approach: cut our main.tf file into pieces.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cutting the main.tf
&lt;/h4&gt;

&lt;p&gt;Terraform allows you to create whatever files you want, during a plan or an apply it will try to concatenate all the &lt;code&gt;*.tf&lt;/code&gt; files in the current folder in one file. It will solve the dependencies between the different file and should be able to recreate the main.tf file as it was before we cut it in pieces. We just need to be &lt;strong&gt;logical&lt;/strong&gt; on how we will do it.&lt;/p&gt;

&lt;p&gt;Let’s put the provider in a different file first. Let’s create a&lt;code&gt;providers.tf&lt;/code&gt; file in the current folder containing just our aws logging creds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="c1"&gt;# providers.tf&lt;/span&gt;

&lt;span class="k"&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;access_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"your_access_key"&lt;/span&gt;
    &lt;span class="nx"&gt;secret_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"your_secret_key"&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;"eu-west-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can even commit this file with empty credentials, and just make sure you’ll never push it again.&lt;/p&gt;

&lt;p&gt;Let’s test it!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform apply&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;…&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ok you’re not reading the whole article. I said to test we use &lt;strong&gt;plan not apply&lt;/strong&gt;. Well anyway if you fell in the trap, this should have not change anything.&lt;/p&gt;

&lt;p&gt;Let’s continue with our network configuration. Let’s put the VPC, gateway in it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# vpc.tf

resource "aws_vpc" "default" {
    cidr_block = "172.16.0.0/16"
}

resource "aws_internet_gateway" "default"{
    vpc_id = "${aws_vpc.default.id}"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s do the same with subnets, security_groups and instances&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="c1"&gt;# subnets.tf&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_subnet"&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;vpc_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&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="k"&gt;}&lt;/span&gt;&lt;span class="s2"&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="s2"&gt;"172.16.0.0/16"&lt;/span&gt; &lt;span class="c1"&gt;# Just one big subnet covering the whole VPC. Of course do not use that in production.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="c1"&gt;# security_groups.tf&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"open_bar"&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;"open_bar"&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 connections inbound and outbound"&lt;/span&gt;
    &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&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="k"&gt;}&lt;/span&gt;&lt;span class="s2"&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="s2"&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="s2"&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;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="s2"&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="s2"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# instances.tf&lt;/span&gt;

&lt;span class="c1"&gt;# Yeah I put the ami with instances. No need elsewhere.&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_ami"&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;most_recent&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;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;"name"&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="s2"&gt;"ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"&lt;/span&gt;&lt;span class="p"&gt;]&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;"virtualization-type"&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="s2"&gt;"hvm"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;owners&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"099720109477"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Canonical&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;"simple_instance"&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;"${data.aws_ami.ubuntu.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;"t2.micro"&lt;/span&gt;
    &lt;span class="nx"&gt;subnet_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${aws_subnet.default.id}"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the end of the refactoring you’ll get a nicer structure. This structure will last for few times until you infrastructure starts to get bigger. With time you’ll see some limit to it like in case of complex dependencies or even about SOC (Separation of concerns)&lt;/p&gt;

&lt;p&gt;So here comes modules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modules
&lt;/h2&gt;

&lt;p&gt;With modules you can seperate components of your infrastructure inside_modules_ allowing you to prevent any repetition in your infra definition. Really handy when you want to scale up some components of your current infra or when you want to refactor “all the masters”.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;To start with modules, you juxg need to create a modules folder at the root of your project, and create a folder with the name of the module you want to create. Inside the last folder you just need to create three files and you will have created your first module! Those files are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;variables.tf: This file contains all the variables you would like to parametrize your module. For example you will pass some vpc_id or some AMIs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;main.tf: Like our first main.tf it will contains all the resource definition of your module.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;outputs.tf: Contains all the variables you will need after executing the modules. The most common use is to &lt;em&gt;output&lt;/em&gt; the public ips of the future created instances.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using it
&lt;/h3&gt;

&lt;p&gt;In our example, the infra is quite simple so this module will be as well. We will just put our simple_instance inside the module. But in a way as we can configure on which subnet, which az it will be.&lt;/p&gt;

&lt;p&gt;Let’s start creating the module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p modules/my\_cluster\_of\_instances touch modules/my\_cluster\_of\_instances/{main,variables,output}.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s put our definition of the “simple_instance” in the main.tf&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# main.tf

resource "aws_instance" "simple_instance" {
    ami = "${var.ami_id}"
    instance_type = "${var.instance_type}"
    subnet_id = "${var.subnet_ids}"
    count = "${cluster_size}"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you saw, I changed the variable to be something defined from the variable.tf file. I added a count attribute in case we want to scale up this module&lt;/p&gt;

&lt;p&gt;Now let’s configure the variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# variables.tf

variable "subnet_ids" {
    description = "The list of subnet id"
}

variable "cluster_size" {
    description "The number of instance you want"
    default = 1
}

variable "instance_type" {
    description = "The type of instance you want"
    default = "t2.micro"
}

variable "ami_id" {
    description = "The AMI to use on these instances"
}

# output.tf

output "private_ips" {
    value = ["${aws_instance.simple_instance.*.private_ip}"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last one use a wildcard as we don’t know how many instances will be created in the module. It means “&lt;em&gt;Ouput&lt;/em&gt; a list of the instances’s private ips”&lt;/p&gt;

&lt;p&gt;So now let’s create a main.tf at the root of our project calling this module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# main.tf

# Everything we had a bit earlier ... (vpcs, subnets until the instance resource)

module "awesome_instance" {
    module_path = "modules/my_cluster_of_instances"
    ami_id = "${data.aws_ami.ubuntu.id}"
    subnet_id = "${aws_subnet.default.id}"
    instance_type = "t2.micro" # No need of this line as there's a default value
    cluster_size = 2 # Here we override the default value
}

aws_security_group_rule "a_simple_sg_rule" {
    security_group_id = "${}"
    type = "ingress"
    from = 0
    to_port = 0
    protocol = -1
    cidr_block = ["${module.awesome_instance.private_ips}"] # Using here the output of our module
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform get # Will create reference to our module
terraform plan # Should destroy what we had before
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sadly terraform will not understand that this module represent your old instance, and will try to remove your old instance to put the two news.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion about project structure
&lt;/h3&gt;

&lt;p&gt;So far, the module structure is the best one I met at the moment. I usually comes with few folders at the root of my projects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;modules/&lt;/li&gt;
&lt;li&gt;env1/&lt;/li&gt;
&lt;li&gt;env2/&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And using envx as a proper seperation between environments. It’s really handy when you have a lot of differences between environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other commands with terraform
&lt;/h2&gt;

&lt;p&gt;To finish this &lt;em&gt;super&lt;/em&gt; &lt;em&gt;long&lt;/em&gt; article, I will briefly speaks about the command we did not see in the article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Taint
&lt;/h3&gt;

&lt;p&gt;In terraform you can taint some resources so they will get destroyed at the next apply. Really useful if you want to start from scratch with some components.&lt;/p&gt;

&lt;p&gt;From our module example, we would use it like that:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;terraform taint -module=awesome_instance instance.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So you need to specify to which module you’re tainting the ressource from. And after that resource_name.which_one .&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt; : There’s no support for wildcard yet according to &lt;a href="https://github.com/hashicorp/terraform/issues/"&gt;this github issue&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Graph
&lt;/h3&gt;

&lt;p&gt;If you have graphviz installed in your laptop, you can create a graph of the terraform resources you define.&lt;/p&gt;

&lt;h3&gt;
  
  
  Import
&lt;/h3&gt;

&lt;p&gt;If you created some resources in the UI, adding their definition in your tf project will not be enough. You need to add it to your terraform state using the import command.&lt;/p&gt;

&lt;p&gt;For example if we did create the ec2 instance in the ui. We would add it like that in the tfstate file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform import aws\_instance.my\_instance the\_id\_of\_the\_instance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;There’s still much more to say about terraform but I’ll stop here as I reached nearly 2500 words… We have seen that Terraform is a great tool to manage infrastructure with code. Their .tf format is a really good thing compared to simple json definition. And terraform is quite permissive so you can start with a simple project and finish with hundreds of modules calling each others making the adopotion of the tool quite easy. Anyway I leave you enjoy your &lt;code&gt;terraform destroy&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Sur ce, codez bien! Ciao!&lt;/p&gt;

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