AWS Storage Blog

Securing your AWS Transfer Family SFTP and FTPS VPC public endpoints

Customers who use the AWS Transfer Family service are typically exchanging files with their business partners over an internet facing endpoint. In doing so, they need to secure these public endpoints so that they are only accessible to known IP addresses and secured against dictionary attacks and port scanners. We previously walked you through how the AWS Transfer Family secures workloads through the use of Amazon Virtual Private Cloud (VPC) Security Groups attached to a VPC hosted endpoint in this blog post, and password authentication through the use of Amazon API Gateway, AWS Web Application Firewall, and AWS Secrets Manager in this blog post.

VPC security groups limit the number of IP addresses to 1,000 addresses that can be secured at once. If you need to secure more than 1,000 IP addresses, you can use AWS Network Firewall. AWS Network Firewall is a managed service that provides fine-grained network protections, scales automatically with your network traffic, and offers built-in redundancies designed to provide high availability. After updating your VPC routing configuration, the Network Firewall ensures that your traffic is inspected and then permitted or denied. Network Firewall also offers a flexible rules engine that gives you the ability to write tens of thousands of firewall rules for granular policy enforcement.

In this blog, I walk you through setting up an AWS Network Firewall within your VPC, and using it to protect your AWS Transfer Family’s VPC hosted SFTP and FTPS endpoints when you need to secure more than 1000 IP addresses. I cover the architectural components of this solution, how to set up the solution with step-by-step instructions, and how to test the solution to ensure that filtering works in your environment. With this solution, you can secure your SFTP and FTPS public endpoints and help ensure data security and privacy at scale. This enables you to avoid unwanted traffic, minimize risk to your file exchanges, and ultimately facilitate business resilience while you focus on your core competencies.

Architecture

In Figure 1, I show you the key components used to build a secure AWS Transfer Family SFTP server, and how to make it available to tens of thousands of SFTP clients over the internet. I utilize an Amazon VPC comprised of 3 firewall subnets and 3 protected subnets. The SFTP VPC hosted endpoints reside in the Protected Subnets and the AWS Network Firewall endpoints reside in the firewall subnets. I enable an Amazon Elastic Compute Cloud (Amazon EC2) Elastic IP (EIP) address for each internet facing SFTP endpoint. An Amazon Virtual Private Cloud internet gateway (IGW) is created to allow connectivity to and from the internet.

Note that an Amazon VPC security group is attached to the SFTP endpoints that allows 0.0.0.0/0 over port TCP/22. All inbound and outbound inspection and filtering occur on the AWS Network Firewall and no traffic is routed to the endpoints directly.

Figure 1-Traffic between the internet and VPC hosted Transfer Family SFTP endpoints protected by AWS Network Firewall
Figure 1: Traffic between the internet and VPC hosted Transfer Family SFTP endpoints protected by AWS Network Firewall

All SFTP client traffic originating from the internet is routed to the IGW Ingress Route Table. This route table manages all the public Amazon EIP and private Amazon VPC Elastic Network Interface mappings. At this stage, the IGW translates the destination public IP address of the SFTP endpoint to its private Amazon VPC elastic network interface address. The source IP address of SFTP client remains the same. The IGW Ingress Route table has a specific route to each firewall endpoint per Availability Zone (AZ). Traffic is then inspected by the AWS Network Firewall. If the source public IP address of the SFTP client is in the allowed list of IP addresses, it is permitted and routed to the Transfer Family server. The return packet from the AWS Transfer Family server is routed to the AWS Network Firewall endpoint for that Availability Zone to ensure synchronous traffic flows. From the AWS Network Firewall, egress traffic is routed to the AWS internet gateway for the reverse IP address translation.

Solution walkthrough 

The following solution walkthrough consists of three parts:

  1. Amazon VPC and AWS Transfer Family configuration
  2. AWS Network Firewall configuration
  3. Amazon VPC route table update

Amazon VPC and AWS Transfer Family configuration

I use the following AWS CloudFormation template to set up the base Amazon VPC configuration in Figure 1. Once created, I use the instructions available in this blog to create the SFTP VPC hosted endpoints. When configuring the SFTP VPC hosted endpoints, I place them into the protected subnets and associate them with an Amazon EIP.

#Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.

AWSTemplateFormatVersion: "2010-09-09"
Description: "AWS Transfer Family SFTP integration with AWS Network Firewall"

Resources:
  VPC:
    Type: "AWS::EC2::VPC"
    Properties:
      CidrBlock: "10.0.0.0/16"
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub "sftp-anfw-vpc"
  FirewallSubnet1:
    Type: "AWS::EC2::Subnet"
    Properties:
      CidrBlock: "10.0.0.0/24"
      MapPublicIpOnLaunch: false
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "Firewall Subnet AZ A"
      AvailabilityZone:
        Fn::Select:
          - "0"
          - Fn::GetAZs:
              Ref: "AWS::Region"
  FirewallSubnet2:
    Type: "AWS::EC2::Subnet"
    Properties:
      CidrBlock: "10.0.1.0/24"
      MapPublicIpOnLaunch: false
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "Firewall Subnet AZ B"
      AvailabilityZone:
        Fn::Select:
          - "1"
          - Fn::GetAZs:
              Ref: "AWS::Region"
  FirewallSubnet3:
    Type: "AWS::EC2::Subnet"
    Properties:
      CidrBlock: "10.0.2.0/24"
      MapPublicIpOnLaunch: false
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "Firewall Subnet AZ C"
      AvailabilityZone:
        Fn::Select:
          - "2"
          - Fn::GetAZs:
              Ref: "AWS::Region"
  SFTPSubnet1:
    Type: "AWS::EC2::Subnet"
    Properties:
      CidrBlock: "10.0.10.0/24"
      MapPublicIpOnLaunch: false
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "Protected Subnet AZ A"
      AvailabilityZone:
        Fn::Select:
          - "0"
          - Fn::GetAZs:
              Ref: "AWS::Region"
  SFTPSubnet2:
    Type: "AWS::EC2::Subnet"
    Properties:
      CidrBlock: "10.0.11.0/24"
      MapPublicIpOnLaunch: false
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "Protected Subnet AZ B"
      AvailabilityZone:
        Fn::Select:
          - "1"
          - Fn::GetAZs:
              Ref: "AWS::Region"
  SFTPSubnet3:
    Type: "AWS::EC2::Subnet"
    Properties:
      CidrBlock: "10.0.12.0/24"
      MapPublicIpOnLaunch: false
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "Protected Subnet AZ C"
      AvailabilityZone:
        Fn::Select:
          - "2"
          - Fn::GetAZs:
              Ref: "AWS::Region"
  FirewallRouteTable1:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "Firewall Route Table 1"
  FirewallRouteTable2:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "Firewall Route Table 2"
  FirewallRouteTable3:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "Firewall Route Table 3"
  RouteTableIGW1:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "IGW Ingress Route Table"
  RouteTableFirewallAssociation1:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId:
        Ref: "FirewallRouteTable1"
      SubnetId:
        Ref: "FirewallSubnet1"
  RouteTableFirewallAssociation2:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId:
        Ref: "FirewallRouteTable2"
      SubnetId:
        Ref: "FirewallSubnet2"
  RouteTableFirewallAssociation3:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId:
        Ref: "FirewallRouteTable3"
      SubnetId:
        Ref: "FirewallSubnet3"
  FirewallRouteTableRoute1:
    Type: "AWS::EC2::Route"
    Properties:
      DestinationCidrBlock: "0.0.0.0/0"
      RouteTableId:
        Ref: "FirewallRouteTable1"
      GatewayId:
        Ref: "Igw"
  FirewallRouteTableRoute2:
    Type: "AWS::EC2::Route"
    Properties:
      DestinationCidrBlock: "0.0.0.0/0"
      RouteTableId:
        Ref: "FirewallRouteTable2"
      GatewayId:
        Ref: "Igw"
  FirewallRouteTableRoute3:
    Type: "AWS::EC2::Route"
    Properties:
      DestinationCidrBlock: "0.0.0.0/0"
      RouteTableId:
        Ref: "FirewallRouteTable3"
      GatewayId:
        Ref: "Igw"
  SFTPRouteTable1:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "Protected Route Table A"
  SFTPRouteTableAssociation1:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId:
        Ref: "SFTPRouteTable1"
      SubnetId:
        Ref: "SFTPSubnet1"
  SFTPRouteTable2:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "Protected Route Table B"
  SFTPRouteTableAssociation2:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId:
        Ref: "SFTPRouteTable2"
      SubnetId:
        Ref: "SFTPSubnet2"
  SFTPRouteTable3:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: "Protected Route Table C"
  SFTPRouteTableAssociation3:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId:
        Ref: "SFTPRouteTable3"
      SubnetId:
        Ref: "SFTPSubnet3"
  Igw:
    Type: "AWS::EC2::InternetGateway"
    Properties: {}
  IGWAttachment:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      VpcId:
        Ref: "VPC"
      InternetGatewayId:
        Ref: "Igw"

AWS Network Firewall configuration

Navigate to the AWS Network Firewall console and choose Create Firewall. Then provide a Name for this resource, a Description, and select the VPC created. Select the Firewall subnets in each Availability Zone.

Figure 2- AWS Network Firewall Configuration - Details and Subnet Configurations

