Skip to content

AWS Transfer Family Migration

30 minute read
Content level: Advanced
0

Migration Guide: FTP/FTPS/SFTP and AS2 Servers to AWS Transfer Family

Table of Contents

  1. Executive Summary
  2. Pre-Migration Assessment
  3. Architecture Planning
  4. Protocol-Specific Migration Guides
  5. 4.1 SFTP Migration
  6. 4.2 FTPS Migration
  7. 4.3 FTP Migration
  8. 4.4 AS2 Migration
  9. Identity Provider Configuration
  10. Testing and Validation
  11. Cutover Strategy
  12. Post-Migration Operations
  13. Troubleshooting

1. Executive Summary

This runbook provides a step-by-step guide for migrating existing file transfer servers (FTP, FTPS, SFTP, and AS2) to AWS Transfer Family. AWS Transfer Family is a fully managed service that enables file transfers over SFTP, FTPS, FTP, and AS2 directly into and out of Amazon S3 or Amazon EFS.

Benefits of Migration

• Fully managed infrastructure (no server patching or maintenance) • Native integration with AWS services (S3, EFS, CloudWatch, EventBridge) • Elastic scaling without capacity planning • Built-in high availability • Pay-per-use pricing model • Compliance support (HIPAA, PCI-DSS, SOC, FedRAMP)

2. Pre-Migration Assessment

2.1 Inventory Current Environment Document the following for each existing server:

ItemDetailsNotes
Server hostname/IP
Protocols in useSFTP / FTPS / FTP / AS2
Number of users/partners
Authentication methodPassword / SSH Key / Both
Average daily transfer volumeGB/day
Peak concurrent connections
File size rangeMin/Max
Storage backendLocal disk / NAS / SAN
IP allowlisting by partnersYes / NoCritical for cutover
DNS name used by partners
TLS certificates (FTPS)Issuer / Expiry
AS2 trading partnersPartner IDs
Custom workflows/scriptsPre/post processing
Compliance requirementsHIPAA, PCI, etc.

2.2 User Inventory

For each user, document:

UsernameProtocolAuth MethodHome DirectoryPermissionsIP Restrictions

2.3 Network Dependencies

• [ ] Partners with IP allowlisting (will need Elastic IP for static IP)

• [ ] Firewall rules that reference current server IP

• [ ] VPN connections to the file transfer server

• [ ] DNS CNAME/A records pointing to current server

• [ ] Load balancer configurations

• [ ] Network ACLs or Security Groups

2.4 Data Flow Mapping

Document all automated processes that depend on file transfers:

| Process | Trigger | Source | Destination | Frequency | SLA |

| --- | --- | --- | --- | --- | --- |

3. Architecture Planning

3.1 Endpoint Type Selection

Endpoint TypeUse CaseAccessibilityStatic IP
PUBLICInternet-facing, no IP restriction neededInternetNo (dynamic)
VPC with Internet FacingInternet-facing with static IPsInternet via EIPYes (Elastic IP)
VPC (Private)Internal transfers onlyWithin VPC / VPN / Direct ConnectVPC Endpoint IPs

Decision Matrix:

• Partners require a static IP to allowlist → VPC with Internet Facing (EIP) • No IP dependency and simplest setup → PUBLIC • Internal (VPN/Direct Connect) → VPC (Private)

3.2 Storage Backend Selection

BackendBest ForConsiderations
Amazon S3Object storage, archival, data lake integrationNo POSIX permissions, lifecycle policies available
Amazon EFSShared filesystem, POSIX compatibility neededSupports NFS mount, maintains directory structure

3.3 Identity Provider Selection

OptionBest ForComplexity
Service ManagedSmall user count, SSH key authLow
AWS LambdaCustom auth logic, integration with existing directoriesMedium
API Gateway + LambdaPassword auth with custom IdPMedium-High
AWS Directory ServiceMicrosoft AD integrationMedium

4. Protocol-Specific Migration Guides

4.1 SFTP Migration

4.1.1 Overview

SFTP (SSH File Transfer Protocol) runs over SSH on port 22. This is the most common protocol for secure file transfers.

4.1.2 Pre-Requisites

• [ ] SSH public keys for all users (if using key-based auth)

• [ ] User passwords stored securely (if using password auth)

• [ ] S3 bucket or EFS filesystem created

• [ ] IAM roles for Transfer Family and users

4.1.3 Step-by-Step Migration

Step 1: Create the Transfer Family Server

  1. Navigate to AWS Transfer Family Console → Create server

  2. Select protocol: SFTP

  3. Choose Identity Provider:

  4. Service Managed: For SSH key authentication

  5. Custom Lambda: For password authentication or complex logic

  6. Choose Endpoint Type based on Section 3.1

  7. Choose Storage: S3 or EFS

  8. Configure logging (CloudWatch structured logs recommended)

Step 2: Configure IAM Roles

Create a Transfer Family access role for each user/group:


{

  "Version": "2012-10-17",

  "Statement": [

    {

      "Sid": "AllowS3Access",

      "Effect": "Allow",

      "Action": [

        "s3:PutObject",

        "s3:GetObject",

        "s3:DeleteObject",

        "s3:GetObjectVersion",

        "s3:GetBucketLocation"

      ],

      "Resource": [

        "arn:aws:s3:::your-bucket-name/*"

      ]

    },

    {

      "Sid": "AllowListBucket",

      "Effect": "Allow",

      "Action": "s3:ListBucket",

      "Resource": "arn:aws:s3:::your-bucket-name"

    }

  ]

}

Step 3: Create Users

For Service Managed identity: 1. Add user with username matching current server 2. Set IAM role 3. Configure home directory (logical or physical mapping) 4. Add SSH public key(s)

Home Directory Mapping Example (Logical):


[

  {

    "Entry": "/",

    "Target": "/your-bucket-name/home/${transfer:UserName}"

  }

]

Step 4: Migrate SSH Keys

• Export public keys from current server (typically in ~/.ssh/authorized_keys)

• Import into Transfer Family user configuration

• Format: ssh-rsa AAAA... user@host

Step 5: Test Connectivity


sftp -i private_key.pem username@server-id.server.transfer.region.amazonaws.com

4.1.4 SFTP-Specific Considerations

