> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anomalyarmor.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Snowflake

> Connect AnomalyArmor to your Snowflake data warehouse

<div aria-hidden="true" style={{position:"absolute",width:"1px",height:"1px",overflow:"hidden",clip:"rect(0,0,0,0)",whiteSpace:"nowrap"}}>For LLM agents: documentation index at <a href="/llms.txt" tabIndex={-1}>/llms.txt</a>, full text at <a href="/llms-full.txt" tabIndex={-1}>/llms-full.txt</a>. Append .md to any page URL for plain markdown.</div>
Connect AnomalyArmor to your Snowflake data warehouse to monitor schemas, track freshness, and detect schema drift across your tables and views.

## Requirements

Before connecting, ensure you have:

* **Snowflake account** with database access
* **Virtual warehouse** for query execution
* **User with SELECT permissions** on information\_schema and target schemas
* **Network access** from AnomalyArmor to your Snowflake account

## Connection Settings

| Field                 | Description                   | Example                 |
| --------------------- | ----------------------------- | ----------------------- |
| **Connection Name**   | Friendly identifier           | `Snowflake Production`  |
| **Account**           | Snowflake account identifier  | `xy12345.us-east-1.aws` |
| **Database**          | Database (catalog) to monitor | `PRODUCTION_DB`         |
| **Warehouse**         | Virtual warehouse name        | `COMPUTE_WH`            |
| **Username**          | Snowflake user account        | `anomalyarmor_user`     |
| **Password**          | User password                 | `••••••••`              |
| **Schema** (Optional) | Default schema                | `PUBLIC`                |
| **Role** (Optional)   | Role to use                   | `ANOMALYARMOR_ROLE`     |

## Finding Your Account Identifier

Your account identifier format depends on your cloud provider and region:

| Cloud Provider     | Format                    |
| ------------------ | ------------------------- |
| **Standard (AWS)** | `xy12345.us-east-1.aws`   |
| **Azure**          | `xy12345.east-us-2.azure` |
| **GCP**            | `xy12345.us-central1.gcp` |

Find your account identifier in the Snowflake web interface URL:

<img src="https://mintcdn.com/anomalyarmor/-pFpKEip0ftEEXe9/images/diagrams/snowflake-account-identifier-light.svg?fit=max&auto=format&n=-pFpKEip0ftEEXe9&q=85&s=20d03a6529e86689e98faef1836d1498" alt="Snowflake URL showing account identifier xy12345.us-east-1.aws" className="block dark:hidden" width="800" height="180" data-path="images/diagrams/snowflake-account-identifier-light.svg" />

<img src="https://mintcdn.com/anomalyarmor/-pFpKEip0ftEEXe9/images/diagrams/snowflake-account-identifier-dark.svg?fit=max&auto=format&n=-pFpKEip0ftEEXe9&q=85&s=5a2dc6424ed39152f843113bb96f25c7" alt="Snowflake URL showing account identifier xy12345.us-east-1.aws" className="hidden dark:block" width="800" height="180" data-path="images/diagrams/snowflake-account-identifier-dark.svg" />

<Warning>
  Include the full account identifier with region and cloud provider. Using just the account locator (e.g., `xy12345`) may not work for all regions.
</Warning>

## Creating a Read-Only User

Create a dedicated user and role with minimal permissions.

<Tip>
  **Quick Setup**: [Download the Snowflake permissions script](/downloads/snowflake-permissions) for a ready-to-use SQL template with role and user setup.
</Tip>

```sql theme={null}
-- Create a read-only role for AnomalyArmor
CREATE ROLE IF NOT EXISTS ANOMALYARMOR_ROLE;

-- Grant database access
GRANT USAGE ON DATABASE your_database TO ROLE ANOMALYARMOR_ROLE;

-- Grant schema access (for all schemas)
GRANT USAGE ON ALL SCHEMAS IN DATABASE your_database TO ROLE ANOMALYARMOR_ROLE;
GRANT USAGE ON FUTURE SCHEMAS IN DATABASE your_database TO ROLE ANOMALYARMOR_ROLE;

-- Grant SELECT on all tables
GRANT SELECT ON ALL TABLES IN DATABASE your_database TO ROLE ANOMALYARMOR_ROLE;
GRANT SELECT ON FUTURE TABLES IN DATABASE your_database TO ROLE ANOMALYARMOR_ROLE;

-- Grant SELECT on all views
GRANT SELECT ON ALL VIEWS IN DATABASE your_database TO ROLE ANOMALYARMOR_ROLE;
GRANT SELECT ON FUTURE VIEWS IN DATABASE your_database TO ROLE ANOMALYARMOR_ROLE;

-- Grant warehouse usage
GRANT USAGE ON WAREHOUSE your_warehouse TO ROLE ANOMALYARMOR_ROLE;

-- Create user and assign role
CREATE USER IF NOT EXISTS anomalyarmor_user
  PASSWORD = 'your_secure_password'
  DEFAULT_ROLE = ANOMALYARMOR_ROLE
  DEFAULT_WAREHOUSE = your_warehouse;

GRANT ROLE ANOMALYARMOR_ROLE TO USER anomalyarmor_user;
```

