EP14: AWS KMS Was Faster Than bcrypt on Lambda

I assumed the network call would lose. But it was 20x faster.

I’ve been deep into building an SFTP project lately.

I’ll share the full story later, but this part is just about authentication and the tradeoffs I ran into.

Here’s the setup.

I’m using AWS Transfer Family for SFTP, with a Lambda function handling authentication. User passwords are stored in DynamoDB, encrypted using KMS. On login, Lambda fetches the password, decrypts it with KMS, and compares it with what the user provides.

Even saying that feels a bit off.

Passwords are supposed to be hashed, not decrypted.

But this system is made of multiple services talking over the network:

SFTP authentication flow across Transfer Family, Lambda, DynamoDB, and KMS

When I first built it, login took 7–9 seconds. Way too slow!

Then I started optimizing. I added VPC endpoints and reduced some hops, but it was still above 5 seconds. Not acceptable for something users interact with directly.

So I looked at Lambda.

While checking Lambda logs, I noticed KMS calls adding latency and assumed the network was the main issue. So I tried bcrypt, the “correct” approach for passwords, hoping it would reduce that overhead.

At that point, I was using 128MB memory.

I thought switching to bcrypt would help. But it didn’t.

I know KMS and bcrypt aren’t the same tool. But for my situation, I had to compare them.

At 128MB the latency was:

  • KMS: around 200ms
  • bcrypt: around 4000ms+

That was unexpected.

bcrypt wasn’t just slower, it was dramatically slower. It turned out to be CPU heavy, and Lambda at low memory just doesn’t have enough power for it.

Then I tried scaling memory:
128MB → 1024MB → 2000MB → 5000MB

KMS vs bcrypt latency across Lambda memory tiers

bcrypt improved, but it still stayed higher than I wanted unless I kept increasing memory and cost.

But KMS behaved differently.

Since it runs outside Lambda, it depends more on network than CPU. At higher memory, I started seeing sub-50ms responses quite often.

So I had a choice.

Use proper one-way hashing like bcrypt, accept more tuning, more CPU usage, and higher cost.

Or use KMS, accept some security tradeoff, but meet latency and keep the system simple.

I chose KMS.

Not because it is better, but because it fit the constraints I had.

It gave me acceptable latency, simpler setup, and less operational overhead.

I did not have to worry much about tuning hashing cost or dealing with CPU limits. Access could be controlled with IAM using least privilege.

But it is still a compromise. Hashing is the right model for passwords. It is one-way and safer by design.

There were other options I could tune and make work, but they would need more effort and still come with tradeoffs.

In my case, performance and simplicity mattered more. And that is really the point of this.

Not that KMS is the right choice, but that real systems force tradeoffs.

The biggest lesson for me was simple. Measure everything. Do not assume.

I assumed network would be the bottleneck. But it turned out CPU inside Lambda was the bigger one.

That is where I landed.

More soon
-Alon