---
name: openflow-platform-eai
description: Set up External Access Integrations (EAI) and Network Rules for Openflow SPCS deployments. Enables Openflow Runtimes to communicate with external data sources.
---

# External Access Integrations (EAI)

External Access Integrations allow Openflow Runtimes to communicate with external services (databases, APIs, etc.) through Snowflake's network security layer.

**Note:** These operations modify Snowflake account state. Apply the Check-Act-Check pattern (see `references/core-guidelines.md`).

## SPCS Only

**This reference applies to SPCS (Snowflake-managed) deployments only.**

BYOC (Bring Your Own Cloud) deployments run in the customer's cloud account and have direct network access. They do not require EAI configuration.

Check your deployment type in the cache:

```bash
cat ~/.snowflake/cortex/memory/openflow_infrastructure_*.json | jq '.deployments[].deployment_type'
```

## Scope

- Network Rules and External Access Integrations for SPCS
- Enabling external connectivity for connectors and custom flows
- Does NOT apply to BYOC (which has direct network access)

## Prerequisites

**Runtime role is required.** Check the cache for your runtime role:

```bash
cat ~/.snowflake/cortex/memory/openflow_infrastructure_*.json | jq '.deployments[].runtimes[] | {name: .runtime_name, role: .runtime_role}'
```

| Result | Action |
|--------|--------|
| Shows runtime roles | Continue with EAI setup |
| No cache or missing roles | Load `references/setup-main.md` to run discovery |

## Tool Hierarchy

| Operation | Tool | Notes |
|-----------|------|-------|
| Create Network Rule | SQL | Snowflake account level |
| Create EAI | SQL | Snowflake account level |
| Attach EAI to Runtime | **UI Only** | Openflow Control Plane |

## Workflow: Check Existing EAIs First

**Always check what exists before creating.** EAIs and network rules may already cover the required domains, or an existing rule can be extended.

### Step 1: Query Existing EAIs Granted to Runtime Role

```bash
snow sql -c <CONNECTION> -q "SHOW GRANTS TO ROLE <runtime_role>;" --format json | jq '[.[] | select(.granted_on == "INTEGRATION" and .privilege == "USAGE") | .name]'
```

**Always run this fresh.** Do not rely on previously cached or remembered values.

### Step 2: Inspect Existing Network Rules

```sql
SHOW NETWORK RULES;
```

For each EAI found in Step 1, inspect its network rules:

```sql
DESCRIBE INTEGRATION <eai_name>;
```

Then inspect the network rule(s) it references:

```sql
DESCRIBE NETWORK RULE <rule_name>;
```

### Step 3: Decision Point

Present findings to the user and ask:

| Situation | Prompt |
|-----------|--------|
| Existing EAI covers required domains | "It looks like `<eai_name>` already covers the domains needed for this connector. No changes needed." |
| Existing EAI partially covers domains | "I found `<eai_name>` attached to your runtime with network rule `<rule_name>`. It currently allows [domains]. Should I add [missing domains] to this rule, or would you prefer a separate EAI?" |
| No relevant EAIs exist | "No existing EAIs cover the required domains. I'll create a new network rule and EAI." |