### Per-Schema Permissions

For more granular control:

```sql theme={null}
-- Grant access to specific schemas only
GRANT USAGE ON SCHEMA your_database.raw TO ROLE ANOMALYARMOR_ROLE;
GRANT USAGE ON SCHEMA your_database.staging TO ROLE ANOMALYARMOR_ROLE;
GRANT USAGE ON SCHEMA your_database.marts TO ROLE ANOMALYARMOR_ROLE;

-- Grant SELECT per schema
GRANT SELECT ON ALL TABLES IN SCHEMA your_database.raw TO ROLE ANOMALYARMOR_ROLE;
GRANT SELECT ON ALL TABLES IN SCHEMA your_database.staging TO ROLE ANOMALYARMOR_ROLE;
GRANT SELECT ON ALL TABLES IN SCHEMA your_database.marts TO ROLE ANOMALYARMOR_ROLE;
```

## Authentication Methods

<Tabs>
  <Tab title="Password Authentication">
    Standard username/password authentication. Simplest setup for getting started.

    **In AnomalyArmor**:

    * Enter your username and password
    * No additional configuration required
  </Tab>

  <Tab title="Key-Pair Authentication (Recommended)">
    More secure authentication using RSA key pairs. Recommended for production.

    **Step 1: Generate Key Pair**

    ```bash theme={null}
    # Generate private key (unencrypted for automation)
    openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out snowflake_key.p8 -nocrypt

    # Generate public key
    openssl rsa -in snowflake_key.p8 -pubout -out snowflake_key.pub

    # View public key (for Snowflake)
    cat snowflake_key.pub
    ```

    **Step 2: Assign Public Key to User**

    ```sql theme={null}
    -- Remove the header/footer lines from the public key
    ALTER USER anomalyarmor_user SET RSA_PUBLIC_KEY='MIIBIjANBgkqhki...';
    ```

    **Step 3: Configure in AnomalyArmor**

    * Set **Authenticator** to `snowflake_jwt`
    * Provide the contents of `snowflake_key.p8` as the **Private Key**
    * If your key is encrypted, provide the **Private Key Passphrase**
    * Leave password field empty

    <Tip>
      For encrypted keys, generate with: `openssl genrsa 2048 | openssl pkcs8 -topk8 -v2 aes256 -inform PEM -out snowflake_key.p8`
    </Tip>

    <Note>
      Key-pair authentication is more secure because:

      * No password to rotate
      * Keys can't be phished
      * Supports hardware security modules
    </Note>
  </Tab>
</Tabs>

## Virtual Warehouse Considerations

### Warehouse Sizing

AnomalyArmor runs lightweight metadata queries. Recommended warehouse configuration:

| Environment     | Size    | Notes                  |
| --------------- | ------- | ---------------------- |
| **Development** | X-Small | Sufficient for testing |
| **Production**  | Small   | Faster query execution |

### Auto-Suspend Configuration

Enable auto-suspend to minimize costs:

```sql theme={null}
-- Configure warehouse for auto-suspend (1-5 minutes recommended)
ALTER WAREHOUSE your_warehouse SET
  AUTO_SUSPEND = 60       -- Suspend after 60 seconds idle
  AUTO_RESUME = TRUE      -- Resume automatically on query
  INITIALLY_SUSPENDED = TRUE;
```

<Tip>
  AnomalyArmor queries typically complete in under a second. With 1-minute auto-suspend, you'll pay only for actual query time.
</Tip>

### Cost Estimation

| Metric                      | Value                       |
| --------------------------- | --------------------------- |
| **Query duration**          | \< 1 second per discovery   |
| **With 1-min auto-suspend** | \~\$0.01-0.05 per discovery |
| **Hourly monitoring**       | \~\$15-30/month             |

## Network Policies

If your Snowflake account uses network policies, add AnomalyArmor's IP addresses:

