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

# AWS S3

> Connect an AWS S3 bucket as your Bring Your Own Storage backend using cross-account IAM Role assumption or static credentials.

## Prerequisites

* **Owner** role in Enclave and an **Enterprise Advanced** plan
* An AWS account with permission to create IAM roles and S3 buckets
* An existing S3 bucket (versioning enabled is recommended)
* Network connectivity from your Enclave deployment to the S3 API endpoint

***

## Choosing an auth method

| Method                          | How it works                                                                                | Stored in DB                            |
| ------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------- |
| **Assume Role** *(recommended)* | Enclave assumes a cross-account IAM role using STS. Short-lived, auto-rotating credentials. | Only the Role ARN                       |
| **Static Credentials**          | An IAM user access key and secret are stored encrypted.                                     | Access key + secret (encrypted at rest) |

Use **Assume Role** in production. Static Credentials are suitable for testing or environments where cross-account IAM is not available.

***

## Option A — Assume Role (recommended)

Enclave uses AWS STS `AssumeRole` to obtain temporary credentials. Your organisation's UUID is used as an External ID, which prevents confused-deputy attacks — no other Enclave tenant can assume your role even if the Enclave platform ARN were known.

### Step 1 — Open the Add Storage Backend dialog

In Enclave, navigate to **Organization → Storage**, click **Add Storage Backend**, select the **AWS S3** card from the provider grid, then set **Authentication Method** to **Assume Role (cross-account — recommended for BYOS)**.

Click **Show IAM Setup Instructions**. The panel will display your pre-filled External ID, Platform Principal ARN, Trust Policy, and Permissions Policy. Keep this panel open — you will copy values from it in the steps below.

### Step 2 — Create an IAM role in AWS

In the AWS account where your S3 bucket resides, go to **IAM → Roles → Create role**.

1. Trusted entity type: **AWS account**
2. Select **Another AWS account**
3. **Account ID**: enter the Enclave platform account ID shown in the IAM Setup Instructions panel
4. Leave "Require external ID" and "Require MFA" **unchecked** — the External ID is enforced via the trust policy in the next step, not here
5. Click **Next** — skip the permissions step for now
6. **Role name**: `enclave-byos-s3-role` (any name is fine)
7. Click **Create role**

<Warning>
  Do not use "Custom trust policy" at role creation time. AWS validates principal ARNs at creation and will reject a role ARN that has not been provisioned yet. Use "Another AWS account" with the account ID — the trust policy will be replaced in the next step.
</Warning>

### Step 3 — Replace the trust policy

1. Open the newly created role → **Trust relationships** tab → **Edit trust policy**
2. Replace the entire content with the **Trust Policy** from the IAM Setup Instructions panel. It will look like:

```json theme={null}
{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "AllowEnclaveAssumeRole",
    "Effect": "Allow",
    "Principal": {
      "AWS": "arn:aws:iam::ENCLAVE_ACCOUNT_ID:root"
    },
    "Action": "sts:AssumeRole",
    "Condition": {
      "ArnLike": {
        "aws:PrincipalArn": "arn:aws:iam::ENCLAVE_ACCOUNT_ID:role/enclave-app-role"
      },
      "StringEquals": {
        "sts:ExternalId": "YOUR_ORG_UUID"
      }
    }
  }]
}
```

3. Click **Update policy**

