Service principal Azure somente leitura: papel Reader, custos, vencimento do secret e como comprovar que não escreve
O guia do Azure deste site explica em cinco passos como criar o service principal pelo portal e colá-lo no Control Cloud. O Search Console mostra buscas que chegam sem uma página que as responda: "azure service principal", "service principal azure", "controle de acesso no azure". Esta nota responde com a CLI: o que é um service principal e como ele difere de um app registration e de uma managed identity, como criá-lo com o papel Reader em um único comando, qual papel acrescenta a leitura de custos, quando o secret vence e como comprovar que ele de fato não pode escrever. Os comandos e os nomes dos papéis saem do Microsoft Learn; a lista de fontes está no final.
App registration, service principal e managed identity
- App registration (o application object): a definição global da aplicação, que fica no tenant onde foi registrada. Ali estão o client ID e as credenciais.
- Service principal: segundo o Microsoft Learn, a representação local desse application object em um tenant. É a identidade à qual o Azure RBAC atribui papéis. Ao registrar uma aplicação, o service principal é criado automaticamente; por isso no portal os dois parecem a mesma coisa.
- Managed identity: um service principal que o Azure administra para código que roda dentro do Azure (uma VM, uma Function). Não há secret para guardar nem rotacionar. Se a ferramenta que lê sua conta roda fora do Azure, não serve: você precisa de um service principal com secret ou certificado.
Criá-lo com o papel Reader em um único comando
az ad sp create-for-rbac registra a aplicação, cria o service principal e atribui o papel em um passo. O Microsoft Learn recomenda passar sempre --role e --scopes: sem eles o service principal existe, mas não tem acesso a nenhum recurso. Para criá-lo você precisa de User Access Administrator ou Role Based Access Control Administrator (ou superior) na assinatura.
# a assinatura ativa da sua sessão do az
SUB=$(az account show --query id --output tsv)
az ad sp create-for-rbac --name "inventario-somente-leitura" \
--role Reader \
--scopes "/subscriptions/$SUB"
A saída é um JSON com quatro campos:
{
"appId": "00000000-0000-0000-0000-000000000000",
"displayName": "inventario-somente-leitura",
"password": "...",
"tenant": "00000000-0000-0000-0000-000000000000"
}
appId é o client ID, password é o client secret e tenant é o tenant ID. O secret não pode ser lido de novo: se você perdê-lo, gere outro com az ad sp credential reset. Dois avisos da documentação: se outro objeto do diretório tiver o mesmo display name, o comando pode modificá-lo, então use um nome único; e se o seu diretório tiver "Users can register applications" em No, o comando falha com "Insufficient privileges to complete the operation" até que um admin do Entra lhe dê um papel como Application Developer.
Reader é o papel built-in que a Microsoft descreve como "View all resources, but does not allow you to make any changes". Sua única ação é */read no control plane e ele não tem DataActions: vê que uma storage account existe, mas não lê os blobs guardados nela.
Menos alcance: resource groups em vez da assinatura
--scopes aceita vários scopes separados por espaços. Se a ferramenta só precisa ver dois resource groups, dê acesso a eles e não à assinatura inteira:
az ad sp create-for-rbac --name "inventario-dois-rg" \
--role Reader \
--scopes "/subscriptions/$SUB/resourceGroups/prod-web" \
"/subscriptions/$SUB/resourceGroups/prod-db"
O preço de reduzir o scope é que o inventário também diminui: o que estiver fora desses resource groups não aparece. Para um inventário completo, o scope certo é a assinatura; para uma equipe que só opera a sua parte, o resource group.
Custos: Reader não basta
Para ver custos no nível da assinatura ou do resource group, o Microsoft Learn exige pelo menos Cost Management Reader (ou Contributor). Em contratos Enterprise também é preciso ativar "AO view charges", e no Microsoft Customer Agreement a opção "Azure charges" do perfil de cobrança. No código do Control Cloud, a consulta à API do Cost Management com um service principal que só tem Reader volta com 403. O papel é acrescentado ao mesmo service principal:
az role assignment create --assignee "$APP_ID" \
--role "Cost Management Reader" \
--scope "/subscriptions/$SUB"
Atribuí-lo exige Owner ou User Access Administrator nesse scope. Cost Management Reader lê custos e não modifica recursos, então a credencial continua sem poder escrever.
O secret vence: quanto dura e como rotacioná-lo
create-for-rbac cria o secret com um ano de validade se você não passar --years. Pelo portal, em Certificates & secrets, o máximo é 24 meses e a Microsoft recomenda menos de 12. A mesma página recomenda certificados ou credenciais federadas em vez de secrets em produção. Se você usa secret, a rotação sem interrupção é adicionar um novo antes de apagar o anterior:
# quando vence cada credencial (o valor não pode ser recuperado)
az ad app credential list --id "$APP_ID"
# um novo, SEM apagar o atual
az ad app credential reset --id "$APP_ID" --append --years 1
# quando o consumidor já usa o novo, o antigo é apagado pelo keyId
az ad app credential delete --id "$APP_ID" --key-id "$KEY_ID_ANTIGO"
Sem --append, o reset substitui as credenciais existentes e quem usava a anterior deixa de autenticar na hora. Anote o vencimento: no dia em que vence, a integração para de ler sem outro aviso além de um erro de login.
Comprovar que ele só lê
Antes de colá-lo em qualquer lugar, faça login com o service principal e teste as duas coisas. read -sp evita que o secret fique no histórico do shell:
read -sp "client secret: " AZ_PASS && echo
az login --service-principal -u "$APP_ID" -p "$AZ_PASS" --tenant "$TENANT"
# ler: tem que funcionar
az group list --output table
# escrever: tem que falhar com AuthorizationFailed
az group create --name teste-escrita --location eastus
# quais papéis ele tem e em qual scope
az role assignment list --assignee "$APP_ID" --all --output table
A criação do resource group tem que falhar com AuthorizationFailed e uma mensagem dizendo que o cliente "does not have authorization to perform action" nesse scope. Se ele for criado, o service principal tem um papel de escrita herdado de outro lugar: a última linha mostra qual e em qual scope. Apague o resource group de teste com o seu usuário e retire esse papel.
Fontes
- Microsoft Learn, "Create Azure service principals using the Azure CLI" e "Reset service principal credentials using the Azure CLI".
- Microsoft Learn, "Application and service principal objects in Microsoft Entra ID" e "What are managed identities for Azure resources?".
- Microsoft Learn, "Add and manage app credentials in Microsoft Entra ID" (vencimento dos client secrets).
- Microsoft Learn, "Azure built-in roles for General" (papel Reader) e "Assign access to Cost Management data".
- Referência da CLI:
az ad sp,az ad app credentialeaz role assignment.
Escrevo sobre infraestrutura no blog do Control Cloud, onde trabalho; a versão original desta nota está em https://controlcloud.dev/pt/blog/service-principal-azure-solo-lectura-reader?utm_source=tabnews&utm_medium=referral&utm_campaign=tabnews-azure-sp