> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-fix-nav-issues.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Accessing Iceberg data securely

> This article demonstrates how ClickHouse Cloud customers can securely access Apache Iceberg data in object storage using role-based access.

export const Image = ({img, alt, size}) => {
  return <Frame>
      <img src={img} alt={alt} />
    </Frame>;
};

ClickHouse Cloud supports secure role-based access to Iceberg data stored in object storage (typically S3) by using an ARN-based AWS IAM trust relationship. This guide follows the same secure-setup pattern as [Accessing S3 data securely](/products/cloud/guides/data-sources/accessing-s3-data-securely), and adds Iceberg-specific configuration in ClickHouse.

<h2 id="overview">
  Overview
</h2>

* Obtain the ClickHouse Cloud service role ID (IAM).
* Create an IAM role in your AWS account that ClickHouse can assume.
* Attach Iceberg-specific object and catalog policies to the role.
* Use Iceberg table functions or the IcebergS3 table engine with role-based credentials.

<h2 id="obtaining-the-clickhouse-service-iam-role-arn">
  Obtain the ClickHouse service role ID (ARN)
</h2>

<Steps>
  <Step>
    <h3 id="login">
      1. Login to your ClickHouse Cloud account.
    </h3>
  </Step>

  <Step>
    <h3 id="select-service">
      2. Select the ClickHouse service where you want to query Iceberg data.
    </h3>
  </Step>

  <Step>
    <h3 id="settings-tab">
      3. Go to the **Settings** tab.
    </h3>
  </Step>

  <Step>
    <h3 id="network-security-information">
      4. Scroll to **Network security information**.
    </h3>
  </Step>

  <Step>
    <h3 id="service-role-iam-value">
      5. Copy the **Service role ID (IAM)** value.
    </h3>

    This ARN is required for the trust policy on the AWS IAM role that will access your Iceberg data.

    <Image img="https://mintcdn.com/private-7c7dfe99-fix-nav-issues/pb3p2qvhHWkIWhRw/images/cloud/security/secures3_arn.png?fit=max&auto=format&n=pb3p2qvhHWkIWhRw&q=85&s=8f9e668058fb087a51c04fc7c39f5bea" size="lg" alt="Obtaining ClickHouse service IAM Role ARN" border width="1222" height="254" data-path="images/cloud/security/secures3_arn.png" />
  </Step>
</Steps>

<h2 id="setting-up-iam-assume-role">
  Set up IAM assume role
</h2>

