Skip to content

Dynamic Egress IP Support for Snowflake Direct Integration #1931

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 97 additions & 39 deletions examples/chatgpt/gpt_actions_library/gpt_action_snowflake_direct.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,15 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## ChatGPT Steps"
"## 1. Configure the Custom GPT"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"### Custom GPT Instructions\n",
"### Set GPT Instructions\n",
"\n",
"Once you've created a Custom GPT, copy the text below in the Instructions panel. Have questions? Check out [Getting Started Example](https://platform.openai.com/docs/actions/getting-started) to see how this step works in more detail."
]
Expand Down Expand Up @@ -217,7 +217,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Authentication Instructions"
"## 2. Configure Snowflake Integration"
]
},
{
Expand All @@ -231,20 +231,11 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Pre-Action Steps"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Before you set up authentication in ChatGPT, please take the following steps in Snowflake.\n",
"\n",
"### 1. Optional: Configure IP Whitelisting for ChatGPT\n",
"### Configure IP Whitelisting for ChatGPT\n",
"Snowflake accounts with network policies that limit connections by IP, may require exceptions to be added for ChatGPT.\n",
"* Review the Snowflake documentation on [Network Policies](https://docs.snowflake.com/en/user-guide/network-policies)\n",
"* Go to the Snowflake Worksheets\n",
"* Create a network rule with the ChatGPT IP egress ranges listed [here](https://platform.openai.com/docs/actions/production/ip-egress-ranges)\n",
"* Create a network rule with the ChatGPT IP egress ranges listed [here](https://platform.openai.com/docs/actions/production/ip-egress-ranges#ip-egress-ranges)\n",
"* Create a corresponding Network Policy"
]
},
Expand All @@ -258,26 +249,11 @@
},
"outputs": [],
"source": [
"## Example with ChatGPT IPs as of October 23, 2024\n",
"## Make sure to get the current IP ranges from https://platform.openai.com/docs/actions/production\n",
"## ChatGPT IP ranges available at https://openai.com/chatgpt-actions.json\n",
"CREATE NETWORK RULE chatgpt_network_rule\n",
" MODE = INGRESS\n",
" TYPE = IPV4\n",
" VALUE_LIST = ('23.102.140.112/28',\n",
" '13.66.11.96/28',\n",
" '104.210.133.240/28',\n",
" '70.37.60.192/28',\n",
" '20.97.188.144/28',\n",
" '20.161.76.48/28',\n",
" '52.234.32.208/28',\n",
" '52.156.132.32/28',\n",
" '40.84.220.192/28',\n",
" '23.98.178.64/28',\n",
" '51.8.155.32/28',\n",
" '20.246.77.240/28',\n",
" '172.178.141.0/28',\n",
" '172.178.141.192/28',\n",
" '40.84.180.128/28');\n",
" VALUE_LIST = ('23.102.140.112/28',...,'40.84.180.128/28');\n",
"\n",
"CREATE NETWORK POLICY chatgpt_network_policy\n",
" ALLOWED_NETWORK_RULE_LIST = ('chatgpt_network_rule');"
Expand All @@ -287,14 +263,14 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Network policies can be applied at the account, security integration, and user level. The most specific network policy overrides the more general network policies. Depending on how these policies are applied, you may need to alter the policies for individual users in addition to the security integration. If you face this issue, you may encounter Snowflake's error code 390422."
"Network policies can be applied at the account, security integration, and user level. The most specific network policy overrides the more general network policies. Depending on how these policies are applied, you may need to alter the policies for individual users in addition to the security integration. If you face this issue, you may encounter Snowflake's error code 390422 or a generic \"Invalid Client\" error."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2. Set up the Security Integration\n",
"### Create the Security Integration\n",
"* Review the Snowflake OAuth Overview: [https://docs.snowflake.com/en/user-guide/oauth-snowflake-overview](https://docs.snowflake.com/en/user-guide/oauth-snowflake-overview)\n",
"* Create new OAuth credentials through a [Security Integration](https://docs.snowflake.com/en/sql-reference/sql/create-security-integration-oauth-snowflake) - you will need a new one for each OAuth app/custom GPT since Snowflake Redirect URIs are 1-1 mapped to Security Integrations"
]
Expand Down Expand Up @@ -324,7 +300,89 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"<details>\n",
" <summary>Optional: Automate Network Rule Configuration</summary>\n",
" \n",
" There are now over 100 egress IP addresses used by ChatGPT. The list updates irregularly and without announcement. To keep up to date with it, we can fetch the list on a daily basis and apply it to our network rule.\n",
"\n",
" ### Network rule to allow outbound traffic to OpenAI\n",
" ```sql\n",
" CREATE OR REPLACE NETWORK RULE chatgpt_actions_rule\n",
" MODE = EGRESS -- outbound\n",
" TYPE = HOST_PORT\n",
" VALUE_LIST = ('openai.com:443');\n",
" ```\n",
" ### Access Integration to apply the rule\n",
" ```sql\n",
" CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION chatgpt_actions_integration\n",
" ALLOWED_NETWORK_RULES = (chatgpt_actions_rule)\n",
" ENABLED = TRUE;\n",
" ```\n",
"\n",
" ### UDF to Fetch the IP ranges\n",
" ```sql\n",
" CREATE OR REPLACE FUNCTION getChatGPTActionsAddresses()\n",
" RETURNS ARRAY -- array<varchar>\n",
" LANGUAGE PYTHON\n",
" RUNTIME_VERSION = 3.10\n",
" PACKAGES = ('requests')\n",
" EXTERNAL_ACCESS_INTEGRATIONS = (chatgpt_actions_integration)\n",
" HANDLER = 'get_ip_address_ranges'\n",
"AS\n",
"$$\n",
"import requests\n",
"\n",
"def get_ip_address_ranges():\n",
" resp = requests.get(\"https://openai.com/chatgpt-actions.json\", timeout=10)\n",
" resp.raise_for_status()\n",
" data = [entry[\"ipv4Prefix\"] for entry in resp.json().get(\"prefixes\", []) if \"ipv4Prefix\" in entry]\n",
" return data\n",
"$$;\n",
" ```\n",
" ### Procedure to update the network rule\n",
" ```sql\n",
" CREATE OR REPLACE PROCEDURE update_chatgpt_network_rule()\n",
" RETURNS STRING\n",
" LANGUAGE SQL\n",
"AS\n",
"$$\n",
"DECLARE\n",
" ip_list STRING;\n",
"BEGIN\n",
" -- Properly quote the IPs for use in VALUE_LIST\n",
" ip_list := '''' || ARRAY_TO_STRING(getChatGPTActionsAddresses(), ''',''') || '''';\n",
"\n",
" -- Run the dynamic SQL to update the rule\n",
" EXECUTE IMMEDIATE\n",
" 'ALTER NETWORK RULE chatgpt_network_rule SET VALUE_LIST = (' || ip_list || ')';\n",
"\n",
" RETURN 'chatgpt_network_rule updated with ' || ARRAY_SIZE(getChatGPTActionsAddresses()) || ' entries';\n",
"END;\n",
"$$;\n",
" ```\n",
"\n",
" ### Call the procedure\n",
" ```sql\n",
" CALL update_chatgpt_network_rule();\n",
" ```\n",
"\n",
" ### Run the procedure every day at 6AM Pacific Time\n",
" ```sql\n",
" CREATE OR REPLACE TASK auto_update_chatgpt_network_rule\n",
" WAREHOUSE = COMPUTE_WH\n",
" SCHEDULE = 'USING CRON 0 6 * * * America/Los_Angeles'\n",
"AS\n",
" CALL update_chatgpt_network_rule();\n",
" ```\n",
"</details>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. Configure GPT Action Authentication\n",
"### Gather key information from Snowflake\n",
"* Retrieve your OAuth Client ID, Auth URL, and Token URL\n"
]
},
Expand All @@ -346,7 +404,7 @@
"metadata": {},
"source": [
"\n",
"You’ll find the required information in these 3 columns:"
"You’ll find the required information in these 3 rows:"
]
},
{
Expand Down Expand Up @@ -391,7 +449,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### In ChatGPT"
"### Set OAuth Values in GPT Action Authentication"
]
},
{
Expand All @@ -407,18 +465,18 @@
"| Client Secret | OAUTH_CLIENT_SECRET from SHOW_OAUTH_CLIENT_SECRETS |\n",
"| Authorization URL | OAUTH_AUTHORIZATION_ENDPOINT from DESCRIBE SECURITY INTEGRATION |\n",
"| Token URL | OAUTH_TOKEN_ENDPOINT from DESCRIBE SECURITY INTEGRATION |\n",
"| Scope | session:role:your_role* |\n",
"| Scope | session:role:CHATGPT_INTEGRATION_ROLE* |\n",
"| Token Exchange Method | Default (POST Request) |\n",
"\n",
"\n",
"*Snowflake scopes pass the role in the format `session:role:<your_role>` for example `session:role:CHATGPT_INTEGRATION_ROLE`. It's possible to leave this empty and specify the role in the instructions, but by adding it here it becomes included in OAuth Consent Request which can sometimes be more reliable. "
"*Snowflake scopes pass the role in the format `session:role:<your_role>` for example `session:role:CHATGPT_INTEGRATION_ROLE`. You can optionally leave this field empty and specify the role in the GPT instructions, but by adding it here it becomes included in OAuth Consent Request which can sometimes be more reliable. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Post-Action Steps"
"### 4. Update the Snowflake Integration Redirect URI"
]
},
{
Expand Down