可易

安全地把 Gemini Enterprise 连接到 Snowflake 数据

可易团队阅读约 10 分钟

按步骤把 Gemini Enterprise 经 ADK 与 MCP 连到 Snowflake:配置 OAuth、最小权限角色和 Cortex Agent,并在用户会话内执行 SQL。

目录

#安全地把 Gemini Enterprise 连接到 Snowflake 数据

企业 AI 需要超越简单的聊天界面。要提供真正的价值,AI 智能体必须访问数据仓库以生成可执行的洞察,同时维持严格的安全与数据治理。

本指南探讨如何在 Google Cloud 的 Gemini Enterprise 与 Snowflake 之间建立安全桥梁。通过使用模型上下文协议(Model Context Protocol,MCP)和 Google 智能体开发工具包(Agent Development Kit,ADK),你可以让智能体充当助手:它理解自然语言,经 Snowflake Cortex 生成精确 SQL,并以用户级权限执行查询。

选择合适的集成模式

直接连接与自定义编排

本文演示的 Google ADK 架构代表高级 / 自定义编排模式。它面向在 Google Cloud 上构建复杂多智能体系统的开发者,例如把 Snowflake 洞察与外部企业工具、自定义推理循环,或 Gemini Agent Engine 中的跨平台状态管理组合在一起的工作流。

对于希望把 Gemini Enterprise 直接连到 Snowflake 的标准企业基础用例,使用此链接中提到的联合方案。

架构方法

该架构允许业务用户提出这样的问题:_"What were our top 5 selling items in Texas last quarter?"_

智能体并不向客户端暴露原始 SQL 执行,而是把查询生成和执行都委托给通过 Snowflake MCP 服务器暴露的、受治理的 Snowflake Cortex Agent:

  1. 受治理的转换:ADK 智能体把用户的自然语言问题传给 Snowflake MCP 服务器,后者调用由 Cortex Analyst 语义视图支持的 Cortex Agent(CORTEX_AGENT_RUN)。
  2. 在受治理边界内直接执行:Cortex Agent 把问题转换成 SQL,并使用已认证用户的 OAuth 会话和角色权限,在 Snowflake 内部直接执行,再把结构化结果返回给 ADK 智能体。

这种方法提供映射到企业语义定义的确定性文本到 SQL 转换,把查询执行保持在 Snowflake 的受治理边界内,并降低模式幻觉或未校验 SQL 执行的风险。

系统架构流

下图说明 Gemini Enterprise 应用与 Snowflake 生态之间的信任边界,以及带编号的执行流。

Gemini Enterprise 与 Snowflake 之间的信任边界和执行流

详细执行序列

为说明智能体如何经 MCP 把自然语言查询转换和受治理执行委托给 Snowflake Cortex Agent,见下面的序列图:

经 MCP 把自然语言查询委托给 Snowflake Cortex Agent 的序列

步骤 1:设置 Snowflake 安全集成

企业 AI 的一个主要风险,是通过通用服务账户授予模型宽泛访问,这可能让用户绕过安全限制。我们通过使用 OAuth 2.0 做用户模拟来解决这一点。

首先,在 Snowflake 中建立一个机密 OAuth 客户端,以保护客户端密钥。下面的片段在 Snowflake 内配置安全集成:

USE ROLE ACCOUNTADMIN;
CREATE OR REPLACE SECURITY INTEGRATION <SECURITY_INTEGRATION_NAME>
TYPE = OAUTH
ENABLED = TRUE
OAUTH_CLIENT = CUSTOM
OAUTH_CLIENT_TYPE = 'CONFIDENTIAL'
-- Google Cloud's official handshake receiver address:
OAUTH_REDIRECT_URI = 'https://vertexaisearch.cloud.google.com/oauth-redirect'
OAUTH_ISSUE_REFRESH_TOKENS = TRUE
-- Let the connection stay alive for 90 days (max Snowflake allowed limit)
OAUTH_REFRESH_TOKEN_VALIDITY = 7776000;

要取回 Google Cloud 配置所需的已生成客户端凭证,在 Snowflake 中运行以下命令:

-- Retrieve OAuth Client ID and Client Secret
SELECT SYSTEM$SHOW_OAUTH_CLIENT_SECRETS('<SECURITY_INTEGRATION_NAME>');

步骤 2:数据治理与访问控制

通过在 Snowflake 内为智能体创建专用角色,应用最小权限原则。

USE ROLE SECURITYADMIN;
-- 1. Create a dedicated role
CREATE ROLE IF NOT EXISTS <GENAI_ROLE_NAME>;
GRANT ROLE <GENAI_ROLE_NAME> TO USER <BUSINESS_USER_NAME>;
USE ROLE SYSADMIN;
-- 2. Grant structural access
GRANT USAGE ON DATABASE <DATABASE_NAME> TO ROLE <GENAI_ROLE_NAME>;
GRANT USAGE ON SCHEMA <DATABASE_NAME>.<SCHEMA_NAME> TO ROLE <GENAI_ROLE_NAME>;
-- 3. Grant compute access
GRANT USAGE ON WAREHOUSE <WAREHOUSE_NAME> TO ROLE <GENAI_ROLE_NAME>;
-- 4 .Grant access to the semantic layer
GRANT SELECT, REFERENCES ON SEMANTIC VIEW <DATABASE_NAME>.<SCHEMA_NAME>.<SEMANTIC_VIEW_NAME> TO ROLE <GENAI_ROLE_NAME>;
-- 5. Grant select privileges on underlying raw data tables
GRANT SELECT ON ALL TABLES IN SCHEMA <DATABASE_NAME>.<SCHEMA_NAME> TO ROLE <GENAI_ROLE_NAME>;

重要

  • 用户上下文必须对支撑语义视图的物理表拥有 SELECT 权限。只授予语义视图的访问会在查询执行期间造成运行时错误。
  • 如果安全策略不允许直接访问基表,在物理表上放置一个 Snowflake Secure View,并在其上构建语义视图。因为 Snowflake 视图以所有者权限(Owner's Rights)执行,用户的 GenAI 角色只需要对 Secure View 和语义视图的 SELECT 权限,而不需要对原始表的权限。
  • Snowflake OAuth 令牌在授权的精确时刻捕获并绑定用户的 DEFAULT_ROLE 和 DEFAULT_WAREHOUSE。如果用户在这些默认值配置之前授权连接,会话会被锁定到错误的角色(当时可用的角色),若预期角色没有所需权限,查询执行将失败。
  • 设置默认值(如下所示),再在 Gemini Enterprise 中授权。
  • 授权连接:让用户在 Gemini Enterprise 中执行一次性 OAuth 授权。
  • (可选)恢复默认值:一旦授权完成,用户可以安全地把 Snowflake 中的默认角色和仓库恢复为自己的标准运维偏好。
ALTER USER <BUSINESS_USER_NAME> SET DEFAULT_ROLE = '<GENAI_ROLE_NAME>';
ALTER USER <BUSINESS_USER_NAME> SET DEFAULT_WAREHOUSE = '<WAREHOUSE_NAME>';

步骤 3:在 Snowflake 内供给 Cortex Agent 和 MCP 服务器

接下来,使用语义视图在 Snowflake 中创建一个受治理的 Cortex Agent,然后供给一台通过 CORTEX_AGENT_RUN 工具类型暴露该智能体的 MCP 服务器。这种方法把 SQL 生成和查询执行都委托给 Snowflake,同时强制调用方的 OAuth 身份和角色权限。

USE DATABASE <DATABASE_NAME>;
USE SCHEMA <SCHEMA_NAME>;
USE ROLE SYSADMIN;
​
-- 1. Create the Cortex Agent over your semantic view
CREATE OR REPLACE AGENT <AGENT_NAME>
  COMMENT = 'Governed data assistant for business queries'
  PROFILE = '{"cortex_analyst": {"semantic_models": ["<DATABASE_NAME>.<SCHEMA_NAME>.<SEMANTIC_VIEW_NAME>"]}}';
​
-- 2. Provision the MCP Server exposing the Cortex Agent
CREATE OR REPLACE MCP SERVER <SERVER_NAME>
FROM SPECIFICATION $$
tools:
  - name: "run_cortex_agent"
    type: "CORTEX_AGENT_RUN"
    identifier: "<DATABASE_NAME>.<SCHEMA_NAME>.<AGENT_NAME>"
    title: "Cortex Agent Assistant"
    description: "Converts natural language questions into SQL and executes them directly within Snowflake using the caller's OAuth session permissions."
$$;

隔离与治理说明:通过使用 CORTEX_AGENT_RUN,查询生成和执行完全保持在 Snowflake 的受治理安全边界内。避免向外部客户端暴露 SYSTEM_EXECUTE_SQL 这类原始执行工具,因为这样做会引入不必要的安全面,并绕过集中的 Cortex Agent 治理。

步骤 4:定位并构造 MCP 服务器 URL

ADK 代码需要你的 Snowflake 托管 MCP 服务器的端点 URL。服务器供给完成后,必须先授予对该服务器的访问,然后可以在 Snowflake 工作表中用以下查询取回其确切端点 URL:

-- 1. Grant access to the Cortex Agent and the MCP server
USE ROLE SECURITYADMIN;
GRANT USAGE ON AGENT <DATABASE_NAME>.<SCHEMA_NAME>.<AGENT_NAME> TO ROLE <GENAI_ROLE_NAME>;
GRANT USAGE ON MCP SERVER <DATABASE_NAME>.<SCHEMA_NAME>.<SERVER_NAME> TO ROLE <GENAI_ROLE_NAME>;
-- 2. View the MCP URL
DESCRIBE MCP SERVER <DATABASE_NAME>.<SCHEMA_NAME>.<SERVER_NAME>;
-- Or:
DESC MCP SERVER <DATABASE_NAME>.<SCHEMA_NAME>.<SERVER_NAME>;

在命令输出中检查元数据属性以定位端点链接。URL 结构如下:

https://<org_name>-<account_name>.snowflakecomputing.com/api/v2/databases/<database_name>/schemas/<schema_name>/mcp-servers/<server_name>

步骤 5:通过 Google ADK 连接

MCP 服务器已创建且其 URL 已解析后,使用 Google Agent Development Kit(ADK)编写智能体代码。在 Python 代码中定义唯一标识符 AUTH_ID(例如 snowflake_oauth_conn),智能体将用它提取用户凭证。

import os
import re
from typing import Optional
from google.adk.agents.llm_agent import LlmAgent
from google.adk.tools.mcp_tool.mcp_toolset import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
from google.adk.tools.tool_context import ToolContext
​
# Define the Auth ID first in your code.
# You will use this exact name when registering the agent in the Google Cloud Console.
# Gemini Enterprise maps the authorization token to this identifier in the ToolContext.
AUTH_ID = "snowflake_oauth_conn"
​
# 1. OAuth Header Extraction:
# Define a callback to dynamically extract the user's OAuth token injected by Gemini Enterprise
# and generate the Authorization headers required to authenticate with the Snowflake MCP.
def get_auth_headers(tool_context: Optional[ToolContext] = None) -> dict:
    """
    OAuth Handling Callback: Dynamically extracts the user's OAuth token injected by Gemini Enterprise and generates the headers required to authenticate with the Snowflake MCP.
    """
    token = None
    if tool_context and hasattr(tool_context, "state"):
        try:
            # Parse the state dictionary injected by Gemini Enterprise containing authorization states
            state_dict = tool_context.state.to_dict() if hasattr(tool_context.state, 'to_dict') else tool_context.state
            pattern = re.compile(fr".*{re.escape(AUTH_ID)}.*", re.IGNORECASE)
            # Find the active token matching our Auth ID (snowflake_oauth_conn)
            matching_keys = [k for k in state_dict.keys() if pattern.match(k)]
            if matching_keys:
                token = state_dict.get(matching_keys[0])
        except Exception as e:
            print(f"Warning: Failed to read ToolContext OAuth state: {e}")
    # Return authorization headers. If token is None, requests to MCP will fail.
    return {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
        "Accept": "application/json, text/event-stream",
    }
​
# 2. MCP Initialization:
# Define the Snowflake MCP URL retrieved from 'DESCRIBE MCP SERVER' directly in the code:
MCP_SERVER_URL = "<YOUR_MCP_SERVER_URL>" # Replace with the URL retrieved from 'DESCRIBE MCP SERVER'
​
# Initialize the Snowflake MCP Toolset using this URL.
snowflake_mcp = McpToolset(
    connection_params=StreamableHTTPConnectionParams(
        url=MCP_SERVER_URL
    ),
    header_provider=get_auth_headers
)
​
# 3. Build the Agent:
# Construct the LlmAgent using the Gemini 2.5 Flash model and attach the Snowflake MCP Toolset.
root_agent = LlmAgent(
    model="gemini-2.5-flash",
    name="enterprise_data_analyst",
    instruction=(
        "You are an enterprise data analyst. Use the `enterprise_data_agent` tool "
        "on the Snowflake MCP server to answer business questions. Pass the user's "
        "natural language question to the tool, which translates it into SQL and "
        "executes it directly within Snowflake's governed boundary, then present "
        "the results clearly to the user."
    ),
    tools=[snowflake_mcp]
)

说明:上面的 Python 片段代表智能体设置的朴素 / 基础版本(plain/vanilla version)。根据组织的具体要求,你应在此模板上增加稳健性(例如自定义错误处理、结构化模式、自定义提示、配置,以及其他工具包装)。

步骤 6:项目结构与部署

要把 ADK 智能体部署到 Agent Platform 中的 Agent Runtime,按以下目录布局组织文件:

snowflake_agent/
├── agent.py # The agent definition and MCP connection code (from Step 5)
├── __init__.py # Package initializer exposing the agent
├── .env # Environment configurations (Google Cloud Project, etc.)
└── requirements.txt # List of project dependencies (google-adk, etc.)
  1. 文件细节
  • \_\_init\_\_.py:向部署 CLI 暴露 root_agent 对象:
# Snowflake ADK Agent package
from .agent import root_agent
  • .env:声明环境配置:
GOOGLE_CLOUD_PROJECT="<YOUR_GCP_PROJECT_ID>"
GOOGLE_CLOUD_LOCATION="<LOCATION>"
GOOGLE_GENAI_USE_VERTEXAI="TRUE"
  • requirements.txt:指定依赖:
google-adk[mcp]==2.3.0
google-genai==2.10.0
pydantic-settings==2.14.2
google-cloud-aiplatform[agent_engines]>=1.50.0

2. 通过 CLI 部署

你不必运行复杂的自定义 Python 脚本或手工容器构建,可以使用官方 Google Agents CLI(agents-cli)部署。CLI 打包代码、设置服务器,并处理部署流水线:

# Deploy the agent to the Google Cloud Agent Runtime
agents-cli deploy --deployment-target agent_runtime

CLI 自动处理部署生命周期。完成后,它输出唯一的项目资源路径(例如 projects/PROJECT_ID/locations/LOCATION/reasoningEngines/RESOURCE_ID),你将在下一步用它注册智能体。

提示:关于 ADK 智能体部署的更多信息和高级配置选项,参阅:

步骤 7:在 Gemini Enterprise 中注册自定义智能体

智能体代码就绪并部署后,在 Google Cloud Console 中注册该智能体。在这里把智能体配置连接起来,并映射从 Snowflake Security Integration 取回的 OAuth 参数。

  1. 从 Snowflake 提取 OAuth 端点

在 Snowflake 中运行此查询,以提取精确的令牌端点和授权端点:

DESCRIBE SECURITY INTEGRATION <SECURITY_INTEGRATION_NAME>;

在结果中找到以下属性的值:

  • OAUTH_AUTHORIZATION_ENDPOINT:你的 Snowflake 授权 URI。
  • OAUTH_TOKEN_ENDPOINT:你的 Snowflake 令牌 URI。

2. Google Cloud 控制台中的注册步骤

  1. 进入控制台中的 Gemini Enterprise 页面。
  2. 选择要用来注册智能体的应用。
  3. 在左侧导航中点击 Agents,然后点击 + Add agent。
  4. 对 Custom agent via Agent Platform 选择 Add。授权设置界面出现。
  5. 设置 Snowflake OAuth 连接:
  • 点击 Add authorization。
  • Authorization name:输入你在 ADK 代码中定义的精确 ID(例如 snowflake_oauth_conn)。这确保凭证正确映射到代码中的 AUTH_ID。
  • Client ID 与 Client secret:输入你使用 SYSTEM$SHOW_OAUTH_CLIENT_SECRETS 查询从 Snowflake 取回的凭证。
  • Token URI:输入从 DESCRIBE SECURITY INTEGRATION 提取的精确令牌端点值。
  • Authorization URI:取从 DESCRIBE SECURITY INTEGRATION 提取的授权端点值,并在末尾追加 ?response_type=code(连同客户端 ID 和作用域查询参数,例如):
https://<org_name>-<account_name>.snowflakecomputing.com/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=https%3A%2F%2Fvertexaisearch.cloud.google.com%2Foauth-redirect&scope=session%3Arole-any&response_type=code

重要

确保 Authorization URI 以 &response_type=code 结尾(如果没有其他参数,则以 ?response_type=code 结尾)。Google Cloud 需要该参数来触发 OAuth 2.0 授权码流程。

  • 点击 Done,然后点击 Next。
  1. 配置智能体属性:
  1. 点击 Create 完成注册。

理解标识符对齐

  • ADK 代码 AUTH_ID <==> Google Cloud Authorization Name:Python 脚本中的 AUTH_ID 必须与控制台注册时输入的 Authorization Name/ID 完全一致。因为我们先写代码,所以注册时复用代码中定义的标识符。
  • Snowflake Security Integration 名称(例如 <SECURITY_INTEGRATION_NAME>):这纯粹是 Snowflake 侧的数据库对象名。它不需要与 Google Cloud Authorization Name 或 ADK Python 代码中的 AUTH_ID 一致。

开始使用

把 Gemini 模型的推理能力、ADK 的编排和 Snowflake 的受治理数据层结合在一起,就可以安全地把 AI 带到你的数据上。该架构提供一个尊重安全边界、同时交付业务价值的智能体助手。 PRIMARY_SOURCE: https://cloud.google.com/blog/products/data-analytics/bridge-gemini-enterprise-and-snowflake-with-google-adk

  • #Gemini Enterprise
  • #Snowflake
  • #MCP
  • #OAuth
  • #ADK