Доступ к хранилищу ключей Azure из пакетной службы Azure

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

Однако я продолжаю сталкиваться с исключением:

Сообщение об исключении: проверено 1 сертификат (а). Не удалось получить токен доступа.

Исключение для сертификата №1 с отпечатком MY-THUMBPRINT: набор ключей не существует

До сих пор я следовал инструкциям, изложенным здесь: https://docs.microsoft.com/en-us/azure/key-vault/service-to-service-authentication

В статье описывается сценарий пакетной службы Azure и указывается, что мне следует использовать субъект-службу. Я хотел бы убедиться, что в системе управления версиями нет секретов или ключей, поэтому я использую первый метод сертификата в локальном хранилище ключей для входа в Azure AD.

Выполнение всего перечисленного ниже локально в качестве исполняемого файла работает нормально, но не выполняется при запуске на узле пула пакетной службы Azure.

На данный момент я сделал следующие шаги:

  1. Создайте субъект-службу и связанный сертификат в хранилище ключей: az ad sp create-for-rbac --name myserviceprincipal --create-cert --cert mycertname --keyvault mykeyvaultname. Сохраните идентификатор приложения-участника-службы и идентификатор клиента для использования в AzureServicesAuthConnectionString.

  2. Создайте политику доступа к хранилищу ключей для созданного субъекта-службы (выполняется в пользовательском интерфейсе портала Azure).

  3. Загрузите созданный сертификат в формате PFX / PEM (выполняется в пользовательском интерфейсе портала Azure).

  4. Обеспечение пароля PFX в сертификате (я делаю это, поскольку для загрузки сертификата в пакет Azure на шаге 6 требуется связанный пароль): https://coombes.nz/blog/azure-keyvault-export-certificate/

# Replace these variables with your own values
$vaultName = "YOUR-KEYVAULT-NAME"
$certificateName = "YOUR-CERTIFICATE-NAME"
$pfxPath = [Environment]::GetFolderPath("Desktop") + "\$certificateName.pfx"
$password = "YOUR-CERTIFICATE-PASSWORD"

