Moving Your Terraform State to Terraform Cloud

I run my practice labs on a number of tier 1 and tier 2 cloud providers. While Terraform can store my state on any S3 compatible bucket, some providers makes it difficult to setup, if not impossible. This is how I get around it by storing my state on Terraform Cloud.

First, I sign up for the account here, which, as of this time of writing is free for personal use. Next, I create my workspace:

![create workspace terraform]({static}/images/create_workspace_tf.png)

After I created my workspace (in this case, scaleway-cka):

![click on workspace]({static}/images/click_on_workspace_tf.png)

I click on NO VCS button:

![No VCS]({static}/images/no_vcs_tf.png)

Then on the right, I click on settings and then general:

![No VCS]({static}/images/general_tf.png)

Finally, I have the choice between remote or local. It is just me working with my terraform code, so I picked local:

![local file]({static}/images/local_tf.png)

Now I am done, so the next step is to perform the actual migration. First, I created a branch off my terraform code (I am not a barbarian, after all):

 git checkout -b move_scaleway_local_to_terraform_cloud

Next, I created a backend.tf file in the main terraform module directory:

terraform {
  backend "remote" {
    hostname = "app.terraform.io"
    organization = "monzell"

    workspaces {
      name = "scaleway-cka"
    }
  }
}

Then, I login into my Terraform cloud account:

terraform login

It prompted me to configure my terraform cloud credentials:

Terraform will request an API token for app.terraform.io using your browser.

If login is successful, Terraform will store the token in plain text in
the following file for use by subsequent commands:
    /Users/rilindo/.terraform.d/credentials.tfrc.json

Do you want to proceed? (y/n) y

I say y for yes and terraform follows up with the prompt to enter the token:

Terraform must now open a web browser to the tokens page for app.terraform.io.

If a browser does not open this automatically, open the following URL to proceed:
    https://app.terraform.io/app/settings/tokens?source=terraform-login


---------------------------------------------------------------------------------

Generate a token using your browser, and copy-paste it into this prompt.

Terraform will store the token in plain text in the following file
for use by subsequent commands:
    /Users/rilindo/.terraform.d/credentials.tfrc.json

Token for app.terraform.io:

And at the same time, bring up the following screen in my browser:

![scaleway token]({static}/images/scaleway_token_tf.png)

I generated my token and pasted it back into terminal token prompt, which allowed me to successfully configure my credentials on my machine.

Retrieved token for user rilindo


---------------------------------------------------------------------------------

Success! Terraform has obtained and saved an API token.

The new API token will be used for any future Terraform command that must make
authenticated requests to app.terraform.io.

Now I am ready to build. First, I re-initialize my terraform configuration with terraform init.

terraform init

Initializing modules...

Initializing the backend...

Successfully configured the backend "remote"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.template: version = "~> 2.1"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Then I created my terraform plan:

terraform plan -out=terraform.tfplan \
>   -var "domain_name=${DOMAIN_NAME}" \
>   -var "public_key=${PUBLIC_KEY}" \
>   -var "sw_ns1=${SW_NS1}" \
>   -var "sw_org_id=${SW_ORG_ID}" \
>   -var "src_ip=${SRC_IP}" \
>   -var "sw_access_key=${SW_ACCESS_KEY}" \
>   -var "sw_secret_key=${SW_SECRET_KEY}"

After reviewing my output:

Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

module.cp01.data.scaleway_instance_image.image: Refreshing state...

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create
 <= read (data resources)

Terraform will perform the following actions:

  # module.cp01.data.template_file.custom_user_data will be read during apply
  # (config refers to values not yet known)
 <= data "template_file" "custom_user_data"  {
      + id       = (known after apply)
      + rendered = (known after apply)
      + template = <<~EOT
            #!/bin/bash

            yum check-update
            yum install -y NetworkManager git epel-release
            hostnamectl set-hostname "${node_name}.${domain_name}"
        EOT
      + vars     = {

.
.
.
.
# module.zone.ns1_zone.domain_name will be created
+ resource "ns1_zone" "domain_name" {
    + autogenerate_ns_record = true
    + dns_servers            = (known after apply)
    + dnssec                 = (known after apply)
    + expiry                 = (known after apply)
    + hostmaster             = (known after apply)
    + id                     = (known after apply)
    + networks               = (known after apply)
    + nx_ttl                 = (known after apply)
    + refresh                = (known after apply)
    + retry                  = (known after apply)
    + ttl                    = 600
    + zone                   = "reverseblade.org"
  }

Plan: 6 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

This plan was saved to: terraform.tfplan

To perform exactly these actions, run the following command to apply:
  terraform apply "terraform.tfplan"

Finally, I went ahead and apply my configuration:

terraform apply "terraform.tfplan"

Back in my Terraform cloud screen, I could see that my workspace is locked:

![workspace lock]({static}/images/terraform_workspace_locked_tf.png)

And when it is done in my terminal:

module.cp01.data.scaleway_instance_image.image: Refreshing state...
module.zone.ns1_zone.domain_name: Creating...
module.cp01_scaleway_instance_ip.scaleway_instance_ip.ip: Creating...
module.ssh_key.scaleway_account_ssh_key.public: Creating...
module.scaleway_security_group.scaleway_instance_security_group.external: Creating...
module.zone.ns1_zone.domain_name: Creation complete after 2s [id=5ee1824015dbdd0091efa8b2]
module.cp01.data.template_file.custom_user_data: Refreshing state...
module.ssh_key.scaleway_account_ssh_key.public: Creation complete after 1s [id=f8f89569-6e52-4a25-986c-57104006a74b]
module.cp01_scaleway_instance_ip.scaleway_instance_ip.ip: Creation complete after 1s [id=fr-par-1/4a5870f2-9989-4e11-a4fc-1fcebbe7c9b1]
module.cp01_record.ns1_record.www: Creating...
module.cp01_record.ns1_record.www: Creation complete after 2s [id=5ee182436711b3008b1e6d80]
module.scaleway_security_group.scaleway_instance_security_group.external: Creation complete after 5s [id=fr-par-1/284ebb7b-7101-47cd-a781-8894ccddad6e]
module.cp01.scaleway_instance_server.instance: Creating...
module.cp01.scaleway_instance_server.instance: Still creating... [10s elapsed]
module.cp01.scaleway_instance_server.instance: Still creating... [20s elapsed]
module.cp01.scaleway_instance_server.instance: Still creating... [30s elapsed]
module.cp01.scaleway_instance_server.instance: Creation complete after 33s [id=fr-par-1/a23efeab-13e8-4609-a2a2-c8f0ecfaafcd]

Apply complete! Resources: 6 added, 0 changed, 0 destroyed.

I can see a new state entry under states, indicating that I either created or updated my state:

![workspace lock]({static}/images/terraform_state_tf.png)

And that is about it.

So far, I liked the Terraform Cloud. I could already see the benefits of using it visually tracking my activity and managing the state through an easy to use UI. If I were part of a larger team using Terraform, I would recommend moving to Terraform cloud, as it removes the need to manage the state manually. I give it a thumbs up.

(in other news, I really need to not rely on the <center> tag for my images)