将 OAuth 2.0 和 Azure 服务主体配合使用来访问 Azure Data Lake Storage Gen2

可将 OAuth 2.0 和 Azure Active Directory (Azure AD) 应用程序服务主体配合使用以进行身份验证,从而安全地访问 Azure Data Lake Storage Gen2 (ADLS Gen2) 帐户中的数据。 使用服务主体进行身份验证为访问存储帐户中的数据提供了两个选项:

  • 指向特定文件或路径的装入点
  • 对数据的直接访问

要选择的选项取决于你计划如何将 Databricks 与 ADLS Gen2 存储配合使用:

  • 若要为多个工作区用户提供对特定路径或文件的访问权限,请创建指向所需存储资源和路径的装入点。
  • 若要为具有不同权限的多个工作区用户提供访问权限,请通过 Azure Blob File System (ABFS) 驱动程序直接访问数据。

装入点还提供了使用标准文件系统语义在整个工作区中轻松访问的好处。 与此相反,直接访问路径需要在笔记本中完全指定。 装入点这一功能可以为访问工作区中的公共资源的多个用户提供更好的用户体验。

本文介绍如何创建 Azure AD 应用程序和服务主体,如何使用该服务主体装载或直接访问 ADLS Gen2 存储帐户中的数据。 下面概述了本文涉及的的任务:

  1. 创建 Azure AD 应用程序,该应用程序将创建用于访问存储帐户的关联服务主体。
  2. 创建 Azure Key Vault 支持的机密范围。 机密范围将安全地存储与 Azure AD 应用程序关联的客户端密码。
  3. 将与 Azure AD 应用程序关联的客户端密码保存在 Azure 密钥保管库中。 向存储帐户进行身份验证时需要提供客户端密码。 密钥保管库安全地存储密码,并允许在配置中不直接引用它的情况下使用它。
  4. 向应用程序分配角色,以向服务主体提供访问 ADLS Gen2 存储帐户所需的权限。
  5. 在存储帐户中创建一个或多个容器。 与文件系统中的目录相似,容器提供一种方法来组织 Azure 存储帐户中的对象。 需要先创建一个或多个容器,然后才能访问 ADLS Gen2 存储帐户。
  6. 通过装入点或直接访问验证和访问 ADLS Gen2 存储帐户。

本文介绍如何使用 Azure Key Vault 支持的机密范围,但你也可以使用 Databricks 支持的机密范围来存储客户端密码。

要求

注册 Azure Active Directory 应用程序

注册 Azure AD 应用程序并分配适当的权限将创建可访问 ADLS Gen2 存储资源的服务主体。

  1. 在 Azure 门户中,转到“Azure Active Directory”服务。

  2. 在“管理”下,单击“应用注册” 。

  3. 单击“+ 新建注册”。 输入应用程序的名称,然后单击“注册”。

  4. 单击"证书 机密"。

  5. 单击“+ 新建客户端密码”。

  6. 添加机密说明,并单击“添加”。

  7. 复制并保存新机密的值。

  8. 在应用程序注册概述中,复制并保存“应用程序(客户端) ID”和“目录(租户) ID” 。

    应用注册概述

创建 Azure 密钥保管库和机密范围

创建 Azure 密钥保管库和该密钥保管库支持的 Azure Databricks 机密范围:

  1. 在 Azure 门户中创建 Azure Key Vault 实例。
  2. 创建由 Azure Key Vault 实例支持的 Azure Databricks 机密范围。

步骤 1:创建 Azure Key Vault 实例

  1. 在Azure 门户,选择"密钥保管库 + 添加 ",并指定密钥保管库的名称。

  2. 单击“查看 + 创建”。

  3. 验证完成后,单击“创建”

  4. 创建密钥保管库之后,转到新密钥保管库的“属性”页。

  5. 复制并保存“保管库 URI”和“资源 ID” 。

    Azure 密钥保管库属性

步骤 2:创建Azure Key Vault机密范围

Azure Databricks 资源可以通过创建 Key Vault 支持的机密范围来引用存储在 Azure 密钥保管库中的机密。 可以使用 Azure Databricks UI、Databricks 机密 CLI或 Databricks 机密 API 2.0 来创建Azure Key Vault机密范围。 本文介绍如何使用 UI 和 CLI。

在 Azure Databricks UI 中创建 Azure Databricks 机密范围

  1. 转到 上Azure Databricks 机密范围" 。 将 per-workspace-url 替换为工作区 per-workspace-url 工作区的唯Azure Databricks URL。

  2. 输入“范围名称”。

  3. 为在步骤 1: 创建 Azure Key Vault 实例中创建的 Azure Key Vault 输入“保管库 URI”和“资源 ID”值。

  4. 单击 “创建”

    创建机密范围

在 CLI 中创建 Azure Databricks 机密范围

若要使用 Databricks CLI 创建 Azure Key Vault 支持的机密范围,请打开终端并运行以下命令:

databricks secrets create-scope \
--scope <scope-name> \
--scope-backend-type AZURE_KEYVAULT \
--resource-id <azure-keyvault-resource-id> \
--dns-name <azure-keyvault-dns-name>

