<?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: Dennis Groß (he/him)</title>
    <description>The latest articles on DEV Community by Dennis Groß (he/him) (@gdenn).</description>
    <link>https://dev.to/gdenn</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%2F666677%2F38595ee9-a1b5-4e84-9469-eaa948b7f4f9.jpeg</url>
      <title>DEV Community: Dennis Groß (he/him)</title>
      <link>https://dev.to/gdenn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gdenn"/>
    <language>en</language>
    <item>
      <title>Beginners Guide to AWS VPCs</title>
      <dc:creator>Dennis Groß (he/him)</dc:creator>
      <pubDate>Sat, 24 Dec 2022 19:00:00 +0000</pubDate>
      <link>https://dev.to/gdenn/beginners-guide-to-aws-vpcs-9ja</link>
      <guid>https://dev.to/gdenn/beginners-guide-to-aws-vpcs-9ja</guid>
      <description>&lt;p&gt;A Virtual Private Cloud is a dedicated network in your AWS account that you can use to deploy private AWS services like EC2. VPCs are isolated networks that are deployed into an AWS region and can use all availability zones of that region.&lt;/p&gt;

&lt;p&gt;A VPC consists of&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subnets&lt;/li&gt;
&lt;li&gt;Routing tables that are associated with subnets&lt;/li&gt;
&lt;li&gt;NAT gateways&lt;/li&gt;
&lt;li&gt;An internet gateway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each AWS Region comes with a default VPC which has one public subnet which can be accessed from the internet and route requests out to the internet.&lt;/p&gt;

&lt;h2&gt;
  
  
  VPC Router
&lt;/h2&gt;

&lt;p&gt;Every VPC has a VPC router that handles the routing between subnets, Internet Gateway, and NAT Gateway. The +1 address in each subnet is reserved for the router.&lt;/p&gt;

&lt;p&gt;The router uses Route Tables that are defined on a per subnet type basis and concrete subnet instances in an availability zone use a Route Table Association to identify their rout table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Network Address Translation (NAT)
&lt;/h2&gt;

&lt;p&gt;NATs map local devices to a public IPv4 address. A request from the internet to a local network device (with a private IPv4) passes the NAT Gateway which then maps the private IPv4 of the device to a public IPv4 that the NAT maintains.&lt;/p&gt;

&lt;p&gt;This can be done in three different modes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static NAT&lt;/li&gt;
&lt;li&gt;Dynamic NAT&lt;/li&gt;
&lt;li&gt;PAT&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Static NAT
&lt;/h3&gt;

&lt;p&gt;Each device with its local, private IPv4 address gets mapped to one static public IPv4 address. So there is a 1:1 relationship between local device IPs and public NAT gateway IPs.&lt;/p&gt;

&lt;p&gt;The AWS Internet Gateway operates in the Static NAT mode.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dynamic NAT
&lt;/h3&gt;

&lt;p&gt;The NAT gateway maintains a list of public IPv4 addresses. Each request from/to a local device gets mapped to one of the available public IPs. So there is no static public IP provided for each device, the IP changes on a per-request basis.&lt;/p&gt;

&lt;h3&gt;
  
  
  PAT
&lt;/h3&gt;

&lt;p&gt;PAT stands for Port Address Translation and maps multiple local device IPs to the same public IP through ports. The NAT gateway associates a port on the public IP to a local device IP on a per-request basis.&lt;/p&gt;

&lt;p&gt;This means that local devices are not directly reachable from the internet since they get associated with a different port for each request.&lt;/p&gt;

&lt;p&gt;The AWS NAT Gateway operates in this mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  VPC CIDR
&lt;/h2&gt;

&lt;p&gt;The VPC CIDR defines the network range that the VPC spans. This range must be private and can be &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/28&lt;/code&gt; at minimum (16 IPs, 14 usable)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/16&lt;/code&gt; at most (65536 IPs, 65534 usable)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good range that you can use are &lt;code&gt;10.x.x.x/y&lt;/code&gt; CIDRs but try to avoid &lt;code&gt;10.0.x.x/y&lt;/code&gt; and &lt;code&gt;10.1.x.x/y&lt;/code&gt; since those are very popular ranges.&lt;/p&gt;

&lt;p&gt;You should plan your VPC CIDRs beforehand and estimate how many regions in an account you want to use. Choose VPC CIDRs that do not overlap in the same organization and give yourself a buffer of 2-3 extra CIDR ranges in case your business use case grows.&lt;/p&gt;

&lt;p&gt;E.g. calculation:&lt;/p&gt;

&lt;p&gt;5 AWS accounts * (4 used regions + 2 Buffer) = 30 CIDR ranges &lt;/p&gt;

&lt;h3&gt;
  
  
  CIDR Sizes
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Micro&lt;/th&gt;
&lt;th&gt;/24&lt;/th&gt;
&lt;th&gt;216 IPv4&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Small&lt;/td&gt;
&lt;td&gt;/21&lt;/td&gt;
&lt;td&gt;2008 IPv4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;/19&lt;/td&gt;
&lt;td&gt;8152 IPv4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;td&gt;/18&lt;/td&gt;
&lt;td&gt;16344 IPv4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Large&lt;/td&gt;
&lt;td&gt;/16&lt;/td&gt;
&lt;td&gt;65456 IPv4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Subnetting
&lt;/h3&gt;

&lt;p&gt;A subnet is a smaller network within the VPC and can vary in&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How it can be accessed from outside of the internet&lt;/li&gt;
&lt;li&gt;How it can access the internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You divide a VPC into subnets by providing the subnet a sub-range of the VPC CIDR.&lt;/p&gt;

&lt;p&gt;So it is important to choose an appropriate CIDR range for your VPC in the first place to house all of your subnets. A subnet should have enough IPs to house all of the AWS services that you need to deploy into your VPC while leaving a proper buffer.&lt;/p&gt;

&lt;p&gt;It is also important to keep in mind that each subnet can only use &lt;code&gt;count(subnet_cidrs) - 2&lt;/code&gt; IPv4 of the subnet CIDR since&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first IPv4 …&lt;/li&gt;
&lt;li&gt;The last IPv4 …&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Three-Tier Application
&lt;/h3&gt;

&lt;p&gt;The Three - Tier Application is a VPC best practice that breaks a VPC into three subnets&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Tier - public subnet for frontend applications and public APIs&lt;/li&gt;
&lt;li&gt;Computing Tier - private subnet for private backend services&lt;/li&gt;
&lt;li&gt;Data Tier - private subnet for data services&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Finding the correct Subnet Structure
&lt;/h3&gt;

&lt;p&gt;The Three-Tier Application VPC structure is always a good starting point, but it makes sense to add a fourth spare subnet in case your business use case grows. It is quite difficult to resize VPCs once they are housing productive workloads so you should think ahead and be more generous with the number of subnets you provide. &lt;/p&gt;

&lt;h3&gt;
  
  
  Availability Zones
&lt;/h3&gt;

&lt;p&gt;VPC subnets are deployed into availability zones, which means you need to provide a CIDR range for each subnet per availability zone. It is a good practice to go with 3 availability zones as a standard but keep a CIDR range for a potential 4th availability zone in reserve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Internet Gateway
&lt;/h2&gt;

&lt;p&gt;The Internet Gateway can provide static, public IPv4 addresses to resources deployed in a VPC subnet that route directly to the Internet Gateway (Static NAT). So resources within those subnets have a public IP address attached and can be accessed from the internet.&lt;/p&gt;

&lt;p&gt;The Internet Gateway service runs in the AWS public zone and &lt;/p&gt;

&lt;p&gt;Region resilient&lt;/p&gt;

&lt;h2&gt;
  
  
  NAT Gateway
&lt;/h2&gt;

&lt;p&gt;The NAT Gateway uses the Port Address Translation (PAT) mode to temporarily map a VPC subnet resource (that routes to the NAT Gateway) to a port on the NAT Gateway public, static IPv4 address. &lt;/p&gt;

&lt;p&gt;A NAT Gateway must be&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deployed to a public subnet (a subnet that routes to an Internet Gateway)&lt;/li&gt;
&lt;li&gt;have an elastic IPv4 address (EIP)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Resources behind NAT Gateways cannot be accessed from the internet but can send requests out to the internet. &lt;/p&gt;

&lt;p&gt;Each HTTP request that goes to the internet needs to go through a public IPv4 address. A TCP/UDP request has a source and destination IP address as well as a source and destination port.  In the case of HTTP, these outgoing requests have an ephemeral source port that can only be reached from the internet resource that you call for the HTTP response.&lt;/p&gt;

&lt;p&gt;The NAT Gateway provides an ephemeral source port to the elastic IP address attached to it for each request coming from a device in the private subnet. So outgoing internet requests are possible because internet resources can respond in the same request to the epihermal source port on the elastic IP address.&lt;/p&gt;

&lt;p&gt;Subsequent requests from outside the internet to the epihermal port are not successful because the ephemeral ports are assigned on a per-request basis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing Tables
&lt;/h2&gt;

&lt;p&gt;A routing table contains route entries and tells each CIDR whether&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it needs to go through the next router, called “next hop”&lt;/li&gt;
&lt;li&gt;can reach the requested resource in the network of this routing device&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;e.g.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;10.0.0/16&lt;/th&gt;
&lt;th&gt;Local&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.0.0.0/0&lt;/td&gt;
&lt;td&gt;igw-12345678901234567&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table above tells the routing device that incoming requests that target an IPv4 within the 10.0.0/16 CIDR remain in the Local network. &lt;/p&gt;

&lt;p&gt;The loopback address 0.0.0.0/0 is set to the Internet Gateway. That address basically matches all IPv4 addresses and routing tables use rules with the loopback address with the lowest priority. This makes sure that all requests that do not match any rule in the table get redirected to the Internet Gateway.&lt;/p&gt;

&lt;p&gt;Routing tables prioritize rules with more specific CIDR ranges over less specific ones. A CIDR range is more specific if it targets a smaller IPv4 range, so when the network mask value is higher. 0 is the lowest network mask and matches all IPv4 addresses, so it has the lowest priority.&lt;/p&gt;

&lt;h3&gt;
  
  
  Route Associations
&lt;/h3&gt;

&lt;p&gt;You typically have multiple subnets spread across availability zones in your region and it would be tedious if you have to define one routing table for each subnet. After all, a subnet needs a routing table to define how incoming/outgoing requests get routed.&lt;/p&gt;

&lt;p&gt;You can define one or multiple routing tables in your VPC configuration and then create one route association per subnet which makes it unnecessary to define a separate routing table for each subnet.&lt;/p&gt;

&lt;p&gt;You should create multiple routing tables if you have different types of subnets like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;public subnets&lt;/li&gt;
&lt;li&gt;private subnets&lt;/li&gt;
&lt;li&gt;private, isolated subnets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thus, you define a routing table for each subnet type instead of each individual subnet. you then associate the routing table with the corresponding subnet, e.g. a private subnet instance gets associated with the private subnet routing table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subnets
&lt;/h2&gt;

&lt;p&gt;Subnets are smaller parts of the VPC network that underly specific routing rules, provided through the associated Routing Table.&lt;/p&gt;

&lt;h3&gt;
  
  
  Public Subnets
&lt;/h3&gt;

&lt;p&gt;A public subnet has a direct route to an internet gateway which attaches a public IPv4 to each resource ENI deployed to the subnet. &lt;/p&gt;

&lt;p&gt;An External Network Interface (ENI) represents a virtual network card and is a bridge between actual AWS resources such as an EC2 instance and your VPC subnets. Requests to an AWS resource actually get targeted to its ENI which proxies the request to the resource. &lt;/p&gt;

&lt;p&gt;Resources should only be deployed to a public network if they purposely should be reachable from the internet. This is necessary e.g. necessary for frontend applications or public APIs. Private APIs or DBMS on the other side should never be deployed in a public network so they do not receive a public IPv4 address.&lt;/p&gt;

&lt;h3&gt;
  
  
  Private Subnets
&lt;/h3&gt;

&lt;p&gt;Private subnets do not route directly to the Internet Gateway and thus do not receive a static public IPv4 address. A private subnet can communicate to the internet by routing through a NAT Gateway to the Internet Gateway.&lt;/p&gt;

&lt;p&gt;The NAT Gateway binds a resource from the private subnet to a port on the public static IPv4 (PAT) so resources in the private subnets can receive responses from websites that they may call from inside the VPC.&lt;/p&gt;

&lt;h3&gt;
  
  
  Private Isolated Subnets
&lt;/h3&gt;

&lt;p&gt;Private isolated subnets are private subnets that have no route to a NAT Gateway and thus cannot reach the internet, nor can be reached from the internet.&lt;/p&gt;

&lt;p&gt;This type of subnet is used to house critical infrastructure like managed data services such as RDS which do not need to communicate to the internet. In fact, it is a security advantage that the resources in this subnet cannon communicate to the internet. Otherwise, an attacker could transfer data out of the VPC upon compromising the isolated subnet.&lt;/p&gt;

&lt;h3&gt;
  
  
  High Availability in VPCs
&lt;/h3&gt;

&lt;p&gt;Subnet instances are deployed into availability zones.&lt;/p&gt;

&lt;p&gt;It is a good practice to deploy subnets into at least three AZs if the system is productive or only one AZ for SDLC or staging. Each CIDR range of subnets deployed in the AZs must not overlap and there is a cost of transferring data cross-az.&lt;/p&gt;

&lt;p&gt;This makes the multi-az setup costly for staging and SDLC accounts.&lt;/p&gt;

&lt;h2&gt;
  
  
  VPC Configuration Flags
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;tenancy&lt;/em&gt; - defines where resources in the VPC get deployed to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;default - uses shared resources&lt;/li&gt;
&lt;li&gt;dedicated - uses dedicated hardware resources (premium price)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;enableDnsHostnames&lt;/em&gt; - gives service instances in your subnets hostnames&lt;/p&gt;

&lt;p&gt;&lt;em&gt;enableDnsSupport&lt;/em&gt; - enables DNS resolution for resources in your DNS (Route53)&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>cloudnative</category>
      <category>cloudskills</category>
    </item>
    <item>
      <title>AWS IAM roles in Terraform</title>
      <dc:creator>Dennis Groß (he/him)</dc:creator>
      <pubDate>Fri, 23 Dec 2022 19:00:00 +0000</pubDate>
      <link>https://dev.to/gdenn/aws-iam-roles-in-terraform-1eh8</link>
      <guid>https://dev.to/gdenn/aws-iam-roles-in-terraform-1eh8</guid>
      <description>&lt;p&gt;IAM roles can be created with the &lt;code&gt;aws_iam_role&lt;/code&gt; resource identifier. Other resources such as EC2 instances can assume these roles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;aws_iam_role&lt;/code&gt; Resource
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_iam_role&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;instance_profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web-server-instance-profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

  &lt;span class="nx"&gt;assume_role_policy&lt;/span&gt; &lt;span class="o"&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="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2012-10-17&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;Statement&lt;/span&gt; &lt;span class="o"&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;Action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sts:AssumeRole&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;Principal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;Service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ec2.amazonaws.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nx"&gt;Effect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Allow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;Sid&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example above contains an IAM role with a role policy that allows the AWS EC2 service to assume another role. the concept of assuming another role through a role is called “role chaining”.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;aws_iam_role&lt;/code&gt; has the following attributes (non-exhaustive listing)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; (optional) - the name of the role as it will appear in the IAM console&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;path&lt;/code&gt; (optional) - groups roles into a common namespace path (to keep a better overview of your roles)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;assume_role_policy&lt;/code&gt; (required) - controls what or who can assume this role (principal). This policy is also known under the term “trust policy”&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;managed_policy_arns&lt;/code&gt; (optional) - list of AWS managed policies that you can attach to this role&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;inline_policy&lt;/code&gt; (optional) - provides you the possibility to write a policy that is directly attached to the role.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;policy&lt;/code&gt; (required) - references a policy document resource that gets attached to the role&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Trust Policies
&lt;/h2&gt;

&lt;p&gt;Every IAM role must specify a trust policy (&lt;code&gt;assume_role_policy&lt;/code&gt;) as mentioned in the last bullet section.&lt;/p&gt;

&lt;p&gt;The trust policy defines who can assume a particular role through the AWS Secure Token Service (STS). The entity that can assume the role is called a principal.&lt;/p&gt;

