Usar .NET para gerenciar ACLs no Azure Data Lake Storage Gen2

Este artigo mostra como usar o .NET para obter, definir e atualizar as listas de controle de acesso de diretórios e arquivos.

A herança de ACL já está disponível para novos itens filho que são criados em um diretório pai. Mas você também pode adicionar, atualizar e remover ACLs recursivamente nos itens filho existentes de um diretório pai sem precisar fazer essas alterações individualmente em cada item filho.

Pacote (NuGet) | Exemplos | Referência de API | Mapeamento de Gen1 para Gen2 | Enviar comentários

Pré-requisitos

  • Uma assinatura do Azure. Consulte Obter a avaliação gratuita do Azure.

  • Uma conta de armazenamento precisa ter o HNS (namespace hierárquico) habilitado. Siga estas instruções para criar um.

  • CLI do Azure versão 2.6.0 ou superior

  • Uma das seguintes permissões de segurança:

    • Uma entidade de segurança do Microsoft Entra ID provisionada à qual foi atribuída a função de Proprietário de Dados do Blob de Armazenamento no escopo do contêiner, conta de armazenamento, grupo de recursos pai ou assinatura de destino.

    • Usuário proprietário do contêiner ou diretório de destino ao qual você planeja aplicar as configurações de ACL. Para definir ACLs recursivamente, isso inclui todos os itens filho no contêiner ou diretório de destino.

    • Chave de conta de armazenamento.

Configurar o seu projeto

Para começar, instale o pacote NuGet do Azure. Storage. files. datalake.

  1. Abra uma janela de comando (por exemplo: Windows PowerShell).

  2. No diretório do projeto, instale o pacote de visualização do Azure. Storage. files. datalake usando o dotnet add package comando.

    dotnet add package Azure.Storage.Files.DataLake -v 12.6.0 -s https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json
    

    Então, adicione o seguinte usando as instruções na parte superior do seu arquivo de código.

    using Azure;
    using Azure.Core;
    using Azure.Storage;
    using Azure.Storage.Files.DataLake;
    using Azure.Storage.Files.DataLake.Models;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    

Conectar à conta

Para usar os trechos de código neste artigo, será necessário criar uma instância de DataLakeServiceClient que representa a conta de armazenamento.

Conectar usando o Microsoft Entra ID

Observação

Se estiver utilizando o Microsoft Entra ID para autorizar o acesso, verifique se a entidade de segurança foi atribuída à função Proprietário de Dados do Blob de Armazenamento. Para saber mais sobre como as permissões de ACL são aplicadas e os efeitos de alterá-las, confira Modelo de controle de acesso no Azure Data Lake Storage Gen2.

Você pode usar a biblioteca de clientes de identidade do Azure para .NET para autenticar seu aplicativo com a ID do Microsoft Entra.

Depois de instalar o pacote, adicione esta instrução usando à parte superior do seu arquivo de código.

using Azure.Identity;

Como parte desse processo, primeiro será necessário atribuir uma das seguintes funções do RBAC do Azure (controle de acesso baseado em função do Azure) à sua entidade de segurança:

Função Capacidade de configuração de ACL
Proprietário de Dados do Blob de Armazenamento Todos os diretórios e arquivos na conta.
Colaborador de dados de blob de armazenamento Somente diretórios e arquivos de propriedade da entidade de segurança.

Em seguida, crie uma instância DataLakeServiceClient e passe em uma nova instância da classe DefaultAzureCredential.

public static DataLakeServiceClient GetDataLakeServiceClient(string accountName)
{
    string dfsUri = $"https://{accountName}.dfs.core.windows.net";

    DataLakeServiceClient dataLakeServiceClient = new DataLakeServiceClient(
        new Uri(dfsUri),
        new DefaultAzureCredential());

    return dataLakeServiceClient;
}

Para saber mais sobre como usar DefaultAzureCredential para autorizar o acesso a dados, confira Como autenticar aplicativos .NET com os serviços do Azure.

Conectar-se usando uma chave de conta

Você pode autorizar o acesso aos dados usando as chaves de acesso da sua conta (Chave Compartilhada). Esse exemplo cria uma instância DataLakeServiceClient autorizada com a chave de conta.

public static DataLakeServiceClient GetDataLakeServiceClient(string accountName, string accountKey)
{
    StorageSharedKeyCredential sharedKeyCredential =
        new StorageSharedKeyCredential(accountName, accountKey);

    string dfsUri = $"https://{accountName}.dfs.core.windows.net";

    DataLakeServiceClient dataLakeServiceClient = new DataLakeServiceClient(
        new Uri(dfsUri),
        sharedKeyCredential);

    return dataLakeServiceClient;
}

