Grant O365 Mailbox Permission to a Managed Identity - azure

Trying to get an Logic App to get email message details via Graph API because the O365 Outlook Connector does not provide the output I need but Graph API does (Internet message headers).
The Outlook connector creates an API Connection for authentication and that works great.
To call Graph API I am using the HTTP action and it supports Managed Identity, so I'm wondering:
Can I grant permission such that the Managed Identity can read a certain mailbox?
Can the HTTP action use an API Connection (similar to what the Outlook connector does)?

1.Can I grant permission such that the Managed Identity can read a certain mailbox?
The managed identity is a service principal, which we can check it and its permissions in the Azure portal -> Azure Active Directory -> Enterprise applications. But we could not add new permissions in that, so we need to create a new AD App in the App registrations, add credentials to your app
, then grant the Mail.Read application permission of Microsoft Graph API, refer to this link. The permission is to call this api List messages(I suppose you want to use this api, if not, just follow the doc to find the application permission, add it.) At last, don't forget to click the Grant admin consent button.
In the logic app, use Active Directory OAuth for Authentication, https://graph.microsoft.com/ for Audience, and specific the URL, Client id, secret, etc, what need to call the MS graph api. xxx#microsoft.com is the user principal name, also is the mailbox address. I am not sure I understand the read a certain mailbox in your question correctly enough, if you mean you want to grant the permission just for only one mailbox, I will say there is no such permission in Microsft graph.
2.Can the HTTP action use an API Connection (similar to what the Outlook connector does)?
There is no pre-bulit connector for http action, you could try the Custom connectors in Logic Apps.

There is a way to add that application role permission to the Managed Identity. It is not possible to do that using the Azure Portal. You can verify in the Azure Portal that the steps below worked though. This method saves you creating a principal yourself and removes the need for client id/secret bookkeeping.
When you use Powershell, it is possible to add the Mail.Read application role permission to a managed identity, be it a system managed or user managed identity. There are other ways of performing the same steps, e.g. Azure CLI. But below is what I know works and have used.
The steps are usable for any identity and application with assignable app roles. So you can also add Sharepoint permissions to list sites, open an Excel sheet. But keep in mind that the Microsoft app roles are mostly all or nothing. It breaks the principle of least priviliged permissions.
I would love to know a generic way to avoid breaking the principle.
To assign an app role permission to a managed identity we need to know a couple of things:
the id of...
...the managed identity (e.g. "logic-app-identity")
...the application that has the application role (e.g. "Microsoft Graph")
...the id of the application role to assign to the managed identity (e.g. "Mail.Read")
And then we can assign the app role to the managed identity.
Set up some variables for readability
$managed_identity_name = "logic-app-identity"
$application_with_the_required_role_name = "Microsoft Graph"
$application_role_to_assign_name = "Mail.Read"
Use AzureAD module and login.
Use the AzureAd module from here
Import-Module AzureAd
Connect-AzureAd #shows popup to login
1. Get the managed identity id
# filter first server side, and in case of multiple results, the where ensures a single result
# -All is necessary because a managed identity is a sort of service principal
$managed_identity_id = (Get-AzureADServicePrincipal -All $true -SearchString $managed_identity_name | where DisplayName -eq $managed_identity_name).ObjectId
2. Get the application with the requested application roles
# -SearchString on "Microsoft Graph" returns two results, therefore the where clause to ensure a single result
# storing the returned object, because it contains the approles array
$application_with_the_required_role = (Get-AzureADServicePrincipal -SearchString "Microsoft Graph" | where DisplayName -eq "Microsoft Graph")
# fun fact: the ObjectId of the "Microsoft Graph" application is always: 94d0e336-e38a-4bfc-9b21-8fbb74b6b835
$application_with_the_required_role_id = $application_with_the_required_role.ObjectId
3. Get the application role id to assign to the managed identity
# the required id is now simply called Id
# fun fact: the ObjectId of the "Mail.Read" app role is always: 810c84a8-4a9e-49e6-bf7d-12d183f40d01
$application_role_to_assign_id = ($application_with_the_required_role.AppRoles | where Value -eq $application_role_to_assign_name).Id
Assign the app role to the managed identity
New-AzureADServiceAppRoleAssignment -ObjectId $managed_identity_id -PrincipalId $managed_identity_id -ResourceId $application_with_the_required_role_id -Id $application_role_to_assign_id
BONUS: verify-ish the assignment
# should list the assigned application to the identity, dig further for the specific app role
# (I don't know how :S)
Get-AzureADServiceAppRoleAssignedTo -ObjectId $managed_identity_id | fl
# and the other way around to list the identities assigned to the application
Get-AzureADServiceAppRoleAssignment -ObjectId $application_with_the_required_role_id | fl

Related

Unable to assign a role to user assigned identity through Azure Run books

By using the below command, trying to assign a role to the managed identity using PowerShell runbook(5.1 Runtime version).
$roleAssignment = New-AzRoleAssignment -ObjectId 'xxxx-xxxx-xxxx-xxxx' -Scope '/subscriptions/xxxx-xxxx-xxxx/resourceGroups/xxxxxxxxx' -RoleDefinitionName 'Contributor'
When we execute the runbook we ran into the below error.
Exception of type 'Microsoft.Rest.Azure.CloudException' was thrown.
But, When executed the same command from local PowerShell ISE we are able to assign the role with out any fail.
How to make runbook to assign the role to the user assigned identity.
Can any one help me solve this.
Unable to assign a role to user assigned identity through Azure Run books (1).html
Unable to assign a role to user assigned identity through Azure Run books
Exception of type ‘Microsoft.Rest.Azure.CloudException’ was thrown.
To resolve the above error, I would suggest you try to follow the below workaround that worked for me: -
Go to Azure AD --> App registrations --> Select your app --> API Permissions --> Add permission --> Microsoft Graph (You can select any Azure resource for which you want to grant permissions for) --> Application Permissions --> Directory --> Directory.Read.All
Then grant admin consent for the selected permissions for that particular resource.
Here, you can select other services which you are using, also in ‘Request API Permissions’ other than Microsoft Graph, you can use other APIs that you are working since the process is same as shown in the below snapshot: -

How do I specify Permissions in a custom app consent policy?

