Terraform for beginners

Terraform for beginners

Publié le


Do not index
Do not index
Primary Keyword
Lié à Analyse sémantique (Articles liés) 1
Lié à Analyse sémantique (Articles liés)
Statut rédaction
Terminé
Lié à Analyse sémantique (Articles liés) 2

Introduction

The DevOps movement includes a series of IT engineering tactics aimed at shortening the amount of time it takes to make changes to software design and deployment. One of these tactics is to leverage technology to write a plan that contains deployment specifications ready to be orchestrated in the cloud or on-premises. Terraform is a tool that allows you to build and manage infrastructure safely and efficiently. This includes low-level components such as compute instances, storage, and networking, as well as high-level components such as DNS entries, SaaS features, etc. Terraform can manage both existing service providers and custom in-house solutions. In this course, you will learn about how to use Terraform to define and to manage your Cloud or on-premise infrastructure
 

Understanding Infrastructure As Code (IaC)

Infrastructure as code is a concept that allows you to:
  • Write down what you want to deploy such as virtual machines, disks, virtual networks, etc... as human readable code without having to use the provider Web GUI
  • Enable DevOps since your infrastructure will be described in a code that can be tracked inside a version control repository. This enables more visibility and collaboration across teams
 

IaC with Terraform

  • Terraform is an IaC tool
  • Why choosing Terraform as IaC tool ?
    • Terraform interacts and takes care of communications with control layer APIs with ease
    • Terraform supports a vast array of private and public Cloud vendors and so much more (on-premise infrastructures, etc...)
    • Terraform tracks the state of each deployed resource
    •  
  • What is the Terraform workflow?
      1. Write: starting by writting the code that describes the infrastructure inside a version control repository (best practice) or locally
      1. Plan: preview the changes that the writtten code would bring into the real infrastructure
      1. Apply: after one last plan/review, you are ready to provision the real infrastructure
       
  • Initializing the Terraform working directory
    • Before you start coding your infrastructure, you need to understand how to initialize Terraform inside your working directory
      You have to enter the following command to get started:
      terraform init
      This command will:
    • Download all of the required components (modules, plugins)
    • Sets up the resource tracking mechanism, called backend
    •  
  • Terraform key concepts : Plan, Apply and Destroy
    • Plan:
      • Reads the code and shows a "plan" of what will be deployed with with code without actually deploying any resource
      • Allows the user to review the action plan before executing anything
      • Requires authetication credentials, if required
    • Apply:
      • Deploys the infrastructure resources according to the descriptions in the code
      • Updates the deployment state mechanism file aka state file or tfstate
    • Destroy:
      • Looks at the recorded state file created during the deployment and destroys all of the resources created with the code
      • Updates the deployment state file by removing all of the destroyed resources
      • Non-reversible command
      •  
  • Resource addressing in Terraform: Understanding Terraform Code
    • Understanding the provider configuration
      • The provider block lets you define your provider configurations
        notion image
       
    • Understanding a resource block definition
      • A resource block defines a resource that will be created from scratch and will be managed by Terraform code
        notion image
        Resource address is: aws_instance.web
       
    • Understanding a data source block definition
      • A data source block give the possibility to get informations of resources that already exists in the infrastructure (eg: getting the public IP address of an existing VM, etc..)
        notion image
        Data source address is: data.aws_instance.my-vm
    • Terraform configuration files uses .tf extension

