Install Terraform with tfenv
Tags: terraform, devops, infrastructureascode, linux
Published: 2023-01-15 18:36:35




![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/splvh7lxc41upuigwrky.png)

There will come a time when you will need to change to different versions of [Terraform](https://www.terraform.io/).  Similar to tools like `rbenv` for [Ruby](https://www.ruby-lang.org) or `pyenv` for [Python](https://www.python.org/), there's a popular tool used to install different versions of [Terraform](https://www.terraform.io/) called `tfenv`.

Most tooling for infrastructure operations runs on Intel processors, called the `amd64` architecture with in [Terraform](https://www.terraform.io/), but given the recent addition of Macbook M1 laptops, the architecture is `arm64`.  Older versions of [Terraform](https://www.terraform.io/) that may be needed will require installing [Terraform](https://www.terraform.io/) that is only available on Intel processors (`amd64` binaries).  This can be installed using `tfenv` as well.

This article will have cover the following sections:

1. Installing `tfenv` on Ubuntu (`linux`) and mac OS (`darwin`)
2. Installing a latest or recent version of [Terraform](https://www.terraform.io/)
3. Installing legacy versions of [Terraform](https://www.terraform.io/) on macOS with Arm processor (Macbook M1/M2)
4. Installing Legacy providers plugins (Ubuntu and Macbook M1/M2)

# Installing tfenv

Here's how you can install `tfenv` on Ubuntu (`linux`) or mac OS (`darwin`).

## Installing tfenv on Ubuntu 

```bash
git clone https://github.com/tfutils/tfenv.git ${HOME}/.tfenv
export PATH="${HOME}/.tfenv/bin:${PATH}"
# install to appropriate shell startup file, e.g. $HOME/.bashrc
echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ${HOME}/.profile
```

## Installing tfenv on mac OS

```bash
brew install tfenv
```

# Installing Terraform

Once `tfenv` is installed and available in the path, you can simply run something like this:

```bash
tfenv install 1.3.7
```

Using `tfenv list-remote` you can fetch different versions of [Terraform](https://www.terraform.io/) that are available for installation.  From there, you can use [GNU grep](https://www.gnu.org/software/grep/) to select the desired version.  For example, here's how to install the latest version:

```bash
LATEST_VERSION=$(tfenv list-remote \
 | grep -vP '\d.\d{0,2}.\d{0,2}-.*' \
 | head -1
)

tfenv install ${LATEST_VERSION}
```

**NOTE**: On macOS, which has BSD flavor `grep`, it doesn't support [PCRE](https://www.pcre.org/).  To get [GNU Grep](https://www.gnu.org/software/grep/) with support for [PCRE](https://www.pcre.org/), use `brew install grep`. 

You can extract the last minor version by passing in an explicit major version to [GNU Grep](https://www.gnu.org/software/grep/):

```bash
# find latest 0.12
LATEST_0_12=$(tfenv list-remote  \
 | grep -oP '^0.12.\d{1,2}' \
 | sort --version-sort \
 | tail -1
)

tfenv install ${LATEST_0_12}
```

For the latest version, whatever that is, you can also just run the following: 

```bash
tfenv install latest
```

# Using the desired Terraform version

When you want to use the a particular version of an installed version `terraform`, you can select it with the following:

```bash
tfenv use 1.3.7
```

Also, to have the [Terraform](https://www.terraform.io/) switch automatically when navigating to the project directory, you can place a `.terraform-version` to auto-select the version:

```bash
mkdir -p  ${HOME}/my_project/.terraform-version
echo '1.3.7' > ${HOME}/my_project/.terraform-version

# change version of Terraform automatically
cd ${HOME}/my_project/.terraform-version
```

# Installing Legacy x64 versions on Mac

If you Macbook sports a arm64 processor, you need to get [Rosetta](https://support.apple.com/en-us/HT211861) to run `amd64` binaries on macOS.  Afterward, you can follow these steps below to install legacy versions of `terraform`. 

```bash
export TFENV_ARCH="amd64"

# install amd64 terrafrom version since there are no arm64 binaries
tfenv install 0.12.31
tfenv use 0.12.31
```

# Installing Legacy providers

In recent versions of [Terraform](https://www.terraform.io/), this installation will happen automatically when you run `terraform init`

First, you need to find the appropriate plugin version that matches the supported version of [Terraform](https://www.terraform.io/).  In the case of `terraform-provider-kubectl`, you need to install `1.11.2` of that version of that plugin.

## Installing legacy provider on Ubuntu Linux

```bash
ARCH="linux_amd64"
VERS="1.11.2"
PKG="terraform-provider-kubectl_${VERS}_${ARCH}.zip"
REPO="gavinbunney/terraform-provider-kubectl"
URL="https://github.com/${REPO}/releases/download/v${VERS}/${PKG}"

# setup plugins directory if this does not exist already
mkdir -p ${HOME}/.terraform.d/plugins/${ARCH}/

# download archive and install plugin
pushd ${HOME}/Downloads
curl -sOL ${URL}
unzip ${PKG} && rm README.md LICENSE
mv terraform-provider-kubectl_v${VERS} \
  ${HOME}/.terraform.d/plugins/${ARCH}/
popd
```

## Installing legacy provider on Macbook M1

For current Macbooks running the arm64 processor, you will need to install the legacy provider for amd64 (not arm64).  This is how you can do that.  

```bash
ARCH="darwin_amd64" # install amd64 plugin for legacy terraform 
VERS="1.11.2"
PKG="terraform-provider-kubectl_${VERS}_${ARCH}.zip"
REPO="gavinbunney/terraform-provider-kubectl"
URL="https://github.com/${REPO}/releases/download/v${VERS}/${PKG}"

# setup plugins directory if this does not exist already
mkdir -p $HOME/.terraform.d/plugins/${ARCH}/

# download archive
pushd ${HOME}/Downloads
curl -sOL ${URL}
unzip ${PKG} && rm README.md LICENSE
mv terraform-provider-kubectl_v${VERS} \
  ${HOME}/.terraform.d/plugins/${ARCH}/
popd
```

# Conclusion

I hope this is useful to your [Terraform](https://www.terraform.io/) adventures.  The reason why locking down versions of [Terraform](https://www.terraform.io/) is important, is that there are significant language changes that make the code incompatible.  The installer dependency chain with [Terraform](https://www.terraform.io/) modules and providers will need to match the target version of the `terraform` command.  

In addition to this, the state that is generated from interacting with the provider will likely need to match, so it is important that the infrastructure that created with a particular version of [Terraform](https://www.terraform.io/), also be removed when ultimately `terraform destroy` is used.

As the infrastructure progresses forward, there are techniques you can use to smoothly transition.  One method it to have modular modules that depend on looking up the state in the cloud through data sources, and important existing infrastructure into the state using `terraform import`.  This is definitely material for a future article.

In the meantime, you can use the supported version with tools like `tfenv`.  Another tool, as an alternative to `tfenv` is [asdf](https://asdf-vm.com/).  I have not explored supported legacy amd64 legacy binaries on Macbook M1 yet, but assume this can work.  The [asdf](https://asdf-vm.com/) is nice in that it has a plugin architecture to support a variety of languages.

Lastly, about this article, which I am sure might unnerve shell purists, where I use `$HOME` instead of `~` and I use of curly braces for `${VARIABLES}`, when they are not needed, when simply `$VARIABLE` is preferred: this was done intentionally to make the variables light up in color syntax highlighters on different platforms, and `$HOME` was used for novice uses that may not be familiar with `~` notation.