<Steps>
  <Step>
    <h3 id="aws-iam-service">
      1. Login to AWS and go to the IAM service.
    </h3>
  </Step>

  <Step>
    <h3 id="create-role">
      2. Select Roles then Create role.
    </h3>

    Select `Trusted entity type` as `Custom trust policy` and enter values based on step 3.
  </Step>

  <Step>
    <h3 id="add-trust-iam-policies">
      3. Add the Trust and IAM policies.
    </h3>

    Replace `{service-role-id}` with the Service Role ID (IAM) from your ClickHouse instance.

    ```json theme={null}
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "ClickHouseServiceRoleTrustPolicy",
          "Effect": "Allow",
          "Action": "sts:AssumeRole",
          "Principal": {
            "AWS": "{service-role-id}"  
          }
        },
        {
          "Sid": "ReadOnlyIcebergS3IAMPolicy",
          "Effect": "Allow",
          "Action": [
            "s3:GetBucketLocation",
            "s3:ListBucket",
            "s3:GetObject",
            "s3:ListMultipartUploadParts",
            "s3:GetObjectVersion",
            "s3:ListBucketVersions"
          ],
          "Resource": [
            "arn:aws:s3:::{your-bucket}",
            "arn:aws:s3:::{your-bucket}/*"
          ]
        },
        {
          "Sid": "OptionalGlueDataCatalogIAMPolicy",
          "Effect": "Allow",
          "Action": [
            "glue:GetDatabase",
            "glue:GetDatabases",
            "glue:GetTable",
            "glue:GetTables",
            "glue:GetPartition",
            "glue:GetPartitions"
          ],
          "Resource": "arn:aws:glue:{region}:{account-id}:*"
        }
      ]
    }
    ```

    <Note>
      For read/write workloads, the IAM policy must include `s3:PutObject`, `s3:DeleteObject`, and metadata-modifying actions for Iceberg. The above sample is conservative read-only.

      If you need stronger isolation, require requests to originate from ClickHouse Cloud VPC endpoints. For more information on this option, review [Secure S3 advanced action control](/products/cloud/guides/data-sources/accessing-s3-data-securely#advanced-action-control).
    </Note>
  </Step>

  <Step>
    <h3 id="finish-role-creation">
      4. Finish role creation.
    </h3>

    a. Click Next, then Next again through the permission assignment screen.

    b. Add a name (e.g. `iceberg-role-for-clickhouse`) and description.

    c. Add tags (optional).

    d. Review the policies.

    e. Select `Create role`.
  </Step>

  <Step>
    <h3 id="copy-role-arn">
      5. Copy the new **IAM Role Arn** after creation.
    </h3>
  </Step>
</Steps>

<h2 id="configure-iceberg-access">
  Configure Iceberg access in ClickHouse Cloud
</h2>

<h3 id="iceberg-table-function-with-role-arn">
  Option A: Iceberg table function with role ARN
</h3>

Use the `icebergS3` table function with the `NOSIGN` option and role-based credentials. ClickHouse Cloud will call STS to assume the role.

```sql theme={null}
SELECT count(*)
FROM icebergS3(
  'https://{your-bucket}.s3.{region}.amazonaws.com/{iceberg-path}/',
  'NOSIGN',
  extra_credentials(role_arn='arn:aws:iam::{account-id}:role/iceberg-role-for-clickhouse', role_session_name='iceberg-session')
);
```

<h3 id="persistent-iceberg-table-engine">
  Option B: Persistent Iceberg table engine
</h3>

```sql theme={null}
CREATE TABLE iceberg_secure (
  id UInt64,
  event_date Date,
  data String
)
ENGINE = IcebergS3(
  'https://{your-bucket}.s3.{region}.amazonaws.com/{iceberg-path}/',
  'NOSIGN',
  extra_credentials(role_arn='arn:aws:iam::{account-id}:role/iceberg-role-for-clickhouse')
);
```

<h3 id="glue-catalog-plus-icebergs3">
  Option C: Glue catalog + IcebergS3
</h3>

```sql theme={null}
CREATE TABLE my_db.my_table
ENGINE = IcebergS3(
  's3://{your-bucekt}/warehouse/{db}/{table}/',
  'NOSIGN',
  extra_credentials(role_arn='arn:aws:iam::{account-id}:role/iceberg-role-for-clickhouse')
)
SETTINGS
  catalog_type = 'glue',
  warehouse = '{your-warehouse}',
  storage_endpoint = 's3://{your-bucket}',
  region = '{region}'
  aws_role_arn = 'arn:aws:iam::{account-id}:role/iceberg-role-for-clickhouse';
```

> Note: When using Glue catalog, ensure your IAM role has both S3 and Glue read/list permissions.

<h3 id="datalake-catalog-for-glue">
  Option D: DataLake Catalog for Glue
</h3>

<Note>
  DataLake Catalog for Glue is coming in version 26.2.
</Note>

```sql theme={null}
CREATE DATABASE glue_test2
ENGINE = DataLakeCatalog
SETTINGS 
    catalog_type = 'glue', 
    region = {region}, 
    aws_role_arn = 'arn:aws:iam::{account-id}:role/iceberg-role-for-clickhouse',
    aws_role_session_name = {session-name},
    SETTINGS
    allow_database_glue_catalog = 1;
```

<h2 id="validate-access">
  Validate access
</h2>

1. Run a simple query:

```sql theme={null}
SELECT * FROM icebergS3('https://{your-bucket}.s3.{region}.amazonaws.com/{iceberg-path}/', 'NOSIGN')
LIMIT 5;
```

2. Check for IAM errors like `AccessDenied` or `InvalidAccessKeyId`.

<h2 id="troubelshooting">
  Troubleshooting
</h2>

* Verify the role ARN from ClickHouse Cloud service settings.
* Ensure your bucket/objects are in the same region as the Iceberg queries to reduce latency and cost.
* Confirm Iceberg table path points to a valid Iceberg metadata location (`metadata/v1/...` files under the table root).
* For catalog mode, check Glue metadata and partition visibility with AWS Glue console.
