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

# Set up IAM role assume

> Configure cross-account S3 access so that RisingWave Cloud can assume an IAM role in your AWS account without sharing long-term credentials.

IAM role assume (also called cross-account role delegation) lets RisingWave Cloud call `sts:AssumeRole` to obtain temporary credentials for your AWS IAM role. This avoids storing long-term access keys and follows AWS security best practices.

Use this method when you want RisingWave Cloud to read from or write to an S3 bucket in **your** AWS account using a role you control.

## How it works

```
RisingWave Cloud (AWS account: <rw-account-id>)
  → calls sts:AssumeRole
  → on: arn:aws:iam::<your-account-id>:role/<your-role>
  → receives temporary credentials
  → accesses your S3 bucket
```

1. You create an IAM role in your AWS account with the required S3 permissions.
2. You configure the role's trust policy to allow RisingWave Cloud's IAM role ARN to assume it.
3. You set `s3.assume_role` (or `s3.iam_role_arn`) in your RisingWave SQL statement to the ARN of your role.

## Required cloud metadata values

Before you begin, retrieve the following values from your cluster's [Cloud metadata](/cloud/cloud-metadata) page in the RisingWave Cloud Console (**Network Access** → **Cloud Meta** tab):

| Metadata field                       | Where it's used                                    |
| :----------------------------------- | :------------------------------------------------- |
| **Workload Identity (IAM Role ARN)** | The `Principal.AWS` value in your IAM trust policy |

## Step-by-step setup

### Step 1 — Create an IAM policy for S3 access

Create a policy that grants RisingWave the necessary permissions on your S3 bucket. Replace `<bucket>` and `<prefix>` with your values.

```json Example: S3 read/write policy theme={null}
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:DeleteObject",
                "s3:DeleteObjectVersion"
            ],
            "Resource": "arn:aws:s3:::<bucket>/<prefix>/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation"
            ],
            "Resource": "arn:aws:s3:::<bucket>",
            "Condition": {
                "StringLike": {
                    "s3:prefix": ["<prefix>/*"]
                }
            }
        }
    ]
}
```

### Step 2 — Create an IAM role with the policy attached

1. In the [AWS IAM console](https://console.aws.amazon.com/iam/), create a new role.
2. Select **Another AWS account** as the trusted entity type and enter the AWS account ID extracted from the **Workload Identity (IAM Role ARN)** (the 12-digit number after `iam::`).
3. Attach the S3 policy created in Step 1.

### Step 3 — Configure the trust policy

After the role is created, update its trust policy to allow the specific RisingWave Cloud IAM role to assume it.

Replace `<iam-role-arn>` with the **Workload Identity (IAM Role ARN)** from Cloud metadata.

```json Example: Trust policy theme={null}
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "<iam-role-arn>"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```

### Step 4 — Register the role in Allowed Principals

Add your IAM role ARN to your cluster's **Allowed Principals** list in the RisingWave Cloud Console to authorize RisingWave Cloud's principal to assume this role for the cluster. See [Managing allowed principals](#managing-allowed-principals-in-risingwave-cloud) below for the exact steps.

### Step 5 — Use the role in RisingWave

Set `s3.assume_role` to the ARN of the role you created in Step 2 and set `enable_config_load = 'true'`.

```sql Example: Sink using IAM role assume theme={null}
CREATE SINK my_sink FROM my_source WITH (
    connector = 'redshift',             -- or 'snowflake_v2', 'iceberg', etc.

    -- S3 staging
    s3.bucket_name    = '<your-bucket>',
    s3.region_name    = '<your-region>',
    s3.path           = '<your-prefix>',

    -- IAM role assume (no long-term credentials needed)
    s3.assume_role    = 'arn:aws:iam::<your-account-id>:role/<your-role>',
    enable_config_load = 'true',

    -- other connector-specific parameters...
);
```

For connectors that use `s3.iam_role_arn` instead of `s3.assume_role` (for example, the Iceberg connector), use:

```sql Example: Iceberg connector with IAM role assume theme={null}
CREATE SINK my_iceberg_sink FROM my_mv WITH (
    connector = 'iceberg',
    type      = 'append-only',
    -- ...
    s3.iam_role_arn    = 'arn:aws:iam::<your-account-id>:role/<your-role>',
    enable_config_load = 'true',
);
```

## Verify the setup

After creating the sink or source, run a quick sanity check:

1. **Check that the role is assumable** — in the AWS console, use **IAM → Roles → \<your-role> → Trust relationships** to confirm the correct principal and condition are present.
2. **Check S3 permissions** — run an `aws s3 ls s3://<bucket>/<prefix>/` command using the role (via `aws sts assume-role`) to verify read access.
3. **Check RisingWave logs** — if the sink or source fails, look for `AccessDenied` or `InvalidClientTokenId` errors. These indicate a misconfigured trust policy or incorrect ARN.

## Common errors

| Error                                          | Likely cause                                                               | Fix                                                                                                 |
| :--------------------------------------------- | :------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------- |
| `AccessDenied` when calling `AssumeRole`       | The trust policy principal doesn't match the RisingWave Cloud IAM role ARN | Copy the exact **Workload Identity (IAM Role ARN)** from Cloud metadata and update the trust policy |
| `AccessDenied` on S3 operations after assuming | The attached S3 policy is missing required actions                         | Add the missing S3 actions (see Step 1)                                                             |
| `InvalidClientTokenId`                         | Incorrect IAM role ARN in the trust policy                                 | Use the **Workload Identity (IAM Role ARN)** from Cloud metadata                                    |

## Managing allowed principals in RisingWave Cloud

To view and manage the IAM role ARNs that are authorized to access your cluster's resources via IAM Assume Role, go to your cluster in the [RisingWave Cloud Console](https://cloud.risingwave.com), click **Network Access** in the left sidebar, and select the **Allowed Principals** tab.

<Frame>
  <img src="https://mintcdn.com/risingwavelabs/0GrCqaLvuBPST-x2/images/cloud/iam-role-assume/network-access-allowed-principals.png?fit=max&auto=format&n=0GrCqaLvuBPST-x2&q=85&s=337f397d24441cbbfef0b0c0b499bc22" alt="Allowed Principals tab on the Network Access page of the RisingWave Cloud Console" width="2188" height="1258" data-path="images/cloud/iam-role-assume/network-access-allowed-principals.png" />
</Frame>

Click **Add principal** to add an IAM Role ARN that is allowed to access this cluster's resources via IAM Assume Role.

## Related pages

* [Cloud metadata](/cloud/cloud-metadata) — retrieve the IAM role ARN for your cluster
* [PrivateLink connection configuration](/cloud/create-a-connection) — set up private network connectivity
* [Sink to Amazon Redshift](/integrations/destinations/redshift) — end-to-end example with S3 staging
* [Sink to Snowflake](/integrations/destinations/snowflake-v2) — end-to-end example with S3 staging