Figure 2: AWS Network Firewall Configuration – Details and Subnet Configurations

Next, under Associated firewall policy, choose Create and associate an empty firewall policy. Enter a new policy name and description and select Create firewall.

All packets that enter the firewall engine first enter the stateless engine and then sent to the stateful engine for further processing. For this exercise, I only utilize the stateless rule engine to process all traffic, and I do not send any traffic to the stateful engine. To ensure this, I update the stateless rule engine default actions. For a deeper explanation of the differences between stateful and stateless rule groups, you can refer to this blog.

Figure 3 - AWS Network Firewall - traffic inspection rules engines packet flow

Figure 3: AWS Network Firewall – traffic inspection rules engines packet flow

Under Firewall policies, select the policy that you created earlier. Then under Stateless default actions, select Edit. For Chose how to treat fragmented packets, select Use the same actions for all packets. Under Action, select Drop. To finish, choose Save.

Figure 4 - AWS Network Firewall - Stateless default actions

Figure 4: AWS Network Firewall – Stateless default actions

Next, under Stateless rule groups, select Add rule groups and then Create and add new stateless group.

Enter a name and description for your stateless rule group. AWS Network Firewall uses capacity settings to calculate and manage the processing requirements for its rules groups and firewall policies. Each rule group must have a capacity setting that’s fixed at creation. For more information on capacity calculations, you can refer to our documentation here. For this exercise, I enter a capacity of 100. I utilize the 5-tuple rule group option to define the source, destination IP addresses, ports, and the action to take.

In the next section, I specify the Priority, Protocol, Source IP address, Source port rang, the Destination IP address, Destination Address, and Actions. The Priority number indicates the processing order of the stateless rule within the rule group. This must be unique within the stateless rule group and it must be a positive integer. Network Firewall processes the rules starting from the lowest numbered priority setting. When you plan the rules in your rule group, provide priority settings with space in between so that you leave yourself room to add rules later. For example, you might start by using priority settings that are multiples of 10 to allow for capacity to add more rules.

The SFTP protocol typically runs over TCP port 22 so I select TCP for the protocol. The source IP address is the public IP address of the SFTP client attempting to connect to your SFTP server. The destination IP address is the private address of the SFTP VPC elastic network interface.

Figure 5 - AWS Network Firewall - New stateless rule creationFigure 5: AWS Network Firewall – New stateless rule creation

You can get a list of all the private VPC elastic network interfaces under the AWS Transfer Family SFTP Server Endpoint configuration. Add a new rule for each VPC elastic network interface IP address.

The AWS Network Firewall stateless rules engine examines each packet in isolation. I added rules to allow traffic from the SFTP clients to the SFTP servers. Now, I add a rule to allow the return traffic from the SFTP servers to the SFTP clients. The source IP address is 10.0.0.0/16 (VPC CIDR), and the destination IP address is 0.0.0.0/0 (all SFTP clients). If new SFTP client IP addresses need to be added, you add new rules within the existing stateless rule group.

Figure 6 - AWS Network Firewall - Example Rules

Figure 6: AWS Network Firewall – Example Rules

Amazon VPC route table update

Now that I have the AWS Transfer Family SFTP server and AWS Network Firewall configured, I need to configure the Amazon VPC route tables to allow traffic to be sent to the AWS Network Firewall for inspection. First, I update the IGW Ingress route table. Under VPC and Route Tables, select the IGW ingress route table. Select the Edge association tab and choose Edit edge associations. Select the Internet gateway and click Save changes.

Figure 7 - Amazon VPC Route Table Edge association update

Figure 7: Amazon VPC Route Table Edge association update

The next step is to send all traffic originating from the internet to the AWS Network Firewall. In this step, I update the IGW Ingress route table to point each individual Protected subnet IP address range to the Availability Zones specific AWS Network Firewall endpoint. You can find a list of the AWS Network Firewall Availability Zones and subsequent endpoints in the Firewall details section.

For this example, in the IGW Ingress Route Table, I point the 10.0.10.0/24 network that belongs to Protected Subnet A, to the firewall endpoint in Availability Zone A. I do the same for the other two Protected subnet IP address ranges.

Figure 8 - IGW Ingress route table updates
Figure 8: IGW Ingress route table updates

Next, for each protected route table, I add a route to the Availability Zone specific AWS Network Firewall endpoint to ensure that traffic is routed symmetrically back to the specific Availability Zone endpoint.

I add the 0.0.0.0/0 route and point it to the firewall endpoint and save the changes. I do the same for the other two protected subnet route tables.

Figure 9 - Protected subnet route table updates

Figure 9: Protected subnet route table updates

Testing

