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

Can't resolve Keyvault reference in App Config with managed identity #15805

Closed
nilsga opened this issue Nov 5, 2020 · 5 comments
Closed

Can't resolve Keyvault reference in App Config with managed identity #15805

nilsga opened this issue Nov 5, 2020 · 5 comments
Labels
App Configuration Service Attention This issue is responsible by Azure service team.

Comments

@nilsga
Copy link

nilsga commented Nov 5, 2020

Describe the bug

Resolving a keyvault reference through App Config, with a VM managed identity does not work.

Command Name
az appconfig kv list

Errors:

'MSIAuthenticationWrapper' object has no attribute '_token_retriever'

To Reproduce:

Steps to reproduce the behavior.

  • Create a VM with a managed identity
  • Create a keyvault, and give VM access policy to get and list secrets
  • Create an App Config instance
  • Add a keyvault reference, say testsecret/keyvaultref
  • From the VM, run az appconfig kv list --name <appconfig_name> --key 'testsecret/*' --resolve-keyvault

Expected Behavior

The value should be resolved from the keyvault.

Environment Summary

Linux-5.4.0-1031-azure-x86_64-with-debian-buster-sid
Python 3.6.10
Installer: DEB

azure-cli 2.14.0

Additional Context

Stacktrace:

msrestazure.azure_active_directory : MSI: Token retrieved
azure.cli.core.util.handle_exception is called with an exception:
Traceback (most recent call last):
  File "/opt/az/lib/python3.6/site-packages/azure/cli/command_modules/appconfig/_kv_helpers.py", line 982, in __resolve_secret
    secret_version=kv_identifier.version)
  File "/opt/az/lib/python3.6/site-packages/azure/keyvault/v7_0/key_vault_client.py", line 1843, in get_secret
    response = self._client.send(request, header_parameters, stream=False, **operation_config)
  File "/opt/az/lib/python3.6/site-packages/msrest/service_client.py", line 336, in send
    pipeline_response = self.config.pipeline.run(request, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/pipeline/__init__.py", line 197, in run
    return first_node.send(pipeline_request, **kwargs)  # type: ignore
  File "/opt/az/lib/python3.6/site-packages/msrest/pipeline/__init__.py", line 150, in send
    response = self.next.send(request, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/pipeline/requests.py", line 72, in send
    return self.next.send(request, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/pipeline/requests.py", line 137, in send
    return self.next.send(request, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/pipeline/__init__.py", line 150, in send
    response = self.next.send(request, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/pipeline/requests.py", line 193, in send
    self.driver.send(request.http_request, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/universal_http/requests.py", line 333, in send
    return super(RequestsHTTPSender, self).send(request, **requests_kwargs)
  File "/opt/az/lib/python3.6/site-packages/msrest/universal_http/requests.py", line 142, in send
    **kwargs)
  File "/opt/az/lib/python3.6/site-packages/requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "/opt/az/lib/python3.6/site-packages/requests/sessions.py", line 653, in send
    r = dispatch_hook('response', hooks, r, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/requests/hooks.py", line 31, in dispatch_hook
    _hook_data = hook(hook_data, **kwargs)
  File "/opt/az/lib/python3.6/site-packages/azure/keyvault/key_vault_authentication.py", line 146, in _handle_401
    security = self._get_message_security(prep, challenge)
  File "/opt/az/lib/python3.6/site-packages/azure/keyvault/key_vault_authentication.py", line 172, in _get_message_security
    scheme))
  File "/opt/az/lib/python3.6/site-packages/azure/keyvault/key_vault_authentication.py", line 61, in _auth_callback_compat
    if len(inspect.getargspec(self._user_callback).args) == 3 \
  File "/opt/az/lib/python3.6/site-packages/azure/cli/command_modules/appconfig/_kv_helpers.py", line 969, in _get_token
    return Profile(cli_ctx=cli_ctx).get_login_credentials(resource)[0]._token_retriever()  # pylint: disable=protected-access
AttributeError: 'MSIAuthenticationWrapper' object has no attribute '_token_retriever'
@ghost ghost added needs-triage This is a new issue that needs to be triaged to the appropriate team. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that labels Nov 5, 2020
@ghost ghost removed the needs-triage This is a new issue that needs to be triaged to the appropriate team. label Nov 5, 2020
@yonzhan yonzhan added Service Attention This issue is responsible by Azure service team. and removed question The issue doesn't require a change to the product in order to be resolved. Most issues start as that labels Nov 5, 2020
@ghost
Copy link

ghost commented Nov 5, 2020

Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @shenmuxiaosen, @avanigupta.

@yonzhan
Copy link
Collaborator

yonzhan commented Nov 5, 2020

appconfig

@shenmuxiaosen
Copy link
Contributor

Hi @nilsga ,
Thanks for reporting this issue. It is due to a bug in our implementation that blocks the MSI authentication flow to key vault. It currently only works when login with user account. Will send a fix.

@jiasli
Copy link
Member

jiasli commented Nov 6, 2020

The code from appconfig is calling _token_retriever:

return Profile(cli_ctx=cli_ctx).get_login_credentials(resource)[0]._token_retriever() # pylint: disable=protected-access

However, _token_retriever is only available for AdalAuthentication which is designed for user and service principal credentials. It is not available for managed identity credential MSIAuthenticationWrapper.

class AdalAuthentication(Authentication): # pylint: disable=too-few-public-methods
def __init__(self, token_retriever, external_tenant_token_retriever=None):
self._token_retriever = token_retriever

Also, _token_retriever is a protected member, so calling it from outside is not supported.

There are 2 correct ways to get a raw token:

  1. Call get_raw_token:
    def get_raw_token(self, resource=None, subscription=None, tenant=None):
  2. (The track 2 approach) Get the credential with get_login_credentials, then call get_token:
    def get_token(self, *scopes, **kwargs): # pylint:disable=unused-argument

If you only need to create a keyvault client, you may simply use the client factory from keyvault command module:

def keyvault_data_plane_factory(cli_ctx, _):

It has been proved to work with both user credential and managed identity credential and has better error handling logic. + @bim-msft for awareness.

@bim-msft
Copy link
Contributor

bim-msft commented Nov 9, 2020

Fixed by #15826
Will take effect at our upcoming release train (Nov 17).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
App Configuration Service Attention This issue is responsible by Azure service team.
Projects
None yet
Development

No branches or pull requests

5 participants