diff --git a/fsi/solutions/generativeAi/EnterpriseAIPortal.json b/fsi/solutions/generativeAi/EnterpriseAIPortal.json index 49b710e6..e805f471 100644 --- a/fsi/solutions/generativeAi/EnterpriseAIPortal.json +++ b/fsi/solutions/generativeAi/EnterpriseAIPortal.json @@ -3,7 +3,7 @@ "view": { "kind": "Form", "properties": { - "title": "Secure and Compliant Generative Azure Open AI", + "title": "Secure and Compliant Generative AI on Azure", "steps": [ { "name": "basics", @@ -735,7 +735,7 @@ "type": "Microsoft.Common.DropDown", "label": "Select the Model you want to deploy", "placeholder": "", - "defaultValue": "GPT-35-Turbo", + "defaultValue": "GPT-4", "toolTip": "", "multiselect": false, "multiLine": true, @@ -754,6 +754,16 @@ "description": "GPT-4 can solve difficult problems with greater accuracy than any of OpenAI's previous models. Like GPT-3.5 Turbo, GPT-4 is optimized for chat and works well for traditional completions tasks. Use the Chat Completions API to use GPT-4.", "value": "gpt-4-32k" }, + { + "label": "GPT-4-Vision", + "description": "GPT-4 Turbo with Vision is a large multimodal model (LMM) developed by OpenAI that can analyze images and provide textual responses to questions about them. It incorporates both natural language processing and visual understanding.The GPT-4 Turbo with Vision model answers general questions about what's present in the images. You can also show it video if you use Vision enhancement.", + "value": "gpt-4-vision" + }, + { + "label": "Embeddings", + "description": "OpenAI offers a powerful second-generation embedding model (denoted by -002 in the model ID). It’s better, cheaper, and simpler to use than previous embeddings models.", + "value": "text-embedding-ada-002" + }, { "label": "GPT-35-Turbo", "description": "GPT-3.5 models can understand and generate natural language or code. The most capable and cost effective model in the GPT-3.5 family is GPT-3.5 Turbo, which has been optimized for chat and works well for traditional completions tasks as well.", @@ -1237,6 +1247,264 @@ "visible": "[and(equals(steps('aiModelSettings').aiContentFilter, 'Yes'), equals(steps('aiModelSettings').aiAddContentFilter, 'Yes'))]" } ] + }, + { + "name": "aiAuxiliarySettings", + "label": "Generative AI use-cases setup", + "subLabel": { + "preValidation": "", + "postValidation": "Done" + }, + "bladeTitle": "Auxiliary services", + "elements": [ + { + "name": "aiAuxiliaryText", + "type": "Microsoft.Common.InfoBox", + "visible": true, + "options": { + "icon": "None", + "text": "Subject to your initial use-cases, you can enable additional Azure services for the complete Generative AI architecture on Azure.", + "uri": "https://www.microsoft.com" + } + }, + { + "name": "aiUseCaseSection", + "type": "Microsoft.Common.Section", + "label": "Use-cases", + "elements": [], + "visible": true + }, + { + "name": "aiUseCaseText", + "type": "Microsoft.Common.TextBlock", + "visible": true, + "options": { + "text": "Technology is advancing at an unprecedented pace, and businesses are seeking innovative ways to maintain a competitive edge. Nowhere is this truer than in the realms of generative AI. From generating realistic images and videos to enhancing customer experiences, generative AI has proven to be a versatile tool across various industries.", + "link": { + "label": "Learn more", + "uri": "https://azure.microsoft.com/en-us/blog/azure-openai-service-10-ways-generative-ai-is-transforming-businesses/" + } + } + }, + { + "name": "aiUseCaseDeployment", + "type": "Microsoft.Common.OptionsGroup", + "label": "Create Azure AI services for the initial use-cases", + "defaultValue": "Yes", + "toolTip": "", + "constraints": { + "allowedValues": [ + { + "label": "Yes", + "value": "Yes" + }, + { + "label": "No", + "value": "No" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "aiUseCaseSelection", + "type": "Microsoft.Common.DropDown", + "label": "Select the initial use-case you want to deploy", + "placeholder": "", + "defaultValue": "Image and video recognition", + "toolTip": "", + "multiselect": false, + "multiLine": true, + "selectAll": false, + "defaultDescription": "Select the initial use-case you want to start with.", + "filter": true, + "constraints": { + "allowedValues": [ + { + "label": "Content creation and design", + "description": "Content creation and design: Effective content creation and design are crucial for attracting and engaging customers.", + "value": "content" + }, + { + "label": "Accelerated automation", + "description": "Automating IT tasks improves employee experiences, enhances customer interactions, and drives more efficiency within a company’s developer community.", + "value": "automation" + }, + { + "label": "Personalized marketing", + "description": "Personalization increases the chances of customer engagement and conversion and can significantly improve marketing ROI..", + "value": "marketing" + }, + { + "label": "Chatbots and virtual agents", + "description": "Chatbots and virtual assistants powered by generative AI provide instant and accurate responses to customer queries.", + "value": "chatbots" + }, + { + "label": "Language translation and natural language processing", + "description": "In a globalized world, language barriers can hinder communication and business growth.", + "value": "language" + }, + { + "label": "Image and video recognition", + "description": "analyze images and provide textual responses to questions about them. It incorporates both natural language processing and visual understanding.", + "value": "vision" + } + ], + "required": true + }, + "visible": "[equals(steps('aiAuxiliarySettings').aiUseCaseDeployment, 'Yes')]" + }, + + { + "name": "aiSearchInfo", + "type": "Microsoft.Common.InfoBox", + "visible": "[equals(steps('aiAuxiliarySettings').aiUseCaseDeployment, 'Yes')]", + "options": { + "icon": "None", + "text": "Azure AI Search, an AI-powered information retrieval platform, helps developers build rich search experiences and generative AI apps that combine large language models with enterprise data. Implement search functionality for any mobile or search application within your organization or as part of software as a service (SaaS) apps.", + "uri": "https://www.microsoft.com" + } + }, + { + "name": "aiEncryptionSection", + "type": "Microsoft.Common.Section", + "label": "Azure AI Search", + "elements": [], + "visible": "[equals(steps('aiAuxiliarySettings').aiUseCaseDeployment, 'Yes')]" + }, + { + "name": "aiSearchNetworkSection", + "type": "Microsoft.Common.Section", + "label": "Network Settings", + "elements": [], + "visible": "[equals(steps('aiAuxiliarySettings').aiUseCaseDeployment, 'Yes')]" + }, + { + "name": "aiSearchDisableNetworkAccess", + "type": "Microsoft.Common.OptionsGroup", + "label": "Disable Public Network Access", + "defaultValue": "Yes (recommended)", + "toolTip": "", + "constraints": { + "allowedValues": [ + { + "label": "Yes (recommended)", + "value": "Yes" + }, + { + "label": "No", + "value": "No" + } + ], + "required": true + }, + "visible": "[equals(steps('aiAuxiliarySettings').aiUseCaseDeployment, 'Yes')]" + }, + { + "name": "aiSearchNwLocationOption", + "type": "Microsoft.Common.OptionsGroup", + "label": "Deploy the Private Endpoint for Azure AI Search into the same region as the Azure AI Search service", + "defaultValue": "Yes", + "toolTip": "This will deploy the Private Endpoint in the provided subnet and will also associate an Application Security Group", + "constraints": { + "allowedValues": [ + { + "label": "Yes", + "value": "Yes" + }, + { + "label": "No", + "value": "No" + } + ], + "required": true + }, + "visible": "[and(equals(steps('aiAuxiliarySettings').aiUseCaseDeployment, 'Yes'), equals(steps('aiAuxiliarySettings').aiSearchDisableNetworkAccess, 'Yes'))]" + }, + { + "name": "aiSearchLocationsApi", + "type": "Microsoft.Solutions.ArmApiControl", + "request": { + "method": "GET", + "path": "locations?api-version=2019-11-01" + } + }, + { + "name": "aiSearchNwLocation", + "type": "Microsoft.Common.DropDown", + "label": "Select region for the Private Endpoint", + "filter": true, + "toolTip": "Select the target region for the Private Endpoint", + "constraints": { + "allowedValues": "[map(steps('aiAuxiliarySettings').aiSearchLocationsApi.value,(item) => parse(concat('{\"label\":\"',item.displayName,'\",\"value\":\"',item.name,'\"}')))]", + "required": true + }, + "visible": "[and(not(equals(steps('aiAuxiliarySettings').aiSearchNwLocationOption, 'Yes')), equals(steps('aiAuxiliarySettings').aiSearchDisableNetworkAccess, 'Yes'))]" + }, + { + "name": "aiSearchSubnetId", + "type": "Microsoft.Common.TextBox", + "label": "ResourceId of existing subnet for connecting Private Endpoint", + "placeholder": "", + "defaultValue": "", + "toolTip": "Use only allowed characters", + "constraints": { + "required": true + }, + "visible": "[and(equals(steps('aiAuxiliarySettings').aiUseCaseDeployment, 'Yes'), equals(steps('aiSettings').aiDisableNetworkAccess, 'Yes'))]" + }, + { + "name": "authzSection", + "type": "Microsoft.Common.Section", + "label": "Authorization Settings", + "elements": [], + "visible": "[equals(steps('aiAuxiliarySettings').aiUseCaseDeployment, 'Yes')]" + }, + { + "name": "aiSearchRbacAuthz", + "type": "Microsoft.Common.OptionsGroup", + "label": "Enable Azure RBAC authorization", + "defaultValue": "Yes (recommended)", + "toolTip": "", + "constraints": { + "allowedValues": [ + { + "label": "Yes (recommended)", + "value": "Yes" + }, + { + "label": "No, use local authorization with API key", + "value": "No" + } + ], + "required": true + }, + "visible": "[equals(steps('aiAuxiliarySettings').aiUseCaseDeployment, 'Yes')]" + }, + { + "name": "aiSearchSystemIdentity", + "type": "Microsoft.Common.OptionsGroup", + "label": "Enable Managed Identity (System-assigned) for Azure AI Search", + "defaultValue": "Yes (recommended)", + "toolTip": "When enabling Managed Identity and usage of Customer-Managed keys, this identity will have RBAC permission access the Azure Open AI instance.", + "constraints": { + "allowedValues": [ + { + "label": "Yes (recommended)", + "value": "Yes" + }, + { + "label": "No", + "value": "No" + } + ], + "required": true + }, + "visible": "[equals(steps('aiAuxiliarySettings').aiUseCaseDeployment, 'Yes')]" + } + ] } ] }, @@ -1279,7 +1547,13 @@ "aiContentHarmFilterCompletion": "[steps('aiModelSettings').aiContentHarmFilterCompletion]", "aiContentHateFilterCompletion": "[steps('aiModelSettings').aiContentHateFilterCompletion]", "aiContentSexualFilterCompletion": "[steps('aiModelSettings').aiContentSexualFilterCompletion]", - "aiContentViolenceFilterCompletion": "[steps('aiModelSettings').aiContentViolenceFilterCompletion]" + "aiContentViolenceFilterCompletion": "[steps('aiModelSettings').aiContentViolenceFilterCompletion]", + "aiSearchDisableNetworkAccess": "[steps('aiAuxiliarySettings').aiSearchDisableNetworkAccess]", + "aiSearchNwLocation": "[if(equals(steps('aiAuxiliarySettings').aiSearchNwLocationOption, 'Yes'), steps('basics').resourceScope.location.name, steps('aiAuxiliarySettings').aiSearchNwLocation)]", + "aiSearchRbacAuthz": "[steps('aiAuxiliarySettings').aiSearchRbacAuthz]", + "aiSearchSubnetId": "[steps('aiAuxiliarySettings').aiSearchSubnetId]", + "aiSearchSystemIdentity": "[steps('aiAuxiliarySettings').aiSearchSystemIdentity]", + "aiUseCaseDeployment": "[steps('aiAuxiliarySettings').aiUseCaseDeployment]" }, "kind": "Subscription", "location": "[steps('basics').resourceScope.location.name]", diff --git a/fsi/solutions/generativeAi/aoaiArm.json b/fsi/solutions/generativeAi/aoaiArm.json index 8c625a03..d4d5d3ab 100644 --- a/fsi/solutions/generativeAi/aoaiArm.json +++ b/fsi/solutions/generativeAi/aoaiArm.json @@ -309,6 +309,57 @@ "No" ], "defaultValue": "No" + }, + "aiSearchSubnetId": { + "type": "string", + "metadata": { + "description": "Provide the subnet id where the Azure Open AI instance that will be connected" + }, + "defaultValue": "" + }, + "aiSearchSystemIdentity": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ] + }, + "aiSearchNwLocation": { + "type": "string", + "defaultValue": "[parameters('location')]" + }, + "aiSearchDisableNetworkAccess": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ] + }, + "aiSearchRbacAuthz": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ] + }, + "aiSearchEncryption": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ] + }, + "aiUseCaseDeployment": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ] } }, "variables": { @@ -319,10 +370,12 @@ "azureOpenAiTemplateUri": "[uri(deployment().properties.templateLink.uri, 'azureOpenAi.json')]", "rgKeyVersionTemplateUri": "[uri(deployment().properties.templateLink.uri, 'rgKey.json')]", "rgAzureOpenAiObjectIdTemplateUri": "[uri(deployment().properties.templateLink.uri, 'rgAzureAiObjectId.json')]", + "rgAzureAiSearchObjectIdTemplateUri": "[uri(deployment().properties.templateLink.uri, 'rgAzureAiObjectId.json')]", "rgRbacTemplateUri": "[uri(deployment().properties.templateLink.uri, 'rgRbac.json')]", "azureOpenAiCmkTemplateUri": "[uri(deployment().properties.templateLink.uri, 'cmkAzureOpenAi.json')]", "azureOpenAiModelTemplateUri": "[uri(deployment().properties.templateLink.uri, 'modelDeployment.json')]", - "azureOpenAiContentFilterTemplateUri": "[uri(deployment().properties.templateLink.uri, 'contentFilter.json')]" + "azureOpenAiContentFilterTemplateUri": "[uri(deployment().properties.templateLink.uri, 'contentFilter.json')]", + "azureAiSearchTemplateUri": "[uri(deployment().properties.templateLink.uri, 'azureAiSearch.json')]" }, "deploymentSuffix": "[concat('-', deployment().location, guid(parameters('prefix')))]", "deploymentNames": { @@ -331,12 +384,17 @@ "storageDeploymentName": "[take(concat(parameters('prefix'), '-sa', variables('deploymentSuffix')), 64)]", "azureOpenAiDeploymentName": "[take(concat(parameters('prefix'), '-aoa', variables('deploymentSuffix')), 64)]", "rgKeyVersionDeploymentName": "[take(concat(parameters('prefix'), '-key', variables('deploymentSuffix')), 64)]", - "rgAzureAiObjectIdDeploymentName": "[take(concat(parameters('prefix'), '-objectId', variables('deploymentSuffix')), 64)]", + "rgAzureAiObjectIdDeploymentName": "[take(concat(parameters('prefix'), '-ai-objectId', variables('deploymentSuffix')), 64)]", + "rgAzureAiSearchObjectIdDeploymentName": "[take(concat(parameters('prefix'), '-search-objectId', variables('deploymentSuffix')), 64)]", "rgRbac1DeploymentName": "[take(concat(parameters('prefix'), '-rbac1', variables('deploymentSuffix')), 64)]", "rgRbac2DeploymentName": "[take(concat(parameters('prefix'), '-rbac2', variables('deploymentSuffix')), 64)]", + "rgRbac3DeploymentName": "[take(concat(parameters('prefix'), '-rbac3', variables('deploymentSuffix')), 64)]", + "rgRbac4DeploymentName": "[take(concat(parameters('prefix'), '-rbac4', variables('deploymentSuffix')), 64)]", + "rgRbac5DeploymentName": "[take(concat(parameters('prefix'), '-rbac5', variables('deploymentSuffix')), 64)]", "azureOpenAiFinalDeploymentName": "[take(concat(parameters('prefix'), '-aoacmk', variables('deploymentSuffix')), 64)]", "azureOpenAiModelDeploymentName": "[take(concat(parameters('prefix'), '-aoaModel', variables('deploymentSuffix')), 64)]", - "azureOpenAIContentFilterDeploymentName": "[take(concat(parameters('prefix'), '-aoaContentFilter', variables('deploymentSuffix')), 64)]" + "azureOpenAIContentFilterDeploymentName": "[take(concat(parameters('prefix'), '-aoaContentFilter', variables('deploymentSuffix')), 64)]", + "azureAiSearchDeploymentName": "[take(concat(parameters('prefix'), 'aaisearch', variables('deploymentSuffix')), 64)]" }, "resourceNames": { "rgName": "[concat(parameters('prefix'), '-rg-', parameters('location'))]" @@ -561,6 +619,59 @@ } } }, + // Deploying Azure AI Search + { + "condition": "[equals(parameters('aiUseCaseDeployment'), 'Yes')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[variables('deploymentNames').azureAiSearchDeploymentName]", + "location": "[parameters('location')]", + "dependsOn": [ + "[concat('Microsoft.Resources/deployments/', variables('deploymentNames').keyVaultDeploymentName)]", + "[concat('Microsoft.Resources/deployments/', variables('deploymentNames').storageDeploymentName)]", + "[concat('Microsoft.Resources/deployments/', variables('deploymentNames').azureOpenAiDeploymentName)]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "contentVersion": "1.0.0.0", + "uri": "[variables('templateUris').azureAiSearchTemplateUri]" + }, + "parameters": { + "rgName": { + "value": "[variables('resourceNames').rgName]" + }, + "location": { + "value": "[parameters('location')]" + }, + "userIdentity": { + "value": "[parameters('userIdentity')]" + }, + "aiSearchRbacAuthz": { + "value": "[parameters('aiSearchRbacAuthz')]" + }, + "aiSearchSubnetId": { + "value": "[parameters('aiSearchSubnetId')]" + }, + "prefix": { + "value": "[parameters('prefix')]" + }, + "aiSearchNwLocation": { + "value": "[parameters('aiNwLocation')]" + }, + "aiSearchDisableNetworkAccess": { + "value": "[parameters('aiSearchDisableNetworkAccess')]" + }, + "aiSearchSystemIdentity": { + "value": "[parameters('aiSearchSystemIdentity')]" + }, + "aiSearchEncryption": { + "value": "[parameters('aiSearchEncryption')]" + } + } + } + }, + // Retrieving objectId of the AOAI System Identity { "condition": "[equals(parameters('aiSystemIdentity'), 'Yes')]", "type": "Microsoft.Resources/deployments", @@ -586,6 +697,34 @@ } } }, + // Retrieving objectId of the AI Search System Identity + { + "condition": "[and(equals(parameters('aiSearchSystemIdentity'), 'Yes'), equals(parameters('aiSystemIdentity'), 'Yes'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[variables('deploymentNames').rgAzureAiSearchObjectIdDeploymentName]", + "resourceGroup": "[variables('resourceNames').rgName]", + "dependsOn": [ + "[concat('Microsoft.Resources/deployments/', variables('deploymentNames').azureOpenAiDeploymentName)]", + "[concat('Microsoft.Resources/deployments/', variables('deploymentNames').azureAiSearchDeploymentName)]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "contentVersion": "1.0.0.0", + "uri": "[variables('templateUris').rgAzureAiSearchObjectIdTemplateUri]" + }, + "parameters": { + "prefix": { + "value": "[parameters('prefix')]" + }, + "location": { + "value": "[parameters('location')]" + } + } + } + }, + // Consider to remove this deployment { "condition": "[equals(parameters('aiSystemIdentity'), 'Yes')]", "type": "Microsoft.Resources/deployments", @@ -614,6 +753,7 @@ } } }, + // Creating Role Assignment for AOAI on Key Vault for Key Vault Crypto Service Encryption User role { "condition": "[equals(parameters('aiSystemIdentity'), 'Yes')]", "type": "Microsoft.Resources/deployments", @@ -642,6 +782,96 @@ } } }, + // Creating Role Assignment for AOAI on AI Search using Search Index Data Reader role + { + "condition": "[and(equals(parameters('aiSearchSystemIdentity'), 'Yes'), equals(parameters('aiSystemIdentity'), 'Yes'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[variables('deploymentNames').rgRbac3DeploymentName]", + "resourceGroup": "[variables('resourceNames').rgName]", + "dependsOn": [ + "[concat('Microsoft.Resources/deployments/', variables('deploymentNames').rgAzureAiObjectIdDeploymentName)]", + "[concat('Microsoft.Resources/deployments/', variables('deploymentNames').rgAzureAiSearchObjectIdDeploymentName)]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "contentVersion": "1.0.0.0", + "uri": "[variables('templateUris').rgRbacTemplateUri]" + }, + "parameters": { + "roleDefinitionId": { + "value": "1407120a-92aa-4202-b7e9-c0e197c71c8f" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "principalId": { + "value": "[if(and(equals(parameters('aiSearchSystemIdentity'), 'Yes'), equals(parameters('aiSystemIdentity'), 'Yes')), reference(variables('deploymentNames').rgAzureAiObjectIdDeploymentName).outputs.systemIdentityId.value, '')]" + } + } + } + }, + // Creating Role Assignment for AOAI on AI Search using Search Service Contributor role + { + "condition": "[and(equals(parameters('aiSearchSystemIdentity'), 'Yes'), equals(parameters('aiSystemIdentity'), 'Yes'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[variables('deploymentNames').rgRbac4DeploymentName]", + "resourceGroup": "[variables('resourceNames').rgName]", + "dependsOn": [ + "[concat('Microsoft.Resources/deployments/', variables('deploymentNames').rgAzureAiObjectIdDeploymentName)]", + "[concat('Microsoft.Resources/deployments/', variables('deploymentNames').azureAiSearchDeploymentName)]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "contentVersion": "1.0.0.0", + "uri": "[variables('templateUris').rgRbacTemplateUri]" + }, + "parameters": { + "roleDefinitionId": { + "value": "7ca78c08-252a-4471-8644-bb5ff32d4ba0" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "principalId": { + "value": "[if(and(equals(parameters('aiSearchSystemIdentity'), 'Yes'), equals(parameters('aiSystemIdentity'), 'Yes')), reference(variables('deploymentNames').rgAzureAiSearchObjectIdDeploymentName).outputs.systemIdentityId.value, '')]" + } + } + } + }, + // Creating Role Assignment for AI Search on AOAI using Cognitive Services Open AI Contributor role + { + "condition": "[and(equals(parameters('aiSearchSystemIdentity'), 'Yes'), equals(parameters('aiSystemIdentity'), 'Yes'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[variables('deploymentNames').rgRbac5DeploymentName]", + "resourceGroup": "[variables('resourceNames').rgName]", + "dependsOn": [ + "[concat('Microsoft.Resources/deployments/', variables('deploymentNames').rgAzureAiObjectIdDeploymentName)]", + "[concat('Microsoft.Resources/deployments/', variables('deploymentNames').azureAiSearchDeploymentName)]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "contentVersion": "1.0.0.0", + "uri": "[variables('templateUris').rgRbacTemplateUri]" + }, + "parameters": { + "roleDefinitionId": { + "value": "a001fd3d-188f-4b5d-821b-7da978bf7442" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "principalId": { + "value": "[if(and(equals(parameters('aiSystemIdentity'), 'Yes'), equals(parameters('aiSearchSystemIdentity'), 'Yes')), reference(variables('deploymentNames').rgAzureAiSearchObjectIdDeploymentName).outputs.systemIdentityId.value, '')]" + } + } + } + }, { "condition": "[not(empty(parameters('aiCmkKeyName')))]", "type": "Microsoft.Resources/deployments", diff --git a/fsi/solutions/generativeAi/azureAiSearch.json b/fsi/solutions/generativeAi/azureAiSearch.json new file mode 100644 index 00000000..560da56e --- /dev/null +++ b/fsi/solutions/generativeAi/azureAiSearch.json @@ -0,0 +1,198 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "rgName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Provide the name of the resource group where the Azure Open AI instance that will be created" + } + }, + "location": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Select the location for the Azure Open AI instance that will be created" + } + }, + "prefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Provide name for the Azure Open AI instance that will be created" + } + }, + "userIdentity": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Provide the user identity (objectId) that will be assigned to the Azure Open AI instance that will be created" + } + }, + "aiSearchSubnetId": { + "type": "string", + "metadata": { + "description": "Provide the subnet id where the Azure Open AI instance that will be connected" + }, + "defaultValue": "" + }, + "aiSearchSystemIdentity": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ] + }, + "aiSearchNwLocation": { + "type": "string", + "defaultValue": "[parameters('location')]" + }, + "aiSearchDisableNetworkAccess": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ] + }, + "aiSearchRbacAuthz": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ] + }, + "aiSearchEncryption": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ] + } + }, + "variables": { + "name-compliant-azureAiSearch": "[toLower(concat(parameters('prefix'), '-', parameters('location'), '-AzAISearch'))]", + "name-compliant-azureAiSearch-pe": "[toLower(concat(parameters('prefix'), '-AzAISearch-pe'))]", + "name-compliant-azureAiSearch-asg": "[toLower(concat(parameters('prefix'), '-AzAISearch-asg'))]", + "name-compliant-storage": "[toLower(take(concat(replace(replace(parameters('prefix'), '-', ''), '_', ''), parameters('location'), uniqueString(deployment().name)), 23))]", + "aiSearchIdentity": { + "type": "SystemAssigned" + }, + "denyFwAcl": { + "defaultAction": "Deny", + "bypass": "AzureServices", + "ipRules": [], + "virtualNetworkRules": [] + } + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2022-09-01", + "name": "[parameters('rgName')]", + "location": "[parameters('location')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "azureAiSearch", + "resourceGroup": "[parameters('rgName')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/resourceGroups/', parameters('rgName'))]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2022-09-01", + "name": "[variables('name-compliant-azureAiSearch')]", + "location": "[parameters('location')]", + "identity": "[if(equals(parameters('aiSearchSystemIdentity'), 'Yes'), variables('aiSearchIdentity'), json('null'))]", + "sku": { + "name": "standard" + }, + "properties": { + "replicaCount": 1, + "partitionCount": 1, + "hostingMode": "default", + "publicNetworkAccess": "[if(equals(parameters('aiSearchDisableNetworkAccess'), 'Yes'), 'Disabled', 'Enabled')]", + "disableLocalAuth": "[if(equals(parameters('aiSearchRbacAuthz'), 'Yes'), bool('true'), bool('false'))]", + "encryptionWithCmk": { + "enforcement": "[if(equals(parameters('aiSearchEncryption'), 'Yes'), 'Enabled', 'Disabled')]" + + } + } + }, + { + "condition": "[and(equals(parameters('aiSearchDisableNetworkAccess'), 'Yes'), not(empty(parameters('aiSearchSubnetId'))))]", + "type": "Microsoft.Network/applicationSecurityGroups", + "apiVersion": "2023-04-01", + "name": "[variables('name-compliant-azureAiSearch-asg')]", + "location": "[parameters('aiSearchNwLocation')]", + "dependsOn": [ + "[concat('Microsoft.Search/searchServices/', variables('name-compliant-azureAiSearch'))]" + ], + "properties": {} + }, + { + "condition": "[and(equals(parameters('aiSearchDisableNetworkAccess'), 'Yes'), not(empty(parameters('aiSearchSubnetId'))))]", + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2021-03-01", + "name": "[variables('name-compliant-azureAiSearch-pe')]", + "location": "[parameters('aiSearchNwLocation')]", + "dependsOn": [ + "[concat('Microsoft.Search/searchServices/', variables('name-compliant-azureAiSearch'))]", + "[concat('Microsoft.Network/applicationSecurityGroups/', variables('name-compliant-azureAiSearch-asg'))]" + + ], + "properties": { + "privateLinkServiceConnections": [ + { + "name": "[variables('name-compliant-azureAiSearch')]", + "properties": { + "privateLinkServiceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('rgName'), '/providers/Microsoft.Search/searchServices/', variables('name-compliant-azureAiSearch'))]", + "groupIds": [ + "searchService" + ] + } + } + ], + "subnet": { + "id": "[parameters('aiSearchSubnetId')]" + }, + "applicationSecurityGroups": [ + { + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('rgName'), '/providers/Microsoft.Network/applicationSecurityGroups/', variables('name-compliant-azureAiSearch-asg'))]" + } + ] + } + }, + { + "condition": "[not(empty(parameters('userIdentity')))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(deployment().name)]", + "dependsOn": [ + "[concat('Microsoft.Search/searchServices/', variables('name-compliant-azureAiSearch'))]" + ], + "properties": { + "roleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "principalId": "[parameters('userIdentity')]" + } + } + ] + } + } + } + ], + "outputs": {} +} \ No newline at end of file diff --git a/fsi/solutions/generativeAi/keyVault.json b/fsi/solutions/generativeAi/keyVault.json index 015252d9..e21993a7 100644 --- a/fsi/solutions/generativeAi/keyVault.json +++ b/fsi/solutions/generativeAi/keyVault.json @@ -129,7 +129,7 @@ "name-compliant-keyvault-st-cmk-name": "[format('{0}/{1}', variables('name-compliant-keyvault'), parameters('stCmkKeyName'))]", "no-st-cmk-name": "[format('{0}/{1}', variables('name-compliant-keyvault'), 'nostcmk')]", "name-compliant-keyvault-ai-cmk-name": "[format('{0}/{1}', variables('name-compliant-keyvault'), parameters('aiCmkKeyName'))]", - "no-ai-cmk-name": "[format('{0}/{1}', variables('name-compliant-keyvault'), 'nostcmk')]", + "no-ai-cmk-name": "[format('{0}/{1}', variables('name-compliant-keyvault'), 'noaicmk')]", "denyFwAcls": { "bypass": "AzureServices", "defaultAction": "Deny", diff --git a/fsi/solutions/generativeAi/modelDeployment.json b/fsi/solutions/generativeAi/modelDeployment.json index 1c01ade6..8644f9c0 100644 --- a/fsi/solutions/generativeAi/modelDeployment.json +++ b/fsi/solutions/generativeAi/modelDeployment.json @@ -21,7 +21,9 @@ "gpt-4", "gpt-4-32k", "gpt-35-turbo", - "gpt-35-turbo-16k" + "gpt-35-turbo-16k", + "gpt-4-vision", + "text-embedding-ada-002" ] } }, @@ -29,6 +31,44 @@ "name-compliant-azureOpenAi": "[concat(parameters('prefix'), '-', parameters('location'), '-AzOpenAI')]" }, "resources": [ + { + "condition": "[equals(parameters('aiModelVersion'), 'text-embedding-ada-002')]", + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2023-05-01", + "name": "[concat(variables('name-compliant-azureOpenAi'), '/', parameters('aiModelDeploymentName'), '-', 'text-embedding-ada-002')]", + "sku": { + "name": "Standard", + "capacity": 1 + }, + "properties": { + "model": { + "format": "OpenAI", + "name": "text-embedding-ada-002", + "version": "2" + }, + "versionUpgradeOption": "OnceNewDefaultVersionAvailable", + "raiPolicyName": "Microsoft.Default" + } + }, + { + "condition": "[equals(parameters('aiModelVersion'), 'gpt-4-vision')]", + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2023-05-01", + "name": "[concat(variables('name-compliant-azureOpenAi'), '/', parameters('aiModelDeploymentName'), '-', 'gpt4-vision')]", + "sku": { + "name": "Standard", + "capacity": 1 + }, + "properties": { + "model": { + "format": "OpenAI", + "name": "gpt-4", + "version": "vision-preview" + }, + "versionUpgradeOption": "OnceNewDefaultVersionAvailable", + "raiPolicyName": "Microsoft.Default" + } + }, { "condition": "[equals(parameters('aiModelVersion'), 'gpt-4-32k')]", "type": "Microsoft.CognitiveServices/accounts/deployments", diff --git a/fsi/solutions/generativeAi/rgAzureAiSearchObjectId.json b/fsi/solutions/generativeAi/rgAzureAiSearchObjectId.json new file mode 100644 index 00000000..7aa05ce8 --- /dev/null +++ b/fsi/solutions/generativeAi/rgAzureAiSearchObjectId.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "prefix": { + "type": "string" + }, + "location": { + "type": "string" + } + }, + "variables": { + "name-compliant-azureAiSearch": "[toLower(concat(parameters('prefix'), '-', parameters('location'), '-AzAISearch'))]" + }, + "resources": [], + "outputs": { + "systemIdentityId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Search/searchServices', variables('name-compliant-azureAiSearch')), '2021-10-01', 'Full').identity.principalId]" + } + } +} \ No newline at end of file