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

[Core] Support getting SSH certificate inside Cloud Shell #22162

Merged
merged 8 commits into from
May 19, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions scripts/release/debian/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ apt-get update
# uuid-dev is used to build _uuid module: https://github.com/python/cpython/pull/3796
apt-get install -y libssl-dev libffi-dev python3-dev debhelper zlib1g-dev uuid-dev
apt-get install -y wget
# Git is not strictly necessary, but it would allow building an experimental package
# with dependency which is currently only available in its git repo feature branch.
apt-get install -y git
rayluo marked this conversation as resolved.
Show resolved Hide resolved

# Download Python source code
PYTHON_SRC_DIR=$(mktemp -d)
Expand Down
22 changes: 19 additions & 3 deletions src/azure-cli-core/azure/cli/core/auth/adal_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from knack.log import get_logger
from msrestazure.azure_active_directory import MSIAuthentication

from azure.cli.core.util import in_cloud_console
from .util import _normalize_scopes, scopes_to_resource, AccessToken

logger = get_logger(__name__)
Expand All @@ -18,9 +19,24 @@ class MSIAuthenticationWrapper(MSIAuthentication):
def get_token(self, *scopes, **kwargs): # pylint:disable=unused-argument
logger.debug("MSIAuthenticationWrapper.get_token invoked by Track 2 SDK with scopes=%s", scopes)

# In Cloud Shell, we use
# - msrestazure to get access token
# - MSAL to get VM SSH certificate
if 'data' in kwargs:
from azure.cli.core.azclierror import AuthenticationError
raise AuthenticationError("VM SSH currently doesn't support managed identity or Cloud Shell.")
if in_cloud_console():
rayluo marked this conversation as resolved.
Show resolved Hide resolved
import msal
from .util import check_result, build_sdk_access_token
app = msal.PublicClientApplication(
"04b07795-8ddb-461a-bbee-02f9e1bf7b46", # Use a real client_id, so that cache would work
#token_cache=..., # TODO: This PoC does not currently maintain a token cache;
# Ideally we should reuse the real MSAL app object which has cache configured.
)
result = app.acquire_token_interactive(list(scopes), prompt="none", data=kwargs["data"])
rayluo marked this conversation as resolved.
Show resolved Hide resolved
check_result(result)
rayluo marked this conversation as resolved.
Show resolved Hide resolved
return build_sdk_access_token(result)
else:
from azure.cli.core.azclierror import AuthenticationError
raise AuthenticationError("VM SSH currently doesn't support managed identity.")

resource = scopes_to_resource(_normalize_scopes(scopes))
if resource:
Expand Down Expand Up @@ -55,7 +71,7 @@ def set_token(self):
import traceback
from azure.cli.core.azclierror import AzureConnectionError, AzureResponseError
try:
super(MSIAuthenticationWrapper, self).set_token()
super().set_token()
except requests.exceptions.ConnectionError as err:
logger.debug('throw requests.exceptions.ConnectionError when doing MSIAuthentication: \n%s',
traceback.format_exc())
Expand Down
23 changes: 3 additions & 20 deletions src/azure-cli-core/azure/cli/core/auth/msal_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from knack.util import CLIError
from msal import PublicClientApplication, ConfidentialClientApplication

from .util import check_result, AccessToken
from .util import check_result, build_sdk_access_token

# OAuth 2.0 client credentials flow parameter
# https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
Expand Down Expand Up @@ -87,7 +87,7 @@ def get_token(self, *scopes, **kwargs):
# launch browser, but show the error message and `az login` command instead.
else:
raise
return _build_sdk_access_token(result)
return build_sdk_access_token(result)


class ServicePrincipalCredential(ConfidentialClientApplication):
Expand Down Expand Up @@ -130,21 +130,4 @@ def get_token(self, *scopes, **kwargs):
if not result:
result = self.acquire_token_for_client(scopes, **kwargs)
check_result(result)
return _build_sdk_access_token(result)


def _build_sdk_access_token(token_entry):
import time
request_time = int(time.time())

# MSAL token entry sample:
# {
# 'access_token': 'eyJ0eXAiOiJKV...',
# 'token_type': 'Bearer',
# 'expires_in': 1618
# }

# Importing azure.core.credentials.AccessToken is expensive.
# This can slow down commands that doesn't need azure.core, like `az account get-access-token`.
# So We define our own AccessToken.
return AccessToken(token_entry["access_token"], request_time + token_entry["expires_in"])
return build_sdk_access_token(result)
17 changes: 17 additions & 0 deletions src/azure-cli-core/azure/cli/core/auth/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,23 @@ def check_result(result, **kwargs):
return None


def build_sdk_access_token(token_entry):
import time
request_time = int(time.time())

# MSAL token entry sample:
# {
# 'access_token': 'eyJ0eXAiOiJKV...',
# 'token_type': 'Bearer',
# 'expires_in': 1618
# }

# Importing azure.core.credentials.AccessToken is expensive.
# This can slow down commands that doesn't need azure.core, like `az account get-access-token`.
# So We define our own AccessToken.
return AccessToken(token_entry["access_token"], request_time + token_entry["expires_in"])


def decode_access_token(access_token):
# Decode the access token. We can do the same with https://jwt.ms
from msal.oauth2cli.oidc import decode_part
Expand Down
2 changes: 1 addition & 1 deletion src/azure-cli-core/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
'jmespath',
'knack~=0.9.0',
'msal-extensions>=0.3.1,<0.4',
'msal>=1.17.0,<2.0.0',
'msal @ git+https://github.com/AzureAD/microsoft-authentication-library-for-python.git@cloudshell-imds', # TBD: 'msal>=1.18.0,<2.0.0',
'msrestazure~=0.6.4',
'packaging>=20.9,<22.0',
'paramiko>=2.0.8,<3.0.0',
Expand Down
3 changes: 2 additions & 1 deletion src/azure-cli/requirements.py3.Linux.txt
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ jsondiff==1.3.0
knack==0.9.0
MarkupSafe==1.1.1
msal-extensions==0.3.1
msal==1.17.0
#msal==1.17.0
git+https://github.com/AzureAD/microsoft-authentication-library-for-python.git@cloudshell-imds#egg=msal
msrest==0.6.21
msrestazure==0.6.4
oauthlib==3.0.1
Expand Down