MicrosoftDocs / azure-docs

Open source documentation of Microsoft Azure
https://docs.microsoft.com/azure
Creative Commons Attribution 4.0 International
10.2k stars 21.36k forks source link

Unclear instructions to run the function locally #118875

Closed Astral100 closed 2 months ago

Astral100 commented 8 months ago

Under "(Optional) Run the function locally" section it only mentions that you need to setup COSMOS_ENDPOINT setting in your local.settings.json in order to run the function locally.

This is wrong, because running function locally like this fails with Request blocked by Auth <my cosmos account> : Request is blocked because principal [89c3cdb1-438c-4e04-a16d-...........] does not have required RBAC permissions to perform action [Microsoft.DocumentDB/databaseAccounts/readMetadata] on resource [/]

The principal id returned in this message is different from the principal id of my azure function.

I understand that my local account has a different principal Id from the system-assigned principle id in my function on Azure. However the document does not explain how to set the same system-assigned principle Id in my local environment and so I am unable to run the function locally.


Document Details

Do not edit this section. It is required for learn.microsoft.com ➟ GitHub issue linking.

seesharprun commented 8 months ago

You are correct that RBAC and security is a weakness in our current Azure Cosmos DB documentation. There's work coming up in the next two months to rework these articles entirely. I'll follow up on this issue as we make progress.

Astral100 commented 8 months ago

@seesharprun Could you point me to the more relevant documentation though? Or explain what I should do to run the function locally with the same system-assigned principle id?

SaibabaBalapur-MSFT commented 8 months ago

@Astral100 I'm going to assign this to the document author @seesharprun so he can take a look at it accordingly.

seesharprun commented 2 months ago

@Astral100, I am publishing an update to this article later today that will include steps on using RBAC to assign your local account permissions to access the data. Functionally, the steps will work like this:

az ad signed-in-user show --query "id"
az cosmosdb sql role assignment create \
    --resource-group $resourceGroupName \
    --account-name $cosmosName \
    --role-definition-id "00000000-0000-0000-0000-000000000002" \
    --principal-id "<your-principal-id>" \
    --scope "/"

Long term, this article is being entirely replaced with a better article that spells out how to do this in minute detail. That documentation doesn't exist today.

Astral100 commented 2 months ago

I have long since solved this issue and forgotten about it :)

I don't remember exactly the solution, but the following code from my Setup class may help:

public static class SetupDi
{
    public static void SetupDataAccessDi(this IServiceCollection services, HostBuilderContext hostContext)
    {
        var sqlDbConnectionString = hostContext.Configuration.GetSection(CoreConstants.AppSettingsConnectionStringKey).Value;
        services.AddSingleton<ISqlDataAccess>(x => new SqlDataAccess(sqlDbConnectionString));

        var isLocalDebugging = Environment.GetEnvironmentVariable("LocalDebugging") == "true";

        services.AddSingleton<CosmosClient>(sp =>
        {
            var cosmosDbEndpoint = Environment.GetEnvironmentVariable("MyCosmosDb__accountEndpoint", EnvironmentVariableTarget.Process);

            var credentials = isLocalDebugging ?
                new DefaultAzureCredential(GetLocalCredentialOptions()) : // running locally
                new DefaultAzureCredential(); // running on Azure 

            var options = new CosmosClientOptions()
            {
                AllowBulkExecution = true
            };

            if (isLocalDebugging)
            {
                options.ConnectionMode = ConnectionMode.Gateway;
            }

            return new CosmosClient(cosmosDbEndpoint, credentials, options);
        });

        services.AddSingleton<IUserDataRepository, UserDataRepository>();
        services.AddSingleton<ICosmosDataAccess, CosmosDataAccess>();
    }

    private static DefaultAzureCredentialOptions GetLocalCredentialOptions()
    {
        return new DefaultAzureCredentialOptions()
        {
            ExcludeManagedIdentityCredential = true,
            // ExcludeAzureCliCredential = true,
            ExcludeAzureDeveloperCliCredential = true,
            ExcludeAzurePowerShellCredential = true,
            ExcludeEnvironmentCredential = true,

            ExcludeInteractiveBrowserCredential = true,
            ExcludeSharedTokenCacheCredential = true,
            ExcludeVisualStudioCodeCredential = true,
            ExcludeVisualStudioCredential = true,
            ExcludeWorkloadIdentityCredential = true,
        };
    }
}

and

public class Program
{
    public static void Main()
    {
        var host = new HostBuilder()
            .ConfigureFunctionsWorkerDefaults()
            .ConfigureAppConfiguration(builder =>
            {
                builder.SetupReplicaServiceConfiguration();
            })
            .ConfigureServices((hostContext, services) =>
            {
                services.SetupReplicaServiceDi(hostContext);
            })
        .Build();

        host.Run();
    }
}

I also believe I granted the same permissions to my machine principal ID running the similar script from your post. Hope this can help