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

# S3Table for Iceberg

This guide describes how to prepare an AWS S3Table catalog for use with StreamNative Ursa as an Iceberg catalog.

> **Important:** The StreamNative Ursa cluster must run in the **same region** as the S3Table bucket. Cross-region access is not supported and will fail with an AWS client error.

## Prerequisites

* An AWS account with permissions to create S3Table buckets and modify IAM roles
* A StreamNative Ursa cluster (the cluster's IAM role will be granted access to the S3Table bucket)

## 1. Create an S3Table Bucket

In the AWS S3 console, create an **S3Table bucket** in the same region as the Ursa cluster. Record the bucket ARN, which has the form:

```
arn:aws:s3tables:<region>:<account-id>:bucket/<bucket-name>
```

## 2. Grant S3Table Permissions via a Table Bucket Policy

Apply a [table bucket policy](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-tables-bucket-policy.html) on the S3Table bucket so that the StreamNative Ursa cluster's IAM role can read and write tables in the bucket.

### 2.1 Find the broker IAM role ARN

The role ARN to grant access to is the IAM role bound to the broker pods of the Pulsar cluster. On Private Cloud (running on EKS), the role ARN is recorded as the `eks.amazonaws.com/role-arn` annotation on the broker's Kubernetes ServiceAccount.

1. List the ServiceAccounts in the namespace where the cluster is deployed and identify the broker ServiceAccount (its name typically ends with `-broker`):

   ```bash theme={null}
   kubectl -n <cluster-namespace> get serviceaccount
   ```

2. Inspect the broker ServiceAccount and copy the value of the `eks.amazonaws.com/role-arn` annotation:

   ```bash theme={null}
   kubectl -n <cluster-namespace> get serviceaccount <broker-sa-name> -o yaml
   ```

   Example output (truncated):

   ```yaml theme={null}
   apiVersion: v1
   kind: ServiceAccount
   metadata:
     annotations:
       eks.amazonaws.com/role-arn: arn:aws:iam::<account-id>:role/StreamNative/sncloud-role/authorization.streamnative.io/iamaccounts/IamAccount-<namespace>-<broker-sa-name>
     name: <broker-sa-name>
     namespace: <cluster-namespace>
   ```

   The string after `eks.amazonaws.com/role-arn:` is the cluster's broker IAM role ARN.

### 2.2 Apply the table bucket policy

In the AWS S3 console, open your S3Table bucket and go to the **Permissions** tab. Choose **Edit** under **Table bucket policy** and paste the following JSON, replacing `<broker-role-arn>` with the ARN you copied in the previous step and `<your-region>`, `<your-aws-account>`, and `<your-bucket-name>` with the values for your bucket.

```json theme={null}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "S3ListTableBucket",
      "Effect": "Allow",
      "Principal": {
        "AWS": "<broker-role-arn>"
      },
      "Action": [
        "s3tables:ListTableBuckets"
      ],
      "Resource": ["*"]
    },
    {
      "Sid": "DataAccessPermissionsForS3TableBucket",
      "Effect": "Allow",
      "Principal": {
        "AWS": "<broker-role-arn>"
      },
      "Action": [
        "s3tables:GetTableBucket",
        "s3tables:CreateNamespace",
        "s3tables:GetNamespace",
        "s3tables:ListNamespaces",
        "s3tables:CreateTable",
        "s3tables:GetTable",
        "s3tables:ListTables",
        "s3tables:UpdateTableMetadataLocation",
        "s3tables:GetTableMetadataLocation",
        "s3tables:GetTableData",
        "s3tables:PutTableData"
      ],
      "Resource": [
        "arn:aws:s3tables:<your-region>:<your-aws-account>:bucket/<your-bucket-name>",
        "arn:aws:s3tables:<your-region>:<your-aws-account>:bucket/<your-bucket-name>/*"
      ]
    }
  ]
}
```

The policy panel is on the **Permissions** tab of the table bucket, as shown below:

<img src="https://mintcdn.com/streamnative/RcAw7mp1LdooFmHe/images/ursa-lakehouse/s3table-bucket-policy.webp?fit=max&auto=format&n=RcAw7mp1LdooFmHe&q=85&s=31c9ef3a1423ff216a67a99d516dffb5" alt="Set the S3 Table bucket policy" width="1720" height="718" data-path="images/ursa-lakehouse/s3table-bucket-policy.webp" />

<img src="https://mintcdn.com/streamnative/RcAw7mp1LdooFmHe/images/ursa-lakehouse/s3table-01.webp?fit=max&auto=format&n=RcAw7mp1LdooFmHe&q=85&s=683b259a155b0d41a3748899a59bc695" alt="Configuration example" width="1920" height="1145" data-path="images/ursa-lakehouse/s3table-01.webp" />

<img src="https://mintcdn.com/streamnative/RcAw7mp1LdooFmHe/images/ursa-lakehouse/s3table-02.webp?fit=max&auto=format&n=RcAw7mp1LdooFmHe&q=85&s=dd4530e3af63bd92525d9105220fb49b" alt="Configuration example" width="1920" height="781" data-path="images/ursa-lakehouse/s3table-02.webp" />

<img src="https://mintcdn.com/streamnative/RcAw7mp1LdooFmHe/images/ursa-lakehouse/s3table-03.webp?fit=max&auto=format&n=RcAw7mp1LdooFmHe&q=85&s=7b1ed8c21261be7abd0ab402a820d09a" alt="IAM permissions example" width="1920" height="1021" data-path="images/ursa-lakehouse/s3table-03.webp" />

## 3. Adjust S3Table Maintenance Settings (Recommended)

By default, S3 Tables retains snapshots for 120 hours (5 days). For production workloads, StreamNative recommends shortening this window to **6 hours**.

| Setting              | Default            | Recommended |
| -------------------- | ------------------ | ----------- |
| `MaximumSnapshotAge` | 120 hours (5 days) | 6 hours     |

**Why this matters.** S3 Tables enforces a fixed 5 MB cap on the Iceberg metadata file size. Long retention windows cause many unexpired snapshots to accumulate in the metadata file. When the metadata file grows beyond 5 MB, **subsequent snapshot commits will fail**, which stops new data from being written into the lakehouse table. A shorter `MaximumSnapshotAge` keeps the metadata file under the cap.

You can update the snapshot management settings from the S3 Table bucket console or via the AWS CLI after the bucket is created. See [S3 Tables maintenance -- Snapshot management](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-tables-maintenance.html#s3-tables-maintenance-snapshot) for the full list of maintenance settings.

## 4. (Optional) Configure AWS Athena Access

If you intend to query the S3Table data via AWS Athena, you must integrate it with AWS Lake Formation.

### 4.1 Prerequisites

Refer to [S3 Tables integration prerequisites](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-tables-integrating-aws.html#table-integration-prerequisites). In summary:

* Attach `AWSLakeFormationDataAdmin` to your IAM principal
* Add `glue:PassConnection` and `lakeformation:RegisterResource` permissions
* Use the latest version of the AWS CLI

When the S3Table bucket is created with AWS analytics services enabled, AWS automatically provisions a role (for example, `S3TablesRoleForLakeFormation_1`).

<img src="https://mintcdn.com/streamnative/RcAw7mp1LdooFmHe/images/ursa-lakehouse/s3table-04.webp?fit=max&auto=format&n=RcAw7mp1LdooFmHe&q=85&s=17f81b69ee3ad47d0629e05db98de55f" alt="S3Tables role" width="1920" height="1028" data-path="images/ursa-lakehouse/s3table-04.webp" />

Add the following inline policy to your IAM principal to grant Lake Formation operations:

```json theme={null}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AWSLakeFormationDataAdminAllow",
      "Effect": "Allow",
      "Action": [
        "lakeformation:*",
        "cloudtrail:DescribeTrails",
        "cloudtrail:LookupEvents",
        "glue:CreateCatalog", "glue:UpdateCatalog", "glue:DeleteCatalog",
        "glue:GetCatalog", "glue:GetCatalogs",
        "glue:GetDatabase", "glue:GetDatabases",
        "glue:CreateDatabase", "glue:UpdateDatabase", "glue:DeleteDatabase",
        "glue:GetConnections", "glue:SearchTables",
        "glue:GetTable", "glue:CreateTable", "glue:UpdateTable", "glue:DeleteTable",
        "glue:GetTableVersions", "glue:GetPartitions", "glue:GetTables",
        "glue:ListWorkflows", "glue:BatchGetWorkflows", "glue:DeleteWorkflow",
        "glue:GetWorkflowRuns", "glue:StartWorkflowRun", "glue:GetWorkflow",
        "glue:PassConnection",
        "s3:ListBucket", "s3:GetBucketLocation", "s3:ListAllMyBuckets", "s3:GetBucketAcl",
        "iam:ListUsers", "iam:ListRoles", "iam:GetRole", "iam:GetRolePolicy"
      ],
      "Resource": "*"
    },
    {
      "Sid": "AWSLakeFormationDataAdminDeny",
      "Effect": "Deny",
      "Action": ["lakeformation:PutDataLakeSettings"],
      "Resource": "*"
    }
  ]
}
```

### 4.2 Create a Resource Link

A resource link provides a Glue Data Catalog reference to your S3Table namespace. See [Creating a resource link](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-tables-integrating-aws.html#database-link-tables).

```bash theme={null}
aws glue create-database --region <region> --catalog-id "<account-id>" --database-input '{
  "Name": "<resource-link-name>",
  "TargetDatabase": {
    "CatalogId": "<account-id>:s3tablescatalog/<table-bucket-name>",
    "DatabaseName": "<namespace>"
  },
  "CreateTableDefaultPermissions": []
}'
```

### 4.3 Grant Lake Formation Permissions

#### On the Table

In the AWS Lake Formation console, navigate to **Data permissions -> Grant** and configure:

1. **Principals**: the IAM user, role, or SAML group that will run queries.
2. **LF-Tags or catalog resources**: choose **Named Data Catalog resources**.
3. **Catalogs**: the Glue Data Catalog created when the table bucket was integrated (`<account-id>:s3tablescatalog/<table-bucket-name>`).
4. **Databases**: the S3Table namespace.
5. **Tables**: the S3Table table.
6. **Table permissions**: **Super**.

<img src="https://mintcdn.com/streamnative/RcAw7mp1LdooFmHe/images/ursa-lakehouse/s3table-05.webp?fit=max&auto=format&n=RcAw7mp1LdooFmHe&q=85&s=7481c68b181bea1d64e17bb34d2dc756" alt="Grant table permission" width="1920" height="1023" data-path="images/ursa-lakehouse/s3table-05.webp" />

<img src="https://mintcdn.com/streamnative/RcAw7mp1LdooFmHe/images/ursa-lakehouse/s3table-06.webp?fit=max&auto=format&n=RcAw7mp1LdooFmHe&q=85&s=f76815109f47dadc32ede0bd85b1707f" alt="Grant table permission" width="1920" height="1209" data-path="images/ursa-lakehouse/s3table-06.webp" />

#### On the Resource Link

Resource links require their own grants in addition to the underlying namespace/table grants:

1. **Principals**: the IAM user/role/group.
2. **Catalogs**: your account's default catalog.
3. **Databases**: the resource link from step 4.2.
4. **Resource link permissions**: **Describe**.

<img src="https://mintcdn.com/streamnative/RcAw7mp1LdooFmHe/images/ursa-lakehouse/s3table-07.webp?fit=max&auto=format&n=RcAw7mp1LdooFmHe&q=85&s=9542d18008e62b89fd6a1a21c84d404e" alt="Grant resource link permission" width="1920" height="1192" data-path="images/ursa-lakehouse/s3table-07.webp" />

## Catalog Information Summary

When the steps above are complete, collect the following values for the StreamNative Ursa compaction service:

| Value                         | Description                                                                                                                                                                                                             |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `iceberg.catalog-backend`     | `s3table`                                                                                                                                                                                                               |
| `iceberg.uri`                 | `https://s3tables.<region>.amazonaws.com/iceberg` (region-specific endpoint -- see the [S3 Tables regions list](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-tables-regions-quotas.html#s3-tables-regions)) |
| `iceberg.warehouse`           | The S3Table bucket ARN: `arn:aws:s3tables:<region>:<account>:bucket/<bucket-name>`                                                                                                                                      |
| `iceberg.rest.signing-region` | The region of the S3Table bucket                                                                                                                                                                                        |

<img src="https://mintcdn.com/streamnative/RcAw7mp1LdooFmHe/images/ursa-lakehouse/s3table-08.webp?fit=max&auto=format&n=RcAw7mp1LdooFmHe&q=85&s=fe123a79b1af757102e4566341764c19" alt="Athena query" width="1920" height="996" data-path="images/ursa-lakehouse/s3table-08.webp" />

For the next steps, see [Configure Lakehouse Catalogs](../../configure-lakehouse-catalogs).
