Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception while fetching value of first key vault secret for the application #4924

Closed
njangir2 opened this issue Oct 24, 2018 · 16 comments
Closed
Labels
Client This issue points to a problem in the data-plane of the library. KeyVault
Milestone

Comments

@njangir2
Copy link

njangir2 commented Oct 24, 2018

Hi,

In my application I am getting exception when my application fetches value of first key vault secret.

The exception I am only getting when I turn on "Common Language Run-time Exceptions" from exception settings.

Exception that I am getting is-
Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException: 'Response status code indicates server error: 401 (Unauthorized).'
StackTrace:-
at Microsoft.Rest.RetryDelegatingHandler.<>c__DisplayClass11_0.<<SendAsync>b__1>d.MoveNext()

My code to fetch the key vault secret is given below-

public async Task<string> GetSecretValue(string clientId, string appKey, string secretIdentifier)
{
	IAdAuthentication authToken = new AdAuthentication
	{
		ClientId = clientId,
		AppKey = appKey
	};
	KeyVaultClient keyVaultClient = new KeyVaultClient(authToken.GetAuthenticationTokenAsync);

	// Get secret from the KeyVault.
	SecretBundle secret = await keyVaultClient.GetSecretAsync(secretIdentifier);

	string secretValue = string.Empty;
	if (secret?.Value != null)
	{
		secretValue = secret.Value.Trim();
	}
	return secretValue;
}

Interface IAdAuthentication

public interface IAdAuthentication
{
	string ClientId { get; set; }

	string AppKey { get; set; }

	/// <summary>
	/// Get Authentication Token
	/// </summary>
	/// <param name="authority"></param>
	/// <param name="resource"></param>
	/// <param name="scope"></param>
	/// <returns></returns>
	Task<string> GetAuthenticationTokenAsync(string authority, string resource, string scope);
}

Implementation of interface IAdAuthentication is in class AdAuthentication

public class AdAuthentication : IAdAuthentication
{
	public string ClientId { get; set; }

	public string AppKey { get; set; }

	/// <summary>
	/// Get Authentication Token
	/// </summary>
	/// <param name="authority"></param>
	/// <param name="resource"></param>
	/// <param name="scope"></param>
	/// <returns></returns>
	public async Task<string> GetAuthenticationTokenAsync(string authority, string resource, string scope)
	{
		if (string.IsNullOrEmpty(authority))
			throw new ArgumentNullException(nameof(authority));
		if (string.IsNullOrEmpty(resource))
			throw new ArgumentNullException(nameof(resource));
		if (string.IsNullOrEmpty(ClientId))
			throw new ArgumentNullException(nameof(ClientId));
		if (string.IsNullOrEmpty(AppKey))
			throw new ArgumentNullException(nameof(AppKey));

		ClientCredential clientCredential = new ClientCredential(ClientId, AppKey);
		AuthenticationContext context = new AuthenticationContext(authority, false, TokenCache.DefaultShared);
		AuthenticationResult result = await context.AcquireTokenAsync(resource, clientCredential);
		return result.AccessToken;
	}
}

Above given exception is being thrown when I fetch the value of first key vault secret for the application instance and it doesn't matter what is the value of first secret identifier. For all next key vault secret exception doesn't occur.
Along with exception value of first key vault secret is also being fetched but I want to mitigate this exception from my application.
It seems issue is around AuthenticationCallback which is passed to initialize KeyVaultClient.
Please let me know what I am missing here.

Adding details of fiddler tracing for the key vault secret request-

-------------------------------------------------------------
CONNECT mykeyvault.vault.azure.net:443 HTTP/1.0
Host: mykeyvault.vault.azure.net:443
Content-Length: 0
Proxy-Connection: Keep-Alive
Pragma: no-cache

A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.

Version: 3.3 (TLS/1.2)
Random: 5B D6 D9 74 4F 81 32 0A 1D CB 8F DF E2 1F 2A 87 EC C2 98 A7 CA 6F EF DF 50 4E 1F 11 7D D7 7D 8F
"Time": 2/15/2032 10:17:23 AM
SessionID: empty
Extensions: 
    server_name mykeyvault.vault.azure.net
    status_request  OCSP - Implicit Responder
    elliptic_curves unknown [0x1D), secp256r1 [0x17], secp384r1 [0x18]
    ec_point_formats    uncompressed [0x0]
    signature_algs  sha256_rsa, sha384_rsa, sha1_rsa, sha256_ecdsa, sha384_ecdsa, sha1_ecdsa, sha1_dsa, sha512_rsa, sha512_ecdsa
    SessionTicket   empty
    ALPN        h2, http/1.1
    extended_master_secret  empty
    0x0018      00 10 03 02 01 00
    renegotiation_info  00
