Subscription Vending no Azure: criando um portal self-service com Forms, Power Automate, GitHub Actions e Terraform

Ilustração sobre Subscription Vending no Azure com portal self-service, automação, GitHub, Terraform e landing zone governada.

No primeiro artigo desta série, mostrei como estruturar um laboratório de Subscription Vending no Azure usando Terraform, GitHub Actions, OIDC e Azure Verified Modules para provisionar uma Application Landing Zone de forma governada.

Na prática, aquele primeiro passo resolveu uma parte importante do problema: transformar a criação de uma landing zone em código, com validação, padronização, controle de estado e execução automatizada.

Mas ainda existia uma pergunta natural para ambientes corporativos:

Como transformar esse processo em uma experiência self-service para as equipes consumidoras?

Em outras palavras: como permitir que uma squad, produto ou área de negócio solicite uma landing zone sem precisar abrir um chamado genérico, preencher um documento solto ou acionar manualmente alguém do time de plataforma?

Foi isso que explorei neste segundo laboratório.

A proposta aqui não é criar um portal sofisticado ou definitivo. O objetivo é demonstrar o padrão arquitetural por trás de um fluxo self-service de Subscription Vending: entrada padronizada, rastreabilidade, validação, automação e execução controlada.

Continuidade do laboratório anterior

Este artigo é uma continuação direta do laboratório publicado anteriormente:

Subscription Vending no Azure: criando landing zones governadas

No primeiro laboratório, o fluxo partia de um arquivo de parâmetros versionado no repositório. Neste segundo, a entrada passa a ser um formulário preenchido pelo usuário.

O repositório usado foi o mesmo:

https://github.com/leomcoco/azure-subscription-vending-avm-lab

A diferença principal está na origem da solicitação.

Antes:

Arquivo .tfvars.json ──> GitHub Actions ──> Terraform plan

Agora:

Microsoft Forms ──> Power Automate ──> GitHub Issue ──> Repository Dispatch ──> GitHub Actions ──> Terraform plan

Essa mudança aproxima o laboratório de um cenário mais realista, onde a plataforma oferece um ponto de entrada simples para os times consumidores, mas mantém o controle técnico no pipeline.

O problema que o self-service precisa resolver

Em ambientes Azure com múltiplas subscriptions, produtos, squads e owners, criar uma landing zone não deveria ser apenas uma ação técnica.

Normalmente, uma solicitação precisa carregar informações mínimas de governança, como:

  • nome da aplicação;
  • ambiente;
  • centro de custo;
  • owner técnico;
  • owner de negócio;
  • criticidade;
  • classificação dos dados;
  • região Azure;
  • espaço de endereçamento;
  • grupos de acesso;
  • orçamento;
  • e-mail para alerta de budget.

Quando essas informações chegam por e-mail, chat ou planilhas, o processo tende a ficar frágil. Falta padrão, falta validação e falta rastreabilidade.

O self-service resolve parte desse problema criando uma entrada estruturada. Mas o ponto mais importante é que o formulário não deve ser o fim do processo. Ele deve ser apenas a primeira etapa de uma cadeia automatizada.

Arquitetura implementada no laboratório

A arquitetura do laboratório ficou assim:

Usuário preenche o Microsoft Forms
       │
       ▼
Power Automate captura a resposta
       │
       ▼
Power Automate cria uma GitHub Issue (Registro e Trilha)
       │
       ▼
Power Automate dispara um evento externo (Repository Dispatch)
       │
       ▼
GitHub Actions recebe o payload JSON
       │
       ▼
Workflow valida os dados da solicitação (Contrato técnico)
       │
       ▼
Terraform executa o pipeline em modo seguro (Plan)
       │
       ▼
Resumo do Plan é publicado automaticamente e vinculado à GitHub Issue
visão geral do fluxo Forms → Power Automate → GitHub Issue → GitHub Actions → Terraform plan

Visão geral do fluxo Forms → Power Automate → GitHub Issue → GitHub Actions → Terraform plan

Esse desenho é simples, mas cobre pontos importantes para uma plataforma corporativa:

  • formulário como ponto de entrada;
  • issue como registro rastreável;
  • pipeline como mecanismo de validação e execução;
  • Terraform como mecanismo de provisionamento;
  • apply desabilitado por padrão;
  • vínculo entre solicitação e resultado técnico.

Por que usar GitHub Issue no meio do fluxo?

Uma decisão importante do laboratório foi criar uma GitHub Issue antes de disparar o workflow.

Isso evita que a automação vire uma “caixa-preta”.

A Issue passa a representar a solicitação formal da landing zone. Ela registra os dados enviados pelo formulário, permite comentários, facilita auditoria e cria um ponto único para acompanhar o resultado.

No laboratório, a Issue recebeu informações como:

Request ID
Application
Environment
Product line
Location
Cost center
Technical owner
Business owner
Criticality
Data classification
Address space
Subnets
Terraform mode
Apply requested
Justification
 Issue criada automaticamente no GitHub com os dados da solicitação

