# Wallet backup configuration
This guide provides instructions for configuring AWS S3 buckets to securely store encrypted Palisade wallet backup files. The setup ensures your encrypted recovery shards are stored with enterprise-grade security while maintaining controlled access for the Palisade MPC (Multi-Party Computation) service to write backups when needed.
This backup process works with [MPC quorums](/products/wallet/user-interface/security-controls/mpc-quorums) to ensure key recovery.
## Architecture overview
Your S3 bucket stores encrypted wallet backups in a specific folder structure, with AWS IAM roles controlling access. The Palisade MPC service assumes a role in your AWS account to write encrypted backup files, ensuring you maintain full ownership and control of your data.
```mermaid
flowchart LR
subgraph palisade["Palisade Cloud"]
MPC["MPC Service"]
end
subgraph customer["Your AWS Account"]
IAM["IAM Role
PalisadeS3BackupRole"]
subgraph s3["S3 Bucket"]
KMS["KMS Encryption"]
Shards["Recovery Shards"]
end
end
MPC -->|"1. AssumeRole
(with External ID)"| IAM
IAM -->|"2. PutObject
(encrypted)"| s3
KMS -.->|encrypts| Shards
```
### Data structure
```
your-backup-bucket/
├── /
│ ├── recovery_shard-0.txt
│ ├── recovery_shard-1.txt
│ └── recovery_shard-2.txt
└── /
├── recovery_shard-0.txt
└── recovery_shard-1.txt
```
## Prerequisites: Generate recovery key pairs
Before setting up your backup strategy, generate RSA-4096 recovery key pairs using either the Palisade Wallet Recovery CLI (recommended) or OpenSSL.
### Key format requirements
Public key files you upload to Palisade must be:
- RSA-4096 public keys
- DER encoded (PKIX/SubjectPublicKeyInfo format)
- Either binary DER format OR hex-encoded text (auto-detected)
Format auto-detection
Palisade automatically detects whether your public key file is binary DER or hex-encoded text and accepts both formats. The UI displays the detected format when you upload a file. Accepted file extensions are `.der`, `.hex`, and `.pem`.
### Option 1: Using the Palisade Wallet Recovery CLI (recommended)
For key generation, validation, and wallet recovery, use the **Palisade Wallet Recovery CLI**:
**Repository**: https://github.com/palisadeinc/wallet-recovery-cli
The CLI provides commands for:
- `generate-recovery-keypair` - Generate RSA-4096 recovery key pairs
- `validate-private-key` - Validate private key files
- `recover` - Recover wallets from encrypted backups
See the [wallet-recovery-cli README](https://github.com/palisadeinc/wallet-recovery-cli) for complete documentation.
Critical: Secure your private key
Store your private key securely. Without it, you cannot recover your wallets. Consider using a hardware security module (HSM) or secure offline storage.
### Option 2: Using OpenSSL (manual generation)
If you cannot use the Palisade CLI, generate keys using OpenSSL:
```bash
# Step 1: Generate an RSA-4096 private key
openssl genrsa -out recovery-private.pem 4096
# Step 2: Extract the public key in binary DER format
openssl rsa -in recovery-private.pem -pubout -outform DER -out recovery-public.der
# Step 3: Securely store the private key (convert to DER and optionally encrypt)
openssl rsa -in recovery-private.pem -outform DER -out recovery-private.der
```
Upload `recovery-public.der` (the binary DER file) to the Palisade UI. The UI auto-detects the format.
Optional hex encoding
You can optionally convert to hex-encoded format:
```bash
xxd -p recovery-public.der | tr -d '\n' > recovery-public.hex
```
### Verify your key files
Before uploading, verify your public key file is in the correct format:
```bash
# Check file size
wc -c recovery-public.der
# Expected output for binary DER: 550 recovery-public.der
# Expected output for hex-encoded: 1100 recovery-public.der
# Check file type
file recovery-public.der
# Binary DER output: recovery-public.der: data
# Hex-encoded output: recovery-public.der: ASCII text, with very long lines, with no line terminators
# For binary DER, check it starts with ASN.1 SEQUENCE tag (0x30)
xxd recovery-public.der | head -1
# Expected: 00000000: 3082 0222 300d 0609 2a86 4886 f70d 0101 0.."0...*.H.....
# For hex-encoded, check content starts correctly
head -c 50 recovery-public.der
# Expected: 30820222300d06092a864886f70d01010105000382020f00
```
## Step 1: Create the S3 bucket
1. Create a new S3 bucket with a descriptive name (e.g., `company-palisade-wallet-backups`).
2. Enable versioning to protect against accidental overwrites.
3. Create a KMS Customer Managed Key (CMK) for encryption, or use an existing one.
4. Enable default encryption with AWS KMS (SSE-KMS):
```json
{
"BucketEncryption": {
"ServerSideEncryptionConfiguration": [
{
"ServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "arn:aws:kms:REGION:ACCOUNT:key/KEY-ID"
},
"BucketKeyEnabled": true
}
]
}
}
```
1. Set bucket ownership and block public access:
- Enable "Block Public Access" for this bucket
- Set Object ownership to "Bucket owner enforced" to disable ACLs
2. Add a bucket policy to enforce TLS, KMS encryption, and block public access:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyInsecureTransport",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::your-backup-bucket",
"arn:aws:s3:::your-backup-bucket/*"
],
"Condition": { "Bool": { "aws:SecureTransport": "false" } }
},
{
"Sid": "DenyUnencryptedObjectUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::your-backup-bucket/*",
"Condition": {
"StringNotEquals": { "s3:x-amz-server-side-encryption": "aws:kms" }
}
},
{
"Sid": "DenyWrongKmsKey",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::your-backup-bucket/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption-aws-kms-key-id": "arn:aws:kms:REGION:ACCOUNT:key/KEY-ID"
}
}
}
]
}
```
1. Configure lifecycle policies for backup retention:
```json
{
"Rules": [
{
"Id": "RetainBackupsAndVersions",
"Status": "Enabled",
"NoncurrentVersionExpiration": {
"NoncurrentDays": 90
},
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
}
]
}
```
## Step 2: Create the IAM role for S3 access
Create an IAM role named `PalisadeS3BackupRole` (or similar) with the following configuration:
### Permission policy
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3BackupWrites",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:AbortMultipartUpload"
],
"Resource": "arn:aws:s3:::your-backup-bucket/*",
"Condition": {
"StringEquals": {
"s3:x-amz-server-side-encryption": "aws:kms",
"s3:x-amz-server-side-encryption-aws-kms-key-id": "arn:aws:kms:REGION:ACCOUNT:key/KEY-ID"
}
}
},
{
"Sid": "AllowS3BucketList",
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::your-backup-bucket"
},
{
"Sid": "AllowKMSEncryption",
"Effect": "Allow",
"Action": [
"kms:GenerateDataKey",
"kms:Encrypt",
"kms:DescribeKey"
],
"Resource": "arn:aws:kms:REGION:ACCOUNT:key/KEY-ID"
},
{
"Sid": "AllowStsGetCallerIdentity",
"Effect": "Allow",
"Action": "sts:GetCallerIdentity",
"Resource": "*"
}
]
}
```
KMS permissions required
The `AllowKMSEncryption` statement is required for the role to encrypt objects with your KMS key.
### Trust relationship policy
#### For sandbox environment (app.sandbox.palisade.co)
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::187316130931:user/mpc-service"
},
"Action": "sts:AssumeRole"
}
]
}
```
#### For production environment (app.palisade.co)
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::663932549156:user/mpc-service"
},
"Action": "sts:AssumeRole"
}
]
}
```
### Enhanced security with External ID (optional)
For additional security, require an External ID in your trust policy. This prevents the "confused deputy" problem where other AWS accounts might try to assume your role.
When you configure an External ID in the Palisade UI, the MPC service includes it when assuming your role. Your trust policy can then require this specific External ID:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::663932549156:user/mpc-service"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "your-unique-external-id"
}
}
}
]
}
```
External ID matching
The External ID you configure in the Palisade UI must exactly match the value in your trust policy's `sts:ExternalId` condition.
## Step 3: Configure in Palisade UI
After creating your S3 bucket and IAM role, configure the backup strategy in the Palisade dashboard.
Navigate to **Settings → Backup & Recovery** and enter the following:
| Field | What to enter | Example |
| --- | --- | --- |
| **Assume Role ARN** | The ARN of the IAM role you created (NOT the bucket ARN) | `arn:aws:iam::123456789012:role/PalisadeS3BackupRole` |
| **Bucket** | Just the bucket name (no ARN, no s3:// prefix) | `company-palisade-wallet-backups` |
| **Region** | The AWS region where your bucket is located | `eu-west-1` |
| **External ID (optional)** | A unique identifier for role assumption security | `palisade-backup-2024-abc123` |
| **KMS Key ARN (optional)** | The KMS key ARN for server-side encryption | `arn:aws:kms:eu-west-1:123456789012:key/12345678-1234-1234-1234-123456789012` |
Common mistake
Do not enter the S3 bucket ARN in the "Assume Role ARN" field. The system expects an IAM Role ARN in the format `arn:aws:iam:::role/`.
### Pre-flight validation
When you save your backup configuration, Palisade automatically validates that:
1. The MPC service can assume the specified IAM role
2. The role has permission to write to the S3 bucket
3. If an External ID is configured, it's accepted by the trust policy
4. If a KMS Key ARN is configured, the role can use it for encryption
This validation happens **before** Palisade provisions any wallets, ensuring you discover configuration issues immediately rather than during wallet creation.
### ARN format reference
| Type | Format | Example |
| --- | --- | --- |
| IAM Role ARN (correct) | `arn:aws:iam:::role/` | `arn:aws:iam::123456789012:role/PalisadeS3BackupRole` |
| S3 Bucket ARN (incorrect) | `arn:aws:s3:::` | `arn:aws:s3:::my-bucket` |
| KMS Key ARN | `arn:aws:kms:::key/` | `arn:aws:kms:eu-west-1:123456789012:key/...` |
## Step 4: Advanced security configuration (optional)
### Enable CloudTrail logging
```json
{
"EventSelectors": [
{
"ReadWriteType": "All",
"IncludeManagementEvents": false,
"DataResources": [
{
"Type": "AWS::S3::Object",
"Values": ["arn:aws:s3:::your-backup-bucket/*"]
}
]
}
]
}
```
### Configure S3 Object Lock (for immutable backups)
```json
{
"ObjectLockEnabled": "Enabled",
"Rule": {
"DefaultRetention": {
"Mode": "COMPLIANCE",
"Days": 30
}
}
}
```
## Security best practices checklist
- [ ] **Encryption at rest**: Default SSE-KMS with your CMK enforced at bucket and IAM policy
- [ ] **Encryption in transit**: Bucket policy enforces SSL/TLS connections
- [ ] **Access control**: IAM role with minimal required permissions
- [ ] **KMS permissions**: Role has `kms:GenerateDataKey` and `kms:Encrypt` on your CMK
- [ ] **External ID**: Configure an External ID for enhanced role assumption security
- [ ] **Versioning**: Enabled to protect against accidental overwrites
- [ ] **Logging**: CloudTrail and S3 access logging enabled
- [ ] **Monitoring**: CloudWatch alarms configured
- [ ] **Backup retention**: Lifecycle policies configured
- [ ] **MFA Delete**: Consider enabling for production buckets
## Troubleshooting
### Access denied errors
| Cause | Solution |
| --- | --- |
| Trust relationship missing Palisade account | Add correct Palisade account ID to trust policy |
| S3 bucket name mismatch | Ensure bucket name in policies matches exactly |
| Missing KMS permissions | Add required KMS permissions to IAM role |
| External ID mismatch | Verify External ID matches between UI and trust policy |
### Encryption errors
| Cause | Solution |
| --- | --- |
| SSE not enabled on bucket | Enable server-side encryption on the bucket |
| Bucket policy missing encryption requirement | Add policy requiring encrypted uploads |
| Missing KMS permissions | Add `kms:GenerateDataKey` and `kms:Encrypt` to IAM role |
| KMS Key ARN mismatch | Ensure KMS Key ARN in UI matches bucket policy |
### Role assumption failures
| Cause | Solution |
| --- | --- |
| Wrong principal ARN | Verify principal matches environment (Sandbox vs Production) |
| External ID not configured | Configure External ID in both Palisade UI and trust policy |
| Unknown error | Check CloudTrail logs for detailed error messages |
### Invalid ARN format in Palisade UI
| Cause | Solution |
| --- | --- |
| Entered S3 bucket ARN instead of IAM role ARN | Use IAM Role ARN format: `arn:aws:iam:::role/` |
| Invalid characters in role name | Use only alphanumeric characters and `+=,.@_-` |
### Pre-flight validation failures
When saving a backup configuration, you may see validation errors:
| Error | Cause | Solution |
| --- | --- | --- |
| "Failed to assume role" | Trust policy doesn't allow Palisade MPC service | Check trust policy principal ARN |
| "External ID mismatch" | External ID in UI doesn't match trust policy | Ensure External IDs match exactly |
| "Access denied to bucket" | Role lacks S3 permissions | Check IAM role permission policy |
| "KMS key access denied" | Role lacks KMS permissions | Add `kms:GenerateDataKey`, `kms:Encrypt` to role |
### Public key validation errors
#### Invalid format or file rejected on upload
The UI validates public key files on upload. Common causes of rejection:
| Cause | Solution |
| --- | --- |
| File is not a valid DER-encoded public key | Ensure the file is RSA-4096 in DER format (PKIX/SubjectPublicKeyInfo) |
| File is PEM format with headers | Use DER format, not PEM. Remove `-----BEGIN PUBLIC KEY-----` headers |
| File contains invalid characters | For hex-encoded files, ensure only hex characters (0-9, a-f) |
#### Key too small or key rejected after upload
This error means your public key is smaller than RSA-4096. Common causes:
| Cause | Solution |
| --- | --- |
| Used RSA-2048 or smaller key size | Generate RSA-4096 keys |
| File was truncated during transfer | Re-generate or re-download the key file |
#### Quick diagnostic
Run this command to check your key file:
```bash
file your-public-key.der && wc -c your-public-key.der
```
Expected output for valid RSA-4096 keys:
```
# Binary DER format (550 bytes):
your-public-key.der: data
550 your-public-key.der
# Hex-encoded format (1100 characters):
your-public-key.der: ASCII text, with very long lines, with no line terminators
1100 your-public-key.der
```
## Wallet recovery process
For complete wallet recovery instructions, see the **Palisade Wallet Recovery CLI** documentation:
**Repository**: https://github.com/palisadeinc/wallet-recovery-cli
The recovery process involves:
1. Downloading the encrypted backup from your S3 bucket
2. Using the `recover` command with your recovery private key
3. Securely handling the recovered wallet private key
Critical: Handle recovered keys with care
The recovered private key can irrevocably sign transactions affecting assets held by that wallet. Handle with extreme care and follow your organization's key management policies.
## Appendix: Quick reference
### Palisade AWS account IDs
| Environment | Account ID | MPC Service Principal |
| --- | --- | --- |
| Sandbox | 187316130931 | `arn:aws:iam::187316130931:user/mpc-service` |
| Production | 663932549156 | `arn:aws:iam::663932549156:user/mpc-service` |