在 Databricks 應用程式中設定授權

Databricks Apps 支援在 Azure Databricks 上的安全應用程式開發。 當應用程式存取工作區內的數據和服務時,他們必須使用強制執行數據訪問控制並尊重使用者許可權的驗證和授權機制。 Databricks Apps 授權模型是以 OAuth 2.0 為基礎,並將指派給應用程式的許可權與存取應用程式的許可權結合在一起。

為了支援此架構,Databricks Apps 使用兩個互補的身分識別模型:

  • 應用程式授權 會提供應用程式自己的身分識別,並具有一組一致的許可權。
  • 用戶授權 可讓應用程式使用與其互動之使用者的身分識別和許可權。

應用程式授權

每個 Azure Databricks 應用程式都有專屬的 service principal,作為其在存取 Azure Databricks 資源時的身份。 此服務主體是應用程式執行個體的唯一,無法跨應用程式重複使用。 您無法在建立應用程式期間變更指派給應用程式的服務主體,或指定現有的服務主體。 Azure Databricks 利用此身分識別獨立於任何使用者來評估應用程式的權限,確保該應用程式只能存取明確授權的資源,甚至在沒有使用者互動的情況下也可存取。

此分隔有助於強化安全性界限,使得應用程式活動的稽核得以進行,也支援背景處理或自動化任務等情境。

服務主體以唯一識別碼來表示。 從應用程式的 「授權」 標籤複製它:

在 Databricks 應用程式中檢視服務主體

當你建立應用程式時,Azure Databricks 會自動為該應用程式配置專用的服務主體。 服務主體在應用程式的所有部署中都會保持不變。 當你刪除應用程式時,Azure Databricks 會刪除服務主體。

請使用服務主體來執行應用程式自行進行的操作,此操作不需要個別用戶的上下文。 常見的使用案例包括:

  • 執行背景任務
  • 讀取或寫入共用設定或元數據
  • 記錄活動或使用計量
  • 透過安全端點呼叫外部服務

應用程式起始的所有動作都會使用服務主體的許可權。 使用標準權限指派,授與服務主體特定資源的存取權。 不過,它不支援用戶層級訪問控制。 與應用程式互動的所有用戶都會共用服務主體所定義的相同許可權,這可防止應用程式根據個別使用者身分識別強制執行更細緻的原則。

下列範例顯示應用程式如何使用其服務主體來查詢 Unity 目錄中的數據:

檢視服務主體在應用程式中的驗證方式

在此情況下,服務主體需要明確存取 SQL 倉儲和它所查詢的 Unity 目錄數據表。

當您想要讓應用程式的所有使用者看到相同的數據,或當應用程式執行未系結至使用者特定存取控制的共享作業時,此模型可正常運作。

擷取應用程式授權認證

對於應用程式授權,Azure Databricks 會自動將服務主體憑證注入應用程式的環境中。 下列環境變數會保存必要的 OAuth 用戶端值:

Variable Description
DATABRICKS_CLIENT_ID 服務主體 OAuth 用戶端識別碼
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

如果你使用 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 向服務主體進行驗證,並使用 Databricks SQL Driver for Node.js執行查詢。

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 Catalog 政策強制執行所有權限。

為了管理代表使用者行動的應用程式的安全風險,Azure Databricks 使用範圍限制應用程式透過使用者授權可執行的動作。

當應用程式需要遵守個別用戶權力時,請套用用戶授權。 一般使用案例包括:

  • 查詢數據表或磁碟區
  • 存取 SQL 倉儲或計算資源
  • 執行與使用者動作相關的作業或工作流程

所有動作都會使用使用者的現有 Unity 目錄權限:

檢視使用者在應用程式中的驗證方式

使用者授權可藉由將數據列層級篩選和數據行遮罩等 Unity 目錄功能套用至應用程式活動,以啟用更細緻的訪問控制。 此方法可讓訪問控制與工作區控管保持一致,並避免將許可權邏輯硬式編碼到應用程式中。

具有使用者授權的精細權限

當您將使用者授權新增至應用程式時,它會強制執行使用者現有的 Unity 目錄許可權,包括:

  • 行級篩選以限制可見的行
  • 用來編輯或轉換敏感資料的欄位遮罩

由於 Azure Databricks 會以使用者身份評估使用者授權請求,因此當應用程式存取資料時,這些政策會自動套用。 例如,如果數據表包含限制依區域可見度的數據列篩選,則應用程式只會傳回使用者允許查詢的數據列。 應用程式中不需要額外的篩選邏輯。

此方法可避免在應用程式程式代碼中複製訪問控制邏輯,並確保工作區層級治理的一致性。 當系統管理員更新 Unity 目錄原則時,應用程式會自動遵守這些變更。

以範圍為基礎的安全性和許可權提升

使用使用者授權的應用程式必須宣告特定的授權範圍,以限制應用程式代表使用者的行為。 範圍會限制特定 API 或資源類型的存取,例如:

  • sql 用於查詢 SQL 倉儲
  • dashboards.genie 用於管理 Genie 空間
  • files.files 用於管理檔案和目錄

如果你沒有選擇任何範圍,Azure Databricks 會指派一個預設範圍,讓應用程式能夠取得基本的使用者身份資訊:

  • iam.access-control:read
  • iam.current-user:read

這些預設值需要支援用戶授權功能,但不允許存取數據或計算資源。 建立或編輯應用程式時,請新增其他範圍。

範圍會落實最低許可權原則。 請務必將應用程式設定為只要求它所需的範圍。 Azure Databricks 會阻擋任何超出核准範圍的功能存取,即使使用者擁有權限。 例如,如果應用程式只請求sql範圍,即使使用者可以在應用程式外部存取模型服務端點,也無法存取。

當使用者首次存取應用程式時,Azure Databricks 會提示他們明確授權該應用程式在所要求的範圍內行動。 用戶同意後,就無法撤銷同意。 系統管理員可以選擇性地代表使用者授予同意,以符合組織政策的存取要求。

將範圍新增至應用程式

Important

使用者授權處於 公開預覽狀態。 您的工作區管理員必須先啟用它,才能將範圍新增至您的應用程式。

啟用使用者授權之後,您必須先重新啟動現有的應用程式,才能將範圍新增至這些應用程式。 如果您停用使用者授權,則必須重新啟動現有應用程式,才能停止使用目前使用者的存取權杖來存取資源。

在 Azure Databricks UI 中建立或編輯應用程式時,請設定使用者授權。

User authorization 中,點選 +Add scope,選擇定義應用程式可代表使用者存取的 Azure Databricks API 或資源範圍。 Azure Databricks 在執行時強制執行這些範圍,並需取得使用者或管理員的同意後才能授權存取權限。

將使用者授權範圍新增至 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 Apps 的權杖,使用者和服務主體都會使用標準 OAuth 2.0 流程進行驗證。 方法取決於呼叫端是使用者還是自動化工作負載。

對於工作區登入(僅限使用者):

  • 單一登入 (SSO): 設定單一登入 (SSO) 時,使用者會透過您的身分識別提供者進行驗證。
  • 一次性密碼 (OTP): 如果未設定 SSO,使用者會收到暫時密碼。

對於 OAuth 流程 (應用程式和工作負載):

  • 使用者對機器 (U2M) OAuth 使用者進行驗證,產生的權杖會啟用使用者授權,讓應用程式可以代表使用者執行動作。
  • 機器對機器 (M2M) OAuth 服務主體會使用用戶端認證或同盟進行驗證。 這些令牌支撐應用程式授權,其中應用程式充當自己而不是使用者。

如需使用權杖驗證呼叫 Databricks 應用程式的指示,請參閱 使用權杖驗證連線到 API Databricks 應用程式

比較和合併模型

Databricks Apps 可以獨立或一起使用應用程式和用戶授權。 這些模型有不同的用途,且設計為平行運作。

授權模型 使用時機 範例使用案例
應用程式授權 當應用程式執行不相依於使用者身分識別的作業時 寫入記錄、存取共用組態、呼叫外部服務
使用者授權 當應用程式需要存取目前用戶內容中的資源時 查詢 Unity 目錄數據、啟動計算、強制執行資料列層級許可權
Both 當應用程式同時執行共用和使用者特定作業時 使用應用程式身分識別記錄計量、使用使用者身分識別查詢篩選的數據