Legacy with Modern integration: secure and on-budget

It’s 2026, and if you’re in IT you probably have “Just do AI!!” fatigue. At the same time, your banking app is probably connected to a system written in a programming language from the 1960s. Yes, IT is changing at lightning speed yet legacy is still a thing. We all know that one black box no one should touch, yet somehow it still needs to keep running for everything else to still work. Today we are going to look at a common enterprise pattern in connecting such legacy systems to modern infrastructure.

The problem

We had a client recently request that we design a system that will handle file transfer to an S3 bucket via FTP from a few hundred global wholesale customers with some using legacy systems. This was an interesting security problem as we were also told these customers do not typically use anything sophisticated like asymmetric SSH keys and would instead use plain text passwords. They do not all have a VPN, and do not have a predictable IP address range that we can whitelist, so the system must be open to the world. This would certainly make a weak or stolen password a single point of failure for the whole system's security. We would like to share how we designed a secure, scalable and cost-optimised solution given the situation that a bad actor got their hands on a customer's password

When integrating a legacy system with a modern system such as an event-driven workflow or even AI training datasets; AWS’ transfer family server seems to fit the bill. To discuss why, let’s side-track a bit to quickly introduce what FTP, SSH and AWS S3 are.

FTP (File Transfer Protocol) and SSH (Secure Shell) are protocols practically available to every OS and application it runs on, whether it’s the latest MacOS or even those ancient banking applications running on COBOL. The fact that SFTP is so accessible across legacy and modern systems, makes it a very common integration protocol.

AWS S3 (Simple Storage Service) is now one of the most versatile pieces of infrastructure for your data. Sure, it can host websites and be your media-offload store, but we’re even at the point where if you drop files in an S3 bucket it can directly trigger a lambda which makes it a popular data interface to trigger event-driven systems. Because it is as simple as being a blob store at the front and has many features at the back, it is a common bridge between legacy systems and modern cloud infrastructure.

Before we talk about what we did, let’s talk about some common anti-patterns we still see in industry that we suggest should be totally avoided lest you too want to risk being in the headlines for a security incident.

Anti-patterns and hacker’s dreams

1. The Open S3 with static access keys

Unfortunately it is common place to see customers making S3 buckets public and use IAM user access keys especially with over-privileged access. However, just because AWS gives you the freedom to compromise your own security doesn’t mean you should; even if it means that everything will ‘just work’ straight away.

Let’s go through why. AWS strongly discourages the use of long-term static access keys, especially in conjunction with public S3 buckets. This is due to a combination of serious security, scalability, and operational risks. Static access keys never expire unless manually rotated or revoked, making them a persistent attack vector if ever exposed, whether through accidental code commits, logs, or configuration files. In many cases, these keys are attached to IAM users with overly permissive policies like s3:*, which means a compromised key can lead to total access over critical data, including reading, writing, or deleting entire S3 buckets. When this is combined with publicly accessible buckets, the risk escalates dramatically, creating a scenario where sensitive data can be easily stolen or manipulated. Beyond the security risks, static keys do not scale well in environments where multiple users, services, or environments require managed, temporary, and auditable access.

2. A hacker’s dream (self-managed EC2 open to the world) 

 
self-managed_EC2_against_attackers-1

 

Self-managed FTP servers on EC2s are still surprisingly common, but they often come with serious security pitfalls. It’s not unusual to find an FTP service running on an EC2 instance tucked into a private subnet, while being exposed to the internet through a public-facing load balancer. Even if other workloads are kept within the same private VPC, there can be a dangerous false sense of security in this setup. Exposing a single EC2 to the world (while assuming the rest of the environment is safe) is one of the riskiest anti-patterns in cloud architecture.

If you haven’t yet experienced a situation where a third-party customer loses their SFTP credentials and the instance is breached, count yourself lucky. But if you’re a major brand, a compromise like this could easily escalate into a headline-making security incident. SFTP is often the protocol of choice because it encrypts traffic and is easy to configure through firewalls, but if an attacker gains access through stolen or brute-forced SSH credentials, the consequences can be severe. Once inside the EC2 instance, the attacker could escalate privileges to root, install tools, and begin scanning the network. This opens the door for lateral movement, potentially compromising neighbouring EC2s, especially those with IAM instance profiles attached. In a worst-case scenario, the attacker could gain access to databases, internal services, or even escalate all the way to administrative access in the AWS account, leading to a full-scale breach.

