Systems often have different tasks and actions that are performed by different users. Users and administrators are the simplest examples of this.
It gets more complicated if there are multiple types of users with their own sets of actions or a hierarchy of administrators. A flexible way of dealing with this complexity is to include role-based access in the interfaces.
Modern serverless implementations should include it while maintaining the benefits of serverless systems.
What is Role-based access?
Every user has a set of actions that they are authorised to perform. The naive way to do this is to have every action check the user against a list of allowed users. This rapidly becomes impractical as the functionality and the number of users increase.
Like many software design solutions, adding another level of indirection gains us a lot. Decouple the action from the user by requiring a permission that the user may have instead. Then also decouple the permissions from the user, by assigning permissions to a role that the user may have.
Access management is then simplified to assigning roles to users. The permissions depend on the implementation details of the actions and can be managed separately. In a content management system, for example, there may be two roles: “Editor” and “Administrator. An editor has permission to edit content, while an administrator has additional permission to delete content.
Lambda Function access implementation
Serverless compute implementations, like AWS Lambda functions, are typically used to create REST APIs. Note that there is a distinction between executing permission for the Lambda and the action it implements. Execution permission is typically governed by IAM (Identity and Access Management) and Cognito and requires a user to log in.
While the Lambda function can get at the Cognito-managed IAM permissions, these are not relevant to the application. While IAM is a role-based system, it is focused on AWS infrastructure access rather than application integration.
Instead, Lambda functions should calculate user permissions as a first step. An application-specific data store like a DynamoDb table with user roles and role permissions is used. The union of all permissions from all the roles that are assigned to the user is checked. If it contains the required permission, execution continues.
Note that any new code could add its own permission requirements or reuse existing permissions. Managing user access only depends on the content of the role data store. Most access changes can be done through updates to this data, independently from updates to the code.
Role-based access is an extremely flexible approach. It is fairly easy to implement in Lambda functions as an application-specific system. Avoid using Cognito and IAM for this purpose. Those are intended for infrastructure-level access.