I have successfully made a Custom App Consent Policy using New-AzureADMSPermissionGrantConditionSet and following the MS docs. I specified ClientApplicationIds and it works great.
Now I also want to specify the permissions that must match. On Permissions, the docs say:
I need help understanding (and accessing) the permission IDs in the "OAuth2Permissions property of the API's ServicePrincipal object".
What ServicePrincipal is the doc referring to? The one in the application’s Home Tenant, or one in the Tenant that is using the application? If the app has not been consented to yet, then there is no ServicePrinciple in the Tenant using the app so I have a chicken-and-egg problem.
And what are the Permissions I'm expecting to get? I'm wondering why MS didn't just let us pass the scopes as strings e.g. email, mail.read etc. I don't understand exactly what the Permissions are in this particular context.
I need help understanding (and accessing) the permission IDs in the "OAuth2Permissions property of the API's ServicePrincipal object".
The permission ID means the id of the Delegated permission of the API( i.e. oauth2Permissions defined in the API) you added in the client app registration.
For example, you created a multi-tenant client app in tenant A, you added the Mail.Read Delegated permission of Microsoft Graph, by default, there would also be a User.Read Delegated permission automatically, so there are two permissions totally in the API permissions of your client app.
Now, you want to use the custom app consent policy in tenant B, you want the user to consent the two permissions, then the -Permissions should be the id of the two permission defined in Microsoft Graph, to find it easily, just navigate to the client app in tenant A -> Manifest, then you can get the ids like below.
The complete command should be
New-AzureADMSPermissionGrantConditionSet `
-PolicyId "joy-custom-policy" `
-ConditionSetType "includes" `
-PermissionType "delegated" `
-ResourceApplication "00000003-0000-0000-c000-000000000000" `
-Permissions #("e1fe6dd8-ba31-4d61-89e7-88639da4683d","570282fd-fa5c-430d-a7fd-fc8dc98a9dca")
In another scenario, you use the custom API(created in tenant A) in the client app instead of a Microsoft API.
If so, you need to grant admin consent for the API App in tenant B first, otherwise you will get an error The app needs access to a service (\"api://tenantA/myapi\") that your organization (tenant B) has not subscribed to or enabled, or you can use the admin account to run New-AzureADServicePrincipal -AppId <appid of the API app> in tenant B, it will also work, after consent, the normal user will be able to consent the permission you defined in the policy.
Note: Sometimes, you may get an error This app may be risky like below.
This means Microsoft detects a risky end-user consent request, the request will require a step-up to admin consent instead, if you still want the user to consent the permission, you need to disable the risk-based step-up consent first, then the user will be able to consent the permission.
Here's an example for how you would get the permission IDs for three delegated permissions for Microsoft Graph, using Azure AD PowerShell:
# The appId for the client application
$clientAppId = "{client-app-id}"
# The claim values for the Microsoft Graph delegated permissions to include
$claimValues = #("User.Read", "Mail.Send", "User.ReadBasic.All")
# Get the service principal for Microsoft Graph
$resource = Get-AzureADServicePrincipal -Filter "servicePrincipalNames/any(n:n eq 'https://graph.microsoft.com')"
# Get the delegated permission IDs for the given claim values
$permissionIds = $resource.OAuth2Permissions `
| ? { $claimValues.Contains($_.Value) } | select -ExpandProperty Id
# Use these permission IDs in a condition set for a custom permission grant policy
New-AzureADMSPermissionGrantConditionSet `
-PolicyId "my-custom-policy" `
-ConditionSetType "includes" `
-ClientApplicationIds #($clientAppId) `
-PermissionType "delegated" `
-ResourceApplication $resource.AppId `
-Permissions $permissionIds

How to Connect-AzAccount in Powershell Core (without prompt)?

I did see this q/a: Connect-AzAccount without prompt
But when I tried the accepted answer, I get the following error:
[6/12/2020 12:36:20 AM] ERROR: Connect-AzAccount : Username + Password authentication is not supported in PowerShell Core. Please use device code authentication for interactive log in, or Service Principal authentication for script log in.
So I went to example 3 of the Connect-AzAccount documentation which specifies the "Service Principal" authentication method, so I mix the two because the suggested vanilla Get-Credential triggers another interactive session. So here's the script now:
$User = "myemail#gmail.com"
$PWord = ConvertTo-SecureString -String "**********" -AsPlainText -Force
$tenant = "f*********************************"
$Credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $User,$PWord
# $Credential = Get-Credential
Connect-AzAccount -Credential $Credential -Tenant $tenant -ServicePrincipal
which brings my next error: [6/12/2020 12:45:45 AM] ERROR: Connect-AzAccount : AADSTS700016: Application with identifier 'myemail' was not found in the directory 'f*********************************'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.
I'm really confused at this point because all I have done at this point in Azure is:
Create a new Azure account
Provision an Azure API Management instance through the UI (which btw, takes like 20 minutes)
Try the above code to connect to Azure inside of a Powershell Azure Function locally.
I think something is wrong with the information I've provided or how I've configured something.
$User is the email I signed up to Azure with.
$PWord is my Azure password
$tenant is the first thing I saw when I opened Azure AD:
What's wrong with how I'm trying to connect to Azure through Powershell Core?
Based on Example 3, it asks for entering your application ID for the username and service principal secret as the password.
So you need to create a service principal at first. And then use its application ID and client secret as the credential.
$User = "{application id}"
$PWord = ConvertTo-SecureString -String "{client secret}" -AsPlainText -Force
I don't like Azure documentation. It gives off a very different vibe from GCP and feels much less beginner friendly.
With that said, they did have some kind of write-up that addresses my issue of creating a service principal and using it to authenticate.
I actually ended up just finding a video (and I never do this) because I wanted to skip past all the technical jargon and just create the darn service principal.
It's not even intuitive - it's like Microsoft could have added a button in AZ AD or IAM that said "Create Service Principal" but no, you have to go to a bunch of other pages that say nothing about service principals. You'll see:
In Azure Portal, navigate to the App Registrations page in Azure Active Directory. What an "app registration" has to do with a service principal, I couldn't tell you. I also couldn't tell you what a service principal is, but I'd imagine it has something to do with service accounts.
Make a New Registration and give it some sort of name to describe what the scope of this service principal will entail. Like normal service account naming conventions. I don't think the account type matters but I chose Multitenant. Redirect URL has nothing to do with service principals, and honestly makes it all the more confusing. I would never associate service accounts with any kind of redirect url, but here we are.
You're going to arrive at a page with Display Name (the name of the service principal you gave it in step 2), Application (client) ID (this is actually your service account username, which is imo non-intuitive), and Object ID (I have no idea what this is but I never needed to use it.
Guess what, you have only created 1/3 of your service account. It doesn't even have a password yet. Within your created app registration, there's a Certificates & Secrets page. On that page, you want to add a new client secret. For my description I just put my service principal "display name". I don't think that was necessary because this client secret is within the scope of the app registration, so even if I named it "poop" I could reasonably assume what it was for. Azure will generate a nuanced client secret and display it, but not warn you that this is the only time you will be able to see the key. Copy it. This is, in normal people talk, your service principal password.
For the last step, you need to get out of dodge, I mean Azure AD. Navigate to your Subscriptions page and click on your active subcription. For some reason IAM is here, so click on that. At this point, your service principal has a username and password, but no actual permissions - you have to configure that manually too. Click Add -> Add Role Assignment. For role, you should do your research but if it's not serious Contributor is probably a safe bet. It has read/write but it doesn't supersede Owner. Make sure you're assigning access to a service principal, and search for its display name. Save.
With all of that done, Connect-AzAccount finally worked.

Add AAD application as a member of a security group

I'm trying to enable service to service auth using AAD tokens. My plan is to validate "groups" claim in the token to make sure the caller is a member of a security group that we created.
For example, we will create group1 for readers and group2 for writers. Then based on "groups" claim, I will figure out the right access level.
I use AAD app to issue the tokens (not a user), so I need that app to be a member of the security group. Azure AD powershell doesn't seem to accept application ids as group members. How to solve this? are there any other recommended patterns when the caller is another AAD app?
Command used:
https://learn.microsoft.com/en-us/powershell/module/azuread/Add-AzureADGroupMember?view=azureadps-2.0
Error:
Add-AzureADGroupMember : Error occurred while executing AddGroupMember
Code: Request_BadRequest
Message: An invalid operation was included in the following modified references: 'members'.
RequestId: 0441a156-3a34-484b-83d7-a7863d14654e
DateTimeStamp: Mon, 11 Dec 2017 21:50:41 GMT
HttpStatusCode: BadRequest
HttpStatusDescription: Bad Request
HttpResponseStatus: Completed
At line:1 char:1
+ Add-AzureADGroupMember -ObjectId "9c2cdf89-b8d6-4fb9-9116-7749adec85c ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Add-AzureADGroupMember], ApiException
+ FullyQualifiedErrorId : Microsoft.Open.AzureAD16.Client.ApiException,Microsoft.Open.AzureAD16.PowerShell.AddGroupMember
Unfortunately, you cannot add an application as a member of Azure AD group.
Though the official document for the Powershell cmdlet Add-AzureADGroupMember doesn't make clear you cannot use Application's ObjectId as the RefObjectId, absolutely you cannot use it.
You cannot add an application as a member of Azure AD group neither.
For example, we will create group1 for readers and group2 for writers.
Then based on "groups" claim, I will figure out the right access
level.
For your scenario, I'm afraid that you couldn't achieve this for now. I understand why you need this. According to your request, my thought is assigning your application from Enterprise Application to Groups or users and manger users with different access rights. However, you cannot choose more roles for the selected group. The only one role is default access If want to define more roles for the app, you can refer to this documentation.
I also tried to use Azure AD RBAC and create new conditional access for my test app,but all don't have read only this choice.
You can also put your idea in Azure Feedback Forum, azure team will see it. Also, I will upvote your idea.
Update:
Currently, you can add a service principal to an AAD Group:
Example:
$spn = Get-AzureADServicePrincipal -SearchString "yourSpName"
$group = Get-AzureADGroup -SearchString "yourGroupName"
Add-AzureADGroupMember -ObjectId $($group.ObjectId) -RefObjectId $($spn.ObjectId)
Updated 2:
Recently, I also see lots of users want to assign roles to a service principal to let the service principal have some permissions to access to the app with a role.
I want to make clear here. Role-based authorized should be used for users, NOT applications. And it's not designed for applications. If you want to give some different permissions you may consider to assign application permissions to your service principal instead.
You can expose your Web App/API with application permissions by editing the Manifest in app registrations.
You can go to Azure portal > Azure Active Directory > App registrations > Select your App > Manifest.
In appRoles, you can insert content like this:
{
"allowedMemberTypes": [
"Application"
],
"displayName": "Access to the settings data",
"id": "c20e145e-5459-4a6c-a074-b942bbd4cfe1",
"isEnabled": true,
"description": "Administrators can access to the settings data in their tenant",
"value": "Settingsdata.ReadWrite.All"
},
Then, you can go another app registration you want to give permission > Settings > require permissions > Add > Search the application name you want to access > Choose the application permission you created before.
Therefore, your sp can obtain a token with that application permissions in token claims.
Also, for authorization from the resource, you need to add code logic to give control policy for that token with Settingsdata.ReadWrite.All claim.
Update 3
Currently, you can add the service principal to one AAD Group directly in Azure portal:
Following Update 3 in the answer of #Wayne Yang, I've successfully implemented this using C# and the MS Graph SDK.
But I think the same should be possible using Powershell and simple REST API calls.
// create new application registration
var app = new Application
{
DisplayName = principal.DisplayName,
Description = principal.Description,
};
app = await _graphClient.Applications.Request().AddAsync(app);
// create new service Principal based on newly created application
var servicePrincipal = new ServicePrincipal
{
AppId = app.AppId
};
// add service principal
servicePrincipal = await _graphClient.ServicePrincipals.Request().AddAsync(servicePrincipal);
// add service principal to existing security group
await _graphClient.Groups[groupId].Members.References.Request().AddAsync(servicePrincipal);

Grant an existing B2C app access to graph API

I have an existing B2C app that I want to give graph access to.
I set this up previously but now want to replicate it but everything i can find is for new apps. I ysed the older graph but i think the article I used has been moved as everything is talking about the new Graph api
Is there a specific article for this, also if anyone has seen an article that describes the process from moving from Azure graph to Microsoft Graph (the new version) for a B2C app that would be great
Thanks
Register the application for the Graph API
In addition to registering the application in the B2C directory,
we must also create an application registration for the graph API.
The three key/id values you will need are the tenantId, ObjectId,
and AppPrincipalId.
To get the tenantId, log into the azure ad b2c directory in the new portal.
https://portal.azure.com/
Be sure you have the correct directory selected after you login
(top right corner).
Click on the help button (a question mark inside a circle) near the
top right corner of the page. In the menu that appears, click the
"Show diagnostics" option. This will display a JSON formatted output in
a new popup/window. Look for the "tenants" array and find the entry
with the display name of the directory you wish to register with the
application. The "id" attribute of that entry is the tenantId.
Example:
{
"clientSessionStartDate": {
//stuff will be here ...
},
//
// more shtuff you don't care about will be here ...
//
"tenants": [
{
"id": "SomeUUIDwithlike36charactersSometime",
"domainName": "yourtenantname.onmicrosoft.com",
"displayName": "displanynameoftenant",
"isSignedInTenant": true
},
// ... snippity lemon
]
// ... snip some more
}
You will also need a unique application Secret and AppPrincipalId to be
generated for the new application.
Also, to set the correct permissions for the application, you will need
its "ObjectId".
The process for registering the application and generating those values
is more complicated, and requires a special module for PowerShell
and the online login module to be downloaded and installed.
Also, be sure you have the latest version of PowerShell installed for
your system, or you will not be able to use the azure module.
Sign-In assistant: https://www.microsoft.com/en-us/download/details.aspx?id=41950
Azure AD PowerShell Module: http://go.microsoft.com/fwlink/p/?linkid=236297
Create the application registration with PowerShell
This next section is an almost verbatim copy-paste fo the documentation.
https://azure.microsoft.com/en-us/documentation/articles/active-directory-b2c-devquickstarts-graph-dotnet/
After you install the PowerShell module, open PowerShell and connect to
your B2C tenant.
> $msolcred = Get-Credential
After you run Get-Credential, you will be prompted for
a user name and password, Enter the user name and password
of your B2C tenant administrator account.
> Connect-MsolService -credential $msolcred
Before you create your application, you need to generate a new client
secret. Your application will use the client secret to authenticate to
Azure AD and to acquire access tokens. You can generate a valid secret
in PowerShell:
> $bytes = New-Object Byte[] 32
> $rand = [System.Security.Cryptography.RandomNumberGenerator]::Create()
> $rand.GetBytes($bytes)
> $rand.Dispose()
> $newClientSecret = [System.Convert]::ToBase64String($bytes)
> $newClientSecret
The final command should print your new client secret. Copy it somewhere safe. You'll need it later. Now you can create your application by providing the new client secret as a credential for the app:
> New-MsolServicePrincipal -DisplayName "My New B2C Graph API App" -Type password -Value $newClientSecret
Example output:
DisplayName : My New B2C Graph API App
ServicePrincipalNames : {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
ObjectId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
AppPrincipalId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
TrustedForDelegation : False
AccountEnabled : True
Addresses : {}
KeyType : Password
KeyId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
StartDate : 1/1/2017 1:33:09 AM
EndDate : 1/1/2017 1:33:09 AM
Usage : Verify
If you successfully create the application, it should print out
properties of the application like the ones above, but with a mix of alpha-numeric characters. You'll need both
ObjectId and AppPrincipalId, so copy those values, too.
You will also need the tenant ID of the B2C directory.
After you create an application in your B2C tenant, you need to assign
it the permissions it needs to perform user CRUD operations. Assign the
application three roles: directory readers (to read users), directory
writers (to create and update users), and a user account administrator
(to delete users). These roles have well-known identifiers, so you can
replace the -RoleMemberObjectId parameter with ObjectId from above and
run the following commands. To see the list of all directory roles,
try running Get-MsolRole.
> Add-MsolRoleMember -RoleObjectId 88d8e3e3-8f55-4a1e-953a-9b9898b8876b -RoleMemberObjectId <Your-ObjectId> -RoleMemberType servicePrincipal
> Add-MsolRoleMember -RoleObjectId 9360feb5-f418-4baa-8175-e2a00bac4301 -RoleMemberObjectId <Your-ObjectId> -RoleMemberType servicePrincipal
> Add-MsolRoleMember -RoleObjectId fe930be7-5e62-47db-91af-98c3a49a38b1 -RoleMemberObjectId <Your-ObjectId> -RoleMemberType servicePrincipal
You now have an application that has permission to create, read,
update, and delete users from your B2C tenant.
I totally forgot this great answer exists and this is how you do it
Authorize By Group in Azure Active Directory B2C

Resources