Uma referência rápida dos padrões arquiteturais que o exame 004 avalia. Leia de cima a baixo ou pule para uma seção.
Compreender Conceitos de Infraestrutura como Código (IaC)
Uma equipa clica manualmente em consolas cloud; ninguém sabe como a produção deveria ser.
Adotar IaC. As configurações residem em ficheiros versionados - os ficheiros são a fonte autoritativa da verdade, não a consola cloud.
Por quê: Registo de auditoria, revisão por pares, rollback e replicação fluem todos do controlo de versão. O provisionamento manual não tem nenhum destes.
Escolher entre descrever o estado final desejado versus scriptar os passos para alcançá-lo.
Terraform é declarativo. Você descreve o alvo; Terraform descobre as chamadas API. Ansible, scripts Bash, SDKs personalizados são imperativos.
Por quê: Configurações declarativas são idempotentes e convergem independentemente do estado inicial. Scripts imperativos devem raciocinar sobre cada transição.
Distinguir o provisionamento inicial das operações contínuas.
Dia 0 = design e planeamento. Dia 1 = provisionamento inicial (primeiro apply). Dia 2 = operações contínuas: patching, escalonamento, rotação de certificados, remediação de drift.
Por quê: A maioria do trabalho de produção é do Dia 2. As ferramentas IaC devem suportar iteração, não apenas a primeira implantação.
Reduzir o risco de drift da consola; exigir que todas as alterações de infraestrutura passem por revisão.
GitOps com IaC: git é a fonte da verdade, PRs desencadeiam plans, merges desencadeiam applies. Bloquear acesso direto à consola via SCP/IAM.
Compreender o Propósito do Terraform
Carga de trabalho abrange AWS e GCP; a equipa quer uma única ferramenta, um único fluxo de trabalho.
Terraform com múltiplos providers numa única configuração: `hashicorp/aws` + `hashicorp/google`. Saídas de um provider alimentam entradas de outro.
Por quê: Core agnóstico ao provider; SDKs por cloud residem em providers plugáveis. CloudFormation/ARM são single-cloud.
`init` (download de providers + backend) → `plan` (pré-visualização) → `apply` (executar) → `destroy` (desmantelar). `plan` é apenas de leitura e seguro.
Por que o Terraform precisa de um ficheiro de estado em vez de consultar a cloud a cada execução?
O estado mapeia endereços de configuração (`aws_instance.web`) para IDs de recursos reais, rastreia dependências e armazena metadados em cache. Sem ele, o Terraform não consegue saber quais recursos da cloud ele gere versus quais foram criados noutro local.
Provisionar VMs versus configurar software dentro delas.
Terraform provisiona recursos cloud (VMs, redes, IAM). Ansible/Chef/Puppet configuram software dentro das VMs. São complementares, não concorrentes.
Uma empresa apenas AWS a debater CloudFormation vs Terraform.
CloudFormation tem integração AWS mais estreita, rollback nativo e zero gestão de ficheiros de estado. Terraform ganha em multi-cloud, ecossistema de módulos maior e ergonomia HCL. Escolha CFN se for apenas AWS e o rollback for o mais importante; Terraform caso contrário.
Compreender os Fundamentos do Terraform
Fixar a origem e a versão do provider para instalações reproduzíveis.
Declarar em `terraform { required_providers { aws = { source = "hashicorp/aws", version = "~> 5.0" } } }`.
Por quê: Sem `required_providers` explícitos, o Terraform assume namespaces de registo legados e pode escolher versões incompatíveis.
A configuração tem `required_providers` para AWS mas nenhum bloco `provider "aws"`.
O Terraform cria uma configuração de provider vazia por defeito. O provider AWS lê então `AWS_ACCESS_KEY_ID`/`AWS_PROFILE`/IMDS na sua precedência padrão.
Por quê: Um bloco `provider` explícito é opcional; é necessário apenas para substituir valores predefinidos ou para criar aliases de várias instâncias.
Faz o download de providers por `required_providers`, inicializa o backend, faz o download das fontes dos módulos e escreve `.terraform/` mais `.terraform.lock.hcl`. Requerido antes de `plan` ou `apply`.
Um ficheiro `.terraform.lock.hcl` apareceu depois de `init`. Fazer commit ou gitignore?
Faça commit. O ficheiro de lock regista as versões exatas do provider + checksums criptográficos. Garante que todos os colaboradores e CI runners instalem providers idênticos.
Por quê: Sem ele, `terraform init` pode escolher uma versão compatível mais recente numa máquina diferente, introduzindo diffs inesperados.
Detetar erros de sintaxe e incompatibilidades de tipo sem aceder a APIs cloud.
`terraform validate` verifica a sintaxe HCL, consistência de tipos, argumentos obrigatórios e referências internas. Apenas local, sem necessidade de autenticação do provider.
Por quê: Não deteta problemas do lado do provider (autenticação, recursos em falta) - estes só surgem em `plan`.
CI executa `terraform init` repetidamente em muitos projetos, cada um a descarregar os mesmos providers do zero.
Defina `TF_PLUGIN_CACHE_DIR` (ou `plugin_cache_dir` na configuração do CLI). Os providers são descarregados uma vez e linkados simbolicamente para diretórios `.terraform/` por projeto.
Os endereços de origem do provider seguem que formato?
`<hostname>/<namespace>/<type>` - por exemplo, `registry.terraform.io/hashicorp/aws`. O hostname omitido assume o Terraform Registry público. Namespace = fornecedor. Type = nome do provider.
Impedir que colaboradores executem uma versão incompatível do CLI Terraform.
`terraform { required_version = ">= 1.5, < 2.0" }`. O CLI recusa-se a operar se a versão em execução não corresponder.
Escolher autenticação do provider para um CI/CD runner.
Melhor: credenciais dinâmicas de curta duração (confiança OIDC para AWS/Azure/GCP, credenciais de provider dinâmicas do HCP Terraform). Aceitável: variáveis de ambiente (`AWS_ACCESS_KEY_ID`). Evitar: credenciais hardcoded no bloco `provider`.
Por quê: Segredos estáticos de longa duração na configuração são a principal causa de incidentes de credenciais vazadas.
Onde vivem as configurações de alto nível?
Um bloco `terraform { ... }` contém `required_version`, `required_providers`, `backend`, `cloud` e experimentos. Múltiplos blocos `terraform` em diferentes ficheiros são mesclados.
Usar Terraform Fora do Fluxo de Trabalho Principal
O recurso existe no estado mas não deve mais ser gerido pelo Terraform; o recurso cloud deve continuar a funcionar.
`terraform state rm <addr>`. Remove do estado sem destruir o recurso cloud.
Um bucket S3 existente criado manualmente precisa ser gerido pelo Terraform sem recriação.
Escreva o bloco de recurso, depois `terraform import aws_s3_bucket.legacy legacy-bucket-name`. O estado agora regista o bucket existente; planos subsequentes mostram apenas drift.
Precisa importar muitos recursos de forma reproduzível através de CI em vez de comandos CLI ad-hoc.
Use o bloco `import` (Terraform 1.5+): `import { to = aws_s3_bucket.legacy, id = "legacy-bucket-name" }`. As importações acontecem durante `apply`, são controladas por versão e funcionam na saída do plan.
`terraform output -json <name>` emite JSON seguro para parsing com `jq`. `terraform output` normal é formatado para humanos e não é seguro para scripts.
Inspecionar o que está atualmente rastreado no estado.
`terraform state list` mostra todos os endereços de recurso. `terraform state show <addr>` mostra atributos para um recurso. Para recursos indexados use aspas: `terraform state show 'aws_instance.web[0]'`.
Caminho local → `./modules/vpc`. Registo público → `terraform-aws-modules/vpc/aws`. Git → `git::https://github.com/org/repo.git//path?ref=v1.0`. S3/HTTP/Mercurial também são suportados.
Fixar um módulo de registo para permitir apenas atualizações de patch.
`version = "~> 3.5.2"` permite `>= 3.5.2, < 3.6.0`. Para tolerância a atualizações menores, use `~> 3.0` (qualquer 3.x). Módulos de caminho local não suportam `version`.
O módulo precisa de um provider com alias (por exemplo, para uma região não padrão).
O chamador passa o bloco `providers = { aws = aws.us_west }` na invocação do `module`. O módulo declara `configuration_aliases = [aws.us_west]` em `required_providers`.
Dois padrões: (1) Workspaces com uma configuração raiz + `*.tfvars` por workspace. (2) Configurações raiz por ambiente (`envs/dev/main.tf`, `envs/prod/main.tf`), cada uma chamando módulos partilhados. O padrão 2 é mais comum para isolamento entre múltiplas equipas.
Usar o Fluxo de Trabalho Principal do Terraform
Garantir que o CI aplique exatamente o que foi revisado no plan, sem drift entre as etapas.
`terraform plan -out=tfplan` guarda o plan. Depois `terraform apply tfplan` aplica esse plan exato. Recusar-se a replanear elimina o risco de time-of-check/time-of-use.
Decodificar os símbolos de saída do plan: `+`, `-`, `~`, `-/+`, `<=`.
`+` criar. `-` destruir. `~` atualizar no local. `-/+` destruir e depois criar (substituir). `<=` ler (data source). O símbolo de substituição significa que um atributo `forces replacement` mudou.
Corrigir rapidamente um recurso quebrado sem tocar no resto da configuração.
`terraform apply -target=aws_instance.web`. Use com moderação - ignora o rastreamento de dependências e pode deixar o estado inconsistente. Documente por que cada `-target` foi usado.
Por quê: A HashiCorp diz explicitamente que `-target` é para resolução de problemas excecional, não para o fluxo de trabalho normal.
O Recurso A deve existir antes do Recurso B, mas B não referencia os atributos de A.
Adicione `depends_on = [resource_a.name]` a B. Use apenas quando referências implícitas de atributos não conseguem expressar a dependência (ex: a política IAM deve propagar antes que o EC2 a utilize).
Substituir uma instância EC2 sempre que um launch template relacionado muda (sem modificar o EC2 diretamente).
`lifecycle { replace_triggered_by = [aws_launch_template.web.latest_version] }` (Terraform 1.2+). A instância é substituída quando qualquer valor listado muda.
Pipeline CI/CD aplica após um trabalho de planificação bem-sucedido; sem humano ao teclado.
`terraform apply -auto-approve` ignora a confirmação interativa. Combine com um ficheiro de plan guardado (`terraform apply tfplan`) para tornar o CI determinístico.
O provider de cloud aplica limites de taxa ao Terraform; muitas criações de recursos estão a falhar intermitentemente.
`terraform apply -parallelism=5` (padrão 10) limita as operações de recursos concorrentes.
Mapeamento de endereço de recurso → ID de recurso cloud, snapshots de atributos, metadados do gráfico de dependências e referências de módulo/provider. Usado para planear diffs e detetar drift.
Engenheiro individual a prototipar localmente - o estado local é OK?
Sim para trabalho solo descartável. Terraform escreve `terraform.tfstate` ao lado da configuração. Mude para um backend remoto no momento em que uma segunda pessoa, um CI runner, ou um ambiente de produção esteja envolvido.
Estado partilhado alojado no Azure sem credenciais estáticas no CI.
Tipo de backend `azurerm`. Defina `use_msi = true` (Managed Identity) ou `use_oidc = true` para que o runner se autentique via sua identidade. Blob lease nativo lida com o locking.
Dois engenheiros executam apply simultaneamente contra o mesmo estado suportado por S3.
A tabela de lock do DynamoDB impede escritas concorrentes. O primeiro adquire o lock, o segundo vê um erro `state lock failed` e deve esperar ou `force-unlock` se o lock estiver obsoleto.
Por quê: Sem DynamoDB, applies concorrentes podem corromper o ficheiro de estado S3.
Gerir dev / staging / prod com uma única configuração raiz.
Workspaces - `terraform workspace new staging`, `terraform workspace select prod`. Cada um tem o seu próprio ficheiro de estado. Referência via `terraform.workspace` em HCL.
Por quê: Opção leve. Para isolamento real (IAM diferente, contas separadas), prefira configurações raiz por ambiente.
Executar `terraform workspace select prod` enquanto os recursos de staging existem.
Os recursos de staging não são afetados. Mudar de workspace apenas altera qual ficheiro de estado o Terraform lê a seguir - é uma mudança de ponteiro local.
Ver workspaces disponíveis e o ativo.
`terraform workspace list` (asterisco marca o atual). `terraform workspace show` imprime apenas o nome atual.
A equipa de segurança pergunta como o Terraform lida com senhas RDS no estado.
Valores sensíveis são armazenados em **texto simples** no estado. Mitigações: encriptar o backend em repouso (S3 SSE-KMS, HCP nativo), restringir o acesso IAM ao bucket de estado e evitar colocar segredos no Terraform quando possível.
Por quê: A flag `sensitive = true` apenas oculta valores da saída do CLI, não do estado.
A conformidade exige encriptação em repouso no estado.
S3: ativar SSE-KMS no bucket. Azure: encriptação de conta de armazenamento (padrão LIGADO). GCS: chaves de encriptação geridas pelo cliente. HCP Terraform: encriptado nativamente em repouso.
Engenheiro executou `terraform destroy` contra prod por engano. Estado agora vazio.
Restaurar a versão anterior do ficheiro de estado do versionamento do S3, depois executar `terraform plan` para ver o que o Terraform agora pensa que precisa ser criado/importado. Combine com a restauração do lado da cloud (snapshots, `aws backup`) para os recursos destruídos.
O ficheiro de estado parece errado; tentado a editá-lo diretamente.
Não. Use os subcomandos `terraform state` (`mv`, `rm`, `replace-provider`, `pull`, `push`). Edições manuais de JSON ignoram verificações de integridade e corrompem a linhagem.
Inspecionar o JSON de estado remoto bruto, ou fazer push de um ficheiro de estado recuperado.
`terraform state pull` escreve o estado remoto atual para stdout. `terraform state push <file>` sobrescreve o remoto com o ficheiro dado. Push é destrutivo - faça backup primeiro.
Passar um token de API temporário através do Terraform sem que ele vá parar ao estado.
Marque a variável `ephemeral = true` (Terraform 1.10+). Valores efémeros nunca são persistidos em ficheiros de estado ou plan. Para exportar através de uma saída de módulo, marque também a saída `ephemeral = true`.
Por quê: `sensitive` está oculto no CLI mas armazenado em plaintext no estado. `ephemeral` nunca é realmente armazenado.
Diferença entre um argumento `sensitive` e um argumento write-only (ex: `password_wo`).
`sensitive` é armazenado em estado plaintext, apenas redigido no CLI. Write-only **nunca** é armazenado no estado. Para detetar alterações em atributos write-only, o Terraform usa um campo de versão companheiro (ex: `password_wo_version`).
Mostrar um elemento de um recurso `count` no estado.
Cite o endereço: `terraform state show 'aws_instance.web[0]'`. Sem aspas, a shell pode interpretar os parênteses.
Equipas diferentes precisam operar independentemente sem interferir no estado umas das outras.
Um ficheiro de estado por equipa (ou por ambiente por equipa). Backends/buckets separados. Use `terraform_remote_state` data source para ler outro estado apenas para leitura.
Configuração escrita para Terraform 0.13; quer usar 1.x.
Os ficheiros de estado são compatíveis com versões futuras: 1.x lê o estado 0.13. A HashiCorp recomenda atualizações incrementais (0.13 → 0.14 → … → 1.x) executando cada versão contra o estado.
Alguém modificou um grupo de segurança via consola; quer que o Terraform reafirne ou aceite o novo estado.
Reafirmar: `terraform apply` - Terraform reverte para a configuração. Aceitar: atualizar HCL para corresponder à realidade, depois aplicar (sem diff). Detetar primeiro via `terraform plan -refresh-only`.
Ler, Gerar e Modificar Configuração
Tipar fortemente uma variável.
Primitivos: `string`, `number`, `bool`. Coleções: `list(<type>)`, `set(<type>)`, `map(<type>)`. Estruturais: `object({...})`, `tuple([...])`. Use `any` apenas quando for verdadeiramente polimórfico.
Gerar uma palavra-passe de base de dados sem que ela apareça em `terraform output`.
`output "db_password" { value = ...; sensitive = true }`. O CLI mostra `(sensitive value)`. Ainda legível via `terraform output db_password` ou `-json` (intencionalmente - para scripts).
Criar N recursos semelhantes - escolher `count` ou `for_each`.
`for_each` (com map ou set) quando os itens têm identidade estável (nomes de região, chaves de ambiente). `count` para "preciso de N cópias, a ordem não importa, a identidade é apenas um índice". Adicionar/remover no meio de `count` causa destroy/recreate; `for_each` preserva a identidade.
`for_each = toset(["a", "b", "c"])`. `each.key` e `each.value` dão ambos a string. Para mapas: `for_each = var.users` - `each.key` = chave do map, `each.value` = valor do map.
Obter uma lista de atributos em todas as instâncias de um recurso `count`.
`aws_instance.web[*].id` retorna uma lista de IDs. Funciona com `count` e `for_each` (mas `for_each` produz um map não ordenado, então `values(aws_instance.web)[*].id`).
Ler um valor de mapa com um padrão se a chave estiver em falta.
`lookup(var.config, "region", "us-east-1")`. Retorna o valor padrão quando a chave não está presente. Para estruturas profundamente opcionais, prefira o `try()` opcional.
Renderizar um script user-data com template com valores de variáveis.
`templatefile("init.sh.tpl", { region = var.region, env = var.env })`. O template usa a sintaxe `${region}`. Alternativa mais recente para renderização estática: `file()` + `format()`.
Provisioner `remote-exec` dentro de um recurso. Ferramenta de último recurso - prefira cloud-init, user data ou gestão de configuração. Os provisioners não são rastreados no estado e não são executados novamente em caso de drift.
Verificar continuamente um invariante de tempo de execução (ex: endpoint de saúde retorna 200) sem bloquear o apply.
`check "endpoint" { data "http" "h" { url = "..." }; assert { condition = data.http.h.status_code == 200; error_message = "..." } }`. Executa em plan/apply; falha é um aviso, não um erro grave.
Por quê: `check` permite data sources com escopo utilizáveis apenas dentro da verificação. `precondition`/`postcondition` são erros graves em plan/apply.
Escolher um modo de execução de workspace no HCP Terraform.
Impulsionado por VCS (auto-plan no git push, mais comum). Impulsionado por CLI (o desenvolvedor executa `terraform plan/apply` localmente, o HCP mantém o estado). Impulsionado por API (execuções Terraform acionadas por API, usadas por sistemas de automação/CD).
plan → estimativa de custo (se ativada) → verificação de política (Sentinel/OPA) → apply manual ou automático. Falhas de política obrigatórias ou falhas de run-task interrompem a pipeline.
Garantir que todos os buckets S3 são encriptados, bloqueando o apply se violado.
Política Sentinel com imposição obrigatória rígida. Inspeciona o plan; a falha bloqueia o apply. Soft-mandatory permite a substituição pelo administrador. Advisory regista logs mas nunca bloqueia.
Integrar um scanner de segurança de terceiros na pipeline de execução do HCP Terraform.
Executar tarefa na fase pós-plan. O HCP POSTa o plan para o seu endpoint; o endpoint responde passa/falha. A imposição obrigatória bloqueia o apply em caso de falha; o advisory apenas avisa.
Mostrar o impacto de um pull request antes de fazer merge.
Os planos especulativos são executados em PRs (ou branches), comentam os resultados de volta para o PR e nunca aplicam. Acionados automaticamente quando a integração VCS está ativada.
Evitar armazenar chaves de acesso AWS como segredos estáticos em variáveis do HCP Terraform.
Credenciais de provider dinâmicas. O HCP Terraform solicita credenciais de curta duração via confiança OIDC para AWS/Azure/GCP. Sem chaves estáticas; identidades por execução; auditável.
Por quê: Chaves estáticas vazam. A confiança OIDC vincula credenciais ao workspace + execução, expira dentro de uma hora.
Partilhar as mesmas credenciais de provider entre vários workspaces.
Conjuntos de variáveis. Definir uma vez ao nível da organização/projeto, anexar a vários workspaces. As atualizações propagam sem edições por workspace.
Um projeto incorporado que existe em todas as organizações e não pode ser excluído (a renomeação é permitida). Todos os workspaces pertencem a ele, a menos que sejam explicitamente atribuídos a outro projeto.
Aplicar um workspace downstream sempre que um workspace upstream concluir um apply bem-sucedido.
Run triggers. Configure o(s) workspace(s) de origem no workspace dependente; o HCP enfileira uma execução no dependente após cada apply upstream bem-sucedido.