DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Understanding Custom Authorization Mechanisms in Amazon API Gateway and AWS AppSync
  • AWS Agentic AI for App Portfolio Modernization
  • Effective Strategies for AWS Cost Optimization
  • Building Cost-Effective Internet Scale Applications

Trending

  • Fast Data Access Using GemFire and Apache Spark (Part 1): Introduction
  • When Similarity Isn’t Accuracy in GenAI: Vector RAG vs GraphRAG
  • Hands-On With Kubernetes 1.35
  • 8 Core LLM Development Skills Every Enterprise AI Team Must Master
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. AWS Transfer Family SFTP Setup (Password + SSH Key Users) Using Lambda Identity Provider + S3

AWS Transfer Family SFTP Setup (Password + SSH Key Users) Using Lambda Identity Provider + S3

Deploy a managed AWS Transfer Family SFTP server backed by S3, using a Lambda identity provider for password and SSH-key logins.

By 
Praveen Chaitanya Jakku user avatar
Praveen Chaitanya Jakku
·
Mar. 04, 26 · Tutorial
Likes (0)
Comment
Save
Tweet
Share
3.2K Views

Join the DZone community and get the full member experience.

Join For Free

Introduction

Even though modern application integrations often use REST APIs, messaging platforms, and event streams, SFTP remains one of the most widely used file-transfer standards in enterprise environments. Many organizations still rely on secure file exchange workflows for batch processing daily reports, data exports/imports, financial reconciliation files, healthcare data transfers, compliance-driven integrations, or vendor-delivered archives.

The problem is that running your own SFTP server is operationally expensive. A traditional setup usually means deploying an EC2 instance with OpenSSH, attaching storage, setting up users with strict directory isolation (chroot), configuring permissions, rotating keys, patching the OS frequently, and dealing with scalability or high availability. It works, but it introduces long-term maintenance overhead and security risk especially if the SFTP endpoint is exposed publicly.

AWS Transfer Family is a managed service designed to eliminate that burden. It provides a managed SFTP endpoint that can write directly to Amazon S3 (or Amazon EFS). No servers to patch, no disk management, and no manual HA design.

In this tutorial, we’ll build a production-ready AWS Transfer Family SFTP server backed by S3, using a Lambda Identity Provider to support both:

  • User 1: Username + Password authentication
  • User 2: Username + SSH public key authentication

We’ll also cover how to deploy this server as either:

  • an internet-facing (public) endpoint, or
  • a private (VPC-hosted/internal) endpoint (recommended for enterprises)

Overview: What You’ll Build

By the end of this tutorial, you’ll have a working system that includes:

✅ An S3 bucket used as the file store
✅ An IAM role granting Transfer Family least-privilege access to S3
✅ A Lambda function that authenticates users and returns session details
✅ A Transfer Family server configured with SFTP + Lambda + S3
✅ Two different user authentication methods in the same server
✅ Working upload/download testing commands (password + key)

This design is ideal for organizations that want a managed SFTP solution that can scale while enforcing clean access boundaries.

Why Use Lambda as the Identity Provider?

AWS Transfer Family supports “service-managed users” created directly in the console. That’s fine for small deployments, but in many real cases you need more flexibility:

  • You may want password authentication for app integrations
  • You may want SSH key authentication for admins or automated secure transfers
  • You may want to control home directories dynamically
  • You may want centralized logic to later integrate with:

    • AWS Secrets Manager for credentials
    • DynamoDB for user directory tables
    • external identity systems (custom API/LDAP-like patterns)

Lambda turns Transfer Family into a programmable authentication gateway instead of a static list of users.

Architecture

At a high level, the workflow looks like this:

Workflow Diagram

Implementation Ste

Step 1 — Create an S3 Bucket

Create a bucket that will store all SFTP files.

Example:

  • Bucket name: my-sftp-bucket

Optional (recommended) prefixes:

  • home/password-user/
  • home/key-user/

CLI:

Plain Text
 
aws s3api put-object --bucket my-sftp-bucket --key home/password-user/ aws s3api put-object --bucket my-sftp-bucket --key home/key-user/


Note: S3 doesn’t require folders to exist ahead of time, but pre-creating prefixes helps keep storage organized.

Step 2 — Create IAM Role for Transfer Family

Create an IAM role that Transfer Family will assume in order to access S3.

  • Role name: TransferFamilyS3AccessRole

Trust Policy (Who can assume this role?)

JSON
 
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowTransferFamilyAssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": "transfer.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}


Permissions Policy (Least privilege to S3 per user)

This policy restricts users to only their own home prefix:

JSON
 
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListUserHome",
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": "arn:aws:s3:::my-sftp-bucket",
      "Condition": {
        "StringLike": {
          "s3:prefix": [
            "home/${transfer:UserName}",
            "home/${transfer:UserName}/*"
          ]
        }
      }
    },
    {
      "Sid": "UserHomeRW",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::my-sftp-bucket/home/${transfer:UserName}/*"
    }
  ]
}


Copy the role ARN (you’ll reference it in Lambda):

Plain Text
 
arn:aws:iam::<YOUR_ACCOUNT_ID>:role/TransferFamilyS3AccessRole


Step 3 — Generate SSH Key Pair for Key User

On your client host (Linux/WorkSpaces/Bastion):

Shell
 
mkdir -p ~/sftp-keys && cd ~/sftp-keys ssh-keygen -t rsa -b 4096 -f sftp_key_user -N ""
chmod 600 sftp_key_user

Files created:

  • sftp_key_user (private key)
  • sftp_key_user.pub (public key)

View the public key:

Shell
 
cat sftp_key_user.pub


Step 4 — Create Lambda Identity Provider

Create a Lambda function:

  • Name: transfer-family-auth-handler
  • Runtime: Python 3.x

Paste this code (clean and production-friendly baseline):

Python
 
import json

S3_BUCKET = "my-sftp-bucket"
ROLE_ARN = "arn:aws:iam::<YOUR_ACCOUNT_ID>:role/TransferFamilyS3AccessRole"

KEY_USER = "key-user"
PASSWORD_USER = "password-user"
PASSWORD_USER_PASSWORD = "ChangeMeStrongPassword@123"

KEY_USER_PUBLIC_KEY = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD..."

def lambda_handler(event, context):
    username = event.get("username")
    password = event.get("password", "")

    if not username:
        return {}

    # Important: target path should not have a trailing slash
    home_target = f"/{S3_BUCKET}/home/{username}"

    resp = {
        "Role": ROLE_ARN,
        "HomeDirectoryType": "LOGICAL",
        "HomeDirectoryDetails": json.dumps([
            {"Entry": "/", "Target": home_target}
        ])
    }

    if username == KEY_USER:
        resp["PublicKeys"] = [KEY_USER_PUBLIC_KEY]
        return resp

    if username == PASSWORD_USER:
        if password == PASSWORD_USER_PASSWORD:
            return resp
        return {}

    return {}


Step 5 — Create AWS Transfer Family Server

Go to:
AWS Transfer Family → Create server

Select:

  • Protocol: ✅ SFTP
  • Domain: ✅ Amazon S3
  • Identity provider: ✅ AWS Lambda
  • Lambda function: ✅ transfer-family-auth-handler

Step 6 — Choose Endpoint Type (Public vs Private)

Option A — Public Endpoint (Internet Facing)

Use this if external vendors/clients need access.

AWS provides hostname:

Plain Text
 
s-xxxx.server.transfer.<region>.amazonaws.com


Security recommendation:

  • Restrict inbound port 22 to known IPs only.

Option B — Private Endpoint (VPC Hosted)

Use this for internal apps and enterprise workloads.

Benefits:

  • No internet exposure
  • Controlled access through VPC routing
  • Easy integration with private systems (EKS, EC2, WorkSpaces)

Cross-account/VPC access is supported using:

  • VPC peering or Transit Gateway
  • route table updates
  • security group rules

Step 7 — Allow Transfer Family to Invoke Lambda

After the server is created, note server ID:

Plain Text
 
s-xxxxxxxxxxxxxxxxx


Grant invoke permission:

JSON
 
aws lambda add-permission \
  --region <REGION> \
  --function-name transfer-family-auth-handler \
  --statement-id AllowTransferFamilyInvoke \
  --action lambda:InvokeFunction \
  --principal transfer.amazonaws.com \
  --source-arn arn:aws:transfer:<REGION>:<YOUR_ACCOUNT_ID>:server/s-xxxxxxxxxxxxxxxxx


Testing & Validation

Connectivity Test

Shell
 
nc -vz <SFTP_HOST> 22


Password User Test

Shell
 
sftp password-user@<SFTP_HOST>


Test upload/download:

Shell
 
pwd ls put /etc/hosts test-upload.txt get test-upload.txt /tmp/test-upload.txt exit


Key User Test

Shell
 
sftp -i ./sftp_key_user -o IdentitiesOnly=yes key-user@<SFTP_HOST>


Upload test:

Shell
 
pwd ls put /etc/hosts key-upload.txt exit


What does -o IdentitiesOnly=yes do?

It forces the SSH client to use only the key you specify, instead of trying any other local keys first. This prevents confusing authentication failures when multiple SSH keys exist on the system.

Application Remote Path Configuration

When you run:

Shell
 
pwd


You’ll see:

Shell
 
/


This is a virtual root, mapped to:

Shell
 
s3://my-sftp-bucket/home/<username>/


So your application should use:

  • / as the base path
    or subfolders like:
  • /incoming
  • /outgoing

Common Pitfalls and Fixes

  • Lambda not invoked: missing Lambda permission (add-permission)
  • Key auth prompts password: missing IdentitiesOnly=yes or wrong public key
  • Uploads fail: IAM policy missing PutObject
  • Public endpoint too open: SG not restricted to known IPs
  • Private endpoint unreachable: missing routes / SG / peering DNS settings

Cost Considerations

AWS Transfer Family is billed based on:

  • endpoint uptime (per-hour server cost)
  • data transferred (per-GB)
    CloudWatch logs also incur small charges depending on verbosity. Lambda cost is generally negligible in this setup because it only runs on authentication events.

Conclusion

AWS Transfer Family provides a clean, scalable way to run SFTP without managing servers. By combining S3 storage with a Lambda identity provider, you can support both password and SSH key authentication and enforce strong per-user directory isolation. This approach works for public vendor access as well as internal enterprise integrations making it a strong fit for real-world cloud modernization initiatives.

AWS AWS Lambda Transfer (computing)

Opinions expressed by DZone contributors are their own.

Related

  • Understanding Custom Authorization Mechanisms in Amazon API Gateway and AWS AppSync
  • AWS Agentic AI for App Portfolio Modernization
  • Effective Strategies for AWS Cost Optimization
  • Building Cost-Effective Internet Scale Applications

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook