Entra App Management Policies: Restringir Secrets e Certificados

As credenciais de aplicações — secrets, certificados, symmetric keys — estão entre os artefactos mais explorados em ataques a tenants Microsoft: um secret vazado num script é acesso silencioso ao Graph, muitas vezes com permissões de aplicação (sem utilizador ao balcão). O consent phishing típico não precisaria disto, mas a realidade de uma PME costuma ser mais banal: apps registadas há anos, secrets com dois anos de validade e ninguém a saber ao certo quem as criou.

App Management Policies do Microsoft Entra ID dão ao tenant uma camada de controlo sobre como apps e service principals podem ser configurados: que credenciais podem ser criadas, com que validade máxima, que identifier URIs são aceites e que audiences são permitidas. É a política que impede o próximo secret “nunca expira” de nascer num tenant que já viveu um incidente.

O que as políticas cobrem

Um bloco applicationRestrictions controla aplicações, um bloco servicePrincipalRestrictions controla service principals. As restrições disponíveis:

Restrição O que faz No admin center
passwordAddition + symmetricKeyAddition Bloqueia a criação de novos secrets (passwords) e symmetric keys Block password addition
passwordLifetime + symmetricKeyLifetime Impõe uma vida útil máxima a secrets Restrict max password lifetime
asymmetricKeyLifetime Impõe uma vida útil máxima a certificados Restrict max certificate lifetime
customPasswordAddition Bloqueia secrets criados por clientes (ex.: módulos PowerShell antigos que geram a password localmente) — não bloqueia secrets gerados pelo Entra Block custom passwords
nonDefaultUriAddition Só aceita identifier URIs por defeito: api://{appId} ou api://{tenantId}/{appId} Block custom identifier URIs
uriAdditionWithoutUniqueTenantIdentifier Bloqueia URIs sem identificador único do tenant Block identifier URIs without unique tenant identifier
audiences Restringe por signInAudience — bloqueia apps multitenant ou de contas consumer Block multitenant applications / Block consumer account applications
trustedCertificateAuthority Só aceita certificados emitidos pelas CAs confiáveis do tenant Só API

Cada restrição tem um state (enabled/disabled) e, nas de lifetime, um maxLifetime em formato ISO-8601 — por exemplo P180D para 180 dias. A Microsoft exige paridade nos blocos de lifetime (documentado no guia de configuração do Entra): passwordAddition e passwordLifetime esperam os QUATRO blocos em igual estado — a restrição e a correspondente symmetricKeyAddition/symmetricKeyLifetime, nas colecções applicationRestrictions e servicePrincipalRestrictions — ou nenhum deles presente. O certificado (asymmetricKeyLifetime) segue a mesma régua nos DOIS blocos de keyCredentials. O agrupamento do portal é diferente: Block password addition e Restrict max password lifetime juntam password+symmetric key, e o Restrict max certificate lifetime fica isolado.

Âmbito temporal: os exemplos desta secção usam state, formato visível na API beta. Os exemplos oficiais em /v1.0/ usam antes restrictForAppsCreatedAfterDateTime — a data a partir da qual a restrição se aplica a apps novas, e que a Microsoft documenta poder aplicar-se retroactivamente a apps existentes (apps criadas antes da data ficam de fora, salvo outra política que as cubra). As duas propriedades coexistem no mesmo objecto de restrição — ao partir de exemplos v1.0 vem a data, não o estado.

Política por omissão do tenant

No topo está a tenant-wide application authentication settings policy, o objeto defaultAppManagementPolicy — existe sempre, não se cria nem apaga, e aplica-se a todas as apps e service principals do tenant. Vem desactivada de origem (isEnabled: false): os PATCHes abaixo enviam isEnabled: true — sem essa linha, as restrições gravam mas não chegam a aplicar-se.

⚠️ Atenção: o que uma política custom define tem prioridade sobre o default — nos dois sentidos. Pode apertar regras para uma app específica, mas também desligar uma restrição que o default impõe (é assim que nascem as excepções): uma restrição marcada disabled na política da app não se aplica, independentemente do default do tenant. Só o que a política custom NÃO define herda do default.

Quando o default não chega, criam-se custom app management policies: uma política custom permite regras diferentes para uma app específica — e cada application ou service principal só pode ter uma política custom atribuída. Os dois usos típicos: dar excepções (a política custom desliga a restrição para essa app) ou apertar (uma app crítica com validade de secret de 30 dias enquanto o resto do tenant fica em 180).

Aplicar no Microsoft Graph

Bloquear a criação de secrets em todo o tenant

O PATCH a seguir activa passwordAddition e symmetricKeyAddition nas duas colecções — aplicações e service principals:


Connect-MgGraph -Scopes "Policy.ReadWrite.ApplicationConfiguration"

$body = @{
    isEnabled = $true
    applicationRestrictions = @{
        passwordCredentials = @(
            @{ restrictionType = "passwordAddition"; state = "enabled" }
            @{ restrictionType = "symmetricKeyAddition"; state = "enabled" }
        )
    }
    servicePrincipalRestrictions = @{
        passwordCredentials = @(
            @{ restrictionType = "passwordAddition"; state = "enabled" }
            @{ restrictionType = "symmetricKeyAddition"; state = "enabled" }
        )
    }
} | ConvertTo-Json -Depth 6

