Configuring your FTPS server behind a firewall or NAT with AWS Transfer Family
AWS customers sometimes host AWS Transfer Family endpoints in network address translation (NAT) architectures. One common reason to host the AWS Transfer endpoint behind a NAT is to protect the server with a firewall offered by an AWS Marketplace partner. With the SFTP protocols, there are generally no major issues with using NAT architectures and AWS Transfer Family server endpoints. However, you may experience issues when using the FTPS protocol with NAT architecture in two common instances. First is when your Transfer Family endpoints are hosted on internal IPs that NAT to an external IP. Second is when your Transfer Family endpoints are hosted on alternative internal IP addresses commonly used for VPN connections that span across VPCs or VPC connected on-premises environments.
When a session is initiated in NAT architectures for FTPS, the initial response from the AWS Transfer Family server will contain a Passive IP (PASV) response. This response includes the internal IP behind which the AWS Transfer server is hosted. Subsequent responses from the FTPS client software may attempt to direct data down the data path via this internal IP, which you are often unable to route.
This means that the FTPS client software will successfully authenticate, but then be unable to exchange data with the server. To demonstrate this type of error, I’ve provided an example of trying to list a folder via FTPS to a VPC hosted endpoint that is only accessible through a private IP fronted by an Elastic IP address attached to a Network Load Balancer (NLB) with the LFTP client. An NLB is an AWS tool that distributes end-user traffic across multiple cloud resources.
In the example, my AWS Transfer endpoint is able to be reached over the public internet via the NLB, and the PASV response directs data to the internal IPv4 address of the endpoint. My client has no route to that internal network, and my connection times out. As a result, my attempt to list the folder will fail.
In order to improve FTPS client software support for these architectures, AWS Transfer Family recently launched the ability to configure a PASV response address for an AWS Transfer server. This new feature allows customers to specify the external IP in the NAT relationship as the PASV response, which will broaden support for affected clients.
In this blog post, I show how to configure a PASV response using the new feature in an architecture that includes a NAT. I also highlight a use case in which a customer hosts an AWS Transfer Family server endpoint with FTPS support behind an NLB. To start off, I discuss the basics of our architecture based on a common deployment scenario. Next, I walk through how to configure this architecture in detail. Finally, I walk through how to test that the architecture is functioning properly.
The following diagram shows the key components that are used to host an AWS Transfer Family server endpoint in a common NAT scenario. In this architecture, the AWS NLB is being used simply to provide a single specific external IP for client access. End users use FTPS client software to access the endpoint using the public Ipv4 Elastic IP address. The Elastic IP address is hosted by the AWS NLB, which redirects inbound traffic to the internal IP representing an AWS Transfer Family server’s VPC hosted endpoint.
Figure 1 – Configuring PASV for AWS Transfer Family servers in NAT architectures
When you create your server, you select the VPC you want to host it in. This VPC is where you host the AWS NLB with the Elastic IP address you want to front your server. The Elastic IP address should be configured as the PASV response address, using the new Transfer Family PASV feature, in order to successfully transfer data.
In the next section, I’ll walk you through some prerequisites if you’d like to work alongside this post to deploy a similar architecture.
When configuring AWS Transfer Family servers with endpoints hosted inside a VPC, you want to start with a VPC that has at least one available Elastic IP address. If you would like to work along with this post, download the AWS CloudFormation template AWS Transfer Family [sftp-workshop.yaml] to get started. The template deploys a VPC environment similar to the example architecture show in the preceding screenshot, including allocating Elastic IPs, a VPC, subnets, and an internet gateway. Additionally, this template creates an Amazon S3 bucket, an IAM role, and a policy to provide you access to this bucket for testing. You can deploy this template from the AWS CloudFormation console.
Once the CloudFormation template is deployed successfully, you see the following information on the outputs tab:
This information in outputs, specifically in the Value column, is useful in later steps. I recommend making a quick note or keeping this output view open in a separate browser tab for later reference.
Next, from the AWS Transfer Family console, choose Create server. On Step 1, Choose protocols, uncheck SFTP, and check FTPS. Select a Server certificate from the AWS Certificate Manager (ACM) picklist. If you don’t have any configured certificates, documentation explaining how to create one can be found here. Once you have selected an ACM certificate, choose the Next button.
For the remaining steps, access detailed documentation on deploying an AWS Transfer Family FTPS server here. For the purposes of aligning with the remaining steps in this post, make sure to deploy your AWS Transfer Family server endpoint in the VPC you created earlier with the Access type set to Internal, and one of your CloudFormation created Subnet IDs selected in Step 3, Choose an endpoint.
Once your AWS Transfer Family server is Online, choose the Server ID link. Scroll down to the Endpoint configuration section, and make a note of the Private IPv4 Address. This is needed in the next step.
In the next section, I’ll walk you through how to configure the new PASV feature in detail.
At this stage, you have an AWS Transfer Family server endpoint deployed in your VPC created with the CloudFormation template and hosted behind an internal IP address. To illustrate the NAT use case, bind a single, static, external IP address for this server. To do so, deploy Elastic Load Balancing (ELB), or in this case specifically a Network Load Balancer (NLB), which I will walk through in detail.
From the Amazon EC2 Console, in the Load Balancing section from the left menu, select Target Groups. Choose Create target group.
On the Specify group details page, choose IP addresses, and supply a Target group name. From the Protocol drop-down, select TCP, and for Port enter 21. Under the drop-down for VPC, select the VPC created by your CloudFormation template.
In the Health checks section, make sure that TCP is selected for health check protocol, and expand Advanced health check settings. Select Override, and again supply port 21 in place of port 80, then choose Next.
On the Register targets page supply the Private IPv4 address of your AWS Transfer Family server. Choose Include as pending below, then select Create target group.
Repeat the previous action nine additional times for each of the data channel ports used for FTPS with AWS Transfer Family, TCP ports 8192-8200. I recommend using a naming convention that makes it easy to differentiate the target group vs. the TCP port supported. When complete, you have a total of 10 target groups.
At this point, you are ready to create your Network Load Balancer and associate the target groups. From the EC2 console, in the Load Balancing menu, select Load Balancers. Choose Create Load Balancer. From the Network Load Balancer section, choose Create. In the Basic configuration section, supply a name under load balancer name. Make sure Internet-facing and IPv4 are selected.
In the Network mapping section, select the VPC created by your CloudFormation template. Under Mappings check the box next to the Availability Zone you chose to deploy your AWS Transfer Family server into. Then select the appropriate Subnet. Under IPv4 settings, you have the choice of either allowing AWS to assign an external IP, or selecting one of the Elastic IPs allocated by your CloudFormation template. Selecting Use an Elastic IP address allows you to choose a single static IP address to front your AWS Transfer Family server.
In the Listeners and routing section, with the Protocol set to TCP, input 21 for Port, and for Default action select the appropriate Target group you configured for port 21 in the Target group console. Choose Add listener. Repeat this step for ports 8192-8200 as well. Once all of your listeners are configured, choose Create load balancer. Your Network Load Balancer is created, but in order to successfully send traffic to your AWS Transfer Family server, you must perform one additional step. Since your AWS Transfer server uses a VPC hosted endpoint, the security group associated with your endpoint must be updated to allow the NLB internal IP address to reach the server and relay traffic.
From the EC2 console, in the Network & Security menu, select Network interfaces. Find the appropriate Network interface ID in the list. The Interface type will be network_load_balancer, and the Description will reflect the name you chose for your Network Load Balancer. Check the box. In the Details section, look for the Private IPv4 address, and make a note of it.
Again in the Network & Security menu, select Security Groups. Choose the Security group ID listed for the VPC ID created by your CloudFormation template. From the Inbound rules tab, choose Edit inbound rules. Choose Add rule. For the Type, select Custom TCP. Protocol will be TCP, and Port range will be 21. For Source, select Custom, and input the Private IPv4 address of your NLB, along with a /32 to limit the rule to one IP. Repeat this process, and for the second rule all settings can be the same, but for Port range input 8192 – 8200. Choose Save rules.
With these rules in place your target groups should all show a status of Healthy. This means your NLB is ready to relay traffic to your AWS Transfer Family server endpoint, but clients that respect the PASV response will still be receiving the Internal IPv4 associated with the endpoint. To correct this, you need to take advantage of our newly launched feature, and configure a PASV response for the server. To set the PASV response, execute the following command using the AWS Command Line Interface (CLI):
>/aws transfer update-server --server-id <serverID of your server> --protocol-details PassiveIp=<Elastic IP of your NLB>
Once you have set this value, find a time to stop and start your AWS Transfer Family server. After a restart of the AWS Transfer server, subsequent connections will receive the updated PASV response, which will direct data connections to the Elastic IP address of the NLB. This means that client connections are now able to successfully connect on the data path.
To clean up the resources you created as part of this post, first delete the Network Load Balancer. Once this step is completed, proceed to deleting the target groups and then the AWS Transfer Family server. Finally, delete the AWS CloudFormation stack that you deployed earlier. Take these steps to ensures you avoid additional costs from your test environment created while following along with this post.
Trade-offs to consider
Setting the PASV response enables clients that respect this response to continue to successfully transmit data via the data channel without error. It should be noted, however, that there are some tradeoffs that come with operating in these architectures. Being behind a single Elastic IP address means that the solution in effect becomes available in a single Availability Zone. By default, Transfer Family servers are highly available across up to three Availability Zones. Since this solution only relies on one Availability Zone, you might want to consider if it is appropriate for mission critical workloads. If your workload is highly sensitive to disruptions, consider an alternative solution that offers high availability across multiple Availability Zones. An AWS Transfer Family server can only support a single manually configured PASV address.
An additional limitation with this approach involves logging. AWS Transfer Family servers log the details of each user interaction to CloudWatch, including logging each connecting user’s source IP address. When relaying data to AWS Transfer Family servers via an NLB, the source IP associated with each user session logged will always show the IP of the NLB or firewall when using a NAT translation. For these reasons, we always encourage customers to consider using an IP allow list with an Internet-facing VPC hosted endpoint as an alternative to using a firewall that requires a NAT in front of their server.
In this blog, I’ve demonstrated how to deploy an AWS Transfer Family server hosted behind a Network Load Balancer, and how to set up a PASV response when using Transfer Family servers in situations that require NAT translation.
There can be a number of reasons to choose to deploy a NAT solution with AWS Transfer Family, including deploying an AWS Transfer Family server behind a third-party firewall solution available on the AWS Marketplace. Using this new feature allows for greater client software compatibility when using AWS Transfer Family server endpoints with FTPS in these types of architectures. Considering the trade-offs from the preceding section, you may require an architecture that uses a NAT with AWS Transfer Family. Feel free to try this feature in your own account.
Thanks for reading this blog post! If you have any questions on updating your PASV response address, don’t hesitate to leave a comment in the comments section.