无法使用C#从具有用户管理身份的Azure密钥保管库下载证书

kknvjkwl  于 2023-04-22  发布在  C#
关注(0)|答案(1)|浏览(115)

我已在Azure密钥保管库的“证书”部分导入证书
创建了一个用户管理的身份,并添加了一个角色分配上述密钥库与贡献者角色。
尝试使用下面的c#代码下载证书

var kvUri = $"https://{KeyVaultName}.vault.azure.net";
string UserManagedIdentityClientId = ConfigKeys.ReadConfigValues("UserManagedIdentityClientId");
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions()
                {
                    ExcludeAzureCliCredential= true,
                    ExcludeAzurePowerShellCredential= true,
                    ExcludeEnvironmentCredential= true,
                    ExcludeInteractiveBrowserCredential= true,
                    ExcludeManagedIdentityCredential= false,
                    ExcludeSharedTokenCacheCredential= true,
                    ExcludeVisualStudioCodeCredential= true,
                    ExcludeVisualStudioCredential= true,
                    ManagedIdentityClientId = UserManagedIdentityClientId
                });
var client = new CertificateClient(new Uri(kvUri), credential);
var certificate = client.DownloadCertificate(CertName);

得到下面的错误,
1.在托管环境中,
“系统找不到指定的文件”
1.在本地环境中,

发生异常

Azure.Identity. CredentialUnavailable异常

HResult=0x80131500

 Message=ManagedIdentityCredential authentication unavailable. Multiple attempts failed to obtain a token from the managed identity endpoint.

 Source=Azure.Identity

 StackTrace:

  at Azure.Identity.DefaultAzureCredential.<GetTokenFromSourcesAsync>d__14.MoveNext()

  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

  at Azure.Identity.DefaultAzureCredential.<GetTokenImplAsync>d__12.MoveNext()

  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

  at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex, String additionalMessage)

  at Azure.Identity.DefaultAzureCredential.<GetTokenImplAsync>d__12.MoveNext()

  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

  at Azure.Identity.DefaultAzureCredential.GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)

  at Azure.Core.Pipeline.BearerTokenAuthenticationPolicy.AccessTokenCache.<GetHeaderValueFromCredentialAsync>d__9.MoveNext()

  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

  at Azure.Core.Pipeline.BearerTokenAuthenticationPolicy.AccessTokenCache.<GetHeaderValueAsync>d__6.MoveNext()

  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

  at Azure.Core.Pipeline.BearerTokenAuthenticationPolicy.AccessTokenCache.<GetHeaderValueAsync>d__6.MoveNext()

  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

  at Azure.Core.Pipeline.BearerTokenAuthenticationPolicy.AuthenticateAndAuthorizeRequest(HttpMessage message, TokenRequestContext context)

  at Azure.Security.KeyVault.ChallengeBasedAuthenticationPolicy.<AuthorizeRequestOnChallengeAsyncInternal>d__10.MoveNext()

  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

  at Azure.Security.KeyVault.ChallengeBasedAuthenticationPolicy.AuthorizeRequestOnChallenge(HttpMessage message)

  at Azure.Core.Pipeline.BearerTokenAuthenticationPolicy.<ProcessAsync>d__11.MoveNext()

  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

  at Azure.Core.Pipeline.BearerTokenAuthenticationPolicy.Process(HttpMessage message, ReadOnlyMemory`1 pipeline)

  at Azure.Core.Pipeline.HttpPipelinePolicy.ProcessNext(HttpMessage message, ReadOnlyMemory`1 pipeline)

  at Azure.Core.Pipeline.RedirectPolicy.<ProcessAsync>d__7.MoveNext()

  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

  at Azure.Core.Pipeline.RedirectPolicy.Process(HttpMessage message, ReadOnlyMemory`1 pipeline)

  at Azure.Core.Pipeline.HttpPipelinePolicy.ProcessNext(HttpMessage message, ReadOnlyMemory`1 pipeline)

  at Azure.Core.Pipeline.RetryPolicy.<ProcessAsync>d__5.MoveNext()

  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

  at Azure.Core.Pipeline.RetryPolicy.<ProcessAsync>d__5.MoveNext()

  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

  at Azure.Core.Pipeline.RetryPolicy.Process(HttpMessage message, ReadOnlyMemory`1 pipeline)

  at Azure.Core.Pipeline.HttpPipelinePolicy.ProcessNext(HttpMessage message, ReadOnlyMemory`1 pipeline)

  at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.Process(HttpMessage message, ReadOnlyMemory`1 pipeline)

  at Azure.Core.Pipeline.HttpPipelinePolicy.ProcessNext(HttpMessage message, ReadOnlyMemory`1 pipeline)

  at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.Process(HttpMessage message, ReadOnlyMemory`1 pipeline)

  at Azure.Core.Pipeline.HttpPipelinePolicy.ProcessNext(HttpMessage message, ReadOnlyMemory`1 pipeline)

  at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.Process(HttpMessage message, ReadOnlyMemory`1 pipeline)

  at Azure.Core.Pipeline.HttpPipeline.Send(HttpMessage message, CancellationToken cancellationToken)

  at Azure.Core.Pipeline.HttpPipeline.SendRequest(Request request, CancellationToken cancellationToken)

  at Azure.Security.KeyVault.KeyVaultPipeline.SendRequest(Request request, CancellationToken cancellationToken)

  at Azure.Security.KeyVault.KeyVaultPipeline.SendRequest[TResult](RequestMethod method, Func`1 resultFactory, CancellationToken cancellationToken, String[] path)

  at Azure.Security.KeyVault.Certificates.CertificateClient.DownloadCertificate(DownloadCertificateOptions options, CancellationToken cancellationToken)

  at Azure.Security.KeyVault.Certificates.CertificateClient.DownloadCertificate(String certificateName, String version, CancellationToken cancellationToken)