&lt;p&gt;Principals can be&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IAM users&lt;/li&gt;
&lt;li&gt;AWS resources (by ARN)&lt;/li&gt;
&lt;li&gt;Other roles (→ “role chaining”)&lt;/li&gt;
&lt;li&gt;Entire services (e.g. “ec2.amazonaws.com”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Inline Policies
&lt;/h2&gt;

&lt;p&gt;An inline policy is a policy document that is directly attached to an IAM role and does only exist in the context of this role.&lt;/p&gt;

&lt;p&gt;It is a best practice to define IAM policies as dedicated resources if they can be re-used in the context of e.g. other roles. But it is ok to define inline policies if you know that the policy only makes sense in the context of a specific role.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managed Policies
&lt;/h2&gt;

&lt;p&gt;AWS provides predefined policy documents for common use cases like using the Cloud Watch Agent in an EC2 instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_iam_role_policy_attachment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;smm_policy_attachment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore&lt;/span&gt;&lt;span class="dl"&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 code above attaches the managed policy &lt;code&gt;"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"&lt;/code&gt; to the AWS instance profile role of an EC2 instance. The policy provides basic permissions to the AWS Systems Manager which we need to use the AWS Session Manager to SSH into the EC2 instance.&lt;/p&gt;

&lt;p&gt;Using managed policies can be beneficial since you are using best practices provided by AWS. Inn addition to that, managed policies remove maintenance overhead from you since you don’t have to maintain the policy.&lt;/p&gt;

&lt;p&gt;On the other hand, managed policies take control away from you since you cannot fine-tune the permissions that they give.&lt;/p&gt;

&lt;h2&gt;
  
  
  EC2 Instance Profile
&lt;/h2&gt;

&lt;p&gt;It is a good practice to handle the permissions of an EC2 instance through an IAM role that the instance assumes. This role is called the “instance profile role”.&lt;/p&gt;

&lt;p&gt;The EC2 &lt;code&gt;aws_instance&lt;/code&gt; resource has an &lt;code&gt;iam_instance_profile&lt;/code&gt; attribute that can be used for this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_instance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web_server&lt;/span&gt;&lt;span class="dl"&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;iam_instance_profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_instance_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_profile&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;depends_on&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;aws_iam_role_policy_attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;smm_policy_attachment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;aws_iam_role_policy_attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cw_agent_policy_attachment&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The attribute references an IAM role. In our case, it references a role called &lt;code&gt;instance_profile&lt;/code&gt; that we create through the &lt;code&gt;aws_iam_role&lt;/code&gt; resource identifier.&lt;/p&gt;

&lt;p&gt;The EC2 instance and IAM role get married together through the &lt;code&gt;aws_iam_instance_profile&lt;/code&gt; that the &lt;code&gt;aws_instance&lt;/code&gt; resource references and which on the other hand references the IAM role.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_iam_instance_profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;instance_profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web-server-instance-profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_profile&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;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_iam_role&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;instance_profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web-server-instance-profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

  &lt;span class="nx"&gt;assume_role_policy&lt;/span&gt; &lt;span class="o"&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="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2012-10-17&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;Statement&lt;/span&gt; &lt;span class="o"&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;Action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sts:AssumeRole&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;Principal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;Service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ec2.amazonaws.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nx"&gt;Effect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Allow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;Sid&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_iam_policy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cw_agent_policy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cw-agent-policy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;path&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;policy to alow ec2 instance to push metrics and logs to CloudWatch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

  &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="o"&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="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2012-10-17&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;Statement&lt;/span&gt; &lt;span class="o"&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;Action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logs:CreateLogGroup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logs:CreateLogStream&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logs:PutLogEvents&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logs:DescribeLogStreams&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="nx"&gt;Effect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Allow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;Resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&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;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;This only works if you specify a “trust policy” on the IAM role (&lt;code&gt;assume_role_policy&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;We used the “ec2.amazonaws.com” service as a trusted principal in this case, but you could be more restrictive by only allowing the &lt;code&gt;web_server&lt;/code&gt; EC2 instance as a principal (by the instance ARN).&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;jsonencode&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;jsonencode&lt;/code&gt; method takes a Terraform object annotation as an argument and converts it to a JSON string that we can use for policy attributes e.g. in the &lt;code&gt;aws_iam_role&lt;/code&gt; resource.&lt;/p&gt;

&lt;p&gt;It is a good practice to use &lt;code&gt;jsonencode&lt;/code&gt; when you specify policies since it makes it possible to define a JSON String policy while having the usual Linter support for Terraform through your IDE.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>aws</category>
      <category>cloud</category>
      <category>cloudskills</category>
    </item>
    <item>
      <title>Compute AWS VPC Subnet CIDRs in Terraform</title>
      <dc:creator>Dennis Groß (he/him)</dc:creator>
      <pubDate>Thu, 22 Dec 2022 19:00:00 +0000</pubDate>
      <link>https://dev.to/gdenn/compute-aws-vpc-subnet-cidrs-in-terraform-3o11</link>
      <guid>https://dev.to/gdenn/compute-aws-vpc-subnet-cidrs-in-terraform-3o11</guid>
      <description>&lt;p&gt;Subnetting is the process of dividing a larger network CIDR e.g. &lt;code&gt;10.0.0.0/16&lt;/code&gt; into smaller subnets e.g. &lt;code&gt;10.0.1.0/24&lt;/code&gt;, &lt;code&gt;10.0.2.0/24&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A CIDR consists of two parts&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the host part of the CIDR&lt;/li&gt;
&lt;li&gt;the subnet mask part of the CIDR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The subnet mask is the &lt;code&gt;/16&lt;/code&gt; value behind the CIDR IP and determines how many bits of the IP are host part. The &lt;code&gt;/16&lt;/code&gt; is a short notation for the bit mask &lt;code&gt;255.255.0.0&lt;/code&gt; which is another short notation for &lt;code&gt;11111111.11111111.00000000.00000000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Do a logical and with the CIDR IP to find the host part, in our case it is the first half of the IP which determines the stable part of the subnet range. The second half of the IP is a wildcard and refers to the dynamic part of our CIDR IP.&lt;/p&gt;

&lt;p&gt;This means that our network defined through &lt;code&gt;10.0.0.0/16&lt;/code&gt; spans the network &lt;code&gt;10.0.0.0&lt;/code&gt; - &lt;code&gt;10.0.255.255&lt;/code&gt; which is around ~65k IPs.&lt;/p&gt;

&lt;p&gt;So the network mask determines the amount of IPs spanned over the network. A higher subnet mask refers to a smaller network size.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subnetting in Terraform
&lt;/h2&gt;

&lt;p&gt;Subnetting is the process of breaking a larger CIDR range down to a smaller subnet CIDRS. E.g. we have a network CIDR &lt;code&gt;10.0.0.0/16&lt;/code&gt; and break it down to multiple subnets &lt;code&gt;10.0.0.0/24&lt;/code&gt; , &lt;code&gt;10.0.1.0/24&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is often necessary for the context of e.g. VPCs in AWS or other cloud providers.&lt;/p&gt;

&lt;p&gt;Terraform offers a function called &lt;code&gt;cidrsubnet&lt;/code&gt; that makes it possible to calculate subnets based on the &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;base CIDR - network CIDR that we divide into subnets&lt;/li&gt;
&lt;li&gt;netnum - Offset that we use for the subnet&lt;/li&gt;
&lt;li&gt;newbits - base CIDR net mask + newbits determines new subnet mask for subnet
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_subnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subnet_computing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;                  &lt;span class="o"&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;map_public_ip_on_launch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="nx"&gt;count&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azs_count&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cidrsubnet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr_offset&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="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;computing_offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;availability_zone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&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;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.vpc_name}-subnet-computing-${count.index}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example above uses the VPC cidr &lt;code&gt;var.cidr&lt;/code&gt; e.g. &lt;code&gt;10.0.0.0/16&lt;/code&gt; and adds the newbits netmask offset to it &lt;code&gt;16 + 8 = 24&lt;/code&gt; which results in the new subnet bit mask &lt;code&gt;/24&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally, we add the netnum which is the current index &lt;code&gt;count.index&lt;/code&gt; + the offset &lt;code&gt;local.computing_offset&lt;/code&gt; that we already used to compute subnet CIDRs for other AWS VPC subnets.&lt;/p&gt;

&lt;p&gt;The result is a subnet CIDR e.g. &lt;code&gt;10.0.12.0/24&lt;/code&gt; that we use for the VPC subnet.&lt;/p&gt;

&lt;p&gt;Using the Terraform &lt;code&gt;cidrsubnet&lt;/code&gt; function makes it obsolete to define lists of subnet CIDRs ranges for each subnet that you want to create. You just have to define a base network CIDR range and an newbits value.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>discuss</category>
      <category>typescript</category>
      <category>node</category>
    </item>
    <item>
      <title>How to use Terraform variables</title>
      <dc:creator>Dennis Groß (he/him)</dc:creator>
      <pubDate>Wed, 21 Dec 2022 19:00:00 +0000</pubDate>
      <link>https://dev.to/gdenn/how-to-use-terraform-variables-1kda</link>
      <guid>https://dev.to/gdenn/how-to-use-terraform-variables-1kda</guid>
      <description>&lt;p&gt;Variables are used to remove hardcoded config values from your Terraform scripts and can be placed in the same file as the script that you are executing or in a dedicated &lt;code&gt;[variables.tf](http://variables.tf)&lt;/code&gt; file (best practice). &lt;/p&gt;

&lt;p&gt;You can provide default values to the variables and override them through the CLI or environment variables if you placed the &lt;code&gt;[variables.tf](http://variables.tf)&lt;/code&gt; in the root module.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;variables.tf&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;You can declare a variable with the &lt;code&gt;variable&lt;/code&gt; block inside a &lt;code&gt;*.tf&lt;/code&gt; script or in a dedicated &lt;code&gt;[variables.tf](http://variables.tf)&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc_cidr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;172.31.0.0/16&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then use the variable in another file within the same module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&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;instance_tenancy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling the &lt;code&gt;terraform plan&lt;/code&gt; command will use the default value of the &lt;code&gt;vpc_cidr&lt;/code&gt; variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="nx"&gt;plan&lt;/span&gt;

&lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="nx"&gt;used&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="nx"&gt;providers&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;generate&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;execution&lt;/span&gt; &lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Resource&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;indicated&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;

&lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;perform&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

  &lt;span class="err"&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="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;arn&lt;/span&gt;                                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;cidr_block&lt;/span&gt;                           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;172.31.0.0/16&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;default_network_acl_id&lt;/span&gt;               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;default_route_table_id&lt;/span&gt;               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;default_security_group_id&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dhcp_options_id&lt;/span&gt;                      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_classiclink&lt;/span&gt;                   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_classiclink_dns_support&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_dns_hostnames&lt;/span&gt;                 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_dns_support&lt;/span&gt;                   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_network_address_usage_metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;                                   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;instance_tenancy&lt;/span&gt;                     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ipv6_association_id&lt;/span&gt;                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ipv6_cidr_block&lt;/span&gt;                      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ipv6_cidr_block_network_border_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;main_route_table_id&lt;/span&gt;                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;owner_id&lt;/span&gt;                             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tags_all&lt;/span&gt;                             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nl"&gt;Plan&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;to&lt;/span&gt; &lt;span class="nx"&gt;add&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&lt;/span&gt; &lt;span class="nx"&gt;change&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&lt;/span&gt; &lt;span class="nx"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Overriding defaults
&lt;/h2&gt;

&lt;p&gt;The value of the variable &lt;code&gt;var.vpc_cidr&lt;/code&gt; can be overwritten with the environment or through the CLI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Override with environment variables
&lt;/h3&gt;

&lt;p&gt;All environment variable overrides need to match the pattern &lt;code&gt;TF_VAR_&amp;lt;var_name&amp;gt;&lt;/code&gt; to override a variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;TF_VAR_vpc_cidr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0/16&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="nx"&gt;plan&lt;/span&gt;       

&lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="nx"&gt;used&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="nx"&gt;providers&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;generate&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;execution&lt;/span&gt; &lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Resource&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;indicated&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;

&lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;perform&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

  &lt;span class="err"&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="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;arn&lt;/span&gt;                                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;cidr_block&lt;/span&gt;                           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0/16&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;default_network_acl_id&lt;/span&gt;               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;default_route_table_id&lt;/span&gt;               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;default_security_group_id&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dhcp_options_id&lt;/span&gt;                      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_classiclink&lt;/span&gt;                   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_classiclink_dns_support&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_dns_hostnames&lt;/span&gt;                 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_dns_support&lt;/span&gt;                   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_network_address_usage_metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;                                   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;instance_tenancy&lt;/span&gt;                     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ipv6_association_id&lt;/span&gt;                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ipv6_cidr_block&lt;/span&gt;                      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ipv6_cidr_block_network_border_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;main_route_table_id&lt;/span&gt;                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;owner_id&lt;/span&gt;                             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tags_all&lt;/span&gt;                             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nl"&gt;Plan&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;to&lt;/span&gt; &lt;span class="nx"&gt;add&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&lt;/span&gt; &lt;span class="nx"&gt;change&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&lt;/span&gt; &lt;span class="nx"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Override with the CLI
&lt;/h3&gt;

&lt;p&gt;Use the &lt;code&gt;-var &amp;lt;var_name&amp;gt;="&amp;lt;value&amp;gt;"&lt;/code&gt; parameter to override a variable with the CLI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="nx"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;vpc_cidr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0/16&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="nx"&gt;used&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="nx"&gt;providers&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;generate&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;execution&lt;/span&gt; &lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Resource&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;indicated&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;

&lt;span class="nx"&gt;Terraform&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;perform&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;following&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

  &lt;span class="err"&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="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;arn&lt;/span&gt;                                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;cidr_block&lt;/span&gt;                           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0/16&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;default_network_acl_id&lt;/span&gt;               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;default_route_table_id&lt;/span&gt;               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;default_security_group_id&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dhcp_options_id&lt;/span&gt;                      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_classiclink&lt;/span&gt;                   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_classiclink_dns_support&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_dns_hostnames&lt;/span&gt;                 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_dns_support&lt;/span&gt;                   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;enable_network_address_usage_metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;                                   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;instance_tenancy&lt;/span&gt;                     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ipv6_association_id&lt;/span&gt;                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ipv6_cidr_block&lt;/span&gt;                      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ipv6_cidr_block_network_border_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;main_route_table_id&lt;/span&gt;                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;owner_id&lt;/span&gt;                             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tags_all&lt;/span&gt;                             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nl"&gt;Plan&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;to&lt;/span&gt; &lt;span class="nx"&gt;add&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&lt;/span&gt; &lt;span class="nx"&gt;change&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&lt;/span&gt; &lt;span class="nx"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>emptystring</category>
    </item>
    <item>
      <title>Use locals with Terraform</title>
      <dc:creator>Dennis Groß (he/him)</dc:creator>
      <pubDate>Tue, 20 Dec 2022 19:00:00 +0000</pubDate>
      <link>https://dev.to/gdenn/use-locals-with-terraform-n73</link>
      <guid>https://dev.to/gdenn/use-locals-with-terraform-n73</guid>
      <description>&lt;p&gt;Locals are like variables another tool to avoid hard coding values in terraform scripts and keep the code DRY.&lt;/p&gt;

&lt;p&gt;The scope of locals is restricted to the current module and can yield&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a hard value like a string, integer etc.&lt;/li&gt;
&lt;li&gt;an expression&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Locals cannot be passed through the CLI or environment and represent a more permanent, constant value or expression in your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Locals
&lt;/h2&gt;

&lt;p&gt;Locals can be defined in the &lt;code&gt;locals&lt;/code&gt; block and used in the same module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;uuidv4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4c67baa1-f139-45c0-85d4-451e615ece9a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-fancy-bucket-${uuidv4}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use Locals With Ternary Operator
&lt;/h3&gt;

&lt;p&gt;Locals can be used together with the Ternary operator to assign a conditional value to a local variable.&lt;/p&gt;

&lt;p&gt;This can be e.g. useful if you want to differentiate the instance count of EC2 instances in a development vs. production environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ec2_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_instance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my_instance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ami-005e54dee72cc1d00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;t2.micro&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2_count&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>terraform</category>
      <category>cloud</category>
      <category>cloudnative</category>
      <category>cloudskills</category>
    </item>
    <item>
      <title>Beginners Guide to EC2</title>
      <dc:creator>Dennis Groß (he/him)</dc:creator>
      <pubDate>Tue, 20 Dec 2022 08:45:29 +0000</pubDate>
      <link>https://dev.to/gdenn/beginners-guide-to-ec2-59fk</link>
      <guid>https://dev.to/gdenn/beginners-guide-to-ec2-59fk</guid>
      <description>&lt;h1&gt;
  
  
  EC2 Instances
&lt;/h1&gt;

&lt;p&gt;The Elastic Compute Cloud (EC2) provides virtual machines on demand. Most of the AWS services are built using the EC2 service in some capacity, which makes EC2 one of the essential services on AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;You can choose from different EC2 instance-type families, the families are specialized into a specific use case like…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;general purpose-balanced - offers an average ratio between CPU, memory, and network resources, used for regular services and applications.&lt;/li&gt;
&lt;li&gt;compute-optimized - focus on CPU resources, used for CPU-intensive operations such as machine learning algorithms.&lt;/li&gt;
&lt;li&gt;memory-optimized - focus on memory, used for services that process a lot of data in memory.&lt;/li&gt;
&lt;li&gt;accelerated computing - provides hardware accelerators, used for example in graphics processing or specific kinds of data processing.&lt;/li&gt;
&lt;li&gt;storage-optimized - focus on high I/O and throughput on attached volumes, used for databases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instances in those families often come in different versions such as T2 and T3. The versions can change different aspects of the instance like…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether CPU credits are used.&lt;/li&gt;
&lt;li&gt;how costs are calculated.&lt;/li&gt;
&lt;li&gt;what CPU architecture gets used.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general, go with the latest version of an instance family, AWS tries to provide the best price/value ratio for the newer versions.&lt;/p&gt;

&lt;p&gt;AWS introduced recently the new Graviton2 processors which you can already find in the newer instance families like T4g or M6g. These processors use an ARM architecture and provide the same CPU resources at a reduced cost [compared to the x86 counterparts]. Try to go with the new Graviton2 processors when you can but keep in mind that your application must support ARM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Virtual Machines
&lt;/h2&gt;

&lt;p&gt;You already read in the intro that EC2 instances are virtual machines, so let me give you a short recap of what virtual machines are. Skip ahead if you are already familiar with the concept of virtualization.&lt;/p&gt;

&lt;p&gt;Virtual machines help you to abstract from concrete hardware like…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPUs&lt;/li&gt;
&lt;li&gt;Memory&lt;/li&gt;
&lt;li&gt;Hard or Network Disks&lt;/li&gt;
&lt;li&gt;Network Resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The base concept behind virtual machines is to use a pool of hardware resources and to create a flexible number of machines with operating systems based on this resource pool. The hardware used by the machines is shared, but the user of the virtual machine would think that this is a fully functional computer.&lt;/p&gt;

&lt;p&gt;Data centers use virtual machines to allocate their hardware resources more flexibly.  A physical computer has a fixed set of CPU, memory, disk, and network resources, but a virtual machine on the other hand can be allocated an arbitrary amount of those system resources. The flexibility of the virtualization concept helps data centers to upsell their hardware resources to customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  EC2 Instance Families
&lt;/h2&gt;

&lt;p&gt;EC2 instances come with a preconfigured set of system resources. AWS categorizes instances by…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;vCPU - essentially CPU threads, modern CPUs support hyper-threading so one physical CPU core [roughly] supports two different threads. You can say one vCPU equals half a physical CPU core.&lt;/li&gt;
&lt;li&gt;Memory&lt;/li&gt;
&lt;li&gt;Storage/Instance Storage - what Storage types can be attached to the EC2 instance, mostly EBS.&lt;/li&gt;
&lt;li&gt;Bandwidth - max network throughput in Gbps that the EC2 instance supports.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;apart from this, there are also a few metrics that apply only to specific EC2 instance families like…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EBS Bandwidth - max network throughput in Gbps to/from attached EBS volumes. A caveat, every EC2 instance has a fixed IOPS limit which can become a bottleneck if you attach multiple EBS volumes.&lt;/li&gt;
&lt;li&gt;CPU Credits - let you perform above your instance vCPU computing capacity for a while until your CPU credits run out. You earn CPU credits when you don’t max out on your instance CPU capabilities. This applies not to all EC2 instances and we tend to call EC2 instances with CPU credits &lt;em&gt;burstable instances&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;EC2 instance families target different application use cases with the baseline being “general purpose”. Most of your applications should use general-purpose instances which offer a good balance between CPU, memory, and network bandwidth.&lt;/p&gt;

&lt;p&gt;Here is an official listing of all &lt;a href="%5Bhttps://aws.amazon.com/ec2/instance-types/%5D(https://aws.amazon.com/ec2/instance-types/)"&gt;instance families by AWS&lt;/a&gt;. I advise you to go with the latest iteration of the instance types which offer you in general a better performance/value proposition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instancy Types
&lt;/h2&gt;

&lt;p&gt;An instance family like T3 offers different instance types like &lt;code&gt;t3.nano&lt;/code&gt; or &lt;code&gt;t3.medium&lt;/code&gt;. We saw already in the blog post that virtual machines consist of system resources that are derived from the hardware resource pool. We also saw why this is a flexible concept, but keep in mind that EC2 instances are virtual machines with a fixed set of system resources.&lt;/p&gt;

&lt;p&gt;You can’t scale the system resources of a running virtual machine. You need to terminate an existing instance and start a new one to up or down-scale system resources.&lt;/p&gt;

&lt;p&gt;AWS provides you with pre-configured EC2 instances and gives them an instance type label. The &lt;code&gt;t3.nano&lt;/code&gt; instance type for example features…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2 vCPUs&lt;/li&gt;
&lt;li&gt;0.5 GiB memory&lt;/li&gt;
&lt;li&gt;CPU credits&lt;/li&gt;
&lt;li&gt;Up to 5 Gbps network transfer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So think about what you want to do with your service or application on EC2. It is a good idea to restrict yourself to the smaller instance types like &lt;code&gt;t3.nano&lt;/code&gt;, &lt;code&gt;t3.micro&lt;/code&gt;, or &lt;code&gt;t3.small&lt;/code&gt; if your application workload runs in a staging or development environment.&lt;/p&gt;

&lt;p&gt;Productive EC2 instances can be larger like the &lt;code&gt;t3.large&lt;/code&gt; instance and may incur significant costs. EC2 uses a pay-as-you-go model, so you pay per second of usage. You only pay for EC2 instances when they are in the running state, stop the instance and you only pay for attached disk volumes like EBS volumes or EFS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Burstable Instances
&lt;/h2&gt;

&lt;p&gt;Some instance types like the &lt;code&gt;t3.*&lt;/code&gt; instances are burstable, which means that they operate with CPU credits. All EC2 instance types have a fixed amount of vCPUs attached which we call the baseline computation performance of the instance.&lt;/p&gt;

&lt;p&gt;Now imagine you run a rather small application on your instance and you decided to go with the &lt;code&gt;t3.small&lt;/code&gt; instance type. That instance type is sufficient for your use case but they are a couple of situations when you would need additional computation power…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;During the booting procedure of the instance.&lt;/li&gt;
&lt;li&gt;On occasional traffic spikes when a lot of people access your application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AWS provides EC2 CPU credits exactly for such use cases. You can think of CPU credits like a savings account in your bank. Your EC2 instance starts with a full savings account filled with CPU credits. You can pay for additional computation resources with these CPU credits whenever your baseline computation power is not enough and you can do that until your CPU credits run out.&lt;/p&gt;

&lt;p&gt;This process happens automatically, EC2 scales your computation performance automatically for the price of some CPU credits when your instance goes through some computation-intensive operations.&lt;/p&gt;

&lt;p&gt;Your instance will save CPU credits into your instance “savings account” when your application is not performing above the baseline performance. There is a fixed rate at which you save CPU credits that depends on the instance family.&lt;/p&gt;

&lt;p&gt;This is a really awesome mechanism and it demonstrates that AWS puts the customer needs in the center when they design/implement their services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instance Lifecycle
&lt;/h2&gt;

&lt;p&gt;An EC2 instance can be in one of 7 different states…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rebooting - restarting the instance while reinitializing the instance.&lt;/li&gt;
&lt;li&gt;pending - currently starting the instance.&lt;/li&gt;
&lt;li&gt;shutting-down - instance termination in progress.&lt;/li&gt;
&lt;li&gt;terminated - instance got removed.&lt;/li&gt;
&lt;li&gt;stopping - preparing to be stopped or hibernated.&lt;/li&gt;
&lt;li&gt;stopped - workloads on the instance are not&lt;/li&gt;
&lt;li&gt;running - workloads are running on the instance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From all of the states above you only pay for…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;running&lt;/li&gt;
&lt;li&gt;stopped - if your instance is in hibernation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of you might be confused that instances can be terminated, stopped, or hibernated. You should…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stop instances if you don’t need to access your workloads on the instance but want to keep the EBS volumes attached [to the instance]. You will only be charged for the EBS volumes and not for the instance computing resources.&lt;/li&gt;
&lt;li&gt;terminate instances if you want to remove the instance permanently, this will also delete all EBS volumes that specify the &lt;code&gt;delete_on_termination&lt;/code&gt; flag.&lt;/li&gt;
&lt;li&gt;hibernate instances if you want to stop the instance workloads but you have in-memory data stored on the instance that you don’t want to lose by stopping the instance. EC2 will take a snapshot of your instance memory before hibernation and restores the snapshot when you start the instance again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also want to make you familiar with a small technicality when it comes to starting/stopping instances. Stopping and then starting an instance is not the same as restarting an instance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stopping an instance followed by a start of the instance keeps the identical instance VM.&lt;/li&gt;
&lt;li&gt;Restarting an instance may change the instance VM.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s a technical detail and for most of you, it won’t matter whether it is the same VM or not.&lt;/p&gt;

&lt;p&gt;EC2 is a zonal service which means that instances are deployed into a specific availability zone. You have to keep in mind that the servers that host your EC2 instances are located in a data center of a specific availability zone. The same is true for EBS volumes. This is the reason why you can only attach EBS volumes to EC2 instances of the same availability zone.&lt;/p&gt;

&lt;p&gt;Restarting the EC2 instance might result in another instance from the same availability zone. This is not a problem in 99% of the cases but it becomes an issue when you work with software licenses or communicate directly with the IPv4 addresses of your instance (use CNAMES wherever possible!).&lt;/p&gt;

&lt;h2&gt;
  
  
  Boot Volume
&lt;/h2&gt;

&lt;p&gt;Every EC2 instance needs a boot volume to install the operating system. In most cases, this boot volume is an attached EBS volume that sets the &lt;code&gt;delete_on_termination&lt;/code&gt; . The flag indicates if the EBS volumes get destroyed when you terminate the EC2 instance.&lt;/p&gt;

&lt;p&gt;In general, we call EBS volumes that…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;terminate with the EC2 instance ephemeral volumes.&lt;/li&gt;
&lt;li&gt;do not terminate with the EC2 instance volumes persistent volumes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I encourage you to use managed data services such as DocumentDB, DynamoDB, or RDS for persistent application data. But there are always exceptions to that equation and you might end up requiring a persistent volume for your application data. Make sure that your EBS volume is &lt;code&gt;delete_on_termination=false&lt;/code&gt; if you want to use it for persistent data, and schedule backups for this volume.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attaching EBS Volumes
&lt;/h2&gt;

&lt;p&gt;EBS volumes other than the boot volume get attached as raw block storage to your EC2 instance so you need to…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;format the block storage with a file system like ext4.&lt;/li&gt;
&lt;li&gt;create a folder on your operating system that you use as a mount target.&lt;/li&gt;
&lt;li&gt;mount the formatted volume to the folder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t have to ssh into new EC2 instances for this, you can automate the procedure with the EC2 User Data script.&lt;/p&gt;

&lt;p&gt;EBS volumes can only be attached to a single EC2 instance (except for io2) and the instance must be from the same region and availability zone. &lt;/p&gt;

&lt;p&gt;You still can transfer your EBS volume data to an EC2 instance in another region/availability zone…&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a snapshot of the EBS volume.&lt;/li&gt;
&lt;li&gt;Copy the snapshot to the other region/availability zone.&lt;/li&gt;
&lt;li&gt;Create an EBS volume from the snapshot copy in that region/availability zone.&lt;/li&gt;
&lt;li&gt;Attach the new EBS volume to the EC2 instance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You need to take an unencrypted snapshot if you want to transfer the snapshot copy to another region. EBS uses the KMS service to encrypt EBS data at rest and KMS keys are a regional construct, so you can’t easily transfer encrypted data cross-region (at least you won’t be able to decrypt it).&lt;/p&gt;

&lt;p&gt;A lot of people are frustrated about such details but this is a great effort by AWS to keep the data integrity of regions.&lt;/p&gt;

&lt;h2&gt;
  
  
  EFS
&lt;/h2&gt;

&lt;p&gt;The Elastics File System (EFS) offers distributed network file systems that you can attach to EC2 (and other services) which is much easier to work with than EBS. As the name suggests, EFS comes with a network file system that is compliant with the NFS protocol installed so you don’t have to mount/format raw block storage.&lt;/p&gt;

&lt;p&gt;But EFS has a premium price compared to EBS. The biggest selling point of EFS is that you can attach it to multiple EC2 instances even cross-az, so you should use those network file systems whenever you work with distributed data….&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when you have multiple EC2 instances that need to access the same persistent data source.&lt;/li&gt;
&lt;li&gt;when you use high-performance computing operations based on a shared data set.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  User Data
&lt;/h2&gt;

&lt;p&gt;Some of you might have worked already with configuration management tools like Ansible which in essence do the same thing as the EC2 User Data script.&lt;/p&gt;

&lt;p&gt;You can pass in a set of shell instructions to the User Data script attribute of an EC2 instance. These instructions will be executed upon the initial boot phase of the EC2 instance, so only once. Restarting an instance won’t trigger the User Data script again, only terminating the instance and bootstrapping a new instance would trigger it again (or a reboot).&lt;/p&gt;

&lt;p&gt;Use the User Data script to automate…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the installation of system dependencies.&lt;/li&gt;
&lt;li&gt;installation and start of the software application or service that you run on your instance.&lt;/li&gt;
&lt;li&gt;the formatting and mounting of EBS volumes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think you should always strive for full automation, so try to automate any installation, configuration or application start that you need to do in your EC2 instance through the User Data script.&lt;/p&gt;

&lt;h2&gt;
  
  
  AMIs and Golden AMIs
&lt;/h2&gt;

&lt;p&gt;Amazon Machine Images (AMIs) contain the operating system and a set of pre-configurations that EC2 instances use as a baseline. Any additional configuration on top of the AMI will typically be met by the User Data script.&lt;/p&gt;

&lt;p&gt;Amazon offers you a set of bare-bones Linux and windows AMIs that you can use, the most important are…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="%5Bhttps://aws.amazon.com/marketplace/pp/prodview-zc4x2k7vt6rpu%5D(https://aws.amazon.com/marketplace/pp/prodview-zc4x2k7vt6rpu)"&gt;Amazon Linux 2 AMI (HVM)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="%5Bhttps://aws.amazon.com/windows/resources/amis/%5D(https://aws.amazon.com/windows/resources/amis/)"&gt;Windows AMIs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hosting world relies mostly on Linux software and operating systems, so I go 99% of the time with the Amazon Linux 2 HVM AMI which is based on a Red Hat Enterprise Linux (RHEL).&lt;/p&gt;

&lt;p&gt;Use Windows if you need to work with .NET or proprietary software from Microsoft.&lt;/p&gt;

&lt;p&gt;The best thing about AMIs is that you can create your own AMIs. Here is the process for creating a new AMI.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configure an EC2 instance using a base AMI e.g. Amazon Linux 2.&lt;/li&gt;
&lt;li&gt;Start the instance.&lt;/li&gt;
&lt;li&gt;Right-click on the instance, “create AMI”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Basically, you create a new AMI based on a running EC2 instance.&lt;/p&gt;

&lt;p&gt;AMIs are a regional construct, which means that any AMI that you create from a running EC2 instance will be stored in the region in which the EC2 instance runs. You can copy your AMI to another region which will result in another AMI with another AMI ID.&lt;/p&gt;

&lt;p&gt;This becomes very relevant when you use IaC tools like CloudFormation or Terraform.&lt;/p&gt;

&lt;p&gt;I recommend you…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a RegionMap in CloudFormation for your AMIs.&lt;/li&gt;
&lt;li&gt;use the Data directive in Terraform to filter for a specific AMI in your region by name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AMIs that contains everything you need to run your application is also called “Golden AMIs”. You should try to create golden AMIs for your EC2 application wherever possible, they reduce the CPU overhead that you incur in the bootstrapping process of your EC2 instances since you use a preconfigured snapshot of an EC2 instance.&lt;/p&gt;

&lt;p&gt;There are a couple of ways to build EC2 AMIs automatically…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;with the EC2 Image Builder service.&lt;/li&gt;
&lt;li&gt;with the Hashicorp Packer tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I go with Packer here. It is easier to write a CI/CD process that creates new golden AMIs with Packer than the EC2 Image Builder but that is only my personal impression.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSH into EC2 via Session Manager
&lt;/h2&gt;

&lt;p&gt;Having SSH access to EC2 instances can be really useful to try out new configurations before you place them in the User Data script, or to debug an existing configuration.&lt;/p&gt;

&lt;p&gt;You could SSH into an EC2 instance with the EC2 Keypair, but the instance must be deployed in a public subnet (a subnet with a direct route to an Internet Gateway) and you must open port 22 for ingress through a security group.&lt;/p&gt;

&lt;p&gt;This poses a serious security risk for most EC2 instances, and you should always try to restrict access to instances as much as you can.&lt;/p&gt;

&lt;p&gt;If not absolutely necessary, you should try to…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;put EC2 instances in private subnets.&lt;/li&gt;
&lt;li&gt;restrict access through security groups, especially port 22.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AWS provides a tool called Session Manager that lets you SSH into an EC2 instance through a Cloud Shell. You don’t need to open a port in the security groups for this or deploy the instance in a public subnet. You don’t even need to have access to a specific Keypair.&lt;/p&gt;

&lt;p&gt;There are only two requirements for the Session Manager to work…&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="%5Bhttps://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-manual-agent-install.html%5D(https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-manual-agent-install.html)"&gt;Install the SSM agent&lt;/a&gt; on your EC2 instance. I recommend you do this through the User Data Script.&lt;/li&gt;
&lt;li&gt;Provide the EC2 instance with the managed policy &lt;code&gt;"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"&lt;/code&gt; to communicate with the Systems Session Manager. You can attach this managed AWS policy to your EC2 instance profile role.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can access the instance now from the AWS console, navigate to the EC2 service, find your instance, right-click, and click on “connect”. You will be redirected to a dialog window, the second tray says “AWS Session Manager”.&lt;/p&gt;

&lt;p&gt;You will see a description of how you need to set up the Session Manager on your instance if your instance is not configured properly.&lt;/p&gt;

&lt;p&gt;I install the SSM agent on all of my EC2 instances, and I use the Systems Manager exclusively for accessing my Instances via SSH. As a short recap, the System Manager…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Offers SSH access to instances that are deployed in private subnets.&lt;/li&gt;
&lt;li&gt;Logs SSH instance access in Cloud Trail, with user ID.&lt;/li&gt;
&lt;li&gt;Requires no SSH Keypair on the instance.&lt;/li&gt;
&lt;li&gt;Makes it easy to define who can access the instance based on IAM policies rather than SSH Keypairs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Launch Templates
&lt;/h2&gt;

&lt;p&gt;In DevOps there is a simple equation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code + Configuration = Software Release&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In an ideal world, you are able to create an immutable code and configuration version. So, you attach a specific code and configuration combination to a semantic version and make sure that this version corresponds always to the same config and code (immutability). &lt;/p&gt;

&lt;p&gt;This is very important and ensures that software releases that you tested on a staging environment operate in the same way on a productive system.&lt;/p&gt;

&lt;p&gt;This should apply to software running on EC2 instances too!&lt;/p&gt;

&lt;p&gt;We can use golden AMIs to fix the software and dependencies running on the EC2 instance but you can still apply variable configuration for…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instance type &amp;amp; Instance family&lt;/li&gt;
&lt;li&gt;Allocated EBS volume&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="%5Bhttps://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html%5D(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html)"&gt;Launch Templates&lt;/a&gt; solve this issue and create a fixed software release for EC2 instances by assigning a version number to a template with an immutable set of configurations.&lt;/p&gt;

&lt;p&gt;You can create a Launch Template from…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An existing EC2 instance - right-click on the instance in the EC2 console and click “Create Launch template”.&lt;/li&gt;
&lt;li&gt;Create a new Launch Template from the EC2 instance console.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I think that was a lot of information to digest, but I always try to understand the technologies and their limitations that I am working with. But we are not done with EC2, there is still a lot you should know if you want to operate EC2 instances successfully and cost-efficient. &lt;/p&gt;

&lt;p&gt;I’ll turn this post into a series and add more content.&lt;/p&gt;

&lt;p&gt;But first, let’s have a short recap of the most important things we learned.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EC2 instances have different instance families and instance types. An instance family is always geared to a specific use case such as “general purpose” or “memory-optimized”, the instance type on the other hand just defines the scale of the computing resources.&lt;/li&gt;
&lt;li&gt;There are 7 different lifecycle states of an EC2 instance. You pay only for running instances and partially for stopped instances in hibernation mode.&lt;/li&gt;
&lt;li&gt;EC2 is a zonal service, instances are deployed into a specific availability zone and you can only attach EBS volumes of the same zone.&lt;/li&gt;
&lt;li&gt;AMIs contain the operating system and initial configuration to start your EC2 instance. You can create Golden AMIs that contain your application and all dependencies that you need to run the application on EC2.&lt;/li&gt;
&lt;li&gt;Launch Templates create an immutable software release on EC2 and consist of a fixed configuration and AMI.&lt;/li&gt;
&lt;li&gt;You should use the Session Manager to SSH into instances.&lt;/li&gt;
&lt;li&gt;Startup sequences or the installation of dependencies can be automated with the EC2 User Data script.&lt;/li&gt;
&lt;li&gt;Some instance families are burstable, which means they offer CPU credits that you can use to temporarily boost your instance's computing performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>ec2</category>
      <category>cloud</category>
      <category>cloudskills</category>
    </item>
    <item>
      <title>How to configure Provider in Terraform</title>
      <dc:creator>Dennis Groß (he/him)</dc:creator>
      <pubDate>Mon, 19 Dec 2022 19:00:00 +0000</pubDate>
      <link>https://dev.to/gdenn/how-to-configure-provider-in-terraform-3i09</link>
      <guid>https://dev.to/gdenn/how-to-configure-provider-in-terraform-3i09</guid>
      <description>&lt;p&gt;Terraform is a multi-cloud viable IaC technology and breaks the functionality to communicate with specific cloud provider APIs (SaaS providers or other APIs) down to providers.&lt;/p&gt;

&lt;p&gt;A provider is a logic module that you use to interact with a specific cloud provider like AWS.&lt;/p&gt;

&lt;p&gt;Terraform providers can be categorized into community-driven providers and those providers maintained by the Hashicorp team directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Specifying a Provider
&lt;/h2&gt;

&lt;p&gt;A provider must be specified in the root module of a Terraform project. &lt;/p&gt;

&lt;p&gt;It is a best practice to define the provider in a &lt;code&gt;[providers.tf](http://providers.tf)&lt;/code&gt; separate from the actual IaC scripts in the root module. This makes it easier to locate the provider configuration in a Terraform project.&lt;/p&gt;

&lt;p&gt;But it is theoretically possible to place a provider configuration in one of the Terraform scripts of the root module.&lt;/p&gt;

&lt;p&gt;It is a best practice to expose credentials and configuration values through variables in the provider configuration, so you don’t have to hard code any values or potentially commit them to Github.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Provider
&lt;/h3&gt;

&lt;p&gt;The AWS provider can be configured with a profile or direct technical user credentials through the &lt;code&gt;AWS_SECRET_KEY&lt;/code&gt; and &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;The provider requires basically two things&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your &lt;code&gt;region&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;credentials for your AWS account (technical IAM user)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Specify Credentials through AWS Profile
&lt;/h3&gt;

&lt;p&gt;Providing the credentials through the &lt;code&gt;~/.aws/credentials&lt;/code&gt; file that stores one or multiple access and secret access keys for AWS profiles is a good practice. You may change the profile in the future or rotate the AWS credentials of the technical users which has an immediate effect on the provider.&lt;/p&gt;

&lt;p&gt;This has also the added benefit that you don’t have any hard credential values in your code files.&lt;/p&gt;

&lt;p&gt;The Terraform provider config will assume that your AWS credentials file is on path &lt;code&gt;~/.aws/credentials&lt;/code&gt; by default, but you can specify a custom path with &lt;code&gt;shared_credentials_file&lt;/code&gt; .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hashicorp/aws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4.41.0&lt;/span&gt;&lt;span class="dl"&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;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.region}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.profile}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Specify Credentials directly
&lt;/h3&gt;

&lt;p&gt;You can specify an AWS IAM user directly in the provider configuration through the &lt;code&gt;access_key&lt;/code&gt; and &lt;code&gt;secret_key&lt;/code&gt; parameters.&lt;/p&gt;

&lt;p&gt;Do not hard-code any secrets into the provider config in this case and make sure you use environment variables and declare variables (without default value) for these credentials.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hashicorp/aws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4.41.0&lt;/span&gt;&lt;span class="dl"&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;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.region}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;access_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.access_key}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;secret_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.secret_key}&lt;/span&gt;&lt;span class="dl"&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 variables in this case can be defined through&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the CLI: &lt;code&gt;-var access_key="..." -var secret_key=".."&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;environment variables: &lt;code&gt;export TF_VAR_access_key="..."; export TF_VAR_secret_key="..."&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>terraform</category>
      <category>cloud</category>
      <category>cloudnative</category>
      <category>cloudskills</category>
    </item>
    <item>
      <title>AWS Best Practices: Three Tier VPC</title>
      <dc:creator>Dennis Groß (he/him)</dc:creator>
      <pubDate>Sun, 18 Dec 2022 19:08:59 +0000</pubDate>
      <link>https://dev.to/gdenn/aws-best-practices-three-tier-vpc-37n0</link>
      <guid>https://dev.to/gdenn/aws-best-practices-three-tier-vpc-37n0</guid>
      <description>&lt;p&gt;The Three Tier VPC is an AWS best practice provides strong network security principles.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Here is the Terraform source code for the VPC that we create in this post &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/gdenn/aws-terraform-examples/tree/master/modules/vpc" rel="noopener noreferrer"&gt;aws-terraform-examples/modules/vpc at master · gdenn/aws-terraform-examples&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Three Tier VPC consists of three different subnet types&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Subnet - public subnet, assigns public ipv4 addresses to resources in this subnet directly through the Internet Gateway&lt;/li&gt;
&lt;li&gt;Computing Subnet - private subnet, cannot be reached from the outside since there is no direct route to the Internet Gateway. This subnet can reach resources from the internet through a Nat Gateway route to the Internet Gateway.&lt;/li&gt;
&lt;li&gt;Data Subnet - private isolated subnet, resources in this subnet cannot be reached from the internet and the resources themselves cannot reach out to the internet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general use the&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Subnet for public resources such as Application Load Balancers, frontend Applications, or Lambda functions that you want to make directly accessible from the internet.&lt;/li&gt;
&lt;li&gt;Computing Subnet for backing services such as private APIs or frontend applications that you expose through an Application Load Balancer.&lt;/li&gt;
&lt;li&gt;Data Subnet for data services and data processing or anything that does not must communicate with external resources on the internet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create the VPC
&lt;/h2&gt;

&lt;p&gt;You can create a VPC with the Terraform &lt;code&gt;aws_vpc&lt;/code&gt; resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt;           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr&lt;/span&gt;
  &lt;span class="nx"&gt;instance_tenancy&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;enable_dns_support&lt;/span&gt;   &lt;span class="o"&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="o"&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="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&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;Environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things are important here&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;instance_tenancy&lt;/em&gt; defines where VPC resources will be placed and should be set to &lt;code&gt;"default"&lt;/code&gt;.  There is also the &lt;code&gt;"dedicated"&lt;/code&gt; option which in the case of EC2 instances will use dedicated instances. Keep this on &lt;code&gt;"default"&lt;/code&gt; unless you have a clear use case for &lt;code&gt;"dedicated"&lt;/code&gt;, otherwise this might cost you a small fortune.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;enable_dns_hostnames&lt;/em&gt; determines whether your resources will receive CNAMEs from the AWS DNS service, leave this on by default. It makes sense to use CNAMEs instead of hardcoded IPs wherever possible.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;enable_dns_support&lt;/em&gt; defines whether your VPC resources are supported by the AWS DNS, you should leave this on as well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can see that we are using a bunch of variables in this VPC resource. Here is a complete snippet of the &lt;code&gt;[variables.tf](http://variables.tf)&lt;/code&gt; content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;environment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;environment type (staging/prod/sdlc)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cidr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc cidr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10.0.0.0/16&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cidr_offset&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;offset that we pass to the cidrsubnet function to build subnets&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;log_group_name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc-flow-logs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;region&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-central-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc_name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;availability_zones&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list of availability zones&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-central-1a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-central-1b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-central-1c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every VPC requires you to define a CIDR range which can be a &lt;code&gt;/16&lt;/code&gt; (largest) subnet or a &lt;code&gt;/28&lt;/code&gt; subnet (smallest).  The size of your VPC highly depends on the number of resources you want to deploy into it. &lt;/p&gt;

&lt;p&gt;Keep in mind that a couple of IPs in each VPC are reserved. Personally, I try to anticipate what I want to do with the VPC in the future. You might deploy some extra resources in 1-2 years, so choose a larger subnet than you need now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable VPC Flow Logs
&lt;/h2&gt;

&lt;p&gt;Flow logs contain top-level meta information of Layer 4 (IP Layer) packages that are transferred in the VPC, it is in general a good practice to enable them and drain them to a CloudWatch Log Group.&lt;/p&gt;

&lt;p&gt;They can help you to…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;analyze attack vectors when your network got compromised.&lt;/li&gt;
&lt;li&gt;debug security group issues with resources.&lt;/li&gt;
&lt;li&gt;are useful for intrusion detection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is how you activate the VPC Flow Logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_flow_log&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc_flow_logs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;iam_role_arn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flow_logs_role&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;log_destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_cloudwatch_log_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_log_group&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;traffic_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ALL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="o"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to create (or reuse an existing) Cloud Watch Log Group. I like to have one Log Group per application stack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_cloudwatch_log_group&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc_log_group&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log_group_name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And an IAM role that gives the VPC permission to push Flow Logs into the Cloud Watch Log Group.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_iam_role&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flow_logs_role&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flow-logs-role&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

  &lt;span class="nx"&gt;assume_role_policy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2012-10-17&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;Statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;Effect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Allow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;Principal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;Service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc-flow-logs.amazonaws.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;Action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sts:AssumeRole&lt;/span&gt;&lt;span class="dl"&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;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_iam_role_policy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;create_log_group_policy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;allow-log-group-policy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flow_logs_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;

  &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2012-10-17&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;Statement&lt;/span&gt; &lt;span class="o"&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;Action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logs:CreateLogGroup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logs:CreateLogStream&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logs:PutLogEvents&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logs:DescribeLogStreams&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="nx"&gt;Effect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Allow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;Resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&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;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;
  
  
  Public &lt;em&gt;Web Subnet&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Resources in the Web Subnet receive static IPv4 addresses and require a direct route to the Internet Gateway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_internet_gateway&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main_igw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="o"&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;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.vpc_name}-igw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Internet Gateway is hosted by AWS in the public zone and is a region resilient service. You don’t have to provide multiple instances of the Internet Gateway to ensure high availability, AWS ensures that there is a sufficient amount of Internet Gateways deployed in your region in case of a failure.&lt;/p&gt;

