Приложение .NET Framework Console, установленное на виртуальной машине, не может получить доступ к хранилищу ключей Azure

У меня есть консольное приложение .NET Framework 4.7.2, которое я пытаюсь настроить с помощью секретов Azure Key Vault.

Я использую app.config ConfigBuilders, чтобы включить чтение Key Vault.

<configSections>
    <section name="configBuilders" type="System.Configuration.ConfigurationBuildersSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" restartOnExternalChanges="false" requirePermission="false"/>
</configSections>
...
<configBuilders>
  <builders>
    <add name="AzureKeyVault" vaultName="key-vault-name" vaultUri="https://key-vault-name.vault.azure.net" type="Microsoft.Configuration.ConfigurationBuilders.AzureKeyVaultConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Azure, Version=1.0.0.0, Culture=neutral"/>
  </builders>
</configBuilders>
...
<connectionStrings configBuilders="AzureKeyVault">
    <add name="DBConnectionString" connectionString="CheckAzureKeyVault"/
</connectionStrings>

Это работает из Visual Studio при локальном запуске. Он также работает при развертывании на нашем тестовом экземпляре EC2 (Windows Server 2016) при запуске под учетной записью службы [с использованием встроенной проверки подлинности Active Directory], которая имеет доступ к хранилищу ключей.

Если я развертываю те же скомпилированные файлы в нашем Production EC2 (также Windows Server 2016) и запускаю его под той же учетной записью службы, я получаю следующую ошибку:

Unhandled Exception: System.TypeInitializationException: The type initializer for 'Example.Program' threw an exception. ---> System.Configuration.ConfigurationErrorsException: The configBuilder 'AzureKeyVault' failed during Initialization.: One or more errors occurred. (C:\Example.Program.exe.Config line 21) ---> System.AggregateException: One or more errors occurred. ---> Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProviderException: Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/xxxx. Exception Message: Tried the following 4 methods to get an access token, but none of them worked.
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/xxx. Exception Message: Tried to get token using Managed Service Identity. Access token could not be acquired. MSI ResponseCode: NotFound, Response: <?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
  <title>404 - Not Found</title>
 </head>
 <body>
  <h1>404 - Not Found</h1>
 </body>
</html>

Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/xxx. Exception Message: Tried to get token using Visual Studio. Access token could not be acquired. Visual Studio Token provider file not found at "C:\xxx\tokenprovider.json"
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/xxx. Exception Message: Tried to get token using Azure CLI. Access token could not be acquired. ERROR: Please run 'az login' to setup account.

Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/xxx. Exception Message: Tried to get token using Active Directory Integrated Authentication. Access token could not be acquired. Federated service at https://xxx returned error: See inner exception for detail.Inner Exception :  Response status code does not indicate success: 400 (BadRequest).

   at Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider.<GetAccessTokenAsyncImpl>d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.KeyVault.KeyVaultCredential.<PreAuthenticate>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.KeyVault.KeyVaultCredential.<ProcessHttpRequestAsync>d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at Microsoft.Azure.KeyVault.KeyVaultClient.<GetSecretsWithHttpMessagesAsync>d__66.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.KeyVault.KeyVaultClientExtensions.<GetSecretsAsync>d__50.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Configuration.ConfigurationBuilders.AzureKeyVaultConfigBuilder.<<GetAllKeys>b__17_0>d.MoveNext()
   --- End of inner exception stack trace ---
   at System.AggregateException.Handle(Func`2 predicate)
   at Microsoft.Configuration.ConfigurationBuilders.AzureKeyVaultConfigBuilder.GetAllKeys()
   at Microsoft.Configuration.ConfigurationBuilders.AzureKeyVaultConfigBuilder.Initialize(String name, NameValueCollection config)
   at System.Configuration.ConfigurationBuildersSection.CreateAndInitializeBuilderWithAssert(Type t, ProviderSettings ps)
   --- End of inner exception stack trace ---
   at System.Configuration.BaseConfigurationRecord.EvaluateOne(String[] keys, SectionInput input, Boolean isTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult)
   at System.Configuration.BaseConfigurationRecord.Evaluate(FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult, Boolean getLkg, Boolean getRuntimeObject, Object& result, Object& resultRuntimeObject)
   at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
   at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
   at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
   at System.Configuration.BaseConfigurationRecord.GetSection(String configKey)
   at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName)
   at System.Configuration.ConfigurationManager.get_AppSettings()
   at Example.Program..cctor()
   --- End of inner exception stack trace ---
   at Example.Program.Main(String[] args)

У меня возникли серьезные проблемы с определением, почему он работает на нашей виртуальной машине Dev, запускающей приложение таким же образом, но не на нашей Prod. .NET Framework 4.8 установлен на обоих, оба могут подключаться к Интернету.

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

Есть предположения?


person topher-j    schedule 25.09.2019    source источник
comment
App.config, который вы развернули в нерабочей среде, действительно содержит строку подключения? (В отличие от сообщения об ошибке)   -  person Alex    schedule 26.09.2019
comment
Эта часть сообщения об ошибке не была изменена, строка подключения отсутствует. Я не думаю, что он ему нужен, так как он работает на виртуальной машине Dev. Текущие исследования показывают, что AD DS (доменные службы Active Directory) по какой-то причине установлены на производственной виртуальной машине. Мы собираемся протестировать удаление этого, и я обновлю, если это проблема. Кажется, это какой-то неочевидный конфликт.   -  person topher-j    schedule 26.09.2019
comment
@ topher-j Есть ли обновления по этой проблеме?   -  person Tony Ju    schedule 07.10.2019
comment
Да, для этой конкретной ошибки мы смогли определить, что это запись CNAME из личного домена (домен, указанный в сообщении об ошибке Federated Service на странице xxx) в AWS ELB. Серверу, на котором работало приложение, по какой-то причине не понравилось это CNAME. Когда мы добавили запись файла hosts, отображающую домен непосредственно на контроллер домена, это сработало. Нам не удалось устранить основную причину, по которой CNAME не воспроизводился должным образом, но мы смогли обойти это с помощью записи файла hosts. Вероятно, это конкретная ошибка нашей среды, но, возможно, она кому-то поможет.   -  person topher-j    schedule 07.10.2019
comment
@ topher-j Спасибо, что поделились этим. Не могли бы вы опубликовать это как ответ? это поможет другим легко увидеть это.   -  person Tom Luo    schedule 09.10.2019


Ответы (1)


Для этой конкретной ошибки мы смогли определить, что это запись CNAME из личного домена (домен, указанный в сообщении об ошибке «Federated Service at xxx») в AWS ELB. Серверу, на котором работало приложение, по какой-то причине не понравилось это CNAME. Когда мы добавили запись файла hosts, отображающую домен непосредственно на контроллер домена, это сработало. Мы не смогли решить основную причину, по которой CNAME пока не воспроизводился должным образом, но мы смогли обойти это с помощью записи в файле hosts. Вероятно, это конкретная ошибка нашей среды, но, возможно, она кому-то поможет.

person topher-j    schedule 14.10.2019