Copilot commented on code in PR #3632:
URL: https://github.com/apache/doris-website/pull/3632#discussion_r3216271772
##########
docs/lakehouse/best-practices/doris-snowflake-catalog.md:
##########
@@ -0,0 +1,451 @@
+---
+{
+ "title": "Integration with Snowflake Catalog",
+ "language": "en",
+ "description": "This document describes how to connect Apache Doris to
Snowflake Horizon Catalog and Snowflake Open Catalog through the Iceberg REST
Catalog API."
+}
+---
+
+Apache Doris can connect to Snowflake Catalog services through the Iceberg
REST Catalog API. This integration allows Doris to query Iceberg tables managed
by Snowflake, and to create and write Iceberg tables when using Snowflake Open
Catalog internal catalogs.
+
+This document covers two Snowflake catalog services:
+
+- **Snowflake Horizon Catalog**: used to access Snowflake-managed Iceberg
tables in an existing Snowflake account.
+- **Snowflake Open Catalog**: Snowflake's managed Apache Polaris / Iceberg
REST Catalog service, used to manage Iceberg catalogs, namespaces, and tables.
+
+## Choosing a Snowflake Catalog
+
+| Item | Snowflake Horizon Catalog | Snowflake Open Catalog |
+| --- | --- | --- |
+| Main use case | Query Snowflake-managed Iceberg tables | Manage Iceberg
tables in Snowflake Open Catalog |
+| Doris `warehouse` | Snowflake database name | Open Catalog catalog name |
+| Credential | Snowflake Programmatic Access Token (PAT) | Service connection
`<client_id>:<client_secret>` |
+| OAuth scope | `session:role:<ROLE_NAME>` | `PRINCIPAL_ROLE:<ROLE_NAME>` |
+| Create tables from Doris | Not recommended | Supported on internal catalogs |
+| Write from Doris | Insert into existing Snowflake-managed Iceberg tables |
Insert into tables in internal catalogs |
+
+Use Horizon Catalog when your tables are managed by Snowflake. Use Open
Catalog internal catalogs when you want Doris to create and manage Iceberg
tables through Snowflake Open Catalog.
+
+> Note: When connecting to Horizon Catalog, set `iceberg.rest.view-enabled` to
`false`.
+
+### Storage Access Model
+
+Horizon Catalog is used for Snowflake-managed Iceberg tables, whose storage
access is managed by Snowflake. Doris obtains table metadata through the REST
Catalog API, and Snowflake returns temporary object storage credentials when
`iceberg.rest.vended-credentials-enabled` is set to `true`. Therefore, you do
not need to configure an AWS IAM role or S3 credentials in the Doris catalog
for Horizon Catalog.
+
+Open Catalog internal catalogs use the object storage location configured for
the catalog. When the location is on AWS S3, Open Catalog needs an IAM role
that it can assume to read and write Iceberg metadata and data files. In the
IAM role trust policy, the trust principal is the AWS principal allowed to call
`sts:AssumeRole`. For Snowflake Open Catalog, use the IAM user ARN shown in the
catalog storage details as the trust principal, and configure the External ID
from the same page. The External ID limits role assumption to this Open Catalog
integration and helps prevent confused-deputy access.
+
+## Connect to Snowflake Horizon Catalog
+
+### Snowflake Environment Setup
+
+Snowflake Horizon Catalog exposes Snowflake-managed Iceberg tables through the
Iceberg REST Catalog API.
+
+The REST endpoints are:
+
+```text
+REST endpoint:
+https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog
+
+Token endpoint:
+https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens
+```
+
+Create a Snowflake-managed Iceberg table:
+
+```sql
+CREATE OR REPLACE ICEBERG TABLE <database_name>.<schema_name>.<table_name> (
+ ID BIGINT,
+ NAME STRING
+)
+CATALOG = 'SNOWFLAKE'
+EXTERNAL_VOLUME = 'SNOWFLAKE_MANAGED';
+```
+
+`SNOWFLAKE_MANAGED` is a Snowflake reserved value. It is not a user-created
external volume, and you do not need to grant Doris access to an external
volume for this value.
+
+Grant privileges to the Snowflake role used by Doris:
+
+```sql
+GRANT USAGE ON DATABASE <database_name> TO ROLE <role_name>;
+GRANT USAGE ON SCHEMA <database_name>.<schema_name> TO ROLE <role_name>;
+GRANT SELECT ON TABLE <database_name>.<schema_name>.<table_name> TO ROLE
<role_name>;
+```
+
+If Doris needs to write to the table, grant write privileges:
+
+```sql
+GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE
+ON TABLE <database_name>.<schema_name>.<table_name>
+TO ROLE <role_name>;
+```
+
+Create a Programmatic Access Token (PAT) for the service user:
+
+```sql
+ALTER USER IF EXISTS <service_user>
+ADD PAT <pat_name>
+ DAYS_TO_EXPIRY = 7
+ ROLE_RESTRICTION = '<role_name>'
+ COMMENT = 'Horizon Iceberg REST access for Doris';
+```
+
+You can verify the PAT with the token endpoint:
+
+```bash
+curl -i --fail -X POST \
+
"https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens"
\
+ --header "Content-Type: application/x-www-form-urlencoded" \
+ --data-urlencode "grant_type=client_credentials" \
+ --data-urlencode "scope=session:role:<role_name>" \
+ --data-urlencode "client_secret=<PAT_token>"
+```
+
+### Create a Doris Catalog
+
+Create an Iceberg REST Catalog in Doris:
+
+```sql
+CREATE CATALOG snowflake_horizon PROPERTIES (
+ 'type' = 'iceberg',
+ 'iceberg.catalog.type' = 'rest',
+ 'iceberg.rest.uri' =
'https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog',
+ 'warehouse' = '<snowflake_database_name>',
+ 'iceberg.rest.security.type' = 'oauth2',
+ 'iceberg.rest.oauth2.credential' = '<PAT_token>',
+ 'iceberg.rest.oauth2.server-uri' =
'https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens',
+ 'iceberg.rest.oauth2.scope' = 'session:role:<role_name>',
+ 'iceberg.rest.vended-credentials-enabled' = 'true',
+ 'client.region' = '<storage_region>',
+ 'iceberg.rest.nested-namespace-enabled' = 'true',
+ 'iceberg.rest.view-enabled' = 'false',
+ 'iceberg.rest.connection-timeout-ms' = '30000',
+ 'iceberg.rest.socket-timeout-ms' = '120000'
+);
+```
+
+Parameter notes:
+
+- `warehouse`: Snowflake database name, not a Snowflake compute warehouse.
+- `iceberg.rest.oauth2.credential`: the Snowflake PAT.
+- `iceberg.rest.oauth2.scope`: `session:role:<role_name>`.
+- `iceberg.rest.vended-credentials-enabled`: enables Snowflake to return
temporary object storage credentials.
+- `client.region`: the region of the underlying object storage.
+- `iceberg.rest.view-enabled`: set to `false` when connecting to Horizon
Catalog.
+
+### Access Horizon Tables
+
+After the catalog is created, query Snowflake-managed Iceberg tables from
Doris:
+
+```sql
+SHOW DATABASES FROM snowflake_horizon;
+SHOW TABLES FROM snowflake_horizon.<schema_name>;
+
+SELECT COUNT(*)
+FROM snowflake_horizon.<schema_name>.<table_name>;
+```
+
+Example output:
+
+```text
+mysql> SHOW DATABASES FROM snowflake_horizon;
++--------------------+
+| Database |
++--------------------+
+| PUBLIC |
+| information_schema |
+| mysql |
++--------------------+
+
+mysql> SHOW TABLES FROM snowflake_horizon.PUBLIC;
++------------------+
+| Tables_in_PUBLIC |
++------------------+
+| DORIS_HORIZON_T |
++------------------+
+
+mysql> SELECT * FROM snowflake_horizon.PUBLIC.DORIS_HORIZON_T;
++------+-------+
+| id | name |
++------+-------+
+| 1 | alice |
+| 2 | bob |
++------+-------+
+```
+
+To write to an existing Snowflake-managed Iceberg table:
+
+```sql
+INSERT INTO snowflake_horizon.<schema_name>.<table_name>
+VALUES (1, 'doris_insert');
+```
+
+## Connect to Snowflake Open Catalog
+
+Snowflake Open Catalog is Snowflake's managed Apache Polaris / Iceberg REST
Catalog service. To use Open Catalog with Doris, prepare object storage access
first, then create an Open Catalog catalog, namespace, catalog role, and
service connection.
+
+The REST endpoints are:
+
+```text
+REST endpoint:
+https://<open_catalog_account_identifier>.snowflakecomputing.com/polaris/api/catalog
+
+Token endpoint:
+https://<open_catalog_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens
+```
+
+### AWS Environment Preparation
+
+Open Catalog stores Iceberg metadata and data files in the object storage
location specified by the catalog. If you use AWS S3, prepare an S3 bucket and
an IAM role before creating the Open Catalog catalog.
+
+#### Create an S3 Bucket
+
+Create a bucket for Iceberg table data:
+
+```bash
+aws s3 mb s3://<bucket_name> --region <region>
+aws s3 ls | grep <bucket_name>
+```
+
+The Open Catalog catalog will use a path in this bucket as its default base
location, for example:
+
+```text
+s3://<bucket_name>/<catalog_prefix>/
+```
+
+#### Create an IAM Policy for S3 Access
+
+Create an IAM policy that allows Open Catalog to access the catalog location.
Save the following content as `snowflake-open-catalog-s3-policy.json`:
+
+```bash
+cat > snowflake-open-catalog-s3-policy.json <<'EOF'
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:ListBucket",
+ "s3:GetBucketLocation",
+ "s3:ListBucketMultipartUploads"
+ ],
+ "Resource": "arn:aws:s3:::<bucket_name>",
+ "Condition": {
+ "StringLike": {
+ "s3:prefix": [
+ "<catalog_prefix>",
+ "<catalog_prefix>/*"
+ ]
+ }
+ }
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:GetObject",
+ "s3:PutObject",
+ "s3:DeleteObject",
+ "s3:AbortMultipartUpload",
+ "s3:ListMultipartUploadParts"
+ ],
+ "Resource": "arn:aws:s3:::<bucket_name>/<catalog_prefix>/*"
+ }
+ ]
+}
+EOF
+```
+
+#### Create an IAM Role
+
+Create a temporary trust policy first. After the Open Catalog catalog is
created, update the trust policy with the IAM user ARN and External ID provided
by Snowflake Open Catalog.
+
+Create `snowflake-open-catalog-trust-policy.json`:
+
+```bash
+cat > snowflake-open-catalog-trust-policy.json <<'EOF'
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "arn:aws:iam::<aws_account_id>:root"
+ },
+ "Action": "sts:AssumeRole"
+ }
+ ]
+}
+EOF
+```
+
+Create the IAM role and attach the S3 policy:
+
+```bash
+aws iam create-role \
+ --role-name <open_catalog_role_name> \
+ --assume-role-policy-document
file://snowflake-open-catalog-trust-policy.json \
+ --description "IAM role for Snowflake Open Catalog to access S3"
+
+aws iam put-role-policy \
+ --role-name <open_catalog_role_name> \
+ --policy-name snowflake-open-catalog-s3-access \
+ --policy-document file://snowflake-open-catalog-s3-policy.json
+```
+
+Verify that the IAM role and inline policy are created:
+
+```bash
+aws iam get-role --role-name <open_catalog_role_name>
+aws iam list-role-policies --role-name <open_catalog_role_name>
+```
+
+Record the role ARN. You will use it when creating the Open Catalog catalog:
+
+```text
+arn:aws:iam::<aws_account_id>:role/<open_catalog_role_name>
+```
+
+### Open Catalog Environment Setup
+
+Create an Open Catalog catalog. Use an **internal catalog** if Doris needs to
create and write Iceberg tables.
+
+
+
+Typical catalog settings:
+
+```text
+name: <catalog_name>
+type: INTERNAL
+storage provider: S3
+default base location: s3://<bucket_name>/<catalog_prefix>/
+S3 role ARN: arn:aws:iam::<aws_account_id>:role/<open_catalog_role_name>
+```
+
+After creating the Open Catalog catalog, open the catalog details page and
copy the following values from storage details:
+
+- IAM user ARN
+- External ID
+
+Then update the IAM role trust relationship to use the exact values from
Snowflake Open Catalog:
+
+```bash
+cat > snowflake-open-catalog-trust-policy.json <<'EOF'
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "<open_catalog_iam_user_arn>"
+ },
+ "Action": "sts:AssumeRole",
+ "Condition": {
+ "StringEquals": {
+ "sts:ExternalId": "<external_id>"
+ }
+ }
+ }
+ ]
+}
+EOF
+
+aws iam update-assume-role-policy \
+ --role-name <open_catalog_role_name> \
+ --policy-document file://snowflake-open-catalog-trust-policy.json
+```
+
+Do not publish the IAM user ARN, External ID, or real role ARN in public
documents or screenshots.
+
+Create a namespace, for example `public`.
+
+> Image placeholder: Create a namespace in Snowflake Open Catalog.
+
Review Comment:
This block still contains an "Image placeholder" note for creating a
namespace. Please replace the placeholder with a real screenshot (if intended)
or remove it and provide the actual UI/SQL steps so it doesn’t ship as
placeholder text in published docs.
##########
docs-next/lakehouse/best-practices/doris-snowflake-catalog.md:
##########
@@ -0,0 +1,451 @@
+---
+{
+ "title": "Integration with Snowflake Catalog",
+ "language": "en",
+ "description": "This document describes how to connect Apache Doris to
Snowflake Horizon Catalog and Snowflake Open Catalog through the Iceberg REST
Catalog API."
+}
+---
+
+Apache Doris can connect to Snowflake Catalog services through the Iceberg
REST Catalog API. This integration allows Doris to query Iceberg tables managed
by Snowflake, and to create and write Iceberg tables when using Snowflake Open
Catalog internal catalogs.
+
+This document covers two Snowflake catalog services:
+
+- **Snowflake Horizon Catalog**: used to access Snowflake-managed Iceberg
tables in an existing Snowflake account.
+- **Snowflake Open Catalog**: Snowflake's managed Apache Polaris / Iceberg
REST Catalog service, used to manage Iceberg catalogs, namespaces, and tables.
+
+## Choosing a Snowflake Catalog
+
+| Item | Snowflake Horizon Catalog | Snowflake Open Catalog |
+| --- | --- | --- |
+| Main use case | Query Snowflake-managed Iceberg tables | Manage Iceberg
tables in Snowflake Open Catalog |
+| Doris `warehouse` | Snowflake database name | Open Catalog catalog name |
+| Credential | Snowflake Programmatic Access Token (PAT) | Service connection
`<client_id>:<client_secret>` |
+| OAuth scope | `session:role:<ROLE_NAME>` | `PRINCIPAL_ROLE:<ROLE_NAME>` |
+| Create tables from Doris | Not recommended | Supported on internal catalogs |
+| Write from Doris | Insert into existing Snowflake-managed Iceberg tables |
Insert into tables in internal catalogs |
+
+Use Horizon Catalog when your tables are managed by Snowflake. Use Open
Catalog internal catalogs when you want Doris to create and manage Iceberg
tables through Snowflake Open Catalog.
+
+> Note: When connecting to Horizon Catalog, set `iceberg.rest.view-enabled` to
`false`.
+
+### Storage Access Model
+
+Horizon Catalog is used for Snowflake-managed Iceberg tables, whose storage
access is managed by Snowflake. Doris obtains table metadata through the REST
Catalog API, and Snowflake returns temporary object storage credentials when
`iceberg.rest.vended-credentials-enabled` is set to `true`. Therefore, you do
not need to configure an AWS IAM role or S3 credentials in the Doris catalog
for Horizon Catalog.
+
+Open Catalog internal catalogs use the object storage location configured for
the catalog. When the location is on AWS S3, Open Catalog needs an IAM role
that it can assume to read and write Iceberg metadata and data files. In the
IAM role trust policy, the trust principal is the AWS principal allowed to call
`sts:AssumeRole`. For Snowflake Open Catalog, use the IAM user ARN shown in the
catalog storage details as the trust principal, and configure the External ID
from the same page. The External ID limits role assumption to this Open Catalog
integration and helps prevent confused-deputy access.
+
+## Connect to Snowflake Horizon Catalog
+
+### Snowflake Environment Setup
+
+Snowflake Horizon Catalog exposes Snowflake-managed Iceberg tables through the
Iceberg REST Catalog API.
+
+The REST endpoints are:
+
+```text
+REST endpoint:
+https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog
+
+Token endpoint:
+https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens
+```
+
+Create a Snowflake-managed Iceberg table:
+
+```sql
+CREATE OR REPLACE ICEBERG TABLE <database_name>.<schema_name>.<table_name> (
+ ID BIGINT,
+ NAME STRING
+)
+CATALOG = 'SNOWFLAKE'
+EXTERNAL_VOLUME = 'SNOWFLAKE_MANAGED';
+```
+
+`SNOWFLAKE_MANAGED` is a Snowflake reserved value. It is not a user-created
external volume, and you do not need to grant Doris access to an external
volume for this value.
+
+Grant privileges to the Snowflake role used by Doris:
+
+```sql
+GRANT USAGE ON DATABASE <database_name> TO ROLE <role_name>;
+GRANT USAGE ON SCHEMA <database_name>.<schema_name> TO ROLE <role_name>;
+GRANT SELECT ON TABLE <database_name>.<schema_name>.<table_name> TO ROLE
<role_name>;
+```
+
+If Doris needs to write to the table, grant write privileges:
+
+```sql
+GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE
+ON TABLE <database_name>.<schema_name>.<table_name>
+TO ROLE <role_name>;
+```
+
+Create a Programmatic Access Token (PAT) for the service user:
+
+```sql
+ALTER USER IF EXISTS <service_user>
+ADD PAT <pat_name>
+ DAYS_TO_EXPIRY = 7
+ ROLE_RESTRICTION = '<role_name>'
+ COMMENT = 'Horizon Iceberg REST access for Doris';
+```
+
+You can verify the PAT with the token endpoint:
+
+```bash
+curl -i --fail -X POST \
+
"https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens"
\
+ --header "Content-Type: application/x-www-form-urlencoded" \
+ --data-urlencode "grant_type=client_credentials" \
+ --data-urlencode "scope=session:role:<role_name>" \
+ --data-urlencode "client_secret=<PAT_token>"
+```
+
+### Create a Doris Catalog
+
+Create an Iceberg REST Catalog in Doris:
+
+```sql
+CREATE CATALOG snowflake_horizon PROPERTIES (
+ 'type' = 'iceberg',
+ 'iceberg.catalog.type' = 'rest',
+ 'iceberg.rest.uri' =
'https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog',
+ 'warehouse' = '<snowflake_database_name>',
+ 'iceberg.rest.security.type' = 'oauth2',
+ 'iceberg.rest.oauth2.credential' = '<PAT_token>',
+ 'iceberg.rest.oauth2.server-uri' =
'https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens',
+ 'iceberg.rest.oauth2.scope' = 'session:role:<role_name>',
+ 'iceberg.rest.vended-credentials-enabled' = 'true',
+ 'client.region' = '<storage_region>',
+ 'iceberg.rest.nested-namespace-enabled' = 'true',
+ 'iceberg.rest.view-enabled' = 'false',
+ 'iceberg.rest.connection-timeout-ms' = '30000',
+ 'iceberg.rest.socket-timeout-ms' = '120000'
+);
+```
+
+Parameter notes:
+
+- `warehouse`: Snowflake database name, not a Snowflake compute warehouse.
+- `iceberg.rest.oauth2.credential`: the Snowflake PAT.
+- `iceberg.rest.oauth2.scope`: `session:role:<role_name>`.
+- `iceberg.rest.vended-credentials-enabled`: enables Snowflake to return
temporary object storage credentials.
+- `client.region`: the region of the underlying object storage.
+- `iceberg.rest.view-enabled`: set to `false` when connecting to Horizon
Catalog.
+
+### Access Horizon Tables
+
+After the catalog is created, query Snowflake-managed Iceberg tables from
Doris:
+
+```sql
+SHOW DATABASES FROM snowflake_horizon;
+SHOW TABLES FROM snowflake_horizon.<schema_name>;
+
+SELECT COUNT(*)
+FROM snowflake_horizon.<schema_name>.<table_name>;
+```
+
+Example output:
+
+```text
+mysql> SHOW DATABASES FROM snowflake_horizon;
++--------------------+
+| Database |
++--------------------+
+| PUBLIC |
+| information_schema |
+| mysql |
++--------------------+
+
+mysql> SHOW TABLES FROM snowflake_horizon.PUBLIC;
++------------------+
+| Tables_in_PUBLIC |
++------------------+
+| DORIS_HORIZON_T |
++------------------+
+
+mysql> SELECT * FROM snowflake_horizon.PUBLIC.DORIS_HORIZON_T;
++------+-------+
+| id | name |
++------+-------+
+| 1 | alice |
+| 2 | bob |
++------+-------+
+```
+
+To write to an existing Snowflake-managed Iceberg table:
+
+```sql
+INSERT INTO snowflake_horizon.<schema_name>.<table_name>
+VALUES (1, 'doris_insert');
+```
+
+## Connect to Snowflake Open Catalog
+
+Snowflake Open Catalog is Snowflake's managed Apache Polaris / Iceberg REST
Catalog service. To use Open Catalog with Doris, prepare object storage access
first, then create an Open Catalog catalog, namespace, catalog role, and
service connection.
+
+The REST endpoints are:
+
+```text
+REST endpoint:
+https://<open_catalog_account_identifier>.snowflakecomputing.com/polaris/api/catalog
+
+Token endpoint:
+https://<open_catalog_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens
+```
+
+### AWS Environment Preparation
+
+Open Catalog stores Iceberg metadata and data files in the object storage
location specified by the catalog. If you use AWS S3, prepare an S3 bucket and
an IAM role before creating the Open Catalog catalog.
+
+#### Create an S3 Bucket
+
+Create a bucket for Iceberg table data:
+
+```bash
+aws s3 mb s3://<bucket_name> --region <region>
+aws s3 ls | grep <bucket_name>
+```
+
+The Open Catalog catalog will use a path in this bucket as its default base
location, for example:
+
+```text
+s3://<bucket_name>/<catalog_prefix>/
+```
+
+#### Create an IAM Policy for S3 Access
+
+Create an IAM policy that allows Open Catalog to access the catalog location.
Save the following content as `snowflake-open-catalog-s3-policy.json`:
+
+```bash
+cat > snowflake-open-catalog-s3-policy.json <<'EOF'
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:ListBucket",
+ "s3:GetBucketLocation",
+ "s3:ListBucketMultipartUploads"
+ ],
+ "Resource": "arn:aws:s3:::<bucket_name>",
+ "Condition": {
+ "StringLike": {
+ "s3:prefix": [
+ "<catalog_prefix>",
+ "<catalog_prefix>/*"
+ ]
+ }
+ }
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:GetObject",
+ "s3:PutObject",
+ "s3:DeleteObject",
+ "s3:AbortMultipartUpload",
+ "s3:ListMultipartUploadParts"
+ ],
+ "Resource": "arn:aws:s3:::<bucket_name>/<catalog_prefix>/*"
+ }
+ ]
+}
+EOF
+```
+
+#### Create an IAM Role
+
+Create a temporary trust policy first. After the Open Catalog catalog is
created, update the trust policy with the IAM user ARN and External ID provided
by Snowflake Open Catalog.
+
+Create `snowflake-open-catalog-trust-policy.json`:
+
+```bash
+cat > snowflake-open-catalog-trust-policy.json <<'EOF'
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "arn:aws:iam::<aws_account_id>:root"
+ },
+ "Action": "sts:AssumeRole"
+ }
+ ]
+}
+EOF
+```
+
+Create the IAM role and attach the S3 policy:
+
+```bash
+aws iam create-role \
+ --role-name <open_catalog_role_name> \
+ --assume-role-policy-document
file://snowflake-open-catalog-trust-policy.json \
+ --description "IAM role for Snowflake Open Catalog to access S3"
+
+aws iam put-role-policy \
+ --role-name <open_catalog_role_name> \
+ --policy-name snowflake-open-catalog-s3-access \
+ --policy-document file://snowflake-open-catalog-s3-policy.json
+```
+
+Verify that the IAM role and inline policy are created:
+
+```bash
+aws iam get-role --role-name <open_catalog_role_name>
+aws iam list-role-policies --role-name <open_catalog_role_name>
+```
+
+Record the role ARN. You will use it when creating the Open Catalog catalog:
+
+```text
+arn:aws:iam::<aws_account_id>:role/<open_catalog_role_name>
+```
+
+### Open Catalog Environment Setup
+
+Create an Open Catalog catalog. Use an **internal catalog** if Doris needs to
create and write Iceberg tables.
+
+
+
+Typical catalog settings:
+
+```text
+name: <catalog_name>
+type: INTERNAL
+storage provider: S3
+default base location: s3://<bucket_name>/<catalog_prefix>/
+S3 role ARN: arn:aws:iam::<aws_account_id>:role/<open_catalog_role_name>
+```
+
+After creating the Open Catalog catalog, open the catalog details page and
copy the following values from storage details:
+
+- IAM user ARN
+- External ID
+
+Then update the IAM role trust relationship to use the exact values from
Snowflake Open Catalog:
+
+```bash
+cat > snowflake-open-catalog-trust-policy.json <<'EOF'
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "<open_catalog_iam_user_arn>"
+ },
+ "Action": "sts:AssumeRole",
+ "Condition": {
+ "StringEquals": {
+ "sts:ExternalId": "<external_id>"
+ }
+ }
+ }
+ ]
+}
+EOF
+
+aws iam update-assume-role-policy \
+ --role-name <open_catalog_role_name> \
+ --policy-document file://snowflake-open-catalog-trust-policy.json
+```
+
+Do not publish the IAM user ARN, External ID, or real role ARN in public
documents or screenshots.
+
+Create a namespace, for example `public`.
+
+> Image placeholder: Create a namespace in Snowflake Open Catalog.
Review Comment:
This block still contains an "Image placeholder" note for creating a
namespace. Please replace the placeholder with a real screenshot (if intended)
or remove it and provide the actual UI/SQL steps so it doesn’t ship as
placeholder text in published docs.
##########
i18n/zh-CN/docusaurus-plugin-content-docs-next/current/lakehouse/best-practices/doris-snowflake-catalog.md:
##########
@@ -0,0 +1,451 @@
+---
+{
+ "title": "集成 Snowflake Catalog",
+ "language": "zh-CN",
+ "description": "本文介绍如何通过 Iceberg REST Catalog 将 Apache Doris 接入 Snowflake
Horizon Catalog 和 Snowflake Open Catalog。"
+}
+---
+
+Apache Doris 可以通过 Iceberg REST Catalog API 接入 Snowflake 的 Catalog
服务。通过该能力,Doris 可以查询 Snowflake 管理的 Iceberg 表,也可以在使用 Snowflake Open Catalog
internal catalog 时创建和写入 Iceberg 表。
+
+本文介绍两种 Snowflake Catalog 接入方式:
+
+- **Snowflake Horizon Catalog**:用于访问现有 Snowflake 账号中的 Snowflake-managed
Iceberg tables。
+- **Snowflake Open Catalog**:Snowflake 托管的 Apache Polaris / Iceberg REST
Catalog 服务,用于管理 Iceberg catalog、namespace 和 table。
+
+## 选择 Horizon Catalog 还是 Open Catalog
+
+| 项目 | Snowflake Horizon Catalog | Snowflake Open Catalog |
+| --- | --- | --- |
+| 主要场景 | 查询 Snowflake-managed Iceberg tables | 在 Snowflake Open Catalog 中管理
Iceberg tables |
+| Doris `warehouse` | Snowflake database name | Open Catalog catalog name |
+| 凭证 | Snowflake Programmatic Access Token,简称 PAT | Service connection
`<client_id>:<client_secret>` |
+| OAuth scope | `session:role:<ROLE_NAME>` | `PRINCIPAL_ROLE:<ROLE_NAME>` |
+| 通过 Doris 建表 | 不推荐 | internal catalog 支持 |
+| 通过 Doris 写入 | 写入已有 Snowflake-managed Iceberg table | 写入 internal catalog 中的表
|
+
+如果表由 Snowflake 管理,使用 Horizon Catalog。如果希望 Doris 通过 Snowflake Open Catalog
创建和管理 Iceberg 表,使用 Open Catalog internal catalog。
+
+> 注意:接入 Horizon Catalog 时,需要设置 `iceberg.rest.view-enabled = false`。
+
+### 存储访问模型
+
+Horizon Catalog 用于 Snowflake-managed Iceberg tables,底层存储访问由 Snowflake 管理。Doris
通过 REST Catalog API 获取表 metadata,且在 `iceberg.rest.vended-credentials-enabled`
设置为 `true` 时,由 Snowflake 下发对象存储临时凭证。因此接入 Horizon Catalog 时,不需要在 Doris Catalog
中配置用户侧 AWS IAM role 或 S3 凭证。
+
+Open Catalog internal catalog 使用 catalog 中配置的对象存储路径。如果该路径在 AWS S3 上,Open
Catalog 需要一个可被其 assume 的 IAM role,用于读写 Iceberg metadata 和数据文件。在 IAM role trust
policy 中,trust principal 指的是被允许调用 `sts:AssumeRole` 的 AWS principal。对于 Snowflake
Open Catalog,需要使用 catalog storage details 中显示的 IAM user ARN 作为 trust
principal,并配置同一页面提供的 External ID。External ID 用于将 assume role 限定到这一个 Open
Catalog 集成,降低 confused-deputy 风险。
+
+## 接入 Snowflake Horizon Catalog
+
+### Snowflake 环境准备
+
+Snowflake Horizon Catalog 通过 Iceberg REST Catalog API 暴露 Snowflake-managed
Iceberg tables。
+
+REST endpoint 如下:
+
+```text
+REST endpoint:
+https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog
+
+Token endpoint:
+https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens
+```
+
+创建 Snowflake-managed Iceberg table:
+
+```sql
+CREATE OR REPLACE ICEBERG TABLE <database_name>.<schema_name>.<table_name> (
+ ID BIGINT,
+ NAME STRING
+)
+CATALOG = 'SNOWFLAKE'
+EXTERNAL_VOLUME = 'SNOWFLAKE_MANAGED';
+```
+
+`SNOWFLAKE_MANAGED` 是 Snowflake 保留值,不是用户自建 external volume,因此不需要单独给 Doris 授权访问
external volume。
+
+给 Doris 使用的 Snowflake role 授权:
+
+```sql
+GRANT USAGE ON DATABASE <database_name> TO ROLE <role_name>;
+GRANT USAGE ON SCHEMA <database_name>.<schema_name> TO ROLE <role_name>;
+GRANT SELECT ON TABLE <database_name>.<schema_name>.<table_name> TO ROLE
<role_name>;
+```
+
+如果需要 Doris 写入表,继续授予写权限:
+
+```sql
+GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE
+ON TABLE <database_name>.<schema_name>.<table_name>
+TO ROLE <role_name>;
+```
+
+为 service user 创建 Programmatic Access Token:
+
+```sql
+ALTER USER IF EXISTS <service_user>
+ADD PAT <pat_name>
+ DAYS_TO_EXPIRY = 7
+ ROLE_RESTRICTION = '<role_name>'
+ COMMENT = 'Horizon Iceberg REST access for Doris';
+```
+
+可以使用 token endpoint 验证 PAT:
+
+```bash
+curl -i --fail -X POST \
+
"https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens"
\
+ --header "Content-Type: application/x-www-form-urlencoded" \
+ --data-urlencode "grant_type=client_credentials" \
+ --data-urlencode "scope=session:role:<role_name>" \
+ --data-urlencode "client_secret=<PAT_token>"
+```
+
+### 在 Doris 中创建 Catalog
+
+在 Doris 中创建 Iceberg REST Catalog:
+
+```sql
+CREATE CATALOG snowflake_horizon PROPERTIES (
+ 'type' = 'iceberg',
+ 'iceberg.catalog.type' = 'rest',
+ 'iceberg.rest.uri' =
'https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog',
+ 'warehouse' = '<snowflake_database_name>',
+ 'iceberg.rest.security.type' = 'oauth2',
+ 'iceberg.rest.oauth2.credential' = '<PAT_token>',
+ 'iceberg.rest.oauth2.server-uri' =
'https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens',
+ 'iceberg.rest.oauth2.scope' = 'session:role:<role_name>',
+ 'iceberg.rest.vended-credentials-enabled' = 'true',
+ 'client.region' = '<storage_region>',
+ 'iceberg.rest.nested-namespace-enabled' = 'true',
+ 'iceberg.rest.view-enabled' = 'false',
+ 'iceberg.rest.connection-timeout-ms' = '30000',
+ 'iceberg.rest.socket-timeout-ms' = '120000'
+);
+```
+
+参数说明:
+
+- `warehouse`:Snowflake database name,不是 Snowflake compute warehouse。
+- `iceberg.rest.oauth2.credential`:Snowflake PAT。
+- `iceberg.rest.oauth2.scope`:`session:role:<role_name>`。
+- `iceberg.rest.vended-credentials-enabled`:允许 Snowflake 返回对象存储临时凭证。
+- `client.region`:底层对象存储所在 region。
+- `iceberg.rest.view-enabled`:接入 Horizon Catalog 时设置为 `false`。
+
+### 访问 Horizon 表
+
+Catalog 创建完成后,可以在 Doris 中查询 Snowflake-managed Iceberg tables:
+
+```sql
+SHOW DATABASES FROM snowflake_horizon;
+SHOW TABLES FROM snowflake_horizon.<schema_name>;
+
+SELECT COUNT(*)
+FROM snowflake_horizon.<schema_name>.<table_name>;
+```
+
+示例结果:
+
+```text
+mysql> SHOW DATABASES FROM snowflake_horizon;
++--------------------+
+| Database |
++--------------------+
+| PUBLIC |
+| information_schema |
+| mysql |
++--------------------+
+
+mysql> SHOW TABLES FROM snowflake_horizon.PUBLIC;
++------------------+
+| Tables_in_PUBLIC |
++------------------+
+| DORIS_HORIZON_T |
++------------------+
+
+mysql> SELECT * FROM snowflake_horizon.PUBLIC.DORIS_HORIZON_T;
++------+-------+
+| id | name |
++------+-------+
+| 1 | alice |
+| 2 | bob |
++------+-------+
+```
+
+写入已有 Snowflake-managed Iceberg table:
+
+```sql
+INSERT INTO snowflake_horizon.<schema_name>.<table_name>
+VALUES (1, 'doris_insert');
+```
+
+## 接入 Snowflake Open Catalog
+
+Snowflake Open Catalog 是 Snowflake 托管的 Apache Polaris / Iceberg REST Catalog
服务。使用 Open Catalog 接入 Doris 时,先准备对象存储访问,再创建 Open Catalog
catalog、namespace、catalog role 和 service connection。
+
+REST endpoint 如下:
+
+```text
+REST endpoint:
+https://<open_catalog_account_identifier>.snowflakecomputing.com/polaris/api/catalog
+
+Token endpoint:
+https://<open_catalog_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens
+```
+
+### AWS 环境准备
+
+Open Catalog 会将 Iceberg metadata 和数据文件存放在 catalog 指定的对象存储路径中。如果使用 AWS S3,需要先准备
S3 bucket 和 IAM role。
+
+#### 创建 S3 存储桶
+
+创建用于存放 Iceberg 表数据的 S3 bucket:
+
+```bash
+aws s3 mb s3://<bucket_name> --region <region>
+aws s3 ls | grep <bucket_name>
+```
+
+Open Catalog catalog 会使用该 bucket 下的一个路径作为 default base location,例如:
+
+```text
+s3://<bucket_name>/<catalog_prefix>/
+```
+
+#### 创建 S3 访问权限策略
+
+创建 IAM policy,允许 Open Catalog 访问 catalog location。将以下内容保存为
`snowflake-open-catalog-s3-policy.json`:
+
+```bash
+cat > snowflake-open-catalog-s3-policy.json <<'EOF'
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:ListBucket",
+ "s3:GetBucketLocation",
+ "s3:ListBucketMultipartUploads"
+ ],
+ "Resource": "arn:aws:s3:::<bucket_name>",
+ "Condition": {
+ "StringLike": {
+ "s3:prefix": [
+ "<catalog_prefix>",
+ "<catalog_prefix>/*"
+ ]
+ }
+ }
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:GetObject",
+ "s3:PutObject",
+ "s3:DeleteObject",
+ "s3:AbortMultipartUpload",
+ "s3:ListMultipartUploadParts"
+ ],
+ "Resource": "arn:aws:s3:::<bucket_name>/<catalog_prefix>/*"
+ }
+ ]
+}
+EOF
+```
+
+#### 创建 IAM Role
+
+先创建一个临时 trust policy。Open Catalog catalog 创建完成后,再使用 Snowflake Open Catalog 提供的
IAM user ARN 和 External ID 更新 trust policy。
+
+创建 `snowflake-open-catalog-trust-policy.json`:
+
+```bash
+cat > snowflake-open-catalog-trust-policy.json <<'EOF'
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "arn:aws:iam::<aws_account_id>:root"
+ },
+ "Action": "sts:AssumeRole"
+ }
+ ]
+}
+EOF
+```
+
+创建 IAM role 并绑定 S3 policy:
+
+```bash
+aws iam create-role \
+ --role-name <open_catalog_role_name> \
+ --assume-role-policy-document
file://snowflake-open-catalog-trust-policy.json \
+ --description "IAM role for Snowflake Open Catalog to access S3"
+
+aws iam put-role-policy \
+ --role-name <open_catalog_role_name> \
+ --policy-name snowflake-open-catalog-s3-access \
+ --policy-document file://snowflake-open-catalog-s3-policy.json
+```
+
+验证 IAM role 和 inline policy 已创建:
+
+```bash
+aws iam get-role --role-name <open_catalog_role_name>
+aws iam list-role-policies --role-name <open_catalog_role_name>
+```
+
+记录 role ARN。创建 Open Catalog catalog 时需要填写该值:
+
+```text
+arn:aws:iam::<aws_account_id>:role/<open_catalog_role_name>
+```
+
+### Open Catalog 环境准备
+
+创建 Open Catalog catalog。如果需要 Doris 创建和写入 Iceberg 表,请使用 **internal catalog**。
+
+
+
+典型配置如下:
+
+```text
+name: <catalog_name>
+type: INTERNAL
+storage provider: S3
+default base location: s3://<bucket_name>/<catalog_prefix>/
+S3 role ARN: arn:aws:iam::<aws_account_id>:role/<open_catalog_role_name>
+```
+
+Open Catalog catalog 创建完成后,在 catalog details 页面中的 storage details 复制以下值:
+
+- IAM user ARN
+- External ID
+
+然后使用 Snowflake Open Catalog 提供的精确值更新 IAM role trust relationship:
+
+```bash
+cat > snowflake-open-catalog-trust-policy.json <<'EOF'
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "<open_catalog_iam_user_arn>"
+ },
+ "Action": "sts:AssumeRole",
+ "Condition": {
+ "StringEquals": {
+ "sts:ExternalId": "<external_id>"
+ }
+ }
+ }
+ ]
+}
+EOF
+
+aws iam update-assume-role-policy \
+ --role-name <open_catalog_role_name> \
+ --policy-document file://snowflake-open-catalog-trust-policy.json
+```
+
+不要在公开文档或截图中暴露 IAM user ARN、External ID 或真实 role ARN。
+
+创建 namespace,例如 `public`。
+
+> 图片占位:在 Snowflake Open Catalog 中创建 namespace。
Review Comment:
这里仍然保留了“图片占位:在 Snowflake Open Catalog 中创建
namespace”的占位提示。建议补充实际截图(如计划提供)或删除占位并补充具体操作步骤,避免占位内容随文档发布。
##########
i18n/zh-CN/docusaurus-plugin-content-docs/current/lakehouse/best-practices/doris-snowflake-catalog.md:
##########
@@ -0,0 +1,451 @@
+---
+{
+ "title": "集成 Snowflake Catalog",
+ "language": "zh-CN",
+ "description": "本文介绍如何通过 Iceberg REST Catalog 将 Apache Doris 接入 Snowflake
Horizon Catalog 和 Snowflake Open Catalog。"
+}
+---
+
+Apache Doris 可以通过 Iceberg REST Catalog API 接入 Snowflake 的 Catalog
服务。通过该能力,Doris 可以查询 Snowflake 管理的 Iceberg 表,也可以在使用 Snowflake Open Catalog
internal catalog 时创建和写入 Iceberg 表。
+
+本文介绍两种 Snowflake Catalog 接入方式:
+
+- **Snowflake Horizon Catalog**:用于访问现有 Snowflake 账号中的 Snowflake-managed
Iceberg tables。
+- **Snowflake Open Catalog**:Snowflake 托管的 Apache Polaris / Iceberg REST
Catalog 服务,用于管理 Iceberg catalog、namespace 和 table。
+
+## 选择 Horizon Catalog 还是 Open Catalog
+
+| 项目 | Snowflake Horizon Catalog | Snowflake Open Catalog |
+| --- | --- | --- |
+| 主要场景 | 查询 Snowflake-managed Iceberg tables | 在 Snowflake Open Catalog 中管理
Iceberg tables |
+| Doris `warehouse` | Snowflake database name | Open Catalog catalog name |
+| 凭证 | Snowflake Programmatic Access Token,简称 PAT | Service connection
`<client_id>:<client_secret>` |
+| OAuth scope | `session:role:<ROLE_NAME>` | `PRINCIPAL_ROLE:<ROLE_NAME>` |
+| 通过 Doris 建表 | 不推荐 | internal catalog 支持 |
+| 通过 Doris 写入 | 写入已有 Snowflake-managed Iceberg table | 写入 internal catalog 中的表
|
+
+如果表由 Snowflake 管理,使用 Horizon Catalog。如果希望 Doris 通过 Snowflake Open Catalog
创建和管理 Iceberg 表,使用 Open Catalog internal catalog。
+
+> 注意:接入 Horizon Catalog 时,需要设置 `iceberg.rest.view-enabled = false`。
+
+### 存储访问模型
+
+Horizon Catalog 用于 Snowflake-managed Iceberg tables,底层存储访问由 Snowflake 管理。Doris
通过 REST Catalog API 获取表 metadata,且在 `iceberg.rest.vended-credentials-enabled`
设置为 `true` 时,由 Snowflake 下发对象存储临时凭证。因此接入 Horizon Catalog 时,不需要在 Doris Catalog
中配置用户侧 AWS IAM role 或 S3 凭证。
+
+Open Catalog internal catalog 使用 catalog 中配置的对象存储路径。如果该路径在 AWS S3 上,Open
Catalog 需要一个可被其 assume 的 IAM role,用于读写 Iceberg metadata 和数据文件。在 IAM role trust
policy 中,trust principal 指的是被允许调用 `sts:AssumeRole` 的 AWS principal。对于 Snowflake
Open Catalog,需要使用 catalog storage details 中显示的 IAM user ARN 作为 trust
principal,并配置同一页面提供的 External ID。External ID 用于将 assume role 限定到这一个 Open
Catalog 集成,降低 confused-deputy 风险。
+
+## 接入 Snowflake Horizon Catalog
+
+### Snowflake 环境准备
+
+Snowflake Horizon Catalog 通过 Iceberg REST Catalog API 暴露 Snowflake-managed
Iceberg tables。
+
+REST endpoint 如下:
+
+```text
+REST endpoint:
+https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog
+
+Token endpoint:
+https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens
+```
+
+创建 Snowflake-managed Iceberg table:
+
+```sql
+CREATE OR REPLACE ICEBERG TABLE <database_name>.<schema_name>.<table_name> (
+ ID BIGINT,
+ NAME STRING
+)
+CATALOG = 'SNOWFLAKE'
+EXTERNAL_VOLUME = 'SNOWFLAKE_MANAGED';
+```
+
+`SNOWFLAKE_MANAGED` 是 Snowflake 保留值,不是用户自建 external volume,因此不需要单独给 Doris 授权访问
external volume。
+
+给 Doris 使用的 Snowflake role 授权:
+
+```sql
+GRANT USAGE ON DATABASE <database_name> TO ROLE <role_name>;
+GRANT USAGE ON SCHEMA <database_name>.<schema_name> TO ROLE <role_name>;
+GRANT SELECT ON TABLE <database_name>.<schema_name>.<table_name> TO ROLE
<role_name>;
+```
+
+如果需要 Doris 写入表,继续授予写权限:
+
+```sql
+GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE
+ON TABLE <database_name>.<schema_name>.<table_name>
+TO ROLE <role_name>;
+```
+
+为 service user 创建 Programmatic Access Token:
+
+```sql
+ALTER USER IF EXISTS <service_user>
+ADD PAT <pat_name>
+ DAYS_TO_EXPIRY = 7
+ ROLE_RESTRICTION = '<role_name>'
+ COMMENT = 'Horizon Iceberg REST access for Doris';
+```
+
+可以使用 token endpoint 验证 PAT:
+
+```bash
+curl -i --fail -X POST \
+
"https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens"
\
+ --header "Content-Type: application/x-www-form-urlencoded" \
+ --data-urlencode "grant_type=client_credentials" \
+ --data-urlencode "scope=session:role:<role_name>" \
+ --data-urlencode "client_secret=<PAT_token>"
+```
+
+### 在 Doris 中创建 Catalog
+
+在 Doris 中创建 Iceberg REST Catalog:
+
+```sql
+CREATE CATALOG snowflake_horizon PROPERTIES (
+ 'type' = 'iceberg',
+ 'iceberg.catalog.type' = 'rest',
+ 'iceberg.rest.uri' =
'https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog',
+ 'warehouse' = '<snowflake_database_name>',
+ 'iceberg.rest.security.type' = 'oauth2',
+ 'iceberg.rest.oauth2.credential' = '<PAT_token>',
+ 'iceberg.rest.oauth2.server-uri' =
'https://<snowflake_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens',
+ 'iceberg.rest.oauth2.scope' = 'session:role:<role_name>',
+ 'iceberg.rest.vended-credentials-enabled' = 'true',
+ 'client.region' = '<storage_region>',
+ 'iceberg.rest.nested-namespace-enabled' = 'true',
+ 'iceberg.rest.view-enabled' = 'false',
+ 'iceberg.rest.connection-timeout-ms' = '30000',
+ 'iceberg.rest.socket-timeout-ms' = '120000'
+);
+```
+
+参数说明:
+
+- `warehouse`:Snowflake database name,不是 Snowflake compute warehouse。
+- `iceberg.rest.oauth2.credential`:Snowflake PAT。
+- `iceberg.rest.oauth2.scope`:`session:role:<role_name>`。
+- `iceberg.rest.vended-credentials-enabled`:允许 Snowflake 返回对象存储临时凭证。
+- `client.region`:底层对象存储所在 region。
+- `iceberg.rest.view-enabled`:接入 Horizon Catalog 时设置为 `false`。
+
+### 访问 Horizon 表
+
+Catalog 创建完成后,可以在 Doris 中查询 Snowflake-managed Iceberg tables:
+
+```sql
+SHOW DATABASES FROM snowflake_horizon;
+SHOW TABLES FROM snowflake_horizon.<schema_name>;
+
+SELECT COUNT(*)
+FROM snowflake_horizon.<schema_name>.<table_name>;
+```
+
+示例结果:
+
+```text
+mysql> SHOW DATABASES FROM snowflake_horizon;
++--------------------+
+| Database |
++--------------------+
+| PUBLIC |
+| information_schema |
+| mysql |
++--------------------+
+
+mysql> SHOW TABLES FROM snowflake_horizon.PUBLIC;
++------------------+
+| Tables_in_PUBLIC |
++------------------+
+| DORIS_HORIZON_T |
++------------------+
+
+mysql> SELECT * FROM snowflake_horizon.PUBLIC.DORIS_HORIZON_T;
++------+-------+
+| id | name |
++------+-------+
+| 1 | alice |
+| 2 | bob |
++------+-------+
+```
+
+写入已有 Snowflake-managed Iceberg table:
+
+```sql
+INSERT INTO snowflake_horizon.<schema_name>.<table_name>
+VALUES (1, 'doris_insert');
+```
+
+## 接入 Snowflake Open Catalog
+
+Snowflake Open Catalog 是 Snowflake 托管的 Apache Polaris / Iceberg REST Catalog
服务。使用 Open Catalog 接入 Doris 时,先准备对象存储访问,再创建 Open Catalog
catalog、namespace、catalog role 和 service connection。
+
+REST endpoint 如下:
+
+```text
+REST endpoint:
+https://<open_catalog_account_identifier>.snowflakecomputing.com/polaris/api/catalog
+
+Token endpoint:
+https://<open_catalog_account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens
+```
+
+### AWS 环境准备
+
+Open Catalog 会将 Iceberg metadata 和数据文件存放在 catalog 指定的对象存储路径中。如果使用 AWS S3,需要先准备
S3 bucket 和 IAM role。
+
+#### 创建 S3 存储桶
+
+创建用于存放 Iceberg 表数据的 S3 bucket:
+
+```bash
+aws s3 mb s3://<bucket_name> --region <region>
+aws s3 ls | grep <bucket_name>
+```
+
+Open Catalog catalog 会使用该 bucket 下的一个路径作为 default base location,例如:
+
+```text
+s3://<bucket_name>/<catalog_prefix>/
+```
+
+#### 创建 S3 访问权限策略
+
+创建 IAM policy,允许 Open Catalog 访问 catalog location。将以下内容保存为
`snowflake-open-catalog-s3-policy.json`:
+
+```bash
+cat > snowflake-open-catalog-s3-policy.json <<'EOF'
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:ListBucket",
+ "s3:GetBucketLocation",
+ "s3:ListBucketMultipartUploads"
+ ],
+ "Resource": "arn:aws:s3:::<bucket_name>",
+ "Condition": {
+ "StringLike": {
+ "s3:prefix": [
+ "<catalog_prefix>",
+ "<catalog_prefix>/*"
+ ]
+ }
+ }
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:GetObject",
+ "s3:PutObject",
+ "s3:DeleteObject",
+ "s3:AbortMultipartUpload",
+ "s3:ListMultipartUploadParts"
+ ],
+ "Resource": "arn:aws:s3:::<bucket_name>/<catalog_prefix>/*"
+ }
+ ]
+}
+EOF
+```
+
+#### 创建 IAM Role
+
+先创建一个临时 trust policy。Open Catalog catalog 创建完成后,再使用 Snowflake Open Catalog 提供的
IAM user ARN 和 External ID 更新 trust policy。
+
+创建 `snowflake-open-catalog-trust-policy.json`:
+
+```bash
+cat > snowflake-open-catalog-trust-policy.json <<'EOF'
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "arn:aws:iam::<aws_account_id>:root"
+ },
+ "Action": "sts:AssumeRole"
+ }
+ ]
+}
+EOF
+```
+
+创建 IAM role 并绑定 S3 policy:
+
+```bash
+aws iam create-role \
+ --role-name <open_catalog_role_name> \
+ --assume-role-policy-document
file://snowflake-open-catalog-trust-policy.json \
+ --description "IAM role for Snowflake Open Catalog to access S3"
+
+aws iam put-role-policy \
+ --role-name <open_catalog_role_name> \
+ --policy-name snowflake-open-catalog-s3-access \
+ --policy-document file://snowflake-open-catalog-s3-policy.json
+```
+
+验证 IAM role 和 inline policy 已创建:
+
+```bash
+aws iam get-role --role-name <open_catalog_role_name>
+aws iam list-role-policies --role-name <open_catalog_role_name>
+```
+
+记录 role ARN。创建 Open Catalog catalog 时需要填写该值:
+
+```text
+arn:aws:iam::<aws_account_id>:role/<open_catalog_role_name>
+```
+
+### Open Catalog 环境准备
+
+创建 Open Catalog catalog。如果需要 Doris 创建和写入 Iceberg 表,请使用 **internal catalog**。
+
+
+
+典型配置如下:
+
+```text
+name: <catalog_name>
+type: INTERNAL
+storage provider: S3
+default base location: s3://<bucket_name>/<catalog_prefix>/
+S3 role ARN: arn:aws:iam::<aws_account_id>:role/<open_catalog_role_name>
+```
+
+Open Catalog catalog 创建完成后,在 catalog details 页面中的 storage details 复制以下值:
+
+- IAM user ARN
+- External ID
+
+然后使用 Snowflake Open Catalog 提供的精确值更新 IAM role trust relationship:
+
+```bash
+cat > snowflake-open-catalog-trust-policy.json <<'EOF'
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "<open_catalog_iam_user_arn>"
+ },
+ "Action": "sts:AssumeRole",
+ "Condition": {
+ "StringEquals": {
+ "sts:ExternalId": "<external_id>"
+ }
+ }
+ }
+ ]
+}
+EOF
+
+aws iam update-assume-role-policy \
+ --role-name <open_catalog_role_name> \
+ --policy-document file://snowflake-open-catalog-trust-policy.json
+```
+
+不要在公开文档或截图中暴露 IAM user ARN、External ID 或真实 role ARN。
+
+创建 namespace,例如 `public`。
+
+> 图片占位:在 Snowflake Open Catalog 中创建 namespace。
Review Comment:
这里仍然保留了“图片占位:在 Snowflake Open Catalog 中创建
namespace”的占位提示。建议补充实际截图(如计划提供)或删除占位并补充具体操作步骤,避免占位内容随文档发布。
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]