Terraform Fundamentals

  • Terraform providers
    • Providers are Terraform's way of abstracting integrations with API control layer of the infrastructure vendors.
    • Terraform, by default, looks for Providers in the Terraform providers registry https://registry.terraform.io/browse/providers
    • Providers are plugins. They are released on a separate rhythm from Terraform itself, and each provider has its own series of version numbers.
    • You can write your own Terraform provider as well.
    • Terraform finds and installs providers when initializing working directory via terraform init command.
    • As a best practice Providers should be pegged down to a specific version, so that any changes across provider version doesn't break your Terraform code.
      • Provider definition example in a file provider.tf . You can choose any other filename.
        provider "aws" {
          region  = "eu-west-1"
          version = "3.69.0"
        }
        By executing the command terraform init ,Terraform will download the required files for this provider from the default Terraform registry.
        You can find all of the available providers list on the Terraform registry here: https://registry.terraform.io/browse/providers
 
  • Terraform state: the concept
    • A way for Terraform to keep tabs on what has been deployed
    • Stored in a flat json file, usually having the name terraform.tfstate
    • Critical to Terraform's functionality so never lose it
    •  
  • Terraform variables
    • Declaring a variable
      • notion image
        All of the variable config arguments are optional so you can also define your variable simply with:
        variable "my-var" {}
        ...and you will provide the value for your variable in the command line or in another file that we will discuss later
    • Referencing a variable
      • Use the var. object suffixed by your variable name
        var.my-var
    • Using terraform.tfvars file to explicitly set variables values
      • Simply create a file with tfvars extension in the same directory as your Terraform code
        my-var       = "eu-west-1"
        my-other-var = "foobar"
        my-super-var = "makeitclear"
        These values will overwrite the default value (if there is any) of each variable from their declaration block
         
    • Variable types
      • string: a sequence of Unicode characters representing some text, like "hello".
      • number: a numeric value. The number type can represent both whole numbers like 15 and fractional values like 6.283185.
      • bool: a boolean value, either true or falsebool values can be used in conditional logic.
      • list (or tuple): a sequence of values, like ["us-west-1a", "us-west-1c"]. Elements in a list or tuple are identified by consecutive whole numbers, starting with zero.
      • map (or object): a group of values identified by named labels, like {name = "Mabel", age = 52}.
      •  
    • Other useful features about variables
      • Validate the value that will be passed to your variable to prevent invalid inputs
        • Here is a validation example that will force the user to put a string that must contain more than 4 characters, otherwise Terraform won't deploy the code and display an error message.
          variable "my-var" {
          	description = "My Test Variable"
          	type        = string
          	default     = "Hello"
            validation {
          		condition = length (var.my-var) > 4
          		error_message = "The string must be more than 4 characters"
            }
          }
      • Set the variable as sentitive so that Terraform won't display its value in the console during Plan, Apply or Destroy phase
        • variable "my-var" {
          	description = "My Test Variable"
          	type        = string
          	default     = "Hello"
            sensitive   = true
          }
 
  • Terraform outputs
    • Returns informations about your resources to be displayed on and to be accessible form the command line
    • Can expose informations for other Terraform configurations to use.
    • Similar to return values in programming languages.
    • Declaring output:
      • notion image
        The value argument is usually a reference to a resource property that you have deployed
    • You can also mark an output as sensitive like variables and Terraform will not display it on the shell output
      • output "container_registry_secret_key" {
        	description = "The secret key that can be used to access the container registry"
          value       = google_service_account_key.artifact-sa-key.private_key
          sensitive   = true
        }
  • Terraform provisioners
    • Terraforms way of bootstrapping custom scripts, commands or actions
    • Can be run locally on the same system where Terraform commands are being issued from
    • Can be run remotely on resources spun up through the Terraform deployment
    • Within Terraform code, each individual resource can have its own "provisioner" defining the connection method (if required such as SSH or WinRM) and the actions/commands or script to execute.
    •  
    • There are 2 types of provisioners:
      • "Creation-time" provisioner which you can set to run when a resource is being created
      • "Destroy-time" provisioner which you can set to run when a resource is being destroyed.
       
    • DISCLAIMER: Hashicorp recommends using Provisioners as a last resort and to try using inherent mechanisms within your infrastructure deployment to carry out custom tasks where possible.
    •  
    • When should you use provisioners?
      • When you want to invoke actions not covered by Terraforms declarative model.
        • Keep in mind that If the command within a provisioner returns non-zero return code, it's considered failed and the underlying resource is tainted. A resource that is tainted will be re-created (destroyed, then created) by Terraform during the next deployment/apply
           
        Provisioner usage example:
        resource "null_resource" "dummy_resource" {
        	provisioner "local-exec" {
        		command = "echo 'created your resource'> status.txt"
            #creation time
        	}
        	provisioner "local-exec" {
        		when    = destroy
        		command = "echo 'destroyed your resource'> status.txt"
        		#destroy time
        	}
        }

Terraform State

  • Terraform state description
    • It maps real-world resources to Terraform configuration.
    • Contains output values.
    • By default, state is stored locally in a file called terraform. tfstate.
    • Prior to any modification operation, Terraform refreshes the state file.
    • Resource dependency metadata is also tracked via the state file.
    • Helps boost deployment performance by caching resource attributes for subsequent use.
    •  
  • Terraform state command
    • Utility for manipulating and reading the Terraform State file.
    • Scenario:
      • Listing out tracked resources and their details via state and list subcommands
        • Command: terraform state list to list all of the tracked resources in the state
        • Command: terraform state show <resource-reference> to get all of the provided resource informations in the state file
      • Manually remove a resource from Terraform State file so that it's not managed by Terraform. For advanced users only
      • Advanced state management (eg: importing an existing resource in the state file)
      •  
  • Local and Remote state storage
    • Local state storage
      • Saves Terraform state locally on your system in a file called terraform.tfstate
      • Terraform's default behavior.
      • For personal projects.
    • Remote state storage
      • Saves state to a remote data source. Examples of storage: AWS S3, Google Storage
      • Allows sharing state file between distributed teams.
      When a state file is being in use for Plan, Apply or Destroy, Terraform puts a lock in it so other team members cannot access to it in order to avoid parallel execution

Terraform Modules

  • What is a Terraform module ?
    • A folder for multiple resources that are used together for code reusability.
    • Every Terraform configuration has at least one module, called the root module, which consists of code files in your main working directory.
    •  
  • Accessing and using Terraform modules
    • Modules can be downloaded or referenced from:
      • Terraform Public Registry
      • A Private Registry
      • Your Local system (since it is a directory)
    • Modules are referenced using a module block.
    • notion image
       
    • Modules can optionally take input and provide outputs to be used into your main code.
    • notion image
 
  • Interacting with Terraform modules inputs and outputs
    • Module inputs
      • Module inputs are arbitrarily named parameters that you pass inside the module block.
      • Module inputs can be used as variables inside the module code.
      • notion image
       
    • Module outputs
      • The outputs declared inside Terraform module code can be fed back into the root module or your main code
      • Accessing the module output follows this pattern: module.<name-of-module>.<name-of-output>
        • Example:
          #In your module
          output "instance_ip" {
            value = aws_instance.private_ip
          }
          
          ##################################################
          
          #In your main terraform code (root module)
          module "my-vpc-module" {
          	source        = "./modules/vpc"
            server-region = "us-east"
          }
          
          resource "dummy_resource" "my-root-resource" {
            #...other parameters
            vpc_ip = module.my-vpc-module.instance_ip
          }

Built-in Functions and Dynamic Blocks

  • Terraform built-in functions
    • Terraform comes pre-packaged with functions to help you transform and combine values.
    • User-defined functions are not allowed - only built-in ones.
    • General syntax: function_name(arg1, arg2, ...)
      • Usage example:
        variable "project-name" { 
        	type = string
        	default = "prod"
        }
        
        resource "aws_vpc" "my-vpc" { 
        	cidr_block = "10.0.0.0/16"
        	tags {
        		Name = join("-",["terraform", var.project-name])
        		# The argument "Name" will have "terraform-prod" as value after using the join() function
        	}
        }
    • The complete list of all available functions can be found on this link: https://www.terraform.io/language/functions
    • TIP: You can test any function quickly by using terraform console
      • Open a terminal, then type terraform console and test your function there
        notion image
       
  • Terraform Type Constraints (Collections & Structural)
    • Primitive types: number, string, bool , any
      • variable "example-var" {
        	type  = bool
        	value = false
        }
    • Complex types: multiple types in a single variable, also called "collections"
      • Constructors for these collections are:
      • list(<TYPE>)
        • variable "list-of-string" {
          	type    = list(string)
          	default = ["alpha","beta","banana split","cupcake"]
          }
      • tuple([<TYPE>, ...])
        • variable "tuple" {
          	type    = tuple([string,number,bool])
          	default = ["alpha",15,false]
          }
      • set(<TYPE>)
        • variable "set-of-number" {
          	type    = set(number)
          	default = [10,77,48,50]
          }
          #A set is a list type that cannot contains duplicate element values
      • map(<TYPE>)
        • variable "map-of-string" {
          	type    = map(string)
          	default = {
          		"primo"   = "alpha"
          		"secondo" = "beta"
          	}
          }
      • object({<ATTR NAME> = <TYPE>, ... })
        • variable "complex-object" {
          	type    = object({
          		name      = string
          		age       = number
          		qualified = bool
              misc      = map(string)
          	})
            default = {
          		name      = "John"
          		age       = 29
          		qualified = true
          		misc      = {
          			"opinion" = "agree"
          		}
          	}
          }
 
  • Terraform dynamic blocks
    • Dynamically constructs repeatable nested configuration blocks inside Terraform resources
    • Supported within the following block types:
      • resource
      • data
      • provider
      • provisioner
    • Used to make the code cleaner
      • Example:
        #Without dynamic block
        resource "aws_security_group" "my-sg" {
        	name   = "prod-instance-sg"
        	vpc_id = aws_vpc.my-vpc.id
        	ingress {
        		from_port   = 22
        		to_port     = 22
        		protocol    = "tcp"
        		cird_blocks = ["1.2.3.3/32"]
        	}
        
        	ingress {
        		#more rules
        	}
        
        	ingress {
        		#another rules
        	}
        	....
        }
        
        #Using dynamic block
        resource "aws_security_group" "my-sg" {
        	name   = "prod-instance-sg"
        	vpc_id = aws_vpc.my-vpc.id
        	
        	dynamic "ingress" {
        		for_each = var.ingress-rules-map    #Complex variable to iterate over
        		
        		content {
        			from_port   = ingress.value["from_port"]    # The nested "content" block
        			to_port     = ingress.value["to_port"]      # defines the body of
        			protocol    = ingress.value["protocol"]     # each generated block
        			cird_blocks = ingress.value["cird_blocks"]  # using the variable you provided
        		}
        	}
        }
        
        #The ingress-rules-map complex variable definition
        variable "ingress-rules-map" {
        	default = {
        		rule_1 = {
        			from_port   = 22
              to_port     = 22
              protocol    = "tcp"
              cidr_blocks = ["1.2.3.4/32"]
            }
        		rule_2 = {
        			from_port   = "any"
              to_port     = 443
              protocol    = "tcp"
              cidr_blocks = ["1.2.3.4/32"]
            }
        		#You can add more as you need
        	}
        }
       
    • Dynamic blocks expect a complex variable type to iterate over.
    • It acts like a for loop and outputs a nested block for each element in your variable.
    •  
      NOTES:
    • Be careful not to overuse dynamic blocks in your main code, as they can be hard to read and maintain.
    • Only use dynamic blocks when you need to hide detail in order to build a cleaner user interface when writing reusable modules.

Terraform CLI

  • Terraform format
    • Formats Terraform code for readability
    • Helps in keeping code consistent
    • Safe to run at any time
    • Scenario:
      • Before pushing your code to version control
      • After upgrading Terraform or its modules
      • Any time you've made changes to code
    • Syntax:
      • terraform fmt
        #no other options required
 
  • Terraform taint
    • Taints a resource, forcing it to be destroyed and recreated upon the next Apply
    • Modifies the state file, which causes the recreation workflow
    • Tainting a resource may cause other dependant resources to be modified upon the next Apply
    • Scenario:
      • To cause provisioners to run.
      • To replace misbehaving resources forcefully
    • Syntax:
      • terraform taint RESOURCE_ADDRESS
        #example
        terraform taint aws_security_group.my-sg
  • Terraform import
    • Maps existing resources to Terraform using an "ID".
    • The "ID" is dependent on the underlying vendor For example to import an AWS EC2 instance you'll need to provide its instance ID. Another example, to import a Helm chart release, you'll need to provide the release name suffixed by the namespace of the release
    • Importing the same resource to multiple Terraform resources can cause unknown behavior and is NOT recommended.
    • Scenario:
      • When you need to work with existing resources.
      • Not allowed to create new resources.
    • Syntax:
      • terraform import RESOURCE_ADDRESS ID
        #example
        terraform import helm_release default/prod-release
  • Terraform CLI configuration block
    • A special configuration block for controlling Terraform's own behavior from the code.
    • This block only allows constant values, named resources and variables are not allowed in it.
    • Scenario:
      • Configuring the backend for storing state files
      • Specifying a required Terraform version
      • Specifying a required Terraform Provider version and its requirements
      • Enable and test Terraform experimental features
      • Passing metadata to providers
    • Usage example:
      • terraform {
        	required_version = ">=0.13.0"         # Requires Terraform 0.13.0 or higher version
        
        	required_providers {                  #  ˥
        		aws = ">=3.0.0"                     #  Requires a provider "aws" with version 3.0.0 or higher
        	}                                     #  ˩
        
          backend "remote" {                    #  ˥
            organization = "my-organization"    #  
            workspaces {                        #  Setup the backend for the state file
              prefix = "infrastructure-"        #
            }                                   #
          }                                     #  ˩
        }
 
  • Terraform workspaces CLI
    • The Terraform Workspaces are alternate state files within the same working directory.
    • Terraform starts with a single workspace that is always called default. It cannot be deleted.
    • Scenario:
      • Test changes using a parallel, distinct copy of infrastructure.
      • Create similar infrastructure across different environments (production, staging, testing, etc...)
      • It can be modeled against branches in version control such as Git.
    • Terraform workspace subcommand examples
      • terraform workspace new <WORKSPACE_NAME>
        #create a new terraform workpace with new empty statefile
        terraform workspace select <WORKSPACE_NAME>
        #select/use the given workspace
    • The current Workspace name is provided through the $(terraform.workspace} variable. It can be useful for resources naming purpose or for conditional resources creation, for example.
 
  • Debugging Terraform
    • TF_LOG is an environment variable for enabling verbose logging in Terraform. By default, it will send logs to stderr (standard error output) on your screen.
    • TF_LOG can be set to the following levels (values): TRACE, DEBUG, INFO, WARN, ERROR
    • TRACE is the most verbose level of logging and the most reliable one.
    • To persist logged output, use the TF_LOG_PATH environment variable with a file path as value.
    • Usage example:
      • Setting logging environment variables for Terraform on Linux:
        export TF_LOG=TRACE
        export TF_LOG_PATH=./terraform.log
    • Output example with the TF_LOG set to TRACE
      • notion image

Terraform Cloud and Enterprise

  • Sentinel (Embedded Policy-As-Code Framework) and its benefits
    • Enforces policies on your code.
    • Has its own policy language - Sentinel language.
    • Designed to be approachable by non programmers (much more human-readable).
    • Benefits:
      • Sandboxing - Guardrails for automation and to protect against accidental deployments
      • Codification - Easier understanding, better collaboration
      • Integrated Version Control
      • Testing and Automation
    • Use case examples:
      • For enforcing CIS standards across AWS accounts
      • Checking to make sure only t3.micro instance types are used
      • Ensuring Security Groups do not allow traffic on port 22
 
  • Hashicorp Vault
    • Secrets management software
    • Dynamically provisions credentials and rotates them
    • Encrypts sensitive data in transit and at rest and provides fine-grained access to secrets using Access Control List
    • How does Vault work with Terraform?
      • notion image
      • Developers don't need to manage long-lived credentials
      • Inject secrets into your Terraform deployment at runtime
      • Fine-grained ACLs for access to temporary credentials
 
  • Terraform Registry
    • A repository of publicly available Terraform providers and modules
    • You can publish and share your own providers and modules
    • You can collaborate with other contributors to make changes to providers and modules
    • Can be directly referenced in your Terraform code
    • URL: https://registry.terraform.io/
 
  • Terraform Cloud Workspaces
    • Workspace directories that is hosted in Terraform Cloud
    • Stores old versions of state files by default
    • Maintains a record of all execution activity
    • All Terraform commands are executed on "managed" Terraform Cloud VMs by default
 
  • Differentiating between Terraform Open Source Software Workspaces and Terraform Cloud Workspaces
    • Components
      OSS Workspace
      Cloud Workspace
      Terraform configuration
      On disk
      In linked version control repository or periodically Uploaded via CLI/API
      Variable values
      As .tfvars files or As CLI arguments or In shell environment
      In Terraform Cloud workspace as variables
      State
      On disk or In a remote backend
      In Terraform Cloud workspace
      Credentials and Secrets
      In shell environment or Entered at prompts
      In Terraform Cloud workspace as sensitive variables
  • Benefits of Terraform Cloud (Summary)
    • Remote Terraform execution
    • Version control integration (Github, Bitbucket etc)
    • Private Terraform Module registry
    • Workspace based organization model that enables cross-organization states sharing
    • Cost estimation for AWS, GCP and Azure infrastructures
    • Sentinel integration features for policies enforcement

Conclusion

  • Infrastructure as Code allows you to deploy IT infrastructures simply by writing code
  • Terraform is a Cloud agnostic Infrastructure as Code tool that uses HCL as configuration language
  • The core Terraform workflow is: Write, Plan and Apply
  • Terraform is able to interact with Cloud vendors API by using "providers
  • Terraform efficiently manages Cloud resources by referring to the state file
  • Terraform uses the concept of workspace to manage states and replicas of the defined infrastructure
  • Terraform Cloud offers even more features like policy enforcement, advanced secret management, remote execution, remote state management and more.
 

S'inscrire à la newsletter DevSecOps Keltio

Pour recevoir tous les mois des articles d'expertise du domaine

S'inscrire