1

I am trying to code function app which will get data from Log analytics workspace and push to event hub using python3. Function app uses managed identity.i am using azure sdk for python. my current code looks like this:

def getAzureEventData():
    """
    if "MSI_ENDPOINT" in os.environ:
        print("GeTTING MSI Authentication")
        creds = MSIAuthentication()
    else:
        creds, *_ = get_azure_cli_credentials()         
    """

   ## want to find out which one is correct tested each one.
    creds = DefaultAzureCredential()
    creds=CredentialWrapper()
    creds = MSIAuthentication()
    #creds, _ = get_azure_cli_credentials(resource="https://api.loganalytics.io")

    log_client = LogAnalyticsDataClient(creds)
    
    laQuery = 'ActivityLog | where TimeGenerated > ago(1d)'
    result = log_client.query(cisalog_workspace_id, QueryBody(query=laQuery))

as per examples I have seen ,

creds, _ = get_azure_cli_credentials(resource="https://api.loganalytics.io")

was used, but when I use that function without any DefaultCredential(), then I get 404 error which says System managed identity is not enabled. when I use DefualtCrednetial I get access_token error and as per suggestion I am using wrapper found in internet. when I use that, I get Exception: ErrorResponseException: (InvalidTokenError) The provided authentication is not valid for this resource. So I am confused how to use Loganalytics SDK client. I am testing in local and also in portal. My end goal is a function app using system managed identity with IAM roles to access LA workspace . I have granted Monitoring reader role on workspace to SMI. still facing issue.

1
  • Very hard to read your description. Could you please plit it into paragraphs? Commented Nov 18, 2020 at 20:01

1 Answer 1

2

If you want to call Azure Log Analytics Rest API in Azure function with AzureMSI, you need to assign Azure RABC role Log Analytics Reader to the MSI. For more details, please refer to here.

For example

  1. Enable Azure Function MSI

  2. Assign role

New-AzRoleAssignment -ObjectId "<the objectId of Azure function MSI>" -RoleDefinitionName "Log Analytics Reader" -Scope "/subscriptions/{subId}"
  1. Code

My cred_wrapper.py

from msrest.authentication import BasicTokenAuthentication
from azure.core.pipeline.policies import BearerTokenCredentialPolicy
from azure.core.pipeline import PipelineRequest, PipelineContext
from azure.core.pipeline.transport import HttpRequest

from azure.identity import DefaultAzureCredential


class CredentialWrapper(BasicTokenAuthentication):
    def __init__(self, credential=None, resource_id="https://westus2.api.loganalytics.io/.default", **kwargs):
        """Wrap any azure-identity credential to work with SDK that needs azure.common.credentials/msrestazure.
        Default resource is ARM (syntax of endpoint v2)
        :param credential: Any azure-identity credential (DefaultAzureCredential by default)
        :param str resource_id: The scope to use to get the token (default ARM)
        """
        super(CredentialWrapper, self).__init__(None)
        if credential is None:
            #credential = DefaultAzureCredential()
            credential = DefaultAzureCredential()
        self._policy = BearerTokenCredentialPolicy(
            credential, resource_id, **kwargs)

    def _make_request(self):
        return PipelineRequest(
            HttpRequest(
                "CredentialWrapper",
                "https://fakeurl"
            ),
            PipelineContext(None)
        )

    def set_token(self):
        """Ask the azure-core BearerTokenCredentialPolicy policy to get a token.
        Using the policy gives us for free the caching system of azure-core.
        We could make this code simpler by using private method, but by definition
        I can't assure they will be there forever, so mocking a fake call to the policy
        to extract the token, using 100% public API."""
        request = self._make_request()
        self._policy.on_request(request)
        # Read Authorization, and get the second part after Bearer
        token = request.http_request.headers["Authorization"].split(" ", 1)[1]
        self.token = {"access_token": token}

    def signed_session(self, session=None):
        self.set_token()
        return super(CredentialWrapper, self).signed_session(session)

My function code

import logging
from azure.loganalytics import LogAnalyticsDataClient
from .cred_wrapper import CredentialWrapper
import azure.functions as func
from azure.loganalytics.models import QueryBody
import json


def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    creds = CredentialWrapper()
    client = LogAnalyticsDataClient(creds)
    result = client.query(workspace_id='',
                          body=QueryBody(query='Heartbeat | take 10'))
    return func.HttpResponse(
        json.dumps(result.tables[0].rows),
        status_code=200
    )

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.