Efficiently Sharing a Lambda Authorizer Across AWS Accounts
Written on
Chapter 1: Understanding Lambda Authorizers
In the realm of cloud computing, especially within large organizations, managing multiple AWS accounts is a common practice for handling various applications. This guide explores how to effectively share a Lambda authorizer across these accounts, allowing you to establish authentication just once.
Many differing views exist regarding the structuring of AWS accounts. Some advocate for a single account to house all resources, while others recommend dedicating each application—often composed of several microservices—to its own account. A few take this a step further by isolating each microservice in its own account.
While none of these strategies are inherently flawed, they all share a common challenge: maintaining uniform authorization across different accounts. The solution involves utilizing a custom Lambda authorizer, although the implementation can be both straightforward and complex.
Section 1.1: What is a Lambda Authorizer?
If you're reading this, you likely have some familiarity with Lambda authorizers. To clarify, a Lambda authorizer is a feature of API Gateway that utilizes a Lambda function to handle authorization for API calls. This includes authenticating OAuth or SAML tokens and applying relevant business logic to manage access.
For serverless applications, deploying a Lambda authorizer atop your API Gateway can significantly enhance control over individual endpoints.
Subsection 1.1.1: Defining a Lambda Authorizer with SAM
The Serverless Application Model (SAM) simplifies the definition of serverless applications, building on CloudFormation. The examples shared here will be formatted in a SAM template, allowing for immediate deployment to your AWS account without navigating through the console.
A Lambda authorizer is fundamentally a function, requiring nothing out of the ordinary for declaration. It simply expects a different event body than what a Lambda function typically receives through API Gateway.
Here’s how you might define a Lambda authorizer in your SAM template:
LambdaAuthorizerCrossAccountFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: lambdas/lambda-authorizer
Runtime: nodejs12.x
Handler: lambda-authorizer.lambdaHandler
Role: !GetAtt LambdaAuthorizerRole.Arn
FunctionName: LambdaAuthorizer
The provided example repository includes the SAM template, though it does not contain the actual code for the authorizer. For practical examples on building the authorizer, AWS offers blueprints on GitHub.
Section 1.2: Granting Authorizer Permissions
Setting up cross-account permissions in AWS can be complex. Permissions must be established in the source account to authorize access to its resources. Knowing your consumers beforehand is essential, and this foresight can actually be beneficial.
For Lambda authorizers, the permission setup is relatively straightforward. You need to grant the API Gateway in the consumer accounts the authority to invoke the authorizer function.
Here’s an example of how to define this permission in your SAM template:
ConsumerOneAuthorizerPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref LambdaAuthorizerCrossAccountFunction
Principal: apigateway.amazonaws.com
SourceArn: !Sub arn:${AWS::Partition}:execute-api:${AWS::Region}:${ConsumerOneAccountId}:/authorizers/
This configuration permits API Gateway to invoke the specified function. The SourceArn delineates which resources are allowed to execute the function. Each consumer account will require a similar permission to access the authorizer, reinforcing the principle of least privilege.
Chapter 2: Implementing the Authorizer in Consumer Accounts
With the authorizer established and permissions granted, the next step is to configure the consuming accounts to utilize it. Below is how you might define the serverless API and authorizer in the SAM template of a consuming account:
ConsumerServiceApi:
Type: AWS::Serverless::Api
Properties:
StageName: test
Auth:
DefaultAuthorizer: LambdaAuthorizer
AddDefaultAuthorizerToCorsPreflight: false
Authorizers:
LambdaAuthorizer:
FunctionPayloadType: REQUEST
FunctionArn: !Sub arn:${AWS::Partition}:lambda:${AWS::Region}:${AuthorizerAccountId}:function:LambdaAuthorizer
Identity:
Headers:
- Authorization
ReauthorizeEvery: 3600
A crucial aspect here is the FunctionArn, which is dynamically generated for security reasons. This parameterization ensures that account IDs are not hard-coded into your source code.
Once deployed, the Lambda authorizer will be created in the consumer account, while the function resides in the account designated as the authorizer.
Final Thoughts
Reusing code and resources is vital for scalable maintainability. Strive to leverage existing resources whenever feasible. Authorization and authentication are prime examples of reusable components that can unify your applications.
Developers often feel inclined to create solutions from scratch. Achieving effective resource sharing across an organization necessitates governance and is not solely a technical challenge.
Removing these technical barriers is the first step; the next is putting these strategies into practice. This guide has outlined how to maintain consistent authentication within your software ecosystem. Now, it's your turn to implement these practices.
In this video, you will learn about securing your API Gateway with a Lambda authorizer and how to implement a custom authorizer effectively.
This tutorial covers how to set up a Lambda authorizer for REST APIs using .NET on AWS, providing a practical approach to serverless architecture.