&lt;p&gt;And that’s sufficient since VPCs are regional constructs which means your blast radius with a VPC is at most a region (if you use multiple availability zones for your subnets).&lt;/p&gt;

&lt;p&gt;The next thing that we need is a Route Table that routes directly to the Internet Gateway that we provisioned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_route_table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public_subnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="o"&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;route&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0/0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;gateway_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_internet_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main_igw&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also add a few locals before we start with the Web Subnet itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;azs_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&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;computing_offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azs_count&lt;/span&gt;
  &lt;span class="nx"&gt;data_offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azs_count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always keep your code DRY and use locals to &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid code redundancies&lt;/li&gt;
&lt;li&gt;Assign complex expressions to local variables with proper names&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We create the Web Subnet with the &lt;code&gt;aws_subnet&lt;/code&gt; resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_subnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subnet_web&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;                  &lt;span class="o"&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;map_public_ip_on_launch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="nx"&gt;count&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azs_count&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cidrsubnet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr_offset&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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&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;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.vpc_name}-subnet-web&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Terraform &lt;code&gt;count&lt;/code&gt; operator creates a subnet for each availability zone that we configured in the variables file. Provide a non-overlapping CIDR range for each subnet that you deploy into an availability zone.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://developer.hashicorp.com/terraform/language/functions/cidrsubnet" rel="noopener noreferrer"&gt;cidrsubnet&lt;/a&gt; function from Terraform computes our VPC CIDR for our subnets which makes it obsolete to pass additional subnet CIDR ranges through variables. &lt;/p&gt;

&lt;h2&gt;
  
  
  Computing Subnet
&lt;/h2&gt;

&lt;p&gt;The next subnet is the Computing Subnet. The subnet is private, resources in the subnet receive no static IPv4 address and are not reachable from the internet. But the resources can communicate with servers that are on the internet. &lt;/p&gt;

&lt;p&gt;The subnet is a great fit for internal APIs or resources that you expose through an Application Load Balancer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_subnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subnet_computing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;                  &lt;span class="o"&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;map_public_ip_on_launch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="nx"&gt;count&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azs_count&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cidrsubnet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr_offset&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="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;computing_offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;availability_zone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&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;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.vpc_name}-subnet-computing-${count.index}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we set the &lt;code&gt;map_public_ip_on_launch&lt;/code&gt; to false, this option only makes sense if you route directly to an Internet Gateway which is not the case with the computing subnet.&lt;/p&gt;

&lt;p&gt;The next thing that we need is a NAT Gateway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_eip&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nat_eip&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_internet_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main_igw&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_count&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_nat_gateway&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;natgw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_count&lt;/span&gt;
  &lt;span class="nx"&gt;allocation_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nat_eip&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;id&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_web&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;id&lt;/span&gt;
  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_internet_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main_igw&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;natgw-${count.index}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Route Table of the Computing subnet routes requests from resources to the internet through the NAT Gateway and from there to the Internet Gateway.&lt;/p&gt;

&lt;p&gt;The NAT Gateway requires a static public IPv4 address which we provide through an Elastic IP (eip). The NAT Gateway does a Port Address Translation (PAT), and resources that communicate to the internet use the NAT Gateway’s public IPv4 address. The NAT Gateway assigns each requesting resource from within the subnet a port.&lt;/p&gt;

&lt;p&gt;Resources are not always reachable from the same port, that’s the reason why you can’t request them from the internet.&lt;/p&gt;

&lt;p&gt;We need to create a Routing Table, a Route, and a Route Table Association for each subnet to finish the computing subnet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_route&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;private_subnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_count&lt;/span&gt;
  &lt;span class="nx"&gt;route_table_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_route_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet&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;id&lt;/span&gt;
  &lt;span class="nx"&gt;destination_cidr_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0/0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;nat_gateway_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_nat_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;natgw&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;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_route_table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;private_subnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_count&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="o"&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;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.vpc_name}-private-subnet-route-table-${count.index}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&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="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_route_table_association&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subnet_computing_route_table_association&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azs_count&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_id&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_computing&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;id&lt;/span&gt;
  &lt;span class="nx"&gt;route_table_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_route_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet&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;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Data Subnet
&lt;/h2&gt;

&lt;p&gt;The last subnet is the Data subnet. Resources in this subnet cannot communicate to the internet and are not reachable from within the internet.&lt;/p&gt;

&lt;p&gt;That makes it a perfect fit for data services or services that perform data processing, or in general everything that doesn’t have to communicate to the internet.&lt;/p&gt;

&lt;p&gt;Putting your data services into a private, isolated subnet is a security best practice. An attacker that compromises your data service cannot offload data to a malicious server from within the VPC subnet.&lt;/p&gt;

&lt;p&gt;We start with the subnet resource again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_subnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subnet_data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;                  &lt;span class="o"&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;map_public_ip_on_launch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="nx"&gt;count&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azs_count&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cidrsubnet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr_offset&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="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data_offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;availability_zone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&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;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.vpc_name}-subnet-data-${count.index}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This subnet does not need a route to the NAT Gateway or Internet Gateway but it is still necessary to provide a Route Table and Route Table Associations for each subnet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_route_table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;private_isolated_subnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="o"&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;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.vpc_name}-private-isolated-subnet-route-table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&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="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_route_table_association&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subnet_data_route_table_association&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azs_count&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_id&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_data&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;id&lt;/span&gt;
  &lt;span class="nx"&gt;route_table_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_route_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_isolated_subnet&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Productive VPC Usage
&lt;/h2&gt;

&lt;p&gt;There are a couple of things that you should do when you create a VPC for productive use&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you have one NAT Gateway &lt;em&gt;per availability zone.&lt;/em&gt; NAT Gateway instances will be deployed into your Web subnet, thus they are not a fully-managed solution like the Internet Gateway and you need to make sure that you have multiple instances of them (HA).&lt;/li&gt;
&lt;li&gt;Enable VPC Flow Logs and drain them to Cloud Watch.&lt;/li&gt;
&lt;li&gt;Use multiple availability zones (at least 3) for your VPC so resources in your VPC can be deployed into multiple zones.&lt;/li&gt;
&lt;li&gt;Be a bit more generous with your VPC CIDR range, it is quite tedious to find out that you're VPC is not sufficiently sized. Moving productive resources is quite challenging and VPC peering is also not a walk in the park. So think ahead in regards to your VPC size&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The VPC stack from this post has everything that you need for productive use, just make sure that you configure three availability zones in the variable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerations for non-productive Use
&lt;/h2&gt;

&lt;p&gt;There are also a few things that you should be aware of when you use this VPC architecture for non-productive use, mostly in regard to cost-efficiency.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use at least two availability zones even for non-productive use. Resources like the Application Load Balancer require at least two availability zones to be deployed, regardless of whether it is for productive or non-productive use.&lt;/li&gt;
&lt;li&gt;Deploy only one NAT Gateway and associate the NAT Gateway with all Computing subnet Route Tables. NAT Gateway cost you per second that they run and additionally for traffic that it transfers so it is a good idea to limit the amount of NAT Gateway for non-productive use.&lt;/li&gt;
&lt;li&gt;Keep in mind that AWS charges you for cross-availability-zone transfer of network data (except for managed solutions). Try to keep your resources deployed in the same AZ so they don’t incur costs for cross-az communication.&lt;/li&gt;
&lt;li&gt;Tag your VPC with the environment tag so operators are never in doubt if the VPC is used for productive or non-productive use (the best practice is still to separate via accounts).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Every AWS cloud engineer should be comfortable with the configuration of a VPC and should know the core components involved.&lt;/p&gt;

&lt;p&gt;You will use VPCs for a large percentile of AWS services and misconfiguring it can cause you a lot of trouble in the long run, so take your time and try to understand all components that we used in this post.&lt;/p&gt;

&lt;p&gt;Here is a short recap of the things that we learned in this post&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Subnet - public subnet for public reachable resources such as load balancers or internet-facing APIs and frontend applications.&lt;/li&gt;
&lt;li&gt;Computing Subnet - private subnet for resources that need to communicate to the internet but should not be reachable from the internet.&lt;/li&gt;
&lt;li&gt;Data Subnet - private, isolated subnet for data services and data processing.&lt;/li&gt;
&lt;li&gt;Internet Gateway - provides static, public IPv4 addresses to resources.&lt;/li&gt;
&lt;li&gt;NAT Gateway - uses Port Address Translation, routes to the Internet Gateway, and makes sure that resources can communicate to the internet but are not reachable from the internet.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>How to use templates in Terraform</title>
      <dc:creator>Dennis Groß (he/him)</dc:creator>
      <pubDate>Sun, 18 Dec 2022 14:45:34 +0000</pubDate>
      <link>https://dev.to/gdenn/how-to-use-templates-in-terraform-14ni</link>
      <guid>https://dev.to/gdenn/how-to-use-templates-in-terraform-14ni</guid>
      <description>&lt;p&gt;Terraform has a &lt;code&gt;templatefile(path, vars)&lt;/code&gt; function that can be used to render the content of a file into a string with variable substitution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Variable Substitution
&lt;/h2&gt;

&lt;p&gt;The variable substitution has an interpolation syntax using &lt;code&gt;${..}&lt;/code&gt; . So you can reference variables that you passed into the second map argument of the &lt;code&gt;templatefile&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_instance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web_server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="o"&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_ami&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amzn2&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;instance_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&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;user_data&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;templatefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-data.sh&lt;/span&gt;&lt;span class="dl"&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above renders a shell script as a string without substituting any template variables.&lt;/p&gt;

&lt;p&gt;The recommended file format is &lt;code&gt;*.tftpl&lt;/code&gt; but the function does not enforce it.&lt;/p&gt;

