GitHub Actions + OIDC: provisionar infraestrutura com Terraform sem credenciais
Por John Pires · 19 de março de 2026

GitHub Actions + OIDC: provisionar infraestrutura com Terraform sem credenciais
Cenario prático do dia a dia
Problema real nas pipelines
Times que usam CI/CD para provisionar recursos na nuvem geralmente mantêm credenciais estáticas (AWS keys, service principals, etc.) em secrets do GitHub. Essas credenciais viciam a segurança: rotação manual, risco de vazamento e dificuldade para aplicar políticas de acesso por repositório ou branch. A alternativa moderna é usar OIDC (OpenID Connect) para permitir que uma execução do GitHub Actions assuma um role na nuvem sem armazenar chaves de longa duração.
Quando aplicar esta abordagem
Use OIDC quando você precisa que pipelines façam deploys ou criem infra (Terraform, Ansible, kubectl) com identidade temporária e limitada. Isso é ideal para: equipes com múltiplos repositórios, ambientes (dev/stage/prod) que exigem separação de privilégios, e requisitos de auditoria/rotacionamento.
Neste artigo vamos centrar no AWS como provedor cloud, Terraform como ferramenta de IaC e GitHub Actions como executor. O mesmo padrão se aplica a GCP e Azure com diferenças no provedor e nas condições de trust.
Dica: OIDC reduz superfície de ataque: não há long-lived credentials no repositório. Ainda assim, modelagem da trust policy e permissions mínimas são críticas.
Arquitetura da solução
Visão geral da arquitetura
Fluxo resumido:
- GitHub Actions emite um token OIDC para a execução do workflow.
- O token aponta para o identity provider token.actions.githubusercontent.com.
- A AWS verifica a trust policy do IAM Role vinculada ao OIDC provider e valida condições (repo, sub, environment).
- Se autorizado, a execução assume o IAM Role e recebe credenciais temporárias (STS) para a duration definida.
- Terraform roda usando essas credenciais temporárias para aplicar alterações.
Componentes e responsabilidades
Componentes:
- GitHub Actions workflow: solicita OIDC e assume role configurado.
- AWS IAM OIDC Provider: mapeia o issuer do GitHub Actions para AWS.
- AWS IAM Role: define a trust policy e permissions para recursos que o Terraform vai manipular.
- Terraform: backend remoto (S3/DynamoDB) e provider configurado para usar assume_role.
As responsabilidades ficam claras: GitHub controla qual repositório/branch pode receber credenciais; AWS controla o que essas credenciais podem fazer.
Codigo completo com explicações
1) Provisionando OIDC provider e IAM Role com Terraform
O bloco abaixo cria o OIDC provider e um role que confia no issuer do GitHub. Substitua 123456789012 pelo seu account id e meu-org/meu-repo pelo repo alvo.
Contexto: estes recursos ficam no Terraform que você roda uma vez (manual/CI) com credenciais administrativas. Após isso, as pipelines do GitHub podem assumir o role via OIDC sem secrets.
# aws-oidc-role.tf
provider "aws" {
region = "us-east-1"
}
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}
resource "aws_iam_role" "github_actions_role" {
name = "gh-actions-oidc-role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Principal = { Federated = aws_iam_openid_connect_provider.github.arn },
Action = "sts:AssumeRoleWithWebIdentity",
Condition = {
StringLike = { "token.actions.githubusercontent.com:sub" = "repo:meu-org/meu-repo:*" },
StringEquals = { "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com" }
}
}
]
})
}
resource "aws_iam_policy" "terraform_apply_policy" {
name = "terraform-apply-policy"
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = [
"s3:*",
"ec2:*",
"iam:PassRole"
],
Resource = "*"
}
]
})
}
resource "aws_iam_role_policy_attachment" "attach" {
role = aws_iam_role.github_actions_role.name
policy_arn = aws_iam_policy.terraform_apply_policy.arn
}
O que acontece: o provider OIDC referencia o issuer do GitHub e cria um role com trust policy restrita ao repo. A policy anexa define permissões que o Terraform precisará. Ajuste a policy para princípio do menor privilégio.
2) Configurando o backend S3 e provider AWS no Terraform
Contexto: aqui configuramos o backend para state compartilhado e o provider que usa assume_role no runtime. O workflow do GitHub vai injetar as variáveis de ambiente necessárias ao assumir o role via OIDC.
# backend-and-provider.tf
terraform {
required_version = ">= 1.0"
backend "s3" {
bucket = "meu-terraform-state-bucket"
key = "infra/prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "meu-terraform-locks"
}
}
provider "aws" {
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::123456789012:role/gh-actions-oidc-role"
session_name = "gh-actions-terraform"
}
}
# exemplo de recurso real manipulado pelo pipeline
resource "aws_s3_bucket" "example" {
bucket = "meu-bucket-infra-exemplo-12345"
acl = "private"
}
O que acontece: quando o Terraform executado no GitHub Actions tiver credenciais temporárias (depois de assumir role), o provider aws usará esse role_arn para operar. O backend S3 garante state compartilhado e DynamoDB lock evita concorrência.
3) Workflow do GitHub Actions usando OIDC
Contexto: este workflow roda em pushes para a branch main e usa a ação oficial da AWS para configurar credenciais via OIDC. Ele executa terraform init/plan/apply de forma segura.
# .github/workflows/terraform.yml
name: terraform
on:
push:
branches: ["main"]
jobs:
apply:
runs-on: ubuntu-latest
permissions:
id-token: write # permite emitir OIDC token
contents: read
steps:
- name: checkout
uses: actions/checkout@v4
- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::123456789012:role/gh-actions-oidc-role
aws-region: us-east-1
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.0
- name: terraform init
run: terraform init -input=false
- name: terraform plan
run: terraform plan -input=false -out=tfplan
- name: terraform apply
if: github.ref == 'refs/heads/main'
run: terraform apply -input=false tfplan
O que acontece: a action configure-aws-credentials solicita o token OIDC ao GitHub e troca por credenciais temporárias via STS AssumeRoleWithWebIdentity. Essas credenciais ficam em variáveis de ambiente AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN e são usadas pelo Terraform.
Tratamento de erros e edge cases
Erros comuns e como diagnosticar
Erro: Invalid identity token ou Access denied for AssumeRoleWithWebIdentity. Causas habituales:
- OIDC provider não foi criado ou thumbprint está errado.
- Trust policy do role não corresponde ao
subdo token (repositório errado, falta de wildcard ou environment mismatch). - role-to-assume ARN incorreto no workflow.
Solução prática:
- Validar a existência do OIDC provider no console AWS ou via
aws iam list-open-id-connect-providers. - Gerar token localmente (usando GitHub CLI) e decodificar para inspecionar o
subeaud. - Checar logs do job no GitHub Actions; a action de configuração da AWS costuma retornar erro detalhado de STS.
Condições finas de trust policy
Evite usar repo:meu-org/meu-repo:*:ref:refs/heads/* sem necessidade. Prefira declarar explicitamente o nome do repositório e opcionalmente o environment para limitar o escopo. Exemplo de condição para permitir somente tags ou branches específicos melhora segurança.
Regra prática: comece amplo em ambiente de desenvolvimento, depois restrinja a trust policy ao promover para produção.
Performance e otimização
Otimização do tempo de pipeline
Assumir um role via OIDC é muito rápido, o gargalo real é o provisioning do Terraform (criação de recursos, waiting for services). Algumas estratégias para reduzir tempo:
- Use parallelismo controlado com módulos do Terraform e
-parallelismquando aplicável. - Quebre pipelines: validate/plan em PRs; apply apenas no main ou manual approval.
- Cache de provider plugins e do diretório .terraform usando actions/cache.
Reduzindo chamadas desnecessárias
Evite aplicar mudanças pequenas automaticamente. Use terraform plan com saída e review automatizado (ex.: upload de plan como artifact ou comentário em PR) para prevenir apply desnecessário. Outra técnica: use labels ou environments que acionem apply apenas quando necessário.
Exemplo de cache de providers (snippet):
- name: Cache Terraform providers
uses: actions/cache@v4
with:
path: |
~/.terraform.d/plugin-cache
.terraform
key: ${{ runner.os }}-terraform-${{ hashFiles('**/*.tf*') }}
restore-keys: |
${{ runner.os }}-terraform-
O que acontece: o cache reduz tempo gasto no download de plugins e módulos, o que é útil quando você tem builds frequentes.
Tratando edge cases operacionais
Rotação e invalidation
A vantagem do OIDC é que não há credenciais long-lived para rotacionar no repositório. Ainda assim, uma alteração no issuer/token life cycle do GitHub exigirá atualizar thumbprint do OIDC provider. Monitore as notificações do GitHub sobre changes no serviço OIDC.
Multi-account e CI cross-account
Para cenários multi-account (ex.: accounts dev/stage/prod), crie roles em cada account com trust policy para o mesmo issuer e limite cada role por repositorio/environment. No workflow, determine qual role-to-assume usar com base em input/branch/env, evitando hardcode em secrets.
Estruture variáveis no workflow assim:
with:
role-to-assume: ${{ matrix.role_arn }}
Isso permite usar matrizes para deploy multi-account sem expor chaves.
Conclusão prática
Resumo das etapas críticas
Passos mínimos para implementar com segurança:
- Criar OIDC Provider apontando para token.actions.githubusercontent.com com thumbprint correto.
- Criar IAM Role com trust policy restrita por
sub(repo e possivelmente environment) eaud= sts.amazonaws.com. - Anexar policies com princípio de menor privilégio ao role.
- Configurar workflow do GitHub para pedir id-token (permission id-token: write) e usar aws-actions/configure-aws-credentials para assumir o role.
- Configurar Terraform provider/backend para usar o role assumido.
Boas práticas finais
Não exponha ARNs de roles sensíveis em logs; restrinja políticas a recursos específicos; monitore audit logs no AWS CloudTrail para detectar usos inesperados do role. Use PRs e revisões de plan para minimizar risco de mudanças perigosas.
Implementar OIDC com GitHub Actions causa um salto grande em segurança operacional e manutenção. O investimento inicial em configurar trust policies e roles compensa pela redução de gerenciamento de secrets e pela adesão ao princípio do menor privilégio.
Se quiser, há variações para Azure/GCP e integração com Vault ou Terraform Cloud/Enterprise que adicionam camadas de controle e auditoria. Para começar com AWS, siga o passo a passo e valide cada etapa: OIDC provider criado, role assumível localmente (testando via GitHub Actions dry-run) e policies restritas.
Aplicar essas práticas tornará seus pipelines mais seguros, auditáveis e fáceis de operar em equipes em crescimento.
Assuntos: DevOps, github-actions, terraform, AWS, oidc
Leia também
Monitorar containers Docker com Prometheus e Grafana via Docker Compose — guia prático
Guia prático para monitorar containers Docker com Prometheus e Grafana via Docker Compose. Inclui arquivos reais, aplicação instrumentada, cAdvisor e dicas…
Portfólio técnico: montar um case deployável em 1 hora com GitHub Actions e Terraform
Guia prático para criar um portfólio técnico deployável em 1 hora usando GitHub Actions e Terraform: estrutura de repositório, Terraform para S3+CloudFront…
Testcontainers e GitHub Actions: testar imagens Docker na CI corretamente
Guia prático de como rodar testes de integração com imagens Docker usando Testcontainers no GitHub Actions: padrões certos e anti-patterns, workflows…
GitHub Actions OIDC: deploy sem segredos em AWS, GCP e Azure (setup prático)
Guia prático para configurar GitHub Actions OIDC e eliminar secrets nas nuvens: passo a passo para AWS, GCP e Azure, exemplos Terraform/gcloud/workflows e…
Escanear imagens Docker no CI com Trivy e GitHub Actions — falhe por CVSS
Aprenda a escanear imagens Docker no CI com Trivy e GitHub Actions e a fazer o pipeline falhar quando uma vulnerabilidade atingir um limiar CVSS. Passo a…
Canary deploy com GitHub Actions em Kubernetes usando Helm e Flagger
Guia prático para implementar canary deploy com GitHub Actions, Helm e Flagger: padrões de pipeline, exemplos de Canary CRD e AnalysisTemplate, integrações…