Ciphers: 
    [C02C]  TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    [C02B]  TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    [C030]  TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    [C02F]  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    [C024]  TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
    [C023]  TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
    [C028]  TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
    [C027]  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
    [C00A]  TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
    [C009]  TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
    [C014]  TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA
    [C013]  TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA
    [009D]  TLS_RSA_WITH_AES_256_GCM_SHA384
    [009C]  TLS_RSA_WITH_AES_128_GCM_SHA256
    [003D]  TLS_RSA_WITH_AES_256_CBC_SHA256
    [003C]  TLS_RSA_WITH_AES_128_CBC_SHA256
    [0035]  TLS_RSA_AES_256_SHA
    [002F]  TLS_RSA_AES_128_SHA
    [000A]  SSL_RSA_WITH_3DES_EDE_SHA

Compression: 
    [00]    NO_COMPRESSION



HTTP/1.1 200 Connection Established
Proxy-Agent: Zscaler/5.6

Encrypted HTTPS traffic flows through this CONNECT tunnel. HTTPS Decryption is enabled in Fiddler, so decrypted sessions running in this tunnel will be shown in the Web Sessions list.

Secure Protocol: Tls12
Cipher: Aes256 256bits
Hash Algorithm: Sha384 ?bits
Key Exchange: RsaKeyX 2048bits

== Server Certificate ==========
[Subject]
  CN=vault.azure.net

[Issuer]
  E=support@zscaler.com, CN=Zscaler Intermediate Root CA (zscaler.net), OU=Zscaler Inc., O=Zscaler Inc., S=California, C=US

[Serial Number]
  7B00004CD55FB23FA0B68D46B8000000009CD5

[Not Before]
  9/13/2017 6:31:29 AM

[Not After]
  9/13/2019 6:31:29 AM

[Thumbprint]
  BE3A3F50134F9E3989C4200C751X473D5235F4C2

[SubjectAltNames]
vault.azure.net, *.vault.azure.net, *.vaultcore.azure.net


------------------------------------------------------------------
GET https://mykeyvault.vault.azure.net/secrets/ContactManager-AppApiUrl/?api-version=7.0 HTTP/1.1
User-Agent: FxVersion/4.6.00001.0 OSName/Windows OSVersion/MicrosoftWindows Microsoft.Azure.KeyVault.KeyVaultClient/3.0.1.0
Host: mykeyvault.vault.azure.net
Connection: Keep-Alive
Cache-Control: no-cache


HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/10.0
WWW-Authenticate: Bearer authorization="https://login.windows.net/e41ed7bb-472e-4682-9ac0-dd00dfe1aa40", resource="https://vault.azure.net"
x-ms-keyvault-region: eastus2
x-ms-request-id: b3baba90-222c-4412-b57e-b5500ff95572
x-ms-keyvault-service-version: 1.1.0.858
x-ms-keyvault-network-info: addr=165.225.34.51;act_addr_fam=InterNetwork;
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Strict-Transport-Security: max-age=31536000;includeSubDomains
X-Content-Type-Options: nosniff
Date: Mon, 29 Oct 2018 09:57:08 GMT
Content-Length: 0
Proxy-Support: Session-Based-Authentication



------------------------------------------------------------------
CONNECT login.windows.net:443 HTTP/1.0
Host: login.windows.net:443
Content-Length: 0
Proxy-Connection: Keep-Alive
Pragma: no-cache

A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.

Version: 3.3 (TLS/1.2)
Random: 5B D6 D9 7C 94 3B 8E 2B 32 4F 6F 70 3F 85 EC C0 53 27 5D C8 5C 3E 33 8F CF 38 30 A4 91 F8 AE 16
"Time": 5/17/2036 8:59:31 PM
SessionID: empty
Extensions: 
    server_name login.windows.net
    status_request  OCSP - Implicit Responder
    elliptic_curves unknown [0x1D), secp256r1 [0x17], secp384r1 [0x18]
    ec_point_formats    uncompressed [0x0]
    signature_algs  sha256_rsa, sha384_rsa, sha1_rsa, sha256_ecdsa, sha384_ecdsa, sha1_ecdsa, sha1_dsa, sha512_rsa, sha512_ecdsa
    SessionTicket   empty
    ALPN        h2, http/1.1
    extended_master_secret  empty
    0x0018      00 10 03 02 01 00
    renegotiation_info  00