Issue criada automaticamente no GitHub com os dados da solicitação

Mesmo em um cenário mais maduro, onde a organização use ServiceNow, Jira, Azure DevOps ou outro portal interno, o conceito é o mesmo: a solicitação precisa ter um identificador, um histórico e um status claro.

Formulário usado como entrada

O formulário foi criado no Microsoft Forms com campos obrigatórios para representar uma solicitação mínima de Application Landing Zone.

Alguns campos usados no laboratório:

- Nome da aplicação
- Ambiente
- Product line
- Subscription ID
- Localização Azure
- Centro de custo
- Owner técnico
- Owner de negócio
- Criticidade
- Classificação dos dados
- Address space da VNet
- Subnet de workload
- Subnet de private endpoints
- Grupo Contributor Object ID
- Grupo Reader Object ID
- Budget mensal
- E-mail para alerta de budget
- Justificativa da solicitação

Microsoft Forms utilizado no laboratório

Microsoft Forms preenchido com os dados do laboratório

Microsoft Forms preenchido com os dados do laboratório

No teste validado, a solicitação usou valores como:

Application: sv-portal-001
Environment: prd
Product line: corp-connected
Location: brazilsouth
Cost center: CC-1001
Criticality: medium
Data classification: internal
Address space: 10.41.0.0/16
Workload subnet: 10.41.1.0/24
Private endpoint subnet: 10.41.2.0/24
Budget: 500

Um detalhe importante: os campos do formulário precisam estar alinhados com o contrato esperado pelo Terraform. Se o formulário permitir valores fora do padrão, o workflow deve bloquear antes de qualquer execução.

Power Automate como orquestrador

O Power Automate foi usado para transformar a resposta do Forms em duas ações principais:

  1. criar uma Issue no GitHub;
  2. disparar o evento repository_dispatch.

O fluxo ficou com esta estrutura:

Quando uma nova resposta é enviada (Microsoft Forms)
       │
       ▼
Obter os detalhes da resposta
       │
       ▼
Compose: Request ID automático
       │
       ▼
Compose: Título da GitHub Issue
       │
       ▼
Compose: Corpo da GitHub Issue (Markdown)
       │
       ▼
Criar uma Issue (Ação do GitHub no Power Automate)
       │
       ▼
Compose: Payload do Dispatch (JSON)
       │
       ▼
Disparar evento de Repository Dispatch (Ação do GitHub)
Fluxo completo no Power Automate com criação da Issue e payload do dispatch.

Fluxo completo no Power Automate com criação da Issue e payload do dispatch.

Fluxo completo no Power Automate

Fluxo completo no Power Automate

O request_id foi gerado automaticamente no fluxo:

sv-20260622-204132

Esse identificador foi usado para compor o nome do state file do Terraform:

sv-20260622-204132.tfstate

Esse ponto é importante porque cada solicitação passa a ter uma trilha própria. Em um ambiente real, esse ID poderia ser enriquecido com número de chamado, código da aplicação, produto ou identificador de demanda.

Payload enviado para o GitHub Actions

O Power Automate montou um payload JSON para o repository_dispatch. Esse payload carrega os dados necessários para o workflow gerar o arquivo request.tfvars.json.

Um exemplo simplificado do payload:

{
  "apply": false,
  "issue_number": 7,
  "request": {
    "request_id": "sv-20260622-204132",
    "application_name": "sv-portal-001",
    "environment": "prd",
    "product_line": "corp-connected",
    "subscription_id": "<subscription-id>",
    "management_group_id": "",
    "location": "brazilsouth",
    "cost_center": "CC-1001",
    "technical_owner": "squad-cloud-demo",
    "business_owner": "area-negocio-demo",
    "criticality": "medium",
    "data_classification": "internal",
    "address_space": [
      "10.41.0.0/16"
    ],
    "subnet_workload_prefixes": [
      "10.41.1.0/24"
    ],
    "subnet_private_endpoint_prefixes": [
      "10.41.2.0/24"
    ],
    "contributor_group_object_id": "<group-object-id>",
    "reader_group_object_id": "<group-object-id>",
    "create_network_watcher_rg": false,
    "budget_enabled": true,
    "budget_amount": 500,
    "budget_start_date": "2026-06-01T00:00:00Z",
    "budget_end_date": "2027-06-01T00:00:00Z",
    "budget_contact_emails": [
      "<email>"
    ],
    "enable_allowed_locations_policy": false,
    "enable_telemetry": false
  }
}

No laboratório, o campo apply foi mantido como false.

Essa decisão foi proposital.

O objetivo era validar o fluxo completo em modo seguro, sem criar recursos automaticamente no Azure a cada submissão do formulário.

Validação antes do Terraform

Um ponto que considero essencial nesse tipo de automação é validar a entrada antes de executar qualquer comando Terraform.

Durante o laboratório, um erro apareceu exatamente nessa etapa:

contributor_group_object_id deve ser um GUID válido em letras minúsculas.

Esse erro foi útil. Ele mostrou que o workflow estava protegendo a execução contra um payload fora do padrão esperado.

A correção foi tratar o valor no Power Automate antes de enviá-lo para o GitHub Actions:

toLower(trim(...))

Isso removeu espaços acidentais e garantiu o envio do GUID em letras minúsculas.

Esse é um exemplo simples, mas representa uma prática importante: o portal pode facilitar a entrada, mas a esteira precisa continuar sendo rígida.

Resultado do Terraform plan

Após os ajustes, o fluxo executou com sucesso.

O GitHub Actions recebeu o evento repository_dispatch, validou o arquivo de entrada, inicializou o Terraform e gerou o plano.

O resumo final mostrou:

Request source: /tmp/subscription-vending/request.tfvars.json
Terraform state key: sv-20260622-204132.tfstate
Apply requested: false
GitHub Issue: #7
Plan: 11 to add, 0 to change, 0 to destroy
GitHub Actions com execução bem-sucedida

GitHub Actions com execução bem-sucedida

Terraform plan summary com 11 to add

Terraform plan summary com 11 to add

Esse resultado confirma que a solicitação saiu do formulário, passou pelo Power Automate, criou uma Issue, disparou o workflow e chegou até o Terraform plan.

Nenhum recurso foi criado, porque o laboratório foi mantido em modo plan.

O que seria criado pelo Terraform

O plano indicou a criação de 11 recursos ou ações, incluindo:

  • Resource Group;
  • Virtual Network;
  • subnet de workload;
  • subnet de private endpoints;
  • budget;
  • role assignments;
  • registros de resource providers necessários.

O grupo de recursos seguiria o padrão:

rg-sv-portal-001-prd-brs-001

A VNet seguiria o padrão:

vnet-sv-portal-001-prd-brs-001

E o budget:

bud-sv-portal-001-prd-brs

Esse padrão de nomenclatura foi derivado dos parâmetros enviados pela solicitação, reforçando a ideia de que o portal não deve apenas coletar dados, mas alimentar uma esteira padronizada.

Pontos de atenção para produção

O laboratório validou o padrão, mas uma implementação produtiva exigiria alguns controles adicionais.

O primeiro ponto é aprovação. Neste laboratório, o fluxo executa o plan automaticamente, mas o apply deve depender de uma aprovação formal, preferencialmente vinculada ao owner técnico, owner financeiro ou time de plataforma.

Também é importante evitar campos totalmente livres para informações críticas. Subscription ID, região Azure, centro de custo, grupos de acesso e classificação dos dados deveriam vir de listas controladas ou de uma base corporativa confiável.

Outros pontos que eu trataria antes de levar esse modelo para produção:

  • validação de CIDR e conflito de rede;
  • controle de regiões permitidas;
  • integração com ITSM ou catálogo interno;
  • segregação clara entre plan e apply;
  • proteção e rotação de tokens;
  • revisão de permissões mínimas;
  • auditoria centralizada;
  • padronização de tags e naming convention;
  • política para exceções e revisão periódica.

O objetivo do laboratório não foi resolver todos esses pontos, mas demonstrar a base de um fluxo self-service governado.

Lições aprendidas

A principal lição deste segundo laboratório é que Subscription Vending não é apenas Terraform.

Terraform é o motor de provisionamento, mas o valor aparece quando existe um fluxo completo em volta dele.

Um bom processo de Subscription Vending precisa conectar:

entrada padronizada
governança
rastreabilidade
validação
automação
controle de execução

Outra lição importante é que o modo plan já gera valor. Ele permite validar a solicitação antes de criar qualquer coisa. Para uma equipe de plataforma, isso reduz risco e ajuda a transformar uma demanda abstrata em uma proposta técnica revisável.

Também ficou claro que pequenas validações fazem diferença. O erro com o contributor_group_object_id mostrou que uma automação self-service sem validação pode só acelerar problemas. A validação precisa fazer parte do desenho desde o início.

Conclusão

Este laboratório mostrou uma forma prática de criar um portal self-service para Subscription Vending no Azure usando ferramentas acessíveis: Microsoft Forms, Power Automate, GitHub Issues, GitHub Actions e Terraform.

A solução não foi desenhada para ser um produto final, mas para demonstrar um padrão reutilizável.

O usuário preenche um formulário. A solicitação vira uma Issue. O GitHub Actions recebe um evento externo. O Terraform executa o plan. O resultado fica registrado e vinculado à solicitação.

Esse fluxo aproxima a plataforma de uma experiência mais madura para os times consumidores, sem abrir mão de controle técnico.

No fim, o ponto central é simples: self-service não significa ausência de governança. Pelo contrário. Um bom self-service cloud deve tornar a governança parte natural do caminho.

Referências oficiais

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *