Installing Terraform and wiring up credentials
Install the CLI, authenticate to a cloud provider without putting keys in your code, and verify the whole chain works before you write a single resource.
Terraform is a single binary. The part that actually goes wrong is credentials, so we will verify those properly.
Install the CLI
macOS
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
Linux
wget -O- https://apt.releases.hashicorp.com/gpg | \
sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform
Windows
choco install terraform
Any platform — tfenv manages multiple versions, which you will want as soon as you have two
projects:
brew install tfenv
tfenv install 1.9.8
tfenv use 1.9.8
Verify:
terraform version
This guide was written against Terraform 1.x. Everything here also works with OpenTofu — swap
terraform for tofu.
Shell completion and an alias
terraform -install-autocomplete
Most people end up with:
alias tf=terraform
Credentials, without putting keys in your code
We will use AWS as the example. The principle is the same everywhere: the provider reads
credentials from the environment, never from your .tf files.
The right way: SSO
brew install awscli
aws configure sso
Follow the prompts, then:
export AWS_PROFILE=my-sso-profile
aws sts get-caller-identity
That last command is the verification. It should print your account id, user id and ARN. If it does, Terraform will authenticate too.
The acceptable way: a named profile
aws configure --profile myproject
export AWS_PROFILE=myproject
aws sts get-caller-identity
In CI: OIDC, not stored keys
GitHub Actions can assume an AWS role directly, with no long-lived secret to leak:
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/terraform
aws-region: us-east-1
Verify the whole chain
Create a throwaway directory and prove the full path works before you build anything real.
mkdir tf-verify && cd tf-verify
main.tf:
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
data "aws_caller_identity" "current" {}
output "account_id" {
value = data.aws_caller_identity.current.account_id
}
terraform init
terraform plan
init downloads the AWS provider. plan should print your account id without creating anything
— a data source only reads.
If that works, everything downstream will.
The gitignore you need immediately
# Local state — never commit this
*.tfstate
*.tfstate.*
.terraform/
.terraform.lock.hcl.backup
# Variable files that may contain secrets
*.tfvars
!example.tfvars
# Crash logs
crash.log
Next: state, resources and the concepts the rest of Terraform is built from.