&lt;p&gt;We can pass additional variables from the terraform script to the user data example above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_instance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web_server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="o"&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_ami&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amzn2&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;instance_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&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;user_data&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;templatefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-data.sh&lt;/span&gt;&lt;span class="dl"&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;log_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test-server&lt;/span&gt;&lt;span class="dl"&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;span class="nx"&gt;sudo&lt;/span&gt; &lt;span class="nx"&gt;chown&lt;/span&gt; &lt;span class="nx"&gt;$USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;$USER&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt; &lt;span class="nx"&gt;$cw_agent_config_folder&lt;/span&gt;
&lt;span class="nx"&gt;sudo&lt;/span&gt; &lt;span class="nx"&gt;mkdir&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;$cw_agent_config_folder&lt;/span&gt;
&lt;span class="nx"&gt;sudo&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EOT&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;$cw_agent_config_path&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;agent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;metrics_collection_interval&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$cw_agent_collection_interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;run_as_user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logs_collected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;files&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;collect_list&lt;/span&gt;&lt;span class="dl"&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;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file_path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$http_access_logs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;log_group_name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${log_group}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;log_stream_name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{instance_id}-access-logs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;retention_in_days&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$cw_agent_log_retention&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;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;EOT&lt;/span&gt;
&lt;span class="nx"&gt;sudo&lt;/span&gt; &lt;span class="nx"&gt;$cw_agent_ctl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;$cw_agent_config_path&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example above shows how you can work both with shell variables and template variables at the same time since the syntax that you use to reference them differs.&lt;/p&gt;

&lt;h2&gt;
  
  
  For Loop - Lists
&lt;/h2&gt;

&lt;p&gt;Templates can also be used to dry up repeating sections.&lt;/p&gt;

&lt;p&gt;This snippet prints “hello world” in 4 different variations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_instance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web_server&lt;/span&gt;&lt;span class="dl"&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;user_data&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;templatefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello-world.tfpl&lt;/span&gt;&lt;span class="dl"&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;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;planet&lt;/span&gt;&lt;span class="dl"&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;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 jsx"&gt;&lt;code&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;names&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello ${name}
%{ endfor ~}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The snippets above render the &lt;code&gt;hello-world.tfpl&lt;/code&gt; into a string that contains to &lt;code&gt;echo&lt;/code&gt; statements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello world&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello planet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is important that we add a shebang into the shell script if we do not use the &lt;code&gt;*.sh&lt;/code&gt; file ending (or comparable) but the &lt;code&gt;*.tfpl&lt;/code&gt; file ending instead. The shebang instructs the script caller which binary must be invoked for the script execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  For Loop - Maps
&lt;/h2&gt;

&lt;p&gt;We can also loop through maps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_instance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web_server&lt;/span&gt;&lt;span class="dl"&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;user_data&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;templatefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello-world.tfpl&lt;/span&gt;&lt;span class="dl"&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;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firstname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Max&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lastname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fischer&lt;/span&gt;&lt;span class="dl"&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;config_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config_value&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;names&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello to ${config_key}: ${config_value}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Results of this output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello to firstname Max&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello to lastname Fischer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>nvidia</category>
      <category>blogging</category>
      <category>hardware</category>
    </item>
    <item>
      <title>How to use count in Terraform</title>
      <dc:creator>Dennis Groß (he/him)</dc:creator>
      <pubDate>Sun, 18 Dec 2022 14:44:30 +0000</pubDate>
      <link>https://dev.to/gdenn/how-to-use-count-in-terraform-38jc</link>
      <guid>https://dev.to/gdenn/how-to-use-count-in-terraform-38jc</guid>
      <description>&lt;p&gt;The count meta argument is an alternative to &lt;code&gt;for_each&lt;/code&gt; and applies a resource multiple times.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_route&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;private_subnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_count&lt;/span&gt;
  &lt;span class="nx"&gt;route_table_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_route_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet&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;destination_cidr_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0/0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;nat_gateway_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_nat_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;natgw&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;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The snippet above uses the &lt;code&gt;count&lt;/code&gt; meta arg to create multiple private subnets. You need to provide an integer value to the &lt;code&gt;count&lt;/code&gt; argument and the resource will be applied according to the value that you choose.&lt;/p&gt;

&lt;p&gt;You can combine the &lt;code&gt;count&lt;/code&gt; with the &lt;code&gt;length(..)&lt;/code&gt; function to get the amount of elements from a list and apply the same amount of resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_route&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;private_subnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&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;route_table_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_route_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet&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;destination_cidr_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0/0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;nat_gateway_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_nat_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;natgw&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;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This also works with maps when you use the &lt;code&gt;length(..)&lt;/code&gt; function on &lt;code&gt;keys&lt;/code&gt; or &lt;code&gt;values&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;you can access the index value (1,2,…) through &lt;code&gt;count.index&lt;/code&gt; which is useful for enumerating resource names or accessing elements with the &lt;code&gt;element(...)&lt;/code&gt; function from an array (i.e. array ob CIDR ranges).&lt;/p&gt;

&lt;p&gt;Use the &lt;code&gt;count&lt;/code&gt; meta argument over &lt;code&gt;for_each&lt;/code&gt; if you have a simple resource use case that does no rely on multiple values but only operates with an index value.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>programming</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How to use Modules in Terraform</title>
      <dc:creator>Dennis Groß (he/him)</dc:creator>
      <pubDate>Sun, 18 Dec 2022 14:34:41 +0000</pubDate>
      <link>https://dev.to/gdenn/how-to-use-modules-in-terraform-43f0</link>
      <guid>https://dev.to/gdenn/how-to-use-modules-in-terraform-43f0</guid>
      <description>&lt;p&gt;A module makes a set of resources reusable by wrapping it into a package that we can use in the context of different Terraform projects.&lt;/p&gt;

&lt;p&gt;In essence, a module is a folder with one or multiple &lt;code&gt;*.tf&lt;/code&gt; files that describe resources. There must be at least one &lt;code&gt;*.tf&lt;/code&gt; file in the module, the so-called root module.&lt;/p&gt;

&lt;h2&gt;
  
  
  Module Distribution
&lt;/h2&gt;

&lt;p&gt;There are multiple ways to re-use Terraform from another system&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have the module code checked out nearby, and reference the module directly&lt;/li&gt;
&lt;li&gt;The module is available in the Terraform Registry&lt;/li&gt;
&lt;li&gt;The module is available in a private registry

&lt;ul&gt;
&lt;li&gt;Github&lt;/li&gt;
&lt;li&gt;Bitbucket&lt;/li&gt;
&lt;li&gt;HTTP URLs&lt;/li&gt;
&lt;li&gt;S3 Bucket&lt;/li&gt;
&lt;li&gt;GCS buckets&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Referencing Modules from the File System
&lt;/h3&gt;

&lt;p&gt;Here is an example of how we reference the &lt;code&gt;vpc&lt;/code&gt; module in a Terraform project relative to the current directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using Registry Modules
&lt;/h3&gt;

&lt;p&gt;Using a module from a Terraform registry is quite the same than referencing a module on the local file system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;terraform-aws-module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3.14.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;passed&lt;/span&gt; &lt;span class="nx"&gt;here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example refers to a module called &lt;code&gt;terraform-aws-module&lt;/code&gt; . the biggest difference between local and registry modules is that registry modules are versioned, so you need to provide a version string.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hosting Modules in Github
&lt;/h3&gt;

&lt;p&gt;You can reference a module from a GitHub repository by URL. This is convenient since most Terraform modules need to be stored in a version control system anyways.&lt;/p&gt;

&lt;p&gt;You can checkout GitHub modules in two ways&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Through HTTPS&lt;/li&gt;
&lt;li&gt;Through SSH
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github.com/gdenn/my-vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="nx"&gt;go&lt;/span&gt; &lt;span class="nx"&gt;here&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;Example SSH&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;git@github.com:gdenn/my-vpc.git&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="nx"&gt;go&lt;/span&gt; &lt;span class="nx"&gt;here&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 reference your GitHub credentials in multiple ways&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;~/.ssh/config&lt;/code&gt; set a &lt;code&gt;Host&lt;/code&gt; entry and point to your &lt;code&gt;IdentiyFile&lt;/code&gt; (SSH key)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;Host&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;github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;
    &lt;span class="nx"&gt;HostName&lt;/span&gt; &lt;span class="nx"&gt;github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;
    &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="nx"&gt;git&lt;/span&gt;
    &lt;span class="nx"&gt;IdentityFile&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/.ssh/i&lt;/span&gt;&lt;span class="nx"&gt;d_rsa&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Pass the credentials to the source parameter
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;git::https://${git_username}:${git_password}@github.com/folder/terraform-azure-core-resource-group.git&lt;/span&gt;&lt;span class="dl"&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;h2&gt;
  
  
  Passing Variables
&lt;/h2&gt;

&lt;p&gt;Every module can have a variables file that stores configurable config parameters that the resource scripts might use.&lt;/p&gt;

&lt;p&gt;Values for the variables can be passed in the module block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt;
    &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-central-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can still pass variables through the environment or use the default values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provider Configuration
&lt;/h2&gt;

&lt;p&gt;A module can inherit the provider config from the caller module (parent module). Although it is advisable to define a provider with a range of compliant versions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;= 0.13.1&lt;/span&gt;&lt;span class="dl"&gt;"&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="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hashicorp/aws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;= 4.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Terraform will try to use a pre-installed provider version (e.g. used by another module or the parent) if it fits the version constrained by this child module.&lt;/p&gt;

&lt;p&gt;In many cases, this might prevent the installation of an unnecessary additional provider and ensures that the module uses a provider this is compatible.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>cloud</category>
      <category>cloudskills</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>10 Reasons Why You Should use Docker</title>
      <dc:creator>Dennis Groß (he/him)</dc:creator>
      <pubDate>Sun, 18 Dec 2022 13:44:07 +0000</pubDate>
      <link>https://dev.to/gdenn/10-reasons-why-you-should-use-docker-5dp0</link>
      <guid>https://dev.to/gdenn/10-reasons-why-you-should-use-docker-5dp0</guid>
      <description>&lt;p&gt;One of the most popular container technology providers Docker registers in February 2022 a record breaking &lt;a href="https://www.docker.com/blog/celebrating-our-second-fiscal-year/"&gt;15+ million active users per month&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The success of Docker is a testament to the impact that container technologies have on the entire IT landscape.&lt;/p&gt;

&lt;p&gt;But what causes more and more developers and organisations to move their applications and services into the container?&lt;/p&gt;

&lt;p&gt;This blog post will explain the fundamental concepts of container technologies and show you 10 reasons that make container technologies attractive for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Container?
&lt;/h2&gt;

&lt;p&gt;Containers are small packages that contain software in a runnable software environment. You can use those packages to ship software to any computer or virtual machine (VM) that supports a container runtime like Docker.&lt;/p&gt;

&lt;p&gt;The idea behind containers is the virtualisation of the operating system. Containers are processes that disguise themselves as operating systems. Container looks like an operating system for applications that run inside the container. But they are in reality processes that run on top of an existing operating system. They share system resources such as disk, memory and network with the host operating system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Container Images
&lt;/h3&gt;

&lt;p&gt;The container image is a file format that we use to specify to a container runtime how a container process should start. It contains a set of top-down instructions that the container runtime carries out when we start a container.&lt;/p&gt;

&lt;p&gt;The file format to specify a container image in the Docker ecosystem is called a Dockerfile. We can create a Dockerfile with our code editor and turn it into a container image with the &lt;code&gt;docker build&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Here is an example Dockerfile from the &lt;a href="https://nodejs.org/en/docs/guides/nodejs-docker-webapp/"&gt;NodeJS community&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;FROM node:16

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json 
# AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

RUN npm install
# If you are building your code for production
# RUN npm ci --only=production

# Bundle app source
COPY . .

EXPOSE 8080
CMD ["node", "server.js"]

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

&lt;/div&gt;



&lt;p&gt;You can see that the Dockerfile above carries out commands with the RUN directive much like you would do in the terminal of your UNIX system. But Dockerfiles offer also container specific declarations like COPY and EXPOSE which we use to inject data into a container process or for port-binding.&lt;/p&gt;

&lt;p&gt;Every container image references a "base image". This is done through the FROM statement. The example above references the official NodeJS Docker image. Using the NodeJS Docker image as a base image ensures that we already have a linux container with NodeJS dependencies like npm and node pre-installed.&lt;/p&gt;

&lt;p&gt;But we could have chosen any other Docker image from the official Docker Hub registry instead.&lt;/p&gt;

&lt;p&gt;The concept of re-using existing Container Images by referencing base images is called image layering. Container images can consist of multiple layers. The example Dockerfile above is based on the NodeJS image layer which is based on the Ubuntu image layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Container Registries
&lt;/h3&gt;

&lt;p&gt;Containers are made to simplify the deployment of software. But we need to ship container images to production systems in order to start container processes.&lt;/p&gt;

&lt;p&gt;Container registries help us to distribute container images. A registry is a database for container images that we can consume through a Rest API or a client. One of the most popular container registries is the Docker Hub Registry. This is the place where many open source communities upload their official container images.&lt;/p&gt;

&lt;p&gt;The Dockerfile example from the last section uses the official Docker Hub image for NodeJS. The docker command line interface (CLI) searches the Docker Hub container registry by default if the required container image cannot be found on the host system&lt;/p&gt;

