microsoft / msticpy

Microsoft Threat Intelligence Security Tools
Other
1.72k stars 310 forks source link

[Bug]: Username-Password Credentials in Environmental Variables don't Work #712

Closed cindraw closed 9 months ago

cindraw commented 9 months ago

Describe the bug Initializing environmental variables for username and password as follows gives an error when trying to connect to a Log Analytics Query Provider when auth_methods is set only for env.

os.environ['AZURE_USERNAME'] = 'my_username'
os.environ['AZURE_PASSWORD'] = 'my_password'
os.environ['AZURE_TENANT_ID'] = 'tenant_id'

To Reproduce Steps to reproduce the behavior:

  1. Import QueryProvider - from msticpy.data.data_providers import QueryProvider
  2. Initialize environmental variables as above
  3. Initialize msticpyconfig.yaml with 'auth_methods': ['env']
  4. Run QueryProvider.connect()
    query_provider = QueryProvider(data_environment='LogAnalytics')
    query_provider.connect()
  5. See error

Expected behavior No errors and successful connection to the pointed Log Analytics Workspace

Screenshots and/or Traceback Stack trace seem to indicate that the env authorization method fails because no (applicable) environmental variables exist. See context for more information.

Environment (please complete the following information):

Additional context It seems there are contradiction between the documentation and the actual working code: image

def az_connect(
    auth_methods: Optional[List[str]] = None,
    tenant_id: Optional[str] = None,
    silent: bool = False,
    **kwargs,
) -> AzCredentials:
    """
    Connect to Azure SDK/API.

    Parameters
    ----------
    auth_methods : List[str], optional
        List of authentication methods to try
        For a list of possible authentication methods use the `list_auth_methods`
        function.
        Default is ["env", "msi", "vscode", "cli", "powershell", "devicecode"]
    tenant_id : str, optional
        The tenant to authenticate against. If not supplied, the default
        tenant for the identity will be used.
    silent : bool, optional
        Set True to hide all output during connection, by default False
    credential : AzureCredential
        If an Azure credential is passed, it will be used directly.
    cloud : str, optional
        What Azure cloud to connect to.
        By default it will attempt to use the cloud setting from config file.
        If this is not set it will default to Azure Public Cloud

    Returns
    -------
    AzCredentials
        Named tuple of:
        - legacy (ADAL) credentials
        - modern (MSAL) credentials

    Raises
    ------
    CloudError
        If chained token credential creation fails.

    See Also
    --------
    list_auth_methods

    """
    az_cloud_config = AzureCloudConfig(cloud=kwargs.get("cloud"))
    # Use auth_methods param or configuration defaults
    data_provs = get_provider_settings(config_section="DataProviders")
    auth_methods = auth_methods or az_cloud_config.auth_methods

    # Ignore AzCLI settings except for authentication creds for EnvCred
    az_cli_config = data_provs.get("AzureCLI")
    if (
        az_cli_config
        and az_cli_config.args
        and isinstance(auth_methods, list)
        and "env" in auth_methods
    ):
        os.environ[AzureCredEnvNames.AZURE_CLIENT_ID] = (
            az_cli_config.args.get("clientId") or ""
        )
        os.environ[AzureCredEnvNames.AZURE_TENANT_ID] = (
            az_cli_config.args.get("tenantId") or ""
        )
        os.environ[AzureCredEnvNames.AZURE_CLIENT_SECRET] = (
            az_cli_config.args.get("clientSecret") or ""
        )
    credentials = az_connect_core(
        auth_methods=auth_methods, tenant_id=tenant_id, silent=silent, **kwargs
    )
    sub_client = SubscriptionClient(
        credential=credentials.modern,
        base_url=az_cloud_config.endpoints.resource_manager,  # type: ignore
        credential_scopes=[az_cloud_config.token_uri],
    )
    if not sub_client:
        raise CloudError("Could not create a Subscription client.")

    return credentials

Please let me know if the feature was removed or if it's planned for addition any time soon.

ianhelle commented 9 months ago

Looks like we partially implemented environment credential - for client_id/secret. The first variant shown here https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet

I'll see if I can add at least the username/password and maybe the certificate-based one.

A workaround would be to create an env var AZURE_CLIENT_SECRET and just set it to a dummy value. But I will try to implement the checks correctly