This is a study guide for the HashiCorp Terraform Associate certification, bringing together the documentation provided by HashiCorp and my own notes.
This material doesn't cover the contents of the exam; it is instead based off of the study guide and exam review provided by HashiCorp.
Study Guide: Study Guide - Terraform Associate Certification | Terraform - HashiCorp Learn
Exam Review: Exam Review - Terraform Associate Certification | Terraform - HashiCorp Learn
Sample Questions: Sample Questions - Terraform Associate Certification | Terraform - HashiCorp Learn
Infrastructure as Code (IaC) is describing computing infrastructure through a written high-level syntax.
As well as Terraform, other IaC tools include AWS CloudFormation, Pulumi and Azure Resource Manager templates.
Infrastructure as Code enables numerous benefits including;
- Versioning of your infrastructure - See what your infrastructure was like at a point in time, and the change that have been made.
- Reusable Code - Separate distinct sets of identical infrastructure can be built from the same code.
- Code Modularity - Components can be broken down into discrete, composable pieces that be reused in different situations.
- Shareable Infrastructure - Infrastructure designs can be shared in Open Source and Inner Source repositories, to allow others to reuse the same code.
Terraform can take advantage of all of these benefits.
Infrastructure as Code allows for several benefitial patterns to be used;
- Service APIs (Application Programming Interfaces) can be consumed to utilise Cloud and On-Premises resources.
- Trivial to consume elasticly scalable cloud resources repeatedly.
- Version Control Systems can be used for historical tracking and control of code.
- Continuous Integration and Continuous Deployment (CI/CD) can be implemented to test and deploy your infrastructure.
- Code as documentation - Not only does your code deploy the infrastructure, it also describes how it all joins together.
What is infrastructure as code and why is it important? Infrastructure as Code in a Private or Public Cloud
Introduction to Infrastructure as Code with Terraform | Terraform - HashiCorp Learn
Use Cases - Terraform by HashiCorp
- Spreading infrastructure across clouds to increase fault tolerance
- Don't have to be reliant upon a single region or even a single cloud
- Provider-agnostic design allows for a single configuration to provision resources across multiple platforms
- Simplifying management, by keeping it under the same
State - Terraform by HashiCorp
Introduction to Infrastructure as Code with Terraform | Terraform - HashiCorp Learn
- Necessary for Terraform to function
- A source of truth to know if things have changed or not
- Need a database of what to map Terraform data to in the real world
- Has to be agnostic; not all providers support tagging or other concepts
- Even within the providers, not all resources necessarily support tagging
- Each distinct state object needs to be mapped to a distinct resource, to avoid ambiguous data
- Metadata such as dependencies needs to be tracked
- Typically configurations are used to determine the dependency order
- However, when you delete a resource, it will disappear from the configurations however
- Need the state to know that the resources need deleting
- Having the state means that order of deletion can also be determined
- Other methods would increase the complexity, especially given that deletions across providers may also need to be performed
- State allows for the attribute values to be cached
- Refreshing the state can be made optional to speed up Terraform for large state files
- Remote state allows for everyone to operate on the same state at the same time
- Implementing locking means that you’re always going to have the latest state to work with
Provider Configuration - Configuration Language - Terraform by HashiCorp Terraform Settings - Configuration Language - Terraform by HashiCorp
Install Terraform | Terraform - HashiCorp Learn Build Infrastructure– Providers
- Terraform releases are available on the Terraform website
- Homebrew tap contains the latest release as well
- Providers are requested via the
provider
block in the root module. terraform init
will download them- Can also define them in the
terraform
block withinrequired_providers
terraform {
required_providers {
aws = {
version = ">= 2.7.0"
source = "hashicorp/aws"
}
}
}
- No longer recommended to set the provider version at the
provider
block level - The name defined in the
required_providers
block is the local name of the provider, which theprovider
block refers to- You should try to use the preferred local name, which prefixes the resource names, unless necessary, to avoid confusion
Build Infrastructure | Terraform - HashiCorp Learn
- Plugin architecture where providers are downloaded and installed to allow access to various services
- Providers are installed during the
terraform init
phase - Plugins installed to the
.terraform
folder
Build Infrastructure | Terraform - HashiCorp Learn
- Define multiple
provider
blocks in the configurations to set them up - Define them all in
required_providers
block as well, just like when you define a single provider - Resource types are aligned to the specific providers, so automatically use the providers they come from
- Don’t forget about local names and how those relate to them
Provider Configuration - Configuration Language - Terraform by HashiCorp
Build Infrastructure | Terraform - HashiCorp Learn
- By default, Terraform will look to the Terraform Registry for providers
- However, you can define a source in the
required_providers
block to pull specific providers from certain locations - This is defined in the
source
parameter as described here - You also define the version constraint to select a specific version of the provider
terraform {
required_providers {
local_name = {
source = [<HOSTNAME>/]<NAMESPACE>/<TYPE>
version =
}
}
}
Provisioners - Terraform by HashiCorp
Cloud Init Provision Infrastructure with Packer | Terraform - HashiCorp Learn
- Provisioners are now considered a last resort for Terraform
- Instead, use infrastructure provisioning tools like Packer and cloud-init, user data or metadata, and other tooling like Chef, etc
- Provisioners require login rights to instances, which you really want to avoid for a reliable build and to remove direct network access to instances
- If you don’t have support in a provider, then that may be a good reason to use
local-exec
as a temporary workaround
Command: fmt - Terraform by HashiCorp
- Best to use
terraform fmt
when you’re writing code yourself - The canonical format can change between terraform versions, so you may need to re-run if upgrading
- Tools that generate Terraform configurations will generate it to this style, so it’s best to follow the canonical style where ever possible
Command: taint - Terraform by HashiCorp
taint
only impacts the state, it doesn’t modify the infrastructure until terraform is next applied- Might want to use taint to force a provisioner to run
- May cause other resources to rebuild if they are dependent upon it
- Could be good to use if some resource attributes are not seen by Terraform
4c. Given a scenario: choose when to use terraform import to import existing infrastructure into your Terraform state
Command: import - Terraform by HashiCorp
- Imports an existing resource into Terraform
- Useful when you have existing resources that you don’t want to or cannot rebuild at that point managed by Terraform
State: Workspaces - Terraform by HashiCorp
- This is discussing CLI workspaces, not Terraform Cloud/Enterprise Workspaces
- Remember; you’re using a single configuration with a single backend, but then slotting multiple states into that one backend
- Could be using feature branches to map to workspaces, for changes to infrastructure code
- Good for testing changes, so there is a primary workspace, with other workspaces for that testing
- Workspaces not great for avoiding tight coupling; system composition would be better done through a combination of strategies including separating your configurations out with clear boundaries
Command: state - Terraform by HashiCorp
- Use the
state
command instead of interrogating terraform state files directly where possible - Much safer to use than handling things manually where you can corrupt the files
- Can use it to manage and change state details of resources;
list
list resources within the state filemv
to move items around in the statepull
to download a remote statepush
to replace a remote statereplace-provider
to replace the provider for a specific resource in staterm
remove items from the state; will not remove the underlying resourceshow
show the attributes of an item within state
Debugging - Terraform by HashiCorp
- Use
TF_LOG
to set log levels, soTRACE, DEBUG, INFO, WARN or ERROR
TF_LOG_PATH
to push the log to a specific location- Good to provide logs in case of a bug within Terraform for error reporting
crash.log
will be written out on a panic error, doesn’t needTF_LOG
to be set
Finding and Using Modules from the Terraform Registry - Terraform by HashiCorp
Modules Overview | Terraform - HashiCorp Learn
- Modules can be sourced locally or from remote sources
- Can pull modules from the public Terraform repository or use private repositories
- Public modules can be listed as “verified” where HashiCorp has validated them
- Not actively maintained by HashiCorp themselves, but rater partners
- Local Paths, Terraform Registry, GitHub, BitBucket, Git/Mercurial, HTTP, S3 buckets, GCS buckets
- Good to use versioning where possible
- HTTP, GCS, S3 can pull down compressed files as well if supported versions
Use Modules from the Registry | Terraform - HashiCorp Learn
- Try using modules!
- Awareness of defined output and input variables, how to pass them into the modules themselves
Input Variables - Configuration Language - Terraform by HashiCorp Modules - Configuration Language - Terraform by HashiCorp
- Variables scoped within modules
- Have to explicitly pass them out from modules via outputs
Use Modules from the Registry | Terraform - HashiCorp Learn
Modules - Configuration Language - Terraform by HashiCorp
- Use the
version
parameter - If using VCS sources, you might have to set it within the
source
parameter instead
The Core Terraform Workflow - Guides - Terraform by HashiCorp
Build Infrastructure | Terraform - HashiCorp Learn
Command: init - Terraform by HashiCorp
Build Infrastructure | Terraform - HashiCorp Learn
Command: validate - Terraform by HashiCorp
Command: plan - Terraform by HashiCorp
Command: apply - Terraform by HashiCorp
Build Infrastructure | Terraform - HashiCorp Learn
Command: destroy - Terraform by HashiCorp
Destroy Infrastructure | Terraform - HashiCorp Learn
Backends - Terraform by HashiCorp Backend Type: local - Terraform by HashiCorp
- Defaults to writing the state out to file
- Uses system APIs to lock the state
- Can set the path
State: Locking - Terraform by HashiCorp
- Locks the state for all operations that could write
- Prevents others from locking the state and causing corruption
- Does not show a message if it happens
- Shows a message if the lock fails
- Can optionally disable locking, but not recommended
- If it takes time to find the lock, it will show a message
- Not all backends support locking; it is on a per-backend basis
- You can force-unlock a lock with the
terraform force-unlock
command- Requires the Lock ID which is shown during the lock failure error message
Backend: Supported Backend Types - Terraform by HashiCorp
- Different backends require different authentication methods, detailed in their documentation
- Typically, it’s specific to how the backend’s platform handles authentication;
- artifactory supports usernames and passwords
- azurerm (Azure Blob Storage) supports several different auth methods
- Managed Service Identity
- SAS Token
- Storage Account Access Key
- Service Principal with Client Certificate
- Service Principal with Client Secret
- consul supports username/password over Basic HTTP auth and certificate based auth
- cos (Tencent Object Storage) supports secret ID and key auth
- etc supports username/password auth
- etcdv3 supports username/password or certificate based auth
- gcs (Google Cloud Storage) supports JSON credentials or access tokens
- http supports HTTP basic username/password auth
- kubernetes uses secrets and supports HTTP basic username/password auth, certificate auth and service account tokens
- manta (Joyent Triton) supports private key based auth
- oss (Alibaba Object Storage Service with Cloud Table Store for locking) supports RAM roles, access keys, assumed roles and credential files
- pg (PostgreSQL) supports connection string auth
- s3 (AWS Simple Storage Service with DynamoDB for locking) requires IAM credentials
- swift (OpenStack) supports secret, token, certificate and username/password based auth
- remote (Terraform Cloud/Enterprise) backend supports token based auth
Backend: Supported Backend Types - Terraform by HashiCorp
Store Remote State | Terraform - HashiCorp Learn
Command: refresh - Terraform by HashiCorp
Backends: Configuration - Terraform by HashiCorp
Store Remote State | Terraform - HashiCorp Learn
- Partial configuration good for keeping secrets out of your configuration
- Keep them out of code storage
- No interpolations allowed in the backend configuration however!
- Pass in interactively, via a backend configuration file or via command line options when you want to hide secrets
State: Sensitive Data - Terraform by HashiCorp
- State file can hold sensitive data
- Therefore, treat the state as a whole like it is sensitive data
- Encrypt in transit and at reset
- Local state is plain text, so use remote state
Define Input Variables | Terraform - HashiCorp Learn Query Data with Output Variables | Terraform - HashiCorp Learn
variable "name" {
default = "value"
type = string
description = "What the variable is for"
validation {
condition = ""
error_message = ""
}
}
Inject secrets into Terraform using the Vault provider | Terraform - HashiCorp Learn
Type Constraints - Configuration Language - Terraform by HashiCorp
Resources - Configuration Language - Terraform by HashiCorp Data Sources - Configuration Language - Terraform by HashiCorp
Internals: Resource Address - Terraform by HashiCorp Expressions - Configuration Language - Terraform by HashiCorp
Functions - Configuration Language - Terraform by HashiCorp
Expressions - Configuration Language - Terraform by HashiCorp
dynamic "setting" {
for_each = var.settings
content {
foo = setting.value["foo"]
bar = setting.value["bar"]
}
Create Resource Dependencies | Terraform - HashiCorp Learn
Sentinel - Terraform Cloud and Terraform Enterprise - Terraform by HashiCorp Private Module Registry - Terraform Cloud and Terraform Enterprise - Terraform by HashiCorp Workspaces - Terraform Cloud and Terraform Enterprise - Terraform by HashiCorp
Why Policy as Code? HashiCorp Terraform Module Registry Terraform Enterprise Workspaces
State: Workspaces - Terraform by HashiCorp Workspaces - Terraform Cloud and Terraform Enterprise - Terraform by HashiCorp
Home - Terraform Cloud and Terraform Enterprise - Terraform by HashiCorp UI/VCS-driven Runs - Runs - Terraform Cloud and Terraform Enterprise - Terraform by HashiCorp
HashiCorp Terraform: Enterprise Pricing, Packages & Features