Trabalhandom com HCP Terraform
O terraform possui o que chamamos de workspaces dentro da própria CLI. A grande diferença entre workspaces é a utilização do mesmo código em diferentes aplicações passando uma entrada de variável diferente.
Vamos imaginar que temos um código que irá criar uma vpc chamada vpc-main. Criamos um workspace1 com o comando terraform workspace create .... Aplicamos o código e ele esta pagando os valores para as variáveis que definimos em variables.tf.
Se criarmos um workspace2 e aplicarmos novamente, ele tentará criar com as mesmas variáveis na mesma região a mesma vpc e encontrará com conflito. Para que isso fosse possível precisamos definir as entradas das variáveis mudando esses valores.
A idéia do workspace é isolar ambientes dentro do mesmo código.
No HCP Terraform workspace trabalha diferente. Workspace representa um projeto terraform, um conjunto de código que será aplicado com entradas de variáveis. Seria como o código e suas entradas e mais nada.
Se queremos aplicar o mesmo código com entradas diferentes é necessário copiar o projeto para outra pasta ou referenciar outra branch. Veremos mais pra frente.
O workspace contêm suas definições de recursos, variáveis de ambiente e de entrada e arquivos de estado. Uma operação do Terraform ocorre dentro de um workspace, e o Terraform usa a configuração e o estado desse workspace para modificar sua infraestrutura.
Fluxo de Trabalho
- Podemos aplicar um código via CLI localmente mesmo usando o HCP Terraform.
- Podemos aplicar um código por alteração de código em um repositório.
- Podemos aplicar um código utilizando a API do HCP.
Usando a CLI
Obviamente o binário do terraform precisa estar instalado no sistema e no Path. Para fazer login vamos executar os comandos abaixo
#Rodando esse comando automaticamente irá direcionar para o HCP Terraform que você precisará se logar. Nesse ponto ele ja define nas credenciais a organização que você criou.
terraform login
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/davidprata/.terraform.d/credentials.tfrc.json
Do you want to proceed?
Only 'yes' will be accepted to confirm.
Enter a value: yes # Tem que digitar
---------------------------------------------------------------------------------
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/davidprata/.terraform.d/credentials.tfrc.json
Token for app.terraform.io:
Enter a value: # Cole o token gerado aqui.
#....
Então vamos já esta logado e pronto para executar operações remotamente. Na plataform o próprio token já define quem é a organização e o usuário.
Variables Sets
O HCP Terraform permite:
- Definir variáveis de entrada e ambiente usando variáveis específicas do workspace.
- Definir conjuntos de variáveis que você pode reutilizar em vários workspaces por exemplo credenciais de provedor (AWS, GCP, etc)
Os conjuntos de variáveis permitem que você evite redefinir as mesmas variáveis em todos os workspaces, para que você possa padronizar configurações comuns em toda a sua organização.
Ao definir um conjunto de variáveis para suas credenciais, você pode reutilizar facilmente as mesmas variáveis em vários workspaces e rotacionar suas credenciais de forma eficiente e segura.
Por exemplo, vamos criar um conjunto de variáveis para a AWS.
Podemos definir:
- variáveis de entrada, valores para variáveis usadas na configuração dentro do código.
- variáveis de ambiente, geralmente utilizados para credenciais ou modificar o comportamento do terraform (nível de log)
Você pode aplicar um conjunto de variáveis a todos os workspace na sua organização ou defini-lo como escopo para workspaces ou projetos específicos.
Evite o escopo global, pois ele não segue as melhores práticas de privilégios mínimos. Vamos fazê-lo aqui para fins de estudo.

Aqui estamos definindo uma variável de ambiente. Quando o terraform rodar, ele rodará em um runner (container provavelmente) e essa variável será carregada no terminal sempre.


Marcar uma variável como sensível impede que o Terraform a exiba na interface do usuário do HCP Terraform e torna a variável somente gravação.
Por fim marque o Create variable set ao final da página.

Para definir variáveis em um workspace vamos primeiro aprender como criar um workspace.
Workspaces
Pela própria cli criamos workspaces dentro do HCP Terraform.
Vamos baixar um projeto simples do terraform que somente criar uma ec2 na aws.
git clone [email protected]:hashicorp-education/learn-terraform.git
cd learn-terraform
tree
.
├── LICENSE
├── README.md
├── main.tf # Recurso da ec2
├── outputs.tf # saidas
├── terraform.tf # O que nos interessa
└── variables.tf # Variávei usadas
Fiz uma alteração na organização apontando para a organização que eu criei para estudo.
cat terraform.tf
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0
terraform {
cloud {
organization = "davidpuziol" # Nome da organização que criamos
workspaces {
name = "learn-terraform" # Nome do workspace que será criado
}
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.31.0"
}
}
required_version = "~> 1.2"
}
Quando executarmos o terraform init, o state da aplicação deste código estará indo direto para o HCP Terraform no workspace apontado. Claro que temos que estar logado anteriormente com o terraform login.
terraform init
Initializing HCP Terraform... # <<<<
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Installing hashicorp/aws v5.31.0...
- Installed hashicorp/aws v5.31.0 (signed by HashiCorp)
HCP Terraform has been successfully initialized!
You may now begin working with HCP Terraform. Try running "terraform plan" to
see any changes that are required for your infrastructure.
If you ever set or change modules or Terraform Settings, run "terraform init"
again to reinitialize your working directory.
E o que temos ?

