One of the initial errors businesses make when diving into serverless technology is coming up with a plan to mitigate when developers make mistakes around security. More and more the tools developers use are open source. This is great as the community of developers are contributing to creating common ways to solve problems, but it comes with a catch. Just like with anything, there are bad actors who aren't all together altruistic. This is shocking, I'm sure. There are ways to mitigate this though, and unsurprisingly they help move toward the five pillars of the AWS Well Architected Framework.
Development Experience Checklist
Do not rely on Access & Secret Access Keys for security
Active malicious dependency blocking
Continual dependency scanning & Automated remediation
Bonus Points: Remove the developer machine from the network
Do not rely on Access & Secret Access Keys for security
Access and secret access keys are great until someone doesn't refresh their access and secret access keys. There are also quite a few dependency hackers who know how to look precisely for these and will readily use them to create bitcoin mining instances. The challenge here is that most development tools want access to these to authenticate with AWS in order to make your life easier by creating resources your developers really want.
The solution to this is pretty simple. Leverage cross account roles even in your own account.
Create a user account with only the access to use STS for the developer cross account role, or at most read access to the common services their non-command line development tools need. This locked down approach, if compromised, will allow bad actors to get access and secret access keys, but which have low access levels.
Create a role in the same account for cross account access from the same account, and grant access to the developers IAM Group to assume this role using STS. To ensure security, turn on the condition that requires MFA Authentication.
The developer can use a simple script which takes in the MFA token from their virtual device. The developer would change the script to have the cross-account role name and their MFA Arn which is associated with their user account. The script then calls STS to retrieve temporary elevated access which is stored in the console session's environment variables. These credentials would last for 1 hour before they would expire but could be easily refreshed by running the elevate script again.
The following repository contains a cloud formation and an example script which can perform this secure access pattern. They can use this same pattern with either a single account or multiple accounts, giving you more options with how you want to secure your company's AWS account.
Why create it yourself?
The following URL is an example of how to configure cross account access to the same account, as well as scripts to allow the developers to assume the roles. This template is MIT licensed so anyone can use and change it for their own purposes.
Active Malicious Dependency Blocking
It's nice to not have to mitigate some concerns around elevated access, but it's even better if these malicious dependencies never get onto your developer's machines. This is where products like JFrog come into play.
Product like JFrog provide a middleman for dependencies to go through. As developers download dependencies, JFrog is continually scanning them for vulnerabilities. It can then create notifications and security reports, as well as block malicious dependencies it already knows about.
JFrog also is a SaaS based business, which ensures that you stay up to date with all the latest improvements in this area.
Continual Dependency Scanning
The next step is to make sure that as you are developing and deploying more and more code, you don't lose track of the fact that security isn't just a onetime operation in your development life cycle. It didn't seem that long ago that a development team would go out and buy a product, install it and never think about the security risks again. Why would we, it was secure when we bought it? Nowadays, vulnerabilities are being found in dependencies constantly. It's not due to code getting worse, but more scrutiny being placed on the ever-growing knowledge of how hackers are breaking into systems. The good news here is that there are answers to this problem.
Regular dependency scanning can take place at two events: Build Time and a Schedule Inspection. More and more dependency tools are adding in alerting for reported vulnerabilities when downloading dependencies. An example is that NodeJS will print out how many vulnerabilities your dependencies have every time you install a new dependency. They will also report these same vulnerabilities in your build logs as your build server downloads the dependencies. This allows your developers immediate feedback that they need to fix something.
Scheduled Inspection is also pretty simple to set up. Github and other source control systems has this built in with weekly scans of the exact dependencies you have checked into your source control. These scans can bring to light dependency vulnerabilities in projects not actively being worked on with vulnerabilities which were recently discovered. With some source controls, a pull-requests are created automatically with the fixes for these vulnerabilities if they're available, decreasing the effort by your development team even further.
Bonus Points: Remove the developer machine from your network
Alright, we get it. There are many controls on your network. You go through and meticulously scan all the traffic, block ports, geo-restrict IP destinations, etc. The problem is a developer is constantly trying out new tools, new libraries and having to change the configuration on their boxes to where everything slows down. The funny thing here is that with AWS and serverless development, do you really need to go through all of that when the developer rarely needs to access resources on your network to do their jobs? I would challenge that you can become more secure by removing the developer from your network entirely, the exception is where you have production NPI or PHI in your test environments, but we'll assume that you already know that's a bad idea. While this approach might seem counter-intuitive to large enterprises, there are large financial services companies that are currently working towards this approach as it offers advantages over more traditional networking approaches.
In this scenario, it's a question of where do you lock down, and where are the risks. I would challenge that you can secure a system by ensuring what is checked-in meets the highest standards, and gates are in place to make sure nothing can get into higher environments without these checks. We can do this in git through branch policies, which restrict access to common branches used by the company.
The developer would create a branch to develop on. This branch would have code checked in, then the developer would use a pull request to merge it into the commonly used branch. In order for this code to be merged through, it has to make it through the gauntlet of checks. We can plug Github integrations like snyk in to block merging until it performs security scanning against its ever-growing database of vulnerabilities. Static code analysis tools are available like deepscan.io and eslint to detect common coding mistakes. Finally, there are AI Code Review tools to give your developers feedback. All of this can take place before your developer's code gets merged and used in more secure environments.
Well Architected Framework Alignment
The AWS Well Architected Framework Five Pillars isn't just about how you use the AWS Services, it extends to how you work and think about the software development life-cycle.
The Security Pillar
The Security pillar talks about applying security at all layers. This approach provides a method to secure your developers' interactions with the code they right and the dependencies they pull in. It also helps secure the AWS account that they'll have the most privilege in, ensuring that you minimize the risk of account hacks. The bonus points option also helps secure your own network, providing a layer between the developers and your business users, allowing you to lock down your network even further with fewer exceptions.
The Performance Efficiency Pillar
The second pillar this aligns with is the performance efficiency. As you offload the effort of researching security vulnerabilities to services that hook into your developer's experience, you also make it much easier for them to keep up with no extra staff or support. This allows your dev team to focus on the full scope of the systems they manage and decreases the number of initiatives, meetings, etc.
Cost Efficiency Pillar
Finally, this approach can help with the Cost Efficiency pillar. One of the enormous costs to supporting systems is the people time. By moving developers outside of your network and building the discipline around managing access and process around source code, you open up options to integrate vendors with minimal risk. This allows you to scale development support as its needed from anywhere in the world.
Security is more important than ever, but we also have more tools than ever before to combat security vulnerabilities in our development team's code and dependencies. Using the approaches above isn't the last step in security but it's a great first step.