Share via


Uso de .NET para administrar listas de control de acceso (ACL) en Azure Data Lake Storage Gen2

En este artículo se muestra cómo usar .NET para obtener, establecer y actualizar las listas de control de acceso de directorios y archivos.

La herencia de ACL ya está disponible para los nuevos elementos secundarios que se crean en un directorio primario. Ahora bien, también se pueden agregar, actualizar y quitar listas de control de acceso de forma recursiva en los elementos secundarios existentes de un directorio primario sin tener que realizar estos cambios individualmente para cada elemento secundario.

Paquete (NuGet) | Ejemplos | Referencia de API | Asignación de Gen1 a Gen2 | Envíenos sus comentarios

Requisitos previos

  • Suscripción a Azure. Consulte Obtención de una versión de evaluación gratuita.

  • Una cuenta de almacenamiento que tenga habilitado el espacio de nombres jerárquico (HNS). Siga estas instrucciones para crear uno.

  • CLI de Azure versión 2.6.0 o posterior.

  • Uno de los siguientes permisos de seguridad:

    • Una entidad de seguridad aprovisionada de Microsoft Entra ID a la que se ha asignado el rol Propietario de datos de blobs de almacenamiento, con ámbito para el contenedor de destino, el grupo de recursos primario o la suscripción.

    • El usuario propietario del contenedor o directorio de destino al que va a aplicar la configuración de ACL. Para establecer listas de control de acceso de forma recursiva, se incluyen todos los elementos secundarios en el contenedor o el directorio de destino.

    • Clave de la cuenta de almacenamiento.

Configurar su proyecto

Para empezar, instale el paquete NuGet Azure.Storage.Files.DataLake.

  1. Abra una ventana de comando (por ejemplo: Windows PowerShell).

  2. En el directorio del proyecto, instale el paquete Azure.Storage.Files.DataLake de la versión preliminar mediante el comando dotnet add package.

    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
    

    A continuación, agregue estas instrucciones USING al inicio del archivo 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;
    

Conexión con la cuenta

Para usar los fragmentos de código de este artículo, tiene que crear una instancia de DataLakeServiceClient que represente la cuenta de almacenamiento.

Conexión mediante Microsoft Entra ID

Nota:

Si usa Microsoft Entra ID para autorizar el acceso, asegúrese de que la entidad de seguridad tenga asignado el rol Propietario de datos de blobs de almacenamiento. Para obtener más información sobre cómo se aplican los permisos de ACL y las consecuencias de cambiarlos, vea Modelo de control de acceso de Azure Data Lake Storage Gen2.

Puede usar la biblioteca cliente de identidad de Azure para .NET a fin de autenticar la aplicación con Microsoft Entra ID.

Después de instalar el paquete, agregue esta instrucción "using" al principio del archivo de código.

using Azure.Identity;

En primer lugar, tendrá que asignar uno de los siguientes roles de control de acceso basado en roles de Azure (Azure RBAC) a la entidad de seguridad:

Role Capacidad de configuración de ACL
Propietario de datos de blobs de almacenamiento Todos los directorios y archivos de la cuenta.
Colaborador de datos de blobs de almacenamiento Solo los directorios y archivos que pertenecen a la entidad de seguridad.

A continuación, cree una instancia de DataLakeServiceClient y pase una nueva instancia de la clase 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 obtener más información sobre el uso de DefaultAzureCredential para autorizar el acceso a los datos, consulte Cómo autenticar aplicaciones .NET con servicios de Azure.

Conexión con una clave de cuenta

Puede autorizar el acceso a los datos mediante las claves de acceso de la cuenta (clave compartida). En este ejemplo se crea una instancia de DataLakeServiceClient autorizada con la clave de cuenta.

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;
}

Precaución

No se recomienda la autorización con clave compartida, ya que puede ser menos segura. Para obtener una seguridad óptima, deshabilite la autorización mediante clave compartida para la cuenta de almacenamiento, como se describe en Impedir la autorización de clave compartida para una cuenta de Azure Storage.

El uso de claves de acceso y cadenas de conexión debe limitarse a la prueba inicial de aplicaciones de concepto o prototipos de desarrollo que no tienen acceso a datos confidenciales o de producción. De lo contrario, siempre se deben preferir las clases de autenticación basadas en tokens disponibles en el SDK de Azure al autenticarse en los recursos de Azure.

Microsoft recomienda que los clientes usen Microsoft Entra ID o una firma de acceso compartido (SAS) para autorizar el acceso a los datos de Azure Storage. Para obtener más información, consulte Autorización de operaciones para el acceso a datos.

Establecimiento de listas de control de acceso

Cuando establece una ACL, debe reemplazar toda la ACL, incluidas todas sus entradas. Si quiere cambiar el nivel de permiso de una entidad de seguridad o agregar una nueva entidad de seguridad a la ACL sin que esto afecte a otras entradas existentes, debe actualizar la ACL en su lugar. Para actualizar una ACL en lugar de reemplazarla, consulte la sección Actualización de ACL de este artículo.

