Databricks Apps 支持在 Azure Databricks 上进行安全的应用程序开发。 当应用访问工作区中的数据和服务时,它们必须使用强制实施数据访问控制并尊重用户权限的身份验证和授权机制。 Databricks Apps 授权模型基于 OAuth 2.0,并将分配给应用的权限与访问应用的权限组合在一起。
为了支持此框架,Databricks Apps 使用两个互补标识模型:
应用授权
每个 Azure Databricks 应用都有一个专用 的服务主体 ,在访问 Azure Databricks 资源时充当其标识。 此服务主体对应用实例是唯一的,不能跨应用重复使用。 无法在创建应用期间更改分配给应用的服务主体或指定现有服务主体。 Azure Databricks 使用此标识来独立于任何用户评估应用的权限,这可确保应用只能访问显式授予该应用的资源,即使在用户交互上下文之外也是如此。
这种分离有助于强制实施安全边界,从而允许审核应用活动,并支持后台处理或自动化任务等方案。
服务主体由唯一 ID 表示。 从应用的 “授权 ”选项卡复制它:
创建应用时,Azure Databricks 会自动为应用预配专用服务主体。 服务主体在应用的所有部署中保持不变。 删除应用时,Azure Databricks 会删除服务主体。
针对应用自行执行的操作使用服务主体,而不需要单个用户上下文。 常见用例包括:
- 运行后台任务
- 读取或写入共享配置或元数据
- 记录活动或使用指标数据
- 通过安全终结点调用外部服务
应用启动的所有作都使用服务主体的权限。 使用标准权限分配向服务主体授予对特定资源的访问权限。 但是,它不支持用户级访问控制。 与应用交互的所有用户共享为服务主体定义的相同权限,从而阻止应用基于单个用户标识强制实施精细策略。
以下示例演示应用如何使用其服务主体查询 Unity 目录中的数据:
在这种情况下,服务主体需要显式访问 SQL 仓库和它查询的 Unity 目录表。
如果希望应用的所有用户查看相同的数据,或者当应用执行不绑定到用户特定访问控制的共享作时,此模型可正常工作。
检索应用授权凭据
对于应用授权,Azure Databricks 会自动将服务主体凭据注入应用环境。 以下环境变量保存所需的 OAuth 客户端值:
| Variable | Description |
|---|---|
DATABRICKS_CLIENT_ID |
服务主体 OAuth 客户端 ID |
DATABRICKS_CLIENT_SECRET |
服务主体 OAuth 客户端密钥 |
Azure Databricks 在应用运行时中自动设置环境变量。 应用在自我身份验证时使用这些变量。
Python
import os
client_id = os.getenv('DATABRICKS_CLIENT_ID')
client_secret = os.getenv('DATABRICKS_CLIENT_SECRET')
JavaScript
const clientId = process.env.DATABRICKS_CLIENT_ID;
const clientSecret = process.env.DATABRICKS_CLIENT_SECRET;
Note
如果使用 Azure Databricks SDK,通常不需要手动访问这些环境变量。 SDK 遵循 统一身份验证 ,并自动检测环境中的凭据。
示例:使用应用授权进行查询
Python
此示例使用 SDK Config 对象,该对象从环境变量中提取服务主体凭据并执行 OAuth 授权。
from databricks import sql
from databricks.sdk.core import Config
cfg = Config()
conn = sql.connect(
server_hostname=cfg.host,
http_path="<your-warehouse-http-path>",
credentials_provider=lambda: cfg.authenticate,
)
query = "SELECT * FROM main.sandbox.sales_customers LIMIT 1000"
with conn.cursor() as cursor:
cursor.execute(query)
df = cursor.fetchall_arrow().to_pandas()
print(df.head())
conn.close()
JavaScript
此示例使用环境变量通过 OAuth 向服务主体进行身份验证,并使用 用于 Node.js的 Databricks SQL 驱动程序 运行查询。
import { DBSQLClient } from '@databricks/sql';
const client = new DBSQLClient();
const connection = await client.connect({
authType: 'databricks-oauth',
host: process.env.DATABRICKS_SERVER_HOSTNAME,
path: process.env.DATABRICKS_HTTP_PATH,
oauthClientId: process.env.DATABRICKS_CLIENT_ID,
oauthClientSecret: process.env.DATABRICKS_CLIENT_SECRET,
});
const query = 'SELECT * FROM main.sandbox.sales_customers LIMIT 1000';
const cursor = await connection.cursor(query);
const rows = [];
for await (const row of cursor) {
rows.push(row);
}
console.log(rows.slice(0, 5)); // Like df.head()
await connection.close();
用户授权
Important
用户授权为公共预览版。
用户授权(有时称为代表用户授权)允许 Databricks Apps 应用以应用用户的身份执行操作。 Azure Databricks 将用户的访问令牌转发到应用,应用使用该令牌代表用户访问资源。 Azure Databricks 基于用户现有的 Unity 目录 策略强制实施所有权限。
为了管理应用在用户授权下代表用户执行时产生的安全风险,Azure Databricks 使用范围来限制应用可以通过用户授权执行的操作。
应用需要遵守单个用户权限时应用用户授权。 典型用例包括:
- 查询表或卷
- 访问 SQL 仓库或计算
- 运行绑定到用户操作的作业或工作流
所有操作都使用用户的现有 Unity Catalog 权限。
用户授权通过向应用活动应用行级筛选器和列掩码等 Unity 目录功能实现精细的访问控制。 此方法使访问控制与工作区治理保持一致,并避免将权限逻辑硬编码到应用中。
通过用户授权实现细化权限
向应用添加用户授权时,它会强制用户现有的 Unity 目录权限,包括:
- 用于限制可见行的行级别筛选器
- 用于编辑或转换敏感数据的列掩码
由于 Azure Databricks 使用用户的标识评估用户授权请求,因此当应用访问数据时,这些策略会自动应用。 例如,如果表包含限制按区域的可见性的行筛选器,则应用仅返回允许用户查询的行。 应用中不需要其他筛选逻辑。
此方法可避免在应用程序代码中复制访问控制逻辑,并确保与工作区级别的治理保持一致。 当管理员更新 Unity 目录策略时,应用会自动尊重这些更改。
基于作用域的安全性和权限提升
使用用户授权的应用必须声明特定的授权范围,以限制应用可以代表用户执行的作。 范围限制对特定 API 或资源类型的访问,例如:
-
sql用于查询 SQL 仓库 -
dashboards.genie用于管理 Genie 空间 -
files.files用于管理文件和目录
如果未选择任何范围,Azure Databricks 会分配一个默认集,该集允许应用检索基本用户标识信息:
iam.access-control:readiam.current-user:read
这些默认值是支持用户授权功能所必需的,但它们不允许访问数据或计算资源。 创建或编辑应用时添加其他范围。
范围强制实施最低特权原则。 确保将应用配置为仅请求它所需要的范围。 即使用户具有权限,Azure Databricks 也会阻止访问已批准范围之外的任何功能。 例如,如果应用程序只请求权限范围 sql,则它无法访问模型服务端点,即使用户在应用程序之外可以访问。
当用户首次访问应用时,Azure Databricks 会提示他们显式授权应用在请求的范围内进行作。 管理员可以选择代表用户授予同意,以便使访问权限符合组织政策。
将范围添加到应用
Important
用户授权为公共预览版。 工作区管理员必须先启用它,然后才能将范围添加到应用。
启用用户授权后,必须先重启现有应用,然后才能向其添加范围。 如果禁用用户授权,则必须重启现有应用,以便他们停止使用当前用户的访问令牌访问资源。
在 Azure Databricks UI 中创建或编辑应用时配置用户授权。
在 “配置 ”步骤中,单击“ +添加范围 ”并选择定义应用可以代表用户访问哪些 Azure Databricks API 或资源的范围。 Azure Databricks 在运行时强制实施这些范围,并在授予访问权限之前要求用户或管理员同意。
有关完整示例,请参阅 GitHub 上的 Databricks Apps 授权演示。 该示例应用演示如何同时使用应用和用户授权模型,并包括使用用户授权的设置说明和示例查询。
检索用户授权凭据
对于用户授权,Azure Databricks 将用户的标识和访问令牌转发到 HTTP 标头中的应用。 应用必须提取这些头部信息才能代表用户执行操作。
检索这些标头的方式取决于所使用的框架。
Streamlit
import streamlit as st
user_access_token = st.context.headers.get('x-forwarded-access-token')
Gradio
import gradio as gr
def query_fn(message, history, request: gr.Request):
access_token = request.headers.get("x-forwarded-access-token")
...
如果将其声明为参数,Gradio 会自动将请求对象注入应用的函数中。 无需手动构造或提取请求。
Dash 和 Flask
from flask import request
headers = request.headers
user_token = headers.get('x-forwarded-access-token')
Shiny
user_token = session.http_conn.headers.get('x-forwarded-access-token')
快速
import express from 'express';
const userAccessToken = req.header('x-forwarded-access-token');
示例:使用用户授权进行查询
在这种情况下,应用将用户的访问令牌直接传递给连接器,Azure Databricks 将用户的权限应用于查询。
Python
from databricks import sql
from databricks.sdk.core import Config
from flask import request
cfg = Config()
user_token = request.headers.get("x-forwarded-access-token")
conn = sql.connect(
server_hostname=cfg.host,
http_path="<your-warehouse-http-path>",
access_token=user_token
)
query = "SELECT * FROM main.sandbox.sales_customers LIMIT 1000"
with conn.cursor() as cursor:
cursor.execute(query)
df = cursor.fetchall_arrow().to_pandas()
print(df.head())
conn.close()
JavaScript
import { DBSQLClient } from '@databricks/sql';
import express from 'express';
const app = express();
app.get('/', async (req, res) => {
const userToken = req.header('x-forwarded-access-token');
const client = new DBSQLClient();
const connection = await client.connect({
authType: 'access-token',
host: process.env.DATABRICKS_SERVER_HOSTNAME,
path: process.env.DATABRICKS_HTTP_PATH,
token: userToken,
});
const query = 'SELECT * FROM main.sandbox.sales_customers LIMIT 1000';
const cursor = await connection.cursor(query);
const rows = [];
for await (const row of cursor) {
rows.push(row);
}
console.log(rows.slice(0, 5));
await connection.close();
res.send('Query complete');
});
app.listen(3000);
用户授权的最佳做法
生成代表用户执行作的应用时,请遵循以下最佳做法来确保安全且可审核的访问:
- 将应用代码存储在仅可供应用所有者或一组受信任的用户访问的文件夹中。
- 仅向负责应用维护和评审的受信任高级开发人员授予
CAN MANAGE权限。 仅向批准运行应用的特定用户或组授予CAN USE权限。 - 确保令牌不会被打印、记录或写入文件。 这适用于所有日志记录语句、调试工具和错误处理程序。 例如,而不是
print(f"User token: {token}")使用headers = {"Authorization": f"Bearer {token}"}。 - 将每个应用配置为仅请求其功能所需的最低授权范围。
- 在代码评审期间,验证范围和权限设置是否符合安全要求,并且不授予不必要的访问权限。
- 在部署到生产环境之前,对所有应用代码强制进行对等评审。
- 确保应用代码记录代表用户执行的每个作的结构化审核日志,包括用户标识、作类型、目标资源和状态。
身份验证方法
若要获取 Databricks 应用的令牌,用户和服务主体都使用标准 OAuth 2.0 流进行身份验证。 该方法取决于调用方是用户还是自动化工作负荷。
工作区登录(仅限用户):
- 单一登录(SSO): 配置单一登录(SSO)时,用户通过标识提供者进行身份验证。
- 一次性密码(OTP): 如果未配置 SSO,则用户会收到临时密码。
对于 OAuth 流(应用和工作负载):
- 用户到计算机 (U2M) OAuth: 用户进行身份验证,生成的令牌启用用户授权,以便应用可以代表用户执行作。
- 计算机到计算机 (M2M) OAuth: 服务主体使用客户端凭据或联合身份验证进行身份验证。 这些令牌支撑应用授权,其中应用充当自身而不是用户。
有关使用令牌身份验证调用 Databricks 应用的说明,请参阅 使用令牌身份验证连接到 API Databricks 应用。
比较和合并模型
Databricks 应用可以独立使用应用和用户授权,也可以一起使用。 这些模型提供不同的用途,旨在并行工作。
| 授权模型 | 何时使用 | 示例用例: |
|---|---|---|
| 应用授权 | 当应用程序执行操作时,不依赖于用户的身份 | 编写日志、访问共享配置、调用外部服务 |
| 用户授权 | 当应用需要访问当前用户的上下文中的资源时 | 查询 Unity 目录数据、启动计算、强制实施行级权限 |
| 两者 | 当应用程序同时执行共享和特定于用户的操作时 | 使用应用标识记录指标,使用用户标识查询筛选的数据 |