&lt;p&gt;Downloading a container image from a registry is called a "pull" or "pulling".&lt;/p&gt;

&lt;p&gt;You can also host a container registry by yourself. Nexus and Artifactory are two common applications that provide container registries. Most cloud providers like Amazon Web Service, Microsoft Azure or Google Cloud Platform offer managed container registries for users.&lt;/p&gt;

&lt;p&gt;How you can use another container registry with your Docker CLI is described &lt;a href="https://www.docker.com/blog/how-to-use-your-own-registry-2/"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Container Orchestration
&lt;/h3&gt;

&lt;p&gt;Operating production systems with many container applications is difficult. Container Orchestrators like Kubernetes, Docker Swarm and Docker Compose exist to make the deployment and maintenance of containerized production systems easier.&lt;/p&gt;

&lt;p&gt;Container orchestrators differ greatly in complexity and features. But Docker Compose is a good orchestrator to get started with Docker. It is primarly used for local development purposes or the deployment of production systems on a single virtual machine or computer.&lt;/p&gt;

&lt;p&gt;Other orchestrators like Kubernetes are more complex to use but make it possible to deploy container applications on infrastructure with multiple virtual machines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open Container Initiative
&lt;/h3&gt;

&lt;p&gt;The Open Container Initiative (OCI) provides a standard for the most important components of container technologies. Part of these standards are for example the container image format and the container runtime API.&lt;/p&gt;

&lt;p&gt;Container Runtimes like containerd, CRI-O, Docker and Mirantis implement this OCI container runtime standard. That is important because container orchestrators like Kubernetes make the Container Runtime configurable. You use any container runtime that respects the OCI standard in your Kubernetes cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reasons to Use Container Technologies
&lt;/h2&gt;

&lt;p&gt;We understand now the fundamental concepts of container technologies and can start to learn more about their use cases and benefits.&lt;/p&gt;

&lt;p&gt;Here are the 10 reasons why you should use container technologies.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Resource Efficiency
&lt;/h2&gt;

&lt;p&gt;Container help us to utilise more of our system resources in our computers, servers and virtual machines.&lt;/p&gt;

&lt;p&gt;Organisations can deploy multiple services or applications on a machine through containers while maintaining a degree of isolation between them. That makes it possible to run more software on the same machine which improves resource utilisation and reduces hosting costs.&lt;/p&gt;

&lt;p&gt;A smaller resource overhead compared to dedicated virtual machines makes the container a cheaper deployment target for software. Container do not provide system resources on their own but reuse existing system resources of the host machine instead.&lt;/p&gt;

&lt;p&gt;A host machine can be anything that provides an operating system like a virtual machine or computer. Virtual machines are an interesting platform to host container processes since they find wide application in cloud computing and software hosting in general.&lt;/p&gt;

&lt;p&gt;Virtualization of system resources in form of virtual machines is time intensive and costly. Automated infrastructures require on average several minutes to bootstrap a virtual machine, while containers are up and running in seconds.&lt;/p&gt;

&lt;p&gt;The speed and resource efficiency of containers make them both a space, resource and time efficient deployment option and help us to maximise the resource usage of virtual machines.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Isolation
&lt;/h2&gt;

&lt;p&gt;Software products have been deployed on virtual machines for a long time. Linux operating systems offer service managers like systemd to orchestrate several service processes on the same virtual machine. But that can be quite challenging because of the lack of isolation between processes.&lt;/p&gt;

&lt;p&gt;Processes running on the same Linux operating system share system wide dependencies, disk space, network and CPU resources. It is difficult to ensure that services running in different Linux processes do not interfere with each other.&lt;/p&gt;

&lt;p&gt;Container processes on the other side offer a higher degree of isolation in comparison. A container process gets started with the Unix &lt;code&gt;clone&lt;/code&gt; system call in contrast to the &lt;code&gt;exec&lt;/code&gt; system call used for most other Unix processes.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;clone&lt;/code&gt; system call spawns a UNIX process like the &lt;code&gt;exec&lt;/code&gt; or &lt;code&gt;fork&lt;/code&gt; system call. But &lt;code&gt;clone&lt;/code&gt; has some important capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;clone&lt;/code&gt; can place child processes into different UNIX namespaces.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;clone&lt;/code&gt; can place child processes into a different virtual address space.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;clone&lt;/code&gt; can change the file descriptor table of the child process.&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We won't go into details of how a Unix operating system works in this blog post. But the capabilities offered by the &lt;code&gt;clone&lt;/code&gt; system call used by container processes improves the isolation of containers compared to "regular" UNIX processes.&lt;/p&gt;

&lt;p&gt;Container processes provide a virtualised operating system that reuses existing system resources of the host. The virtualised operating system prevents the leakage of system wide dependencies like dynamic link libraries into software processes that run inside a container.&lt;/p&gt;

&lt;p&gt;For example, installing a NodeJS NPM package in one container process running a NodeJS app does not affect other container processes. The same might not be true for two NodeJS processes running on the same Linux machine. There is the possibility that both apps use the same NodeJS interpreter which might lead to incompatabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Automated Setup
&lt;/h2&gt;

&lt;p&gt;Container images provide a declarative syntax that you can use to describe a container. Container Runtimes use container images to start container processes on a host operating system.&lt;/p&gt;

&lt;p&gt;The starting procedure that the Container Runtime carries out is automated and reproducible. Instructing the Container Runtime to start a container process using the same image a hundred times, leads a hundred times to the same result.&lt;/p&gt;

&lt;p&gt;That is an important quality of Container Technologies. It makes software deployments more predictable and bugs in software systems more relatable. Software Developers can reproduce bugs that appear in production systems easier if the underlying application runs in a container. Developers can use the container image to run an application in the same runtime environment on their local machine for trouble shooting.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Reusability
&lt;/h2&gt;

&lt;p&gt;The container image ecosystem works like an onion. Container images consist of multiple layers that are entwined into each other like an onion.&lt;/p&gt;

&lt;p&gt;Reusing rather than rewriting container images makes it easier to specify a container. A NodeJS developer can use the official NodeJS Docker Hub image to containerise his application. There is no need to specify installation routines for a NodeJS interpreter or the NPM package manager. This step is already covered by the NodeJS base container image.&lt;/p&gt;

&lt;p&gt;Compare this approach with the typical installation workflow on virtual machines. A vanilla virtual machine comes with an operating system only. DevOps have to intercept the virtual machine through SSH to install software dependencies and parts of the software runtime by hand.&lt;/p&gt;

&lt;p&gt;Additional software like Chef or Ansible can automate this process but administrators have to configure and maintain automation workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Flexibility
&lt;/h2&gt;

&lt;p&gt;A Docker Container can be deployed to any operating system with a Docker Engine installed. Docker supports a wide range of operating systems from Windows, MacOS to most Linux distributions.&lt;/p&gt;

&lt;p&gt;Being able to deploy a container across many operating systems offers flexibility. It makes us more independent from conditions that we meet on our infrastructure. Virtual machines on Amazon Web Services might differ greatly from virtual machines on Microsoft Azure. So your software applications might require different dependencies depending on the infrastructure that you deploy them on.&lt;/p&gt;

&lt;p&gt;Container technologies ship their own software runtime and circumvent discrepancies between infrastructures. That makes it easier to deploy them on different infrastructures.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Reproducibility
&lt;/h2&gt;

&lt;p&gt;The premise of containers is that software running inside them behaves the same, regardless on which host system we deploy them. The extended isolation of container processes compared to "regular" UNIX processes ensures that this premise holds true.&lt;/p&gt;

&lt;p&gt;Knowing that your containerised application behaves the same on any host system makes it easier to reproduce and debug problems that happen in productive systems. Software developers can run containerised application on their local machine and debug a problem that the customer reported at the production environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Interoperability
&lt;/h2&gt;

&lt;p&gt;Container technologies simplify the collaboration between developers and operators. Operators can provide the container image while software developers focus on programming the software application specified in the container image.&lt;/p&gt;

&lt;p&gt;Changes in the software application rarely require changes of the container image. This makes it easier to isolate the developer and operator role in a software company.&lt;/p&gt;

&lt;p&gt;Container images function as a contract between developer and operator. This contract specifies how software can be deployed on the production system through a container runtime.&lt;/p&gt;

&lt;p&gt;Compare this with "regular" software processes running on a developer machine or a virtual machine. Complex software processes require different data services and software dependencies. Developers and operators have to install these runtime dependencies on local development machines and virtual machines alike. This results in a confusing installation procedure that can lead to misunderstandings.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Composability
&lt;/h2&gt;

&lt;p&gt;Composing software services and applications across multiple virtual machines can be challenging. Platform providers tend to install applications and services on dedicated virtual machines to limit potential side effects.&lt;/p&gt;

&lt;p&gt;Additional software like Chef or Ansible get used to automate this process but require configuration and maintenance of qualified personnel.&lt;/p&gt;

&lt;p&gt;The implementation of large micro service architectures with multiple applications and services that communicate with each other are common these days.&lt;/p&gt;

&lt;p&gt;Container orchestrators like Kubernetes can help to schedule and deploy containerised micro services across multiple virtual machines.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Scalability
&lt;/h2&gt;

&lt;p&gt;Containers are fast, it takes a few seconds to start a container on a host system. They are so fast that Kubernetes kills failing container services and starts a new service rather than fixing the old instance.&lt;/p&gt;

&lt;p&gt;Deployment speed is an important metric in software hosting. It reduces the downtime of services during updates and makes it easier to scale out.&lt;/p&gt;

&lt;p&gt;Creating a new virtual machine on an automated infrastructure (IaaS) like AWS on the other hand takes minutes. Requesting a larger VM on the same infrastructure to satisfy the growing resource demand of an application costs you another couple of minutes.&lt;/p&gt;

&lt;p&gt;This makes it much more difficult to scale out applications or services that run as processes on a virtual machines instead of containers.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Less Permissive
&lt;/h2&gt;

&lt;p&gt;It can be challenging to deploy applications on virtual machines if you don't have sufficient permissions to install third party applications and dependencies.&lt;/p&gt;

&lt;p&gt;Many Linux users install software and dependencies through a package manager like aptitude with superuser permissions. This can be done with the sudo command that runs a terminal command with superuser priviliges.&lt;/p&gt;

&lt;p&gt;But giving every developer and operator superuser priviliges is dangerous. Many organizations restrict superuser priviliges on productive virtual machines for this reason.&lt;/p&gt;

&lt;p&gt;Container processes do not need to be executed with superuser priviliges. They ship their own virtual operating system and developers specify required dependencies through the container image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Container technologies revolutionised how we as a community operate and deploy software.&lt;/p&gt;

&lt;p&gt;This blog post taught us the fundamental concepts of container technologies along with their advantages.&lt;/p&gt;

&lt;p&gt;But containers are not a magic pill. They have limitations like any other technology. One of the weaknesses of container technologies is at the same time its biggest strength. The lack of virtualised system resources in containers make them slim and fast but they compromise the isolation of containers in comparison to virtual machines.&lt;/p&gt;

&lt;p&gt;A container does not virtualise network, storage or server resources. It reuses existing system resources of the host system along with other containers and processes. Container runtimes cannot limit the bandwidth of IO operations for a container process. This problem is also known as the IOPS problem.&lt;/p&gt;

&lt;p&gt;Placing two large containerised databases on the same virtual machine might lead to resource contingencies. One database could occupy the complete bandwidth for data IO operations of the host system, effectively leaving the other database dry.&lt;/p&gt;

&lt;p&gt;And those are the 10 reasons why you should use container technologies.&lt;/p&gt;

&lt;p&gt;I recommend you have a look at the excellent &lt;a href="https://docs.docker.com"&gt;documentation of Docker&lt;/a&gt; if you want to get started with container technologies now.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man2/clone.2.html"&gt;Linux Manual Page - clone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man2/fork.2.html"&gt;Linux Manual Page - fork&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man3/exec.3.html"&gt;Linux Manual Page - exec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.redhat.com/en/topics/containers"&gt;Red Hat - Understanding Linux Containers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/blog/celebrating-our-second-fiscal-year/"&gt;Celebrating Our Second Fiscal Year - Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com"&gt;Official Docker Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="%E2%80%8Chttps://www.ansible.com"&gt;Ansible by Red Hat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.chef.io"&gt;The Chef Automation Software&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com"&gt;The Docker Hub Container Registry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en/docs/guides/nodejs-docker-webapp/"&gt;Dockerizing a Node.js web app - nodejs.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cloudnative</category>
      <category>docker</category>
      <category>container</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
