diff --git a/.azdo/pipelines/azure-dev.yml b/.azdo/pipelines/azure-dev.yml new file mode 100644 index 0000000000..a43f250ead --- /dev/null +++ b/.azdo/pipelines/azure-dev.yml @@ -0,0 +1,88 @@ +# Run when commits are pushed to mainline branch (main or master) +# Set this to the mainline branch you are using +trigger: + - main + - master + +# 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: + # azconnection is the service connection created by azd. You can change it to any service connection you have in your organization. + 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) + AZD_INITIAL_ENVIRONMENT_CONFIG: $(AZD_INITIAL_ENVIRONMENT_CONFIG) + AZURE_OPENAI_SERVICE: $(AZURE_OPENAI_SERVICE) + AZURE_OPENAI_RESOURCE_GROUP: $(AZURE_OPENAI_RESOURCE_GROUP) + AZURE_FORMRECOGNIZER_SERVICE: $(AZURE_FORMRECOGNIZER_SERVICE) + AZURE_FORMRECOGNIZER_RESOURCE_GROUP: $(AZURE_FORMRECOGNIZER_RESOURCE_GROUP) + AZURE_FORMRECOGNIZER_SKU: $(AZURE_FORMRECOGNIZER_SKU) + AZURE_SEARCH_INDEX: $(AZURE_SEARCH_INDEX) + AZURE_SEARCH_SERVICE: $(AZURE_SEARCH_SERVICE) + AZURE_SEARCH_SERVICE_RESOURCE_GROUP: $(AZURE_SEARCH_SERVICE_RESOURCE_GROUP) + AZURE_SEARCH_SERVICE_LOCATION: $(AZURE_SEARCH_SERVICE_LOCATION) + AZURE_SEARCH_SERVICE_SKU: $(AZURE_SEARCH_SERVICE_SKU) + AZURE_SEARCH_QUERY_LANGUAGE: $(AZURE_SEARCH_QUERY_LANGUAGE) + AZURE_SEARCH_QUERY_SPELLER: $(AZURE_SEARCH_QUERY_SPELLER) + AZURE_SEARCH_SEMANTIC_RANKER: $(AZURE_SEARCH_SEMANTIC_RANKER) + AZURE_STORAGE_ACCOUNT: $(AZURE_STORAGE_ACCOUNT) + AZURE_STORAGE_RESOURCE_GROUP: $(AZURE_STORAGE_RESOURCE_GROUP) + AZURE_STORAGE_SKU: $(AZURE_STORAGE_SKU) + AZURE_APP_SERVICE_SKU: $(AZURE_APP_SERVICE_SKU) + AZURE_OPENAI_CHATGPT_DEPLOYMENT: $(AZURE_OPENAI_CHATGPT_DEPLOYMENT) + AZURE_OPENAI_EMB_DEPLOYMENT: $(AZURE_OPENAI_EMB_DEPLOYMENT) + OPENAI_HOST: $(OPENAI_HOST) + OPENAI_API_KEY: $(OPENAI_API_KEY) + OPENAI_ORGANIZATION: $(OPENAI_ORGANIZATION) + AZURE_USE_APPLICATION_INSIGHTS: $(AZURE_USE_APPLICATION_INSIGHTS) + USE_VECTORS: $(USE_VECTORS) + USE_GPT4V: $(USE_GPT4V) + AZURE_USE_AUTHENTICATION: $(AZURE_USE_AUTHENTICATION) + AZURE_ENFORCE_ACCESS_CONTROL: $(AZURE_ENFORCE_ACCESS_CONTROL) + AZURE_TENANT_ID: $(AZURE_TENANT_ID) + AZURE_AUTH_TENANT_ID: $(AZURE_AUTH_TENANT_ID) + AZURE_SERVER_APP_ID: $(AZURE_SERVER_APP_ID) + AZURE_CLIENT_APP_ID: $(AZURE_CLIENT_APP_ID) + ALLOWED_ORIGIN: $(ALLOWED_ORIGIN) + AZURE_SERVER_APP_SECRET: $(AZURE_SERVER_APP_SECRET) + AZURE_CLIENT_APP_SECRET: $(AZURE_CLIENT_APP_SECRET) + + - task: AzureCLI@2 + displayName: Deploy Application + inputs: + azureSubscription: azconnection + scriptType: bash + scriptLocation: inlineScript + inlineScript: | + azd deploy --no-prompt diff --git a/.github/workflows/azure-dev.yml b/.github/workflows/azure-dev.yml new file mode 100644 index 0000000000..2d97986cfb --- /dev/null +++ b/.github/workflows/azure-dev.yml @@ -0,0 +1,107 @@ +name: Deploy + +on: + workflow_dispatch: + push: + # Run when commits are pushed to mainline branch (main or master) + # Set this to the mainline branch you are using + branches: + - main + - master + +# GitHub Actions workflow to deploy to Azure using azd +# To configure required secrets for connecting to Azure, simply run `azd pipeline config` + +# Set up permissions for deploying with secretless Azure federated credentials +# https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-portal%2Clinux#set-up-azure-login-with-openid-connect-authentication +permissions: + id-token: write + contents: read + +jobs: + build: + runs-on: ubuntu-latest + env: + # azd required + AZURE_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }} + AZURE_TENANT_ID: ${{ vars.AZURE_TENANT_ID }} + AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }} + AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }} + AZURE_LOCATION: ${{ vars.AZURE_LOCATION }} + # project specific + AZURE_OPENAI_SERVICE: ${{ vars.AZURE_OPENAI_SERVICE }} + AZURE_OPENAI_RESOURCE_GROUP: ${{ vars.AZURE_OPENAI_RESOURCE_GROUP }} + AZURE_FORMRECOGNIZER_SERVICE: ${{ vars.AZURE_FORMRECOGNIZER_SERVICE }} + AZURE_FORMRECOGNIZER_RESOURCE_GROUP: ${{ vars.AZURE_FORMRECOGNIZER_RESOURCE_GROUP }} + AZURE_FORMRECOGNIZER_SKU: ${{ vars.AZURE_FORMRECOGNIZER_SKU }} + AZURE_SEARCH_INDEX: ${{ vars.AZURE_SEARCH_INDEX }} + AZURE_SEARCH_SERVICE: ${{ vars.AZURE_SEARCH_SERVICE }} + AZURE_SEARCH_SERVICE_RESOURCE_GROUP: ${{ vars.AZURE_SEARCH_SERVICE_RESOURCE_GROUP }} + AZURE_SEARCH_SERVICE_LOCATION: ${{ vars.AZURE_SEARCH_SERVICE_LOCATION }} + AZURE_SEARCH_SERVICE_SKU: ${{ vars.AZURE_SEARCH_SERVICE_SKU }} + AZURE_SEARCH_QUERY_LANGUAGE: ${{ vars.AZURE_SEARCH_QUERY_LANGUAGE }} + AZURE_SEARCH_QUERY_SPELLER: ${{ vars.AZURE_SEARCH_QUERY_SPELLER }} + AZURE_SEARCH_SEMANTIC_RANKER: ${{ vars.AZURE_SEARCH_SEMANTIC_RANKER }} + AZURE_STORAGE_ACCOUNT: ${{ vars.AZURE_STORAGE_ACCOUNT }} + AZURE_STORAGE_RESOURCE_GROUP: ${{ vars.AZURE_STORAGE_RESOURCE_GROUP }} + AZURE_STORAGE_SKU: ${{ vars.AZURE_STORAGE_SKU }} + AZURE_APP_SERVICE_SKU: ${{ vars.AZURE_APP_SERVICE_SKU }} + AZURE_OPENAI_CHATGPT_DEPLOYMENT: ${{ vars.AZURE_OPENAI_CHATGPT_DEPLOYMENT }} + AZURE_OPENAI_EMB_DEPLOYMENT: ${{ vars.AZURE_OPENAI_EMB_DEPLOYMENT }} + OPENAI_HOST: ${{ vars.OPENAI_HOST }} + OPENAI_API_KEY: ${{ vars.OPENAI_API_KEY }} + OPENAI_ORGANIZATION: ${{ vars.OPENAI_ORGANIZATION }} + AZURE_USE_APPLICATION_INSIGHTS: ${{ vars.AZURE_USE_APPLICATION_INSIGHTS }} + USE_VECTORS: ${{ vars.USE_VECTORS }} + USE_GPT4V: ${{ vars.USE_GPT4V }} + AZURE_USE_AUTHENTICATION: ${{ vars.AZURE_USE_AUTHENTICATION }} + AZURE_ENFORCE_ACCESS_CONTROL: ${{ vars.AZURE_ENFORCE_ACCESS_CONTROL }} + AZURE_AUTH_TENANT_ID: ${{ vars.AZURE_AUTH_TENANT_ID }} + AZURE_SERVER_APP_ID: ${{ vars.AZURE_SERVER_APP_ID }} + AZURE_CLIENT_APP_ID: ${{ vars.AZURE_CLIENT_APP_ID }} + ALLOWED_ORIGIN: ${{ vars.ALLOWED_ORIGIN }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install azd + uses: Azure/setup-azd@v0.1.0 + + - name: Install Nodejs + uses: actions/setup-node@v3 + with: + node-version: 20 + + - name: Log in with Azure (Federated Credentials) + if: ${{ env.AZURE_CLIENT_ID != '' }} + run: | + azd auth login ` + --client-id "$Env:AZURE_CLIENT_ID" ` + --federated-credential-provider "github" ` + --tenant-id "$Env:AZURE_TENANT_ID" + shell: pwsh + + - name: Log in with Azure (Client Credentials) + if: ${{ env.AZURE_CREDENTIALS != '' }} + run: | + $info = $Env:AZURE_CREDENTIALS | ConvertFrom-Json -AsHashtable; + Write-Host "::add-mask::$($info.clientSecret)" + + azd auth login ` + --client-id "$($info.clientId)" ` + --client-secret "$($info.clientSecret)" ` + --tenant-id "$($info.tenantId)" + shell: pwsh + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Provision Infrastructure + run: azd provision --no-prompt + env: + AZD_INITIAL_ENVIRONMENT_CONFIG: ${{ secrets.AZD_INITIAL_ENVIRONMENT_CONFIG }} + AZURE_SERVER_APP_SECRET: ${{ secrets.AZURE_SERVER_APP_SECRET }} + AZURE_CLIENT_APP_SECRET: ${{ secrets.AZURE_CLIENT_APP_SECRET }} + + - name: Deploy Application + run: azd deploy --no-prompt diff --git a/azure.yaml b/azure.yaml index 0b9264ef2b..2dbc71b194 100644 --- a/azure.yaml +++ b/azure.yaml @@ -13,13 +13,49 @@ services: windows: shell: pwsh run: cd ../frontend;npm install;npm run build - interactive: true + interactive: false continueOnError: false posix: shell: sh run: cd ../frontend;npm install;npm run build - interactive: true + interactive: false continueOnError: false +pipeline: + variables: + - AZURE_OPENAI_SERVICE + - AZURE_OPENAI_RESOURCE_GROUP + - AZURE_FORMRECOGNIZER_SERVICE + - AZURE_FORMRECOGNIZER_RESOURCE_GROUP + - AZURE_FORMRECOGNIZER_SKU + - AZURE_SEARCH_INDEX + - AZURE_SEARCH_SERVICE + - AZURE_SEARCH_SERVICE_RESOURCE_GROUP + - AZURE_SEARCH_SERVICE_LOCATION + - AZURE_SEARCH_SERVICE_SKU + - AZURE_SEARCH_QUERY_LANGUAGE + - AZURE_SEARCH_QUERY_SPELLER + - AZURE_SEARCH_SEMANTIC_RANKER + - AZURE_STORAGE_ACCOUNT + - AZURE_STORAGE_RESOURCE_GROUP + - AZURE_STORAGE_SKU + - AZURE_APP_SERVICE_SKU + - AZURE_OPENAI_CHATGPT_DEPLOYMENT + - AZURE_OPENAI_EMB_DEPLOYMENT + - OPENAI_HOST + - OPENAI_API_KEY + - OPENAI_ORGANIZATION + - AZURE_USE_APPLICATION_INSIGHTS + - USE_VECTORS + - USE_GPT4V + - AZURE_USE_AUTHENTICATION + - AZURE_ENFORCE_ACCESS_CONTROL + - AZURE_AUTH_TENANT_ID + - AZURE_SERVER_APP_ID + - AZURE_CLIENT_APP_ID + - ALLOWED_ORIGIN + secrets: + - AZURE_SERVER_APP_SECRET + - AZURE_CLIENT_APP_SECRET hooks: preprovision: windows: diff --git a/infra/main.bicep b/infra/main.bicep index dc883359ed..68b9f94248 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -122,6 +122,12 @@ var useKeyVault = useGPT4V || useSearchServiceKey var tenantIdForAuth = !empty(authTenantId) ? authTenantId : tenantId var authenticationIssuerUri = '${environment().authentication.loginEndpoint}${tenantIdForAuth}/v2.0' +@description('Whether the deployment is running on GitHub Actions') +param runningOnGh string = '' + +@description('Whether the deployment is running on Azure DevOps Pipeline') +param runningOnAdo string = '' + // Organize resources in a resource group resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: !empty(resourceGroupName) ? resourceGroupName : '${abbrs.resourcesResourceGroups}${environmentName}' @@ -424,13 +430,15 @@ module storage 'core/storage/storage-account.bicep' = { } // USER ROLES +var principalType = empty(runningOnGh) && empty(runningOnAdo) ? 'User': 'ServicePrincipal' + module openAiRoleUser 'core/security/role.bicep' = if (openAiHost == 'azure') { scope: openAiResourceGroup name: 'openai-role-user' params: { principalId: principalId roleDefinitionId: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' - principalType: 'User' + principalType: principalType } } @@ -440,7 +448,7 @@ module formRecognizerRoleUser 'core/security/role.bicep' = { params: { principalId: principalId roleDefinitionId: 'a97b65f3-24c7-4388-baec-2e87135dc908' - principalType: 'User' + principalType: principalType } } @@ -450,7 +458,7 @@ module storageRoleUser 'core/security/role.bicep' = { params: { principalId: principalId roleDefinitionId: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' - principalType: 'User' + principalType: principalType } } @@ -460,7 +468,7 @@ module storageContribRoleUser 'core/security/role.bicep' = { params: { principalId: principalId roleDefinitionId: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' - principalType: 'User' + principalType: principalType } } @@ -471,7 +479,7 @@ module searchRoleUser 'core/security/role.bicep' = if (!useSearchServiceKey) { params: { principalId: principalId roleDefinitionId: '1407120a-92aa-4202-b7e9-c0e197c71c8f' - principalType: 'User' + principalType: principalType } } @@ -481,7 +489,7 @@ module searchContribRoleUser 'core/security/role.bicep' = if (!useSearchServiceK params: { principalId: principalId roleDefinitionId: '8ebe5a00-799e-43f5-93ac-243d3dce84a7' - principalType: 'User' + principalType: principalType } } @@ -491,7 +499,7 @@ module searchSvcContribRoleUser 'core/security/role.bicep' = if (!useSearchServi params: { principalId: principalId roleDefinitionId: '7ca78c08-252a-4471-8644-bb5ff32d4ba0' - principalType: 'User' + principalType: principalType } } diff --git a/infra/main.parameters.json b/infra/main.parameters.json index e18780bc68..40c03b798f 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -74,7 +74,7 @@ "embeddingDeploymentName": { "value": "${AZURE_OPENAI_EMB_DEPLOYMENT=embedding}" }, - "openAiHost":{ + "openAiHost": { "value": "${OPENAI_HOST=azure}" }, "openAiApiKey": { @@ -119,8 +119,14 @@ "allowedOrigin": { "value": "${ALLOWED_ORIGIN}" }, - "useIntegratedVectorization" :{ + "useIntegratedVectorization": { "value": "${USE_FEATURE_INT_VECTORIZATION}" + }, + "runningOnGh": { + "value": "${GITHUB_ACTIONS}" + }, + "runningOnAdo": { + "value": "${TF_BUILD}" } } }