# Integrate with Snowflake

info
This feature is not enabled on accounts by default. Contact Technical Support or your Customer Success representative to enable it.

This guide explains how to integrate the Treasure AI-managed Glue HMS catalog and Iceberg tables with Snowflake using a catalog-linked database backed by the AWS Glue Iceberg REST catalog.

## Overview

After provisioning Iceberg catalog resources for your Treasure AI account, you can link the Glue HMS catalog into Snowflake as a catalog-linked database. This allows you to query Treasure AI-managed Iceberg tables directly from Snowflake without copying data.

The integration uses:

- A **catalog integration** that connects Snowflake to the Treasure AI catalog through the AWS Glue Iceberg REST endpoint, authenticated with the Treasure AI reader IAM role via AWS Signature Version 4 (SigV4)
- A **catalog-linked database** that exposes the Treasure AI Glue database and its Iceberg tables in Snowflake


For access to the underlying table data, this guide uses **catalog-vended credentials**: Snowflake requests scoped, short-lived credentials from the catalog through AWS Lake Formation for each table it reads. This is the recommended method — you do not configure a Snowflake external volume or manage storage access on the Snowflake side.

## Prerequisites

- Iceberg catalog resources provisioned and `active` for your account (see [Provision Resources](/ja/products/customer-data-platform/composable-publish/resource-provisioning))
- A Snowflake account with privileges to create catalog integrations and databases (`ACCOUNTADMIN`, or a role granted `CREATE INTEGRATION` and `CREATE DATABASE`)


### Authentication

For authentication details and API endpoints by site, see [Use Iceberg Catalog Management API](/ja/products/customer-data-platform/composable-publish/use-iceberg-catalog-api).

### Required Information

