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

使用者授權

使用者授權,有時稱為 代表用戶授權,可讓 Databricks Apps 應用程式以應用程式使用者的身分行事。 Azure Databricks 會將使用者的存取權杖轉發給應用程式,應用程式利用該權杖代表使用者存取資源。 Azure Databricks 根據使用者現有的 Unity Catalog 政策強制執行所有權限。

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

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

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

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

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

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

Note

轉發的使用者權杖,其範圍限定於應用程式執行所在的工作區。 你不能用它來查詢 SQL 倉庫或存取其他工作空間中的資源。 若要連接運行於另一個工作區的倉庫,請使用以下方法之一:

  • 在承載倉庫的工作區部署應用程式。 這是最簡單的選項,且因為轉發的使用者令牌在該工作區有效,能保留每位使用者權限的強制執行。
  • 使用服務主體來認證目標工作空間。 如果你不需要每個使用者強制執行權限,建議使用 M2M OAuth ,搭配一個能存取該工作區倉庫的服務主體,而不是轉發的使用者憑證。 所有應用程式使用者隨後共享服務主體的權限。

透過使用者授權實現細緻權限控管

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

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

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

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

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

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

  • sql 用於查詢 SQL 倉儲
  • genie 用於管理您的 Genie Agent
  • files 用於管理檔案和目錄

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

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

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

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

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

將範圍新增至應用程式

在 Azure Databricks UI 或 Databricks CLI 中新增授權範圍。

UI

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

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

將使用者授權範圍新增至 Databricks 應用程式

CLI

建立或更新應用程式時傳入 user_api_scopes:

databricks apps create <app-name> \
  --json '{
    "user_api_scopes": ["sql", "files"]
  }'
databricks apps create-update <app-name> \
  --json '{
    "update_mask": "user_api_scopes",
    "app": {
      "user_api_scopes": ["sql", "files"]
    }
  }'

完整範例請參見 GitHub 上的 Databricks Apps 授權示範。 範例應用程式示範如何使用應用程式和使用者授權模型,並包含具有使用者授權的設定指示和範例查詢。

支援的範圍

Azure Databricks Apps 支援以下 Azure Databricks API 範圍:

Azure Databricks Apps 也支援以下 SDK 範圍。 這些範圍可利用 :read 修飾符限制對 GET 端點的存取。

以下範圍已淘汰。 還是用目前的瞄準鏡吧。

已棄用的範圍 現行範圍
dashboards.genie genie
files.files files
serving.serving-endpoints model-serving
serving.serving-endpoints-data-plane model-serving
sql.alerts sql
sql.alerts-legacy sql
sql.dashboards sql
sql.data-sources sql
sql.dbsql-permissions sql
sql.queries sql
sql.queries-legacy sql
sql.query-history sql
sql.statement-execution sql
sql.warehouses sql
vectorsearch.vector-search-endpoints vector-search
vectorsearch.vector-search-indexes vector-search

限制使用者授權範圍

Workspace 管理員可以控制應用程式開發者可以新增哪些 OAuth 範圍到工作區中的應用程式。

UI

  1. 按下 Azure Databricks 工作區頂端列中的使用者名稱,然後選取 [設定]。
  2. 點擊 開發。
  3. 在 應用程式中,找到 「限制 OAuth 應用程式至選取值 範圍」設定,並設定允許清單。
  4. 重新整理頁面以使變更生效。

預設值為 All APIs,可允許所有受支援的範圍。 選擇 「無」 則會停用使用者授權。

CLI

使用 Databricks CLI 來取得或更新範圍允許清單。

要取得目前的設定:

databricks workspace-settings-v2 get-public-workspace-setting allowedAppsUserApiScopes

若要設定特定允許的範圍:

databricks workspace-settings-v2 patch-public-workspace-setting allowedAppsUserApiScopes \
  --json '{
    "allowed_apps_user_api_scopes": {
      "allowed_scopes": ["sql", "files"]
    },
    "name": "allowedAppsUserApiScopes"
  }'

允許所有範圍(預設):

databricks workspace-settings-v2 patch-public-workspace-setting allowedAppsUserApiScopes \
  --json '{
    "allowed_apps_user_api_scopes": {
      "allowed_scopes": ["*"]
    },
    "name": "allowedAppsUserApiScopes"
  }'

要停用使用者授權,請設 allowed_scopes 為空陣列([])。

帳號管理員可以為應用程式新增範圍,即使這些範圍不在工作區允許清單中。

Note

已經在執行的應用程式會繼續使用現有的範圍。 你無法啟動、部署或更新應用程式,除非移除不允許的範圍。

取得使用者授權憑證

使用者授權時,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 當應用程式同時執行共用和使用者特定作業時 使用應用程式身分識別記錄計量、使用使用者身分識別查詢篩選的數據