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 opentofuIt’s adviced to also install the OpenTofu plugin if you are using VSCode.
→ vim main.tf
→ tofu initDon’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.0Get 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 tableGet 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 tableNow 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.exampleWith 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 tableHave 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.tfvarsFinally, 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'"
doneWe 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.tfvarsFinally, clean up.
→ tofu destroy -target=module.google_vm -var-file my.tfvars [-auto-approve]