## Overview

ION delivers automated data snapshots directly to an S3 bucket in your AWS account as `.tar` archives, once you set up the bucket and grant First Resonance access to write to it.

## What you need

- An S3 bucket in your AWS account
- An IAM role that First Resonance assumes to write to your bucket
- An external ID (provided by First Resonance) for secure role assumption

Once configured, snapshots are delivered to:

```
s3://<your-bucket>/<tenant-schema>/<job-id>/
```

## Set up delivery

1. **Create an S3 bucket**  
Create a bucket in your preferred AWS region, either through the AWS console or using the CLI:

```
aws s3 mb s3://<your-bucket> --region <your-region>
```

We recommend enabling:
- **Versioning**: protects against accidental overwrites.
- **Server-side encryption** (SSE-S3 or SSE-KMS): encrypts data at rest.

2. **Create an IAM role**  
Create an IAM role that First Resonance assumes to deliver snapshots to your bucket.

### Trust policy

The trust policy allows First Resonance to assume the role using an external ID. Replace `<fr-account-id>` with the First Resonance AWS account ID for your environment (provided by your account team), and `<external-id>` with the external ID we provide.

```
{
  "Version": "2012-10-17",
  "Statement": [\
    {\
      "Effect": "Allow",\
      "Principal": {\
        "AWS": "arn:aws:iam::<fr-account-id>:root"\
      },\
      "Action": "sts:AssumeRole",\
      "Condition": {\
        "StringEquals": {\
          "sts:ExternalId": "<external-id>"\
        }\
      }\
    }\
  ]
}
```

The external ID prevents the [confused deputy problem](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html) and ensures only First Resonance can assume this role.

### Permission policy

Attach the following policy to the role. Replace `<your-bucket>` with your bucket name.

```
{
  "Version": "2012-10-17",
  "Statement": [\
    {\
      "Sid": "SnapshotDeliveryBucketAccess",\
      "Effect": "Allow",\
      "Action": [\
        "s3:GetObject",\
        "s3:PutObject",\
        "s3:DeleteObject",\
        "s3:AbortMultipartUpload",\
        "s3:ListBucketMultipartUploads",\
        "s3:ListMultipartUploadParts",\
        "s3:ListBucket"\
      ],\
      "Resource": [\
        "arn:aws:s3:::<your-bucket>",\
        "arn:aws:s3:::<your-bucket>/*"\
      ]\
    }\
  ]
}
```

`s3:PutObject` handles the core upload. The additional permissions allow First Resonance to clean up incomplete uploads and list bucket contents for verification.

3. **Send your configuration**  
Provide the following details to your account team:

| Field | Description |
| --- | --- |
| Bucket name | Your S3 bucket name. |
| Bucket region | The AWS region where your bucket is located. |
| Role ARN | The full ARN of the IAM role you created. |

First Resonance provides the external ID and configures your snapshot schedule.

4. **Validation**

After we receive your configuration, our system validates access by:

1. Assuming the IAM role with the external ID.
2. Verifying the bucket exists and is accessible.
3. Writing and deleting a small test object.

If validation fails, we reach out with the specific error so you can adjust permissions.

## What gets delivered

Each snapshot creates files under your bucket with this structure:

```
s3://<your-bucket>/
  └── <tenant-schema>/
      └── <job-id>/
          ├── snapshot_tables_<job-id>.tar
          └── snapshot_attachments_<job-id>.tar
```

For large snapshots that are split into multiple files, each file includes a part number (for example, `snapshot_tables_part1_<job-id>.tar` and `snapshot_tables_part2_<job-id>.tar`).

- **snapshot_tables**: all database tables as compressed CSV files, bundled into a tar archive.
- **snapshot_attachments**: file attachments bundled into a tar archive.

## Troubleshooting

**Role assumption fails (AccessDenied)**  
**Cause:** Trust policy does not allow the First Resonance account.  
**Fix:** Verify the `Principal` in the trust policy matches the account ID provided by your account team.

**Role assumption fails with correct principal**  
**Cause:** External ID mismatch.  
**Fix:** Verify the `sts:ExternalId` condition matches the value provided by First Resonance.

**Access denied to bucket**  
**Cause:** Missing or incorrect permission policy.  
**Fix:** Verify the permission policy is attached to the role and the bucket name matches.

**Test write fails (AccessDenied)**  
**Cause:** Role lacks `s3:PutObject` permission.  
**Fix:** Check the permission policy includes `PutObject` on the bucket resource.

**Bucket does not exist**  
**Cause:** Wrong bucket name or region.  
**Fix:** Verify the bucket name and that it exists in the expected region.

## Security notes

- First Resonance uses **STS AssumeRole** with short-lived credentials that are automatically refreshed during long-running snapshots. No credentials are stored.
- The **external ID** ensures only First Resonance can assume the role.
- First Resonance only writes to your tenant’s prefix and does not read or modify other data in your bucket.
- All data is transmitted over HTTPS (TLS).
