Security and Serverless
It’s just a different set of issues — but I prefer the security problems I have with serverless than the old ways
There are a few of us that have been using a serverless approach (not necessarily the framework) for well over a year now. Mainly this is AWS Lambda but other serverless approaches are available.
One question that has come up a number of times is whether this approach is better from a security point of view. Also, there are people that have come across much greater problems than I and have written various posts about it, mainly @Ben11Kehoe who has asked a lot of difficult questions and worked some things out that we’ve all benefitted from.
This post is simply a few pointers on how we’ve learned some things. This may also be a first post that starts discussions rather than a definitive guide.
Bad code is still bad code
No legislating for being an idiot. So do your best to avoid it.
There’s still a server (but it’s ok!)
Your code still has to run somewhere, and so you will still have to consider the same issues as you would with any other server. But in a slightly different way.
As anyone will tell you, if you can gain access to the server, you can do a lot of damage including to the wider network, so you should still be aware of various exploits of such as code injection and cross site scripting.
Not only that but third party libraries are a security risk too. Small functions reduce the scope of that, but organisations like Snyk (pronounced sneak) can help with some of those scenarios.
The advantage of serverless here is that it has a timeout on invocation. It’s not something to be ignored! Set real timeouts and make your functions run as quick as possible. It’s really helpful
This isn’t an article about that (there are many of those) so go find one. The point here is that going serverless doesn’t protect you from having to consider these things as well.
Use an API Gateway
I’m pretty sure every solution that provides Function as a Service (FaaS) has an API Gateway that sits between the invocation of the function and the web.
This is really important. The advantage of this is that the service provider should be adding in certain services and checks for you (DDoS, API Key management etc). Trust me that those things are quite hard to do and manage, so make use of them.
As a quick example the original way of doing AWS Lambda was to utilise the Lambda directly (there was no API Gateway) and that caused an issue with permissions as you had to get IAM credentials from somewhere, which meant that you gave access pretty much directly to the Lambda if the code could be compiled.
Putting the API Gateway in between means that you can create a user that only has the ability to access the API Gateway, and that gives added protection.
Also, one thing we do is obfuscate our API URL. And change it regularly. Gone are the days of my domain being the only way in.
SQL injection is still a problem
Validate inputs, and use good libraries to deal with any interaction with SQL databases.
Or just don’t bother using SQL any more. Use services that provide data storage and retrieval with actual scalability and write better apps!
(I’m being a bit controversial here, but we use DynamoDB and I don’t want to go back to SQL for client/server given the known exploits and enforcing code in this scenario is harder than what appears to be a more secure approach to data storage/retrieval).
Learn how to use the permissions (properly!)
Right. If your function is doing 47 things, then you’re doing it wrong!
Why? Because that function is then going to need all the permissions to do all those things.
If it does only 1 thing, then it only needs that single permission.
I know that when you first start out looking at Lambda functions, that permissions is almost an aside, but it’s the most important thing for security.
Also, some of the functions that were in there as “templates” use switch statements, and that I think should be an antipattern here. It’s a less secure function because if you accidentally introduce exploitable code, your attack area becomes much greater.
On a side note, ensuring that every user that has access to production has no delete permissions on any service is a good way of ensuring you don’t have a disastrous “rm -Rf”-type problems at some point!
Permissions for users/roles
On the user permissions, you should be very careful. I recently was at a talk on penetration testing where I outlined our serverless approach, and was congratulated on a very good technical system. I was then asked were all our laptops encrypted and all our employees happy…!
Most of the dangerous exploits come down to either people in your staff or your users. Give them only the permissions they need. Don’t be lazy and give them everything (as so many systems/people do).
On the same note, ensure that any permissions you give to client applications and third parties are locked down (e.g. to just using the API Gateway!).
For your client applications, the best solution I’ve come up with so far (in the AWS world) is to use Cognito and give the absolute minimum permissions inside the unauthorised role. That way, you never have to put secrets in the app!
Data, Keys and Secrets
Access to data, keys and security has always been quite complicated, but it’s vital.
Simple things like not putting keys in client applications and git repositories is well known, but there are other things to consider.
This issue is especially important when you have data at rest. It’s not just about encrypting back and forth between client and server (that should be partly dealt with by API Gateway and secure HTTP of course) but how to ensure data is not viewable if removed (either by malicious users or malicious employees!).
And if you use third party services that cost you hundreds of dollars a month (or thousands) then you don’t want the keys to be shared accidentally, or passwords or whatever. Or stolen.
Key management solutions exist and some providers provide encryption solutions as part of the Functions as a Service. However, knowing about them, and using them appears to be two different things.
Find a good solution and use it.
I haven’t forgotten the events. Simply the event message bus should only be available to those parts of the system sending messages. Don’t open it up to users without knowing what permissions are needed and where!
What has this got to do with serverless?
Well, the FaaS approach + Events + API Gateway + DynamoDB has proved more secure for us than I ever thought possible, partly because we have a serious security team at AWS backing us up and dealing with hacking attempts and security issues for tens of thousands of people, not just us!
Thinking back to having to constantly upgrade servers, manage firewalls, SSH into boxes, and do a whole lot of other things on multiple instances has meant that moving towards this scenario is a dream for a manager.
But there are still issues!
I am not trying to say it’s perfect, but as I’ve said many times, it’s just a different set of problems.
And I prefer the problems I have with a serverless approach than the old ways.
But the service providers should be providing more and more security options over time (as exploits are found and companies utilise serverless approaches more), and to be honest, they will be hiring some of the best security people and implementing good practices much more than most people/companies ever could.
While it’s not always a sensible idea to trust third parties completely, the interesting thing here is that if you don’t trust them, you can still use the services and make use of services to encrypt at rest and separate key management and other things to utilise the services and keep your information out of the prying eyes of your service provider.
So keep an eye on the changes coming up and go for it.
This article is not definitive
I’m still interested in learning more and more and it is entirely possible that I’ve missed some things out. The intent is to start discussion, so comment/reply as I’m interested to see the opinions of others.
And I could be wrong and have a massive blind spot! If I have, please point it out so I can fix it :D
For a collection of my posts on serverless go here: