# Migrating Redis OSS Across AWS Accounts — Real Issues Faced and the Production-Safe Solution

Migrating Redis OSS data across AWS accounts sounds simple:

Export snapshot → Restore in another account.

In practice, it is not that straightforward.

In this case, we migrated Redis OSS from **Account A** to **Account B** in the same region (`ap-south-1`) using default encryption (**SSE-S3**).

This post documents:

*   Why snapshot export initially failed
    
*   Why cross-account restore failed
    
*   What actually worked
    
*   The production-safe migration pattern
    

No assumptions. Only what was tested and validated.

* * *

### 1\. Architecture Overview

**Source Account (Account A)**  
Redis OSS → Manual Snapshot → Export to S3

**Target Account (Account B)**  
S3 (copied snapshot) → Restore Redis OSS

Key constraint:  
No public bucket. No insecure workaround. Production-safe design.

* * *

### 2\. Phase 1 — Snapshot Export to S3 (Why It Failed)

When exporting the snapshot from ElastiCache to S3, we encountered:

```plaintext
ElastiCache was unable to validate the authenticated user has access to the S3 bucket
```

At that time:

*   Bucket existed
    
*   Same region (`ap-south-1`)
    
*   Block public access enabled
    
*   SSE-S3 encryption enabled
    
*   Bucket policy configured
    

Yet export failed.

* * *

### Root Cause

In standard AWS regions, ElastiCache export and seed operations commonly require ACL-based grants using the service Canonical ID.  
In opt-in regions, AWS also documents a bucket policy–based approach using the `elasticache-snapshot` service principal.

Modern S3 guidance promotes disabling ACLs, but Redis export requires:

*   ACLs enabled
    
*   ElastiCache Canonical ID added
    

Without ACL configuration, export validation fails.

* * *

### Correct Export Configuration

**Step 1 — Enable ACLs**

S3 → Bucket → Permissions → Object Ownership

Change from:

```plaintext
Bucket owner enforced
```

To:

```plaintext
ACLs enabled (Bucket owner preferred)
```

Save changes.

* * *

**Step 2 — Add ElastiCache Canonical ID**

S3 → Bucket → Permissions → ACL → Edit

Add Canonical ID:

```plaintext
540804c33a284a299d2547575ce1010f2312ef3da9b3a053c8bc45bf233e4353
```

Grant:

*   Objects → List, Write
    
*   Bucket ACL → Read, Write
    

Important:

*   Block Public Access remained enabled
    
*   No “Everyone” permission added
    

After this configuration, the snapshot export succeeded.

For standard (non-GovCloud) AWS regions, ElastiCache uses the same Canonical ID. Only GovCloud regions use different Canonical IDs. Always verify from AWS official [documentation](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/backups-exporting.html) before configuring.

* * *

### 3\. Phase 2 — Cross-Account Restore Attempt

Snapshot successfully exported to:

```plaintext
s3://redis-oss-backup-bucket/redis-oss-backup-0001.rdb
```

The next step was restoring in Account B.

The restore operation is executed by the ElastiCache service in the target account, and cross-account restore requires exact service principal and permission configuration, and our bucket policy did not satisfy those requirements.

* * *

### Attempt — Cross-Account Bucket Policy

We initially configured a bucket policy allowing the ElastiCache service principal access. However, snapshot seeding requires the correct regional elasticache-snapshot service principal and specific permissions (including s3:GetBucketAcl). Our configuration did not match the documented requirement, which contributed to restore failure.

```plaintext
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowElastiCacheFromAccountB",
      "Effect": "Allow",
      "Principal": {
        "Service": "elasticache.amazonaws.com"
      },
      "Action": [
        "s3:GetObject",
        "s3:ListBucket",
        "s3:GetBucketLocation"
      ],
      "Resource": [
        "arn:aws:s3:::redis-oss-backup-bucket",
        "arn:aws:s3:::redis-oss-backup-bucket/*"
      ],
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "ACCOUNT_B_ID"
        }
      }
    }
  ]
}
```

Restore failed with:

```plaintext
No permission to access S3 object
```

Even though:

*   Region matched
    
*   Object key was correct
    
*   SSE-S3 encryption used
    
*   Service-linked role existed
    

Restore did not succeed.

* * *

### **Why It Failed**

In our tested configuration, cross-account restore required more precise service principal permissions than our implementation provided.

The restore process expects:

*   Bucket ownership alignment
    
*   Same-account execution boundary
    

In our tested implementation, the cross-account restore failed with the bucket policy configuration we applied. Rather than iterating further on service-layer permission nuances, we adopted a production-safe pattern: copy the snapshot into an S3 bucket owned by the target account and restore from there.

* * *

### 4\. Diagnostic Test — Public Object

To isolate the issue, we temporarily made the object public.

Restore succeeded immediately.

This confirmed:

*   Snapshot file was valid
    
*   Region correct
    
*   Encryption is not the issue
    
*   The permission boundary was the root cause
    

Public access is not production-safe and was used only for troubleshooting.

* * *

### 5\. Final Production-Safe Migration Pattern

Instead of forcing cross-account restore, we redesigned the architecture.

### Correct Approach

Account A  
Export snapshot → S3 bucket A

↓

Secure object copy

↓

Account B  
Restore from S3 bucket B

This ensures ownership alignment and eliminates the cross-account restore boundary.

* * *

### 6\. Implementation Steps

### Step 1 — Create S3 Bucket in Account B

*   Region: `ap-south-1`
    
*   Block Public Access: Enabled
    
*   Object Ownership: Bucket owner enforced
    
*   Default Encryption: SSE-S3
    

* * *

### Step 2 — Copy Snapshot Securely

```plaintext
aws s3 cp s3://redis-oss-backup-bucket/redis-oss-backup-0001.rdb \
s3://redis-oss-backup-bucket-b/redis-oss-backup-0001.rdb \
--source-region ap-south-1 \
--region ap-south-1
```

After copy:

*   Object owner becomes Account B
    
*   No cross-account policy required
    

Ownership alignment resolves the restore issue.

* * *

### Step 3 — Restore in Account B

Use:

```plaintext
redis-oss-backup-bucket-b/redis-oss-backup-0001.rdb
```

Restore completed successfully.

* * *

### 7\. When to Use Replication Instead

If the requirement is disaster recovery or continuous synchronization:

Use S3 Cross-Account Replication.

For one-time migration, manual secure copy is simpler and cleaner.

* * *

### 8\. Key Engineering Takeaways

1.  In standard regions, Redis OSS export typically requires ACL configuration with the ElastiCache Canonical ID.
    
2.  Cross-account restore requires precise configuration of the service principal and permissions.
    
3.  Ownership alignment via secure object copy eliminates cross-account complexity and reduces operational risk.
    
4.  SSE-S3 simplifies cross-account migration.
    
5.  Public object works but is insecure.
    
6.  Ownership alignment is the key requirement.
    
7.  Secure object copy is the cleanest production solution.
    

* * *

### Final Principle

When migrating workloads across AWS accounts:

Do not force cross-account service execution boundaries when the service is not designed to support them.

Move the data.

Align ownership.

Restore cleanly.

That is production-grade cloud engineering.
