Serverless applications are growing in popularity among DevOps engineers. They provide a convenient, predictable way to run simple processes like CI/CD builds or automation scripts with no need to stand up infrastructure. They are also commonly used to deploy microservices. However, serverless applications present unique security challenges, one of them being authentication.
How can you ensure services communicate with other services or with the outside world only if authorized to do so? How can you ensure users can conveniently and securely access multiple instances of a serverless function?
In serverless applications, there are many components interacting—not only end users and applications but also cloud vendors and applications. This is why common authentication methods, such as single factor, two-factor and multifactor authentication offer only a bare minimum foundation. Serverless authentication requires a zero-trust mentality—no connection should be trusted, even communication between internal components of an application should be authenticated and validated.
To properly secure serverless authentication, you also need to use authentication and authorization protocols, configure secure intraservice permissions and monitor and control incoming and outgoing access. In this article, I’ll cover all these briefly and demonstrate a practical example—setting up authentication in the AWS serverless ecosystem.
What Are the Most Common Authentication Methods?
Here is an outline of the standard authentication methods used by most applications.
Single-Factor Authentication
Also called primary authentication, this is the most prevalent and straightforward type of authentication. Single-factor authentication asks for only one authentication method; for example, a security PIN, password or PIV card, to gain access to a service or system.
These methods are solid in relation to familiarity and usability; however, they are generally linked to poor security and credentials can readily be stolen or guessed through phishing, data breaches or by using keyloggers.
Two-Factor Authentication
Two-factor authentication (2FA) adds another layer of intricacy, as it needs an additional factor to authenticate a user’s identity. Common verification methods include one-time passwords, tokens created by a registered device or PIN numbers. The presence of two verification methods significantly improves your level of security.
Multifactor Authentication
This is the most complex process of authentication. It makes use of two or more independent factors to verify a user’s identity and authorize access to the system. In common scenarios, multifactor authentication (MFA) makes use of at least two of the following factors:
- A PIN or password (something known)
- Security token or mobile phone (something owned)
- FaceID or fingerprint (something you are)
- Location information, typing speed or the like (something you can do)
Authentication and Authorization Protocols
An authentication protocol is a communication protocol that protects authentication data as it transfers between two entities. It enables a receiving entity to authenticate a connecting entity as well as authenticate itself to a connecting entity. This is achieved by declaring the type of information required for authentication and syntax.
There are several types of authentication and authorization protocols, including:
- Lightweight Directory Access Protocol (LDAP)—a software protocol that enables anyone to find data about individuals, organizations, and resources like files and devices within a network. LDAP allows this whether a user uses the public internet or a corporate intranet.
- The Security Assertion Markup Language (SAML)—an open standard that allows sharing security information about authentication, authorization and identity across several different systems.
- Open Authorization (OAuth)—an open standard authorization framework designed for token-based authorization established over the internet. OAuth enables third-party services to use end-user account information without exposing user account credentials to the third party. This blog post can help you understand the differences between SAML and OAuth.
- OpenID—enables authentication services and websites to exchange security information in a standardized manner. OpenID Connect—the newest version of the protocol—provides improved identity management, support for mobile application development, and interoperability. Learn more in the official OIDC FAQ.
Secure Authentication on Serverless
In serverless systems, there are four forms of access—four forms of communication that should be secured. An individual service won’t have to include all four, but the categories that it does feature should be well-protected.
Intraservice Access
Creating a system by uniting serverless services has many advantages. However, you should consider the security of every additional service.
A service with excess permissions is a liability. Unnecessary permissions provide excessive access to data, actions or services, and a bug might let malicious users exploit that service and use its permissions to endanger your system. Hence, you should give careful consideration to the permissions required by each service.
Effectively overseeing intraservice access permissions is often an overwhelming job. Luckily, all of the top-tier cloud providers have native access management services to make this task simpler. AWS has AWS IAM, Azure has Azure Active Directory and Google Cloud Platform (GCP) provides Cloud IAM.
Incoming Access
A network is made accessible through a SaaS offering to external users. Access will be restricted, and every user will require the official credentials to achieve that access.
However, this brings up the same problems raised above—the secrets must be stored somewhere. You cannot manage how your users access and store the credentials that you provide them with; therefore, you should assume that their credentials are not being kept securely and that they may be compromised at any point.
This would appear to be an unmanageable issue, but there is a solution—to provide temporary credentials. This means that even if the secrets were revealed, they would expire shortly afterwards.
The cloud providers have services for this. Google Cloud IAM offers short-lived credentials, AWS IAM lets you create temporary credentials and Azure Active Directory lets you configure expiration dates for its signatures that have shared access.
Outgoing Access
When your organization’s serverless function has access to an external third-party service, it typically needs some sort of access credentials. These credentials need to be kept somewhere, but this storage is sometimes not as secure as it should be. Today, certain web applications continue to store secrets in databases, text files or hardcoded within the function code.
Cloud providers have services for securely retaining credentials and secrets. AWS has AWS Secrets Manager, Azure offers Azure Key Vault and GCP offers Google Cloud Secret Manager.
End User and Customer Access
The issues with this access type are akin to those for incoming access, though the solution is different. Whether in B2B or (particularly) B2C environments, not many users would put up with a requirement to continuously regenerate or refresh their credentials. Thus, another approach is needed.
The top-tier cloud providers all have a user authentication service—Azure Active Directory B2C, AWS Cognito and Google Identity Platform. You should also consider using third-party end-user verification, as this will help you avoid vendor lock-in. Third-party offerings also tend to offer a better developer experience. The most common third-party authentication providers are Okta and Auth0.
AWS Lambda Authentication Solution Example
Amazon Cognito offers managed authentication and authorization that can help you build secure web services in a serverless architecture. It is typically used in combination with Amazon API Gateway when building complex serverless applications that require permission control.
For example, a payroll system may have a manager and two additional employees. The three employees can use their unique usernames and passwords to log into the payroll system—this process is called authentication.
To retrieve paystubs, the three employees undergo role-based authentication:
REST API GET /api/employee/{employee_id}/paystubs
However, the permissions they get through this process should be unique to their needs. This may involve setting up the following conditions:
- The manager can access the paystubs of all employees.
- Employees cannot access the paystubs of other employees, only their own.
You can use AWS managed services to fulfill the above requirements and also meet future scaling needs.
Image Source: AWS
Step One: Setting Up AWS Lambda Authorizer
The Lambda authorizer is the brain that centrally determines whether the requester has the relevant permissions for the requested API resources.
Here’s how you can set it up:
- Navigate to the Amazon API Gateway and create an authorizer.
- Select the API resources you want to secure and assign the AWS Lambda function to them.
- Configure your new AWS Lambda authorizer.
Step Two: Building User Access Control List (ACL)
It is crucial to establish user permissions and keep them up-to-date. The approach might differ according to your identity provider. Here is an example of the process if you use Amazon Cognito as your IDP.
1. Initialize the ACL
Every user has a unique ID, so you can describe each user’s permissions by inserting items in the permission table in Amazon DynamoDB when you register with Cognito. The DynamoDB permission table stores the access control list for all users, although the implementation may differ based on the use case.
For this example, let’s use a single integer ID for each employee (the UUID strings in real applications tend to be much longer).
Manager:
uuid: xxxx-xxx-xxx-xxxx-xxxxxxxx
employee: {“allow”: [“/5”,”/5/*”]}
paystubs: {“allow”:[1,2]}
Employee 1:
uuid: xxxx-xxx-xxx-xxxx-xxxxxxxx
employee: {“allow”: [“/6”,”/6/*”]}
paystubs: {“allow”:[3,4]}
Employee 2:
uuid: xxxx-xxx-xxx-xxxx-xxxxxxxx
employee: {“allow”: [“*”],”deny”:[“/7”,”/7/*”]} // employee_id=7 is the manager of employee 2
paystubs: {“allow”:[1,2,3,4]}
2. Manage the Access Control List (ACL)
The user permissions in a complex project are constantly changing. Employees can be promoted, demoted or terminated, with different access requirements depending on their changing roles. A new manager, for example, needs access to all pay stubs, which means you have to create a new pay stub object for every employee.
You can manage user permissions using the Amazon DynamoDB stream:
Lambda functions can easily be integrated when you insert or modify items in the permissions table. A Lambda function might include code that modifies permissions according to changes to the role of a user.
3. Build an ACL policy
Once you’ve established an ACL with user permissions for every object, you should create an authorization policy document. The Lambda function authorizer uses this policy to evaluate whether user API requests should be allowed or denied.
Amazon API Gateway offers a mechanism for evaluating policies internally. internal policy evaluation mechanism. The Gateway will automatically evaluate any policy JSON returned by the authorizer. For details about Lambda authorizer’s output standard, see this document.
In this article, I covered the basics of authentication in serverless applications:
- Single-factor authentication
- Two-factor authentication
- Multifactor authentication
- Intraservice access
- Outgoing access
- Incoming access
- A real-life example with Amazon Cognito
I hope this will be of help as you gain a better understanding of authentication and authorization techniques that help secure serverless applications.