This repository is for learning and educational purposes only.
It contains Terraform/OpenTofu scripts that create real resources, which may incur costs.
- Do not use this code in production environments.
- The resources are not configured for production security, reliability, or compliance.
- There is no warranty or guarantee of correctness, safety, or cost containment.
- Always review and understand the code before running it.
By using this repository, you acknowledge that you are responsible for any costs or impacts resulting from its execution.
→ brew install opentofu
It’s adviced to also install the OpenTofu plugin if you are using VSCode.
→ vim main.tf
→ tofu init
Don’t forget to add the relevant files to your .gitignore
file, as described here.
→ tofu providers
Providers required by configuration:
.
└── provider[registry.opentofu.org/hashicorp/aws] ~> 6.0
Get the latest ARM-based Amazon Linux 2023 AMI version using the AWS CLI like this:
→ aws ec2 describe-images \
--owners amazon \
--filters "Name=name,Values=al2023-*-arm64" "Name=state,Values=available" \
--query 'Images | sort_by(@, &CreationDate)[-1]' \
--output table
Get a matching instance type eligible for the free tier using the AWS CLI like this:
→ aws ec2 describe-instance-types \
--filters "Name=processor-info.supported-architecture,Values=arm64" \
"Name=free-tier-eligible,Values=true" \
--query 'InstanceTypes[*].InstanceType' \
--output table
Now we can plan and apply the plan and check the state afterwards:
→ cat > my.tfvars <<EOF
name_prefix = "opentofu-first-steps"
ssh_key = "~/.ssh/id_ed25519.pub"
EOF
→ tofu plan -var-file my.tfvars
→ tofu apply -var-file my.tfvars
→ tofu state list
→ tofu state show aws_instance.example
With the outputs.tf
in place, we can run tofu refresh
and see the output of the instance ARN.
In case you want to recreate the instance, you can use tofu taint
as follows:
→ tofu taint aws_instance.example
→ tofu apply -var-file my.tfvars [-auto-approve]
Hint: SSH into the EC2 instance and check /var/log/cloud-init-output.log
to see if there was any error during the setup.
Finally, clean up.
→ tofu destroy -var-file my.tfvars [-auto-approve]
→ tofu init
→ tofu providers
Providers required by configuration:
.
├── provider[registry.opentofu.org/hashicorp/azurerm] ~> 4.0
├── provider[registry.opentofu.org/hashicorp/aws] ~> 6.0
└── module.aws_instance
└── provider[registry.opentofu.org/hashicorp/aws]
→ az login --use-device-code
→ az account show --query id --output tsv
→ cat >> my.tfvars <<EOF
subscription_id = "$(az account show --query id --output tsv)"
EOF
→ az account list | jq
→ az account list-locations | jq -r '. | sort_by(.name) | .[].name'
→ az account list-locations | jq -r '.[] | select(.name=="westeurope")'
→ az vm image list-offers --location westeurope \
--publisher Canonical --output table
→ az vm image list-skus --location westeurope \
--publisher Canonical --offer ubuntu-24_04-lts --output table
→ az vm image list --location westeurope \
--publisher Canonical --offer ubuntu-24_04-lts --sku server \
--all --output table
Have a look at https://az-vm-image.info/
→ tofu plan -target=module.azure_vm -var-file my.tfvars
→ tofu apply -target=module.azure_vm -var-file my.tfvars
Finally, clean up.
→ tofu destroy -target=module.azure_vm -var-file my.tfvars [-auto-approve]
→ tofu init
→ tofu providers
Providers required by configuration:
.
├── provider[registry.opentofu.org/hashicorp/azurerm] ~> 4.0
├── provider[registry.opentofu.org/hashicorp/google] ~> 6.0
├── provider[registry.opentofu.org/hashicorp/aws] ~> 6.0
├── module.aws_instance
│ └── provider[registry.opentofu.org/hashicorp/aws]
├── module.azure_vm
│ └── provider[registry.opentofu.org/hashicorp/azurerm]
└── module.google_vm
└── provider[registry.opentofu.org/hashicorp/google]
→ gcloud auth login
→ gcloud auth list
→ # create project
→ gcloud projects create opentofu-first-steps
→ gcloud projects list
→ gcloud config set project opentofu-first-steps
→ gcloud config list
→ # create service account and key pair
→ gcloud iam service-accounts create opentofu-first-steps-vm-sa \
--description="Service account for VM access" \
--display-name="opentofu-first-steps-service-account"
→ gcloud iam service-accounts list
→ gcloud iam service-accounts keys list \
--iam-account opentofu-first-steps-vm-sa@opentofu-first-steps.iam.gserviceaccount.com
→ # this creates and downloads a key pair as `key.json`
→ gcloud iam service-accounts keys create key.json \
--iam-account opentofu-first-steps-vm-sa@opentofu-first-steps.iam.gserviceaccount.com
→ # grant least-privilege access to service account
→ gcloud projects add-iam-policy-binding opentofu-first-steps \
--member="serviceAccount:opentofu-first-steps-vm-sa@opentofu-first-steps.iam.gserviceaccount.com" \
--role="roles/compute.instanceAdmin.v1"
→ gcloud projects add-iam-policy-binding opentofu-first-steps \
--member="serviceAccount:opentofu-first-steps-vm-sa@opentofu-first-steps.iam.gserviceaccount.com" \
--role="roles/compute.networkAdmin"
→ gcloud projects add-iam-policy-binding opentofu-first-steps \
--member="serviceAccount:opentofu-first-steps-vm-sa@opentofu-first-steps.iam.gserviceaccount.com" \
--role="roles/iam.serviceAccountUser"
→ cat >> my.tfvars <<EOF
project_id = "opentofu-first-steps"
EOF
→ # link billing account to project in order to be able to enable Compute API
→ gcloud billing accounts list
→ gcloud billing projects link opentofu-first-steps --billing-account <BILLING-ACCOUNT-ID>
→ gcloud billing projects describe opentofu-first-steps
→ # enable Compute API
→ gcloud services enable compute.googleapis.com --project opentofu-first-steps
→ gcloud services list --enabled --project opentofu-first-steps
→ # get regions
→ gcloud compute regions list --format="value(name)"
→ # get machine types matching `micro` in all zones of region `us-central1`
→ for z in $(gcloud compute zones list --filter="region:(us-central1)" --format="value(name)"); do
echo "Zone: $z"
gcloud compute machine-types list --zones=$z --format="value(name)" --filter="name~'micro'"
done
We will use e2-micro
in us-central1
as this is the free-tier eligible combination.
→ tofu plan -target=module.google_vm -var-file my.tfvars
→ tofu apply -target=module.google_vm -var-file my.tfvars
Finally, clean up.
→ tofu destroy -target=module.google_vm -var-file my.tfvars [-auto-approve]