Ciphers: 
    [C02C]  TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    [C02B]  TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    [C030]  TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    [C02F]  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    [C024]  TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
    [C023]  TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
    [C028]  TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
    [C027]  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
    [C00A]  TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
    [C009]  TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
    [C014]  TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA
    [C013]  TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA
    [009D]  TLS_RSA_WITH_AES_256_GCM_SHA384
    [009C]  TLS_RSA_WITH_AES_128_GCM_SHA256
    [003D]  TLS_RSA_WITH_AES_256_CBC_SHA256
    [003C]  TLS_RSA_WITH_AES_128_CBC_SHA256
    [0035]  TLS_RSA_AES_256_SHA
    [002F]  TLS_RSA_AES_128_SHA
    [000A]  SSL_RSA_WITH_3DES_EDE_SHA

Compression: 
    [00]    NO_COMPRESSION



HTTP/1.1 200 Connection Established
Proxy-Agent: Zscaler/5.6

Encrypted HTTPS traffic flows through this CONNECT tunnel. HTTPS Decryption is enabled in Fiddler, so decrypted sessions running in this tunnel will be shown in the Web Sessions list.

Secure Protocol: Tls12
Cipher: Aes256 256bits
Hash Algorithm: Sha384 ?bits
Key Exchange: RsaKeyX 2048bits

== Server Certificate ==========
[Subject]
  CN=graph.windows.net

[Issuer]
  E=support@zscaler.com, CN=Zscaler Intermediate Root CA (zscaler.net), OU=Zscaler Inc., O=Zscaler Inc., S=California, C=US

[Serial Number]
  200003E3D42591706F9A74181400000003E3D4

[Not Before]
  8/29/2018 12:38:12 PM

[Not After]
  8/29/2020 12:38:12 PM

[Thumbprint]
  27242CE7B9E88BD32DE00CB02BF2033B3AX47DDD

[SubjectAltNames]
*.accesscontrol.windows.net, *.accesscontrol.windows-ppe.net, *.b2clogin.com, *.cpim.windows.net, *.microsoftaik.azure.net, *.microsoftaik-int.azure-int.net, *.windows-ppe.net, aadg.windows.net, aadgv6.ppe.windows.net, aadgv6.windows.net, account.live.com, account.live-int.com, api.password.ccsctp.com, api.passwordreset.microsoftonline.com, autologon.microsoftazuread-sso.com, becws.ccsctp.com, clientconfig.microsoftonline-p.net, clientconfig.microsoftonline-p-int.net, companymanager.ccsctp.com, companymanager.microsoftonline.com, cpim.windows.net, device.login.microsoftonline.com, device.login.windows-ppe.net, directoryproxy.ppe.windows.net, directoryproxy.windows.net, graph.ppe.windows.net, graph.windows.net, graphstore.windows.net, login.live.com, login.live-int.com, login.microsoft.com, login.microsoftonline.com, login.microsoftonline-p.com, login.microsoftonline-pst.com, login.microsoft-ppe.com, login.windows.net, logincert.microsoftonline.com, logincert.microsoftonline-int.com, login-us.microsoftonline.com, microsoftaik.azure.net, microsoftaik-int.azure-int.net, nexus.microsoftonline-p.com, nexus.microsoftonline-p-int.com, pas.windows.net, pas.windows-ppe.net, password.ccsctp.com, passwordreset.activedirectory.windowsazure.us, passwordreset.microsoftonline.com, provisioning.microsoftonline.com, signup.live.com, signup.live-int.com, sts.windows.net, xml.login.live.com, xml.login.live-int.com, *.login.microsoftonline.com, login.microsoftonline-int.com, accesscontrol.aadtst3.windows-int.net, *.accesscontrol.aadtst3.windows-int.net


------------------------------------------------------------------
GET https://login.windows.net/common/discovery/instance?api-version=1.1&authorization_endpoint=https://login.windows.net/e41ed7bb-472e-4682-9ac0-dd00dfe1aa40/oauth2/authorize HTTP/1.1
client-request-id: dc9c444d-5a14-4e0c-a8af-fa5ad44930e0
return-client-request-id: true
x-client-DM: VMware Virtual Platform
Accept: application/json
x-client-Ver: 4.3.0.0
x-ms-PKeyAuth: 1.0
x-client-CPU: x64
x-client-SKU: PCL.UAP
Host: login.windows.net
Connection: Keep-Alive
Cache-Control: no-cache


HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/json; charset=utf-8
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
client-request-id: dc9c444d-5a14-4e0c-a8af-fa5ad44930e0
x-ms-request-id: cbd2d6c4-57af-4e90-8e8c-fec278b74b00
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
Set-Cookie: esctx=AQABAAAAAAC5una0EUFgTIF8ElaxtWjTyrZcJfJlYlmLZhgPyiVeColz5g03S9fX_lMIQxsDqOLcD48dBrq1lzrwm_R5KQ0aQwBpyf41EMKYybbS9bJF1EARNWl5u68rj09wRyg8VoIcIntNSzLIVCP-M-GM1o5BdHUfESmTTmFObRSnAewkoTTHEyeILstPRJxRPWUFlxkgAA; domain=.login.windows.net; path=/; secure; HttpOnly
Set-Cookie: x-ms-gateway-slice=003; path=/; secure; HttpOnly
Set-Cookie: stsservicecookie=ests; path=/; secure; HttpOnly
Date: Mon, 29 Oct 2018 09:57:15 GMT
Content-Length: 967

{"tenant_discovery_endpoint":"https://login.windows.net/e41ed7bb-472e-4682-9ac0-dd00dfe1aa40/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}

------------------------------------------------------------------
GET https://mykeyvault.vault.azure.net/secrets/ContactManager-AppApiUrl/?api-version=7.0 HTTP/1.1
x-ms-client-request-id: 639b8a72-c739-48c3-b9c3-f60a5ed8fa86
User-Agent: FxVersion/4.6.00001.0 OSName/Windows OSVersion/MicrosoftWindows Microsoft.Azure.KeyVault.KeyVaultClient/3.0.1.0
accept-language: en-US
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dDI7Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N5SEpsWSIsImtpZCI6Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N9SEpsWSJ9.eyJhdWQiOiJodPRwczovL3ZhdWx0LmF6dXJlLm5ldCIsImjzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkyMTEwMmEwLWI2MjEtNDM5Yy04NDY2LTdmZDU0MjE5YWU4Mi8iLCJpYXQiOjE1NDA4MDQyODIsIm5iZiI6MTU0MDgwNDI4MiwiZXhwIjoxNTQwODA4MTgyLCJhaW8iOiI0MlJnWUlnTys5WmZMcjV1cnl6djNUV3Jkd3ZjQXdBPSIsImFwcGlkIjoiZmJmMzdmNDktMTMxMC00N2JjLWE1ZjAtYmY4OWQ4NGUyYmE4IiwiYXBwaWRhY3IiOiIxIiwiZV9leHAiOjI2MjgwMCwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOTIxMTAyYTAtYjYyMS00MzljLTg0NjYtN2ZkNTQyMTlhZTgyLyIsIm9pZCI6IjNiNWQ4OVY1LWNlMGItNGI4Ny1hZDVmLTVmNmUyZjM5N2E1ZSIsInN1YiI6IjNiNWQ4OWY1LWNlMGItNGI4Ny1hZDVmLTVmNmUyZjM5N2E1ZSIsInRpZCI6IjkyMTEwMmEwLWI2MjEtNDM5Yy04NDY2LTdmZDU0MjE5YWU4MiIsInV0aSI6IkhDMTJWZVBoV2tTNjJ5Z0Q1aFlfQUEiLCJ2ZXIiOiIxLjAifQ.Q36_4BxTPnvvZPO9LeTOl95u6CXpK1bmctUQfpFKwkrtMneFwqriCGHU9z_CseL-6uhGpUL_1m1MGUANr7r7HUoJwtteFY1SseTyfmvjjbwx9IkjMWwddV-95SVJxnlM54N6ol2Tn11bifDgSPbIPeDvaJ7JZSclk1FuqZItUdKGPwHHpGl2LP5gvtGbl-N_dypofLD1hZtH9DUFEtnt_ArCn_jN8nRblbe3vuLF9-MtiqF-rLt5Wx6s8gBo96boeBF7SL8weFjQfsNr_Q4ntX9o0IouywtW7rYp6Swo0j-OzfkDewuKBhqOheMtModX6xn1nvamVhldabz4Vjracg
Host: mykeyvault.vault.azure.net
Connection: Keep-Alive
Cache-Control: no-cache


HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
x-ms-keyvault-region: eastus2
x-ms-request-id: d08a432e-00b4-4310-ab8b-90035e8e5626
x-ms-keyvault-service-version: 1.1.0.858
x-ms-keyvault-network-info: addr=165.225.34.51;act_addr_fam=InterNetwork;
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Strict-Transport-Security: max-age=31536000;includeSubDomains
X-Content-Type-Options: nosniff
Date: Mon, 29 Oct 2018 09:57:23 GMT
Content-Length: 270

{"value":"https://testserver.net:8476/api/","id":"https://mykeyvault.vault.azure.net/secrets/ContactManager-AppApiUrl/edd10997e4224a7cb756687e6318d972","attributes":{"enabled":true,"created":1535976474,"updated":1535976474,"recoveryLevel":"Purgeable"}}

------------------------------------------------------------------
@schaabs schaabs added KeyVault 0 - Backlog Client This issue points to a problem in the data-plane of the library. and removed 0 - Backlog labels Jan 17, 2019
@masonyc
Copy link

masonyc commented Jan 5, 2020

Any updates on this one?

@hjaeger
Copy link

hjaeger commented Jan 13, 2020

Anyone have any updates on this one?

@maplemale
Copy link

maplemale commented Jan 17, 2020

Seems odd this is still open and there aren't more replies / participants / followers and votes. As far as i can tell this is the standard way to retrieve secrets from KeyVault. Is there something I'm missing?

Can of course work around this issue and ignore exception, but seems like a foundational bug in the SDK for KeyVault. I have not actually deployed my first app to Azure yet. Is this bug only going to occur in the IDE and maybe why it's not a hot issue?

@JohnBoncek
Copy link

JohnBoncek commented Jan 20, 2020

You're not missing anything as far as I can tell. I get this also, from my App Service deployed to Azure every time it starts up. Issue opened Oct 24, 2018. No one assigned.

@seanbamsft
Copy link

The original issue report describes by-design behavior. The Key Vault client makes an unauthenticated request to AKV. This request returns a 401 with authentication info in the WWW-Authenticate header. The retry handler used by the SDK throws and catches an exception as the response isn't a 2xx value. As this isn't retriable, we get the original 401 in our code, look at the WWW-Authenticate header, then call the user-provided authentication callback, passing in the values from that header. We cache these values, so this 401 only happens on the first request. The very beginning of the issue report says they only observe the exception when they change their debug settings to stop on any exception that is thrown. That exception is going to be caught and handled by the SDK.

@JohnBoncek
Copy link

"By-design" is not necessarily correct. This needs to be fixed. In my opinion, it is never acceptable practice to throw exceptions as part of normal operation, if for no other reason than that it will forever raise questions in users' minds.

@seanbamsft
Copy link

The exception never leaves the shared REST SDK code. The exception is thrown and caught in the same function. It's internal to the design of the shared REST API client and how it determines if operations can be retried. As far as the AKV code is concerned, we call HttpClient.SendAsync and then check if response.StatusCode is HttpStatusCode.Unauthorized. The only reason the exception was observable is because the user turned on the option to see exceptions when they are thrown regardless of whether they're handled. This call still needs to go through the RetryDelegatingHandler in case there is an HTTP 500 response or a timeout, but there's no way to hint to it that a 401 is an expected response, so the retry handler wraps it in an exception, evaluates it against the transient error detection strategy, doesn't retry, catches the exception, and returns the original response. The exception never makes it back to the AKV SDK or to the user's code.

@JohnBoncek
Copy link

This isn't just when running under the debugger. It happens to my App Service running in Azure as well every time it accesses its key vault on startup. I see failures in my Application Map, for instance. Is there something I can do to hide it or exclude it from being logged in that case?

@seanbamsft
Copy link

The 401 response is an expected and documented part of the Key Vault API. It is used to avoid hard coding the AAD login URL and AAD resource URI. Both of these are subject to change and by designing the SDK to discover their value from the WWW-Authenticate header in the 401 response allows these to be updated without requiring all customers to update their services (for example, in Azure Government cloud, the AAD URL changed from login-us.microsoftonline.com to login.microsoftonline.us). Tools like Application Insights that record all HTTP requests will observe that 401. I have not used Application Insights, but I did find a Stack Overflow post that describes how you can treat certain requests as successful.

@maplemale
Copy link

maplemale commented Jan 27, 2020

In my case, I am getting a token by instantiating and using an AzureServiceTokenProvider provider object. That token is being supplied for the AuthenticationCallback class on the KeyVaultClient constructor. I think that would/should avoid this exception? But I am not setting the AzureAdInstance (We are NOT passing it into the AzureServiceTokenProvider constructor).

If you look at: Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider, the default is: "https://login.microsoftonline.com/". Not 100% sure that's right in our case, but I think it is.

I also see a constructor overload for KeyVaultClient which accepts an HttpClient. Perhaps if I retrieve a token from the client provider, create an HttpClient and pass it into the KeyVaultClient constructor that would solve the issue of the 401 exceptions showing up in AppInsights when things are starting up? This isn't something I have the capacity to attempt right now, so I'm asking - giving others ideas for a work around.

I don't care for this exception based programming from MS whether it's by design or not doesn't really matter to me - seems kludge.

@heaths
Copy link
Member

heaths commented Feb 10, 2020

You might upgrade to the Azure.Security.KeyVault.* packages which do not use exception-based flow for authentication. The DefaultAzureCredential from Azure.Identity makes this a trivial exercise, as authentication in general have been greatly improved. For example, you can simply do the following:

var client = new SecretClient(new Uri("https://myvault.vault.azure.net"), new DefaultAzureCredential());
KeyVaultSecret secret = await client.GetSecretAsync("mysecret");

Rather than handling the authentication callbacks yourself, would this be a better option? The older Microsoft.Azure.KeyVault* code will only be receiving critical fixes. The newer libraries have a lot of improvements, some (with more to come) described in https://aka.ms/azsdkvalueprop.

@AlexGhiondea AlexGhiondea added this to the Backlog milestone Mar 2, 2020
@admilazz
Copy link

admilazz commented Apr 10, 2020

Although the exception never leaves the SDK, it has side effects:

  • It causes the entire response stream to be read as a string. This is bad for streaming responses.
  • It emits trace output.

In my case, it's happening with an HTTP 101 Switching Protocols response, which is not in any way erroneous, and the protocol I'm switching to is a streaming one that can't be read all at once.

I can't get too worked up about legitimately failed requests emitting trace output, but I think the determination of what requests are failed needs to be narrowed. In particular, 1xx responses should not be treated as failed. 3xx responses probably should not either. And as for 4xx responses, well many of them are used for normal communications and none of them should really be retried that I can see, except maybe HTTP 429. In general, I think only 5xx responses (and 429 and maybe 423 Locked, but probably not) should trigger a retry.

@heaths
Copy link
Member

heaths commented Apr 11, 2020

Thank you for raising this issue. While the initial exception for the HTTP 401 response is expected in these older Microsoft.Azure.* packages, it is something we do not do in the newer Azure.* packages. The 401 is handled without throwing and the challenge is authenticated automatically using the DefaultAzureCredential or other TokenCredential classes you can use.

As for other HTTP response codes, these changes to Microsoft.Azure.* packages would be breaking behavior. Where Azure.* packages exist, we are only making critical updates to Microsoft.Azure.* packages and recommend that people upgrade. In this case, Azure.Security.KeyVault.Secrets would be what you want.

We are discussing what changes we might make to these newer Azure.* packages to improve performance in error conditions for performance-critical code. While Try-style methods are nice, out parameters cannot be used in async methods, which is what we recommend people use for better performance. When we have actionable proposals, we will open separate issues accordingly.

@heaths heaths closed this as completed Apr 11, 2020
@Jawvig
Copy link

Jawvig commented Oct 30, 2020

For anyone hoping that an upgrade to Azure.Security.KeyVault.Secrets package will get rid of the 401 error shown in Application Insights for the first secret request, I'm afraid I have bad news. It's still there. It still shows up as a failing call to Key Vault in the Application Map and the failure can be viewed in the dependencies table. This is with Azure.Security.KeyVault.Secrets version 4.2.0-beta.2, but we have the issue in 4.1.0 as well.

@sonnyhcl
Copy link

sonnyhcl commented Jun 9, 2021

Raise this issue again. Since KeyVault has service limitation as 2000 transactions/10seconds for RSA2048, if SDK always call API twice for one client query, this will shrink service limit to 1000 transactions/10 seconds.

@heaths
Copy link
Member

heaths commented Jun 9, 2021

The bearer token is cached if you reuse client instances, which is better for performance anyway, and unauthenticated requests against the service do not count against the quota.

@Azure Azure locked as resolved and limited conversation to collaborators Jun 9, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Client This issue points to a problem in the data-plane of the library. KeyVault
Projects
None yet
Development

No branches or pull requests