QuotaGuard and Snowflake Integration Guide
QuotaGuard and Snowflake Integration Guide
QuotaGuard gives your Snowflake clients two fixed outbound IP addresses that satisfy a Snowflake network policy. Set your driver’s proxy parameters to point at QuotaGuard, register your two static IPs in the network policy’s allowed list, and every connection reaches Snowflake from an address the policy accepts. This guide covers the Python, JDBC, Node.js, Go, .NET, ODBC, SnowSQL, dbt, and SQLAlchemy clients, plus testing, the native PrivateLink comparison, and troubleshooting.
This page documents connecting to the Snowflake data warehouse over its standard HTTPS interface. It does not cover other Snowflake products.
Why Snowflake Connections Need a Static IP
Snowflake controls connection-level access with network policies. When a network policy is active on your account or on a user, Snowflake checks the source IP of every connection against an allowed IP list and refuses anything not on it. The check runs before authentication, so a correct username, password, and key pair are still rejected if the IP is wrong.
Applications on serverless and PaaS hosts use outbound IP addresses that rotate on every deploy, restart, and scale event. There is no fixed address to put on the allowed list. You cannot list a cloud provider’s published range either, because that range covers thousands of other tenants and defeats the policy.
These clients hit the network policy wall most often:
- Backends on AWS Lambda, Render, Railway, Fly.io, Heroku, and Cloud Functions
- ETL and orchestration jobs on Airflow, dbt, and reverse-ETL tools
- BI and analytics tools connecting from rotating cloud IPs
- CI and CD pipelines running migrations or tests against Snowflake
- Partner integrations connecting into a Snowflake account that mandates IP allowlisting on a shared data set
Two static IPs solve all of these. You register the pair once and the connection stops breaking on every deploy.
Where the Allowed IP List Lives in Snowflake
A network policy is the object that holds the allowed IP list. A user with the SECURITYADMIN role or higher creates and applies it. You build the list one of two ways.
The direct way uses ALLOWED_IP_LIST on the policy:
-- Run as SECURITYADMIN or higher.
-- Use your two QuotaGuard static IPs from the dashboard.
CREATE NETWORK POLICY quotaguard_access
ALLOWED_IP_LIST = ('203.0.113.10', '203.0.113.11');
The newer way uses network rules, which are schema-level objects you can reuse across policies:
CREATE NETWORK RULE quotaguard_ips
MODE = INGRESS
TYPE = IPV4
VALUE_LIST = ('203.0.113.10', '203.0.113.11');
CREATE NETWORK POLICY quotaguard_access
ALLOWED_NETWORK_RULE_LIST = ('quotaguard_ips');
Then activate the policy at the account level, or scope it to a single service user:
-- Whole account...
ALTER ACCOUNT SET NETWORK_POLICY = quotaguard_access;
-- ...or one user instead.
ALTER USER service_user SET NETWORK_POLICY = quotaguard_access;
Four things to know about how this behaves:
- The allowed list accepts individual IPv4 addresses and CIDR ranges, including a single address written as a
/32. It holds multiple entries, so both QuotaGuard IPs go on the same policy. - A user-level network policy takes precedence over the account-level one. If a service user has its own policy, that is the list that applies to it.
- Snowflake automatically blocks every address not on the allowed list. There is no separate block list to maintain for this case.
- Snowflake will not let you apply a policy that would lock out the user setting it. Keep your own current IP on the list alongside the QuotaGuard pair when you activate or change a policy.
In the console, the same objects live under Admin, then Security, then Network Policies. The SQL above is the faster path for a service account.
Getting Started
After creating a QuotaGuard account, you are redirected to your dashboard, where you can find your proxy credentials and two static IP addresses.
Choose the right proxy region: Select the QuotaGuard region closest to your Snowflake account to minimize latency. The region is set at sign-up. Changes after sign-up require contacting support.
Step 1: Set the Proxy URL
Your QuotaGuard Static connection URL has this shape, with the region host taken from your dashboard:
QUOTAGUARDSTATIC_URL="http://username:password@<your-quotaguard-proxy-host>:9293"
The host is region-specific. Use the exact host shown in your dashboard. The HTTP/HTTPS port is 9293.
One Snowflake-specific setting matters here. Snowflake streams large result sets and bulk loads from cloud storage stages on S3, GCS, or Azure, not over the service connection the network policy checks. Keep that storage traffic off the proxy with NO_PROXY, so a large load does not consume your plan bandwidth and does not add a pointless hop:
NO_PROXY=".amazonaws.com"
Match the NO_PROXY suffix to the cloud your Snowflake account runs on: .amazonaws.com for AWS, .core.windows.net for Azure, .googleapis.com for GCP.
Step 2: Route Each Client Through the Proxy
Snowflake connections run over HTTPS, so every driver attaches the proxy the same way in principle: point it at your region host on port 9293. The host, port, and credentials inside every example below come from your dashboard and must be exact.
Python (snowflake-connector-python)
Pass the proxy as connection parameters:
import snowflake.connector
conn = snowflake.connector.connect(
account="myorg-myaccount",
user="SERVICE_USER",
password="...",
warehouse="COMPUTE_WH",
database="ANALYTICS",
schema="PUBLIC",
proxy_host="<your-quotaguard-proxy-host>",
proxy_port=9293,
proxy_user="QG_USERNAME",
proxy_password="QG_PASSWORD",
)
The connector also honors the HTTPS_PROXY and NO_PROXY environment variables, which is the simplest path when you cannot edit the connection call:
export HTTPS_PROXY="http://QG_USERNAME:QG_PASSWORD@<your-quotaguard-proxy-host>:9293"
export NO_PROXY=".amazonaws.com"
JDBC
Set the proxy parameters directly in the connection string:
jdbc:snowflake://myorg-myaccount.snowflakecomputing.com/?user=SERVICE_USER&warehouse=COMPUTE_WH&useProxy=true&proxyHost=<your-quotaguard-proxy-host>&proxyPort=9293&proxyUser=QG_USERNAME&proxyPassword=QG_PASSWORD
The same values can be passed as JVM system properties instead, which is useful when you cannot change the connection string. Since Java 8u111, Basic authentication for HTTPS tunneling through an HTTP proxy is disabled by default, so include -Djdk.http.auth.tunneling.disabledSchemes="" for the credentials to take effect:
-Dhttps.proxyHost=<your-quotaguard-proxy-host>
-Dhttps.proxyPort=9293
-Dhttps.proxyUser=QG_USERNAME
-Dhttps.proxyPassword=QG_PASSWORD
-Djdk.http.auth.tunneling.disabledSchemes=""
Use the JDBC nonProxyHosts parameter to keep stage storage traffic off the proxy, the JDBC equivalent of NO_PROXY.
Node.js (snowflake-sdk)
Pass the proxy as connection options:
const snowflake = require('snowflake-sdk');
const connection = snowflake.createConnection({
account: 'myorg-myaccount',
username: 'SERVICE_USER',
password: '...',
warehouse: 'COMPUTE_WH',
database: 'ANALYTICS',
proxyHost: '<your-quotaguard-proxy-host>',
proxyPort: 9293,
proxyUser: 'QG_USERNAME',
proxyPassword: 'QG_PASSWORD',
proxyProtocol: 'http',
});
Version 1.15.0 and later of the driver also reads the HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables. A value set in the connection options takes precedence over the environment.
Go (gosnowflake)
The Go driver reads the standard proxy environment variables, so you set them once and the driver picks them up. There is a cmd/proxyconnection example in the driver repository.
export HTTPS_PROXY="http://QG_USERNAME:QG_PASSWORD@<your-quotaguard-proxy-host>:9293"
export NO_PROXY=".amazonaws.com"
SQLAlchemy (snowflake-sqlalchemy)
The SQLAlchemy dialect passes connect_args straight to the Python connector, so the same proxy parameters apply:
from sqlalchemy import create_engine
engine = create_engine(
"snowflake://SERVICE_USER:password@myorg-myaccount/ANALYTICS/PUBLIC?warehouse=COMPUTE_WH",
connect_args={
"proxy_host": "<your-quotaguard-proxy-host>",
"proxy_port": 9293,
"proxy_user": "QG_USERNAME",
"proxy_password": "QG_PASSWORD",
},
)
dbt (dbt-snowflake)
dbt-snowflake runs on the Python connector. Set HTTPS_PROXY in the environment dbt runs in:
export HTTPS_PROXY="http://QG_USERNAME:QG_PASSWORD@<your-quotaguard-proxy-host>:9293"
export NO_PROXY=".amazonaws.com"
Known gotcha: the connector does not read an operating-system proxy auto-config (PAC) script. On a machine where the browser reaches Snowflake through a PAC file, dbt debug can still fail with the network-policy error because dbt never picks up the PAC proxy. Set an explicit HTTPS_PROXY value instead of relying on a PAC script.
SnowSQL (CLI)
SnowSQL uses the Python connector. The simplest path is to set HTTPS_PROXY before launching SnowSQL, the same value as above. If your SnowSQL version supports proxy keys in ~/.snowsql/config, set proxy_host and proxy_port under your connection there. Confirm the keys against your SnowSQL version before relying on them, and fall back to the environment variable if they are not present.
.NET (Snowflake.Data)
The .NET connector runs on the standard .NET HTTP stack, so set the HTTPS_PROXY environment variable for the process, or configure a WebProxy on the handler your application uses. Confirm the exact connection-string proxy parameters against the current Snowflake .NET driver documentation before depending on a specific parameter name.
ODBC
The ODBC driver reads proxy settings from the standard proxy environment variables on the host. Set HTTPS_PROXY for the process that loads the driver. Some platforms also accept proxy settings in the DSN. Confirm the DSN keys against the current ODBC driver documentation for your platform.
Testing the Connection
Confirm two things: that your traffic leaves from a QuotaGuard static IP, and that Snowflake sees that IP.
First, check the egress IP through the proxy. Route a request to the IP check endpoint and read the response:
curl -x "http://QG_USERNAME:QG_PASSWORD@<your-quotaguard-proxy-host>:9293" https://ip.quotaguard.com
{"ip":"203.0.113.10"}
The returned IP must be one of the two static IPs in your dashboard. Call it more than once and you will see both addresses, because the pair is load-balanced.
Second, confirm what Snowflake recorded. Snowflake’s LOGIN_HISTORY exposes the client IP of each connection, so you can verify the address the network policy saw:
SELECT event_timestamp, user_name, client_ip, is_success, error_message
FROM TABLE(INFORMATION_SCHEMA.LOGIN_HISTORY_BY_USER('SERVICE_USER'))
ORDER BY event_timestamp DESC
LIMIT 10;
A successful row whose client_ip matches one of your QuotaGuard IPs confirms the full path. The account-level SNOWFLAKE.ACCOUNT_USAGE.LOGIN_HISTORY view holds the same client_ip column with a longer history and some latency.
Snowflake PrivateLink vs a NAT Gateway vs QuotaGuard
Snowflake’s native answer to the public-IP problem is PrivateLink, which removes the public internet path entirely. It works and is the right choice for some architectures. It also carries real weight: it requires the Business Critical edition or higher, your client in the same cloud as your account, and private-connectivity setup on both ends. A self-managed NAT gateway is the other native option, and it only covers the one platform whose VPC you control.
| Snowflake PrivateLink | Self-managed NAT gateway | QuotaGuard | |
|---|---|---|---|
| Setup | Private link on both ends | Own VPC plus gateway | One proxy config on the driver |
| Edition requirement | Business Critical or higher | None | None |
| Scope | Same cloud as the account | One VPC or platform | Any cloud, any platform |
| Same identity everywhere | No | No | Yes, the same two IPs |
| Regulated data, no decrypt | Handled by the private path | Your responsibility | QuotaGuard Shield |
| Starting cost | Edition plus endpoint | Around $32/month plus data | $19/month |
Use PrivateLink if you are single-cloud, on Business Critical, and want to remove the public path. Use QuotaGuard if you run across clouds or platforms, are not on Business Critical, or want one fixed identity that works everywhere you deploy. This page documents the QuotaGuard path.
Outbound and Inbound
Outbound is the main case for Snowflake. Your application, ETL job, BI tool, or CI pipeline connects out to Snowflake, and Snowflake checks the source IP against the network policy. Everything above covers this direction.
Inbound applies when traffic flows into your application rather than out to Snowflake. Snowflake’s own bulk loading pulls from cloud storage stages, which is a separate path that does not touch your application’s inbound endpoint. Where inbound matters is upstream: when a partner or enterprise system pushes data into your application on a fixed endpoint before your application loads it into Snowflake. QuotaGuard includes inbound proxy on Micro plans and above, and QuotaGuard Shield covers the inbound path when that incoming data is regulated.
Troubleshooting
Incoming request with IP/Token X.X.X.X is not allowed to access Snowflake
The connection reached Snowflake from an IP that is not on the network policy’s allowed list. Confirm your egress IP with the curl test above, then confirm both QuotaGuard IPs are on the policy. If a user-level policy exists, remember it overrides the account-level one, so check the policy that actually applies to the connecting user.
407 Proxy Authentication Required
The proxy credentials are wrong or missing. Recheck the username and password in your QUOTAGUARDSTATIC_URL against the dashboard. A common cause is a credential that was not URL-encoded when it contains a special character.
Connection times out
Usually a wrong host or port. Confirm you are using your region’s host from the dashboard and port 9293 for Static. A timeout only on data loads or unloads points the other way: stage traffic is being forced through the proxy, so set NO_PROXY for your cloud storage domain.
Wrong IP returned, or only one IP ever appears The pair is load-balanced, so repeated checks should show both addresses over time. Seeing a non-QuotaGuard IP means the driver is not actually using the proxy. Confirm the proxy parameters are set on the connection your code opens, not on a different client or a global default the runtime ignores.
Certificate or OCSP errors Do not switch on the driver’s insecure mode to get past these. QuotaGuard does not decrypt the session, so your driver validates Snowflake’s own certificate directly. An OCSP failure usually means the OCSP endpoint is unreachable from your network, not a proxy problem. Allow the OCSP host through rather than disabling validation.
PUT or GET stage commands fail through the proxy
Stage transfers go to cloud storage, not to the Snowflake service. Add your storage domain to NO_PROXY (.amazonaws.com, .core.windows.net, or .googleapis.com) so those transfers go direct.
dbt connects in the GUI but dbt debug fails with the network-policy error
The connector does not read a PAC auto-config script. Set an explicit HTTPS_PROXY value in the environment dbt runs in rather than relying on an operating-system PAC file.
Secrets or environment variables not loading at runtime On serverless and PaaS hosts, confirm the proxy variables are set in the platform’s environment configuration and are present in the running process, not only in your local shell or a build step.
QuotaGuard Static vs QuotaGuard Shield
| Feature | QuotaGuard Static | QuotaGuard Shield |
|---|---|---|
| Protocol | HTTP / HTTPS / SOCKS5 | HTTPS / SOCKS5 over TLS |
| Customer-to-proxy hop | Plaintext | TLS-encrypted |
| HTTPS payload | Tunneled end-to-end, never decrypted at the proxy | Tunneled end-to-end, never decrypted at the proxy |
| Best for | Most apps | Regulated data or environments that require TLS on every hop |
| Starting price | $19/month | $29/month |
Static is right for most Snowflake connections and satisfies the network policy on its own. Choose Shield if the workload handles regulated data or the environment requires TLS between your app and the proxy itself. Both work with Snowflake because neither one decrypts the session, which matters because Snowflake’s security model rejects proxies that decrypt and re-encrypt traffic.
Ready to Get Started?
Get in touch or create a free trial account.