Invoke-MgGraphRequest -Method PATCH `
  -Uri "https://graph.microsoft.com/beta/policies/defaultAppManagementPolicy" `
  -Body $body -ContentType "application/json"

O admin center faz o mesmo sem Graph: Entra ID > Enterprise apps > Application policies > Block password addition, estado On, Applies to = All applications, Save.

Limitar a vida de certificados a 180 dias


$body = @{
    isEnabled = $true
    applicationRestrictions = @{
        keyCredentials = @(
            @{ restrictionType = "asymmetricKeyLifetime"; state = "enabled"; maxLifetime = "P180D" }
        )
    }
    servicePrincipalRestrictions = @{
        keyCredentials = @(
            @{ restrictionType = "asymmetricKeyLifetime"; state = "enabled"; maxLifetime = "P180D" }
        )
    }
} | ConvertTo-Json -Depth 6

Invoke-MgGraphRequest -Method PATCH `
  -Uri "https://graph.microsoft.com/beta/policies/defaultAppManagementPolicy" `
  -Body $body -ContentType "application/json"

Para secrets, a mecânica é igual com passwordLifetime/symmetricKeyLifetime (os quatro blocos no mesmo estado, como visto acima).

Excepção para uma app específica

Uma política custom com a restrição desligada — por exemplo, uma app que precisa de identifier URIs fora dos formatos padrão:


$body = @{
    displayName = "Excepcao identifier URIs"
    description = "Policy granting an exemption to the nonDefaultUriAddition restriction"
    isEnabled = $true
    restrictions = @{
        applicationRestrictions = @{
            identifierUris = @{
                nonDefaultUriAddition = @{ state = "disabled" }
            }
        }
    }
} | ConvertTo-Json -Depth 6

$p = Invoke-MgGraphRequest -Method POST `
  -Uri "https://graph.microsoft.com/beta/policies/appManagementPolicies" `
  -Body $body -ContentType "application/json"

# Atribuir a app concreta ao objecto policies
Invoke-MgGraphRequest -Method POST `
  -Uri "https://graph.microsoft.com/beta/applications/{objectId-da-app}/appManagementPolicies/`$ref" `
  -Body (@{ "@odata.id" = "https://graph.microsoft.com/v1.0/policies/appManagementPolicies/$($p.id)" } | ConvertTo-Json) `
  -ContentType "application/json"

Se a app já tiver política própria, a excepção entra nessa política — e convém confirmar que a política não está atribuída a mais apps, ou a excepção espalha-se.

Excepção para um processo (caller exception)

Quando quem viola a política não é a app mas o processo que a cria — um runner que regista apps e cria secrets em lote —, a excepção dá-se ao actor via custom security attributes, na secção Excluded callers da restrição. Este tipo de excepção usa custom security attributes e requer as roles Attribute Definition Administrator (definir o atributo) e Attribute Assignment Administrator (atribuir ao actor), para além das roles de configuração das políticas. A Attribute Assignment Reader só é necessária para quem usa o Entra admin center ou o portal Azure — via Graph ou PowerShell não é exigida.

Os exemplos usam o endpoint /beta/, como na documentação da feature — o resource appManagementPolicy também existe em /v1.0/.

Papéis necessários

Para configurar app management policies: Security Administrator e mais Cloud Application Administrator ou Application Administrator — ou um Global Administrator sozinho. Leitura e atribuição têm papéis próprios na API. A aplicação prática do dia-a-dia é esta dupla.

O que as políticas NÃO fazem

  • Não revogam nem apagam credenciais já existentes — as restrições são sobre a criação e a configuração a partir daí. Os secrets antigos, se existirem, mantêm-se até expirar ou serem apagados à mão — um inventário prévio de apps cobre essa parte.
  • A restrição customPasswordAddition não bloqueia secrets gerados pelo próprio Entra no portal/Graph — bloqueia só os criados pelo cliente (SDKs antigos, módulos PowerShell legacy).
  • trustedCertificateAuthority só está disponível via API — sem toggle no admin center.

Erros comuns

  • O admin center recusa editar restrições manipuladas na API — aparece “The restriction have been modified outside of this interface. To prevent data loss, editing is disabled until restrictions are synchronized.” As restrições de lifetime têm a regra de paridade: os 4 blocos de password/symmetric key (e os 2 de certificado) têm de estar no mesmo estado — ou ausentes por inteiro. A correcção faz-se no Graph.
  • A excepção fica atribuída a mais apps do que pretendido — as políticas custom partilham-se por atribuição — ver sempre appliesTo antes de gravar.
  • Apps multitenant de terceiros — as restrições a service principals de outros tenants aplicam-se no objeto SP — sem isso, apps SaaS com secrets continuam nas regras do tenant de origem.

Artigos Relacionados

Fontes oficiais