While running Terraform in the Cloud Shell is the easiest way to run Terraform, most developers prefer to edit and develop code on their own machine in their local environment.
Terraform provides an easy way to do this. First, install Terraform on your computer. Terraform is available on most platforms, including Linux, macOS, and Windows. To install Terraform, please go to https://developer.hashicorp.com/terraform/downloads and follow the installation instructions for your environment.
In this book, we use Terraform on Ubuntu, but the code and the principles are the same regardless of the operating system.
You also require the Google Cloud CLI: gcloud
. So, if you have not already installed it, please go ahead and do so. To see whether you have successfully installed both, run these commands in your preferred shell on your local machine:
$ gcloud --version
$ terraform –version
Once you have successfully installed both gcloud
and Terraform, you need to authenticate Terraform against the Google Cloud project you are using.
Authentication using a service account
Note
The code for this section is in chap01/key-file
.
There are several ways to authenticate Terraform with Google Cloud. The first is using a service account. For this, you create a service account and download a key file.
You can create a service account and download the key file interactively using the web console or the following gcloud
commands. If you haven’t authenticated against Google Cloud in your shell, please do so now using the gcloud auth
login
command.
Please note that for simplicity’s sake, we have given the Terraform service account the broad role of editor. This is not recommended as it violates the security principle of least privilege. You need to replace <PROJECT_ID>
with the ID of your Google Cloud project:
$ gcloud auth login --no-launch-browser
$ gcloud config set project "<PROJECT_ID>"
$ gcloud iam service-accounts create terraform \
--description="Terraform Service Account" \
--display-name="terraform"
$ export GOOGLE_SERVICE_ACCOUNT=`gcloud iam service-accounts \
list --format="value(email)" --filter=name:"terraform@"`
$ export GOOGLE_CLOUD_PROJECT=`gcloud info \
--format="value(config.project)"`
$ gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
--member="serviceAccount:$GOOGLE_SERVICE_ACCOUNT" \
--role="roles/editor"
$ gcloud iam service-accounts keys create "./terraform.json" \
--iam-account=$GOOGLE_SERVICE_ACCOUNT
Once you have a key file, you can reference it in your Terraform configuration using the provider declaration.
As we mentioned, Terraform does not care about filenames. It combines all files with the .tf
extension and then creates an execution plan using all the configurations. However, while Terraform doesn’t care about filenames, humans do. As one of the objectives of IaC is to share and reuse code, there are commonly adopted file naming conventions. We use those conventions throughout the book.
The convention is to place the provider declaration in a file called provider.tf
. We mentioned earlier that Terraform supports several cloud providers and other infrastructure tools. It does so by using the concept of a provider. A provider is a translation layer between Terraform and the external API of the provider. When you run Terraform, it translates your configuration code into API calls that interact with the provider—in this case, Google Cloud. If you run Terraform with the AWS provider, it generates AWS API calls.
This is also the reason that while Terraform works with all cloud providers, each configuration file is specific to a particular cloud provider. You cannot use the same code to provision a Google Cloud and an AWS VM. However, the principles of developing and managing Terraform code and the workflow are similar for all cloud providers. Thus, if you have mastered Terraform for Google Cloud, you can use that knowledge to learn Terraform for AWS and Azure.
The Google provider has several optional attributes. The most commonly used attributes are project, region, and zone, which specify the default project
, region
, and zone
. So, the provider file for our example using the credentials file in the current directory looks like this:
Note
You need to replace <PROJECT_ID>
with the project ID of your Google Cloud project.
provider.tf
provider "google" {
project = <PROJECT_ID>
region = "us-central1"
zone = "us-central1-c"
credentials = "./terraform.json"
}
Thus, you can now run the Terraform workflow on your local computer, like so:
$ terraform init
$ terraform apply
Service account keys are very powerful in Google Cloud and must be treated carefully. Thus, we do not recommend including a reference to the credentials and—particularly—storing the key file in the local directory. It is easy to accidentally include the key file in your source code, where it can leak. It also makes the code less portable.
Authentication using a service account and environment variable
Note
The code for this section is in chap01/environment-variable
.
A better way is to store the key content in an environment variable, which can, in turn, be stored more securely (for example, via envchain
) than plaintext key files on disk, as can be seen in the following command:
$ export GOOGLE_CREDENTIALS=`cat ../key-file/terraform.json`
Using an environment variable has the added benefit of making your Terraform code more portable, as it does not include the authentication method in the Terraform code.
Service account impersonation
Note
The code for this section is in chap01/service-account-impersonation
.
A third method is to use service account impersonation. This Google Cloud concept lets users act as or impersonate a service account. To use service account impersonation, you first need to allow you, the user, the Identity and Access Management (IAM) role of Service Account Token Creator (roles/iam.serviceAccountTokenCreator
). Please note that this role is not enabled by default, even for a project owner, so you have to add that IAM role explicitly.
Second, set the GOOGLE_IMPERSONATE_SERVICE_ACCOUNT
environment variable to the Terraform service account we created in the previous section. Ensure that the GOOGLE_APPLICATION_CREDENTIALS
environment variable is NOT set.
Next, acquire the user credentials to use for Application Default Credentials (ADC) using the following command:
$ gcloud auth application-default login
These are credentials that Terraform uses to impersonate the service account and perform other actions on behalf of that service account using the IAM permission of that service account. Please note that this is a separate authentication from the Google platform credentials (gcloud
auth login
).
As we mentioned, service account keys must be handled with care, thus it is better to delete them if they are not in use. Thus, here is the complete code to impersonate the service account and clean up the environment:
# Delete unused credentials locally
$ unset GOOGLE_CREDENTIALS
# Delete previously issued keys
$ rm ../key-file/terraform.json
$ gcloud iam service-accounts keys list \
--iam-account=$GOOGLE_ SERVICE_ACCOUNT
$ gcloud iam service-accounts keys delete \
<SERVICE ACCOUNT_ID> --iam-account=$GOOGLE_SERVICE_ACCOUNT
# Set up impersonation
$ export GOOGLE_IMPERSONATE_SERVICE_ACCOUNT=\
`gcloud iam service-accounts list --format="value(email)" \
--filter=name:terraform`
$ gcloud auth application-default login --no-launch-browser
$ export USER_ACCOUNT_ID=`gcloud config get core/account`
$ gcloud iam service-accounts add-iam-policy-binding \
$GOOGLE_IMPERSONATE_SERVICE_ACCOUNT \
--member="user:$USER_ACCOUNT_ID" \
--role="roles/iam.serviceAccountTokenCreator"
$ export GOOGLE_CLOUD_PROJECT=`gcloud info \ --format="value(config.project)"`
While this may look tedious, you only need to do it once. Using impersonation makes the code more portable and more secure, as it does not rely on service account keys and does not specify the authentication method in your configuration files. Please note that it might take a couple of minutes for the added IAM role to become effective. But once it is effective, run the following command:
$ terraform apply
Now that we have shown different ways to authenticate Terraform to Google Cloud and created a simple server, let’s provision something more useful. But before we move to the next section, don’t forget to destroy the server by running the following command:
$ terraform destroy