$pfxSecret = Get-AzureKeyVaultSecret -VaultName $vaultName -Name $certificateName
$pfxUnprotectedBytes = [Convert]::FromBase64String($pfxSecret.SecretValueText)
$pfx = New-Object Security.Cryptography.X509Certificates.X509Certificate2
$pfx.Import($pfxUnprotectedBytes, $null, [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
$pfxProtectedBytes = $pfx.Export([Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12, $password)
[IO.File]::WriteAllBytes($pfxPath, $pfxProtectedBytes)
  1. Установка сертификата локально в хранилище LocalMachine моего компьютера (для локального тестирования).

  2. Отправка сертификата в пакетную службу Azure (с помощью загрузки пользовательского интерфейса портала Azure).

  3. Связывание сертификата с соответствующим пулом узлов и перезагрузка узлов (пока используется пользовательский интерфейс портала Azure).

Пакет моего приложения, работающий в пакетной службе Azure, представляет собой простой исполняемый файл консоли. Для AzureServicesAuthConnectionString установлено значение RunAs=App;AppId={AppId};TenantId={TenantId};CertificateThumbprint={Thumbprint};CertificateStoreLocation={LocalMachine}, а оставшийся код хранилища ключей для получения секрета выглядит так:

Environment.SetEnvironmentVariable("AzureServicesAuthConnectionString", "RunAs=App;AppId=<MY-APP-ID>;TenantId=<MY-TENANT>;CertificateThumbprint=<MY-THUMBPRINT>;CertificateStoreLocation=LocalMachine");

AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(Environment.GetEnvironmentVariable("AzureServicesAuthConnectionString"));
KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync("<MY-SECRET>").ConfigureAwait(false);
var message = secret.Value;
Console.WriteLine(message);

Локально все работает нормально, но не работает на удаленном узле. Я могу подключиться к узлу пакетной службы Azure по протоколу RDP и увидеть, что сертификат был установлен для локального компьютера.

Мне интересно, как исправить мою ошибку, или если мои шаги в чем-то неправильны?


person apleroy    schedule 25.09.2019    source источник
comment
Быстрый поиск сообщения об ошибке в Google может предположить, что с сертификатом не связан соответствующий закрытый ключ? Проверьте эту статью: blogs.msdn.microsoft.com/dsnotes/2015/08/13/   -  person David C    schedule 25.09.2019


Ответы (2)


В дополнение к вышесказанному я выполнил инструкции из статьи Сэма Когана здесь: https://samcogan.com/secure-credential-access-with-azure-batch-and-keyvault/

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

Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProviderException: Parameters: Connection String: RunAs=App;AppId=<My Service Principal ID>;TenantId=<My Tenant ID>;CertificateThumbprint=<My cert thumbprint>;CertificateStoreLocation=LocalMachine, Resource: https://vault.azure.net, Authority: https://login.windows.net/<My Tenant ID>. Exception Message: Tried 1 certificate(s). Access token could not be acquired.
Exception for cert #1 with thumbprint <My cert thumbprint>: Keyset does not exist

Мои шаги по воспроизведению:

  1. Создайте сертификат (я добавил часть -a sha256 -len 2048, поскольку та же ошибка была описана и устранена здесь: Как пройти аутентификацию с помощью Key Vault из Azure Batch)
C:\Program Files (x86)\Windows Kits\10\bin\x64> .\makecert.exe -sv batchcertificate6.pvk -n "cn=andybatch6.cert.mydomain.org" batchcertificate6.cer -r -pe -a sha256 -len 2048
  1. Преобразуйте сертификат на шаге 1 в формат PFX:
C:\Program Files (x86)\Windows Kits\10\bin\x64> .\pvk2pfx.exe -pvk batchcertificate6.pvk -spc batchcertificate6.cer -pfx batchcertificate7.pfx -po <MyPassword>  -pi <MyPassword>  
  1. Создайте приложение ActiveDirectory и субъект-службу, а затем свяжите и загрузите созданный сертификат:
#Point the script at the cer file you created 

$cerCertificateFilePath = 'C:\Program Files (x86)\Windows Kits\10\bin\x64\batchcertificate6.cer' 
$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 
$cer.Import($cerCertificateFilePath)

#Load the certificate into memory 
$credValue = [System.Convert]::ToBase64String($cer.GetRawCertData()) 

#Create a new AAD application that uses this certifcate 
$newADApplication = New-AzureRmADApplication -DisplayName "<My display name>" -HomePage "<my url>" -IdentifierUris " <my url>" -certValue $credValue 

#Create new AAD service principle that uses this application 
$newAzureAdPrincipal = New-AzureRmADServicePrincipal -ApplicationId $newADApplication.ApplicationId
  1. Предоставьте доступ к хранилищу ключей для субъекта-службы (я добавил дополнительные разрешения в пользовательский интерфейс, но также запустил это через командную строку):
Set-AzureRmKeyVaultAccessPolicy -VaultName 'myvaultname' -ServicePrincipalName '<my url>' -PermissionsToSecrets 'Get'
  1. Загрузите сертификат (pfx) в пакетную службу Azure через портал. Свяжите его с моим пулом узлов как LocalMachine и перезагрузите узлы. Запустите приложение со строкой подключения, например:
Environment.SetEnvironmentVariable("AzureServicesAuthConnectionString",
                    "RunAs=App;" +
                    "AppId=<the app id of my active directory app registration> ;" +
                    "TenantId=<my subscription tenant id>;" +
                    "CertificateThumbprint=<the thumbprint of my cert>;" +
                    "CertificateStoreLocation=LocalMachine");

                AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(Environment.GetEnvironmentVariable("AzureServicesAuthConnectionString"));
                KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
                var secret = await keyVaultClient.GetSecretAsync("https://<my vault name>.vault.azure.net/secrets/<secret name>/<secret id>")
                        .ConfigureAwait(false);
                message = secret.Value;
                Console.WriteLine(message);

Мой код работает с установленным сертификатом локально, используя указанную выше строку подключения, но имеет вышеупомянутое исключение при работе в пакетной службе Azure.

person apleroy    schedule 29.09.2019

Чтобы получить доступ к сертификату, он должен быть связан и установлен для «Текущего пользователя». Может быть, у LocalMachine нет соответствующего уровня разрешений?

В пакетной службе Azure убедитесь, что загруженный сертификат связан с:

Имя магазина: «Мой» Расположение магазина: «Текущий пользователь»

Это сообщение было полезным: https://github.com/nabhishek/customactivity_sample/tree/linkedservice

Как было это сообщение: X509Certificate - Keyset не существует

Строка подключения в C # exe выглядит так:

Environment.SetEnvironmentVariable("AzureServicesAuthConnectionString",
                    "RunAs=App;" +
                    "AppId=<the app id of my active directory app registration> ;" +
                    "TenantId=<my subscription tenant id>;" +
                    "CertificateThumbprint=<the thumbprint of my cert>;" +
                    "CertificateStoreLocation=CurrentUser");

                AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(Environment.GetEnvironmentVariable("AzureServicesAuthConnectionString"));
                KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
                var secret = await keyVaultClient.GetSecretAsync("https://<my vault name>.vault.azure.net/secrets/<secret name>/<secret id>")
                        .ConfigureAwait(false);
                message = secret.Value;
                Console.WriteLine(message);
person apleroy    schedule 29.09.2019