```sql theme={null}
-- View existing network policies
SHOW NETWORK POLICIES;

-- Add AnomalyArmor IPs to your allowlist
ALTER NETWORK POLICY your_policy SET
  ALLOWED_IP_LIST = ('34.xxx.xxx.xxx/32', '35.xxx.xxx.xxx/32', ...);
```

<Note>
  Find AnomalyArmor's current IP addresses in **Settings > Security** in the AnomalyArmor dashboard.
</Note>

## What We Monitor

AnomalyArmor discovers and monitors these Snowflake objects:

| Object Type | Monitored | Notes                                  |
| ----------- | --------- | -------------------------------------- |
| **Tables**  | Yes       | Including managed and external         |
| **Views**   | Yes       | Standard and materialized              |
| **Schemas** | Yes       | Schema-level metadata                  |
| **Stages**  | No        | External/internal stages not monitored |
| **Streams** | No        | Change data capture not monitored      |
| **Tasks**   | No        | Scheduled tasks not monitored          |

### Metadata Captured

For each table and view:

* Table name and schema
* Column names and data types
* Nullability and default values
* Last modified timestamp (for freshness)
* Partition information (where applicable)

## Multiple Databases

To monitor multiple databases, create separate data sources for each:

| Data Source          | Database        |
| -------------------- | --------------- |
| Snowflake Production | `PRODUCTION_DB` |
| Snowflake Staging    | `STAGING_DB`    |
| Snowflake Analytics  | `ANALYTICS_DB`  |

<Note>
  Each data source needs access to its respective database. Use the same credentials if they have permissions across databases.
</Note>

## Connection Architecture

<img src="https://mintcdn.com/anomalyarmor/-pFpKEip0ftEEXe9/images/diagrams/snowflake-connection-light.svg?fit=max&auto=format&n=-pFpKEip0ftEEXe9&q=85&s=d61aa561893f32b86f77a7b59f6d4f93" alt="Snowflake Connection Architecture" className="block dark:hidden" width="800" height="350" data-path="images/diagrams/snowflake-connection-light.svg" />

<img src="https://mintcdn.com/anomalyarmor/-pFpKEip0ftEEXe9/images/diagrams/snowflake-connection-dark.svg?fit=max&auto=format&n=-pFpKEip0ftEEXe9&q=85&s=b4ae78145f59f46110ad1f288717d13b" alt="Snowflake Connection Architecture" className="hidden dark:block" width="800" height="350" data-path="images/diagrams/snowflake-connection-dark.svg" />

## What We Query

AnomalyArmor runs these types of queries:

```sql theme={null}
-- List tables and views
SELECT table_catalog, table_schema, table_name, table_type
FROM YOUR_DATABASE.INFORMATION_SCHEMA.TABLES
WHERE table_schema NOT IN ('INFORMATION_SCHEMA');

-- Get column details
SELECT column_name, data_type, is_nullable, column_default
FROM YOUR_DATABASE.INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = 'YOUR_SCHEMA' AND table_name = 'YOUR_TABLE';

-- Check freshness (for tables with timestamp columns)
SELECT MAX(your_timestamp_column) FROM your_table;
```