Si elige establecer la lista de control de acceso, debe agregar una entrada para el usuario propietario, otra para el grupo propietario y una tercera para los demás usuarios. Para más información sobre el usuario propietario, el grupo propietario y el resto de usuarios, consulte Usuarios e identidades.

Esta sección le muestra cómo:

  • Establecer la ACL de un directorio
  • Establecer la ACL de un archivo
  • Establecimiento de listas de control de acceso de forma recursiva

Establecer la ACL de un directorio

Obtenga la lista de control de acceso (ACL) de un directorio al llamar al método DataLakeDirectoryClient.GetAccessControlAsync y establezca dicha lista con una llamada al método DataLakeDirectoryClient.SetAccessControlList.

En este ejemplo se obtiene y después se establece la ACL de un directorio denominado my-directory. La cadena user::rwx,group::r-x,other::rw- concede al usuario propietario permisos de lectura, escritura y ejecución, permisos de solo lectura y ejecución al grupo propietario, y permisos de lectura y escritura al resto.

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);

}

También puede obtener y establecer la ACL del directorio raíz de un contenedor. Para obtener el directorio raíz, pase una cadena vacía ("") en el método DataLakeFileSystemClient.GetDirectoryClient.

Establecer la ACL de un archivo

Obtenga la lista de control de acceso (ACL) de un archivo al llamar al método DataLakeFileClient.GetAccessControlAsync y establezca dicha lista con una llamada al método DataLakeFileClient.SetAccessControlList.

En este ejemplo se obtiene y después se establece la ACL de un archivo denominado my-file.txt. La cadena user::rwx,group::r-x,other::rw- concede al usuario propietario permisos de lectura, escritura y ejecución, permisos de solo lectura y ejecución al grupo propietario, y permisos de lectura y escritura al resto.

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);
}

Establecimiento de listas de control de acceso de forma recursiva

Establezca las listas de control de acceso de forma recursiva llamando al método DataLakeDirectoryClient.SetAccessControlRecursiveAsync. Pase a este método una lista de PathAccessControlItem. Cada PathAccessControlItem define una entrada de la ACL.

Si desea establecer una entrada de la ACL predeterminada, puede establecer la propiedad PathAccessControlItem.DefaultScope de PathAccessControlItem en true.

En este ejemplo se establece la ACL de un directorio denominado my-parent-directory. Este método acepta un parámetro booleano denominado isDefaultScope que especifica si se debe establecer la ACL predeterminada. Ese parámetro se utiliza en el constructor de PathAccessControlItem. Las entradas de la ACL conceden al usuario propietario permisos de lectura, escritura y ejecución, permisos solo de lectura y ejecución al grupo propietario, y ningún permiso al resto. La última entrada de ACL de este ejemplo proporciona a un usuario específico con el identificador de objeto xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx permisos de lectura y ejecución.

    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);
}

Actualización de ACL

Cuando actualiza una ACL, modifica la ACL en lugar de reemplazarla. Por ejemplo, puede agregar una nueva entidad de seguridad a la ACL sin que esto afecte a otras entidades de seguridad que se enumeran en la ACL. Para reemplazar la ACL en lugar de actualizarla, consulte la sección Establecimiento de listas de control de acceso de este artículo.

Esta sección le muestra cómo:

  • Actualización de una ACL
  • Actualización de listas de control de acceso de forma recursiva

Actualización de una ACL

En primer lugar, para obtener la ACL de un directorio, llame al método DataLakeDirectoryClient.GetAccessControlAsync. Copie la lista de entradas de ACL en una nueva lista de objetos PathAccessControl. A continuación, busque la entrada que desea actualizar y reemplácela en la lista. Establezca la ACL mediante una llamada al método DataLakeDirectoryClient.SetAccessControlList.

En este ejemplo se actualiza la ACL raíz de un contenedor mediante la sustitución de la entrada de ACL de todos los demás usuarios.

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);
    }

   }

Actualización de listas de control de acceso de forma recursiva

Para actualizar una ACL de forma recursiva, cree un nuevo objeto ACL con la entrada de la ACL que quiera actualizar y, a continuación, use ese objeto en la operación para actualizar la ACL. No debe obtener la ACL existente, simplemente proporcione las entradas de la ACL que se vayan a actualizar.

Actualice una ACL de forma recursiva llamando al método DataLakeDirectoryClient.UpdateAccessControlRecursiveAsync. Pase a este método una lista de PathAccessControlItem. Cada PathAccessControlItem define una entrada de la ACL.

Si desea actualizar una entrada de la ACL predeterminada, puede establecer la propiedad PathAccessControlItem.DefaultScope de PathAccessControlItem en true.

En este ejemplo se actualiza una entrada de ACL con permiso de escritura. Este método acepta un parámetro booleano denominado isDefaultScope que especifica si se debe actualizar la ACL predeterminada. Ese parámetro se utiliza en el constructor de 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);

}

Eliminación de entradas de ACL

Puede quitar una o varias entradas de ACL. Esta sección le muestra cómo:

  • Eliminación de una entrada de ACL
  • Eliminación de las entradas de ACL de forma recursiva

Eliminación de una entrada de ACL

En primer lugar, para obtener la ACL de un directorio, llame al método DataLakeDirectoryClient.GetAccessControlAsync. Copie la lista de entradas de ACL en una nueva lista de objetos PathAccessControl. A continuación, busque la entrada que desea quitar y llame al método Remove de la colección. Establezca la ACL actualizada mediante una llamada al método DataLakeDirectoryClient.SetAccessControlList.

En este ejemplo se actualiza la ACL raíz de un contenedor mediante la sustitución de la entrada de ACL de todos los demás usuarios.

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);
    }

}

Eliminación de las entradas de ACL de forma recursiva

Para quitar entradas de ACL de forma recursiva, cree un nuevo objeto de ACL para la entrada de ACL que se va a quitar y, a continuación, use ese objeto en la operación para quitar la ACL. No debe obtener la ACL existente; simplemente proporcione las entradas de la ACL que se van a quitar.

Elimine entradas de ACL llamando al método DataLakeDirectoryClient.RemoveAccessControlRecursiveAsync. Pase a este método una lista de PathAccessControlItem. Cada PathAccessControlItem define una entrada de la ACL.

Si desea quitar una entrada de la ACL predeterminada, puede establecer la propiedad PathAccessControlItem.DefaultScope de PathAccessControlItem en true.

En este ejemplo se quita una entrada de la ACL del directorio llamado my-parent-directory. Este método acepta un parámetro booleano denominado isDefaultScope que especifica si se debe quitar la entrada de la ACL predeterminada. Ese parámetro se utiliza en el constructor de 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);

}

Recuperación de errores

Al modificar listas de control de acceso de forma recursiva, es posible que se produzcan errores del entorno de ejecución o de los permisos. En el caso de los errores de tiempo de ejecución, reinicie el proceso desde el principio. Los errores de permisos pueden producirse si la entidad de seguridad no tiene permisos suficientes para modificar la ACL de un directorio o archivo que se encuentra en la jerarquía de directorios que se está modificando. Solucione el problema de permisos y, a continuación, elija reanudar el proceso desde el punto de error mediante un token de continuación, o bien reinicie el proceso desde el principio. No tiene que usar el token de continuación si prefiere reiniciar desde el principio. Puede volver a aplicar las entradas de ACL sin ningún efecto negativo.

Este ejemplo devuelve un token de continuación en caso de que se produzca un error. La aplicación puede volver a llamar a este método de ejemplo después de que se haya solucionado el error y pasar el token de continuación. Si se llama a este método de ejemplo por primera vez, la aplicación puede pasar un valor de null para el parámetro del token de continuación.

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;
    }

}

Si desea que el proceso se complete sin que se interrumpa por errores de permisos, puede especificarlo.

Para asegurarse de que el proceso se completa sin interrupciones, pase un objeto AccessControlChangedOptions y establezca la propiedad ContinueOnFailure de ese objeto en true.

En este ejemplo se establecen las entradas de ACL de forma recursiva. Si este código se encuentra un error de permiso, lo registra y continúa la ejecución. En este ejemplo se imprime el número de errores en la consola.

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());
}

Procedimientos recomendados

En esta sección se proporcionan algunas directrices de procedimientos recomendados para configurar las ACL de forma recursiva.

Manejo de errores de tiempo de ejecución

Se puede producir un error de tiempo de ejecución por muchos motivos (por ejemplo: una interrupción o un problema de conectividad de cliente). Si se produce un error de tiempo de ejecución, reinicie el proceso de ACL recursivo. Las ACL se pueden volver a aplicar a los elementos sin provocar ningún efecto negativo.

Manejo de errores de permisos (403)

Si experimenta una excepción de control de acceso al ejecutar un proceso de ACL recursivo, es posible que la entidad de seguridad de AD no tenga permisos suficientes para aplicar una ACL a uno o varios de los elementos secundarios de la jerarquía de directorios. Cuando se produce un error de permiso, el proceso se detiene y se proporciona un token de continuación. Repare el problema de permisos y, después, use el token de continuación para procesar el conjunto de datos restante. Los directorios y archivos que ya se han procesado correctamente no tendrán que procesarse de nuevo. También puede optar por reiniciar el proceso de ACL recursivo. Las ACL se pueden volver a aplicar a los elementos sin provocar ningún efecto negativo.

Credenciales

Se recomienda que aprovisione una entidad de seguridad de Microsoft Entra a la que se haya asignado el rol Propietario de datos de blobs de almacenamiento en el ámbito de la cuenta de almacenamiento o el contenedor de destino.

Rendimiento

Para reducir la latencia, se recomienda ejecutar el proceso de ACL recursivo en una máquina virtual de Azure que se encuentre en la misma región que la cuenta de almacenamiento.

Límites de ACL

El número máximo de ACL que puede aplicar a un directorio o archivo es de 32 ACL de acceso y 32 ACL predeterminadas. Para más información, consulte Control de acceso en Azure Data Lake Storage Gen2.

Consulte también