3. Good, but we can do better!

Another common approach that is commendable is using Transfer Family with API Gateway, WAF (Web Application Firewall) and an authentication processing layer, that is usually an ECS, EC2 or a Lambda. Transfer Family service is a secure managed service by AWS that is appropriate for this use case. If you’re using an ECS or EC2 for authentication, then perhaps this one is worth visiting. However note you are increasing the attack surface of your system by introducing an API Gateway. This is an extra endpoint you have to secure on the application layer, which is why a Web Application Firewall needs to be added on to this. If you want to stay simple, secure and cost efficient, try our approach.

Daemon’s approach

If we are serving a global base of customers with an SFTP service we want no compromises. It has to be secure, scalable, highly available, reliable and (since we need to make a profit from this) cost-efficient.

The golden rule for security is to have multiple layers of defence, and to know exactly what to do if there is a breach.

Layer 1 : AWS Transfer Family Server

There are so many off-the-shelf benefits of using AWS Transfer family for security compared to a self-managed EC2. To name a few, infrastructure security is already managed by AWS; built-in DDoS and network protection, integrated identity management and not to mention a massively reduced attack surface by only exposing SFTP on port 22.

For me the biggest one is no SSH access. It’s not uncommon for even large enterprise companies to setup customers as UNIX users with plain text passwords rather than FTP-only users. If you have a self-managed EC2 open to the world with SSH access and a leaked customer password, you better be on top of that, because that is a major risk!

Total Monthly Cost: $216/month baseline

Self-managed EC2 FTP servers do break, I’ve been there. An EC2 t3.medium and an attached volume EBS (Elastic Block Storage) of 500GB costs about $50 a month. If your internal operational costs for managing EC2 SFTP servers exceed ~$170/month in staff time and infrastructure complexity, Transfer Family becomes cost-neutral while providing superior security, reliability and availability.

Layer 2 : Custom fail2ban authentication Lambda

Even at this stage we will have about a hundred brute force attacks every five minutes. But at least we have minimised the attack surface to only brute force attacks. These attacks are usually automated and they simply go through a list of common usernames like ‘admin’ and a list of common and stolen passwords. This will usually happen from a single or a few different IP addresses. First our lambda checks from a DynamoDB if the IP has been blacklisted and caches the IP address in the lambda. This slightly saves on cost in case we have a flooded attack. If it is a cache miss, it checks with Cognito whether this is an authenticated user. If it does not authenticate, this IP has 9 more chances to get in. If it fails, that IP is blacklisted. We can limit the time it is blacklisted in case it is a genuine customer who forgot their password and can easily and safely reset it with Cognito.

In our production system we have about 400 invocations a month lasting about 950ms each.

Monthly Cost: ~$0.0008 (less than 1 cent)

 

Layer 3 : Cognito

It is worth noting that Transfer Family does offer a built-in service-managed user option too, but it only supports asymmetric key pairs (which, to be fair, should be a default security standard anyway). Since our client's wholesale customers only use passwords, that option was off the table, so we went with a custom, secure approach built around Cognito.

When it comes to your SOC2, PCI DSS, GDPR audits, Cognito takes care of all of that in this system. Plus it’s so easy to sign-up new customers with a password policy of your choice with Cognito’s integrated hosted UI and easy to change a forgotten or breached password. In our whole system, a user’s password is the weakest link in the chain, so its best we secure this as much as we can. It was also beneficial for the business' administration when setting up new customers with email integration.

At the time of publishing, Cognito only starts to cost us after the first 10,000 monthly active users, which kept this project comfortably within Cognito's free tier.

Monthly Cost: $0 (under 10,000 monthly active users)

 

Layer 4 : Design for worst case scenario

The worst case scenario here is that a customer username and password is stolen as secure as it may have been. Our custom lambda limits every successful authentication to only the customer’s S3 directory (it’s really a pseudo-directory). So if they do get in they’ll only have access to the customer data who compromised their username and password. They would not be able to elevate access, they would not be able to do any lateral movement and all other customers' data and all your other AWS infra would be safe.

Monthly Cost: uses the same lambda as above which cost less than 1 cent a month.

Conclusion

Security does not need to be over-complicated or too expensive. It only has to be well thought out and defended in multiple layers. If you see a business case in integrating legacy systems with modern event driven architecture, AI data lakes or simply enrolling a FTP feature for a customer base, try Daemon’s approach that makes no compromises.

 

Back to Blog