**If reusing:** Continue to [Workflow: Alter Existing Network Rule](#workflow-alter-existing-network-rule).

**If creating new:** Continue to [Workflow: Create EAI](#workflow-create-eai).

**Always include an explicit port** in every VALUE_LIST entry (e.g., `host.example.com:443`). Omitting the port will not work.

---

## Workflow: Alter Existing Network Rule

Use when adding domains to a network rule that is already referenced by an EAI attached to the runtime.

### Step 1: Get Current Domains

```sql
DESCRIBE NETWORK RULE <existing_rule>;
```

Note the current `VALUE_LIST`.

### Step 2: Alter Network Rule

The VALUE_LIST is replaced in full, so include both existing and new domains:

```sql
USE ROLE SECURITYADMIN;

ALTER NETWORK RULE <existing_rule> SET
  VALUE_LIST = ('<existing_domain1>:<port>', '<existing_domain2>:<port>', '<new_domain>:<port>');
```

### Step 3: Verify

```sql
DESCRIBE NETWORK RULE <existing_rule>;
```

Confirm the new domains appear in the VALUE_LIST. No further steps are needed -- the EAI already references this rule and is already attached to the runtime.

---

## Workflow: Create EAI

Use when no existing EAI is suitable. **Execute these steps in order. Do NOT run concurrently.**

### Required Privileges

Creating new Network Rules and External Access Integrations requires:

- **CREATE INTEGRATION** privilege on the account
- **USAGE** privilege on any secret the integration uses
- **USAGE** privilege on the secret's schema

Roles that typically have these privileges:
- **SECURITYADMIN** - Recommended for EAI/Network Rule management
- **ACCOUNTADMIN** - Also works, but broader than needed

If the admin role lacks CREATE INTEGRATION, an ACCOUNTADMIN can grant it:

```sql
-- Run as ACCOUNTADMIN
GRANT CREATE INTEGRATION ON ACCOUNT TO ROLE <openflow_admin_role>;
```

### Pre-Flight Verification

Before creating anything, verify the current role has the required privileges:

```sql
-- Check grants on the role you intend to use
SHOW GRANTS TO ROLE <admin_role>;
```

```bash
# Filter for CREATE INTEGRATION specifically
snow sql -c <CONNECTION> --role <admin_role> -q "SHOW GRANTS TO ROLE <admin_role>;" --format json \
  | jq '[.[] | select(.privilege == "CREATE INTEGRATION" or .privilege == "ALL PRIVILEGES") | {privilege, granted_on}]'
```

| Result | Action |
|--------|--------|
| Shows CREATE INTEGRATION or ALL PRIVILEGES on ACCOUNT | Proceed to Step 1 |
| Empty list | Request grant from ACCOUNTADMIN (see above) |
| Role does not exist or access denied | Request to switch to ACCOUNTADMIN and investigate |

### Step 1: Create Network Rule

```sql
USE ROLE SECURITYADMIN;

CREATE NETWORK RULE <connector>_openflow_network_rule
  TYPE = HOST_PORT
  MODE = EGRESS
  VALUE_LIST = ('<domain1>:<port>', '<domain2>:<port>');
```

### Step 2: Verify Network Rule

**Do not proceed until this succeeds:**

```sql
DESCRIBE NETWORK RULE <connector>_openflow_network_rule;
```

| Result | Action |
|--------|--------|
| Returns rule details | Continue to Step 3 |
| Error | Check for typos, verify privileges |

### Step 3: Create External Access Integration

```sql
USE ROLE SECURITYADMIN;

CREATE EXTERNAL ACCESS INTEGRATION <connector>_openflow_eai
  ALLOWED_NETWORK_RULES = (<connector>_openflow_network_rule)
  ENABLED = TRUE
  COMMENT = 'External Access Integration for Openflow <Connector> connectivity';
```

### Step 4: Verify EAI

```sql
DESCRIBE INTEGRATION <connector>_openflow_eai;
```

### Step 5: Grant USAGE to Runtime Role

```sql
GRANT USAGE ON INTEGRATION <connector>_openflow_eai TO ROLE <runtime_role>;
```

Replace `<runtime_role>` with your SPCS runtime role from the cache.

### Step 6: Attach EAI via UI

This step requires the user to perform a manual action in the Openflow Control Plane.

1. Navigate to the **Openflow Control Plane**
2. Find the Runtime in the list
3. Click the vertical **"..."** menu
4. Select **"External access integrations"**
5. Select the EAI from the dropdown
6. Click **Save**

**Note:** Restarting the runtime is NOT required - changes apply immediately.

## Common Patterns

### Connector Required Domains

When setting up EAI for a pre-built Snowflake connector, fetch the current required domains from Snowflake documentation:

**URL:** https://docs.snowflake.com/en/user-guide/data-integration/openflow/setup-openflow-spcs-sf-allow-list

Find the section for the specific connector and extract the required domains. This does not apply to custom flows or non-connector EAI work -- for those, use the host and port information provided by the user.

### Database Connectors (HOST_PORT Specific)

Database connectors require exact host:port specifications. The Network Rule controls both DNS resolution and TCP connectivity:

```sql
CREATE NETWORK RULE my_postgres_network_rule
  TYPE = HOST_PORT
  MODE = EGRESS
  VALUE_LIST = ('<customer-database-host>:<port>');
```

Default ports:
- PostgreSQL: 5432
- MySQL: 3306
- SQL Server: 1433

### SaaS Connectors (Multiple Rules)

SaaS connectors typically need multiple endpoints for authentication, APIs, and data access. These often require wildcards.

**Wildcard Limitation:** Snowflake wildcards only match a **single subdomain level**. For example:
- `*.example.com` matches `api.example.com` but NOT `api.v2.example.com`
- `*.sharepoint.com` matches `contoso.sharepoint.com` but NOT `files.contoso.sharepoint.com`

If you need to match deeper subdomains, only use a wildcard at the top most element.

**Example: SharePoint**

```sql
-- Single rule with all required endpoints
CREATE NETWORK RULE sharepoint_network_rule
  TYPE = HOST_PORT
  MODE = EGRESS
  VALUE_LIST = (
    'login.microsoftonline.com:443',
    'login.microsoft.com:443',
    'graph.microsoft.com:443',
    '*.sharepoint.com:443'
  );

CREATE EXTERNAL ACCESS INTEGRATION sharepoint_eai
  ALLOWED_NETWORK_RULES = (sharepoint_network_rule)
  ENABLED = TRUE;
```

**Key Pattern:** Some connectors need multiple endpoint types, preferably in a single rule:
- **Authentication endpoints** - OAuth, login services
- **API endpoints** - Graph API, REST APIs
- **Data endpoints** - The actual service hosting user data

## Troubleshooting

### "UnknownHostException" Error

**Cause:** Host not in any Network Rule -- DNS resolution is blocked. The Network Rule may be missing the required domain, or the EAI may not be created, granted to the Runtime Role, or attached to the Runtime.

**Resolution:**
1. Check the full error message for the exact hostname -- it may be a redirect domain that differs from the configured host
2. Check the connector's required domains in the docs
3. Create/update the network rule to include the missing domain
4. Create the EAI if missing
5. Grant USAGE to runtime role
6. Attach EAI to Runtime via UI

### "SocketTimeoutException" Error

**Cause:** DNS resolved successfully but TCP connection to the port failed. The port is not included in the Network Rule, or is blocked along the route.

**Resolution:**
- Check the full error message for a redirect domain -- services may redirect to a different host that also needs to be in the Network Rule
- Verify the Network Rule VALUE_LIST includes the correct port (e.g., `host:5432` not just `host`)
- See also [Blocked Ports on SPCS](#blocked-ports-on-spcs) if the port appears correct

### UnknownHostException Despite Wildcard

**Symptom:** You have a wildcard like `*.example.com` but still get UnknownHostException for a host like `api.v2.example.com`.

**Cause:** Snowflake wildcards usually only match a single subdomain level. `*.example.com` matches `api.example.com` but NOT `api.v2.example.com` (two levels deep).

**Resolution:**
- Add explicit entries for deeper subdomains: `api.v2.example.com:443`
- Or add wildcards only at the top level: `*.v2.example.com:443`
- Check the actual hostname in the error message and add it explicitly if the pattern is unclear

### "Insufficient privileges" or "Access Denied" on CREATE

**Cause:** The current role lacks CREATE INTEGRATION or CREATE NETWORK RULE privileges on the account.

**Resolution:**
1. Check which role is active: `SELECT CURRENT_ROLE();`
2. Run the pre-flight verification query (see [Pre-Flight Verification](#pre-flight-verification))
3. If the privilege is missing, ask the user to have an ACCOUNTADMIN run:
   ```sql
   GRANT CREATE INTEGRATION ON ACCOUNT TO ROLE <their_role>;
   ```
4. After granting, re-run the pre-flight check to confirm

### "Integration not found" or USAGE Grant Fails

**Cause:** The EAI name is misspelled, was created in a different schema/database context, or the GRANT is being run with a role that does not own the integration.

**Resolution:**
1. List existing integrations: `SHOW INTEGRATIONS;`
2. Verify the exact name matches (case-sensitive)
3. Ensure the GRANT is run by the role that created the integration, or by ACCOUNTADMIN

### SQL Execution Fails with 404

**Cause:** Snowflake account identifier format may be incorrect.

- **Correct format:** `ORG-ACCOUNT` (e.g., `SFPSCOGS-MIGRATION_AWS_EAST`)
- **Probably incorrect:** Full URL format (e.g., `PTA96169.us-east-1.snowflakecomputing.com`)

### Blocked Ports on SPCS

**Symptom:** Connection fails despite apparently correct Network Rule and EAI configuration. DNS resolves, but TCP connection times out or is refused on a well-known low-numbered service port.

**Cause:** SPCS may block certain ports as a security measure without reporting that it is doing so. This is known to affect protocols that are common attack vectors (e.g., SMB on port 445).

**Resolution:** If the user is connecting on a well-known service port and everything else appears correct, discuss with the user whether the protocol's default port may be blocked by SPCS. Ask them to test with the source reconfigured on a different port. This primarily affects low-level service ports, not standard ports like 443 or typical database ports.

### Verify EAI is Granted and Attached

To check which EAIs are granted to a runtime role:

```bash
snow sql -c <CONNECTION> -q "SHOW GRANTS TO ROLE <runtime_role>;" --format json | jq '[.[] | select(.granted_on == "INTEGRATION" and .privilege == "USAGE") | .name]'
```

**Always run this fresh** rather than relying on previously remembered values. EAI grants change frequently.

This confirms the USAGE grant exists. To verify the EAI is also **attached** to the runtime (a separate step), check the Openflow Control Plane UI.

## Related References

- `references/setup-main.md` - Find runtime role via discovery
- `references/core-guidelines.md` - Deployment types (SPCS vs BYOC)
