-
Notifications
You must be signed in to change notification settings - Fork 7
Enable TNU to use Azure auth for DRS operations #399 #401
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
Merged
mbaumann-broad
merged 11 commits into
master
from
mbaumann-issue-399-add-drs-azure-auth
Jan 25, 2023
Merged
Changes from 4 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
4ab9951
Initial implementation of Azure auth support for DRS
6b5fdd5
Add /.venv to .gitignore
d6d42d7
Suppress extraneous INFO level logging by azure-identity
37e4018
Change get_execution_context to work better in the common cases
a99fc77
Added unit test for utils.get_execution_context
f6e234e
Add unit tests for azure_auth.py
b12651a
Add unit tests for terra_auth.py
15cd61c
Update README for drs subcommand support in Terra Azure
237c672
Change enums values from int to string
d4ee570
Add log level type specifier
d84d3e5
Correct code comments
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
azure-identity >= 1.12.0, < 2 | ||
google-cloud-storage >= 1.38.0, < 2 | ||
gs-chunked-io >= 0.5.1, < 0.6 | ||
firecloud | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
""" | ||
Microsoft Azure identity/auth support. | ||
|
||
See: | ||
https://azuresdkdocs.blob.core.windows.net/$web/python/azure-identity/1.12.0/index.html | ||
https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python | ||
https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/identity/azure-identity/azure/identity/_credentials/default.py | ||
""" | ||
import logging | ||
import os | ||
from typing import Optional | ||
|
||
from azure.identity import DefaultAzureCredential | ||
from terra_notebook_utils.logger import logger | ||
|
||
|
||
# Single instance of DefaultAzureCredential that initialized lazily. | ||
# The instance is treated as threadsafe and reusable. | ||
# The Azure documentation is silent on thread safety. | ||
# Based on scanning the code, it appears to be threadsafe. | ||
# See: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/identity/ | ||
# azure-identity/azure/identity/_credentials/default.py | ||
_AZURE_CREDENTIAL: Optional[DefaultAzureCredential] = None | ||
|
||
|
||
def _set_azure_identity_logging_level(level) -> None: | ||
mbaumann-broad marked this conversation as resolved.
Show resolved
Hide resolved
|
||
""" Set the logging level for modules participating the Azure default credential flow """ | ||
import azure.identity | ||
logging.getLogger(azure.identity._credentials.environment.__name__).setLevel(level) | ||
logging.getLogger(azure.identity._credentials.managed_identity.__name__).setLevel(level) | ||
logging.getLogger(azure.identity._credentials.chained.__name__).setLevel(level) | ||
logging.getLogger("azure.core.pipeline.policies.http_logging_policy").setLevel(level) | ||
|
||
|
||
# Suppress extraneous azure-identity INFO level logging | ||
_set_azure_identity_logging_level(logging.WARNING) | ||
|
||
|
||
def _get_default_credential() -> DefaultAzureCredential: | ||
""" | ||
Instantiate DefaultAzureCredential lazily if/when needed. | ||
|
||
Note: It would not need to be instantiated this way, as | ||
# no exception is raised even if Azure credentials are not configured. | ||
:return: Reference to instance of DefaultAzureCredential | ||
""" | ||
|
||
# Should a more sophisticated Singleton pattern be used instead? | ||
global _AZURE_CREDENTIAL | ||
if not _AZURE_CREDENTIAL: | ||
_AZURE_CREDENTIAL = DefaultAzureCredential() | ||
mbaumann-broad marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return _AZURE_CREDENTIAL | ||
|
||
|
||
def get_azure_access_token() -> str: | ||
""" | ||
Return an Azure access token. | ||
|
||
raises ClientAuthenticationError | ||
""" | ||
if os.environ.get('TERRA_NOTEBOOK_AZURE_ACCESS_TOKEN'): | ||
logger.debug("Using Azure token configured using 'TERRA_NOTEBOOK_AZURE_ACCESS_TOKEN'") | ||
token = os.environ['TERRA_NOTEBOOK_AZURE_ACCESS_TOKEN'] | ||
else: | ||
logger.debug("Requesting Azure default credentials token.") | ||
token_scope = "https://management.azure.com/.default" | ||
azure_token = _get_default_credential().get_token(token_scope) | ||
logger.debug("Using Azure default credentials token.") | ||
token = azure_token.token | ||
return token |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import json | ||
import logging | ||
from logging import Logger | ||
|
||
logger = logging.getLogger(__name__) | ||
logger: Logger = logging.getLogger(__name__) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
""" | ||
Support for auth with Terra backend services. | ||
""" | ||
from azure.core.exceptions import ClientAuthenticationError | ||
from google.auth.exceptions import DefaultCredentialsError | ||
|
||
from terra_notebook_utils import azure_auth, gs, ExecutionPlatform | ||
from terra_notebook_utils.logger import logger | ||
from terra_notebook_utils.utils import get_execution_context | ||
|
||
|
||
class AuthenticationError(Exception): | ||
pass | ||
|
||
|
||
class TerraAuthTokenProvider: | ||
""" | ||
Provides auth bearer tokens suitable for use with Terra backend services. | ||
""" | ||
def __init__(self): | ||
self.execution_context = get_execution_context() | ||
|
||
@staticmethod | ||
def _identify_valid_access_token() -> str: | ||
""" | ||
Try to obtain an auth bearer tokens suitable for use with Terra backend services | ||
mbaumann-broad marked this conversation as resolved.
Show resolved
Hide resolved
|
||
from the Terra supported auth providers. First try Google, then try Azure. | ||
Return the first successfully obtained token, otherwise raise AuthenticationError. | ||
|
||
:return: auth bearer token suitable for use with Terra backend services | ||
:raises: AuthenticationError | ||
""" | ||
try: | ||
mbaumann-broad marked this conversation as resolved.
Show resolved
Hide resolved
|
||
logger.debug("Attempting to obtain a Google access token to use with Terra backend services.") | ||
google_token = gs.get_access_token() | ||
logger.debug("Using Google access token to use with Terra backend services.") | ||
return google_token | ||
except DefaultCredentialsError as ex: | ||
logger.debug("Failed to obtain a Google access token to use with Terra backend services.", exc_info=ex) | ||
|
||
try: | ||
logger.debug("Attempting to obtain a Azure access token to use with Terra backend services.") | ||
azure_token = azure_auth.get_azure_access_token() | ||
logger.debug("Using Azure access token to use with Terra backend services.") | ||
return azure_token | ||
except ClientAuthenticationError as ex: | ||
logger.debug("Failed to obtain a Azure access token to use with Terra backend services.", exc_info=ex) | ||
|
||
raise AuthenticationError("Failed to obtain a Google or Azure token to auth with Terra backend services.") | ||
|
||
def get_terra_access_token(self) -> str: | ||
if self.execution_context.execution_platform == ExecutionPlatform.GOOGLE: | ||
logger.debug("Using Google default credentials to auth with Terra services.") | ||
return gs.get_access_token() | ||
elif self.execution_context.execution_platform == ExecutionPlatform.AZURE: | ||
logger.debug("Using Azure default credentials to auth with Terra services.") | ||
return azure_auth.get_azure_access_token() | ||
else: | ||
return self._identify_valid_access_token() | ||
|
||
|
||
# Single instance of TerraAuthTokenProvider. | ||
TERRA_AUTH_TOKEN_PROVIDER = TerraAuthTokenProvider() | ||
|
||
|
||
def get_terra_access_token() -> str: | ||
""" Return an auth bearer token suitable for use with Terra backend services. | ||
:raises: AuthenticationError | ||
""" | ||
return TERRA_AUTH_TOKEN_PROVIDER.get_terra_access_token() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.