Custom Entra ID Role — EnergyConnect Infrastructure Deployer
Overview
Each EnergyConnect environment uses an Azure DevOps service connection to deploy infrastructure. These service connections are backed by Entra ID app registrations with federated credentials.
Rather than granting broad built-in roles (such as Directory Writers) or tenant-wide Graph API permissions (such as Group.ReadWrite.All), we use a custom Entra ID role that grants only the permissions required for infrastructure deployment.
Role name: EnergyConnect Infrastructure Deployer
Design Principles
- No Graph API application permissions. All operations are handled through the custom directory role — no
Application.ReadWrite.OwnedBy,AppRoleAssignment.ReadWrite.All, orGroup.ReadWrite.Allpermissions are granted on the app registration. - One role per tenant. The role is defined once per Entra ID tenant and assigned to each environment's service connection.
createAsOwnerfor traceability. The role usescreateAsOwner(rather thancreate) so that the service connection is automatically added as owner of resources it creates. This provides an audit trail of which service connection created each resource. Note: ownership is not required for subsequent updates — the update permissions are directory-scoped and apply to all resources of that type in the tenant.
What the Role Enables
The infrastructure deployment (Bicep with extension microsoftGraphV1) performs these Entra ID operations:
| Operation | Bicep resource type | Example |
|---|---|---|
| Create app registrations | Microsoft.Graph/applications | Client auth app, AdvancedVEE app |
| Update app registration properties | Microsoft.Graph/applications | App roles, redirect URIs, scopes, audience |
| Create service principals | Microsoft.Graph/servicePrincipals | Enterprise app for the app registration |
| Assign app roles to groups | Microsoft.Graph/appRoleAssignedTo | Grant "MeteringPoint.Writer" role to the Administrator group |
| Create security groups | Microsoft.Graph/groups | Infrastructure groups (Owner, Contributor, Reader, VM Admin), application groups (Administrator, CPMPHandler, etc.) |
Permissions
App Registrations
| Permission | Why |
|---|---|
applications/createAsOwner | Create app registrations (client auth, AdvancedVEE). The SC is auto-added as owner for traceability. |
applications/allProperties/read | Read all properties. Required by the Graph extension to resolve existing apps by uniqueName and read back properties after creation. Narrower reads (standard/read + owners/read) are insufficient. |
applications/basic/update | Update display name, description, homepage URL. |
applications/appRoles/update | Define app roles (e.g., MeteringPoint.Reader, ConnectionPoint.Writer). |
applications/credentials/update | Manage certificates and client secrets. |
applications/authentication/update | Configure redirect URIs, implicit flow settings, and sign-out URLs. |
applications/permissions/update | Configure required API permissions and exposed scopes (oauth2PermissionScopes). |
applications/audience/update | Set the signInAudience property (used by the AdvancedVEE app registration). |
Service Principals
| Permission | Why |
|---|---|
servicePrincipals/createAsOwner | Create the enterprise app (service principal) for each app registration. |
servicePrincipals/allProperties/read | Read all SP properties. Required by the Graph extension to resolve the SP and read its appRoles when creating appRoleAssignedTo resources. Narrower reads are insufficient. |
servicePrincipals/basic/update | Update basic properties like display name and account enabled status. |
servicePrincipals/appRoleAssignedTo/update | Assign app roles to Entra ID groups on the service principal (e.g., assign the "MeteringPoint.Writer" role to the "Administrator" group). |
Security Groups
| Permission | Why |
|---|---|
groups.security/createAsOwner | Create security groups for infrastructure RBAC (Owner, Contributor, Reader, VM Admin) and application roles (Administrator, CPMPHandler, CPMPReader, SystemReader, Hangfire). Uses groups.security/ (not groups/) to limit creation to security groups only. |
groups/standard/read | Read standard group properties. Note: groups.security/standard/read does not exist in Entra ID custom roles — groups/standard/read covers all group types. |
groups.security/basic/update | Update display name and description of security groups. |
groups.security/members/update | Manage security group membership. |
groups.security/owners/update | Manage security group ownership. |