Создание ресурса иммерсивного средства чтения и настройка проверки подлинности Azure Active Directory

В этой статье представлен скрипт, который создаст ресурс иммерсивного средства чтения и настроит проверку подлинности Azure Active Directory (AAD). Каждый раз при создании ресурса иммерсивного средства чтения — с помощью этого скрипта или на портал — его также необходимо настраивать с помощью разрешений AAD. В этом вам поможет скрипт.

Этот сценарий предназначен для создания и настройки всех необходимых ресурсов иммерсивного средства чтения и AAD за один шаг. Тем не менее можно также просто настроить проверку подлинности AAD для существующего ресурса иммерсивного средства чтения, если, например, вы уже создали его на портале Azure.

Для некоторых клиентов может потребоваться создать несколько ресурсов иммерсивного средства чтения отдельно для среды разработки и рабочей среды или, возможно, для нескольких различных регионов, в которых развернута служба. В этих случаях можно не один раз возвращаться к использованию скрипта для создания различных ресурсов иммерсивного средства чтения, а также их настройки с помощью разрешений AAD.

Скрипт является гибким. Сначала он выполнит поиск существующих ресурсов иммерсивного средства чтения и AAD в вашей подписке и создаст их только в том случае, если их еще не существует. Если вы создаете ресурс иммерсивного средства чтения впервые, скрипт сделает все необходимое. Если вы хотите использовать его только для настройки AAD для существующего ресурса иммерсивного средства чтения, созданного на портале, он также это сделает. Его также можно использовать для создания и настройки нескольких ресурсов иммерсивного средства чтения.

Настройка среды PowerShell

  1. Для начала откройте Azure Cloud Shell. Проверьте, задано ли для Cloud Shell значение PowerShell в раскрывающемся списке в верхнем левом углу или путем ввода pwsh.

  2. Скопируйте следующий фрагмент кода и вставьте его в оболочку.

    function Create-ImmersiveReaderResource(
        [Parameter(Mandatory=$true, Position=0)] [String] $SubscriptionName,
        [Parameter(Mandatory=$true)] [String] $ResourceName,
        [Parameter(Mandatory=$true)] [String] $ResourceSubdomain,
        [Parameter(Mandatory=$true)] [String] $ResourceSKU,
        [Parameter(Mandatory=$true)] [String] $ResourceLocation,
        [Parameter(Mandatory=$true)] [String] $ResourceGroupName,
        [Parameter(Mandatory=$true)] [String] $ResourceGroupLocation,
        [Parameter(Mandatory=$true)] [String] $AADAppDisplayName,
        [Parameter(Mandatory=$true)] [String] $AADAppIdentifierUri,
        [Parameter(Mandatory=$true)] [String] $AADAppClientSecretExpiration
    )
    {
        $unused = ''
        if (-not [System.Uri]::TryCreate($AADAppIdentifierUri, [System.UriKind]::Absolute, [ref] $unused)) {
            throw "Error: AADAppIdentifierUri must be a valid URI"
        }
    
        Write-Host "Setting the active subscription to '$SubscriptionName'"
        $subscriptionExists = Get-AzSubscription -SubscriptionName $SubscriptionName
        if (-not $subscriptionExists) {
            throw "Error: Subscription does not exist"
        }
        az account set --subscription $SubscriptionName
    
        $resourceGroupExists = az group exists --name $ResourceGroupName
        if ($resourceGroupExists -eq "false") {
            Write-Host "Resource group does not exist. Creating resource group"
            $groupResult = az group create --name $ResourceGroupName --location $ResourceGroupLocation
            if (-not $groupResult) {
                throw "Error: Failed to create resource group"
            }
            Write-Host "Resource group created successfully"
        }
    
        # Create an Immersive Reader resource if it doesn't already exist
        $resourceId = az cognitiveservices account show --resource-group $ResourceGroupName --name $ResourceName --query "id" -o tsv
        if (-not $resourceId) {
            Write-Host "Creating the new Immersive Reader resource '$ResourceName' (SKU '$ResourceSKU') in '$ResourceLocation' with subdomain '$ResourceSubdomain'"
            $resourceId = az cognitiveservices account create `
                            --name $ResourceName `
                            --resource-group $ResourceGroupName `
                            --kind ImmersiveReader `
                            --sku $ResourceSKU `
                            --location $ResourceLocation `
                            --custom-domain $ResourceSubdomain `
                            --query "id" `
                            -o tsv
    
            if (-not $resourceId) {
                throw "Error: Failed to create Immersive Reader resource"
            }
            Write-Host "Immersive Reader resource created successfully"
        }
    
        # Create an Azure Active Directory app if it doesn't already exist
        $clientId = az ad app show --id $AADAppIdentifierUri --query "appId" -o tsv
        if (-not $clientId) {
            Write-Host "Creating new Azure Active Directory app"
            $clientId = az ad app create --display-name $AADAppDisplayName --identifier-uris $AADAppIdentifierUri --query "appId" -o tsv
            if (-not $clientId) {
                throw "Error: Failed to create Azure Active Directory application"
            }
            Write-Host "Azure Active Directory application created successfully."
    
            $clientSecret = az ad app credential reset --id $clientId --end-date "$AADAppClientSecretExpiration" --query "password" | % { $_.Trim('"') }
            if (-not $clientSecret) {
                throw "Error: Failed to create Azure Active Directory application client secret"
            }
            Write-Host "Azure Active Directory application client secret created successfully."
    
            Write-Host "NOTE: To manage your Active Directory application client secrets after this Immersive Reader Resource has been created please visit https://portal.azure.com and go to Home -> Azure Active Directory -> App Registrations -> (your app) '$AADAppDisplayName' -> Certificates and Secrets blade -> Client Secrets section" -ForegroundColor Yellow
        }
    
        # Create a service principal if it doesn't already exist
        $principalId = az ad sp show --id $AADAppIdentifierUri --query "id" -o tsv
        if (-not $principalId) {
            Write-Host "Creating new service principal"
            az ad sp create --id $clientId | Out-Null
            $principalId = az ad sp show --id $AADAppIdentifierUri --query "id" -o tsv
    
            if (-not $principalId) {
                throw "Error: Failed to create new service principal"
            }
            Write-Host "New service principal created successfully"
    
            # Sleep for 5 seconds to allow the new service principal to propagate
            Write-Host "Sleeping for 5 seconds"
            Start-Sleep -Seconds 5
        }
    
        Write-Host "Granting service principal access to the newly created Immersive Reader resource"
        $accessResult = az role assignment create --assignee $principalId --scope $resourceId --role "Cognitive Services Immersive Reader User"
        if (-not $accessResult) {
            throw "Error: Failed to grant service principal access"
        }
        Write-Host "Service principal access granted successfully"
    
        # Grab the tenant ID, which is needed when obtaining an Azure AD token
        $tenantId = az account show --query "tenantId" -o tsv
    
        # Collect the information needed to obtain an Azure AD token into one object
        $result = @{}
        $result.TenantId = $tenantId
        $result.ClientId = $clientId
        $result.ClientSecret = $clientSecret
        $result.Subdomain = $ResourceSubdomain
    
        Write-Host "`nSuccess! " -ForegroundColor Green -NoNewline
        Write-Host "Save the following JSON object to a text file for future reference."
        Write-Host "*****"
        if($clientSecret -ne $null) {
    
            Write-Host "This function has created a client secret (password) for you. This secret is used when calling Azure Active Directory to fetch access tokens."
            Write-Host "This is the only time you will ever see the client secret for your Azure Active Directory application, so save it now." -ForegroundColor Yellow
        }
        else{
            Write-Host "You will need to retrieve the ClientSecret from your original run of this function that created it. If you don't have it, you will need to go create a new client secret for your Azure Active Directory application. Please visit https://portal.azure.com and go to Home -> Azure Active Directory -> App Registrations -> (your app) '$AADAppDisplayName' -> Certificates and Secrets blade -> Client Secrets section." -ForegroundColor Yellow
        }
        Write-Host "*****`n"
        Write-Output (ConvertTo-Json $result)
    }
    
  3. Выполните функцию Create-ImmersiveReaderResource, указав вместо заполнителей <PARAMETER_VALUES> ниже соответствующие собственные значения.

    Create-ImmersiveReaderResource -SubscriptionName '<SUBSCRIPTION_NAME>' -ResourceName '<RESOURCE_NAME>' -ResourceSubdomain '<RESOURCE_SUBDOMAIN>' -ResourceSKU '<RESOURCE_SKU>' -ResourceLocation '<RESOURCE_LOCATION>' -ResourceGroupName '<RESOURCE_GROUP_NAME>' -ResourceGroupLocation '<RESOURCE_GROUP_LOCATION>' -AADAppDisplayName '<AAD_APP_DISPLAY_NAME>' -AADAppIdentifierUri '<AAD_APP_IDENTIFIER_URI>' -AADAppClientSecretExpiration '<AAD_APP_CLIENT_SECRET_EXPIRATION>'
    

    Полная команда будет выглядеть примерно следующим образом. Здесь для ясности мы поместили каждый параметр в отдельной строке, чтобы команда была видна целиком. Не следует копировать или использовать эту команду в том виде, в котором она здесь представлена. Скопируйте и используйте команду, приведенную выше, с собственными значениями. В этом примере вместо заполнителя <PARAMETER_VALUES> использованы фиктивные значения. Ваши значения будут отличаться, так как вы будете использовать для них собственные имена.

    Create-ImmersiveReaderResource
        -SubscriptionName 'MyOrganizationSubscriptionName'
        -ResourceName 'MyOrganizationImmersiveReader'
        -ResourceSubdomain 'MyOrganizationImmersiveReader'
        -ResourceSKU 'S0'
        -ResourceLocation 'westus2'
        -ResourceGroupName 'MyResourceGroupName'
        -ResourceGroupLocation 'westus2'
        -AADAppDisplayName 'MyOrganizationImmersiveReaderAADApp'
        -AADAppIdentifierUri 'api://MyOrganizationImmersiveReaderAADApp'
        -AADAppClientSecretExpiration '2021-12-31'
    
    Параметр Комментарии
    Параметр SubscriptionName Имя подписки Azure, которая будет использоваться для вашего ресурса иммерсивного средства чтения. Для создания ресурса необходимо иметь подписку.
    ResourceName Должен содержать буквы и цифры. Может также содержать "-", если он не является первым или последним символом. Длина не может превышать 63 символов.
    ResourceSubdomain Для ресурса иммерсивного средства чтения требуется пользовательский поддомен. Поддомен используется пакетом SDK при вызове службы иммерсивного средства чтения для запуска средства чтения. Поддомен должен быть глобально уникальным. Поддомен должен содержать буквы и цифры. Может также содержать "-", если он не является первым или последним символом. Длина не может превышать 63 символов. Этот параметр является необязательным, если ресурс уже существует.
    ResourceSKU Доступные варианты: S0 (стандартный уровень) или S1 (образование/некоммерческие организации). Дополнительные сведения обо всех доступных номерах SKU см. на странице цен на Cognitive Services. Этот параметр является необязательным, если ресурс уже существует.
    ResourceLocation Параметры: australiaeast, brazilsouth, canadacentral, centralindia, centralus, eastasia, eastus, eastus2, francecentral, germanywestcentral, japaneast, japanwest, jioindiawest, koreacentral, northcentralus, northeurope, norwayeast, southafricanorth, southcentralus, southeastasia, swedencentral, switzerlandnorth, switzerlandwest, uaenorth, uksouth, westcentralus, westeurope, westus, westus2, westus3. Этот параметр является необязательным, если ресурс уже существует.
    ResourceGroupName Ресурсы создаются в группах ресурсов в рамках подписок. Укажите имя существующей группы ресурсов. Если группа ресурсов еще не существует, будет создана новая группа ресурсов с таким именем.
    ResourceGroupLocation Если группа ресурсов не существует, необходимо указать расположение, в котором она будет создана. Выполните az account list-locations для получения списка расположений. Используйте свойство Имя (без пробелов) возвращаемого результата. Этот параметр является необязательным, если группа ресурсов уже существует.
    AADAppDisplayName Отображаемое имя приложения Azure Active Directory. Если существующее приложение AAD не найдено, будет создано новое приложение с таким именем. Этот параметр является необязательным, если приложение AAD уже существует.
    AADAppIdentifierUri Универсальный код ресурса (URI) для приложения AAD. Если существующее приложение AAD не найдено, будет создано новое приложение с таким универсальным кодом ресурса (URI). Например, api://MyOrganizationImmersiveReaderAADApp. Здесь мы используем префикс api:// схемы URI Azure AD по умолчанию для совместимости с политикой Azure AD, использующей проверенные домены.
    AADAppClientSecretExpiration Дата или дата и время, после наступления которых истекает срок действия секрета клиента приложения AAD (например, 2020-12-31T11:59:59+00:00 или 2020-12-31). Эта функция создаст для вас секрет клиента. Для управления секретами клиента приложения AAD после создания этого ресурса зайдите на страницу https://portal.azure.com и перейдите в раздел "Главная" —> Azure Active Directory —> "Регистрация приложений" —> (ваше приложение) [AADAppDisplayName] —> колонка "Сертификаты и секреты" —> раздел "Секреты клиента" (как показано на снимке экрана "Управление секретами приложения AAD" ниже).

    Управление секретами приложения AAD

    Колонка

  4. Скопируйте выходные данные JSON в текстовый файл для последующего использования. Полученный результат должен выглядеть примерно так:

    {
      "TenantId": "...",
      "ClientId": "...",
      "ClientSecret": "...",
      "Subdomain": "..."
    }
    

Дальнейшие действия