E nesse mesmo workspace o que temos de variável lá? Variáveis da AWS herdadas pois são de escopo global.

Uma coisa que é importante mensionar
Variáveis definidas dentro de um workspace sempre substituem variáveis de conjuntos de variáveis que têm o mesmo tipo e a mesma chave.
Ou seja, se criar a mesma variável aqui mas mudando o valor ela sobreescreverá a global. Vamos criar para testar.

Não tenho essa variáveis setadas na minha máquina, na hora do plan ele usou a variável definida no HCP Platform
terraform plan
Running plan in HCP Terraform. Output will stream here. Pressing Ctrl-C
will stop streaming the logs, but will not stop the plan running remotely.
Preparing the remote plan...
To view this run in a browser, visit:
https://app.terraform.io/app/davidpuziol/learn-terraform/runs/run-8BtvJdw1B2CzAZYc
Waiting for the plan to start...
Terraform v1.10.3
on linux_amd64
Initializing plugins and modules...
data.aws_ami.ubuntu: Refreshing...
data.aws_ami.ubuntu: Refresh complete after 1s [id=ami-03420c5d8fd979bd3]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.ubuntu will be created
+ resource "aws_instance" "ubuntu" {
+ ami = "ami-03420c5d8fd979bd3"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ disable_api_stop = (known after apply)
+ disable_api_termination = (known after apply)
+ ebs_optimized = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ host_resource_group_arn = (known after apply)
+ iam_instance_profile = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
+ instance_lifecycle = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "t2.micro"
+ ipv6_address_count = (known after apply)
+ ipv6_addresses = (known after apply)
+ key_name = (known after apply)
+ monitoring = (known after apply)
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
+ placement_partition_number = (known after apply)
+ primary_network_interface_id = (known after apply)
+ private_dns = (known after apply)
+ private_ip = (known after apply)
+ public_dns = (known after apply)
+ public_ip = (known after apply)
+ secondary_private_ips = (known after apply)
+ security_groups = (known after apply)
+ source_dest_check = true
+ spot_instance_request_id = (known after apply)
+ subnet_id = (known after apply)
+ tags = {
+ "Name" = "Provisioned by Terraform"
}
+ tags_all = {
+ "Name" = "Provisioned by Terraform"
}
+ tenancy = (known after apply)
+ user_data = (known after apply)
+ user_data_base64 = (known after apply)
+ user_data_replace_on_change = false
+ vpc_security_group_ids = (known after apply)
+ capacity_reservation_specification (known after apply)
+ cpu_options (known after apply)
+ ebs_block_device (known after apply)
+ enclave_options (known after apply)
+ ephemeral_block_device (known after apply)
+ instance_market_options (known after apply)
+ maintenance_options (known after apply)
+ metadata_options (known after apply)
+ network_interface (known after apply)
+ private_dns_name_options (known after apply)
+ root_block_device (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ instance_ami = "ami-03420c5d8fd979bd3"
+ instance_arn = (known after apply)
------------------------------------------------------------------------
Cost Estimation:
Resources: 1 of 1 estimated
$8.6304/mo +$8.6304
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
Se definirmos uma variável dentro do workspace que temos setada dentro de variables.tf irá substituir?
variable "instance_type" {
description = "Type of EC2 instance to provision"
default = "t2.micro"
}

terraform plan
Running plan in HCP Terraform. Output will stream here. Pressing Ctrl-C
will stop streaming the logs, but will not stop the plan running remotely.
Preparing the remote plan...
To view this run in a browser, visit:
https://app.terraform.io/app/davidpuziol/learn-terraform/runs/run-HeS6JZ7mAddgJt2r
Waiting for the plan to start...
Terraform v1.10.3
on linux_amd64
Initializing plugins and modules...
data.aws_ami.ubuntu: Refreshing...
data.aws_ami.ubuntu: Refresh complete after 1s [id=ami-03420c5d8fd979bd3]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.ubuntu will be created
+ resource "aws_instance" "ubuntu" {
+ ami = "ami-03420c5d8fd979bd3"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ disable_api_stop = (known after apply)
+ disable_api_termination = (known after apply)
+ ebs_optimized = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ host_resource_group_arn = (known after apply)
+ iam_instance_profile = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
+ instance_lifecycle = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "t2.medium" #<<<<<<<<<<<<< MUDOU
+ ipv6_address_count = (known after apply)
+ ipv6_addresses = (known after apply)
+ key_name = (known after apply)
+ monitoring = (known after apply)
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
+ placement_partition_number = (known after apply)
+ primary_network_interface_id = (known after apply)
+ private_dns = (known after apply)
+ private_ip = (known after apply)
+ public_dns = (known after apply)
+ public_ip = (known after apply)
+ secondary_private_ips = (known after apply)
+ security_groups = (known after apply)
+ source_dest_check = true
+ spot_instance_request_id = (known after apply)
+ subnet_id = (known after apply)
+ tags = {
+ "Name" = "Provisioned by Terraform"
}
+ tags_all = {
+ "Name" = "Provisioned by Terraform"
}
+ tenancy = (known after apply)
+ user_data = (known after apply)
+ user_data_base64 = (known after apply)
+ user_data_replace_on_change = false
+ vpc_security_group_ids = (known after apply)
+ capacity_reservation_specification (known after apply)
+ cpu_options (known after apply)
+ ebs_block_device (known after apply)
+ enclave_options (known after apply)
+ ephemeral_block_device (known after apply)
+ instance_market_options (known after apply)
+ maintenance_options (known after apply)
+ metadata_options (known after apply)
+ network_interface (known after apply)
+ private_dns_name_options (known after apply)
+ root_block_device (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ instance_ami = "ami-03420c5d8fd979bd3"
+ instance_arn = (known after apply)
------------------------------------------------------------------------
Cost Estimation:
Resources: 1 of 1 estimated
$34.5216/mo +$34.5216
Podemos observar que mudou. Mas podemos remover a definição desta variável? Comentei para testar...
terraform plan
###...
Terraform v1.10.3
on linux_amd64
Initializing plugins and modules...
╷
│ Warning: Value for undeclared variable
│
│ The root module does not declare a variable named "instance_type" but a
│ value was found in file
│ "/home/tfc-agent/.tfc-agent/component/terraform/runs/run-h4jNZMZec9buqtXJ/terraform.tfvars".
│ If you meant to use this value, add a "variable" block to the
│ configuration.
│
│ To silence these warnings, use TF_VAR_... environment variables to provide
│ certain "global" settings to all configurations in your organization. To
│ reduce the verbosity of these warnings, use the -compact-warnings option.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on main.tf line 26, in resource "aws_instance" "ubuntu":
│ 26: instance_type = var.instance_type
│
│ An input variable with the name "instance_type" has not been declared. This
│ variable can be declared with a variable "instance_type" {} block.
╵
Operation failed: failed running terraform plan (exit 1)
Não podemos. As variáveis no workspace somente setam os valores não as definições.
Se executarmos um terraform plan ou apply passando os valores das variávels pela linha de comando ao invés de definir no variables.tf, este terá preferência sobre a mesma variável setada no HCP Terraform. Por exemplo temos instance_type definido como t2.medium dentro do workspace e vamos forçar que seja t2.small pela linha de comando.
terraform plan -var="instance_type=t2.small"
Running plan in HCP Terraform. Output will stream here.
#...
# aws_instance.ubuntu will be created
+ resource "aws_instance" "ubuntu" {
#...
+ instance_lifecycle = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "t2.small" # <<<<< Forçado
+ ipv6_address_count = (known after apply)
#...
}
#...
Sabendo isso evite usar desta maneira pois se fizermos um run em seguida pela UI teremos divergências e a infra será alterada pois não irá salvar nas variáveis que estão definidas no workspace.
O botão lock (ícone de cadeado) para indicar se o espaço de trabalho está bloqueado, o que impede que outros acionem novas execuções. Também é permitido destravar somente apertando este botão. Seria uma facilidade ao invés de rodar o comando terraform unlock.
Então vamos rodar o terraform apply para ver onde vai parar o state.

E o que temos no overview...

E podemos ver todos os detalhes, o runs etc.

Vamos rodar um plan direto pelo HCP Terraform.


Só de rodar um terraform destroy sem aceitar, já acusou.

Para destruir, precisamos vir aqui. Isso não destroy o workspace, somente os recursos que nele foram criados. Na verdade ele gera um plano destrutivo que precisamos aceitar ao final.


E por fim no overview não aparece mais nada.

Agora vamos analisar um detalhe
Só de curiosidade, vamos tentar criar um workspace da cli, ou seja, não é o mesmo workspace do HCP Terraform.
terraform workspace new workspace1
workspaces not supported
Esse conceito de workspace, uma vez que o projeto foi inicilizado no HCP não é possível.
Se deletarmos completamente a pasta .terraform e remover a parte as definições de cloud e workspace o terraform.tf...
rm -rf .terraform .terraform.lock.hcl
cat terraform.tf
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0
terraform {
# cloud {
# organization = "davidpuziol"
# workspaces {
# name = "learn-terraform"
# }
# }
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.31.0"
}
}
required_version = "~> 1.2"
}
terraform init
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.31.0"...
- Installing hashicorp/aws v5.31.0...
- Installed hashicorp/aws v5.31.0 (signed by HashiCorp)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
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.
# Veja que agora eu posso criar um workspace localmente
terraform workspace new workspace1
Created and switched to workspace "workspace1"!
# Listando
terraform workspace list
default
* workspace1
HCP Terraform NÃO SUPORTA WORKSPACES igual a CLI, o que é muito bom por que esse workspace gera muito problema na equipe! Eu não gosto de trabalhar com esse recurso.