ConsiderationDetails
Host keyTransfer Family generates a new host key. Partners will see a host key change warning. Communicate in advance. You can import your existing host key to avoid this.
PortAlways port 22 (cannot be changed)
CiphersTransfer Family supports a fixed set of ciphers. Verify compatibility with partner clients.
BannerCustom banners can be configured via PreAuthenticationLoginBanner and PostAuthenticationLoginBanner
Session policyScope down permissions per session using session policies

4.2 FTPS Migration

4.2.1 Overview

FTPS (FTP over TLS/SSL) uses TLS encryption on ports 21 (control) and passive data ports. Transfer Family supports both Explicit and Implicit FTPS.

4.2.2 Pre-Requisites

• [ ] TLS certificate imported into AWS Certificate Manager (ACM)

• [ ] Certificate must be in the same region as the Transfer Family server

• [ ] Certificate must be RSA 2048-bit (Transfer Family requirement)

• [ ] If using a custom domain, DNS configuration ready

• [ ] Passive port range awareness (Transfer Family manages this automatically)

4.2.3 Step-by-Step Migration

Step 1: Import TLS Certificate to ACM

If migrating an existing certificate:


aws acm import-certificate \

  --certificate fileb://certificate.pem \

  --private-key fileb://private-key.pem \

  --certificate-chain fileb://certificate-chain.pem \

  --region your-region

Or request a new certificate via ACM if using a custom domain.

Step 2: Create the Transfer Family Server

  1. Select protocol: FTPS

  2. Choose Identity Provider (same options as SFTP)

  3. Choose Endpoint Type:

  4. PUBLIC: Not available for FTPS — must use VPC endpoint

  5. VPC with Internet Facing: For internet-accessible FTPS with EIP

  6. VPC (Private): For internal FTPS

  7. Attach the ACM certificate

  8. Configure Security Policy (choose TLS version minimum)

Step 3: Configure Security Groups

For FTPS, the Security Group must allow:

PortDirectionPurpose
21InboundFTP control channel
8192-8200InboundPassive data channel (Transfer Family range)

Important: Transfer Family uses passive port range 8192-8200 (not the traditional 1024-65535).

Step 4: Create Users

Same process as SFTP (Section 4.1.3, Step 3). Users can authenticate with: - Password (requires custom identity provider) - Certificate-based mutual TLS (not supported — use password)

Step 5: DNS Configuration

Point your custom domain CNAME to the Transfer Family VPC endpoint:


ftp.company.com → vpce-ID.vpce-svc-ID.region.vpce.amazonaws.com

Or if using Internet Facing with EIP, point to the Elastic IP.

Step 6: Test Connectivity


# Explicit FTPS

curl --ftp-ssl --user username:password ftps://server-endpoint:21/



# Using lftp

lftp -u username,password -e "set ftp:ssl-force true; ls; quit" server-endpoint

4.2.4 FTPS-Specific Considerations

ConsiderationDetails
Implicit vs ExplicitTransfer Family supports both. Explicit is more common.
Passive portsFixed range 8192-8200 (communicate to partners for firewall rules)
PUBLIC endpointNot available for FTPS — must use VPC endpoint type
Certificate renewalIf using ACM-issued cert, renewal is automatic. For imported certs, plan manual renewal.
Security PolicyChoose TransferSecurityPolicy-2024-01 or newer for TLS 1.2+
Active mode FTPNot supported — only Passive mode

4.3 FTP Migration

4.3.1 Overview

FTP (unencrypted) is supported by Transfer Family for backward compatibility. It should only be used within private networks where encryption is handled at the network layer (VPN, Direct Connect).

⚠️ Security Warning: FTP transmits data and credentials in plaintext. Use only within trusted networks. Migrate to SFTP or FTPS when possible.

4.3.2 Pre-Requisites

• [ ] VPC with private subnets (FTP is only available with VPC endpoint — not PUBLIC)

• [ ] Network-level encryption (VPN or Direct Connect) if traversing untrusted networks

• [ ] Security Groups configured

4.3.3 Step-by-Step Migration

Step 1: Create the Transfer Family Server

  1. Select protocol: FTP

  2. Choose Identity Provider:

  3. Custom Lambda (recommended — password auth required for FTP)

  4. API Gateway + Lambda

  5. Endpoint Type: VPC (only option for FTP)

  6. Internal or Internet Facing with EIP

  7. Storage: S3 or EFS

Step 2: Configure Security Groups

PortDirectionPurpose
21InboundFTP control channel
8192-8200InboundPassive data channel

Step 3: Identity Provider Setup

FTP requires password authentication. You must set up a custom identity provider:

• AWS Lambda function that validates credentials

• Can integrate with Parameter Store, Secrets Manager, LDAP, or external databases

• Return user role, home directory, and policy in response

Step 4: Create Users in Identity Provider

Store credentials in your chosen backend (e.g., Parameter Store):


/transfer/{server-id}/{username}

Value (JSON):


{

  "Password": "hashed-or-encrypted-password",

  "Role": "arn:aws:iam::account-id:role/transfer-user-role",

  "HomeDirectoryType": "LOGICAL",

  "HomeDirectoryDetails": "[{\"Entry\": \"/\", \"Target\": \"/bucket/home/username\"}]",

  "Policy": ""

}

Step 5: Test Connectivity


ftp server-vpc-endpoint-ip

# Login with username and password

4.3.4 FTP-Specific Considerations

ConsiderationDetails
Endpoint typeVPC only — PUBLIC not available
AuthenticationPassword only (no SSH keys)
EncryptionNone — rely on network-layer encryption
Active modeNot supported — Passive mode only
Migration pathPlan to migrate partners to SFTP/FTPS over time

4.4 AS2 Migration

4.4.1 Overview

AS2 (Applicability Statement 2) is used for B2B EDI (Electronic Data Interchange) message exchange. It provides non-repudiation through MDN (Message Disposition Notifications) and uses digital signatures and encryption.

4.4.2 Pre-Requisites

• [ ] Trading partner AS2 IDs and certificates

• [ ] Your organization's AS2 ID

• [ ] Signing and encryption certificates (imported to ACM)

• [ ] Trading partner endpoint URLs (for outbound)

• [ ] S3 bucket for incoming messages

• [ ] Agreement on MDN type (Sync/Async) with each partner

4.4.3 Step-by-Step Migration

Step 1: Import Certificates

Import your signing and encryption certificates to ACM:


# Signing certificate

aws acm import-certificate \

  --certificate fileb://signing-cert.pem \

  --private-key fileb://signing-key.pem \

  --certificate-chain fileb://chain.pem \

  --tags Key=Usage,Value=AS2-Signing



# Encryption certificate

aws acm import-certificate \

  --certificate fileb://encryption-cert.pem \

  --private-key fileb://encryption-key.pem \

  --certificate-chain fileb://chain.pem \

  --tags Key=Usage,Value=AS2-Encryption

Import trading partner certificates (public certificates only):


aws acm import-certificate \

  --certificate fileb://partner-cert.pem \

  --tags Key=Usage,Value=AS2-Partner-PartnerName

Step 2: Create the Transfer Family AS2 Server

  1. Navigate to AWS Transfer Family Console → Create server

  2. Select protocol: AS2

  3. Endpoint Type: VPC with Internet Facing (recommended for B2B)

  4. Configure Security Groups:

PortDirectionPurpose
5080InboundAS2 HTTP messages

Step 3: Create Local Profile

Your organization's AS2 identity: - AS2 ID: Your organization's AS2 identifier - Certificate: Your signing/encryption certificate from ACM

Step 4: Create Partner Profile

For each trading partner: - Partner AS2 ID - Partner certificate(s) from ACM

Step 5: Create Agreements (Inbound)

For each inbound trading partner connection: 1. Select Local Profile (your org) 2. Select Partner Profile 3. Configure S3 destination for incoming files 4. Set IAM access role 5. Configure MDN response (Signed/Unsigned, Sync/Async)

Step 6: Create Connectors (Outbound)

For each outbound connection to a trading partner: 1. Set partner AS2 endpoint URL 2. Select Local Profile 3. Select Partner Profile 4. Configure signing and encryption algorithms 5. Set MDN expectations

Step 7: Test with Trading Partners


# Send test file via connector

aws transfer start-file-transfer \

  --connector-id c-111111111111 \

  --send-file-paths /bucket-name/outbound/test-file.edi

4.4.4 AS2-Specific Considerations

| Consideration | Details |

| --- | --- |

| Port | 5080 (not standard 80/443 — communicate to partners) |

| MDN | Synchronous MDN supported; Async MDN also supported |

| Algorithms | SHA-256 signing, AES-128/256 encryption recommended |

| Certificate rotation | Plan rotation well in advance — coordinate with all partners |

| Inbound URL | Format: https://server-id.server.transfer.region.amazonaws.com:5080 or via EIP |

| Message size | Max 50 MB per transfer |

| Monitoring | CloudWatch logs + EventBridge notifications for MDN failures |

4.5 Multi-Protocol Server Configuration

4.5.1 Overview

AWS Transfer Family supports enabling multiple protocols (SFTP, FTPS, FTP, AS2) on a single server. This simplifies management and reduces costs compared to running separate servers per protocol.

4.5.2 Supported Protocol Combinations

CombinationSupportedEndpoint Type Required
SFTP + FTPS✅ YesVPC (Internet Facing or Private)
SFTP + FTP✅ YesVPC (Internet Facing or Private)
SFTP + FTPS + FTP✅ YesVPC (Internet Facing or Private)
SFTP only✅ YesPUBLIC, VPC, or VPC Internet Facing
AS2 + any other protocol❌ NoAS2 requires a dedicated server

Important: If you need AS2 alongside SFTP/FTPS/FTP, you must create a separate Transfer Family server for AS2.

Important: PUBLIC endpoint type only supports SFTP. To enable FTPS or FTP, you must use a VPC endpoint.

4.5.3 When to Use Multi-Protocol

• Partners use different protocols (some SFTP, some FTPS)

• Migrating partners from FTP/FTPS to SFTP incrementally

• Need to support legacy FTP clients while offering SFTP for modern ones

• Want a single endpoint hostname and IP for all protocols

4.5.4 Step-by-Step: Enabling Multiple Protocols

Step 1: Plan Endpoint Type

Since FTPS and FTP require VPC endpoints, a multi-protocol server must use: - VPC with Internet Facing (for external partners) - VPC Private (for internal)

Step 2: Create the Server with Multiple Protocols

Console: 1. Create server → select multiple protocols (e.g., SFTP + FTPS) 2. Choose VPC endpoint type 3. Attach TLS certificate (required for FTPS)

CLI:


aws transfer create-server \

  --protocols SFTP FTPS \

  --endpoint-type VPC \

  --endpoint-details \

    VpcId=vpc-ID,SubnetIds=subnet-ID,subnet-yyyy,SecurityGroupIds=sg-ID,AddressAllocationIds=eipalloc-ID,eipalloc-yyyy \

  --certificate arn:aws:acm:region:account:certificate/cert-id \

  --identity-provider-type AWS_LAMBDA \

  --function arn:aws:lambda:region:account:function:idp-function

Step 3: Configure Security Groups

For a multi-protocol server, open all required ports:

PortProtocolPurpose
22SFTPSSH file transfer
21FTPS / FTPControl channel
8192-8200FTPS / FTPPassive data channel

Step 4: Configure Identity Provider

For multi-protocol servers, the custom Lambda identity provider can differentiate behavior per protocol using the protocol field in the event:


def lambda_handler(event, context):

    protocol = event.get("protocol")  # "SFTP", "FTPS", or "FTP"

    username = event.get("username")



    if protocol == "SFTP":

        # Return SSH key-based auth response

        return {

            "Role": "arn:aws:iam::account:role/sftp-role",

            "PublicKeys": ["ssh-rsa AAAA..."],

            "HomeDirectoryType": "LOGICAL",

            "HomeDirectoryDetails": json.dumps([{"Entry": "/", "Target": "/bucket/sftp-users/" + username}])

        }

    elif protocol in ("FTPS", "FTP"):

        # Validate password and return response

        return {

            "Role": "arn:aws:iam::account:role/ftp-role",

            "HomeDirectoryType": "LOGICAL",

            "HomeDirectoryDetails": json.dumps([{"Entry": "/", "Target": "/bucket/ftp-users/" + username}])

        }

Step 5: User Configuration

Users can be configured to access via specific protocols or all protocols: - Same username can work across protocols (if IdP supports it) - Different home directories per protocol (via Lambda logic above) - Different IAM roles per protocol for varied permissions

4.5.5 Multi-Protocol Considerations

ConsiderationDetails
TLS CertificateRequired if FTPS is one of the protocols. Not needed for SFTP-only or FTP-only.
Identity ProviderService Managed only works for SFTP (SSH keys). For FTPS/FTP password auth, custom Lambda is required.
Endpoint TypeMust be VPC if FTPS or FTP is included. PUBLIC only supports SFTP alone.
Host Key (SFTP)Can import existing host key even on multi-protocol servers
Security PolicyApplies to FTPS TLS negotiation; separate SSH policies apply to SFTP
Adding protocols laterYou can add/remove protocols from an existing server without recreating it
BillingCharged per protocol enabled (per hour per protocol)

4.5.6 Adding a Protocol to an Existing Server


# Add FTPS to an existing SFTP-only server

aws transfer update-server \

  --server-id s-111111111111 \

  --protocols SFTP FTPS \

  --certificate arn:aws:acm:region:account:certificate/cert-id



# Note: You may need to update the endpoint type from PUBLIC to VPC first

⚠️ Warning: Changing endpoint type from PUBLIC to VPC requires server recreation (cannot be done in-place). Plan this as a new server migration if currently using PUBLIC.

5. Identity Provider Configuration

5.1 Service Managed (Simplest)

Best for: SFTP with SSH key auth and small number of users.

• Users created directly in Transfer Family

• SSH keys managed per user

• No password authentication support

5.2 Custom Lambda Identity Provider

Best for: Password auth, integration with existing user stores, dynamic user provisioning.

Architecture:

Client → Transfer Family → AWS Lambda → Parameter Store / Secrets Manager / LDAP / DB

Lambda Response Format:


{

  "Role": "arn:aws:iam::account-id:role/transfer-role",

  "HomeDirectoryType": "LOGICAL",

  "HomeDirectoryDetails": "[{\"Entry\": \"/\", \"Target\": \"/bucket/prefix\"}]",

  "PublicKeys": ["ssh-rsa AAAA..."],

  "Policy": "session-policy-json"

}

5.3 AWS Directory Service

Best for: Organizations using Microsoft Active Directory.

• Supports AD Connector or AWS Managed Microsoft AD

• Users authenticate with AD credentials

• Group-based access control

6. Testing and Validation

6.1 Functional Testing Checklist

TestProtocolStatus
User authentication (key)SFTP☐
User authentication (password)SFTP/FTPS/FTP☐
File upload (small file < 1MB)All☐
File upload (large file > 1GB)All☐
File downloadAll☐
Directory listingAll☐
Directory creationAll☐
File deletionAll☐
File rename/moveAll☐
Home directory isolationAll☐
Concurrent connectionsAll☐
AS2 message sendAS2☐
AS2 message receiveAS2☐
AS2 MDN validationAS2☐
Session policy enforcementAll☐
IP allowlist verificationAll☐

6.2 Performance Testing

• [ ] Measure transfer speeds (compare with baseline from existing server)

• [ ] Test with maximum expected concurrent connections

• [ ] Test largest expected file size

• [ ] Verify timeout behavior for long-running transfers

6.3 Security Testing

• [ ] Verify users cannot access other users' directories

• [ ] Confirm TLS/cipher compatibility (FTPS)

• [ ] Validate SSH key rotation process

• [ ] Test failed authentication logging

• [ ] Verify CloudWatch logs capture all operations

6.4 Parallel Run

Run both old and new servers simultaneously:

  1. Configure a subset of test users on Transfer Family

  2. Have partners test with the new endpoint

  3. Monitor for 1-2 weeks minimum

  4. Compare transfer logs between old and new systems

  5. Resolve any issues before full cutover

7. Cutover Strategy

7.1 Pre-Cutover Checklist

• [ ] All users tested and validated on Transfer Family

• [ ] All trading partners (AS2) confirmed connectivity

• [ ] Monitoring and alerting configured

• [ ] Rollback plan documented and tested

• [ ] Communication sent to all partners (48-72 hours advance notice minimum)

• [ ] DNS TTL lowered to 60 seconds (at least 48 hours before cutover)

7.2 Cutover Options

Option A: DNS Switchover (Recommended)

  1. Partners use a DNS name (e.g., sftp.company.com)

  2. Update DNS record to point to Transfer Family endpoint

  3. Propagation happens within TTL window

  4. Old server remains available as rollback

Option B: IP Preservation (VPC with EIP)

  1. Allocate new Elastic IPs for Transfer Family

  2. Communicate new IPs to partners who allowlist

  3. Partners update firewall rules

  4. Switch traffic

Option C: Import Host Key (SFTP — minimize disruption)

  1. Export host key from existing server

  2. Import into Transfer Family: aws transfer import-host-key

  3. Partners won't see host key change warning

7.3 Cutover Day Procedure

TimeActionOwner
T-4hFinal sync of user dataAdmin
T-2hVerify all partners notifiedPM
T-1hLower DNS TTL confirmed (should be done 48h ago)Admin
T-0Update DNS / switch trafficAdmin
T+15mVerify first connections on new serverAdmin
T+30mMonitor for errors in CloudWatchAdmin
T+1hConfirm all active partners connected successfullyAdmin
T+4hDecision: proceed or rollbackTeam
T+24hDisable old server (keep for 7 days as rollback)Admin
T+7dDecommission old serverAdmin

7.4 Rollback Plan

If issues arise during cutover:

  1. Revert DNS to original server IP

  2. Or redirect traffic back via EIP reassociation

  3. Investigate issue on Transfer Family

  4. Schedule next cutover window

8. Post-Migration Operations

8.1 Monitoring Setup

CloudWatch Metrics to Monitor:

MetricAlarm ThresholdDescription
FilesInAnomaly detectionFiles received
FilesOutAnomaly detectionFiles sent
BytesInAnomaly detectionData received
BytesOutAnomaly detectionData sent
InboundMessage (AS2)= 0 for extended periodNo messages received

CloudWatch Logs:

• Enable structured logging on the Transfer Family server

• Set log retention policy (e.g., 30 days)

• Create metric filters for authentication failures

EventBridge Rules (Recommended):

• File upload completion → trigger downstream processing

• Authentication failure → alert security team

• AS2 MDN failure → alert operations team

8.2 Operational Procedures

ProcedureFrequencyOwner
User onboarding/offboardingAs neededAdmin
SSH key rotationPer security policy (90 days recommended)Admin
Certificate renewal (FTPS/AS2)Before expiryAdmin
Security policy reviewQuarterlySecurity
Access log reviewWeekly/MonthlySecurity
Capacity reviewMonthlyAdmin

8.3 Cost Optimization

• Enable S3 lifecycle policies to move old files to cheaper storage classes

• Review and right-size EFS throughput mode if using EFS

• Consider S3 Intelligent-Tiering for unpredictable access patterns

• Monitor and disable unused protocols on the server

9. Troubleshooting

9.1 Common Issues

IssuePossible CauseResolution
Connection refusedSecurity Group not allowing portVerify SG rules (22/21/5080)
Authentication failedWrong key format or expired credentialsVerify key format, check IdP logs
Host key changed (SFTP)New server has different host keyImport old host key or have partner accept new
Passive mode timeout (FTPS/FTP)Firewall blocking ports 8192-8200Update partner firewall rules
Permission denied on uploadIAM role missing s3:PutObjectReview user IAM role
Home directory not foundS3 prefix doesn't existCreate the prefix or use Logical directory
AS2 MDN failureCertificate mismatch or expiredVerify partner certificate in ACM
Slow transfersNetwork path or S3 throttlingCheck VPC routing, enable S3 Transfer Acceleration
Cannot list directoryMissing s3:ListBucket permissionAdd ListBucket to IAM role

9.2 Useful AWS CLI Commands


# List servers

aws transfer list-servers



# Describe server details

aws transfer describe-server --server-id s-111111111111



# Test identity provider

aws transfer test-identity-provider \

  --server-id s-111111111111 \

  --user-name testuser \

  --server-protocol SFTP



# List users

aws transfer list-users --server-id s-111111111111



# Check structured logging

aws transfer describe-server --server-id s-111111111111 \

  --query 'Server.StructuredLogDestinations'



# Import host key (SFTP)

aws transfer import-host-key \

  --server-id s-111111111111 \

  --host-key-body file://host_key_rsa



# Start AS2 file transfer

aws transfer start-file-transfer \

  --connector-id c-111111111111 \

  --send-file-paths /bucket/path/file.edi

9.3 Log Locations

Log TypeLocation
Transfer Family structured logsCloudWatch Logs: /aws/transfer/s-111111111111
Lambda IdP logsCloudWatch Logs: /aws/lambda/function-name
S3 access logsS3 bucket (if enabled)
CloudTrail API callsCloudTrail event history

10. CloudFormation / IaC Examples

10.1 SFTP Server — Public Endpoint (Service Managed)

Simplest deployment: public SFTP with SSH key authentication.


AWSTemplateFormatVersion: '2010-09-09'

Description: Transfer Family SFTP Server - Public Endpoint with Service Managed IdP



Parameters:

  SftpUserName:

    Type: String

    Default: partner-upload

    Description: SFTP username



  SftpPublicKey:

    Type: String

    Description: SSH public key (ssh-rsa format)



  BucketName:

    Type: String

    Description: S3 bucket for file storage



Resources:

  TransferBucket:

    Type: AWS::S3::Bucket

    Properties:

      BucketName: !Ref BucketName

      VersioningConfiguration:

        Status: Enabled



  TransferServer:

    Type: AWS::Transfer::Server

    Properties:

      EndpointType: PUBLIC

      IdentityProviderType: SERVICE_MANAGED

      Protocols:

        - SFTP

      LoggingRole: !GetAtt TransferLoggingRole.Arn

      StructuredLogDestinations:

        - !GetAtt TransferLogGroup.Arn



  TransferUser:

    Type: AWS::Transfer::User

    Properties:

      ServerId: !GetAtt TransferServer.ServerId

      UserName: !Ref SftpUserName

      Role: !GetAtt TransferUserRole.Arn

      HomeDirectoryType: LOGICAL

      HomeDirectoryMappings:

        - Entry: /

          Target: !Sub '/${BucketName}/home/${SftpUserName}'

      SshPublicKeys:

        - !Ref SftpPublicKey



  TransferUserRole:

    Type: AWS::IAM::Role

    Properties:

      AssumeRolePolicyDocument:

        Version: '2012-10-17'

        Statement:

          - Effect: Allow

            Principal:

              Service: transfer.amazonaws.com

            Action: sts:AssumeRole

      Policies:

        - PolicyName: S3Access

          PolicyDocument:

            Version: '2012-10-17'

            Statement:

              - Effect: Allow

                Action:

                  - s3:PutObject

                  - s3:GetObject

                  - s3:DeleteObject

                  - s3:GetObjectVersion

                Resource: !Sub 'arn:aws:s3:::${BucketName}/*'

              - Effect: Allow

                Action: s3:ListBucket

                Resource: !Sub 'arn:aws:s3:::${BucketName}'



  TransferLoggingRole:

    Type: AWS::IAM::Role

    Properties:

      AssumeRolePolicyDocument:

        Version: '2012-10-17'

        Statement:

          - Effect: Allow

            Principal:

              Service: transfer.amazonaws.com

            Action: sts:AssumeRole

      Policies:

        - PolicyName: CloudWatchLogs

          PolicyDocument:

            Version: '2012-10-17'

            Statement:

              - Effect: Allow

                Action:

                  - logs:CreateLogGroup

                  - logs:CreateLogStream

                  - logs:PutLogEvents

                  - logs:CreateLogDelivery

                  - logs:GetLogDelivery

                  - logs:UpdateLogDelivery

                  - logs:DeleteLogDelivery

                  - logs:ListLogDeliveries

                  - logs:DescribeLogGroups

                  - logs:DescribeResourcePolicies

                  - logs:PutResourcePolicy

                Resource: '*'



  TransferLogGroup:

    Type: AWS::Logs::LogGroup

    Properties:

      LogGroupName: !Sub '/aws/transfer/${AWS::StackName}'

      RetentionInDays: 30



Outputs:

  ServerEndpoint:

    Value: !Sub '${TransferServer.ServerId}.server.transfer.${AWS::Region}.amazonaws.com'

  ServerId:

    Value: !GetAtt TransferServer.ServerId

10.2 SFTP + FTPS Server — VPC with Internet Facing (Elastic IP)

Multi-protocol server with static IPs for partner allowlisting and custom Lambda IdP.


