diff --git a/azure-functions/README.md b/azure-functions/README.md new file mode 100644 index 00000000..629377f2 --- /dev/null +++ b/azure-functions/README.md @@ -0,0 +1,57 @@ +--- +page_type: sample +languages: +- azurecli +products: +- azure +- azure-cli +- azure-functions +name: Azure Functions sample scripts +url-fragment: +description: These scripts demonstrate how to create and manage Azure Functions resources using the Azure CLI. +--- +# Azure Functions + +## Azure CLI sample scripts + +These end-to-end Azure CLI scripts help you learn how to provision and manage the Azure resources required by Azure Functions. You must use the [Azure Functions Core Tools][func-core-tools] to create actual Azure Functions code projects from the command line on your local computer and deploy code to these Azure resources. + +For a complete end-to-end example of developing and deploying from the command line using both Core Tools and the Azure CLI, see one of these language-specific [command line quickstarts][func-quickstart]. + +The scripts in this directory demonstrate working with [Azure Functions][func-home] using the [Azure CLI reference commands][azure-cli]. + +| Script | Description | +| ------ | ----------- | +|**Create a function app**|| +|[create-function-app-flex-consumption.sh][af-1]| Creates a function app in a [Flex Consumption plan][plan-flex] with a user-assigned managed identity. **This is the recommended serverless hosting plan.** | +|[create-function-app-consumption.sh][af-2]| Creates a function app in a [Consumption plan][plan-consumption]. | +|[create-function-app-premium-plan.sh][af-3]| Creates a function app in a [Premium (Elastic Premium) plan][plan-premium]. | +|[create-function-app-app-service-plan.sh][af-4]| Creates a function app in a dedicated [App Service plan][plan-dedicated]. | +|**Connect to services**|| +|[create-function-app-connect-to-storage-account.sh][af-5]| Creates a function app in a [Flex Consumption plan][plan-flex] and connects it to a storage account using managed identity. | +|[create-function-app-connect-to-cosmos-db.sh][af-6]| Creates a function app in a [Flex Consumption plan][plan-flex] and connects it to Azure Cosmos DB using managed identity and RBAC. | +|[connect-azure-openai-resources.sh][af-7]| Creates a function app in a [Flex Consumption plan][plan-flex] and connects it to Azure OpenAI using managed identity. | +|[functions-cli-mount-files-storage-linux.sh][af-8]| Creates a Linux function app and mounts an Azure Files share, which lets you leverage existing data or machine learning models in your functions. | +|**Deploy code**|| +|[deploy-function-app-with-function-github-continuous.sh][af-9]| Creates a function app in a [Consumption plan][plan-consumption] and deploys code from a public GitHub repository. | + + +[af-1]: ./create-function-app-flex-consumption/create-function-app-flex-consumption.sh +[af-2]: ./create-function-app-consumption/create-function-app-consumption.sh +[af-3]: ./create-function-app-premium-plan/create-function-app-premium-plan.sh +[af-4]: ./create-function-app-app-service-plan/create-function-app-app-service-plan.sh +[af-5]: ./create-function-app-connect-to-storage/create-function-app-connect-to-storage-account.sh +[af-6]: ./create-function-app-connect-to-cosmos-db/create-function-app-connect-to-cosmos-db.sh +[af-7]: ./connect-azure-openai-resources/connect-azure-openai-resources.sh +[af-8]: ./functions-cli-mount-files-storage-linux/functions-cli-mount-files-storage-linux.sh +[af-9]: ./deploy-function-app-with-function-github-continuous/deploy-function-app-with-function-github-continuous.sh + + +[func-home]: https://learn.microsoft.com/azure/azure-functions/ +[func-core-tools]: https://learn.microsoft.com/azure/azure-functions/functions-run-local +[func-quickstart]: https://learn.microsoft.com/azure/azure-functions/how-to-create-function-azure-cli +[azure-cli]: https://learn.microsoft.com/cli/azure/reference-index +[plan-flex]: https://learn.microsoft.com/azure/azure-functions/flex-consumption-plan +[plan-consumption]: https://learn.microsoft.com/azure/azure-functions/consumption-plan +[plan-premium]: https://learn.microsoft.com/azure/azure-functions/functions-premium-plan +[plan-dedicated]: https://learn.microsoft.com/azure/azure-functions/dedicated-plan diff --git a/azure-functions/connect-azure-openai-resources/connect-azure-openai-resources.sh b/azure-functions/connect-azure-openai-resources/connect-azure-openai-resources.sh new file mode 100644 index 00000000..07391865 --- /dev/null +++ b/azure-functions/connect-azure-openai-resources/connect-azure-openai-resources.sh @@ -0,0 +1,105 @@ +#!/bin/bash +# Passed validation in Cloud Shell on 2/28/2026 + +# Function app, storage account, and user identity names must be unique. + +# Variable block +let "randomIdentifier=$RANDOM*$RANDOM" +location="swedencentral" +resourceGroup="msdocs-azure-functions-rg-$randomIdentifier" +tag="connect-azure-openai-resources" +storage="msdocsaccount$randomIdentifier" +userIdentity="msdocs-managed-identity-$randomIdentifier" +functionApp="msdocs-serverless-function-$randomIdentifier" +openaiName="msdocs-openai-$randomIdentifier" +modelName="gpt-4o" +skuStorage="Standard_LRS" +functionsVersion="4" +languageWorker="python" +languageVersion="3.11" + +# Install the Application Insights extension +az extension add --name application-insights + +# Create a resource group +echo "Creating $resourceGroup in "$location"..." +az group create --name $resourceGroup --location "$location" --tags $tag + +# Create an Azure storage account in the resource group with key access disabled. +echo "Creating $storage" +az storage account create --name $storage --location "$location" --resource-group $resourceGroup \ + --sku $skuStorage --allow-blob-public-access false --allow-shared-key-access false + +# Create a user-assigned managed identity +echo "Creating $userIdentity" +output=$(az identity create --name $userIdentity --resource-group $resourceGroup --location $location \ + --query "{userId:id, principalId: principalId, clientId: clientId}" -o json) + +# Use jq to parse the output and assign the properties to variables +userId=$(echo $output | jq -r '.userId') +principalId=$(echo $output | jq -r '.principalId') +clientId=$(echo $output | jq -r '.clientId') + +# Get the storage ID and create a role assignment (Storage Blob Data Owner) for the user +storageId=$(az storage account show --resource-group $resourceGroup --name $storage --query 'id' -o tsv) +az role assignment create --assignee-object-id $principalId --assignee-principal-type ServicePrincipal \ + --role "Storage Blob Data Owner" --scope $storageId + +# Create the function app in a Flex Consumption plan that uses the user-assigned managed identity +# to access the deployment share. +az functionapp create --resource-group $resourceGroup --name $functionApp --flexconsumption-location $location \ + --runtime $languageWorker --runtime-version $languageVersion --storage-account $storage \ + --deployment-storage-auth-type UserAssignedIdentity --deployment-storage-auth-value $userIdentity + +# Create a role assigment (Monitoring Metrics Publisher) in Application Insights for the user identity +appInsights=$(az monitor app-insights component show --resource-group $resourceGroup \ + --app $functionApp --query "id" --output tsv) +az role assignment create --role "Monitoring Metrics Publisher" --assignee $principalId --scope $appInsights + +# Update app settings to use managed identities for all connections +clientId=$(az identity show --name $userIdentity --resource-group $resourceGroup \ + --query 'clientId' -o tsv) +az functionapp config appsettings set --name $functionApp --resource-group $resourceGroup \ + --settings AzureWebJobsStorage__accountName=$storage AzureWebJobsStorage__credential=managedidentity \ + AzureWebJobsStorage__clientId=$clientId \ + APPLICATIONINSIGHTS_AUTHENTICATION_STRING="ClientId=$clientId;Authorization=AAD" +az functionapp config appsettings delete --name $functionApp \ + --resource-group $resourceGroup --setting-names AzureWebJobsStorage + +# Create an Azure OpenAI resource +echo "Creating Azure OpenAI resource" +openaiId=$(az cognitiveservices account create --name $openaiName \ + --resource-group $resourceGroup --kind OpenAI --sku S0 --location $location --yes \ + --query 'id' -o tsv) + +# Create role assignments ("Cognitive Services OpenAI User" & "Azure AI User") for the identity +echo "Adding UAMI to the 'Cognitive Services OpenAI User' role." +principalId=$(az identity show --name $userIdentity --resource-group $resourceGroup \ + --query 'principalId' -o tsv) +az role assignment create --assignee $principalId \ + --role "Cognitive Services OpenAI User" --scope $openaiId +az role assignment create --assignee $principalId \ + --role "Azure AI User" --scope $openaiId + +# Create the same role assignments for your Azure account so you can connect during local development. +echo "Adding current Azure account to the 'Cognitive Services OpenAI User' role." +accountId=$(az ad signed-in-user show --query id -o tsv) +az role assignment create --assignee $accountId \ + --role "Cognitive Services OpenAI User" --scope $openaiId +az role assignment create --assignee $accountId \ + --role "Azure AI User" --scope $openaiId + +# Get the user-assigned managed identity details +user=$(az identity show --name $userIdentity --resource-group $resourceGroup \ + --query "{userId:id, clientId: clientId}" -o json) + +# Add the required app settings to the function app +az functionapp config appsettings set --name $functionApp --resource-group $resourceGroup \ + --settings AzureOpenAI__Endpoint="https://$openaiName.openai.azure.com/" \ + AzureOpenAI__credential=managedidentity \ + AzureOpenAI__managedIdentityResourceId=$(echo $user | jq -r '.userId') \ + AzureOpenAI__clientId=$(echo $user | jq -r '.clientId') \ + CHAT_MODEL_DEPLOYMENT_NAME=$modelName + +# echo "Deleting all resources" +# az group delete --name $resourceGroup -y diff --git a/azure-functions/create-function-app-app-service-plan/create-function-app-app-service-plan.sh b/azure-functions/create-function-app-app-service-plan/create-function-app-app-service-plan.sh index 505a63d5..e5665aa5 100644 --- a/azure-functions/create-function-app-app-service-plan/create-function-app-app-service-plan.sh +++ b/azure-functions/create-function-app-app-service-plan/create-function-app-app-service-plan.sh @@ -1,20 +1,22 @@ #!/bin/bash -# Passed validation in Cloud Shell on 3/24/2022 +# Passed validation in Cloud Shell on 2/28/2026 -# +# For the recommended serverless plan, see create-function-app-flex-consumption. # Function app and storage account names must be unique. # Variable block let "randomIdentifier=$RANDOM*$RANDOM" location="eastus" resourceGroup="msdocs-azure-functions-rg-$randomIdentifier" -tag="create-function-app-consumption" +tag="create-function-app-app-service-plan" storage="msdocsaccount$randomIdentifier" appServicePlan="msdocs-app-service-plan-$randomIdentifier" functionApp="msdocs-serverless-function-$randomIdentifier" skuStorage="Standard_LRS" skuPlan="B1" functionsVersion="4" +runtime="dotnet-isolated" +runtimeVersion="8.0" # Create a resource group echo "Creating $resourceGroup in "$location"..." @@ -26,12 +28,15 @@ az storage account create --name $storage --location "$location" --resource-grou # Create an App Service plan echo "Creating $appServicePlan" -az functionapp plan create --name $appServicePlan --resource-group $resourceGroup --location "$location" --sku $skuPlan +az functionapp plan create --name $appServicePlan --resource-group $resourceGroup \ + --location "$location" --sku $skuPlan # Create a Function App echo "Creating $functionApp" -az functionapp create --name $functionApp --storage-account $storage --plan $appServicePlan --resource-group $resourceGroup --functions-version $functionsVersion -# +az functionapp create --name $functionApp --storage-account $storage \ + --plan $appServicePlan --resource-group $resourceGroup \ + --runtime $runtime --runtime-version $runtimeVersion \ + --functions-version $functionsVersion # echo "Deleting all resources" # az group delete --name $resourceGroup -y diff --git a/azure-functions/create-function-app-connect-to-cosmos-db/create-function-app-connect-to-cosmos-db.sh b/azure-functions/create-function-app-connect-to-cosmos-db/create-function-app-connect-to-cosmos-db.sh index a070de0b..e36d42ed 100644 --- a/azure-functions/create-function-app-connect-to-cosmos-db/create-function-app-connect-to-cosmos-db.sh +++ b/azure-functions/create-function-app-connect-to-cosmos-db/create-function-app-connect-to-cosmos-db.sh @@ -1,9 +1,8 @@ #!/bin/bash -# Passed validation in Cloud Shell on 3/24/2022 +# Passed validation in Cloud Shell on 2/28/2026 -# -# Function app and storage account names must be unique. +# Function app, storage account, Cosmos DB, and user identity names must be unique. # Variable block let "randomIdentifier=$RANDOM*$RANDOM" @@ -11,36 +10,89 @@ location="eastus" resourceGroup="msdocs-azure-functions-rg-$randomIdentifier" tag="create-function-app-connect-to-cosmos-db" storage="msdocsaccount$randomIdentifier" +userIdentity="msdocs-managed-identity-$randomIdentifier" functionApp="msdocs-serverless-function-$randomIdentifier" +cosmosDbAccount="msdocs-cosmosdb-$randomIdentifier" +cosmosDbDatabase="documents-db" +cosmosDbContainer="documents" skuStorage="Standard_LRS" functionsVersion="4" +languageWorker="python" +languageVersion="3.11" + +# Install the Application Insights extension +az extension add --name application-insights # Create a resource group echo "Creating $resourceGroup in "$location"..." az group create --name $resourceGroup --location "$location" --tags $tag -# Create a storage account for the function app. +# Create an Azure storage account in the resource group with key access disabled. echo "Creating $storage" -az storage account create --name $storage --location "$location" --resource-group $resourceGroup --sku $skuStorage +az storage account create --name $storage --location "$location" --resource-group $resourceGroup \ + --sku $skuStorage --allow-blob-public-access false --allow-shared-key-access false -# Create a serverless function app in the resource group. -echo "Creating $functionApp" -az functionapp create --name $functionApp --resource-group $resourceGroup --storage-account $storage --consumption-plan-location "$location" --functions-version $functionsVersion +# Create a user-assigned managed identity +echo "Creating $userIdentity" +output=$(az identity create --name $userIdentity --resource-group $resourceGroup --location $location \ + --query "{userId:id, principalId: principalId, clientId: clientId}" -o json) + +# Use jq to parse the output and assign the properties to variables +userId=$(echo $output | jq -r '.userId') +principalId=$(echo $output | jq -r '.principalId') +clientId=$(echo $output | jq -r '.clientId') + +# Get the storage ID and create a role assignment (Storage Blob Data Owner) for the identity +storageId=$(az storage account show --resource-group $resourceGroup --name $storage --query 'id' -o tsv) +az role assignment create --assignee-object-id $principalId --assignee-principal-type ServicePrincipal \ + --role "Storage Blob Data Owner" --scope $storageId -# Create an Azure Cosmos DB database account using the same function app name. +# Create the function app in a Flex Consumption plan echo "Creating $functionApp" -az cosmosdb create --name $functionApp --resource-group $resourceGroup +az functionapp create --resource-group $resourceGroup --name $functionApp --flexconsumption-location $location \ + --runtime $languageWorker --runtime-version $languageVersion --storage-account $storage \ + --deployment-storage-auth-type UserAssignedIdentity --deployment-storage-auth-value $userIdentity + +# Create a role assignment (Monitoring Metrics Publisher) in Application Insights for the user identity +appInsights=$(az monitor app-insights component show --resource-group $resourceGroup \ + --app $functionApp --query "id" --output tsv) +az role assignment create --role "Monitoring Metrics Publisher" --assignee $principalId --scope $appInsights + +# Update app settings to use managed identities for host storage connections +clientId=$(az identity show --name $userIdentity --resource-group $resourceGroup \ + --query 'clientId' -o tsv) +az functionapp config appsettings set --name $functionApp --resource-group $resourceGroup \ + --settings AzureWebJobsStorage__accountName=$storage AzureWebJobsStorage__credential=managedidentity \ + AzureWebJobsStorage__clientId=$clientId \ + APPLICATIONINSIGHTS_AUTHENTICATION_STRING="ClientId=$clientId;Authorization=AAD" +az functionapp config appsettings delete --name $functionApp \ + --resource-group $resourceGroup --setting-names AzureWebJobsStorage + +# Create an Azure Cosmos DB account +echo "Creating $cosmosDbAccount" +az cosmosdb create --name $cosmosDbAccount --resource-group $resourceGroup \ + --locations regionName=$location failoverPriority=0 isZoneRedundant=False -# Get the Azure Cosmos DB connection string. -endpoint=$(az cosmosdb show --name $functionApp --resource-group $resourceGroup --query documentEndpoint --output tsv) -echo $endpoint +# Create a database and containers for the Cosmos DB account +az cosmosdb sql database create --account-name $cosmosDbAccount --resource-group $resourceGroup \ + --name $cosmosDbDatabase +az cosmosdb sql container create --account-name $cosmosDbAccount --resource-group $resourceGroup \ + --database-name $cosmosDbDatabase --name $cosmosDbContainer --partition-key-path "/id" +az cosmosdb sql container create --account-name $cosmosDbAccount --resource-group $resourceGroup \ + --database-name $cosmosDbDatabase --name leases --partition-key-path "/id" -key=$(az cosmosdb keys list --name $functionApp --resource-group $resourceGroup --query primaryMasterKey --output tsv) -echo $key +# Assign the Cosmos DB Built-in Data Contributor role to the managed identity +cosmosDbId=$(az cosmosdb show --name $cosmosDbAccount --resource-group $resourceGroup --query 'id' -o tsv) +az cosmosdb sql role assignment create --account-name $cosmosDbAccount --resource-group $resourceGroup \ + --role-definition-name "Cosmos DB Built-in Data Contributor" --scope "/" \ + --principal-id $principalId -# Configure function app settings to use the Azure Cosmos DB connection string. -az functionapp config appsettings set --name $functionApp --resource-group $resourceGroup --setting CosmosDB_Endpoint=$endpoint CosmosDB_Key=$key -# +# Get the Cosmos DB endpoint and configure the function app to connect using managed identity +endpoint=$(az cosmosdb show --name $cosmosDbAccount --resource-group $resourceGroup --query documentEndpoint --output tsv) +az functionapp config appsettings set --name $functionApp --resource-group $resourceGroup \ + --settings COSMOS_CONNECTION__accountEndpoint=$endpoint COSMOS_CONNECTION__credential=managedidentity \ + COSMOS_CONNECTION__clientId=$clientId \ + COSMOS_DATABASE_NAME=$cosmosDbDatabase COSMOS_CONTAINER_NAME=$cosmosDbContainer # echo "Deleting all resources" # az group delete --name $resourceGroup -y diff --git a/azure-functions/create-function-app-connect-to-storage/create-function-app-connect-to-storage-account.sh b/azure-functions/create-function-app-connect-to-storage/create-function-app-connect-to-storage-account.sh index 3180df13..36d05762 100644 --- a/azure-functions/create-function-app-connect-to-storage/create-function-app-connect-to-storage-account.sh +++ b/azure-functions/create-function-app-connect-to-storage/create-function-app-connect-to-storage-account.sh @@ -1,8 +1,7 @@ #!/bin/bash -# Passed validation in Cloud Shell on 3/24/2022 +# Passed validation in Cloud Shell on 2/28/2026 -# -# Function app and storage account names must be unique. +# Function app, storage account, and user identity names must be unique. # Variable block let "randomIdentifier=$RANDOM*$RANDOM" @@ -10,28 +9,75 @@ location="eastus" resourceGroup="msdocs-azure-functions-rg-$randomIdentifier" tag="create-function-app-connect-to-storage-account" storage="msdocsaccount$randomIdentifier" +connStorage="msdocsconnaccount$randomIdentifier" +userIdentity="msdocs-managed-identity-$randomIdentifier" functionApp="msdocs-serverless-function-$randomIdentifier" skuStorage="Standard_LRS" functionsVersion="4" +languageWorker="dotnet-isolated" +languageVersion="8.0" + +# Install the Application Insights extension +az extension add --name application-insights # Create a resource group echo "Creating $resourceGroup in "$location"..." az group create --name $resourceGroup --location "$location" --tags $tag -# Create an Azure storage account in the resource group. +# Create an Azure storage account in the resource group with key access disabled. echo "Creating $storage" -az storage account create --name $storage --location "$location" --resource-group $resourceGroup --sku $skuStorage +az storage account create --name $storage --location "$location" --resource-group $resourceGroup \ + --sku $skuStorage --allow-blob-public-access false --allow-shared-key-access false + +# Create a user-assigned managed identity +echo "Creating $userIdentity" +output=$(az identity create --name $userIdentity --resource-group $resourceGroup --location $location \ + --query "{userId:id, principalId: principalId, clientId: clientId}" -o json) + +# Use jq to parse the output and assign the properties to variables +userId=$(echo $output | jq -r '.userId') +principalId=$(echo $output | jq -r '.principalId') +clientId=$(echo $output | jq -r '.clientId') + +# Get the storage ID and create a role assignment (Storage Blob Data Owner) for the identity +storageId=$(az storage account show --resource-group $resourceGroup --name $storage --query 'id' -o tsv) +az role assignment create --assignee-object-id $principalId --assignee-principal-type ServicePrincipal \ + --role "Storage Blob Data Owner" --scope $storageId -# Create a serverless function app in the resource group. +# Create the function app in a Flex Consumption plan echo "Creating $functionApp" -az functionapp create --name $functionApp --resource-group $resourceGroup --storage-account $storage --consumption-plan-location "$location" --functions-version $functionsVersion +az functionapp create --resource-group $resourceGroup --name $functionApp --flexconsumption-location $location \ + --runtime $languageWorker --runtime-version $languageVersion --storage-account $storage \ + --deployment-storage-auth-type UserAssignedIdentity --deployment-storage-auth-value $userIdentity + +# Create a role assignment (Monitoring Metrics Publisher) in Application Insights for the user identity +appInsights=$(az monitor app-insights component show --resource-group $resourceGroup \ + --app $functionApp --query "id" --output tsv) +az role assignment create --role "Monitoring Metrics Publisher" --assignee $principalId --scope $appInsights + +# Update app settings to use managed identities for host storage connections +clientId=$(az identity show --name $userIdentity --resource-group $resourceGroup \ + --query 'clientId' -o tsv) +az functionapp config appsettings set --name $functionApp --resource-group $resourceGroup \ + --settings AzureWebJobsStorage__accountName=$storage AzureWebJobsStorage__credential=managedidentity \ + AzureWebJobsStorage__clientId=$clientId \ + APPLICATIONINSIGHTS_AUTHENTICATION_STRING="ClientId=$clientId;Authorization=AAD" +az functionapp config appsettings delete --name $functionApp \ + --resource-group $resourceGroup --setting-names AzureWebJobsStorage + +# Create a second storage account for the function app to connect to. +echo "Creating $connStorage" +az storage account create --name $connStorage --location "$location" --resource-group $resourceGroup --sku $skuStorage -# Get the storage account connection string. -connstr=$(az storage account show-connection-string --name $storage --resource-group $resourceGroup --query connectionString --output tsv) +# Assign Storage Blob Data Owner on the second storage account to the managed identity +connStorageId=$(az storage account show --resource-group $resourceGroup --name $connStorage --query 'id' -o tsv) +az role assignment create --assignee-object-id $principalId --assignee-principal-type ServicePrincipal \ + --role "Storage Blob Data Owner" --scope $connStorageId -# Update function app settings to connect to the storage account. -az functionapp config appsettings set --name $functionApp --resource-group $resourceGroup --settings StorageConStr=$connstr -# +# Configure the function app to connect to the second storage account using managed identity +az functionapp config appsettings set --name $functionApp --resource-group $resourceGroup \ + --settings StorageConnection__serviceUri="https://$connStorage.blob.core.windows.net" \ + StorageConnection__credential=managedidentity StorageConnection__clientId=$clientId # echo "Deleting all resources" # az group delete --name $resourceGroup -y diff --git a/azure-functions/create-function-app-consumption-python/create-function-app-consumption-python.sh b/azure-functions/create-function-app-consumption-python/create-function-app-consumption-python.sh deleted file mode 100644 index e3615976..00000000 --- a/azure-functions/create-function-app-consumption-python/create-function-app-consumption-python.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -# Passed validation in Cloud Shell on 3/24/2022 - -# -# Function app and storage account names must be unique. - -# Variable block -let "randomIdentifier=$RANDOM*$RANDOM" -location="eastus" -resourceGroup="msdocs-azure-functions-rg-$randomIdentifier" -tag="create-function-app-consumption-python" -storage="msdocsaccount$randomIdentifier" -functionApp="msdocs-serverless-python-function-$randomIdentifier" -skuStorage="Standard_LRS" -functionsVersion="4" -pythonVersion="3.9" #Allowed values: 3.7, 3.8, and 3.9 - -# Create a resource group -echo "Creating $resourceGroup in "$location"..." -az group create --name $resourceGroup --location "$location" --tags $tag - -# Create an Azure storage account in the resource group. -echo "Creating $storage" -az storage account create --name $storage --location "$location" --resource-group $resourceGroup --sku $skuStorage - -# Create a serverless python function app in the resource group. -echo "Creating $functionApp" -az functionapp create --name $functionApp --storage-account $storage --consumption-plan-location "$location" --resource-group $resourceGroup --os-type Linux --runtime python --runtime-version $pythonVersion --functions-version $functionsVersion -# - -# echo "Deleting all resources" -# az group delete --name $resourceGroup -y diff --git a/azure-functions/create-function-app-consumption/create-function-app-consumption.sh b/azure-functions/create-function-app-consumption/create-function-app-consumption.sh index 414d4f15..ba45e6b2 100644 --- a/azure-functions/create-function-app-consumption/create-function-app-consumption.sh +++ b/azure-functions/create-function-app-consumption/create-function-app-consumption.sh @@ -1,7 +1,7 @@ #!/bin/bash -# Passed validation in Cloud Shell on 3/24/2022 +# Passed validation in Cloud Shell on 2/28/2026 -# +# For the recommended serverless plan, see create-function-app-flex-consumption. # Function app and storage account names must be unique. # Variable block @@ -13,6 +13,8 @@ storage="msdocsaccount$randomIdentifier" functionApp="msdocs-serverless-function-$randomIdentifier" skuStorage="Standard_LRS" functionsVersion="4" +runtime="dotnet-isolated" +runtimeVersion="8.0" # Create a resource group echo "Creating $resourceGroup in "$location"..." @@ -24,8 +26,10 @@ az storage account create --name $storage --location "$location" --resource-grou # Create a serverless function app in the resource group. echo "Creating $functionApp" -az functionapp create --name $functionApp --storage-account $storage --consumption-plan-location "$location" --resource-group $resourceGroup --functions-version $functionsVersion -# +az functionapp create --name $functionApp --storage-account $storage \ + --consumption-plan-location "$location" --resource-group $resourceGroup \ + --runtime $runtime --runtime-version $runtimeVersion \ + --functions-version $functionsVersion # echo "Deleting all resources" # az group delete --name $resourceGroup -y diff --git a/azure-functions/create-function-app-flex-consumption/create-function-app-flex-consumption.sh b/azure-functions/create-function-app-flex-consumption/create-function-app-flex-consumption.sh new file mode 100644 index 00000000..091daf3d --- /dev/null +++ b/azure-functions/create-function-app-flex-consumption/create-function-app-flex-consumption.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# Passed validation in Cloud Shell on 2/28/2026 + +# Flex Consumption is the recommended plan for most serverless workloads. +# Function app, storage account, and user identity names must be unique. + +# Variable block +let "randomIdentifier=$RANDOM*$RANDOM" +location="northeurope" +resourceGroup="msdocs-azure-functions-rg-$randomIdentifier" +tag="create-function-app-flex-consumption" +storage="msdocsaccount$randomIdentifier" +userIdentity="msdocs-managed-identity-$randomIdentifier" +functionApp="msdocs-serverless-function-$randomIdentifier" +skuStorage="Standard_LRS" +functionsVersion="4" +languageWorker="python" +languageVersion="3.11" + +# Install the Application Insights extension +az extension add --name application-insights + +# Create a resource group +echo "Creating $resourceGroup in "$location"..." +az group create --name $resourceGroup --location "$location" --tags $tag + +# Create an Azure storage account in the resource group with key access disabled. +echo "Creating $storage" +az storage account create --name $storage --location "$location" --resource-group $resourceGroup \ + --sku $skuStorage --allow-blob-public-access false --allow-shared-key-access false + +# Create a user-assigned managed identity +echo "Creating $userIdentity" +output=$(az identity create --name $userIdentity --resource-group $resourceGroup --location $location \ + --query "{userId:id, principalId: principalId, clientId: clientId}" -o json) + +# Use jq to parse the output and assign the properties to variables +userId=$(echo $output | jq -r '.userId') +principalId=$(echo $output | jq -r '.principalId') +clientId=$(echo $output | jq -r '.clientId') + +# Get the storage ID and create a role assignment (Storage Blob Data Owner) for the user +storageId=$(az storage account show --resource-group $resourceGroup --name $storage --query 'id' -o tsv) +az role assignment create --assignee-object-id $principalId --assignee-principal-type ServicePrincipal \ + --role "Storage Blob Data Owner" --scope $storageId + +# Create the function app in a Flex Consumption plan that uses the user-assigned managed identity +# to access the deployment share. +az functionapp create --resource-group $resourceGroup --name $functionApp --flexconsumption-location $location \ + --runtime $languageWorker --runtime-version $languageVersion --storage-account $storage \ + --deployment-storage-auth-type UserAssignedIdentity --deployment-storage-auth-value $userIdentity + +# Create a role assigment (Monitoring Metrics Publisher) in Application Insights for the user identity +appInsights=$(az monitor app-insights component show --resource-group $resourceGroup \ + --app $functionApp --query "id" --output tsv) +az role assignment create --role "Monitoring Metrics Publisher" --assignee $principalId --scope $appInsights + +# Update app settings to use managed identities for all connections +clientId=$(az identity show --name $userIdentity --resource-group $resourceGroup \ + --query 'clientId' -o tsv) +az functionapp config appsettings set --name $functionApp --resource-group $resourceGroup \ + --settings AzureWebJobsStorage__accountName=$storage AzureWebJobsStorage__credential=managedidentity \ + AzureWebJobsStorage__clientId=$clientId \ + APPLICATIONINSIGHTS_AUTHENTICATION_STRING="ClientId=$clientId;Authorization=AAD" +az functionapp config appsettings delete --name $functionApp \ + --resource-group $resourceGroup --setting-names AzureWebJobsStorage + +# echo "Deleting all resources" +# az group delete --name $resourceGroup -y diff --git a/azure-functions/create-function-app-premium-plan/create-function-app-premium-plan.sh b/azure-functions/create-function-app-premium-plan/create-function-app-premium-plan.sh index cb62bbe6..2b841180 100644 --- a/azure-functions/create-function-app-premium-plan/create-function-app-premium-plan.sh +++ b/azure-functions/create-function-app-premium-plan/create-function-app-premium-plan.sh @@ -1,7 +1,7 @@ #!/bin/bash -# Passed validation in Cloud Shell on 3/24/2022 +# Passed validation in Cloud Shell on 2/28/2026 -# +# For the recommended serverless plan, see create-function-app-flex-consumption. # Function app and storage account names must be unique. # Variable block @@ -12,9 +12,11 @@ tag="create-function-app-premium-plan" storage="msdocsaccount$randomIdentifier" premiumPlan="msdocs-premium-plan-$randomIdentifier" functionApp="msdocs-function-$randomIdentifier" -skuStorage="Standard_LRS" # Allowed values: Standard_LRS, Standard_GRS, Standard_RAGRS, Standard_ZRS, Premium_LRS, Premium_ZRS, Standard_GZRS, Standard_RAGZRS +skuStorage="Standard_LRS" skuPlan="EP1" functionsVersion="4" +runtime="node" +runtimeVersion="20" # Create a resource group echo "Creating $resourceGroup in "$location"..." @@ -30,8 +32,10 @@ az functionapp plan create --name $premiumPlan --resource-group $resourceGroup - # Create a Function App echo "Creating $functionApp" -az functionapp create --name $functionApp --storage-account $storage --plan $premiumPlan --resource-group $resourceGroup --functions-version $functionsVersion -# +az functionapp create --name $functionApp --storage-account $storage \ + --plan $premiumPlan --resource-group $resourceGroup --os-type Linux \ + --runtime $runtime --runtime-version $runtimeVersion \ + --functions-version $functionsVersion # echo "Deleting all resources" # az group delete --name $resourceGroup -y diff --git a/azure-functions/deploy-function-app-with-function-github-continuous/deploy-function-app-with-function-github-continuous.sh b/azure-functions/deploy-function-app-with-function-github-continuous/deploy-function-app-with-function-github-continuous.sh index f5c08e08..2a79bf6f 100644 --- a/azure-functions/deploy-function-app-with-function-github-continuous/deploy-function-app-with-function-github-continuous.sh +++ b/azure-functions/deploy-function-app-with-function-github-continuous/deploy-function-app-with-function-github-continuous.sh @@ -1,40 +1,35 @@ #!/bin/bash -# Passed validation in Cloud Shell on 3/24/2022 - -# +# Passed validation in Cloud Shell on 2/28/2026 # Function app and storage account names must be unique. let "randomIdentifier=$RANDOM*$RANDOM" -location=eastus +location="eastus" resourceGroup="msdocs-azure-functions-rg-$randomIdentifier" tag="deploy-function-app-with-function-github" -storage="msdocs$randomIdentifier" +storage="msdocsaccount$randomIdentifier" +functionApp="msdocs-serverless-function-$randomIdentifier" skuStorage="Standard_LRS" -functionApp=mygithubfunc$randomIdentifier functionsVersion="4" runtime="node" +runtimeVersion="20" # Public GitHub repository containing an Azure Functions code project. gitrepo=https://github.com/Azure-Samples/functions-quickstart-javascript -## Enable authenticated git deployment in your subscription when using a private repo. -#token= -#az functionapp deployment source update-token \ -# --git-token $token -# Create a resource group. -echo "Creating $resourceGroup in ""$location""..." +# Create a resource group +echo "Creating $resourceGroup in "$location"..." az group create --name $resourceGroup --location "$location" --tags $tag # Create an Azure storage account in the resource group. echo "Creating $storage" az storage account create --name $storage --location "$location" --resource-group $resourceGroup --sku $skuStorage -# Create a function app with source files deployed from the specified GitHub repo. +# Create a serverless function app in the resource group. echo "Creating $functionApp" -az functionapp create --name $functionApp --storage-account $storage --consumption-plan-location "$location" --resource-group $resourceGroup --deployment-source-url $gitrepo --deployment-source-branch main --functions-version $functionsVersion --runtime $runtime - -# Connect to function application -curl -s "https://${functionApp}.azurewebsites.net/api/httpexample?name=Azure" -# +az functionapp create --name $functionApp --storage-account $storage \ + --consumption-plan-location "$location" --resource-group $resourceGroup \ + --runtime $runtime --runtime-version $runtimeVersion \ + --functions-version $functionsVersion \ + --deployment-source-url $gitrepo --deployment-source-branch main # echo "Deleting all resources" # az group delete --name $resourceGroup -y diff --git a/azure-functions/functions-cli-mount-files-storage-linux/functions-cli-mount-files-storage-linux.sh b/azure-functions/functions-cli-mount-files-storage-linux/functions-cli-mount-files-storage-linux.sh index 5c9384d7..520115ec 100644 --- a/azure-functions/functions-cli-mount-files-storage-linux/functions-cli-mount-files-storage-linux.sh +++ b/azure-functions/functions-cli-mount-files-storage-linux/functions-cli-mount-files-storage-linux.sh @@ -1,7 +1,6 @@ #!/bin/bash -# Passed validation in Cloud Shell on 3/24/2022 +# Passed validation in Cloud Shell on 2/28/2026 -# # Function app and storage account names must be unique. # Variable block @@ -13,7 +12,7 @@ export AZURE_STORAGE_ACCOUNT="msdocsstorage$randomIdentifier" functionApp="msdocs-serverless-function-$randomIdentifier" skuStorage="Standard_LRS" functionsVersion="4" -pythonVersion="3.9" #Allowed values: 3.7, 3.8, and 3.9 +pythonVersion="3.11" share="msdocs-fileshare-$randomIdentifier" directory="msdocs-directory-$randomIdentifier" shareId="msdocs-share-$randomIdentifier" @@ -25,14 +24,18 @@ az group create --name $resourceGroup --location "$location" --tags $tag # Create an Azure storage account in the resource group. echo "Creating $AZURE_STORAGE_ACCOUNT" -az storage account create --name $AZURE_STORAGE_ACCOUNT --location "$location" --resource-group $resourceGroup --sku $skuStorage +az storage account create --name $AZURE_STORAGE_ACCOUNT --location "$location" \ + --resource-group $resourceGroup --sku $skuStorage # Set the storage account key as an environment variable. export AZURE_STORAGE_KEY=$(az storage account keys list -g $resourceGroup -n $AZURE_STORAGE_ACCOUNT --query '[0].value' -o tsv) # Create a serverless function app in the resource group. echo "Creating $functionApp" -az functionapp create --name $functionApp --storage-account $AZURE_STORAGE_ACCOUNT --consumption-plan-location "$location" --resource-group $resourceGroup --os-type Linux --runtime python --runtime-version $pythonVersion --functions-version $functionsVersion +az functionapp create --name $functionApp --storage-account $AZURE_STORAGE_ACCOUNT \ + --consumption-plan-location "$location" --resource-group $resourceGroup \ + --os-type Linux --runtime python --runtime-version $pythonVersion \ + --functions-version $functionsVersion # Work with Storage account using the set env variables. # Create a share in Azure Files. @@ -57,7 +60,6 @@ az webapp config storage-account add \ # List webapp storage account az webapp config storage-account list --resource-group $resourceGroup --name $functionApp -# # echo "Deleting all resources" # az group delete --name $resourceGroup -y