Replace

  • <scope-name> 替换为新范围的名称。
  • <azure-keyvault-resource-id> 具有密钥保管库 <azure-keyvault-resource-id>
  • <azure-keyvault-dns-name> 使用 <azure-keyvault-dns-name>

使用步骤 1:创建 Azure Key Vault 实例中的值的示例:

databricks secrets create-scope \
--scope example-akv-scope \
--scope-backend-type AZURE_KEYVAULT \
--resource-id /subscriptions/… \
--dns-name https://example-akv.vault.azure.net/

将客户端密码保存到 Azure 密钥保管库中

  1. 在 Azure 门户中,转到“Key Vault”服务。

  2. 选择在步骤 1:创建 Azure Key Vault 实例中创建的密钥保管库。

  3. "设置 机密"下,单击"生成/导入"。

  4. 选择“手动”上传选项,并在“值”字段中输入客户端机密 。

    创建机密

使用机密 CLI 验证是否正确创建了机密:

databricks secrets list --scope example-akv-scope
Key name               Last updated
--------------------   --------------
example-adls2-secret   1605122724000

分配角色

可以通过向与存储帐户关联的 Azure AD 应用程序注册分配角色来控制对存储资源的访问。 此示例将“存储 Blob 数据参与者”分配给 ADLS Gen2 存储帐户。 可能需要根据特定要求分配其他角色。

  1. 在 Azure 门户中,转到“存储帐户”服务。

  2. 选择要用于此应用程序注册的 ADLS Gen2 帐户。

  3. 单击“访问控制(IAM)”。

  4. 单击“+ 添加”,然后从下拉菜单中选择“添加角色分配” 。

  5. 将“选择”字段设置为 Azure AD 应用程序名称,并将“角色”设置为“存储 Blob 数据参与者” 。

  6. 单击“保存” 。

    分配应用程序角色

创建容器

与文件系统中的目录相似,容器提供一种方法来组织 Azure 存储帐户中的对象。 需要先创建一个或多个容器,然后才能访问 ADLS Gen2 存储帐户。 可以直接在 Azure Databricks 笔记本中创建容器,也可通过 Azure 命令行接口、Azure API 或 Azure 门户创建。 通过门户创建容器:

  1. 在 Azure 门户中,转到“存储帐户”。

  2. 选择 ADLS Gen2 帐户,然后单击“容器”。

  3. 单击“+ 容器”。

  4. 为容器输入一个名称,然后单击“创建”。

    创建容器

装载 ADLS Gen2 存储

装载 ADLS Gen2 存储:

  1. 使用服务主体作为凭据,为 ADLS Gen2 存储帐户配置 OAuth 2.0 身份验证。
  2. 通过 Databricks API 创建装入点。

重要

  • Azure Databricks 工作区中的所有用户都有权访问已装载的 ADLS Gen2 帐户。 应仅向用于访问 ADLS Gen2 帐户的服务主体授予对该 ADLS Gen2 帐户的访问权限,不应授予对其他 Azure 资源的访问权限。
  • 通过群集创建装入点后,群集用户可立即访问装入点。 若要在另一个正在运行的群集中使用装入点,则必须在运行的群集上运行 dbutils.fs.refreshMounts(),使新创建的装入点可供使用。
  • 在作业运行时卸载装入点可能会导致错误。 确保生产作业不会在处理过程中卸载存储。

在笔记本中运行以下命令,以验证并创建装入点。

configs = {"fs.azure.account.auth.type": "OAuth",
          "fs.azure.account.oauth.provider.type": "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider",
          "fs.azure.account.oauth2.client.id": "<application-id>",
          "fs.azure.account.oauth2.client.secret": dbutils.secrets.get(scope="<scope-name>",key="<service-credential-key-name>"),
          "fs.azure.account.oauth2.client.endpoint": "https://login.microsoftonline.com/<directory-id>/oauth2/token"}

# Optionally, you can add <directory-name> to the source URI of your mount point.
dbutils.fs.mount(
  source = "abfss://<container-name>@<storage-account-name>.dfs.core.windows.net/",
  mount_point = "/mnt/<mount-name>",
  extra_configs = configs)
val configs = Map(
  "fs.azure.account.auth.type" -> "OAuth",
  "fs.azure.account.oauth.provider.type" -> "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider",
  "fs.azure.account.oauth2.client.id" -> "<application-id>",
  "fs.azure.account.oauth2.client.secret" -> dbutils.secrets.get(scope="<scope-name>",key="<service-credential-key-name>"),
  "fs.azure.account.oauth2.client.endpoint" -> "https://login.microsoftonline.com/<directory-id>/oauth2/token")
// Optionally, you can add <directory-name> to the source URI of your mount point.
dbutils.fs.mount(
  source = "abfss://<container-name>@<storage-account-name>.dfs.core.windows.net/",
  mount_point = "/mnt/<mount-name>",
  extra_configs = configs)

Replace

  • <application-id>对于 Azure Active Directory 应用程序,<application-id>
  • <scope-name> 替换为 Databricks 机密范围名称。
  • <service-credential-key-name> 替换为包含客户端密码的密钥的名称。
  • <directory-id>对于 Azure Active Directory 应用程序的<directory-id>
  • <container-name> 替换为 ADLS Gen2 存储帐户中的容器的名称。
  • <storage-account-name> 替换为 ADLS Gen2 存储帐户名称。
  • <mount-name> 替换为 DBFS 中的预期装入点的名称。

访问 ADLS Gen2 文件系统中的文件,就像访问 DBFS 中的文件一样:

df = spark.read.text("/mnt/%s/...." % <mount-name>)
df = spark.read.text("dbfs:/mnt/<mount-name>/....")
val df = spark.read.text("/mnt/<mount-name>/....")
val df = spark.read.text("dbfs:/mnt/<mount-name>/....")

若要卸载装入点,请使用以下命令:

dbutils.fs.unmount("/mnt/<mount-name>")

直接访问 ADLS Gen2

传递凭据以直接访问存储资源的方式取决于你是计划使用数据帧或数据集 API,还是 RDD API。

数据帧或数据集 API

如果你使用的是 Spark 数据帧或数据集 API,Databricks 建议你在笔记本的会话配置中设置帐户凭据:

spark.conf.set("fs.azure.account.auth.type.<storage-account-name>.dfs.core.windows.net", "OAuth")
spark.conf.set("fs.azure.account.oauth.provider.type.<storage-account-name>.dfs.core.windows.net", "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider")
spark.conf.set("fs.azure.account.oauth2.client.id.<storage-account-name>.dfs.core.windows.net", "<application-id>")
spark.conf.set("fs.azure.account.oauth2.client.secret.<storage-account-name>.dfs.core.windows.net", dbutils.secrets.get(scope="<scope-name>",key="<service-credential-key-name>"))
spark.conf.set("fs.azure.account.oauth2.client.endpoint.<storage-account-name>.dfs.core.windows.net", "https://login.microsoftonline.com/<directory-id>/oauth2/token")

Replace

  • <storage-account-name> 替换为 ADLS Gen2 存储帐户的名称。
  • <application-id>对于 Azure Active Directory 应用程序,<application-id>
  • <scope-name> 替换为 Databricks 机密范围名称。
  • <service-credential-key-name> 替换为包含客户端密码的密钥的名称。
  • <directory-id>对于 Azure Active Directory 应用程序的<directory-id>

RDD API

如果使用 RDD API 来访问 ADLS Gen2,则无法访问使用设置的 Hadoop 配置选项 spark.conf.set(...) 。 请改为在创建群集时将 Hadoop 配置选项指定为 Spark 配置。 必须将前缀添加 spark.hadoop. 到 hadoop 配置密钥,才能将其传播到 RDD 作业使用的 hadoop 配置。

警告

这些凭据可供访问群集的所有用户使用。

spark.hadoop.fs.azure.account.auth.type.<storage-account-name>.dfs.core.windows.net OAuth
spark.hadoop.fs.azure.account.oauth.provider.type.<storage-account-name>.dfs.core.windows.net org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider
spark.hadoop.fs.azure.account.oauth2.client.id.<storage-account-name>.dfs.core.windows.net <application-id>
spark.hadoop.fs.azure.account.oauth2.client.secret.<storage-account-name>.dfs.core.windows.net <service-credential>
spark.hadoop.fs.azure.account.oauth2.client.endpoint.<storage-account-name>.dfs.core.windows.net https://login.microsoftonline.com/<directory-id>/oauth2/token

Replace

  • <storage-account-name> 替换为 ADLS Gen2 存储帐户的名称。
  • <application-id>对于 Azure Active Directory 应用程序,<application-id>
  • <service-credential> 替换为客户端密码的值。
  • <service-credential-key-name> 替换为包含客户端密码的密钥的名称。
  • <directory-id>对于 Azure Active Directory 应用程序的<directory-id>

使用标准 Spark 和 Databricks API 从存储帐户读取:

val df = spark.read.parquet("abfss://<container-name>@<storage-account-name>.dfs.core.windows.net/<directory-name>")

dbutils.fs.ls("abfss://<container-name>@<storage-account-name>.dfs.core.windows.net/<directory-name>")

Replace

  • <container-name> 替换为 ADLS Gen2 存储帐户中的容器的名称。
  • <storage-account-name> 替换为 ADLS Gen2 存储帐户名称。
  • <directory-name> 替换为存储帐户中的可选路径。

示例笔记本

此笔记本演示如何使用服务主体执行以下操作:

  1. 验证 ADLS Gen2 存储帐户。
  2. 在存储帐户中装载文件系统。
  3. 将包含物联网 (IoT) 数据的 JSON 文件写入新容器。
  4. 使用直接访问和通过装入点列出文件。
  5. 使用直接访问和通过装入点来读取和显示 IoT 文件。

ADLS Gen2 包含 Azure 服务主体的 OAuth 2.0 笔记本

获取笔记本