From 8594806cd09a77fdd037bb73e98719bf6461a6eb Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 12 Aug 2021 16:01:35 +0200 Subject: [PATCH 01/29] Update and rename _lesson_template.md to managed-identity-powershell.md added basic steps to assign managed identity --- lessons/_lesson_template.md | 83 --------- lessons/managed-identity-powershell.md | 240 +++++++++++++++++++++++++ 2 files changed, 240 insertions(+), 83 deletions(-) delete mode 100644 lessons/_lesson_template.md create mode 100644 lessons/managed-identity-powershell.md diff --git a/lessons/_lesson_template.md b/lessons/_lesson_template.md deleted file mode 100644 index 5ecae86a..00000000 --- a/lessons/_lesson_template.md +++ /dev/null @@ -1,83 +0,0 @@ -# Lesson Title ({language}) - -Watch the recording of this lesson [on YouTube](). - -## Goal 🎯 - -The goal of this lesson is to ... - -This lessons consists of the following exercises: - -|Nr|Exercise -|-|- -|0|[Prerequisites](#0-prerequisites) -|1|Exercise title 1 -|2|Exercise title 2 -|3|Exercise title 3 -|4|[Homework](#4-homework) -|5|[More info](#5-more-info) - -> πŸ“ **Tip** - If you're stuck at any point you can have a look at the [source code](../../src/{language}/{topic}) in this repository. - ---- - -## 0. Prerequisites - -| Prerequisite | Exercise -| - | - - -See [{language} prerequisites](../prerequisites/prerequisites-{language}.md) for more details. - -## 1. Exercise title 1 - -//TODO Describe sub goal - -### Steps - -1. -2. -3. - -> πŸ“ **Tip** - < TIP > - -> πŸ”Ž **Observation** - < OBSERVATION > - -> ❔ **Question** - < QUESTION > - -## 2. Exercise title 2 - -//TODO Describe sub goal -### Steps - -1. -2. -3. - -> πŸ“ **Tip** - < TIP > - -> πŸ”Ž **Observation** - < OBSERVATION > - -> ❔ **Question** - < QUESTION > - -## 3. Exercise title 3 - -//TODO Describe sub goal - -### Steps - -1. -2. -3. - -> πŸ“ **Tip** - < TIP > - -> πŸ”Ž **Observation** - < OBSERVATION > - -> ❔ **Question** - < QUESTION > - -## 4. Homework - -## 5. More info - ---- -[πŸ”Ό Lessons Index](../../README.md) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md new file mode 100644 index 00000000..0adb11ec --- /dev/null +++ b/lessons/managed-identity-powershell.md @@ -0,0 +1,240 @@ +# Managed Identity (PowerShell) + +Watch the recording of this lesson [on YouTube](). + +## Goal 🎯 + +The goal of this lesson is to understand how you can create and use a system assigned managed to call an Azure function in order to obtain a Microsoft Graph access token with the right permission scope. Microsoft Graph is THE API for all things Microsoft 365. + +This lessons consists of the following exercises: + +|Nr|Exercise +|-|- +|0|[Prerequisites](#0-prerequisites) +|1|[Create an Azure Functions](#1-create-an-azure-functions) +|2|[Create Azure resources](#2-create-azure-resources) +|3|[Create Managed Identity and assign permissions](#3-create-managed-identity-and-assign-permissions) +|4|[Obtain an access token](#4-obtain-an-access-token) +|5|[Homework](#5-homework) +|6|[More info](#6-more-info) + +> πŸ“ **Tip** - If you're stuck at any point you can have a look at the [source code](../../src/{language}/{topic}) in this repository. + +--- + +## 0. Prerequisites + +| Prerequisite | Exercise +| - | - + +See [{language} prerequisites](../prerequisites/prerequisites-{language}.md) for more details. + +## 1. Create an Azure Functions + +before we will deploy our app to Azure, we will develop it locally in Visual Studio Code. This comes with some great advantages such as + +* we don’t need to adjust to ever changing UI in Azure portal +* we can benefit from source control +* we can collaborate with others + +### Steps + +1. Install the Core Tools package with `npm install -g azure-functions-core-tools@3 --unsafe-perm true` +2. Install the [Azure Functions extension for VS Code](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions) +3. Select **New Project** +4. Select a folder for your project +5. Select a language – I will use PowerShell +6. Select **HTTP trigger** as a template +7. Type in a better name like `GetGraphToken` +8. Select Authorization level **Function** +9. Select how you want to open your project – I prefer **Add to workspace** +10. Open `run.ps1` +11. Replace the default code by this: + +``` +using namespace System.Net + +# Input bindings are passed in via param block +param($Request, $TriggerMetadata) + +# Write to the Azure Functions log stream. +Write-Host "PowerShell HTTP trigger function processed a request." + +# Interact with query parameters or the body of the request +.$Scope = $Request.Query.Scope +if (-not $Scope) { + $Scope = $Request.Body.Scope +} +#If parameter "Scope" has not been provided, we assume that graph.microsoft.com is the target resource +If (!$Scope) { + $Scope = "https://graph.microsoft.com/" +} + +$tokenAuthUri = $env:IDENTITY_ENDPOINT + "?resource=$Scope&api-version=2019-08-01" +$response = Invoke-RestMethod -Method Get -Headers @{"X-IDENTITY-HEADER"="$env:IDENTITY_HEADER"} -Uri $tokenAuthUri -UseBasicParsing + +$accessToken = $response.access_token + +#Invoke REST call to Graph API +$uri = 'https://graph.microsoft.com/v1.0/groups' +$authHeader = @{ +'Content-Type'='application/json' +'Authorization'='Bearer ' + $accessToken +} + +$result = (Invoke-RestMethod -Uri $uri -Headers $authHeader -Method Get -ResponseHeadersVariable RES).value + +If ($result) { + $body = $result + $StatusCode = '200' +} +Else { + $body = $RES + $StatusCode = '400'} + +# Associate values to output bindings by calling 'Push-OutputBinding' +Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $body +}) +``` +> πŸ“ **Tip** - Watch out – the Graph API will this way return up to 100 groups – Please adjust with query parameters as needed like `https://graph.microsoft.com/v1.0/groups?$top=42` or use pagination, which is described here: [Paging Microsoft Graph data in your app](https://docs.microsoft.com/en-us/graph/paging) + +Take a moment to understand what the code does: + +* log that a request was received +* define the scope (if not stated, it’s Microsoft Graph) +* obtain the token from the environment variables IDENTITY_ENDPOINT and IDENTITY_HEADER (more about that in the next step!) +* pass that token in the header of the REST call towards the group endpoint of Microsoft Graph +* get the status code (hopefully 200) 🀞 + +## 2. Create Azure resources + +Now we want to create all resources that we need in Azure: + +For testing purposes, I pseudo-randomized a number to not always need to come up with new names: + +``` +#Get a random number between 100 and 300 to more easily be able to distinguish between several trials +$rand = Get-Random -Minimum 100 -Maximum 300 +``` +We will now set some variables, this reduces risk of typos and makes our code better readable – also we can reuse it better – this is a courtesy to future-self +``` +#Set values +$resourceGroup = "DemoPlay$rand" +$location = "westeurope" +$storage = "luisedemostorage$rand" +$functionapp = "LuiseDemo-functionapp$rand" + +``` +Let’s create a resource-group that will later hold our Azure Functions App +``` +#create group +az group create -n $resourceGroup -l $location +``` + +As our Functions App will need a storage account, we will create this as well: + +``` +#create storage account +az storage account create ` + -n $storage ` + -l $location ` + -g $resourceGroup ` + --sku Standard_LRS +``` +Now create the Azure Functions App which later holds our function (remember we created that earlier locally, but will later deploy it to Azure) + +``` +#create function +az functionapp create ` + -n $functionapp ` + --storage-account $storage ` + --consumption-plan-location $location ` + --runtime powershell ` + -g $resourceGroup ` + --functions-version 3 +``` + +> πŸ”Ž **Observation** - < It will take a few moments for everything to be set, once this step is completed, you will be prompted with a message, that you also can benefit from Application Insights. > + +## 3. Create Managed Identity and assign permissions + +We want things to be super secure – this is why we want to enable a system assigned Managed Identity for our new function: + +### Steps + +``` +az functionapp identity assign -n $functionapp -g $resourceGroup +``` +Our Managed Identity shall have the right permission scope to access Graph API for Group.Read.All, and to eventually be able to make the required REST call, we will need + +- the Graph API service Provider +- permission scope, expressed as App role +Let’s do this: + +``` +#Get Graph Api service provider (that's later needed for --api) +az ad sp list --query "[?appDisplayName=='Microsoft Graph'].{Name:appDisplayName, Id:appId}" --output table --all +#Save that service provider +$graphId = az ad sp list --query "[?appDisplayName=='Microsoft Graph'].appId | [0]" --all +# Get permission scope for "Group.Read.All" +$appRoleId = az ad sp show --id $graphId --query "appRoles[?value=='Group.Read.All'].id | [0]" +``` +Time to make the REST call to assign the permissions as shown above to the Managed Identity: +``` +#Set values +$webAppName="LuiseDemo-functionapp$rand" +$principalId=$(az resource list -n $webAppName --query [*].identity.principalId --out tsv) +$graphResourceId=$(az ad sp list --display-name "Microsoft Graph" --query [0].objectId --out tsv) +$appRoleId=$(az ad sp list --display-name "Microsoft Graph" --query "[0].appRoles[?value=='Group.Read.All' && contains(allowedMemberTypes, 'Application')].id" --out tsv) +$body="{'principalId':'$principalId','resourceId':'$graphResourceId','appRoleId':'$appRoleId'}" + +#the actual REST call +az rest --method post --uri https://graph.microsoft.com/v1.0/servicePrincipals/$principalId/appRoleAssignments --body $body --headers Content-Type=application/json +``` + +> πŸ“ **Tip** - < you may control if everything worked as intended in Azure portal: Azure Active Directory --> Enterprise applications --> Managed Identity + +> πŸ”Ž **Observation** - < OBSERVATION > + +> ❔ **Question** - < how would you several permissions in one go? > + +To see things work, we will need to deploy our function into our Functions App. + +1. head over to Visual Studio Code again +2. select **deploy to Functions App** +3. Select the Functions App yuou already created +4. Confirm the Pop up window by selecting **Deploy** + +> πŸ”Ž **Observation** - < this might take a minute > + +// check with Marc if I need to explain how to test in Azure portal + +## 4. Obtain an access token + +In this step we want to learn how we could ontain an access token which we needed for a successful HTTP request against Microsoft Graph API: + +### Steps + +1. Although we would usually load an authentication library such as Azure.Identity and then to obtain a token, there is an easier, but not documented way get the token in an Azure Functions: Following and extrapolating [Obtain tokens for Azure resources](https://docs.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=powershell#obtain-tokens-for-azure-resources) to Microsoft Graph surprisingly works: + +``` +$resourceURI = "https://" +$tokenAuthURI = $env:IDENTITY_ENDPOINT + "?resource=$resourceURI&api-version=2019-08-01" +$tokenResponse = Invoke-RestMethod -Method Get -Headers @{"X-IDENTITY-HEADER"="$env:IDENTITY_HEADER"} -Uri $tokenAuthURI +$accessToken = $tokenResponse.access_token +``` + +2. have a look at your **IDENTITY_ENDPOINT** and **IDENTITY_HEADER** environment variables at `https://.scm.azurewebsites.net/ENV.cshtml#envVariables` + +## 5. Homework + + + +## 6. More info + + +--- +[πŸ”Ό Lessons Index](../../README.md) From d7a2aafd811d5d637756d7fd7baafbb654f7f4b1 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 12 Aug 2021 16:02:04 +0200 Subject: [PATCH 02/29] Update managed-identity-powershell.md --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 0adb11ec..682bf16c 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -209,7 +209,7 @@ To see things work, we will need to deploy our function into our Functions App. > πŸ”Ž **Observation** - < this might take a minute > -// check with Marc if I need to explain how to test in Azure portal + ## 4. Obtain an access token From 6497edfef86f1fe9568d086d8db575fa529b21f5 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Mon, 16 Aug 2021 12:12:15 +0200 Subject: [PATCH 03/29] Create _lesson_template.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit added the template again πŸ™ˆ --- lessons/_lesson_template.md | 83 +++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 lessons/_lesson_template.md diff --git a/lessons/_lesson_template.md b/lessons/_lesson_template.md new file mode 100644 index 00000000..5ecae86a --- /dev/null +++ b/lessons/_lesson_template.md @@ -0,0 +1,83 @@ +# Lesson Title ({language}) + +Watch the recording of this lesson [on YouTube](). + +## Goal 🎯 + +The goal of this lesson is to ... + +This lessons consists of the following exercises: + +|Nr|Exercise +|-|- +|0|[Prerequisites](#0-prerequisites) +|1|Exercise title 1 +|2|Exercise title 2 +|3|Exercise title 3 +|4|[Homework](#4-homework) +|5|[More info](#5-more-info) + +> πŸ“ **Tip** - If you're stuck at any point you can have a look at the [source code](../../src/{language}/{topic}) in this repository. + +--- + +## 0. Prerequisites + +| Prerequisite | Exercise +| - | - + +See [{language} prerequisites](../prerequisites/prerequisites-{language}.md) for more details. + +## 1. Exercise title 1 + +//TODO Describe sub goal + +### Steps + +1. +2. +3. + +> πŸ“ **Tip** - < TIP > + +> πŸ”Ž **Observation** - < OBSERVATION > + +> ❔ **Question** - < QUESTION > + +## 2. Exercise title 2 + +//TODO Describe sub goal +### Steps + +1. +2. +3. + +> πŸ“ **Tip** - < TIP > + +> πŸ”Ž **Observation** - < OBSERVATION > + +> ❔ **Question** - < QUESTION > + +## 3. Exercise title 3 + +//TODO Describe sub goal + +### Steps + +1. +2. +3. + +> πŸ“ **Tip** - < TIP > + +> πŸ”Ž **Observation** - < OBSERVATION > + +> ❔ **Question** - < QUESTION > + +## 4. Homework + +## 5. More info + +--- +[πŸ”Ό Lessons Index](../../README.md) From 25561f8f15e90d54d68e3df48308725172a844de Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Mon, 16 Aug 2021 12:53:32 +0200 Subject: [PATCH 04/29] Update managed-identity-powershell.md added link on Managed Identities from Docs, added a sentence on why we prefer mI over App registrations and handling secrets, skipped steps 1 and 2 as they are part of prerequisites --- lessons/managed-identity-powershell.md | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 682bf16c..4b9b988b 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -4,7 +4,7 @@ Watch the recording of this lesson [on YouTube](). ## Goal 🎯 -The goal of this lesson is to understand how you can create and use a system assigned managed to call an Azure function in order to obtain a Microsoft Graph access token with the right permission scope. Microsoft Graph is THE API for all things Microsoft 365. +The goal of this lesson is to understand how you can create and use a system assigned managed to call an Azure function in order to obtain a Microsoft Graph access token with the right permission scope. We prefer Managed Identities over an App registration with an app secret, because its more secure. Secrets can potentially be leaked and expire and therefore they are an additional workload to handle. When we use a Managed Identity, we won't need an app registration in Azure Active Directory and won't even have access to any secret. Learn more here: [What are managed identities for Azure resources?](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) Microsoft Graph is THE API for all things Microsoft 365. This lessons consists of the following exercises: @@ -39,17 +39,14 @@ before we will deploy our app to Azure, we will develop it locally in Visual Stu ### Steps -1. Install the Core Tools package with `npm install -g azure-functions-core-tools@3 --unsafe-perm true` -2. Install the [Azure Functions extension for VS Code](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions) -3. Select **New Project** -4. Select a folder for your project -5. Select a language – I will use PowerShell -6. Select **HTTP trigger** as a template -7. Type in a better name like `GetGraphToken` -8. Select Authorization level **Function** -9. Select how you want to open your project – I prefer **Add to workspace** -10. Open `run.ps1` -11. Replace the default code by this: +1. Select **New Project** +2. Select a folder for your project +3. Select a language – I will use PowerShell +4. Select **HTTP trigger** as a template +5. Type in a better name like `GetGraphToken` +6. Select Authorization level **Function**79. Select how you want to open your project – I prefer **Add to workspace** +7. Open `run.ps1` +8. Replace the default code by this: ``` using namespace System.Net @@ -233,8 +230,7 @@ $accessToken = $tokenResponse.access_token ## 6. More info - +[What are managed identities for Azure resources?](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) --- [πŸ”Ό Lessons Index](../../README.md) From 1455f92a2f21880328734e5e03b0a5349d46d2d9 Mon Sep 17 00:00:00 2001 From: Luise Freese <49960482+LuiseFreese@users.noreply.github.com> Date: Mon, 16 Aug 2021 13:23:46 +0200 Subject: [PATCH 05/29] fixed formatting issues --- lessons/managed-identity-powershell.md | 77 ++++++++++++++++---------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 4b9b988b..6f7812a4 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -4,7 +4,7 @@ Watch the recording of this lesson [on YouTube](). ## Goal 🎯 -The goal of this lesson is to understand how you can create and use a system assigned managed to call an Azure function in order to obtain a Microsoft Graph access token with the right permission scope. We prefer Managed Identities over an App registration with an app secret, because its more secure. Secrets can potentially be leaked and expire and therefore they are an additional workload to handle. When we use a Managed Identity, we won't need an app registration in Azure Active Directory and won't even have access to any secret. Learn more here: [What are managed identities for Azure resources?](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) Microsoft Graph is THE API for all things Microsoft 365. +The goal of this lesson is to understand how you can create and use a system assigned managed to call an Azure function in order to obtain a Microsoft Graph access token with the right permission scope. We prefer Managed Identities over an App registration with an app secret, because its more secure. Secrets can potentially be leaked and expire and therefore they are an additional workload to handle. When we use a Managed Identity, we won't need an app registration in Azure Active Directory and won't even have access to any secret. Learn more here: [What are managed identities for Azure resources?](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview) Microsoft Graph is THE API for all things Microsoft 365. This lessons consists of the following exercises: @@ -31,7 +31,7 @@ See [{language} prerequisites](../prerequisites/prerequisites-{language}.md) for ## 1. Create an Azure Functions -before we will deploy our app to Azure, we will develop it locally in Visual Studio Code. This comes with some great advantages such as +before we will deploy our app to Azure, we will develop it locally in Visual Studio Code. This comes with some great advantages such as * we don’t need to adjust to ever changing UI in Azure portal * we can benefit from source control @@ -39,16 +39,16 @@ before we will deploy our app to Azure, we will develop it locally in Visual Stu ### Steps -1. Select **New Project** +1. Select _New Project_ 2. Select a folder for your project 3. Select a language – I will use PowerShell -4. Select **HTTP trigger** as a template +4. Select _HTTP trigger_ as a template 5. Type in a better name like `GetGraphToken` -6. Select Authorization level **Function**79. Select how you want to open your project – I prefer **Add to workspace** +6. Select Authorization level _Function_. Select how you want to open your project – I prefer _Add to workspace_ 7. Open `run.ps1` -8. Replace the default code by this: +8. Replace the default code by this: -``` +``` PowerShell using namespace System.Net # Input bindings are passed in via param block @@ -95,9 +95,10 @@ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ Body = $body }) ``` -> πŸ“ **Tip** - Watch out – the Graph API will this way return up to 100 groups – Please adjust with query parameters as needed like `https://graph.microsoft.com/v1.0/groups?$top=42` or use pagination, which is described here: [Paging Microsoft Graph data in your app](https://docs.microsoft.com/en-us/graph/paging) -Take a moment to understand what the code does: +> πŸ“ **Tip** - Watch out – the Graph API will this way return up to 100 groups – Please adjust with query parameters as needed like `https://graph.microsoft.com/v1.0/groups?$top=42` or use pagination, which is described here: [Paging Microsoft Graph data in your app](https://docs.microsoft.com/graph/paging) + +Take a moment to understand what the code does: * log that a request was received * define the scope (if not stated, it’s Microsoft Graph) @@ -107,16 +108,21 @@ Take a moment to understand what the code does: ## 2. Create Azure resources -Now we want to create all resources that we need in Azure: +Now we want to create all resources that we need in Azure: For testing purposes, I pseudo-randomized a number to not always need to come up with new names: -``` +```azurecli + + #Get a random number between 100 and 300 to more easily be able to distinguish between several trials $rand = Get-Random -Minimum 100 -Maximum 300 ``` + We will now set some variables, this reduces risk of typos and makes our code better readable – also we can reuse it better – this is a courtesy to future-self -``` + +```azurecli + #Set values $resourceGroup = "DemoPlay$rand" $location = "westeurope" @@ -124,15 +130,19 @@ $storage = "luisedemostorage$rand" $functionapp = "LuiseDemo-functionapp$rand" ``` + Let’s create a resource-group that will later hold our Azure Functions App -``` + +```azurecli + #create group az group create -n $resourceGroup -l $location ``` As our Functions App will need a storage account, we will create this as well: -``` +```azurecli + #create storage account az storage account create ` -n $storage ` @@ -140,9 +150,11 @@ az storage account create ` -g $resourceGroup ` --sku Standard_LRS ``` + Now create the Azure Functions App which later holds our function (remember we created that earlier locally, but will later deploy it to Azure) -``` +```azurecli + #create function az functionapp create ` -n $functionapp ` @@ -161,16 +173,19 @@ We want things to be super secure – this is why we want to enable a system ass ### Steps -``` +```azurecli + az functionapp identity assign -n $functionapp -g $resourceGroup ``` + Our Managed Identity shall have the right permission scope to access Graph API for Group.Read.All, and to eventually be able to make the required REST call, we will need -- the Graph API service Provider -- permission scope, expressed as App role +* the Graph API service Provider +* permission scope, expressed as App role Let’s do this: -``` +```azurecli + #Get Graph Api service provider (that's later needed for --api) az ad sp list --query "[?appDisplayName=='Microsoft Graph'].{Name:appDisplayName, Id:appId}" --output table --all #Save that service provider @@ -178,8 +193,11 @@ $graphId = az ad sp list --query "[?appDisplayName=='Microsoft Graph'].appId | [ # Get permission scope for "Group.Read.All" $appRoleId = az ad sp show --id $graphId --query "appRoles[?value=='Group.Read.All'].id | [0]" ``` + Time to make the REST call to assign the permissions as shown above to the Managed Identity: -``` + +```azurecli + #Set values $webAppName="LuiseDemo-functionapp$rand" $principalId=$(az resource list -n $webAppName --query [*].identity.principalId --out tsv) @@ -197,12 +215,12 @@ az rest --method post --uri https://graph.microsoft.com/v1.0/servicePrincipals/$ > ❔ **Question** - < how would you several permissions in one go? > -To see things work, we will need to deploy our function into our Functions App. +To see things work, we will need to deploy our function into our Functions App. 1. head over to Visual Studio Code again -2. select **deploy to Functions App** -3. Select the Functions App yuou already created -4. Confirm the Pop up window by selecting **Deploy** +2. select _deploy to Functions App_ +3. Select the Functions App you already created +4. Confirm the Pop up window by selecting _Deploy_ > πŸ”Ž **Observation** - < this might take a minute > @@ -210,20 +228,20 @@ To see things work, we will need to deploy our function into our Functions App. ## 4. Obtain an access token -In this step we want to learn how we could ontain an access token which we needed for a successful HTTP request against Microsoft Graph API: +In this step we want to learn how we could obtain an access token which we needed for a successful HTTP request against Microsoft Graph API: ### Steps -1. Although we would usually load an authentication library such as Azure.Identity and then to obtain a token, there is an easier, but not documented way get the token in an Azure Functions: Following and extrapolating [Obtain tokens for Azure resources](https://docs.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=powershell#obtain-tokens-for-azure-resources) to Microsoft Graph surprisingly works: +1. Although we would usually load an authentication library such as Azure.Identity and then to obtain a token, there is an easier, but not documented way get the token in an Azure Functions: Following and extrapolating [Obtain tokens for Azure resources](https://docs.microsoft.com/azure/app-service/overview-managed-identity?tabs=powershell#obtain-tokens-for-azure-resources) to Microsoft Graph surprisingly works: -``` +```azurecli $resourceURI = "https://" $tokenAuthURI = $env:IDENTITY_ENDPOINT + "?resource=$resourceURI&api-version=2019-08-01" $tokenResponse = Invoke-RestMethod -Method Get -Headers @{"X-IDENTITY-HEADER"="$env:IDENTITY_HEADER"} -Uri $tokenAuthURI $accessToken = $tokenResponse.access_token ``` -2. have a look at your **IDENTITY_ENDPOINT** and **IDENTITY_HEADER** environment variables at `https://.scm.azurewebsites.net/ENV.cshtml#envVariables` +2. have a look at your _IDENTITY_ENDPOINT_ and _IDENTITY_HEADER_ environment variables at `https://.scm.azurewebsites.net/ENV.cshtml#envVariables` ## 5. Homework @@ -231,6 +249,7 @@ $accessToken = $tokenResponse.access_token ## 6. More info -[What are managed identities for Azure resources?](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) +[What are managed identities for Azure resources?](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview) + --- [πŸ”Ό Lessons Index](../../README.md) From 66c0b5471e1b2cec789ab66425f1aaa340bf7691 Mon Sep 17 00:00:00 2001 From: Luise Freese <49960482+LuiseFreese@users.noreply.github.com> Date: Mon, 16 Aug 2021 13:35:52 +0200 Subject: [PATCH 06/29] added goal of step 1 and dropped benefits of developing in VSCode --- lessons/managed-identity-powershell.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 6f7812a4..b021846a 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -27,15 +27,11 @@ This lessons consists of the following exercises: | Prerequisite | Exercise | - | - -See [{language} prerequisites](../prerequisites/prerequisites-{language}.md) for more details. +See [{PowerShell} prerequisites](../prerequisites/prerequisites-{powershell}.md) for more details. -## 1. Create an Azure Functions +## 1. Create an Azure Functions App -before we will deploy our app to Azure, we will develop it locally in Visual Studio Code. This comes with some great advantages such as - -* we don’t need to adjust to ever changing UI in Azure portal -* we can benefit from source control -* we can collaborate with others +before we will deploy our app to Azure, we will develop it locally in Visual Studio Code. The goal of this exercise is to understand how to make an HTTP request to Microsoft Graph API, as we want to return all groups of the tenant. ### Steps From babf377b29747f0d8242f5f0aa56d570f31fbf92 Mon Sep 17 00:00:00 2001 From: Luise Freese <49960482+LuiseFreese@users.noreply.github.com> Date: Mon, 16 Aug 2021 13:51:16 +0200 Subject: [PATCH 07/29] solved formatting issues as requested --- lessons/managed-identity-powershell.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index b021846a..060c380f 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -44,7 +44,8 @@ before we will deploy our app to Azure, we will develop it locally in Visual Stu 7. Open `run.ps1` 8. Replace the default code by this: -``` PowerShell +```powershell + using namespace System.Net # Input bindings are passed in via param block @@ -108,8 +109,7 @@ Now we want to create all resources that we need in Azure: For testing purposes, I pseudo-randomized a number to not always need to come up with new names: -```azurecli - +```powershell #Get a random number between 100 and 300 to more easily be able to distinguish between several trials $rand = Get-Random -Minimum 100 -Maximum 300 @@ -117,7 +117,7 @@ $rand = Get-Random -Minimum 100 -Maximum 300 We will now set some variables, this reduces risk of typos and makes our code better readable – also we can reuse it better – this is a courtesy to future-self -```azurecli +```powershell #Set values $resourceGroup = "DemoPlay$rand" @@ -129,7 +129,7 @@ $functionapp = "LuiseDemo-functionapp$rand" Let’s create a resource-group that will later hold our Azure Functions App -```azurecli +```powershell #create group az group create -n $resourceGroup -l $location @@ -137,7 +137,7 @@ az group create -n $resourceGroup -l $location As our Functions App will need a storage account, we will create this as well: -```azurecli +```powershell #create storage account az storage account create ` @@ -149,7 +149,7 @@ az storage account create ` Now create the Azure Functions App which later holds our function (remember we created that earlier locally, but will later deploy it to Azure) -```azurecli +```powershell #create function az functionapp create ` @@ -169,7 +169,7 @@ We want things to be super secure – this is why we want to enable a system ass ### Steps -```azurecli +```powershell az functionapp identity assign -n $functionapp -g $resourceGroup ``` @@ -180,7 +180,7 @@ Our Managed Identity shall have the right permission scope to access Graph API f * permission scope, expressed as App role Let’s do this: -```azurecli +```powershell #Get Graph Api service provider (that's later needed for --api) az ad sp list --query "[?appDisplayName=='Microsoft Graph'].{Name:appDisplayName, Id:appId}" --output table --all @@ -192,7 +192,7 @@ $appRoleId = az ad sp show --id $graphId --query "appRoles[?value=='Group.Read.A Time to make the REST call to assign the permissions as shown above to the Managed Identity: -```azurecli +```powershell #Set values $webAppName="LuiseDemo-functionapp$rand" @@ -230,7 +230,7 @@ In this step we want to learn how we could obtain an access token which we neede 1. Although we would usually load an authentication library such as Azure.Identity and then to obtain a token, there is an easier, but not documented way get the token in an Azure Functions: Following and extrapolating [Obtain tokens for Azure resources](https://docs.microsoft.com/azure/app-service/overview-managed-identity?tabs=powershell#obtain-tokens-for-azure-resources) to Microsoft Graph surprisingly works: -```azurecli +```powershell $resourceURI = "https://" $tokenAuthURI = $env:IDENTITY_ENDPOINT + "?resource=$resourceURI&api-version=2019-08-01" $tokenResponse = Invoke-RestMethod -Method Get -Headers @{"X-IDENTITY-HEADER"="$env:IDENTITY_HEADER"} -Uri $tokenAuthURI From 19c7855e928bd21cccc3a1d92c574ba2b9370200 Mon Sep 17 00:00:00 2001 From: Luise Freese <49960482+LuiseFreese@users.noreply.github.com> Date: Mon, 16 Aug 2021 13:58:28 +0200 Subject: [PATCH 08/29] referred to deployment lesson for the create Azure resources section --- lessons/managed-identity-powershell.md | 58 +++----------------------- 1 file changed, 5 insertions(+), 53 deletions(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 060c380f..a06281b4 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -107,61 +107,13 @@ Take a moment to understand what the code does: Now we want to create all resources that we need in Azure: -For testing purposes, I pseudo-randomized a number to not always need to come up with new names: +Create a -```powershell - -#Get a random number between 100 and 300 to more easily be able to distinguish between several trials -$rand = Get-Random -Minimum 100 -Maximum 300 -``` - -We will now set some variables, this reduces risk of typos and makes our code better readable – also we can reuse it better – this is a courtesy to future-self - -```powershell - -#Set values -$resourceGroup = "DemoPlay$rand" -$location = "westeurope" -$storage = "luisedemostorage$rand" -$functionapp = "LuiseDemo-functionapp$rand" - -``` - -Let’s create a resource-group that will later hold our Azure Functions App - -```powershell - -#create group -az group create -n $resourceGroup -l $location -``` - -As our Functions App will need a storage account, we will create this as well: - -```powershell - -#create storage account -az storage account create ` - -n $storage ` - -l $location ` - -g $resourceGroup ` - --sku Standard_LRS -``` - -Now create the Azure Functions App which later holds our function (remember we created that earlier locally, but will later deploy it to Azure) - -```powershell - -#create function -az functionapp create ` - -n $functionapp ` - --storage-account $storage ` - --consumption-plan-location $location ` - --runtime powershell ` - -g $resourceGroup ` - --functions-version 3 -``` +* resource group `$resourcegroup` +* storage account +* function App `$functionapp` (PowerShell) -> πŸ”Ž **Observation** - < It will take a few moments for everything to be set, once this step is completed, you will be prompted with a message, that you also can benefit from Application Insights. > +If you are unfamiliar with this process, please find more info in the [Deployment lesson](https://github.com/marcduiker/azure-functions-university/blob/main/lessons/deployment/deployment-lesson.md) ## 3. Create Managed Identity and assign permissions From d26ead51ae1e0ab0506bf4a4e85acd6c866b5d72 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Mon, 16 Aug 2021 15:11:39 +0200 Subject: [PATCH 09/29] Update code-tour-and-links-watcher.yml added as requested `https://graph.microsoft.com.*` to be excluded from checks --- .github/workflows/code-tour-and-links-watcher.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code-tour-and-links-watcher.yml b/.github/workflows/code-tour-and-links-watcher.yml index 8fd5e70e..c768d0a6 100644 --- a/.github/workflows/code-tour-and-links-watcher.yml +++ b/.github/workflows/code-tour-and-links-watcher.yml @@ -26,9 +26,9 @@ jobs: id: lychee uses: lycheeverse/lychee-action@v1.0.8 with: - args: --verbose --no-progress --exclude-mail --exclude-loopback --exclude "https?://localhost.*" "https://sandbox.api.sap.com.*" "https://azure-university-app-config.*" "https://192.168.7.108.*" -- "**/*.md" + args: --verbose --no-progress --exclude-mail --exclude-loopback --exclude "https?://localhost.*" "https://sandbox.api.sap.com.*" "https://azure-university-app-config.*" "https://192.168.7.108.*" https://graph.microsoft.com.* -- "**/*.md" env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - name: Fail if there were link errors - run: exit ${{ steps.lychee.outputs.exit_code }} \ No newline at end of file + run: exit ${{ steps.lychee.outputs.exit_code }} From 7a326d0c1319936689dba60a0ddb131ea733d871 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Mon, 16 Aug 2021 15:30:00 +0200 Subject: [PATCH 10/29] Update code-tour-and-links-watcher.yml added `"` round the URL so that YAML likes it. --- .github/workflows/code-tour-and-links-watcher.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-tour-and-links-watcher.yml b/.github/workflows/code-tour-and-links-watcher.yml index c768d0a6..b63a5b1f 100644 --- a/.github/workflows/code-tour-and-links-watcher.yml +++ b/.github/workflows/code-tour-and-links-watcher.yml @@ -26,7 +26,7 @@ jobs: id: lychee uses: lycheeverse/lychee-action@v1.0.8 with: - args: --verbose --no-progress --exclude-mail --exclude-loopback --exclude "https?://localhost.*" "https://sandbox.api.sap.com.*" "https://azure-university-app-config.*" "https://192.168.7.108.*" https://graph.microsoft.com.* -- "**/*.md" + args: --verbose --no-progress --exclude-mail --exclude-loopback --exclude "https?://localhost.*" "https://sandbox.api.sap.com.*" "https://azure-university-app-config.*" "https://192.168.7.108.*" "https://graph.microsoft.com.*" -- "**/*.md" env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} From dca9a2012038889e3b0a0746dbb4a70ea106064d Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:41:16 +0200 Subject: [PATCH 11/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index a06281b4..40672bd1 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -4,7 +4,7 @@ Watch the recording of this lesson [on YouTube](). ## Goal 🎯 -The goal of this lesson is to understand how you can create and use a system assigned managed to call an Azure function in order to obtain a Microsoft Graph access token with the right permission scope. We prefer Managed Identities over an App registration with an app secret, because its more secure. Secrets can potentially be leaked and expire and therefore they are an additional workload to handle. When we use a Managed Identity, we won't need an app registration in Azure Active Directory and won't even have access to any secret. Learn more here: [What are managed identities for Azure resources?](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview) Microsoft Graph is THE API for all things Microsoft 365. +The goal of this lesson is to understand how you can create and use a system-assigned managed identity to call an Azure Function in order to obtain a Microsoft Graph access token with the right permission scope. We prefer Managed Identities over an App registration with an app secret because it's more secure. Secrets can potentially be leaked or expire, and therefore they are an additional workload to handle. When we use a managed identity, we don't need an app registration in Azure Active Directory, and we don't need access to any secret. Learn more here: [What are managed identities for Azure resources?](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview) Microsoft Graph is THE API for all things Microsoft 365. This lessons consists of the following exercises: From 7cb8b16544c8437614735211f6e14266345d5d90 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:41:44 +0200 Subject: [PATCH 12/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 40672bd1..b9bf77a5 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -11,7 +11,7 @@ This lessons consists of the following exercises: |Nr|Exercise |-|- |0|[Prerequisites](#0-prerequisites) -|1|[Create an Azure Functions](#1-create-an-azure-functions) +|1|[Create an Azure Functions](#1-create-an-azure-functions-app) |2|[Create Azure resources](#2-create-azure-resources) |3|[Create Managed Identity and assign permissions](#3-create-managed-identity-and-assign-permissions) |4|[Obtain an access token](#4-obtain-an-access-token) From 48e11c8230fd4bb50e53e3059b55835a0ab63af6 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:41:50 +0200 Subject: [PATCH 13/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index b9bf77a5..e120a108 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -115,7 +115,7 @@ Create a If you are unfamiliar with this process, please find more info in the [Deployment lesson](https://github.com/marcduiker/azure-functions-university/blob/main/lessons/deployment/deployment-lesson.md) -## 3. Create Managed Identity and assign permissions +## 3. Create managed identity and assign permissions We want things to be super secure – this is why we want to enable a system assigned Managed Identity for our new function: From 3b3effd9fa386db3731cc57b98864a7d63f3d0b9 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:41:57 +0200 Subject: [PATCH 14/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index e120a108..d7b42227 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -117,7 +117,7 @@ If you are unfamiliar with this process, please find more info in the [Deploymen ## 3. Create managed identity and assign permissions -We want things to be super secure – this is why we want to enable a system assigned Managed Identity for our new function: +We want things to be super secure – this is why we want to enable a system assigned managed identity for our new function: ### Steps From bf5290e0bcbb34a09b154512ac4bfaa6d04330f5 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:42:08 +0200 Subject: [PATCH 15/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 1 - 1 file changed, 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index d7b42227..a4ae7b77 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -145,7 +145,6 @@ $appRoleId = az ad sp show --id $graphId --query "appRoles[?value=='Group.Read.A Time to make the REST call to assign the permissions as shown above to the Managed Identity: ```powershell - #Set values $webAppName="LuiseDemo-functionapp$rand" $principalId=$(az resource list -n $webAppName --query [*].identity.principalId --out tsv) From 65b04b154b85893a0e04b48a227ad8c4e563eaef Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:42:23 +0200 Subject: [PATCH 16/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 1 - 1 file changed, 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index a4ae7b77..26805758 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -133,7 +133,6 @@ Our Managed Identity shall have the right permission scope to access Graph API f Let’s do this: ```powershell - #Get Graph Api service provider (that's later needed for --api) az ad sp list --query "[?appDisplayName=='Microsoft Graph'].{Name:appDisplayName, Id:appId}" --output table --all #Save that service provider From 32bf11338e76b4488455e97e00b5a602b98a73fd Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:45:04 +0200 Subject: [PATCH 17/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 26805758..3f9e1ed8 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -135,7 +135,7 @@ Let’s do this: ```powershell #Get Graph Api service provider (that's later needed for --api) az ad sp list --query "[?appDisplayName=='Microsoft Graph'].{Name:appDisplayName, Id:appId}" --output table --all -#Save that service provider +#Save that service provider in a variable $graphId = az ad sp list --query "[?appDisplayName=='Microsoft Graph'].appId | [0]" --all # Get permission scope for "Group.Read.All" $appRoleId = az ad sp show --id $graphId --query "appRoles[?value=='Group.Read.All'].id | [0]" From 912e85afc0cb881ce3293affee39d64926aa279f Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:45:11 +0200 Subject: [PATCH 18/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 3f9e1ed8..11302df7 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -155,7 +155,7 @@ $body="{'principalId':'$principalId','resourceId':'$graphResourceId','appRoleId' az rest --method post --uri https://graph.microsoft.com/v1.0/servicePrincipals/$principalId/appRoleAssignments --body $body --headers Content-Type=application/json ``` -> πŸ“ **Tip** - < you may control if everything worked as intended in Azure portal: Azure Active Directory --> Enterprise applications --> Managed Identity +> πŸ“ **Tip** - You can verify if everything worked as intended in Azure portal: Azure Active Directory --> Enterprise applications --> Managed Identity > πŸ”Ž **Observation** - < OBSERVATION > From 3d5c977682c398af9a3aaca10c8491b585eab370 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:45:38 +0200 Subject: [PATCH 19/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 1 - 1 file changed, 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 11302df7..e7348ea9 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -45,7 +45,6 @@ before we will deploy our app to Azure, we will develop it locally in Visual Stu 8. Replace the default code by this: ```powershell - using namespace System.Net # Input bindings are passed in via param block From 577cb0425c5b674af5e7a7a3451c8ea8650d2185 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:45:56 +0200 Subject: [PATCH 20/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index e7348ea9..8b67a59e 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -106,7 +106,7 @@ Take a moment to understand what the code does: Now we want to create all resources that we need in Azure: -Create a +Use the Azure CLI or VSCode to create: * resource group `$resourcegroup` * storage account From db2fbdabab4971f270ff3cb397ddc333b523bab8 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:46:30 +0200 Subject: [PATCH 21/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 8b67a59e..63e6ae96 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -108,7 +108,7 @@ Now we want to create all resources that we need in Azure: Use the Azure CLI or VSCode to create: -* resource group `$resourcegroup` +* A resource group * storage account * function App `$functionapp` (PowerShell) From 3c1c78f84f4e5d4504fd38ea9498c4e2b47673bc Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:46:42 +0200 Subject: [PATCH 22/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 63e6ae96..67ae506a 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -109,7 +109,7 @@ Now we want to create all resources that we need in Azure: Use the Azure CLI or VSCode to create: * A resource group -* storage account +* A storage account * function App `$functionapp` (PowerShell) If you are unfamiliar with this process, please find more info in the [Deployment lesson](https://github.com/marcduiker/azure-functions-university/blob/main/lessons/deployment/deployment-lesson.md) From dc439462aa941549eab16d82f448e5c0c216d426 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:46:57 +0200 Subject: [PATCH 23/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 67ae506a..a94550d6 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -122,7 +122,7 @@ We want things to be super secure – this is why we want to enable a system ass ```powershell -az functionapp identity assign -n $functionapp -g $resourceGroup +az functionapp identity assign -n $functionApp -g $resourceGroup ``` Our Managed Identity shall have the right permission scope to access Graph API for Group.Read.All, and to eventually be able to make the required REST call, we will need From 291720756741b7a241db9dc1fd69d9344364dee3 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:47:07 +0200 Subject: [PATCH 24/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index a94550d6..495f1cbe 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -150,7 +150,7 @@ $graphResourceId=$(az ad sp list --display-name "Microsoft Graph" --query [0].ob $appRoleId=$(az ad sp list --display-name "Microsoft Graph" --query "[0].appRoles[?value=='Group.Read.All' && contains(allowedMemberTypes, 'Application')].id" --out tsv) $body="{'principalId':'$principalId','resourceId':'$graphResourceId','appRoleId':'$appRoleId'}" -#the actual REST call +#The actual REST call to assign the app role to the service principal az rest --method post --uri https://graph.microsoft.com/v1.0/servicePrincipals/$principalId/appRoleAssignments --body $body --headers Content-Type=application/json ``` From 69c2950c5522c4efdbe81534ea69a9d465efcb57 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:47:42 +0200 Subject: [PATCH 25/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 495f1cbe..3d2847e1 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -110,7 +110,9 @@ Use the Azure CLI or VSCode to create: * A resource group * A storage account -* function App `$functionapp` (PowerShell) +* A PowerShell Function App + +We'll need the names of the resource group and Function App in the next step, so you might want to use variables for those (e.g. `$resourcegroup` and `$functionApp`) in case you use the Azure CLI. If you are unfamiliar with this process, please find more info in the [Deployment lesson](https://github.com/marcduiker/azure-functions-university/blob/main/lessons/deployment/deployment-lesson.md) From a927a3ebacb328919ab58b9b0ce1e27e306917f0 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:47:58 +0200 Subject: [PATCH 26/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 3d2847e1..dc2f4a45 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -127,7 +127,7 @@ We want things to be super secure – this is why we want to enable a system ass az functionapp identity assign -n $functionApp -g $resourceGroup ``` -Our Managed Identity shall have the right permission scope to access Graph API for Group.Read.All, and to eventually be able to make the required REST call, we will need +Our managed identity needs the correct permission scope to access Graph API for Group.Read.All, and to eventually be able to make the required REST call, we will need * the Graph API service Provider * permission scope, expressed as App role From 2cc0157aecd5b6da95a63ad9b4d21fbc8f9bfbd3 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:48:08 +0200 Subject: [PATCH 27/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 1 - 1 file changed, 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index dc2f4a45..eea5fc0e 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -123,7 +123,6 @@ We want things to be super secure – this is why we want to enable a system ass ### Steps ```powershell - az functionapp identity assign -n $functionApp -g $resourceGroup ``` From fc93be289f6383ab3a7536783195ddea08dd4fa9 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 09:48:20 +0200 Subject: [PATCH 28/29] Update lessons/managed-identity-powershell.md Co-authored-by: Marc Duiker --- lessons/managed-identity-powershell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index eea5fc0e..5babe4fc 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -141,7 +141,7 @@ $graphId = az ad sp list --query "[?appDisplayName=='Microsoft Graph'].appId | [ $appRoleId = az ad sp show --id $graphId --query "appRoles[?value=='Group.Read.All'].id | [0]" ``` -Time to make the REST call to assign the permissions as shown above to the Managed Identity: +Time to make the REST call to assign the permissions as shown above to the managed identity: ```powershell #Set values From aac4683c40c6a92b4df15f6c3d648fefc48dabe8 Mon Sep 17 00:00:00 2001 From: Luise Freese Date: Thu, 19 Aug 2021 10:47:26 +0200 Subject: [PATCH 29/29] Update managed-identity-powershell.md adds some "use the PowerShell terminal" to clarify :-) --- lessons/managed-identity-powershell.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lessons/managed-identity-powershell.md b/lessons/managed-identity-powershell.md index 5babe4fc..8796ad55 100644 --- a/lessons/managed-identity-powershell.md +++ b/lessons/managed-identity-powershell.md @@ -11,7 +11,7 @@ This lessons consists of the following exercises: |Nr|Exercise |-|- |0|[Prerequisites](#0-prerequisites) -|1|[Create an Azure Functions](#1-create-an-azure-functions-app) +|1|[Create an Azure Functions App](#1-create-an-azure-functions-app) |2|[Create Azure resources](#2-create-azure-resources) |3|[Create Managed Identity and assign permissions](#3-create-managed-identity-and-assign-permissions) |4|[Obtain an access token](#4-obtain-an-access-token) @@ -122,6 +122,8 @@ We want things to be super secure – this is why we want to enable a system ass ### Steps +Use the PowerShell terminal and type + ```powershell az functionapp identity assign -n $functionApp -g $resourceGroup ``` @@ -130,7 +132,8 @@ Our managed identity needs the correct permission scope to access Graph API for * the Graph API service Provider * permission scope, expressed as App role -Let’s do this: + +Let’s do this - use the PowerShell terminal and type: ```powershell #Get Graph Api service provider (that's later needed for --api) @@ -143,6 +146,8 @@ $appRoleId = az ad sp show --id $graphId --query "appRoles[?value=='Group.Read.A Time to make the REST call to assign the permissions as shown above to the managed identity: +Use the PowerShell terminal and type + ```powershell #Set values $webAppName="LuiseDemo-functionapp$rand" @@ -180,7 +185,9 @@ In this step we want to learn how we could obtain an access token which we neede 1. Although we would usually load an authentication library such as Azure.Identity and then to obtain a token, there is an easier, but not documented way get the token in an Azure Functions: Following and extrapolating [Obtain tokens for Azure resources](https://docs.microsoft.com/azure/app-service/overview-managed-identity?tabs=powershell#obtain-tokens-for-azure-resources) to Microsoft Graph surprisingly works: -```powershell +Review the code in `Run.ps1`: + +``` $resourceURI = "https://" $tokenAuthURI = $env:IDENTITY_ENDPOINT + "?resource=$resourceURI&api-version=2019-08-01" $tokenResponse = Invoke-RestMethod -Method Get -Headers @{"X-IDENTITY-HEADER"="$env:IDENTITY_HEADER"} -Uri $tokenAuthURI