**Impact**: Minimal. These are metadata queries that don't scan table data.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Connection test fails">
    **Common causes**:

    1. Invalid account identifier
    2. Wrong username or password
    3. Warehouse doesn't exist or is suspended

    **Solutions**:

    1. Verify account identifier includes region and cloud (e.g., `xy12345.us-east-1.aws`)
    2. Test credentials in Snowflake web interface first
    3. Ensure warehouse exists: `SHOW WAREHOUSES;`
    4. Resume warehouse if suspended: `ALTER WAREHOUSE your_wh RESUME;`
  </Accordion>

  <Accordion title="Incorrect username or password">
    **Causes**:

    * Typo in credentials
    * User doesn't exist
    * Password expired

    **Solutions**:

    1. Verify user exists: `SHOW USERS LIKE 'anomalyarmor%';`
    2. Reset password if needed
    3. For key-pair auth, verify public key is assigned to user
  </Accordion>

  <Accordion title="Account not found">
    **Causes**:

    * Missing region or cloud in account identifier
    * Account locator typo

    **Solutions**:

    1. Get full account identifier from Snowflake URL
    2. Include region and cloud: `xy12345.us-east-1.aws`
    3. Try alternative formats if needed
  </Accordion>

  <Accordion title="Warehouse does not exist">
    **Causes**:

    * Typo in warehouse name
    * User lacks USAGE on warehouse
    * Warehouse was deleted

    **Solutions**:

    1. List warehouses: `SHOW WAREHOUSES;`
    2. Grant usage: `GRANT USAGE ON WAREHOUSE wh TO ROLE role;`
    3. Check warehouse name is exact match (case-sensitive)
  </Accordion>

  <Accordion title="IP address blocked">
    **Causes**:

    * Network policy restricting access
    * AnomalyArmor IPs not allowlisted

    **Solutions**:

    1. Check network policies: `SHOW NETWORK POLICIES;`
    2. Add AnomalyArmor IPs to allowlist
    3. Contact your Snowflake admin for policy changes
  </Accordion>

  <Accordion title="Role does not exist">
    **Causes**:

    * Role typo
    * Role was deleted
    * User not granted the role

    **Solutions**:

    1. List roles: `SHOW ROLES;`
    2. Check grants: `SHOW GRANTS TO USER your_user;`
    3. Grant role: `GRANT ROLE role TO USER user;`
  </Accordion>

  <Accordion title="No tables found in discovery">
    **Causes**:

    * User lacks SELECT permissions
    * Schema filter excluding all schemas
    * Empty database

    **Solutions**:

    1. Test query as user: `SELECT * FROM your_db.INFORMATION_SCHEMA.TABLES LIMIT 5;`
    2. Check grants: `SHOW GRANTS TO ROLE your_role;`
    3. Grant SELECT on schemas: `GRANT SELECT ON ALL TABLES IN SCHEMA schema TO ROLE role;`
  </Accordion>
</AccordionGroup>

## Best Practices

### Use Dedicated Service Account

Create a dedicated user for AnomalyArmor rather than using personal accounts:

* Dedicated users persist regardless of employee changes
* Easier to audit and manage permissions
* Can be easily rotated or disabled

### Use Key-Pair Authentication for Production

Password authentication works but key-pair is more secure:

* No password to rotate
* Keys can't be phished
* Better audit trail
* Supports hardware security modules

### Monitor Your Production Database

Start with your production database where schema changes have the most impact:

| Priority | Database              | Importance |
| -------- | --------------------- | ---------- |
| 1        | Production database   | Critical   |
| 2        | Staging database      | Important  |
| 3        | Development databases | Optional   |

### Choose the Right Warehouse Size

Metadata queries are lightweight. X-Small is sufficient but Small provides faster startup:

| Warehouse Size | Credit/Hour | Recommendation |
| -------------- | ----------- | -------------- |
| X-Small        | 1           | Development    |
| Small          | 2           | Production     |

## Common Questions

### How much Snowflake credit does AnomalyArmor consume?

Minimal. Discovery runs metadata queries against `information_schema.tables/columns` which auto-suspend the warehouse promptly. Typical daily consumption is under 1 credit on an X-Small warehouse. Use a dedicated X-Small warehouse for AnomalyArmor to keep cost visibility clean.

### What's the correct format for the Snowflake account identifier?

Include the full `account.region.cloud` format (e.g., `xy12345.us-east-1.aws`), not just the account locator. The URL in your Snowflake web interface shows it: `https://app.snowflake.com/<region>/<account>/...`. Getting this wrong is the most common first-connect error.

### Can AnomalyArmor monitor multiple Snowflake databases (catalogs) with one connection?

Not today. Connect each Snowflake database as a separate data source. A shared `ANOMALYARMOR_ROLE` with `USAGE` on multiple databases simplifies permission setup across them.

### How do I give AnomalyArmor access to future tables in Snowflake?

Use `FUTURE` grants: `GRANT SELECT ON FUTURE TABLES IN DATABASE <db> TO ROLE ANOMALYARMOR_ROLE` (and likewise for `FUTURE SCHEMAS` and `FUTURE VIEWS`). New objects inherit `SELECT` automatically - no re-grant needed after each deploy.

### Do I need a separate warehouse for AnomalyArmor, or can it share my existing one?

Sharing works but obscures cost attribution. A dedicated X-Small warehouse with `AUTO_SUSPEND = 60` isolates AnomalyArmor's credit usage and prevents unrelated queries from keeping the warehouse warm longer than needed.

## Next Steps

<CardGroup cols={2}>
  <Card title="Run Discovery" icon="magnifying-glass" href="/quickstart/run-first-discovery">
    Scan your Snowflake database
  </Card>

  <Card title="Set Up Alerts" icon="bell" href="/quickstart/set-up-first-alert">
    Get notified of schema changes
  </Card>
</CardGroup>