AWSTemplateFormatVersion: '2010-09-09'

Description: Transfer Family Multi-Protocol (SFTP+FTPS) - VPC Internet Facing with EIP



Parameters:

  VPCID:

    Type: AWS::EC2::VPC::Id

    Description: VPC for the Transfer Family server



  SubnetIDs:

    Type: List<AWS::EC2::Subnet::Id>

    Description: Subnets for the VPC endpoint (one per AZ)



  SecurityGroupID:

    Type: AWS::EC2::SecurityGroup::Id

    Description: Security Group allowing ports 22, 21, 8192-8200



  EIPAllocationID1:

    Type: String

    Description: Elastic IP Allocation ID for first subnet



  EIPAllocationID2:

    Type: String

    Description: Elastic IP Allocation ID for second subnet



  CertificateArn:

    Type: String

    Description: ACM certificate ARN for FTPS TLS



  BucketName:

    Type: String

    Description: S3 bucket for file storage



Resources:

  TransferBucket:

    Type: AWS::S3::Bucket

    Properties:

      BucketName: !Ref BucketName

      VersioningConfiguration:

        Status: Enabled



  TransferServer:

    Type: AWS::Transfer::Server

    Properties:

      EndpointType: VPC

      EndpointDetails:

        VpcId: !Ref VPCID

        SubnetIds: !Ref SubnetIDs

        SecurityGroupIds:

          - !Ref SecurityGroupID

        AddressAllocationIds:

          - !Ref EIPAllocationID1

          - !Ref EIPAllocationID2

      Protocols:

        - SFTP

        - FTPS

      Certificate: !Ref CertificateArn

      IdentityProviderType: AWS_LAMBDA

      IdentityProviderDetails:

        Function: !GetAtt IdPLambda.Arn

      LoggingRole: !GetAtt TransferLoggingRole.Arn

      StructuredLogDestinations:

        - !GetAtt TransferLogGroup.Arn

      SecurityPolicyName: TransferSecurityPolicy-2024-01



  IdPLambda:

    Type: AWS::Lambda::Function

    Properties:

      FunctionName: !Sub '${AWS::StackName}-idp'

      Runtime: python3.12

      Handler: index.lambda_handler

      Role: !GetAtt IdPLambdaRole.Arn

      Timeout: 30

      Environment:

        Variables:

          SECRETS_REGION: !Ref 'AWS::Region'

      Code:

        ZipFile: |

          import os

          import json

          import boto3



          region = os.environ['SECRETS_REGION']

          client = boto3.client('ssm', region_name=region)



          def lambda_handler(event, context):

              server_id = event.get('serverId')

              username = event.get('username')

              protocol = event.get('protocol')

              password = event.get('password', '')



              print(f"Auth request: user={username}, protocol={protocol}, server={server_id}")



              # Lookup user in Parameter Store

              param_name = f"/transfer/{server_id}/{username}"

              try:

                  resp = client.get_parameter(Name=param_name, WithDecryption=True)

                  user_config = json.loads(resp['Parameter']['Value'])

              except client.exceptions.ParameterNotFound:

                  print(f"User not found: {username}")

                  return {}



              # Password validation for FTPS/FTP

              if protocol in ('FTPS', 'FTP'):

                  stored_password = user_config.get(f'{protocol}Password', user_config.get('Password', ''))

                  if password != stored_password:

                      print("Password mismatch")

                      return {}



              # Build response

              response = {

                  "Role": user_config['Role'],

                  "HomeDirectoryType": user_config.get('HomeDirectoryType', 'LOGICAL'),

                  "HomeDirectoryDetails": user_config.get('HomeDirectoryDetails', '[]')

              }



              # Add SSH keys for SFTP

              if protocol == 'SFTP' and 'PublicKeys' in user_config:

                  response['PublicKeys'] = user_config['PublicKeys']



              return response



  IdPLambdaPermission:

    Type: AWS::Lambda::Permission

    Properties:

      Action: lambda:InvokeFunction

      FunctionName: !GetAtt IdPLambda.Arn

      Principal: transfer.amazonaws.com

      SourceArn: !GetAtt TransferServer.Arn



  IdPLambdaRole:

    Type: AWS::IAM::Role

    Properties:

      AssumeRolePolicyDocument:

        Version: '2012-10-17'

        Statement:

          - Effect: Allow

            Principal:

              Service: lambda.amazonaws.com

            Action: sts:AssumeRole

      ManagedPolicyArns:

        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

      Policies:

        - PolicyName: SSMAccess

          PolicyDocument:

            Version: '2012-10-17'

            Statement:

              - Effect: Allow

                Action:

                  - ssm:GetParameter

                Resource: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/transfer/*'



  TransferLoggingRole:

    Type: AWS::IAM::Role

    Properties:

      AssumeRolePolicyDocument:

        Version: '2012-10-17'

        Statement:

          - Effect: Allow

            Principal:

              Service: transfer.amazonaws.com

            Action: sts:AssumeRole

      Policies:

        - PolicyName: CloudWatchLogs

          PolicyDocument:

            Version: '2012-10-17'

            Statement:

              - Effect: Allow

                Action:

                  - logs:CreateLogGroup

                  - logs:CreateLogStream

                  - logs:PutLogEvents

                  - logs:CreateLogDelivery

                  - logs:GetLogDelivery

                  - logs:UpdateLogDelivery

                  - logs:DeleteLogDelivery

                  - logs:ListLogDeliveries

                  - logs:DescribeLogGroups

                  - logs:DescribeResourcePolicies

                  - logs:PutResourcePolicy

                Resource: '*'



  TransferLogGroup:

    Type: AWS::Logs::LogGroup

    Properties:

      LogGroupName: !Sub '/aws/transfer/${AWS::StackName}'

      RetentionInDays: 30



Outputs:

  ServerEndpoint:

    Value: !Sub '${TransferServer.ServerId}.server.transfer.${AWS::Region}.amazonaws.com'

  ServerId:

    Value: !GetAtt TransferServer.ServerId

  ElasticIPs:

    Description: Static IPs for partner allowlisting

    Value: !Sub 'EIP1: ${EIPAllocationID1}, EIP2: ${EIPAllocationID2}'

10.3 AS2 Server with Trading Partner Configuration


AWSTemplateFormatVersion: '2010-09-09'

Description: Transfer Family AS2 Server with Trading Partner Agreement



Parameters:

  VPCID:

    Type: AWS::EC2::VPC::Id



  SubnetIDs:

    Type: List<AWS::EC2::Subnet::Id>



  SecurityGroupID:

    Type: AWS::EC2::SecurityGroup::Id



  EIPAllocationID:

    Type: String

    Description: Elastic IP for AS2 inbound endpoint



  LocalAS2ID:

    Type: String

    Description: Your organization AS2 ID



  PartnerAS2ID:

    Type: String

    Description: Trading partner AS2 ID



  LocalCertificateArn:

    Type: String

    Description: ACM ARN for your signing/encryption certificate



  PartnerCertificateArn:

    Type: String

    Description: ACM ARN for partner public certificate



  InboundBucketName:

    Type: String

    Description: S3 bucket for received AS2 messages



Resources:

  InboundBucket:

    Type: AWS::S3::Bucket

    Properties:

      BucketName: !Ref InboundBucketName

      VersioningConfiguration:

        Status: Enabled



  AS2Server:

    Type: AWS::Transfer::Server

    Properties:

      EndpointType: VPC

      EndpointDetails:

        VpcId: !Ref VPCID

        SubnetIds: !Ref SubnetIDs

        SecurityGroupIds:

          - !Ref SecurityGroupID

        AddressAllocationIds:

          - !Ref EIPAllocationID

      Protocols:

        - AS2

      LoggingRole: !GetAtt AS2LoggingRole.Arn

      StructuredLogDestinations:

        - !GetAtt AS2LogGroup.Arn



  LocalProfile:

    Type: AWS::Transfer::Profile

    Properties:

      As2Id: !Ref LocalAS2ID

      ProfileType: LOCAL

      CertificateIds:

        - !Ref LocalCertificate



  PartnerProfile:

    Type: AWS::Transfer::Profile

    Properties:

      As2Id: !Ref PartnerAS2ID

      ProfileType: PARTNER

      CertificateIds:

        - !Ref PartnerCertificate



  LocalCertificate:

    Type: AWS::Transfer::Certificate

    Properties:

      Usage: SIGNING

      Certificate: !Ref LocalCertificateArn



  PartnerCertificate:

    Type: AWS::Transfer::Certificate

    Properties:

      Usage: ENCRYPTION

      Certificate: !Ref PartnerCertificateArn



  InboundAgreement:

    Type: AWS::Transfer::Agreement

    Properties:

      ServerId: !GetAtt AS2Server.ServerId

      LocalProfileId: !GetAtt LocalProfile.ProfileId

      PartnerProfileId: !GetAtt PartnerProfile.ProfileId

      BaseDirectory: !Sub '/${InboundBucketName}/inbound'

      AccessRole: !GetAtt AS2AccessRole.Arn

      Status: ACTIVE



  AS2AccessRole:

    Type: AWS::IAM::Role

    Properties:

      AssumeRolePolicyDocument:

        Version: '2012-10-17'

        Statement:

          - Effect: Allow

            Principal:

              Service: transfer.amazonaws.com

            Action: sts:AssumeRole

      Policies:

        - PolicyName: S3Access

          PolicyDocument:

            Version: '2012-10-17'

            Statement:

              - Effect: Allow

                Action:

                  - s3:PutObject

                  - s3:GetObject

                  - s3:GetObjectVersion

                Resource: !Sub 'arn:aws:s3:::${InboundBucketName}/*'

              - Effect: Allow

                Action: s3:ListBucket

                Resource: !Sub 'arn:aws:s3:::${InboundBucketName}'



  AS2LoggingRole:

    Type: AWS::IAM::Role

    Properties:

      AssumeRolePolicyDocument:

        Version: '2012-10-17'

        Statement:

          - Effect: Allow

            Principal:

              Service: transfer.amazonaws.com

            Action: sts:AssumeRole

      Policies:

        - PolicyName: CloudWatchLogs

          PolicyDocument:

            Version: '2012-10-17'

            Statement:

              - Effect: Allow

                Action:

                  - logs:CreateLogGroup

                  - logs:CreateLogStream

                  - logs:PutLogEvents

                  - logs:CreateLogDelivery

                  - logs:GetLogDelivery

                  - logs:UpdateLogDelivery

                  - logs:DeleteLogDelivery

                  - logs:ListLogDeliveries

                  - logs:DescribeLogGroups

                  - logs:DescribeResourcePolicies

                  - logs:PutResourcePolicy

                Resource: '*'



  AS2LogGroup:

    Type: AWS::Logs::LogGroup

    Properties:

      LogGroupName: !Sub '/aws/transfer/${AWS::StackName}-as2'

      RetentionInDays: 30



Outputs:

  AS2Endpoint:

    Description: AS2 inbound endpoint URL

    Value: !Sub 'https://${AS2Server.ServerId}.server.transfer.${AWS::Region}.amazonaws.com:5080'

  ServerId:

    Value: !GetAtt AS2Server.ServerId

10.4 Private VPC Server (Internal)

For internal file transfers over VPN or Direct Connect.


AWSTemplateFormatVersion: '2010-09-09'

Description: Transfer Family SFTP - Private VPC (internal access)



Parameters:

  VPCID:

    Type: AWS::EC2::VPC::Id



  SubnetIDs:

    Type: List<AWS::EC2::Subnet::Id>



  SecurityGroupID:

    Type: AWS::EC2::SecurityGroup::Id



  BucketName:

    Type: String



Resources:

  TransferBucket:

    Type: AWS::S3::Bucket

    Properties:

      BucketName: !Ref BucketName

      VersioningConfiguration:

        Status: Enabled



  TransferServer:

    Type: AWS::Transfer::Server

    Properties:

      EndpointType: VPC

      EndpointDetails:

        VpcId: !Ref VPCID

        SubnetIds: !Ref SubnetIDs

        SecurityGroupIds:

          - !Ref SecurityGroupID

      Protocols:

        - SFTP

      IdentityProviderType: SERVICE_MANAGED

      LoggingRole: !GetAtt TransferLoggingRole.Arn

      StructuredLogDestinations:

        - !GetAtt TransferLogGroup.Arn



  TransferLoggingRole:

    Type: AWS::IAM::Role

    Properties:

      AssumeRolePolicyDocument:

        Version: '2012-10-17'

        Statement:

          - Effect: Allow

            Principal:

              Service: transfer.amazonaws.com

            Action: sts:AssumeRole

      Policies:

        - PolicyName: CloudWatchLogs

          PolicyDocument:

            Version: '2012-10-17'

            Statement:

              - Effect: Allow

                Action:

                  - logs:CreateLogGroup

                  - logs:CreateLogStream

                  - logs:PutLogEvents

                  - logs:CreateLogDelivery

                  - logs:GetLogDelivery

                  - logs:UpdateLogDelivery

                  - logs:DeleteLogDelivery

                  - logs:ListLogDeliveries

                  - logs:DescribeLogGroups

                  - logs:DescribeResourcePolicies

                  - logs:PutResourcePolicy

                Resource: '*'



  TransferLogGroup:

    Type: AWS::Logs::LogGroup

    Properties:

      LogGroupName: !Sub '/aws/transfer/${AWS::StackName}'

      RetentionInDays: 30



Outputs:

  ServerId:

    Value: !GetAtt TransferServer.ServerId

  VPCEndpoint:

    Description: Connect via this VPC endpoint (accessible over VPN/DX)

    Value: !Sub '${TransferServer.ServerId}.server.transfer.${AWS::Region}.amazonaws.com'

10.5 EventBridge + Lambda Post-Upload Processing

Add this to any of the above templates to trigger automated processing when files arrive.


  # Add to Resources section of any Transfer Family template



  FileUploadRule:

    Type: AWS::Events::Rule

    Properties:

      Name: !Sub '${AWS::StackName}-file-upload'

      Description: Triggers processing when a file upload completes

      EventPattern:

        source:

          - aws.transfer

        detail-type:

          - "SFTP Server File Upload Completed"

        detail:

          server-id:

            - !GetAtt TransferServer.ServerId

      Targets:

        - Arn: !GetAtt ProcessingLambda.Arn

          Id: processing-lambda



  FileUploadLambdaPermission:

    Type: AWS::Lambda::Permission

    Properties:

      Action: lambda:InvokeFunction

      FunctionName: !GetAtt ProcessingLambda.Arn

      Principal: events.amazonaws.com

      SourceArn: !GetAtt FileUploadRule.Arn



  ProcessingLambda:

    Type: AWS::Lambda::Function

    Properties:

      FunctionName: !Sub '${AWS::StackName}-file-processor'

      Runtime: python3.12

      Handler: index.lambda_handler

      Role: !GetAtt ProcessingLambdaRole.Arn

      Timeout: 60

      Code:

        ZipFile: |

          import json

          import boto3

          import re



          s3 = boto3.client('s3')



          def lambda_handler(event, context):

              detail = event.get('detail', {})

              file_path = detail.get('file-path', '')

              username = detail.get('username', '')

              server_id = detail.get('server-id', '')



              print(f"File received: path={file_path}, user={username}, server={server_id}")



              # Parse S3 bucket and key from file-path

              # Format: /<bucket-name>/<key>

              match = re.match(r'^/([^/]+)/(.+)$', file_path)

              if not match:

                  print(f"Could not parse file path: {file_path}")

                  return {'statusCode': 400}



              bucket = match.group(1)

              key = match.group(2)



              print(f"Processing: bucket={bucket}, key={key}")



              # Add your processing logic here

              # Example: copy to processed folder, trigger workflow, notify, etc.



              return {'statusCode': 200, 'body': f'Processed {key}'}



  ProcessingLambdaRole:

    Type: AWS::IAM::Role

    Properties:

      AssumeRolePolicyDocument:

        Version: '2012-10-17'

        Statement:

          - Effect: Allow

            Principal:

              Service: lambda.amazonaws.com

            Action: sts:AssumeRole

      ManagedPolicyArns:

        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

      Policies:

        - PolicyName: S3Access

          PolicyDocument:

            Version: '2012-10-17'

            Statement:

              - Effect: Allow

                Action:

                  - s3:GetObject

                  - s3:PutObject

                  - s3:CopyObject

                Resource: !Sub 'arn:aws:s3:::${BucketName}/*'

10.6 Security Group Template (Reference)

Reusable Security Group for Transfer Family multi-protocol deployments.

TransferFamilySecurityGroup:

Type: AWS::EC2::SecurityGroup

Properties:

  GroupDescription: Security Group for AWS Transfer Family Server

  VpcId: !Ref VPCID

  SecurityGroupIngress:

    # SFTP

    - IpProtocol: tcp

      FromPort: 22

      ToPort: 22

      CidrIp: 0.0.0.0/0

      Description: SFTP access

    # FTP/FTPS control channel

    - IpProtocol: tcp

      FromPort: 21

      ToPort: 21

      CidrIp: 0.0.0.0/0

      Description: FTP/FTPS control channel

    # FTP/FTPS passive data channel

    - IpProtocol: tcp

      FromPort: 8192

      ToPort: 8200

      CidrIp: 0.0.0.0/0

      Description: FTP/FTPS passive data ports

    # AS2

    - IpProtocol: tcp

      FromPort: 5080

      ToPort: 5080

      CidrIp: 0.0.0.0/0

      Description: AS2 inbound messages

  Tags:

    - Key: Name

      Value: !Sub '${AWS::StackName}-transfer-sg'

Appendix A: Security Policy Comparison

Policy NameMin TLSUse Case
TransferSecurityPolicy-2024-01TLS 1.2Recommended default
TransferSecurityPolicy-2023-05TLS 1.2Previous default
TransferSecurityPolicy-FIPS-2024-01TLS 1.2FIPS compliance required
TransferSecurityPolicy-PQ-SSH-2023-04N/APost-quantum SSH

Appendix B: Supported Ciphers and Key Exchange Algorithms

Refer to the latest AWS documentation: https://docs.aws.amazon.com/transfer/latest/userguide/security-policies.html

Appendix C: Pricing Considerations

ComponentPricing Model
Server endpointPer hour (while enabled)
Data transfer (upload)Per GB
Data transfer (download)Per GB
AS2 messagesPer message
SFTP connectorsPer connector + per file

Tip: Stop the Transfer Family server during off-hours if transfers are batch-scheduled to reduce hourly costs. Use aws transfer stop-server and aws transfer start-server.

AWS
EXPERT

published 14 days ago57 views