You can easily test access to your AWS Transfer Family SFTP server either via your terminal on Linux or macOS systems, or by using a third-party tool such as Cyberduck, WinSCP, or Filezilla. Before attempting to connect to the server, you must first return to the AWS Transfer Family Management Console page for your server to create a user account.

Note that my example uses a service-managed identity provider for the SFTP server, which authenticates users using SSH keys. Instructions on how to generate SSH keys can be found here. AWS Transfer Family for SFTP also supports custom authentication methods, which allows you to do password authentication, as well as authentication via third party providers.

To validate access, I run a netcat command from a test instance from an approved IP address. I can see that we have connected to the SFTP endpoint successfully.

sh-4.2$ nc -v s-6869a18c94ee43f7b.server.transfer.us-east-1.amazonaws.com 22
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Connected to 44.195.199.186:22.
SSH-2.0-AWS_SFTP_1.0
sh-4.2$

Now I run the same test from a test instance that does not have an approved IP address and I can see that the connection fails.

sh-4.2$ nc -v s-6869a18c94ee43f7b.server.transfer.us-east-1.amazonaws.com 22
sh-4.2$

Logging 

You can configure logging on the AWS Network Firewall to provide detailed information about network traffic. The logs are published to the configured log destination, where you can retrieve and view them. For this exercise, I configured my logs to be sent to an Amazon CloudWatch Log Group.

Figure 10 - AWS Network Firewall Configuration - Logging options

Figure 10: AWS Network Firewall Configuration – Logging options

Here is an example of flow log that shows a failed connection through the AWS Network Firewall. I can see that only a single packet of type "syn": true was processed by the firewall.

{
    "firewall_name": "sftp-anfw-demo",
    "availability_zone": "us-east-1b",
    "event_timestamp": "1627913953",
    "event": {
        "timestamp": "2021-08-02T14:19:13.000068+0000",
        "flow_id": 2010551477827788,
        "event_type": "netflow",
        "src_ip": "162.142.125.150",
        "src_port": 24618,
        "dest_ip": "10.0.11.227",
        "dest_port": 12115,
        "proto": "TCP",
        "netflow": {
            "pkts": 1,
            "bytes": 44,
            "start": "2021-08-02T14:18:11.489676+0000",
            "end": "2021-08-02T14:18:11.489676+0000",
            "age": 0,
            "min_ttl": 32,
            "max_ttl": 32
        },
        "tcp": {
            "tcp_flags": "02",
            "syn": true
        }
    }
}

Now, here is an example of a flow log from an approved IP address. I can see the full three-way handshake between the SFTP client (25.173.191.12) and the Transfer Family server (10.0.11.227).

{
    "firewall_name": "sftp-anfw-demo",
    "availability_zone": "us-east-1b",
    "event_timestamp": "1627913467",
    "event": {
        "timestamp": "2021-08-02T14:11:07.000211+0000",
        "flow_id": 1424679208782992,
        "event_type": "netflow",
        "src_ip": "10.0.11.227",
        "src_port": 22,
        "dest_ip": "35.173.191.12",
        "dest_port": 37762,
        "proto": "TCP",
        "app_proto": "ssh",
        "netflow": {
            "pkts": 13,
            "bytes": 904,
            "start": "2021-08-02T13:59:04.429200+0000",
            "end": "2021-08-02T14:01:04.436421+0000",
            "age": 120,
            "min_ttl": 251,
            "max_ttl": 251
        },
        "tcp": {
            "tcp_flags": "1b",
            "syn": true,
            "fin": true,
            "psh": true,
            "ack": true
        }
    }
}

Monitoring metrics

You can monitor AWS Network Firewall metrics through Amazon CloudWatch, which automatically collects raw data and processes it into readable, near real-time metrics. You are able to view the DroppedPacks, Passed Packets, and ReceivedPacketCount metrics. These metrics are found in the firewall portal under the Monitoring section.

Figure 11 - AWS Network Firewall Monitoring metrics

Figure 11: AWS Network Firewall Monitoring metrics

Cleaning up

To avoid ongoing charges for the resources you created, you should delete the CloudFormation template, the EC2 EIPs used for the SFTP servers, the AWS Transfer family SFTP server, and the AWS Network Firewall.

Conclusion

In this blog post, I covered easily deploying an AWS Network Firewall to secure AWS Transfer Family VPC internet endpoints when you need to secure more than 1000 IP addresses. With AWS Network Firewall’s flexible rules engine, I demonstrated defining firewall rules that give you fine-grained control over network traffic from the internet. The AWS Network Firewall also scales automatically with your network traffic, so you don’t worry about deploying and managing any infrastructure.

Try this solution today, and let us know what you think!

Thank you for reading this blog post, please leave a comment if you have any questions. To learn more about AWS Network Firewall, check out the following resources: