Snowflake edge connector
Run local or VPC-hosted RLM analysis against Snowflake while Snowflake credentials remain in a trusted broker. Generated Python talks to that broker with a short-lived capability; it never receives the Snowflake account credential or driver configuration.
The connector is a deployment preview. It requires the mrl Edge image, a customer-provisioned Snowflake service identity, and an explicit local SQL policy.
What lives where
ModelRelay owns the Snowflake connector, authentication, SQL policy validation, hard result limits, and operator commands. Droste remains the generated-code runtime: it receives only a connector-neutral database capability and uses schema and query operations. Snowflake-specific credentials and policy do not belong in Droste.
flowchart LR
M[ModelRelay model calls] --> R[Droste runner container]
R -->|Bearer capability and schema or query| B[Trusted mrl Snowflake broker]
B -->|Local Snowflake SQL policy| V[Validator]
V -->|Normalized SELECT| S[Snowflake]
The broker returns rows only to the local runner. As with other local RLM sources, generated code can include selected or derived values in model subcalls or the final answer; those values then follow the normal ModelRelay request path. Snowflake credentials and authentication tokens are never sent to ModelRelay.
Quick start
Start from the deployment example in deploy/snowflake-edge:
cp deploy/snowflake-edge/snowflake.json.example \
deploy/snowflake-edge/snowflake.json
export MODELRELAY_API_KEY='mr_sk_...'
export MODELRELAY_SNOWFLAKE_PRIVATE_KEY_FILE="$PWD/snowflake_rsa_key.p8"
export MODELRELAY_SNOWFLAKE_BROKER_TOKEN="$(openssl rand -hex 32)"
docker build -f Dockerfile.edge-snowflake \
-t modelrelay/mrl-edge-snowflake:2.4.0 .
docker compose -f deploy/snowflake-edge/compose.yaml up -d broker
Test authenticated readiness, then run RLM:
docker compose -f deploy/snowflake-edge/compose.yaml exec broker \
/mrl snowflake test-connection --config /run/modelrelay/snowflake.json
MODELRELAY_RLM_QUERY='Compare weekly revenue and explain anomalies' \
docker compose -f deploy/snowflake-edge/compose.yaml \
--profile run run --rm runner
The two services must stay separate. Only broker mounts snowflake.json and the private key; runner receives the broker URL and short-lived capability token.
Snowflake setup
Run deploy/snowflake-edge/setup.sql with an administrator role after replacing its example identifiers. The minimum role needs:
USAGEon one warehouse, the approved database, and approved schemas.- Explicit
SELECTgrants on only the approved tables and views. AvoidALLandFUTUREgrants, and mirror every grant inpolicy.tables.allowlist. - no create, write, stage, procedure, or function privileges.
Use secure views when base-table definitions or sensitive columns must not be exposed. Snowflake continues to enforce secure-view, masking, and row-access policies for the service role. Schema discovery reports accessible tables, columns, table types, and whether a view is secure; it omits view definitions and does not require access to POLICY_REFERENCES.
Keep Snowflake statement timeouts on the service user or warehouse as a second boundary. The effective Snowflake timeout is the lowest nonzero applicable timeout. A resource monitor can additionally suspend the connector warehouse when its credit budget is reached.
Connector configuration
The JSON configuration is owned by the trusted broker. The caller of /v1/sql cannot choose or relax its policy.
{
"snowflake": {
"account": "organization-account",
"user": "MODELRELAY_SERVICE",
"warehouse": "MODELRELAY_RLM_WH",
"database": "ANALYTICS",
"schema": "RLM_APPROVED",
"role": "MODELRELAY_RLM_READONLY",
"auth": {
"type": "key_pair",
"key_pair": {
"private_key_file": "/run/secrets/snowflake_private_key"
}
},
"limits": {
"max_rows": 1000,
"max_response_bytes": 1048576,
"max_timeout_ms": 5000,
"max_queued_timeout_ms": 5000
}
},
"tenant_id": "customer-tenant",
"source_id": "finance-warehouse",
"policy": {
"dialect": "snowflake",
"read_only": true,
"limits": {
"default_limit": 1000,
"max_limit": 1000,
"timeout_ms": 5000
},
"tables": {
"allowlist": ["ANALYTICS.RLM_APPROVED.MONTHLY_REVENUE"]
},
"aggregations": {
"allowed": true,
"functions": ["count", "sum", "avg", "min", "max"]
}
}
}
policy is the authoritative structured SQL policy. Its dialect must be snowflake and read_only must be true; every raw query is validated locally before execution. tenant_id is required and source_id is an optional attribution label. The independent snowflake.limits are host-enforced hard caps. A policy cannot raise them. Requests exceeding the row, encoded-byte, execution-time, or queued-time limit fail closed.
Authentication methods
Set exactly one auth.type and its matching object:
| Method | Configuration | Secret semantics |
|---|---|---|
workload_identity |
provider is AWS, AZURE, GCP, or OIDC; optional impersonation_path, entra_resource, or token_file |
OIDC requires token_file; the file is mounted only in the broker |
oauth_client_credentials |
client_id_env, client_secret_env, HTTPS token_url, and optional scope |
The first two fields name environment variables containing client credentials |
key_pair |
private_key_file and optional passphrase_env |
The broker reads an encrypted or unencrypted PKCS8 PEM file; the optional environment variable contains its passphrase |
The Compose example uses an unencrypted private key. For an encrypted PKCS8 key, set passphrase_env to a variable name inside key_pair and inject that variable only into the broker. Never mount the key, OIDC token file, or OAuth secrets into the runner.
For example, workload identity with an AWS runtime identity is:
{
"auth": {
"type": "workload_identity",
"workload_identity": {"provider": "AWS"}
}
}
OAuth client credentials are:
{
"auth": {
"type": "oauth_client_credentials",
"oauth_client_credentials": {
"client_id_env": "SNOWFLAKE_OAUTH_CLIENT_ID",
"client_secret_env": "SNOWFLAKE_OAUTH_CLIENT_SECRET",
"token_url": "https://identity.example.com/oauth2/token",
"scope": "session:role:MODELRELAY_RLM_READONLY"
}
}
}
Password authentication is not supported. Prefer workload identity where the deployment platform and Snowflake account support it, then OAuth client credentials, then a rotated key pair. The Go connector does not support GCP regional endpoints for workload identity, and Azure sovereign-cloud workload identity is not supported.
Broker and runner commands
Start the trusted broker:
mrl snowflake serve \
--config /run/modelrelay/snowflake.json \
--listen 0.0.0.0:8081 \
--broker-token-env MODELRELAY_SNOWFLAKE_BROKER_TOKEN
Run generated code in a separate process or container:
mrl rlm 'Analyze the approved Snowflake data' \
--snowflake-broker-url http://broker:8081/v1/sql \
--snowflake-broker-token-env MODELRELAY_SNOWFLAKE_BROKER_TOKEN
The broker defaults to 127.0.0.1:8787. Its API is deliberately small:
| Endpoint | Authentication | Purpose |
|---|---|---|
GET /healthz |
None | Process/config liveness only; never returns secrets or rows |
GET /readyz |
Bearer capability | Snowflake readiness check |
POST /v1/sql |
Bearer capability | Policy-validated schema and query operations |
Use GET /healthz for process liveness and mrl snowflake test-connection --config PATH or authenticated GET /readyz for Snowflake readiness. Inspect the approved schema with mrl snowflake schema --config PATH.
Production controls
- Run the broker and runner as nonroot in separate containers or security principals. Never mount the Snowflake config, token file, or private key into the runner.
- Use a read-only root filesystem, a bounded
/tmptmpfs, dropped Linux capabilities, andno-new-privileges. - Restrict broker ingress to the runner network. Restrict egress to Snowflake, required cloud identity or OAuth endpoints, and ModelRelay from the runner.
- Rotate the broker capability per deployment or job. Do not reuse it as a Snowflake or ModelRelay credential. The Compose quickstart passes it as an environment value visible in Docker metadata; production orchestrators should inject it directly without a checked-in env file.
- Search Snowflake query history by the connector’s query tag for attribution and incident response. Query tags contain identifiers only, never SQL results or credentials.
Current limitations
Provisioning the Snowflake account, warehouse, role, identity-provider integration, private connectivity, resource monitor, and policy-protected test fixtures remains customer-owned. Validate private-link DNS and egress from the target VPC before onboarding. General availability also depends on completing a design-partner deployment with secure views or masking/row-access policies in place.