diff --git a/.azdo/pipelines/azure-dev.yml b/.azdo/pipelines/azure-dev.yml new file mode 100644 index 000000000..b571fd91c --- /dev/null +++ b/.azdo/pipelines/azure-dev.yml @@ -0,0 +1,87 @@ +# Run when commits are pushed to mainline branch (main or master) +# Set this to the mainline branch you are using +trigger: + - main + - master + - dev + +# Azure Pipelines workflow to deploy to Azure using azd +# To configure required secrets and service connection for connecting to Azure, simply run `azd pipeline config --provider azdo` +# Task "Install azd" needs to install setup-azd extension for azdo - https://marketplace.visualstudio.com/items?itemName=ms-azuretools.azd +# See below for alternative task to install azd if you can't install above task in your organization + +pool: + vmImage: ubuntu-latest + +steps: + - task: setup-azd@0 + displayName: Install azd + + # If you can't install above task in your organization, you can comment it and uncomment below task to install azd + # - task: Bash@3 + # displayName: Install azd + # inputs: + # targetType: 'inline' + # script: | + # curl -fsSL https://aka.ms/install-azd.sh | bash + + # azd delegate auth to az to use service connection with AzureCLI@2 + - pwsh: | + azd config set auth.useAzCliAuth "true" + displayName: Configure AZD to Use AZ CLI Authentication. + + - task: AzureCLI@2 + displayName: Provision Infrastructure + inputs: + azureSubscription: azconnection + scriptType: bash + scriptLocation: inlineScript + inlineScript: | + azd provision --no-prompt + env: + + AZURE_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID) + AZURE_ENV_NAME: $(AZURE_ENV_NAME) + AZURE_LOCATION: $(AZURE_LOCATION) + # Project specific environment variables + # AZURE_RESOURCE_GROUP: $(AZURE_RESOURCE_GROUP) + # AZURE_AIHUB_NAME: $(AZURE_AIHUB_NAME) + # AZURE_AIPROJECT_NAME: $(AZURE_AIPROJECT_NAME) + # AZURE_AISERVICES_NAME: $(AZURE_AISERVICES_NAME) + # AZURE_SEARCH_SERVICE_NAME: $(AZURE_SEARCH_SERVICE_NAME) + # AZURE_APPLICATION_INSIGHTS_NAME: $(AZURE_APPLICATION_INSIGHTS_NAME) + # AZURE_CONTAINER_REGISTRY_NAME: $(AZURE_CONTAINER_REGISTRY_NAME) + # AZURE_KEYVAULT_NAME: $(AZURE_KEYVAULT_NAME) + # AZURE_STORAGE_ACCOUNT_NAME: $(AZURE_STORAGE_ACCOUNT_NAME) + # AZURE_LOG_ANALYTICS_WORKSPACE_NAME: $(AZURE_LOG_ANALYTICS_WORKSPACE_NAME) + # USE_CONTAINER_REGISTRY: $(USE_CONTAINER_REGISTRY) + # USE_APPLICATION_INSIGHTS: $(USE_APPLICATION_INSIGHTS) + # USE_SEARCH_SERVICE: $(USE_SEARCH_SERVICE) + # AZURE_AI_CHAT_DEPLOYMENT_NAME: $(AZURE_AI_CHAT_DEPLOYMENT_NAME) + # AZURE_AI_CHAT_DEPLOYMENT_SKU: $(AZURE_AI_CHAT_DEPLOYMENT_SKU) + # AZURE_AI_CHAT_DEPLOYMENT_CAPACITY: $(AZURE_AI_CHAT_DEPLOYMENT_CAPACITY) + # AZURE_AI_CHAT_MODEL_FORMAT: $(AZURE_AI_CHAT_MODEL_FORMAT) + # AZURE_AI_CHAT_MODEL_NAME: $(AZURE_AI_CHAT_MODEL) + # AZURE_AI_CHAT_MODEL_VERSION: $(AZURE_AI_CHAT_MODEL_VERSION) + # AZURE_AI_EMBED_DEPLOYMENT_NAME: $(AZURE_AI_EMBED_DEPLOYMENT_NAME) + # AZURE_AI_EMBED_DEPLOYMENT_SKU: $(AZURE_AI_EMBED_DEPLOYMENT_SKU) + # AZURE_AI_EMBED_DEPLOYMENT_CAPACITY: $(AZURE_AI_EMBED_DEPLOYMENT_CAPACITY) + # AZURE_AI_EMBED_MODEL_FORMAT: $(AZURE_AI_EMBED_MODEL_FORMAT) + # AZURE_AI_EMBED_MODEL_NAME: $(AZURE_AI_EMBED_MODEL_NAME) + # AZURE_AI_EMBED_MODEL_VERSION: $(AZURE_AI_EMBED_MODEL_VERSION) + # AZURE_EXISTING_AIPROJECT_CONNECTION_STRING: $(AZURE_EXISTING_AIPROJECT_CONNECTION_STRING) + - task: AzureCLI@2 + displayName: Deploy Application + inputs: + azureSubscription: azconnection + scriptType: bash + scriptLocation: inlineScript + inlineScript: | + azd deploy --no-prompt + env: + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + AZURE_ENV_NAME: ${{ secrets.AZURE_ENV_NAME }} + AZURE_LOCATION: ${{ secrets.AZURE_LOCATION }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a6ae6ab8d..457b35fba 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -28,8 +28,7 @@ "ms-python.python", "ms-azuretools.vscode-azcli", "ms-azuretools.vscode-bicep", - "ms-azuretools.azure-dev", - "ms-azuretools.vscode-azurefunctions" + "ms-azuretools.azure-dev" ] } }, diff --git a/.github/workflows/CAdeploy.yml b/.github/workflows/CAdeploy.yml index 7865b05d4..d9d2e004e 100644 --- a/.github/workflows/CAdeploy.yml +++ b/.github/workflows/CAdeploy.yml @@ -115,7 +115,7 @@ jobs: az deployment group create \ --resource-group ${{ env.RESOURCE_GROUP_NAME }} \ --template-file infra/main.bicep \ - --parameters AzureOpenAILocation=${{ env.AZURE_LOCATION }} + --parameters AzureOpenAILocation=${{ env.AZURE_LOCATION }} environmentName=${{ env.SOLUTION_PREFIX }} cosmosLocation=eastus2 - name: List KeyVaults and Store in Array id: list_keyvaults diff --git a/.gitignore b/.gitignore index f223f792e..cec1e1d05 100644 --- a/.gitignore +++ b/.gitignore @@ -403,4 +403,4 @@ scriptenv .azure clientdata -clienttranscripts \ No newline at end of file +clienttranscripts diff --git a/README.md b/README.md index 4f182dcf8..a5ac4e09d 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ Follow the quick deploy steps on the deployment guide to deploy this solution to -| [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fmicrosoft%2Fbuild-your-own-copilot-solution-accelerator%2Fdev%2Finfra%2Fmain.json) | -|---| +
diff --git a/docs/ManualAppRegistrationConfiguration.md b/docs/ManualAppRegistrationConfiguration.md new file mode 100644 index 000000000..cc50eb349 --- /dev/null +++ b/docs/ManualAppRegistrationConfiguration.md @@ -0,0 +1,66 @@ +# Manual App Registration Configuration +This guide provides detailed steps to manually register both front-end and backend applications in Azure if automated registration is not an option due to security in place in your tenant and subscription. + +## Prerequisites + +- Access to **Microsoft Entra ID** +- Necessary permissions to create and manage **App Registrations** in your Azure tenant + +## Step 1: Register the Web Application +### 1. Create App Registration +- Go to **Azure Portal** > **Microsoft Entra ID** > **Manage** > **App registrations** +- Click **+ New registration** +- Name the app (e.g., `byoc-app`) +- Under **Redirect URI**, choose **Web** and enter: + + ``` + https://azurecontainerapps.io/auth/login/aad/callback + ``` + + To find your Web App URL: + - Navigate to your newly deployed resource group in the Azure Portal. + - Locate the web app in resource group. + - Copy the Default domain url from the Overview . + +- Click **Register** + ![ManualRegisterAppWeb1](./Images/ManualRegisterAppWeb1.png) + + + +### 2. Configure Certificates and Secrets + +- Go to **Certificates & secrets** +- Click **+ New client secret** +- Description: Provide a meaningful name to identify the secret +- Expires: Select from the options or define a custom range +- Start (Optional for custom range): Set the starting date of the secret's validity +- End (Optional for custom range): Set the ending date of the secret's validity +- Click **Add** and remember to copy and store the secret value securely as it will not be shown again +![ManualRegisterAppWeb3](./Images/ManualRegisterAppWeb3.png) + +### 3. Get Tenant ID +- Go to **Tenant Properties** in [Azure Portal](https://portal.azure.com) +- Copy the Tenant ID (will be used in next step) + +![ManualRegisterAppWeb6](./Images/ManualRegisterAppWeb6.png) + +### 4. Set Up Authentication in Web Container App + +- Go to your Web Container App +- Go to **Authentication** +- Click **Add Identity Provider** +- Choose **Microsoft** +- Input: + - **Client ID**: The Application (client) ID from the app registration + - **Client Secret**: The secret value you generated in Certificates & Secrets from the app registration + - **Issuer URL**: `https://sts.windows.net//v2.0` + - **Allowed Token Audiences**: Usually the Application ID URI or Client ID +- Click **Add** + +![ManualRegisterAppWeb4](./Images/ManualRegisterAppWeb4.png) + +--- + +## Conclusion + +You have now manually configured Azure App Registrations. \ No newline at end of file diff --git a/docs/images/AppAuthenticationIdentityProviderRestriction.png b/docs/images/AppAuthenticationIdentityProviderRestriction.png new file mode 100644 index 000000000..2da9f4411 Binary files /dev/null and b/docs/images/AppAuthenticationIdentityProviderRestriction.png differ diff --git a/docs/images/ManualRegisterAppWeb1.png b/docs/images/ManualRegisterAppWeb1.png new file mode 100644 index 000000000..a6fe9e39c Binary files /dev/null and b/docs/images/ManualRegisterAppWeb1.png differ diff --git a/docs/images/ManualRegisterAppWeb3.png b/docs/images/ManualRegisterAppWeb3.png new file mode 100644 index 000000000..8f83739c6 Binary files /dev/null and b/docs/images/ManualRegisterAppWeb3.png differ diff --git a/docs/images/ManualRegisterAppWeb4.png b/docs/images/ManualRegisterAppWeb4.png new file mode 100644 index 000000000..2ee3ee194 Binary files /dev/null and b/docs/images/ManualRegisterAppWeb4.png differ diff --git a/docs/images/ManualRegisterAppWeb6.png b/docs/images/ManualRegisterAppWeb6.png new file mode 100644 index 000000000..2fca2c873 Binary files /dev/null and b/docs/images/ManualRegisterAppWeb6.png differ diff --git a/docs/images/readMe/architecture.png b/docs/images/readMe/architecture.png index 3716611da..104b326f7 100644 Binary files a/docs/images/readMe/architecture.png and b/docs/images/readMe/architecture.png differ diff --git a/infra/deploy_cosmos_db.bicep b/infra/deploy_cosmos_db.bicep index d0b778862..6b26f820a 100644 --- a/infra/deploy_cosmos_db.bicep +++ b/infra/deploy_cosmos_db.bicep @@ -112,4 +112,3 @@ resource AZURE_COSMOSDB_ENABLE_FEEDBACK 'Microsoft.KeyVault/vaults/secrets@2021- output cosmosAccountName string = cosmos.name output cosmosDatabaseName string = databaseName output cosmosContainerName string = collectionName - diff --git a/infra/deploy_sql_db.bicep b/infra/deploy_sql_db.bicep index 27339fba6..34cb8688a 100644 --- a/infra/deploy_sql_db.bicep +++ b/infra/deploy_sql_db.bicep @@ -13,6 +13,7 @@ param sqlDBName string param location string = solutionLocation @description('The administrator username of the SQL logical server.') +@secure() param administratorLogin string = 'sqladmin' @description('The administrator password of the SQL logical server.') @@ -112,6 +113,6 @@ resource sqldbDatabasePwd 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' } } -output sqlServerName string = '${serverName}.database.windows.net' +output sqlServerName string = serverName output sqlDbName string = sqlDBName -output sqlDbUser string = administratorLogin +// output sqlDbUser string = administratorLogin diff --git a/infra/main.bicep b/infra/main.bicep index 54acda493..3e286e79f 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -226,9 +226,9 @@ module appserviceModule 'deploy_app_service.bicep' = { AzureOpenAIEmbeddingkey:keyVault.getSecret('AZURE-OPENAI-KEY') AzureOpenAIEmbeddingEndpoint:aifoundry.outputs.aiServicesTarget USE_INTERNAL_STREAM:'True' - SQLDB_SERVER:sqlDBModule.outputs.sqlServerName + SQLDB_SERVER:'${sqlDBModule.outputs.sqlServerName}.database.windows.net' SQLDB_DATABASE:sqlDBModule.outputs.sqlDbName - SQLDB_USERNAME:sqlDBModule.outputs.sqlDbUser + SQLDB_USERNAME:'sqladmin' SQLDB_PASSWORD:keyVault.getSecret('SQLDB-PASSWORD') AZURE_COSMOSDB_ACCOUNT: cosmosDBModule.outputs.cosmosAccountName AZURE_COSMOSDB_CONVERSATIONS_CONTAINER: cosmosDBModule.outputs.cosmosContainerName @@ -256,7 +256,7 @@ output STORAGE_CONTAINER_NAME string = storageAccountModule.outputs.storageConta output KEY_VAULT_NAME string = keyvaultModule.outputs.keyvaultName output COSMOSDB_ACCOUNT_NAME string = cosmosDBModule.outputs.cosmosAccountName output RESOURCE_GROUP_NAME string = resourceGroup().name -output SQLDB_SERVER string = replace(sqlDBModule.outputs.sqlServerName, '.database.windows.net','') +output SQLDB_SERVER string = sqlDBModule.outputs.sqlServerName output SQLDB_DATABASE string = sqlDBModule.outputs.sqlDbName output MANAGEDINDENTITY_WEBAPP_NAME string = managedIdentityModule.outputs.managedIdentityWebAppOutput.name output MANAGEDINDENTITY_WEBAPP_CLIENTID string = managedIdentityModule.outputs.managedIdentityWebAppOutput.clientId diff --git a/infra/main.json b/infra/main.json index 23da09d3b..0e4dc7597 100644 --- a/infra/main.json +++ b/infra/main.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "6807899313442022071" + "templateHash": "1797657337218629559" } }, "parameters": { @@ -39,8 +39,7 @@ "type": "string", "defaultValue": "gpt-4o-mini", "allowedValues": [ - "gpt-4o-mini", - "gpt-4o" + "gpt-4o-mini" ], "minLength": 1, "metadata": { @@ -91,8 +90,6 @@ "eastus2", "francecentral", "japaneast", - "norwayeast", - "southindia", "swedencentral", "uksouth", "westus", @@ -1933,7 +1930,7 @@ "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "1848692139029312246" + "templateHash": "4179944107717925300" } }, "parameters": { @@ -1969,7 +1966,7 @@ } }, "administratorLogin": { - "type": "string", + "type": "securestring", "defaultValue": "sqladmin", "metadata": { "description": "The administrator username of the SQL logical server." @@ -2086,15 +2083,11 @@ "outputs": { "sqlServerName": { "type": "string", - "value": "[format('{0}.database.windows.net', parameters('serverName'))]" + "value": "[parameters('serverName')]" }, "sqlDbName": { "type": "string", "value": "[parameters('sqlDBName')]" - }, - "sqlDbUser": { - "type": "string", - "value": "[parameters('administratorLogin')]" } } } @@ -2233,13 +2226,13 @@ "value": "True" }, "SQLDB_SERVER": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_sql_db'), '2022-09-01').outputs.sqlServerName.value]" + "value": "[format('{0}.database.windows.net', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_sql_db'), '2022-09-01').outputs.sqlServerName.value)]" }, "SQLDB_DATABASE": { "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_sql_db'), '2022-09-01').outputs.sqlDbName.value]" }, "SQLDB_USERNAME": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_sql_db'), '2022-09-01').outputs.sqlDbUser.value]" + "value": "sqladmin" }, "SQLDB_PASSWORD": { "reference": { @@ -3085,7 +3078,7 @@ }, "SQLDB_SERVER": { "type": "string", - "value": "[replace(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_sql_db'), '2022-09-01').outputs.sqlServerName.value, '.database.windows.net', '')]" + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_sql_db'), '2022-09-01').outputs.sqlServerName.value]" }, "SQLDB_DATABASE": { "type": "string", diff --git a/infra/scripts/quota_check_params.sh b/infra/scripts/quota_check_params.sh index a373ad1cb..62a2305c8 100644 --- a/infra/scripts/quota_check_params.sh +++ b/infra/scripts/quota_check_params.sh @@ -247,4 +247,4 @@ else echo "➡️ To request a quota increase, visit: https://aka.ms/oai/stuquotarequest" fi -echo "✅ Script completed." +echo "✅ Script completed." \ No newline at end of file