内部异常

Inner Exception 1:

   AggregateException: Retry failed after 4 tries. Retry settings can be adjusted in ClientOptions.Retry or by configuring a custom retry policy in ClientOptions.RetryPolicy.
  

   Inner Exception 2:

   RequestFailedException: Unable to connect to the remote server
   

   Inner Exception 3:

   WebException: Unable to connect to the remote server

  
   Inner Exception 4:

   SocketException: A socket operation was attempted to an unreachable network

使用CertificateClient,我想下载在Azure密钥库“证书”部分导入的证书。

sqougxex

sqougxex1#

要加载包含私钥的证书,则需要将其作为秘密而不是证书进行检索。如果将其作为证书获取,则只能获取其公钥。
这是我用来从Azure Key Vault获取完整证书的代码。

/// <summary>
    /// Load a certificate (with private key) from Azure Key Vault
    ///
    /// Getting a certificate with private key is a bit of a pain, but the code below solves it.
    /// 
    /// Get the private key for Key Vault certificate
    /// https://github.com/heaths/azsdk-sample-getcert
    /// 
    /// See also these GitHub issues: 
    /// https://github.com/Azure/azure-sdk-for-net/issues/12742
    /// https://github.com/Azure/azure-sdk-for-net/issues/12083
    /// </summary>
    /// <param name="config"></param>
    /// <param name="certificateName"></param>
    /// <returns></returns>
    public static X509Certificate2 LoadCertificate(IConfiguration config, string certificateName)
    {
        string vaultUrl = config["Vault:Url"] ?? "";
        string clientId = config["Vault:ClientId"] ?? "";
        string tenantId = config["Vault:TenantId"] ?? "";
        string secret = config["Vault:ClientSecret"] ?? "";

        Console.WriteLine($"Loading certificate '{certificateName}' from Azure Key Vault");

        var credentials = new ClientSecretCredential(tenantId: tenantId, clientId: clientId, clientSecret: secret);
        var certClient = new CertificateClient(new Uri(vaultUrl), credentials);
        var secretClient = new SecretClient(new Uri(vaultUrl), credentials);

        var cert = GetCertificateAsync(certClient, secretClient, certificateName);

        Console.WriteLine("Certificate loaded");
        return cert;
    }

    /// <summary>
    /// Helper method to get a certificate
    /// 
    /// Source https://github.com/heaths/azsdk-sample-getcert/blob/master/Program.cs
    /// </summary>
    /// <param name="certificateClient"></param>
    /// <param name="secretClient"></param>
    /// <param name="certificateName"></param>
    /// <returns></returns>
    private static X509Certificate2 GetCertificateAsync(CertificateClient certificateClient,
                                                            SecretClient secretClient,
                                                            string certificateName)
    {

        KeyVaultCertificateWithPolicy certificate = certificateClient.GetCertificate(certificateName);

        // Return a certificate with only the public key if the private key is not exportable.
        if (certificate.Policy?.Exportable != true)
        {
            return new X509Certificate2(certificate.Cer);
        }

        // Parse the secret ID and version to retrieve the private key.
        string[] segments = certificate.SecretId.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries);
        if (segments.Length != 3)
        {
            throw new InvalidOperationException($"Number of segments is incorrect: {segments.Length}, URI: {certificate.SecretId}");
        }

        string secretName = segments[1];
        string secretVersion = segments[2];

        KeyVaultSecret secret = secretClient.GetSecret(secretName, secretVersion);

        // For PEM, you'll need to extract the base64-encoded message body.
        // .NET 5.0 preview introduces the System.Security.Cryptography.PemEncoding class to make this easier.
        if ("application/x-pkcs12".Equals(secret.Properties.ContentType, StringComparison.InvariantCultureIgnoreCase))
        {
            byte[] pfx = Convert.FromBase64String(secret.Value);
            return new X509Certificate2(pfx);
        }

        throw new NotSupportedException($"Only PKCS#12 is supported. Found Content-Type: {secret.Properties.ContentType}");
    }
}

相关问题