我有一个 Azure 函数,我在其中创建了一个 HTTP 客户端。该客户需要证书。该证书存储在 Azure KeyVault 中。在生产环境中,我在Azure功能的Application Insights中不断收到以下错误:
消息:结果:函数“MyDummyFunction” 调用引发了异常。异常:System.Net.Http.HttpRequestException:无法建立 SSL 连接,请参阅内部异常。 ---> System.Security.Authentication.AuthenticationException:身份验证失败,请参阅内部异常。 ---> Interop+OpenSsl+SslException:SSL 握手失败,出现 OpenSSL 错误 - SSL_ERROR_SSL。
这是我尝试设置证书的方式。
public class DummyHttpClient
{
public readonly HttpClient client;
private readonly ILogger<DummyHttpClient> logger;
private readonly ActivationConfiguration configuration;
public DummyHttpClient(ActivationConfiguration configuration, ILogger<DummyHttpClient> logger)
{
this.logger = logger;
this.configuration = configuration;
var handler = ClientHandlerConfigure();
this.client = ClientConfigure(handler);
}
private HttpClientHandler ClientHandlerConfigure()
{
var certificate = GetCertificate();
var handler = new HttpClientHandler()
{
SslProtocols = SslProtocols.Tls12,
ClientCertificateOptions = ClientCertificateOption.Manual,
ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => { return true; },
};
if (certificateForBHN is not null)
{
handler.ClientCertificates.Add(certificate);
}
return handler;
}
private HttpClient ClientConfigure(HttpClientHandler handler)
{
var client = new HttpClient(handler)
{
BaseAddress = new Uri(configuration.ApiBaseAddress),
Timeout = TimeSpan.FromSeconds(100),
};
client.DefaultRequestHeaders.Add("ContentType", "application/json");
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.ConnectionClose = false;
return client;
}
private X509Certificate2 GetCertificate()
{
var client = new CertificateClient(new Uri($"https://dummykeyvault.vault.azure.net/"), new DefaultAzureCredential());
var certificateOptions = new DownloadCertificateOptions("Activation")
{
KeyStorageFlags = X509KeyStorageFlags.MachineKeySet,
};
var certificate = client.DownloadCertificate(certificateOptions);
return certificate.Value;
}
}
我已按照以下步骤操作并能够在 Azure 中运行您的代码。
代码片段:
public class DummyHttpClient
{
public readonly HttpClient client;
private readonly ILogger<DummyHttpClient> logger;
private readonly ActivationConfiguration configuration;
public DummyHttpClient(ActivationConfiguration configuration, ILogger<DummyHttpClient> logger)
{
this.logger = logger;
this.configuration = configuration;
var handler = ClientHandlerConfigure();
this.client = ClientConfigure(handler);
}
private HttpClientHandler ClientHandlerConfigure()
{
var certificate = GetCertificate();
var handler = new HttpClientHandler
{
SslProtocols = SslProtocols.Tls12,
ClientCertificateOptions = ClientCertificateOption.Manual,
ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, certChain, policyErrors) => true,
};
if (certificate != null)
{
handler.ClientCertificates.Add(certificate);
}
return handler;
}
private HttpClient ClientConfigure(HttpClientHandler handler)
{
var client = new HttpClient(handler)
{
BaseAddress = new Uri(configuration.ApiBaseAddress),
Timeout = TimeSpan.FromSeconds(100),
};
client.DefaultRequestHeaders.Add("ContentType", "application/json");
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.ConnectionClose = false;
return client;
}
private X509Certificate2 GetCertificate()
{
var client = new CertificateClient(new Uri("https://keyvault.vault.azure.net/"), new DefaultAzureCredential());
var certificateName = "certificate_name";
var certificateWithPolicy = client.GetCertificate(certificateName);
var downloadOptions = new DownloadCertificateOptions(certificateWithPolicy.Value.Name)
{
KeyStorageFlags = X509KeyStorageFlags.MachineKeySet,
};
var certificate = client.DownloadCertificate(downloadOptions);
return new X509Certificate2(certificate.Value);
}
}
功能代码:
public class Function1
{
private readonly ILogger<Function1> _logger;
private readonly DummyHttpClient _dummyHttpClient;
public Function1(ILogger<Function1> logger, DummyHttpClient dummyHttpClient)
{
_logger = logger;
_dummyHttpClient = dummyHttpClient;
}
[Function("Function1")]
public IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequest req)
{
var response = _dummyHttpClient.client.GetAsync("items");
_logger.LogInformation("C# HTTP trigger function processed a request.");
return new OkObjectResult("Welcome to Azure Functions!");
}
}
在Azure功能应用程序中启用系统身份:
将
Key Vault Administrator
和 Key Vault Certificates Officer
角色分配给函数应用程序:
传送门:
2024-10-28T12:36:24Z [Information] C# HTTP trigger function processed a request.
2024-10-28T12:36:24Z [Information] Executing OkObjectResult, writing value of type 'System.String'.
2024-10-28T12:36:24Z [Information] Executed 'Functions.Function1' (Succeeded, Id=5848e8b2-c933-4056-a0c8-33a88d827180, Duration=3000ms)
调用日志: