2 de maio de 20265 min de leitura

Modernizando Pipelines de Terraform no Azure: OIDC Federation para GitHub Actions e Azure DevOps

Banner - Modernizando Pipelines de Terraform no Azure: OIDC Federation para GitHub Actions e Azure DevOps

O segredo que ninguém quer rotacionar

TL;DR: Este artigo analisa a implementação do Workload Identity Federation (WIF) para substituir chaves de acesso estáticas (ARM_CLIENT_SECRET) por tokens de curta duração em pipelines de CI/CD no Azure. A conclusão é que o uso de Managed Identities federadas elimina o risco de vazamento de credenciais, reduz o overhead operacional de rotação de segredos e garante uma segmentação RBAC mais precisa, sendo uma recomendação de segurança essencial para qualquer infraestrutura cloud moderna.

A maioria dos nossos clientes ainda autentica pipelines de Terraform usando o mesmo método de três anos atrás: um ARM_CLIENT_SECRET de longa duração armazenado no GitHub Actions ou Azure DevOps. Você insere uma vez, copia para lá e para cá, e só rotaciona quando o sistema quebra.

Esta é a credencial mais ignorada da nuvem e, estatisticamente, a mais propensa a vazamentos. Um desenvolvedor tira um print do grupo de variáveis, um log de pipeline ecoa o valor, um fork herda o segredo ou, pior, a chave expira numa sexta-feira à noite, paralisando os deployments de produção.

O Workload Identity Federation (WIF) resolve esse problema. O pipeline gera um token de curta duração em tempo de execução, troca por um access token do Azure via Microsoft Entra ID e, o mais importante, nunca toca em um segredo. GitHub Actions suporta WIF desde 2021; Azure DevOps, desde fevereiro de 2024. O provider azurerm do Terraform já está pronto para isso desde a v3.7.

Como a troca funciona na prática?

Antes de olhar o YAML, entenda o fluxo lógico:

  1. O sistema de CI (GitHub/ADO) assina um JWT de curta duração descrevendo exatamente o que está rodando: repositório, branch, ambiente e service connection.
  2. O pipeline envia esse JWT para o Microsoft Entra ID.
  3. O Entra verifica o payload contra uma federated identity credential configurada em uma managed identity ou app registration. As claims iss, sub e aud devem corresponder exatamente.
  4. Se tudo validar, o Entra retorna um Azure access token válido apenas para a duração daquele trabalho.
  5. O Terraform utiliza o token, o job termina e o acesso expira. Nada persiste.

O token é vinculado a um subject específico (ex: repo:contoso/platform:environment:prod). Ele não pode ser reutilizado por outro repo, branch ou pipeline.

Fluxo de WIF

Arquitetura recomendada

Abaixo, as escolhas que funcionam melhor em produção:

Decisão Escolha
Tipo de identidade User-assigned managed identity (UAMI)
Granularidade Uma UAMI por ambiente (não por pipeline)
Escopo de confiança Pinned ao claim environment
Escopo RBAC Resource group, não subscription
Remote state OIDC + use_azuread_auth = true, sem chaves compartilhadas

Part 1 - GitHub Actions

Passo 1: Criar a identidade e federar

Dois comandos por ambiente. Só isso.

az identity create -g rg-platform-identity -n id-tf-prod -l eastus

az identity federated-credential create \
  --name github-prod \
  --identity-name id-tf-prod \
  --resource-group rg-platform-identity \
  --issuer https://token.actions.githubusercontent.com \
  --subject repo:contoso/platform:environment:prod \
  --audiences api://AzureADTokenExchange

Passo 2: Configurar o GitHub

Em Settings → Environments, crie os ambientes nonprod e prod. Adicione três variáveis de ambiente (não secrets!): AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID.

O workflow:

permissions:
  id-token: write
  contents: read

jobs:
  apply:
    runs-on: ubuntu-latest
    environment: prod
    env:
      ARM_USE_OIDC: "true"
      ARM_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }}
      ARM_TENANT_ID: ${{ vars.AZURE_TENANT_ID }}
      ARM_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init && terraform apply -auto-approve

Part 2 - Azure DevOps

A lógica é igual, mas a mecânica muda. Para times de plataforma, a via manual + UAMI é superior para governança.

  1. No ADO, crie uma nova ARM service connectionWorkload Identity Federation (manual). Salve como draft.
  2. No Azure, adicione a federated credential na UAMI com os valores informados pelo ADO.
  3. Em pipelines, use a tarefa AzureCLI@2 para carregar a conexão.

Cuidados com o State File

O arquivo de estado é o seu blast radius. Com OIDC, você pode bloquear o storage sem usar access keys:

backend "azurerm" {
  resource_group_name  = "rg-tfstate"
  storage_account_name = "sttfstateprodeastus"
  container_name       = "platform-prod"
  key                  = "platform.tfstate"
  use_oidc             = true
  use_azuread_auth     = true
}

Dê à UAMI a role Storage Blob Data Contributor apenas no container e desabilite o shared key access na conta de armazenamento.

Migração sem janela de manutenção

Você não precisa de um hard cutover:

  1. Crie a nova UAMI com as mesmas permissões do SP antigo.
  2. Federe um pipeline "canário" e valide.
  3. Migre os outros ambientes em ondas.
  4. Após um ciclo de release estável, desabilite o secret antigo do SP.
  5. Remova o SP após o segundo ciclo.

Perguntas Frequentes

  • Por que abandonar o uso de ARM_CLIENT_SECRET?
    Credenciais longas são o vetor de ataque mais provável em pipelines: podem vazar em logs, screenshots ou ser expostas em forks. Além disso, a rotação manual é um processo falho que gera interrupções operacionais.

  • O que o Workload Identity Federation (WIF) resolve na prática?
    O WIF permite que o pipeline solicite tokens de curta duração em runtime via Microsoft Entra ID. Isso elimina a necessidade de armazenar qualquer segredo fixo no CI/CD, garantindo que o acesso expire automaticamente após o job.

  • Qual a recomendação de arquitetura para identidades no Azure?
    Utilize User-assigned managed identities (UAMIs) — uma por ambiente — em vez de App Registrations genéricas. Isso alinha a identidade ao ciclo de vida do recurso e simplifica a governança de permissões.

  • É possível realizar essa migração sem downtime?
    Sim. Você pode manter o Service Principal antigo e o novo UAMI ativos simultaneamente, migrando os pipelines em ondas de menor risco e realizando o corte definitivo apenas após validar a estabilidade dos fluxos.


Artigo originalmente publicado em Azure Updates - Latest from Azure Charts.

Gostou? Compartilhe:
Precisa de ajuda?Fale com nossos especialistas 👋
Avatar Walcew - Headset