Custom S3 Storage

Configure Slateo to use your own AWS S3 buckets for query results and file storage.

Overview

By default, Slateo stores query results and uploaded files in Slateo-managed S3 buckets. For organizations with data residency requirements or compliance needs, you can configure Slateo to use buckets in your own AWS account.

Key Benefits:

  • Data never stored outside your AWS account
  • Per-organization IAM role for tenant isolation
  • Full control over encryption, retention, and access policies
  • Audit trail in your own CloudTrail logs

How it works

Each organization has a dedicated IAM role (slateo-prod-storage-<your-org>). Your bucket policy grants cross-account access to this role, and Slateo services assume the role to access your buckets.

Custom S3 Storage Architecture

Key components:

  1. Per-Org IAM Role: Slateo creates a dedicated role for your organization (slateo-prod-storage-<your-org>)
  2. Cross-Account Access: Slateo services assume this role to access your buckets
  3. Bucket Policy: Your S3 bucket policy grants the Slateo IAM role permission to read/write objects

Prerequisites

Before starting, ensure you have:

  • AWS account with permissions to create S3 buckets and bucket policies
  • Slateo organization slug (the subdomain in your Slateo URL, e.g., acme from acme.slateo.ai)

Setup steps

Step 1: Create S3 buckets

Create two S3 buckets in your AWS account:

Bucket PurposeRecommended NamingDescription
Uploads{company}-slateo-uploadsUser file uploads, CSVs, exports
Cache{company}-slateo-cacheQuery result caching

Using AWS CLI:

# Create uploads bucket
aws s3api create-bucket \
  --bucket {company}-slateo-uploads \
  --region us-west-2 \
  --create-bucket-configuration LocationConstraint=us-west-2

# Create cache bucket
aws s3api create-bucket \
  --bucket {company}-slateo-cache \
  --region us-west-2 \
  --create-bucket-configuration LocationConstraint=us-west-2

Block public access (required for both buckets):

aws s3api put-public-access-block \
  --bucket {company}-slateo-uploads \
  --public-access-block-configuration \
    BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

aws s3api put-public-access-block \
  --bucket {company}-slateo-cache \
  --public-access-block-configuration \
    BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

Step 2: Configure bucket policies

Add the following policy to both buckets. Replace {your-org-slug} with your organization slug and {company} with your company name in the bucket names.

Apply to uploads bucket:

aws s3api put-bucket-policy --bucket {company}-slateo-uploads --policy '{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowSlateoListBucket",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::880265510198:role/slateo-prod-storage-{your-org-slug}"
      },
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::{company}-slateo-uploads"
    },
    {
      "Sid": "AllowSlateoObjectAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::880265510198:role/slateo-prod-storage-{your-org-slug}"
      },
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:GetObjectTagging",
        "s3:PutObjectTagging"
      ],
      "Resource": "arn:aws:s3:::{company}-slateo-uploads/*"
    }
  ]
}'

Apply to cache bucket:

aws s3api put-bucket-policy --bucket {company}-slateo-cache --policy '{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowSlateoListBucket",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::880265510198:role/slateo-prod-storage-{your-org-slug}"
      },
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::{company}-slateo-cache"
    },
    {
      "Sid": "AllowSlateoObjectAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::880265510198:role/slateo-prod-storage-{your-org-slug}"
      },
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:GetObjectTagging",
        "s3:PutObjectTagging"
      ],
      "Resource": "arn:aws:s3:::{company}-slateo-cache/*"
    }
  ]
}'

Step 3: Configure CORS on cache bucket

Add CORS configuration to the cache bucket to allow browser-based downloads of query results:

aws s3api put-bucket-cors --bucket {company}-slateo-cache --cors-configuration '{
  "CORSRules": [
    {
      "AllowedHeaders": ["*"],
      "AllowedMethods": ["GET", "HEAD"],
      "AllowedOrigins": [
        "https://*.slateo.ai",
        "https://slateo.ai"
      ],
      "ExposeHeaders": ["ETag"],
      "MaxAgeSeconds": 3600
    }
  ]
}'

Step 4: (Optional) Configure KMS encryption

If using SSE-KMS encryption with a customer-managed key, grant Slateo's role access to your KMS key.

Add this statement to your KMS key policy (replace {your-org-slug} with your organization slug):

{
  "Sid": "AllowSlateoKMSAccess",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::880265510198:role/slateo-prod-storage-{your-org-slug}"
  },
  "Action": [
    "kms:Decrypt",
    "kms:Encrypt",
    "kms:GenerateDataKey"
  ],
  "Resource": "*"
}

Step 5: Configure buckets in Slateo

After configuring your buckets and policies, update your database configuration in Slateo:

  1. Go to AdminDatabases
  2. Click the settings icon (gear) on your database connection
  3. Select S3 as the storage provider
  4. Enter the following fields:
    • S3 Upload Bucket: Your uploads bucket name
    • S3 Cache Bucket: Your cache bucket name
    • AWS Region: The region where your buckets are located (defaults to us-west-2)
  5. Click Save to apply the configuration

Security considerations

PracticeDescription
Block public accessEnable all public access blocks on both buckets
Enable versioningProtect against accidental deletions (optional)
Enable access loggingLog all S3 requests to a separate bucket
Use KMS encryptionUse customer-managed keys for additional control
Enable CloudTrailAudit all API calls to your buckets

Troubleshooting

Access denied errors

  1. Check S3 storage status - Ensure the status shows Ready in Admin → Databases
  2. Verify bucket policy includes the correct IAM role: arn:aws:iam::880265510198:role/slateo-prod-storage-<your-org>
  3. Check bucket names match exactly (case-sensitive)
  4. Verify Resource ARNs include both the bucket (arn:aws:s3:::bucket) and objects (arn:aws:s3:::bucket/*) patterns

Browser download failures (query results)

If you see TypeError: Failed to fetch when viewing query results:

  1. Verify CORS configuration is applied to the cache bucket (not uploads)
  2. Check AllowedOrigins includes https://*.slateo.ai and https://slateo.ai
  3. Verify AllowedMethods includes GET and HEAD
  4. Clear browser cache - The browser may have cached a failed CORS preflight. Try a hard refresh (Cmd+Shift+R / Ctrl+Shift+R) or incognito window.

KMS decryption failures

  1. Verify KMS key policy grants access to your organization's Slateo IAM role
  2. Ensure key is in the same region as the bucket
  3. Check that key is enabled and not pending deletion

General issues

  1. Confirm buckets are created in a supported region
  2. Check CloudTrail logs for detailed error information
  3. Contact support with your organization slug and error details

Frequently asked questions

Can I use a single bucket for both uploads and cache?

No. Both upload and cache bucket fields must be specified, and they should be separate buckets for proper isolation and different lifecycle policies.

What regions are supported?

Any AWS region is supported. We recommend us-west-2 for lowest latency to Slateo's infrastructure. If your analytical database is in a different region, consider placing buckets in that region.

How do I verify the integration is working?

After configuration, run a query and check that the results are cached in your bucket. Query cache files are stored with the prefix {org-id}/query-cache/parquet/. You can also upload a CSV file and verify it appears under {org-id}/uploads/.

Can I migrate existing data to my buckets?

When you configure custom buckets, new data will automatically go to your buckets. Existing cached query results will remain in their previous location and become inaccessible through Slateo (you can re-run queries to regenerate them). Contact support if you need to discuss migration of historical file uploads.

Is there additional latency with custom buckets?

No. Cross-account IAM role assumption adds negligible overhead. For lowest latency, place your buckets in us-west-2 where Slateo's infrastructure runs.

How does this affect my AWS bill?

You will see S3 storage and request charges in your AWS account for data stored in your buckets. Cross-account access from Slateo does not incur additional AWS charges beyond standard S3 pricing.


Was this page helpful?

Was this page helpful?