Azure function App - Error building configuration in an external startup class.

David M 236 Reputation points
2025-06-03T07:21:06.93+00:00

Bonjour,

J'ai un service fonction App (qui utilise des variables stockées dans un Key Vault) qui fonctionnait très bien depuis un moment.

Seulement, contrairement à d'autres de mes services Function App, les URL de fonctions ne sont pas protégées par une clé (url?code=4cDlZ6AgFK9c...)

J'ai voulu changer le paramétrage pour essayer de les passer en isolated (un message me le conseillait "Update your function app to the isolated worker model for continued support. The in-process model will be retired starting November 10, 2026."). J'ai aussi monté les versions de DOT NET (6=>8) et supprimé l'identité.
Ce qui a fait que mon service ne fonctionnait plus. Les fonctions ne se listaient même plus.

J'ai réussi à refaire le lien avec Keyvault et remis le paramétrage initial.

Mais j'ai toujours ce message d'erreur persistent après redémarrage du service "Error building configuration in an external startup class."
Je ne comprend pas pourquoi, mon paramétrage est exactement le même qu'avant.

Voici le message d'erreur complet:

Microsoft.Azure.WebJobs.Script.ExternalStartupException : Error building configuration in an external startup class. ---> 
Azure.Identity.CredentialUnavailableException : DefaultAzureCredential failed to retrieve a token from the included credentials. See the troubleshooting guide for more information. 
https://aka.ms/azsdk/net/identity/defaultazurecredential/troubleshoot - EnvironmentCredential authentication unavailable. Environment variables are not fully configured. 
See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/environmentcredential/troubleshoot - ManagedIdentityCredential authentication unavailable. 
Multiple attempts failed to obtain a token from the managed identity endpoint. 
- Visual Studio Token provider can't be accessed at D:\DWASFiles\Sites\ubysol-dev-scheduler-azf\LocalAppData\.IdentityService\AzureServiceAuth\tokenprovider.json 
- Stored credentials not found. Need to authenticate user in VSCode Azure Account. See the troubleshooting guide for more information. 
https://aka.ms/azsdk/net/identity/vscodecredential/troubleshoot - Azure CLI not installed - Az.Account module >= 2.2.0 is not installed. ---> 
System.AggregateException : Multiple exceptions were encountered while attempting to authenticate. (EnvironmentCredential authentication unavailable. 
Environment variables are not fully configured. See the troubleshooting guide for more information. 
https://aka.ms/azsdk/net/identity/environmentcredential/troubleshoot) (ManagedIdentityCredential authentication unavailable. 
Multiple attempts failed to obtain a token from the managed identity endpoint.) 
(Visual Studio Token provider can't be accessed at D:\DWASFiles\Sites\ubysol-dev-scheduler-azf\LocalAppData\.IdentityService\AzureServiceAuth\tokenprovider.json) 
(Stored credentials not found. Need to authenticate user in VSCode Azure Account. See the troubleshooting guide for more information. 
https://aka.ms/azsdk/net/identity/vscodecredential/troubleshoot) (Azure CLI not installed) (Az.Account module >= 2.2.0 is not installed.) ---> 
EnvironmentCredential authentication unavailable. Environment variables are not fully configured. See the troubleshooting guide for more information. 
https://aka.ms/azsdk/net/identity/environmentcredential/troubleshoot ---> (Inner Exception #0) 
Azure.Identity.CredentialUnavailableException : EnvironmentCredential authentication unavailable. Environment variables are not fully configured. 
See the troubleshooting guide for more information. 
https://aka.ms/azsdk/net/identity/environmentcredential/troubleshoot at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex,String additionalMessage) 
at async Azure.Identity.EnvironmentCredential.GetTokenImplAsync(Boolean async,TokenRequestContext requestContext,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Identity.EnvironmentCredential.GetTokenAsync(TokenRequestContext requestContext,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Identity.DefaultAzureCredential.GetTokenFromSourcesAsync(TokenCredential[] sources,TokenRequestContext requestContext,Boolean 
async,CancellationToken cancellationToken)<--- ---> (Inner Exception #1) Azure.Identity.CredentialUnavailableException : 
ManagedIdentityCredential authentication unavailable. Multiple attempts failed to obtain a token from the managed identity endpoint. ---> 
System.AggregateException : Retry failed after 4 tries. Retry settings can be adjusted in ClientOptions.Retry. 
(An attempt was made to access a socket in a way forbidden by its access permissions. (169.254.169.254:80)) (An attempt was made to access a socket in a way forbidden 
by its access permissions. (169.254.169.254:80)) (An attempt was made to access a socket in a way forbidden by its access permissions. (169.254.169.254:80)) 
(An attempt was made to access a socket in a way forbidden by its access permissions. (169.254.169.254:80)) ---> 
An attempt was made to access a socket in a way forbidden by its access permissions. (169.254.169.254:80) ---> 
An attempt was made to access a socket in a way forbidden by its access permissions. (169.254.169.254:80) ---> 
An attempt was made to access a socket in a way forbidden by its access permissions. at async Azure.Core.Pipeline.RetryPolicy.ProcessAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Identity.ManagedIdentitySource.AuthenticateAsync(Boolean async,TokenRequestContext 
context,CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Identity.ImdsManagedIdentitySource.AuthenticateAsync(Boolean async,TokenRequestContext context,CancellationToken cancellationToken) ---> 
(Inner Exception #0) Azure.RequestFailedException : An attempt was made to access a socket in a way forbidden by its access permissions. 
(169.254.169.254:80) ---> System.Net.Http.HttpRequestException : An attempt was made to access a socket in a way forbidden by its access permissions. (169.254.169.254:80) ---> 
System.Net.Sockets.SocketException : An attempt was made to access a socket in a way forbidden by its access permissions. 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host,Int32 port,HttpRequestMessage 
initialRequest,Boolean async,CancellationToken cancellationToken) End of inner exception at async System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host,Int32 port,
HttpRequestMessage initialRequest,Boolean async,CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at System.Threading.Tasks.ValueTask`1.get_Result() at async System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request,Boolean async,CancellationToken 
cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request,Boolean async,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync[T](??) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at System.Threading.Tasks.ValueTask`1.get_Result() at async System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request,Boolean async,CancellationToken 
cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request,Boolean async,Boolean doRequestAuth,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(??) 
End of inner exception at async Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(??) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Core.Pipeline.HttpPipelineTransportPolicy.ProcessAsync(HttpMessage message,ReadOnlyMemory`1 pipeline) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.ResponseBodyPolicy.ProcessAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.RedirectPolicy.ProcessAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.RetryPolicy.ProcessAsync(??)<--- ---> 
(Inner Exception #1) Azure.RequestFailedException : An attempt was made to access a socket in a way forbidden by its access permissions. 
(169.254.169.254:80) ---> System.Net.Http.HttpRequestException : An attempt was made to access a socket in a way forbidden by its access permissions. (169.254.169.254:80) ---> 
System.Net.Sockets.SocketException : An attempt was made to access a socket in a way forbidden by its access permissions. 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host,Int32 
port,HttpRequestMessage initialRequest,Boolean async,CancellationToken cancellationToken) End of inner exception 
at async System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host,Int32 port,HttpRequestMessage initialRequest,Boolean async,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request,Boolean async,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request,Boolean async,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync[T](??) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at System.Threading.Tasks.ValueTask`1.get_Result() at async System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request,Boolean 
async,CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request,Boolean async,Boolean doRequestAuth,CancellationToken 
cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(??) End of inner exception 
at async Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(??) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Core.Pipeline.HttpPipelineTransportPolicy.ProcessAsync(HttpMessage message,ReadOnlyMemory`1 pipeline) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.ResponseBodyPolicy.ProcessAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.RedirectPolicy.ProcessAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.RetryPolicy.ProcessAsync(??)<--- ---> 
(Inner Exception #2) Azure.RequestFailedException : An attempt was made to access a socket in a way forbidden by its access permissions. (169.254.169.254:80) ---> 
System.Net.Http.HttpRequestException : An attempt was made to access a socket in a way forbidden by its access permissions. (169.254.169.254:80) ---> 
System.Net.Sockets.SocketException : An attempt was made to access a socket in a way forbidden by its access permissions. 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host,Int32 port,HttpRequestMessage 
initialRequest,Boolean async,CancellationToken cancellationToken) End of inner exception at async System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host,Int32 port,
HttpRequestMessage initialRequest,Boolean async,CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at System.Threading.Tasks.ValueTask`1.get_Result() at async System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request,Boolean async,CancellationToken 
cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request,Boolean async,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync[T](??) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at System.Threading.Tasks.ValueTask`1.get_Result() at async System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request,Boolean async,CancellationToken 
cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request,Boolean async,Boolean doRequestAuth,CancellationToken 
cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(??) End of inner exception 
at async Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(??) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Core.Pipeline.HttpPipelineTransportPolicy.ProcessAsync(HttpMessage message,ReadOnlyMemory`1 pipeline) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.ResponseBodyPolicy.ProcessAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.RedirectPolicy.ProcessAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.RetryPolicy.ProcessAsync(??)<--- ---> 
(Inner Exception #3) Azure.RequestFailedException : An attempt was made to access a socket in a way forbidden by its access permissions. (169.254.169.254:80) ---> 
System.Net.Http.HttpRequestException : An attempt was made to access a socket in a way forbidden by its access permissions. (169.254.169.254:80) ---> 
System.Net.Sockets.SocketException : An attempt was made to access a socket in a way forbidden by its access permissions. 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host,Int32 port,HttpRequestMessage 
initialRequest,Boolean async,CancellationToken cancellationToken) End of inner exception at async System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host,Int32 
port,HttpRequestMessage initialRequest,Boolean async,CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at System.Threading.Tasks.ValueTask`1.get_Result() at async System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request,Boolean async,CancellationToken 
cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request,Boolean async,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync[T](??) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at System.Threading.Tasks.ValueTask`1.get_Result() at async System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request,Boolean async,CancellationToken 
cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.ValueTask`1.get_Result() 
at async System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request,Boolean async,Boolean doRequestAuth,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(??) End of inner exception 
at async Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(??) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Core.Pipeline.HttpPipelineTransportPolicy.ProcessAsync(HttpMessage message,ReadOnlyMemory`1 pipeline) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.ResponseBodyPolicy.ProcessAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.RedirectPolicy.ProcessAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.RetryPolicy.ProcessAsync(??)<--- End of inner exception 
at async Azure.Identity.ImdsManagedIdentitySource.AuthenticateAsync(Boolean async,TokenRequestContext context,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Identity.ManagedIdentityClient.AuthenticateAsync(Boolean async,TokenRequestContext 
context,CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Identity.ManagedIdentityCredential.GetTokenImplAsync(Boolean async,TokenRequestContext requestContext,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex,String additionalMessage) 
at async Azure.Identity.ManagedIdentityCredential.GetTokenImplAsync(Boolean async,TokenRequestContext requestContext,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Identity.ManagedIdentityCredential.GetTokenAsync(TokenRequestContext requestContext,
CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Identity.DefaultAzureCredential.
GetTokenFromSourcesAsync(TokenCredential[] sources,TokenRequestContext requestContext,Boolean async,CancellationToken cancellationToken)<--- ---> 
(Inner Exception #2) Azure.Identity.CredentialUnavailableException : Visual Studio Token provider can't be accessed 
at D:\DWASFiles\Sites\ubysol-dev-scheduler-azf\LocalAppData\.IdentityService\AzureServiceAuth\tokenprovider.json ---> 
System.IO.DirectoryNotFoundException : Could not find a part of the path 'D:\DWASFiles\Sites\ubysol-dev-scheduler-azf\LocalAppData\.IdentityService\AzureServiceAuth\tokenprovider.json'. 
at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath,FileMode mode,FileAccess access,FileShare share,FileOptions options) 
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath,FileMode mode,FileAccess access,FileShare share,FileOptions options,Int64 preallocationSize) 
at System.IO.Strategies.OSFileStreamStrategy..ctor(String path,FileMode mode,FileAccess access,FileShare share,FileOptions options,Int64 preallocationSize) 
at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path,FileMode mode,FileAccess access,FileShare share,FileOptions options,Int64 preallocationSize) 
at System.IO.Strategies.FileStreamHelpers.ChooseStrategy(FileStream fileStream,String path,FileMode mode,FileAccess access,FileShare share,Int32 bufferSize,FileOptions 
options,Int64 preallocationSize) at System.IO.StreamReader.ValidateArgsAndOpenPath(String path,Encoding encoding,Int32 bufferSize) 
at System.IO.File.InternalReadAllText(String path,Encoding encoding) at System.IO.File.ReadAllText(String path) 
at Azure.Identity.VisualStudioCredential.GetTokenProviderContent(String tokenProviderPath) End of inner exception 
at Azure.Identity.VisualStudioCredential.GetTokenProviderContent(String tokenProviderPath) at Azure.Identity.VisualStudioCredential.GetTokenProviders(String tokenProviderPath) 
at async Azure.Identity.VisualStudioCredential.GetTokenImplAsync(TokenRequestContext requestContext,Boolean async,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex,String additionalMessage) 
at async Azure.Identity.VisualStudioCredential.GetTokenImplAsync(TokenRequestContext requestContext,Boolean async,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Identity.VisualStudioCredential.GetTokenAsync(TokenRequestContext requestContext,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Identity.DefaultAzureCredential.GetTokenFromSourcesAsync(TokenCredential[] 
sources,TokenRequestContext requestContext,Boolean async,CancellationToken cancellationToken)<--- ---> (Inner Exception #3) Azure.Identity.CredentialUnavailableException : 
Stored credentials not found. Need to authenticate user in VSCode Azure Account. 
See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/vscodecredential/troubleshoot ---> 
System.InvalidOperationException : The operation completed successfully. at Azure.Identity.WindowsNativeMethods.ThrowIfFailed(Boolean isSucceeded,String methodName) 
at Azure.Identity.WindowsVisualStudioCodeAdapter.GetCredentials(String serviceName,String accountName) at Azure.Identity.VisualStudioCodeCredential.GetStoredCredentials(String 
environmentName) End of inner exception at Azure.Identity.VisualStudioCodeCredential.GetStoredCredentials(String environmentName) 
at async Azure.Identity.VisualStudioCodeCredential.GetTokenImplAsync(TokenRequestContext requestContext,Boolean async,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex,String additionalMessage) 
at async Azure.Identity.VisualStudioCodeCredential.GetTokenImplAsync(TokenRequestContext requestContext,Boolean async,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Identity.VisualStudioCodeCredential.GetTokenAsync(TokenRequestContext requestContext,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Identity.DefaultAzureCredential.GetTokenFromSourcesAsync(TokenCredential[] 
sources,TokenRequestContext requestContext,Boolean async,CancellationToken cancellationToken)<--- ---> (Inner Exception #4) Azure.Identity.CredentialUnavailableException : 
Azure CLI not installed at async Azure.Identity.AzureCliCredential.RequestCliAccessTokenAsync(Boolean async,TokenRequestContext context,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Identity.AzureCliCredential.GetTokenImplAsync(Boolean async,TokenRequestContext requestContext,
CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception 
ex,String additionalMessage) at async Azure.Identity.AzureCliCredential.GetTokenImplAsync(Boolean async,TokenRequestContext requestContext,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Identity.AzureCliCredential.GetTokenAsync(TokenRequestContext requestContext,CancellationToken 
cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Identity.DefaultAzureCredential.GetTokenFromSourcesAsync(TokenCredential[] 
sources,TokenRequestContext requestContext,Boolean async,CancellationToken cancellationToken)<--- ---> (Inner Exception #5) Azure.Identity.CredentialUnavailableException : 
Az.Account module >= 2.2.0 is not installed. at Azure.Identity.AzurePowerShellCredential.CheckForErrors(String output) 
at async Azure.Identity.AzurePowerShellCredential.RequestAzurePowerShellAccessTokenAsync(Boolean async,TokenRequestContext context,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Identity.AzurePowerShellCredential.GetTokenImplAsync(Boolean async,TokenRequestContext 
requestContext,CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex,String additionalMessage) 
at async Azure.Identity.AzurePowerShellCredential.GetTokenImplAsync(Boolean async,TokenRequestContext requestContext,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Identity.AzurePowerShellCredential.GetTokenAsync(TokenRequestContext requestContext,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Identity.DefaultAzureCredential.GetTokenFromSourcesAsync(TokenCredential[] 
sources,TokenRequestContext requestContext,Boolean async,CancellationToken cancellationToken)<--- End of inner exception 
at async Azure.Identity.DefaultAzureCredential.GetTokenFromSourcesAsync(TokenCredential[] sources,TokenRequestContext requestContext,Boolean async,CancellationToken 
cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Identity.DefaultAzureCredential.GetTokenImplAsync(Boolean async,TokenRequestContext requestContext,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex,String additionalMessage) 
at async Azure.Identity.DefaultAzureCredential.GetTokenImplAsync(Boolean async,TokenRequestContext requestContext,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Identity.DefaultAzureCredential.GetTokenAsync(TokenRequestContext requestContext,CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Security.KeyVault.ChallengeBasedAuthenticationPolicy.AuthenticateRequestAsync(HttpMessage message,Boolean async) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Security.KeyVault.ChallengeBasedAuthenticationPolicy.ProcessCoreAsync(HttpMessage message,ReadOnlyMemory`1 pipeline,Boolean async) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.RedirectPolicy.ProcessAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.RetryPolicy.ProcessAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.RetryPolicy.ProcessAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Core.Pipeline.HttpPipeline.SendRequestAsync(Request request,CancellationToken cancellationToken) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Security.KeyVault.KeyVaultPipeline.SendRequestAsync(??) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at async Azure.Security.KeyVault.KeyVaultPipeline.GetPageAsync[T](Uri firstPageUri,String nextLink,Func`1 
itemFactory,String operationName,CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Core.PageResponseEnumerator.FuncAsyncPageable`1.AsPages[T](String continuationToken,Nullable`1 pageSizeHint) 
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1.ThrowForFailedGetResult(Int16 token) 
at async Azure.Core.PageResponseEnumerator.FuncAsyncPageable`1.AsPages[T](String continuationToken,Nullable`1 pageSizeHint) 
at async Azure.AsyncPageable`1.GetAsyncEnumerator[T](CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.AsyncPageable`1.GetAsyncEnumerator[T](CancellationToken cancellationToken) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1.ThrowForFailedGetResult(Int16 token) 
at async Azure.AsyncPageable`1.GetAsyncEnumerator[T](CancellationToken cancellationToken) 
at async Azure.Extensions.AspNetCore.Configuration.Secrets.AzureKeyVaultConfigurationProvider.LoadAsync() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at async Azure.Extensions.AspNetCore.Configuration.Secrets.AzureKeyVaultConfigurationProvider.LoadAsync() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
at Azure.Extensions.AspNetCore.Configuration.Secrets.AzureKeyVaultConfigurationProvider.Load() at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers) 
at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build() at Ubysol.Scheduler.FunctionStartupBase.ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder) 
at D:\a\1\s\Ubysol.Scheduler\FunctionStartupBase.cs : 54 at Microsoft.Azure.WebJobs.WebJobsBuilderExtensions.ConfigureAndLogUserConfigurationProviders(IWebJobsConfigurationStartup 
startup,WebJobsBuilderContext context,IWebJobsConfigurationBuilder builder,ILoggerFactory loggerFactory) 
at D:\a\_work\1\s\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsBuilderExtensions.cs : 342 
at Microsoft.Azure.WebJobs.WebJobsBuilderExtensions.UseWebJobsConfigurationStartup(IWebJobsConfigurationBuilder builder,Type startupType,WebJobsBuilderContext context,ILoggerFactory 
loggerFactory) at D:\a\_work\1\s\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsBuilderExtensions.cs : 327 
at Microsoft.Azure.WebJobs.WebJobsBuilderExtensions.UseExternalConfigurationStartup(IWebJobsConfigurationBuilder builder,IWebJobsStartupTypeLocator startupTypeLocator,
WebJobsBuilderContext context,ILoggerFactory loggerFactory) at D:\a\_work\1\s\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsBuilderExtensions.cs : 367 
at Microsoft.Azure.WebJobs.Script.ScriptHostBuilderExtensions.<>c__DisplayClass7_3.<AddScriptHostCore>b__8(IWebJobsStartupTypeLocator locator) 
at /_/src/WebJobs.Script/ScriptHostBuilderExtensions.cs : 263 End of inner exception
Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
5,911 questions
{count} votes

Accepted answer
  1. Galih Ridho Utomo 90 Reputation points
    2025-06-06T02:23:50.6433333+00:00

    Le message d’erreur indique que votre Function App ne parvient plus à récupérer les secrets depuis le Key Vault parce que le mécanisme d’authentification (DefaultAzureCredential) ne trouve aucun moyen valide de se connecter. En d’autres termes, quand votre code (dans FunctionStartupBase.ConfigureAppConfiguration) appelle quelque chose comme :

    builder.ConfigurationBuilder
           .AddAzureKeyVault(
               new Uri(keyVaultUri),
               new DefaultAzureCredential());
    

    le DefaultAzureCredential va essayer, dans l’ordre, plusieurs méthodes d’obtention de jeton (environnement, identité managée, VS/VS Code, Azure CLI, Azure PowerShell), et – dans votre cas – toutes échouent :

    • EnvironmentCredential : il n’y a pas (ou plus) de variables d’environnement (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET) qui permettent à un client de se faire authentifier.

    ManagedIdentityCredential : la Function App n’a pas d’identité managée (vous l’avez supprimée pour tester l’isolated worker), donc l’appel au point de terminaison d’IMDS (169.254.169.254:80) est bloqué et renvoie une erreur de « socket forbidden ».

    VisualStudioCredential / VisualStudioCodeCredential / AzureCliCredential / AzurePowerShellCredential : aucun de ces outils n’est disponible en production (dans Azure Functions), ou bien ils ne sont pas configurés. D’où l’erreur « Azure CLI not installed », « Az.Account module >= 2.2.0 not installed », etc.


    1. Pourquoi votre Function App fonctionnait avant, et plus maintenant

    Avant : vous aviez une identité managée associée à la Function App (soit « System-assigned », soit une identité user-assigned), et vous aviez donné à cette identité les droits « Get » + « List » sur le Key Vault (via une access policy ou via RBAC Key Vault Secrets User).

    Dans ce contexte, DefaultAzureCredential avait accès à l’endpoint géré (IMDS) et obtenait un jeton auprès de l’Azure Instance Metadata Service.

      Les fonctions s’exécutaient, les secrets étaient lus, et tout marchait.
      
      **Pendant votre migration (in-process → isolated, .NET 6 → .NET 8)** :
      
         Vous avez **supprimé** l’identité managée (pour « tester » l’isolated worker ou parce que le message de migration vous l’indiquait).
         
            De fait, la Function App n’avait plus d’identité managée, donc `ManagedIdentityCredential` ne pouvait plus fonctionner.
            
               Vous n’aviez pas non plus de variables d’environnement pour un service principal, ni d’autre méthode valide pour que `DefaultAzureCredential` récupère un jeton.
               
                  Conséquence : au démarrage, `AddAzureKeyVault(...)` lève `CredentialUnavailableException`.
                  
                  **Après votre retour au paramétrage initial** :
                  
                     Vous avez remis la configuration « à l’identique » avant la migration (même code, même version de .NET, mêmes settings), **mais vous n’avez vraisemblablement pas réactivé (ou reparamétré) l’identité managée** dans le portail Azure.
                     
                        Du coup, même si le code `AddAzureKeyVault` est revenu comme avant, la Function App n’a toujours plus d’identité managée configurée, donc l’authentification échoue toujours.
                        
    

    1. Comment résoudre pas à pas

    2.1. Réactiver (ou recréer) l’identité managée

    Dans le Portail Azure, ouvrez votre Function App concernée.

    Allez dans la section Identity (Identité).

    Sous « System assigned », passez le commutateur sur On, puis Enregistrer.

    Azure alloue alors une identité managée au niveau de la Function App et génère automatiquement un objet principal dans Azure AD.

    Notez l’ID d’objet (object ID) si vous devez l’ajouter manuellement aux politiques du Key Vault, mais ce n’est généralement pas nécessaire pour un accès en RBAC.

    2.2. Donner les droits sur le Key Vault

    Il y a deux manières principales de donner à cette identité managée l’accès aux secrets :

    a) Via Access policies (politiques d’accès classiques) – (méthode “Legacy”)

    Ouvrez le Key Vault concerné.

    Dans le menu latéral, choisissez Access policies.

    Cliquez sur + Add Access Policy.

    Pour « Secret permissions », sélectionnez au minimum Get et List (voire Set, Delete si votre code en a besoin, mais généralement Get suffit).

      Cliquez sur **Select principal**, recherchez le nom de votre Function App (ou l’objet principal créé à l’étape précédente) et validez.
      
         Validez à nouveau pour créer la nouvelle politique d’accès.
         
         N’oubliez pas de cliquer sur **Save** pour enregistrer les modifications.
         
    

    b) Via Azure RBAC (recommandé pour les nouveaux déploiements)

    Ouvrez le Key Vault.

    Dans le menu, cliquez sur Access control (IAM).

    Cliquez sur + Add > Add role assignment.

    Dans Role, choisissez Key Vault Secrets User (ou Key Vault Secrets Officer si vous prévoyez aussi d’écrire des secrets).

      Dans **Assign access to**, sélectionnez **Managed identity**.
      
         Cliquez sur **Select members**, cherchez votre Function App, sélectionnez-la, puis validez.
         
         Cliquez sur **Save** (ou **Review + assign**).
         
    

    Pourquoi RBAC plutôt que Access policies ? À partir de 2024, Microsoft pousse vers l’usage d’Azure RBAC pour Key Vault (cela permet de gérer l’accès via des rôles standards plutôt que des policies héritées). Les deux méthodes fonctionnent, mais si vous utilisez déjà RBAC pour d’autres ressources, c’est plus cohérent.

    2.3. Vérifier la configuration de vos settings

    Dans la Function App, ouvrez Configuration > Application settings.

    Assurez-vous que la variable contenant l’URL du Key Vault est correctement définie ; par exemple, si votre code lit :

    var keyVaultUri = Environment.GetEnvironmentVariable("KEY_VAULT_URI");
    

    alors la setting KEY_VAULT_URI doit être égale à quelque chose comme

    https://mon-vault-name.vault.azure.net/
    

    Vérifiez également que vous n’avez pas accidentellement renseigné des variables d’environnement incomplètes pour un EnvironmentCredential (n’insérez pas de AZURE_CLIENT_ID ou AZURE_CLIENT_SECRET à moins que vous les ayez créés comme service principal ; autrement, laissez-les vides).

    Si vous aviez supprimé l’identité, il se peut qu’il reste des settings propres à l’isolated worker ou un WEBSITE_LOAD_USER_PROFILE que vous avez modifié ; remettez-les « comme avant » si vous les avez changés.

    Vérifiez également la présence de AzureWebJobsStorage (obligatoire à l’exécution) et FUNCTIONS_WORKER_RUNTIME (doit être dotnet-isolated ou dotnet selon votre modèle) – mais ça ne concerne pas directement le Key Vault.

    2.4. Redéployer et tester

    Après avoir réactivé l’identité managée (et donné les droits sur le Key Vault), redémarrez la Function App (bouton Restart).

    Consultez les Log Stream (dans Monitoring > Log Stream) pour vérifier que l’erreur CredentialUnavailableException n’apparaît plus pour le Key Vault.

    Vérifiez que vos fonctions sont de nouveau listées dans Functions et que l’URL de chaque fonction inclut bien le ?code=… (la signature hérité de la Function key).

    Si les clés (les host keys ou les function keys) ne s’affichent toujours pas, c’est probablement parce que vous aviez modifié un paramètre du runtime lors de la migration vers l’isolated worker.

      Dans ce cas, assurez-vous que votre `host.json` n’a pas de section qui désactive la protection par clé, par exemple :
      
      ```json
      {
    

    "version": "2.0", "extensions": { "http": { "routePrefix": "" } }, "functions": [ "MyFunction1", "MyFunction2" ] } ```

         Vérifiez aussi que **Authentication / Authorization** (dans le menu latéral) n’a pas été configuré pour ouvrir librement les endpoints.
         
    

    1. Pourquoi le message « Error building configuration in an external startup class » persiste

    Le texte complet indique que c’est le chargement de la configuration (en particulier AzureKeyVaultConfigurationProvider) qui échoue, précisément au moment où il tente :

    var credential = new DefaultAzureCredential();
    var builder = new ConfigurationBuilder()
        .AddAzureKeyVault(new Uri(keyVaultUri), credential)
        .AddEnvironmentVariables();
    

    Tant que DefaultAzureCredential ne trouve pas au moins un mode valide pour authentifier (identité managée, variables d’environnement, etc.), le provider Key Vault lève une exception, et donc l’host de Azure Functions n’arrive pas à « construire » la configuration, d’où l’erreur globale dans ExternalStartupException.

    En résumé :

    Vous avez supprimé l’identité managée, or c’est la voie d’authentification principale en production pour un DefaultAzureCredential.

    Vous n’avez pas compensé en ajoutant un service principal via variables d’environnement (AZURE_CLIENT_ID/TENANT/SECRET).

    Même si vous avez remis le code « exactement comme avant », la Function App n’a plus d’identité (laquel ne se réactive pas automatiquement).

    Par conséquent, DefaultAzureCredential ne parvient plus à s’authentifier → erreur persistante.


    1. Résumé des actions à mener

    Réactiver l’identité managée (System-assigned) dans le portail Azure pour votre Function App.

    Accorder le rôle « Key Vault Secrets User » (ou « Get + List » via Access policies classiques) à cette identité sur le Key Vault.

    Vérifier vos Application Settings :

    Que KEY_VAULT_URI (ou équivalent) pointe bien vers l’URL complète de votre vault (https://…vault.azure.net/).

      Que vous n’avez pas laissé des variables d’environnement partielles pour un `EnvironmentCredential` qui empêcherait la chaîne `DefaultAzureCredential` de « sauter » rapidement sur l’identité managée.
      
      **Redémarrer la Function App**, surveiller le **Log Stream**, et s’assurer que l’erreur `Azure.Identity.CredentialUnavailableException` n’apparaît plus.
      
      Une fois l’authentification à Key Vault rétablie, vos fonctions devraient à nouveau se lister (puisque la configuration a pu se charger). Vous retrouverez aussi les URL protégées par leur clé (ex. `https://…/api/MyFunction?code=XYZ`).
      
    

    Note sur les URL de fonction (clé de fonction)

    Si, dans le portail, vous allez dans Functions > (votre fonction) > Manage, vous devrez voir la « Function key » (la valeur ?code=…) sous forme, par exemple, de master key ou de function key.

    Si ces clés sont toujours absentes, vérifiez que vous n’avez pas, au niveau du host.json ou d’une extension, désactivé la validation par clé HTTP. Par défaut, Azure Functions exige une clé pour quiconque appelle GET/POST /api/votreFonction. Si vous la retirez, l’URL peut rester publique, mais ce n’est pas conseillé en production.


    1. Si, pour une raison spécifique, vous ne voulez pas (ou ne pouvez pas) repasser par l’identité managée

    Il existe deux alternatives :

    Service Principal + variables d’environnement

    Créez un Service Principal dans Azure AD (via az ad sp create-for-rbac --name "mon-sp" ou équivalent).

      Dans le Key Vault, créez une **Access policy** pour ce SP (Get + List).
      
         Dans la Function App, ajoutez dans **Configuration > Application settings** :
         
         ```sql
         AZURE_CLIENT_ID    = <clientId du SP>
    

    AZURE_TENANT_ID = <tenantId> AZURE_CLIENT_SECRET= <secret généré> KEY_VAULT_URI = https://mon-vault-name.vault.azure.net/ ```

            `DefaultAzureCredential` va alors détecter ces trois variables et s’authentifier via l’`EnvironmentCredential`.
            
               **Inconvénient** : le secret est stocké dans les App Settings, et il faut le renouveler manuellement si jamais il expire.
               
               **Azure Managed Identity + Browsersync**
               
                  Si votre code démarre parfois en local (Visual Studio, VS Code), installez l’extension Azure Account et signez-vous ; ainsi, `VisualStudioCredential` ou `VisualStudioCodeCredential` pourrait fonctionner durant le debug local.
                  
                     En revanche, en production, il faut à minima l’identité managée ou les variables d’environnement.
                     
    

    1. En conclusion

    Le cœur du problème : DefaultAzureCredential ne trouve aucun moyen valide de s’authentifier parce que vous avez supprimé l’identité managée et vous n’avez pas fourni d’EnvironmentCredential.

    La solution la plus simple est de réactiver l’identité managée de la Function App et de redonner les droits d’accès au Key Vault. Après redémarrage, l’authentification se fera automatiquement via cette identité.

    Une fois l’accès au Key Vault rétabli, l’erreur « Error building configuration in an external startup class » disparaîtra, vos fonctions seront à nouveau listées, et chaque URL aura bien son ?code=… (la clé) comme précédemment.

    N’hésitez pas à me faire savoir si, après avoir suivi ces étapes, vous rencontrez encore des difficultés ou si un autre message d’erreur apparaît !Le message d’erreur indique que votre Function App ne parvient plus à récupérer les secrets depuis le Key Vault parce que le mécanisme d’authentification (DefaultAzureCredential) ne trouve aucun moyen valide de se connecter. En d’autres termes, quand votre code (dans FunctionStartupBase.ConfigureAppConfiguration) appelle quelque chose comme :

    builder.ConfigurationBuilder
           .AddAzureKeyVault(
               new Uri(keyVaultUri),
               new DefaultAzureCredential());
    

    le DefaultAzureCredential va essayer, dans l’ordre, plusieurs méthodes d’obtention de jeton (environnement, identité managée, VS/VS Code, Azure CLI, Azure PowerShell), et – dans votre cas – toutes échouent :

    EnvironmentCredential : il n’y a pas (ou plus) de variables d’environnement (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET) qui permettent à un client de se faire authentifier.

    ManagedIdentityCredential : la Function App n’a pas d’identité managée (vous l’avez supprimée pour tester l’isolated worker), donc l’appel au point de terminaison d’IMDS (169.254.169.254:80) est bloqué et renvoie une erreur de « socket forbidden ».

    VisualStudioCredential / VisualStudioCodeCredential / AzureCliCredential / AzurePowerShellCredential : aucun de ces outils n’est disponible en production (dans Azure Functions), ou bien ils ne sont pas configurés. D’où l’erreur « Azure CLI not installed », « Az.Account module >= 2.2.0 not installed », etc.


    1. Pourquoi votre Function App fonctionnait avant, et plus maintenant

    Avant : vous aviez une identité managée associée à la Function App (soit « System-assigned », soit une identité user-assigned), et vous aviez donné à cette identité les droits « Get » + « List » sur le Key Vault (via une access policy ou via RBAC Key Vault Secrets User).

    Dans ce contexte, DefaultAzureCredential avait accès à l’endpoint géré (IMDS) et obtenait un jeton auprès de l’Azure Instance Metadata Service.

      Les fonctions s’exécutaient, les secrets étaient lus, et tout marchait.
      
      **Pendant votre migration (in-process → isolated, .NET 6 → .NET 8)** :
      
         Vous avez **supprimé** l’identité managée (pour « tester » l’isolated worker ou parce que le message de migration vous l’indiquait).
         
            De fait, la Function App n’avait plus d’identité managée, donc `ManagedIdentityCredential` ne pouvait plus fonctionner.
            
               Vous n’aviez pas non plus de variables d’environnement pour un service principal, ni d’autre méthode valide pour que `DefaultAzureCredential` récupère un jeton.
               
                  Conséquence : au démarrage, `AddAzureKeyVault(...)` lève `CredentialUnavailableException`.
                  
                  **Après votre retour au paramétrage initial** :
                  
                     Vous avez remis la configuration « à l’identique » avant la migration (même code, même version de .NET, mêmes settings), **mais vous n’avez vraisemblablement pas réactivé (ou reparamétré) l’identité managée** dans le portail Azure.
                     
                        Du coup, même si le code `AddAzureKeyVault` est revenu comme avant, la Function App n’a toujours plus d’identité managée configurée, donc l’authentification échoue toujours.
                        
    

    1. Comment résoudre pas à pas

    2.1. Réactiver (ou recréer) l’identité managée

    Dans le Portail Azure, ouvrez votre Function App concernée.

    Allez dans la section Identity (Identité).

    Sous « System assigned », passez le commutateur sur On, puis Enregistrer.

    Azure alloue alors une identité managée au niveau de la Function App et génère automatiquement un objet principal dans Azure AD.

    Notez l’ID d’objet (object ID) si vous devez l’ajouter manuellement aux politiques du Key Vault, mais ce n’est généralement pas nécessaire pour un accès en RBAC.

    2.2. Donner les droits sur le Key Vault

    Il y a deux manières principales de donner à cette identité managée l’accès aux secrets :

    a) Via Access policies (politiques d’accès classiques) – (méthode “Legacy”)

    Ouvrez le Key Vault concerné.

    Dans le menu latéral, choisissez Access policies.

    Cliquez sur + Add Access Policy.

    Pour « Secret permissions », sélectionnez au minimum Get et List (voire Set, Delete si votre code en a besoin, mais généralement Get suffit).

      Cliquez sur **Select principal**, recherchez le nom de votre Function App (ou l’objet principal créé à l’étape précédente) et validez.
      
         Validez à nouveau pour créer la nouvelle politique d’accès.
         
         N’oubliez pas de cliquer sur **Save** pour enregistrer les modifications.
         
    

    b) Via Azure RBAC (recommandé pour les nouveaux déploiements)

    Ouvrez le Key Vault.

    Dans le menu, cliquez sur Access control (IAM).

    Cliquez sur + Add > Add role assignment.

    Dans Role, choisissez Key Vault Secrets User (ou Key Vault Secrets Officer si vous prévoyez aussi d’écrire des secrets).

      Dans **Assign access to**, sélectionnez **Managed identity**.
      
         Cliquez sur **Select members**, cherchez votre Function App, sélectionnez-la, puis validez.
         
         Cliquez sur **Save** (ou **Review + assign**).
         
    

    Pourquoi RBAC plutôt que Access policies ? À partir de 2024, Microsoft pousse vers l’usage d’Azure RBAC pour Key Vault (cela permet de gérer l’accès via des rôles standards plutôt que des policies héritées). Les deux méthodes fonctionnent, mais si vous utilisez déjà RBAC pour d’autres ressources, c’est plus cohérent.

    2.3. Vérifier la configuration de vos settings

    Dans la Function App, ouvrez Configuration > Application settings.

    Assurez-vous que la variable contenant l’URL du Key Vault est correctement définie ; par exemple, si votre code lit :

    var keyVaultUri = Environment.GetEnvironmentVariable("KEY_VAULT_URI");
    

    alors la setting KEY_VAULT_URI doit être égale à quelque chose comme

    https://mon-vault-name.vault.azure.net/
    

    Vérifiez également que vous n’avez pas accidentellement renseigné des variables d’environnement incomplètes pour un EnvironmentCredential (n’insérez pas de AZURE_CLIENT_ID ou AZURE_CLIENT_SECRET à moins que vous les ayez créés comme service principal ; autrement, laissez-les vides).

    Si vous aviez supprimé l’identité, il se peut qu’il reste des settings propres à l’isolated worker ou un WEBSITE_LOAD_USER_PROFILE que vous avez modifié ; remettez-les « comme avant » si vous les avez changés.

    Vérifiez également la présence de AzureWebJobsStorage (obligatoire à l’exécution) et FUNCTIONS_WORKER_RUNTIME (doit être dotnet-isolated ou dotnet selon votre modèle) – mais ça ne concerne pas directement le Key Vault.

    2.4. Redéployer et tester

    Après avoir réactivé l’identité managée (et donné les droits sur le Key Vault), redémarrez la Function App (bouton Restart).

    Consultez les Log Stream (dans Monitoring > Log Stream) pour vérifier que l’erreur CredentialUnavailableException n’apparaît plus pour le Key Vault.

    Vérifiez que vos fonctions sont de nouveau listées dans Functions et que l’URL de chaque fonction inclut bien le ?code=… (la signature hérité de la Function key).

    Si les clés (les host keys ou les function keys) ne s’affichent toujours pas, c’est probablement parce que vous aviez modifié un paramètre du runtime lors de la migration vers l’isolated worker.

      Dans ce cas, assurez-vous que votre `host.json` n’a pas de section qui désactive la protection par clé, par exemple :
      
      ```json
      {
    

    "version": "2.0", "extensions": { "http": { "routePrefix": "" } }, "functions": [ "MyFunction1", "MyFunction2" ] } ```

         Vérifiez aussi que **Authentication / Authorization** (dans le menu latéral) n’a pas été configuré pour ouvrir librement les endpoints.
         
    

    1. Pourquoi le message « Error building configuration in an external startup class » persiste

    Le texte complet indique que c’est le chargement de la configuration (en particulier AzureKeyVaultConfigurationProvider) qui échoue, précisément au moment où il tente :

    var credential = new DefaultAzureCredential();
    var builder = new ConfigurationBuilder()
        .AddAzureKeyVault(new Uri(keyVaultUri), credential)
        .AddEnvironmentVariables();
    

    Tant que DefaultAzureCredential ne trouve pas au moins un mode valide pour authentifier (identité managée, variables d’environnement, etc.), le provider Key Vault lève une exception, et donc l’host de Azure Functions n’arrive pas à « construire » la configuration, d’où l’erreur globale dans ExternalStartupException.

    En résumé :

    Vous avez supprimé l’identité managée, or c’est la voie d’authentification principale en production pour un DefaultAzureCredential.

    Vous n’avez pas compensé en ajoutant un service principal via variables d’environnement (AZURE_CLIENT_ID/TENANT/SECRET).

    Même si vous avez remis le code « exactement comme avant », la Function App n’a plus d’identité (laquel ne se réactive pas automatiquement).

    Par conséquent, DefaultAzureCredential ne parvient plus à s’authentifier → erreur persistante.


    1. Résumé des actions à mener

    Réactiver l’identité managée (System-assigned) dans le portail Azure pour votre Function App.

    Accorder le rôle « Key Vault Secrets User » (ou « Get + List » via Access policies classiques) à cette identité sur le Key Vault.

    Vérifier vos Application Settings :

    Que KEY_VAULT_URI (ou équivalent) pointe bien vers l’URL complète de votre vault (https://…vault.azure.net/).

      Que vous n’avez pas laissé des variables d’environnement partielles pour un `EnvironmentCredential` qui empêcherait la chaîne `DefaultAzureCredential` de « sauter » rapidement sur l’identité managée.
      
      **Redémarrer la Function App**, surveiller le **Log Stream**, et s’assurer que l’erreur `Azure.Identity.CredentialUnavailableException` n’apparaît plus.
      
      Une fois l’authentification à Key Vault rétablie, vos fonctions devraient à nouveau se lister (puisque la configuration a pu se charger). Vous retrouverez aussi les URL protégées par leur clé (ex. `https://…/api/MyFunction?code=XYZ`).
      
    

    Note sur les URL de fonction (clé de fonction)

    Si, dans le portail, vous allez dans Functions > (votre fonction) > Manage, vous devrez voir la « Function key » (la valeur ?code=…) sous forme, par exemple, de master key ou de function key.

    Si ces clés sont toujours absentes, vérifiez que vous n’avez pas, au niveau du host.json ou d’une extension, désactivé la validation par clé HTTP. Par défaut, Azure Functions exige une clé pour quiconque appelle GET/POST /api/votreFonction. Si vous la retirez, l’URL peut rester publique, mais ce n’est pas conseillé en production.


    1. Si, pour une raison spécifique, vous ne voulez pas (ou ne pouvez pas) repasser par l’identité managée

    Il existe deux alternatives :

    Service Principal + variables d’environnement

    Créez un Service Principal dans Azure AD (via az ad sp create-for-rbac --name "mon-sp" ou équivalent).

      Dans le Key Vault, créez une **Access policy** pour ce SP (Get + List).
      
         Dans la Function App, ajoutez dans **Configuration > Application settings** :
         
         ```sql
         AZURE_CLIENT_ID    = <clientId du SP>
    

    AZURE_TENANT_ID = <tenantId> AZURE_CLIENT_SECRET= <secret généré> KEY_VAULT_URI = https://mon-vault-name.vault.azure.net/ ```

            `DefaultAzureCredential` va alors détecter ces trois variables et s’authentifier via l’`EnvironmentCredential`.
            
               **Inconvénient** : le secret est stocké dans les App Settings, et il faut le renouveler manuellement si jamais il expire.
               
               **Azure Managed Identity + Browsersync**
               
                  Si votre code démarre parfois en local (Visual Studio, VS Code), installez l’extension Azure Account et signez-vous ; ainsi, `VisualStudioCredential` ou `VisualStudioCodeCredential` pourrait fonctionner durant le debug local.
                  
                     En revanche, en production, il faut à minima l’identité managée ou les variables d’environnement.
                     
    

    1. En conclusion

    Le cœur du problème : DefaultAzureCredential ne trouve aucun moyen valide de s’authentifier parce que vous avez supprimé l’identité managée et vous n’avez pas fourni d’EnvironmentCredential.

    La solution la plus simple est de réactiver l’identité managée de la Function App et de redonner les droits d’accès au Key Vault. Après redémarrage, l’authentification se fera automatiquement via cette identité.

    • Une fois l’accès au Key Vault rétabli, l’erreur « Error building configuration in an external startup class » disparaîtra, vos fonctions seront à nouveau listées, et chaque URL aura bien son ?code=… (la clé) comme précédemment.
    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. David M 236 Reputation points
    2025-06-10T07:02:46.0366667+00:00
    Merci à vous pour vos réponses, le service est revenu d'aplomb. J'en suis maintenant à mon point de départ qui m'avait mis dans cette situation, à savoir : "Seulement, contrairement à d'autres de mes services Function App, les URL de fonctions ne sont pas protégées par une clé (url?code=4cDlZ6AgFK9c...)"
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.