Cuidado

A autorização com Chave Compartilhada não é recomendada, pois pode ser menos segura. Para uma segurança ideal, desabilite a autorização por meio da Chave Compartilhada para sua conta de armazenamento, conforme descrito em Impedir autorização de Chave Compartilhada para uma conta do Armazenamento do Microsoft Azure.

O uso de chaves de acesso e cadeias de conexão deve ser limitado a aplicativos iniciais de prova de conceito ou protótipos de desenvolvimento que não acessem dados confidenciais ou de produção. Caso contrário, as classes de autenticação baseadas em token disponíveis no SDK do Azure devem ser sempre preferenciais ao autenticar recursos do Azure.

A Microsoft recomenda que os clientes usem o Microsoft Entra ID ou uma assinatura de acesso compartilhado (SAS) para autorizar o acesso aos dados no Armazenamento do Microsoft Azure. Para obter mais informações, confira Autorizar operações para acesso a dados.

Definir ACLs

Aodefiniruma ACL, vocêsubstitui toda a ACL, incluindo todas as entradas. Se você quiser alterar o nível de permissão de uma entidade de segurança ou adicionar uma nova entidade de segurança à ACL sem afetar outras entradas existentes, deverá atualizar a ACL. Para atualizar uma ACL em vez de substituí-la, confira a seção Atualizar ACLs deste artigo.

Se você optar pordefinira ACL, deverá adicionar uma entrada para o usuário proprietário, uma entrada para o grupo proprietário e uma entrada para todos os outros usuários. Para saber mais sobre o usuário proprietário, o grupo proprietário e todos os outros usuários, confira Usuários e identidades.

Esta seção mostra como:

  • Definir o ACL de um diretório
  • Definir o ACL de um arquivo
  • Definir ACLs recursivamente

Definir o ACL de um diretório

Obtenha a ACL (lista de controle de acesso) de um diretório chamando o método DataLakeDirectoryClient. GetAccessControlAsync e defina a ACL chamando o método DataLakeDirectoryClient. setaccesscontrollist.

Este exemplo obtém e define a ACL de um diretório chamado my-directory. A cadeia de caracteres user::rwx,group::r-x,other::rw- fornece as permissões de leitura, gravação e execução do usuário proprietário, fornece ao grupo proprietário somente permissões de leitura e execução e concede a todos os outros permissões de leitura e gravação.

public async Task ManageDirectoryACLs(DataLakeFileSystemClient fileSystemClient)
{
    DataLakeDirectoryClient directoryClient =
      fileSystemClient.GetDirectoryClient("");

    PathAccessControl directoryAccessControl =
        await directoryClient.GetAccessControlAsync();

    foreach (var item in directoryAccessControl.AccessControlList)
    {
        Console.WriteLine(item.ToString());
    }

    IList<PathAccessControlItem> accessControlList
        = PathAccessControlExtensions.ParseAccessControlList
        ("user::rwx,group::r-x,other::rw-");

    directoryClient.SetAccessControlList(accessControlList);

}

Também é possível obter e definir a ACL do diretório raiz de um contêiner. Para obter o diretório raiz, passe uma cadeia de caracteres vazia ( "" ) para o método DataLakeFileSystemClient. GetDirectoryClient.

Definir o ACL de um arquivo

Obtenha a ACL (lista de controle de acesso) de um arquivo chamando o método DataLakeFileClient. GetAccessControlAsync e defina a ACL chamando o método DataLakeFileClient. setaccesscontrollist.

Este exemplo obtém e define a ACL de um arquivo chamado my-file.txt. A cadeia de caracteres user::rwx,group::r-x,other::rw- fornece as permissões de leitura, gravação e execução do usuário proprietário, fornece ao grupo proprietário somente permissões de leitura e execução e concede a todos os outros permissões de leitura e gravação.

public async Task ManageFileACLs(DataLakeFileSystemClient fileSystemClient)
{
    DataLakeDirectoryClient directoryClient =
        fileSystemClient.GetDirectoryClient("my-directory");

    DataLakeFileClient fileClient =
        directoryClient.GetFileClient("hello.txt");

    PathAccessControl FileAccessControl =
        await fileClient.GetAccessControlAsync();

    foreach (var item in FileAccessControl.AccessControlList)
    {
        Console.WriteLine(item.ToString());
    }

    IList<PathAccessControlItem> accessControlList
        = PathAccessControlExtensions.ParseAccessControlList
        ("user::rwx,group::r-x,other::rw-");

    fileClient.SetAccessControlList(accessControlList);
}

Definir ACLs recursivamente

Defina ACLs recursivamente chamando o método DataLakeDirectoryClient. SetAccessControlRecursiveAsync. Passe este método uma lista de PathAccessControlItem. Cada PathAccessControlItem define uma entrada de ACL.

Se você quiser definir uma entrada ACL padrão, poderá definir a propriedade PathAccessControlItem. DefaultScope de PathAccessControlItem como true.

Este exemplo define a ACL de um diretório chamado my-parent-directory. Esse método aceita um parâmetro booliano chamado isDefaultScope que especifica se a ACL padrão deve ser definida. Esse parâmetro é usado no construtor do PathAccessControlItem. A cadeia de caracteres do ACL fornece as permissões de leitura, gravação e execução do usuário proprietário, fornece ao grupo proprietário somente permissões de leitura e execução e não concede acessos a todos os outros. A última entrada de ACL neste exemplo fornece um usuário específico com as permissões de leitura e execução da ID de objeto xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.

    public async Task SetACLRecursively(DataLakeServiceClient serviceClient, bool isDefaultScope)
{
    DataLakeDirectoryClient directoryClient =
        serviceClient.GetFileSystemClient("my-container").
            GetDirectoryClient("my-parent-directory");

    List<PathAccessControlItem> accessControlList =
        new List<PathAccessControlItem>()
    {
new PathAccessControlItem(AccessControlType.User,
    RolePermissions.Read |
    RolePermissions.Write |
    RolePermissions.Execute, isDefaultScope),

new PathAccessControlItem(AccessControlType.Group,
    RolePermissions.Read |
    RolePermissions.Execute, isDefaultScope),

new PathAccessControlItem(AccessControlType.Other,
    RolePermissions.None, isDefaultScope),

new PathAccessControlItem(AccessControlType.User,
    RolePermissions.Read |
    RolePermissions.Execute, isDefaultScope,
    entityId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
    };

    await directoryClient.SetAccessControlRecursiveAsync
        (accessControlList, null);
}

Atualizar ACLs

AoAtualizaruma ACL, você modifica a ACL em vez de substituir a ACL. Por exemplo, você pode adicionar uma nova entidade de segurança à ACL sem afetar outras entidades de segurança listadas na ACL. Para substituir a ACL em vez de atualizá-la, confira a seção Definir ACLsdeste artigo.

Esta seção mostra como:

  • Atualizar uma ACL
  • Atualizar ACLs recursivamente

Atualizar uma ACL

Primeiro, obtenha a ACL de um diretório chamando o método DataLakeDirectoryClient. GetAccessControlAsync. Copie a lista de entradas de ACL para uma nova lista de objetos PathAccessControl. Em seguida, localize a entrada que você deseja atualizar e a substitua na lista. Defina a ACL chamando o método DataLakeDirectoryClient. Setaccesscontrollist.

Este exemplo atualiza a ACL raiz de um contêiner substituindo a entrada de ACL para todos os outros usuários.

public async Task UpdateDirectoryACLs(DataLakeFileSystemClient fileSystemClient)
{
    DataLakeDirectoryClient directoryClient =
      fileSystemClient.GetDirectoryClient("");

    PathAccessControl directoryAccessControl =
        await directoryClient.GetAccessControlAsync();

    List<PathAccessControlItem> accessControlListUpdate 
        = (List<PathAccessControlItem>)directoryAccessControl.AccessControlList;

    int index = -1;

    foreach (var item in accessControlListUpdate)
    {
        if (item.AccessControlType == AccessControlType.Other)
        {
            index = accessControlListUpdate.IndexOf(item);
            break;
        }
    }

    if (index > -1)
    {
        accessControlListUpdate[index] = new PathAccessControlItem(AccessControlType.Other,
        RolePermissions.Read |
        RolePermissions.Execute);

        directoryClient.SetAccessControlList(accessControlListUpdate);
    }

   }

Atualizar ACLs recursivamente

Para atualizar uma ACL recursivamente, crie um novo objeto ACL com a entrada de ACL que você deseja atualizar e, em seguida, use esse objeto na operação atualizar a ACL. Não obtenha a ACL existente, basta fornecer as entradas de ACL a serem atualizadas.

Atualize uma ACLs recursivamente chamando o método DataLakeDirectoryClient. UpdateAccessControlRecursiveAsync. Passe este método uma lista de PathAccessControlItem. Cada PathAccessControlItem define uma entrada de ACL.

Se você quiser atualizar uma entrada ACL padrão, poderá definir a propriedade PathAccessControlItem. DefaultScope de PathAccessControlItem como true.

Este exemplo atualiza uma entrada ACL com permissão de gravação. Esse método aceita um parâmetro booliano chamado isDefaultScope que especifica se a ACL padrão deve ser atualizada. Esse parâmetro é usado no construtor do PathAccessControlItem.

public async Task UpdateACLsRecursively(DataLakeServiceClient serviceClient, bool isDefaultScope)
{
    DataLakeDirectoryClient directoryClient =
        serviceClient.GetFileSystemClient("my-container").
        GetDirectoryClient("my-parent-directory");

    List<PathAccessControlItem> accessControlListUpdate =
        new List<PathAccessControlItem>()
    {
new PathAccessControlItem(AccessControlType.User,
    RolePermissions.Read |
    RolePermissions.Write |
    RolePermissions.Execute, isDefaultScope,
    entityId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
    };

    await directoryClient.UpdateAccessControlRecursiveAsync
        (accessControlListUpdate, null);

}

Remover entradas de ACL

Você pode remover uma ou mais entradas de ACL. Esta seção mostra como:

  • Remover uma entrada de ACL
  • Remover entradas de ACL recursivamente

Remover uma entrada de ACL

Primeiro, obtenha a ACL de um diretório chamando o método DataLakeDirectoryClient. GetAccessControlAsync. Copie a lista de entradas de ACL para uma nova lista de objetos PathAccessControl. Em seguida, localize a entrada que você deseja remover e chame o método Remove da coleção. Defina a ACL atualizada chamando o método DataLakeDirectoryClient. Setaccesscontrollist.

Este exemplo atualiza a ACL raiz de um contêiner substituindo a entrada de ACL para todos os outros usuários.

public async Task RemoveDirectoryACLEntry
    (DataLakeFileSystemClient fileSystemClient)
{
    DataLakeDirectoryClient directoryClient =
      fileSystemClient.GetDirectoryClient("");

    PathAccessControl directoryAccessControl =
        await directoryClient.GetAccessControlAsync();

    List<PathAccessControlItem> accessControlListUpdate
        = (List<PathAccessControlItem>)directoryAccessControl.AccessControlList;

    PathAccessControlItem entryToRemove = null;

    foreach (var item in accessControlListUpdate)
    {
        if (item.EntityId == "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
        {
            entryToRemove = item;
            break;
        }
    }

    if (entryToRemove != null)
    {
        accessControlListUpdate.Remove(entryToRemove);
        directoryClient.SetAccessControlList(accessControlListUpdate);
    }

}

Remover entradas de ACL recursivamente

Para remover as entradas de ACL recursivamente, crie um novo objeto ACL para a entrada de ACL a ser removida e, em seguida, use este objeto em remover a operação de ACL. Não obtenha a ACL existente, basta fornecer as entradas da ACL a serem removidas.

Remova as entradas de ACL chamando o método DataLakeDirectoryClient. RemoveAccessControlRecursiveAsync. Passe este método uma lista de PathAccessControlItem. Cada PathAccessControlItem define uma entrada de ACL.

Se você quiser remover uma entrada ACL padrão, poderá definir a propriedade PathAccessControlItem. DefaultScope de PathAccessControlItem como true.

Este exemplo remove uma entrada ACL da ACL do diretório chamado my-parent-directory. Esse método aceita um parâmetro booliano chamado isDefaultScope que especifica se a ACL padrão deve ser removida. Esse parâmetro é usado no construtor do PathAccessControlItem.

public async Task RemoveACLsRecursively(DataLakeServiceClient serviceClient, bool isDefaultScope)
{
    DataLakeDirectoryClient directoryClient =
        serviceClient.GetFileSystemClient("my-container").
            GetDirectoryClient("my-parent-directory");

    List<RemovePathAccessControlItem> accessControlListForRemoval =
        new List<RemovePathAccessControlItem>()
        {
    new RemovePathAccessControlItem(AccessControlType.User, isDefaultScope,
    entityId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
        };

    await directoryClient.RemoveAccessControlRecursiveAsync
        (accessControlListForRemoval, null);

}

Recuperar de falhas

Você pode encontrar erros de tempo de execução ou de permissão ao modificar ACLs recursivamente. Para erros de tempo de execução, reinicie o processo desde o início. Poderão ocorrer erros de permissão se a entidade de segurança não tiver permissão suficiente para modificar a ACL de um diretório ou arquivo que está na hierarquia de diretório que está sendo modificada. Resolva o problema de permissão e, em seguida, escolha retomar o processo no ponto de falha usando um token de continuação ou reiniciar o processo do início. Você não precisará usar o token de continuação se preferir reiniciar desde o início. É possível reaplicar entradas de ACL sem nenhum impacto negativo.

Este exemplo retorna um token de continuação no caso de uma falha. O aplicativo pode chamar esse método de exemplo novamente depois que o erro for resolvido e passar o token de continuação. Se esse método de exemplo for chamado pela primeira vez, o aplicativo poderá passar um valor denullpara o parâmetro de token de continuação.

public async Task<string> ResumeAsync(DataLakeServiceClient serviceClient,
    DataLakeDirectoryClient directoryClient,
    List<PathAccessControlItem> accessControlList,
    string continuationToken)
{
    try
    {
        var accessControlChangeResult =
            await directoryClient.SetAccessControlRecursiveAsync(
                accessControlList, continuationToken: continuationToken, null);

        if (accessControlChangeResult.Value.Counters.FailedChangesCount > 0)
        {
            continuationToken =
                accessControlChangeResult.Value.ContinuationToken;
        }

        return continuationToken;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
        return continuationToken;
    }

}

Se você quiser que o processo seja concluído sem interrupções por erros de permissão, poderá especificar isso.

Para garantir que o processo seja concluído sem interrupções, passe um objeto AccessControlChangedOptions e defina a propriedade ContinueOnFailure desse objeto como true.

Este exemplo define as entradas de ACL recursivamente. Se esse código encontrar um erro de permissão, ele registrará essa falha e continuará a execução. Este exemplo imprime o número de falhas no console.

public async Task ContinueOnFailureAsync(DataLakeServiceClient serviceClient,
    DataLakeDirectoryClient directoryClient,
    List<PathAccessControlItem> accessControlList)
{
    var accessControlChangeResult =
        await directoryClient.SetAccessControlRecursiveAsync(
            accessControlList, null, new AccessControlChangeOptions()
            { ContinueOnFailure = true });

    var counters = accessControlChangeResult.Value.Counters;

    Console.WriteLine("Number of directories changed: " +
        counters.ChangedDirectoriesCount.ToString());

    Console.WriteLine("Number of files changed: " +
        counters.ChangedFilesCount.ToString());

    Console.WriteLine("Number of failures: " +
        counters.FailedChangesCount.ToString());
}

Práticas recomendadas

Esta seção fornece algumas diretrizes de práticas recomendadas para definir as ACLs recursivamente.

Manipulanr erros de tempo de execução

Um erro de runtime pode ocorrer por vários motivos (por exemplo: uma interrupção ou um problema de conectividade de cliente). Se você encontrar um erro de runtime, reinicie o processo de ACL recursivo. As ACLs podem ser reaplicadas para itens sem causar um impacto negativo.

Tratamento de erros de permissão (403)

Se você encontrar uma exceção de controle de acesso durante a execução de um processo de ACL recursivo, a entidade de segurança do AD poderá não ter permissão suficiente para aplicar uma ACL a um ou mais dos itens filho na hierarquia de diretórios. Quando ocorre um erro de permissão, o processo é interrompido e um token de continuação é fornecido. Corrija o problema de permissão e, em seguida, use o token de continuação para processar o conjunto de dados restante. Os diretórios e arquivos que já foram processados com êxito não precisam ser processados novamente. Você também pode optar por reiniciar o processo de ACL recursivo. As ACLs podem ser reaplicadas para itens sem causar um impacto negativo.

Credenciais

Recomendamos que você provisione uma entidade de segurança do Microsoft Entra que tenha sido atribuída à função de proprietário de dados do blob de armazenamento no escopo da conta de armazenamento de destino ou do contêiner.

Desempenho

Para reduzir a latência, recomendamos que você execute o processo de ACL recursivo em uma Máquina Virtual (VM) do Azure localizada na mesma região que a sua conta de armazenamento.

Limites de ACL

O número máximo de ACLs que você pode aplicar a um diretório ou arquivo é de 32 ACLs de acesso e 32 ACLs padrão. Para obter mais informações, consulte Controle de acesso no Azure Data Lake Storage Gen2.

Confira também