Retrieve these values from the [Get Resource Status](/ja/products/customer-data-platform/composable-publish/resource-provisioning#get-resource-status) endpoint:

```sh
curl "https://api-iceberg-mng.us01.treasuredata.com/v1/iceberg/catalog/resources" \
  -H "Authorization: TD1 <admin_api_key>" \
  -H "Accept: application/json"
```

| Response Field | Used As | Example |
|  --- | --- | --- |
| `aws_region` | Glue region in `CATALOG_URI` and the SigV4 signing region | `us-east-1` |
| `aws_account_id` | Glue catalog name (`CATALOG_NAME`) | `123456789012` |
| `iam_role_arn` | SigV4 IAM role (`SIGV4_IAM_ROLE`) | `arn:aws:iam::123456789012:role/zcpo-hms-tenant-us01_td10000` |
| `db_name` | Allowed namespace in the catalog-linked database (`ALLOWED_NAMESPACES`) | `td10000_us01_export` |


The Glue catalog name is the AWS account ID (`aws_account_id`), because the default Glue catalog for an account is named after the account.

## Setup

Steps 1–4 correspond to [Configure a catalog integration for AWS Glue Iceberg REST](https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-catalog-integration-rest-glue), and step 5 corresponds to [Create a catalog-linked database](https://docs.snowflake.com/en/user-guide/tables-iceberg-catalog-linked-database).

### Step 1 (Snowflake): Create a Catalog Integration

Create a catalog integration that points at the Treasure AI Glue Iceberg REST endpoint and uses catalog-vended credentials. Follow [CREATE CATALOG INTEGRATION (Apache Iceberg REST)](https://docs.snowflake.com/en/sql-reference/sql/create-catalog-integration-rest), and set [`ACCESS_DELEGATION_MODE = VENDED_CREDENTIALS`](https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-catalog-integration-vended-credentials).

Substitute the values from the Treasure AI resource response:

```sql
CREATE CATALOG INTEGRATION my_glue_rest_integration
  CATALOG_SOURCE = ICEBERG_REST
  TABLE_FORMAT = ICEBERG
  REST_CONFIG = (
    CATALOG_URI = 'https://glue.<aws_region>.amazonaws.com/iceberg'
    CATALOG_API_TYPE = AWS_GLUE
    CATALOG_NAME = '<aws_account_id>'
    ACCESS_DELEGATION_MODE = VENDED_CREDENTIALS
  )
  REST_AUTHENTICATION = (
    TYPE = SIGV4
    SIGV4_IAM_ROLE = '<iam_role_arn>'
    SIGV4_SIGNING_REGION = '<aws_region>'
  )
  ENABLED = TRUE;
```

### Step 2 (Snowflake): Retrieve the IAM User and External ID

Describe the catalog integration to retrieve the AWS IAM user and external ID that Snowflake generated for it:

```sql
DESCRIBE CATALOG INTEGRATION my_glue_rest_integration
  ->> SELECT * FROM $1 WHERE "property" LIKE 'API_AWS_%';
```

Record the values of `API_AWS_IAM_USER_ARN` and `API_AWS_EXTERNAL_ID`. Use them in the next step.

### Step 3 (Treasure AI): Update Trust Policy of IAM Role for Reading Tables

Update the trust policy of the IAM role for reading tables so Snowflake can assume it.

Call the trust policy update endpoint with `service` set to `snowflake`, the `API_AWS_IAM_USER_ARN` from Step 2 as `iam_principal_arns`, and the `API_AWS_EXTERNAL_ID` from Step 2 as `external_ids`:

```sh
curl -X POST "https://api-iceberg-mng.us01.treasuredata.com/v1/iceberg/catalog/resources/reader_role/trust_policy" \
  -H "Authorization: TD1 <admin_api_key>" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "entries": [
      {
        "service": "snowflake",
        "iam_principal_arns": ["<API_AWS_IAM_USER_ARN>"],
        "external_ids": ["<API_AWS_EXTERNAL_ID>"]
      }
    ]
  }'
```

The external ID is matched against the `sts:ExternalId` condition in the IAM role trust policy, so only the specified Snowflake catalog integration can assume the role. This value is generated by Snowflake and is only known after creating the integration.

Important
The catalog integration will not work until this step is completed. Poll the [Get Resource Status](/ja/products/customer-data-platform/composable-publish/resource-provisioning#get-resource-status) endpoint and wait for the status to return to `active` before proceeding.

### Step 4 (Snowflake): Verify the Catalog Integration

Confirm that Snowflake can reach the catalog and assume the reader role. Follow [Check the catalog integration configuration](https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-catalog-integration-rest-check-config#use-systemverify_catalog_integration):

```sql
SELECT SYSTEM$VERIFY_CATALOG_INTEGRATION('my_glue_rest_integration');
```

The integration is configured correctly when the result reports success:

```json
{
  "success": true,
  "errorCode": "",
  "errorMessage": ""
}
```

If `success` is `false`, verify the IAM user ARN and external ID registered in Step 3 and that the resource status returned to `active`.

### Step 5 (Snowflake): Create a Catalog-Linked Database

Create a catalog-linked database that exposes the Treasure AI Glue database. Follow [CREATE DATABASE (catalog-linked)](https://docs.snowflake.com/en/sql-reference/sql/create-database-catalog-linked), and set `ALLOWED_NAMESPACES` to the Treasure AI `db_name`:

```sql
CREATE DATABASE my_linked_db
  LINKED_CATALOG = (
    CATALOG = 'my_glue_rest_integration'
    ALLOWED_NAMESPACES = ('<db_name>')
    ALLOWED_WRITE_OPERATIONS = NONE
  );
```

Set `ALLOWED_WRITE_OPERATIONS = NONE` because the Treasure AI reader role is read-only.

`ALLOWED_NAMESPACES` accepts more than one namespace. In addition to the default `export` database, you can link any databases you created via the [Database Management API](/ja/products/customer-data-platform/composable-publish/database-management) by adding their names to the list:

```sql
CREATE DATABASE my_linked_db
  LINKED_CATALOG = (
    CATALOG = 'my_glue_rest_integration'
    ALLOWED_NAMESPACES = ('<db_name>', '<another_db_name>')
    ALLOWED_WRITE_OPERATIONS = NONE
  );
```

Only databases listed in `ALLOWED_NAMESPACES` are linked. To expose a database created later, update the catalog-linked database to include its name.

Alternatively, you can expose a database through its own catalog-linked database by running `CREATE DATABASE` again with a different Snowflake database name against the same catalog integration. Reuse the integration from Step 1 — you do not create a new one.

## Validation

Check that Snowflake has successfully linked the catalog with [SYSTEM$CATALOG_LINK_STATUS](https://docs.snowflake.com/en/sql-reference/functions/system_catalog_link_status):

```sql
SELECT SYSTEM$CATALOG_LINK_STATUS('my_linked_db');
```

Linking is working when `executionState` is `RUNNING` and `failureDetails` is empty:

```json
{ "failureDetails": [], "executionState": "RUNNING", "lastLinkAttemptStartTime": "2026-07-15T04:40:49.001Z" }
```

After linking completes, the Treasure AI Glue database and its Iceberg tables appear in the catalog-linked database and you can query them from Snowflake.

## Troubleshooting

| Symptom | Possible Cause |
|  --- | --- |
| `SYSTEM$VERIFY_CATALOG_INTEGRATION` returns `success: false` | IAM user ARN or external ID mismatch — verify the values registered in Step 3 |
| Access denied when querying table data | Vended credentials could not be issued — confirm the resource status returned to `active` after Step 3 |
| `SYSTEM$CATALOG_LINK_STATUS` shows `failureDetails` | Namespace mismatch — confirm `ALLOWED_NAMESPACES` matches the Treasure AI `db_name` |
| Region or signing error | `CATALOG_URI` and `SIGV4_SIGNING_REGION` must both use the Treasure AI `aws_region` |


## Important Notes

- The trust policy update in Step 3 is a full replacement. To add another integration later without dropping Snowflake, use the read-modify-write flow in [Manage the Reader Role Trust Policy](/ja/products/customer-data-platform/composable-publish/trust-policy-management).
- The reader IAM role is read-only. Snowflake can query tables but cannot modify data in the Treasure AI-managed S3 bucket, which is why `ALLOWED_WRITE_OPERATIONS` is set to `NONE`.
- Catalog-vended credentials are the recommended access method. Configuring a Snowflake external volume is an alternative if you prefer to manage storage access on the Snowflake side, but it is not required for this integration.
- A single catalog integration can expose the default `export` database and any created via the [Database Management API](/ja/products/customer-data-platform/composable-publish/database-management). List them together in one catalog-linked database's `ALLOWED_NAMESPACES`, or give each its own catalog-linked database — both reuse the same integration (see Step 5).