<Note>
  The `Principal` is the Enclave account root (required to pass AWS's creation-time validation). The `ArnLike` condition locks assumption to the specific Enclave platform role at runtime. The `sts:ExternalId` scopes this role exclusively to your organisation.
</Note>

### Step 4 — Add S3 permissions

1. **Permissions** tab → **Add permissions** → **Create inline policy**
2. Switch to the **JSON** editor and paste the **Permissions Policy** from the IAM Setup Instructions panel, replacing `YOUR_BUCKET_NAME` with your actual bucket name:

```json theme={null}
{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "EnclaveS3BYOSAccess",
    "Effect": "Allow",
    "Action": [
      "s3:GetObject",
      "s3:PutObject",
      "s3:DeleteObject",
      "s3:ListBucket",
      "s3:GetBucketLocation",
      "s3:HeadBucket"
    ],
    "Resource": [
      "arn:aws:s3:::YOUR_BUCKET_NAME",
      "arn:aws:s3:::YOUR_BUCKET_NAME/*"
    ]
  }]
}
```

3. Click **Next** → name the policy (e.g. `enclave-byos-s3-permissions`) → **Create policy**

### Step 5 — Configure in Enclave

Copy the **Role ARN** from the role Summary page and fill in the remaining fields:

| Field    | Value                                                                   |
| -------- | ----------------------------------------------------------------------- |
| Role ARN | `arn:aws:iam::YOUR_ACCOUNT_ID:role/enclave-byos-s3-role`                |
| Bucket   | Your S3 bucket name                                                     |
| Region   | AWS region of the bucket (e.g. `us-east-1`)                             |
| Endpoint | Leave blank — AWS S3 endpoint is resolved automatically from the region |

<Note>
  You do not need to enter an External ID in the dialog — Enclave sets it automatically from your organisation ID. The value shown in IAM Setup Instructions is for reference when setting up the trust policy.
</Note>

Click **Test Connection** to verify, then **Save**.

***

## Option B — Static Credentials

<Warning>
  Static credentials are stored encrypted at rest in Enclave's database. Assume Role is strongly recommended for production use.
</Warning>

### Step 1 — Create an IAM user

In your AWS account, go to **IAM → Users → Create user**. On the permissions step, attach an inline policy:

```json theme={null}
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "s3:GetObject",
      "s3:PutObject",
      "s3:DeleteObject",
      "s3:ListBucket",
      "s3:GetBucketLocation",
      "s3:HeadBucket"
    ],
    "Resource": [
      "arn:aws:s3:::YOUR_BUCKET_NAME",
      "arn:aws:s3:::YOUR_BUCKET_NAME/*"
    ]
  }]
}
```

Then go to the user → **Security credentials** → **Create access key** → choose **Application running outside AWS** → download the Access Key ID and Secret Access Key.

### Step 2 — Configure in Enclave

| Field                                                            | Value |
| ---------------------------------------------------------------- | ----- |
| Select the **AWS S3** card from the provider grid, then fill in: |       |

| Field             | Value                                                       |
| ----------------- | ----------------------------------------------------------- |
| Access Key ID     | IAM user access key ID                                      |
| Secret Access Key | IAM user secret key                                         |
| Bucket Name       | Your S3 bucket name                                         |
| Region            | AWS region of the bucket (e.g. `ap-south-1`)                |
| Endpoint URL      | Leave blank — AWS S3 resolves automatically from the region |

Click **Test Connection** to verify, then **Save**.

***

## After saving

The backend is saved in **inactive** state. Return to **Organization → Storage**, open the **⋯** menu on the new backend, and click **Activate** to start routing uploads to it.

Then go to **Security → Policies → Storage** to assign the backend to the correct org unit scope (tenant-wide, domain, or department).

***

## Troubleshooting

| Error                   | Likely cause                                                                                              |
| ----------------------- | --------------------------------------------------------------------------------------------------------- |
| `AccessDenied`          | IAM role or user does not have the required S3 permissions. Check the inline policy and the bucket name.  |
| `NoSuchBucket`          | Bucket name or region is incorrect.                                                                       |
| `InvalidClientTokenId`  | Access Key ID is wrong or the IAM user has been deleted.                                                  |
| `NoCredentialProviders` | For Assume Role: the External ID or Role ARN is incorrect. Verify the trust policy was applied correctly. |
| Connection timeout      | Your Enclave deployment cannot reach the S3 endpoint. Check network/firewall rules.                       |
