serverless-application-model
serverless-application-model copied to clipboard
Unable to use cross-account token lambda authorizer with SAM template
Description:
We have 2 AWS accounts, let's say account A and account B. Account A contains a lambda authorizer we want to use in Account B with API Gateway as a token authorizer. Using the classic cloud formation template, we will be able to create the authorizer reference in account B, and it will not attempt to modify the authorizer in account A to update its resource-based policy to allow cross-account access. The CFT deployment will be able to complete without problems.
However, using SAM syntax like below will cause the CFT deployment to fail:
# template.yaml, intended to be deployed in Account B
TestAuthServiceGateway:
Type: AWS::Serverless::Api
Properties:
StageName: !Ref Environment
OpenApiVersion: '3.0.0'
Auth:
DefaultAuthorizer: MyAuthorizerInAccountA
Authorizers:
MyAuthorizerInAccountA:
FunctionArn: arn:aws:lambda:us-west-2:<AccountA>:function:dev-us-west-2-StandardAuthorizer
FunctionPayloadType: 'TOKEN'
Identity:
ReauthorizeEvery: 0 # disable cache
ValidationExpress: ^Bearer [a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$
The reason is the user who triggered this deployment is currently in Account B and does not have permission to modify the authorizer in Account A.
The error CFT gives looks like below:
User: arn:aws:iam::<AccountB>:user/CICD is not authorized to perform: lambda:AddPermission on resource: arn:aws:lambda:us-west-2:<AccountA>:function:dev-us-west-2-StandardAuthorizer (Service: AWSLambda; Status Code: 403; Error Code: AccessDeniedException; Request ID: 964a7be1-fb95-4759-8c2d-11476c74630b)
My questions are:
- Is there a way to setup IAM role/policy/trust relationship, such that user in Account B, at cloudformation deployment time, can have the permission to modify cross-account authorizer's resource-based policy? This wiki does not suggest "lambda:AddPermission" is a supported API in resourced-based policy. I also gave it a try, and could not get it to work.
- Is it possible to suggest a feature request that do not set the authorizer's resource policy at deployment time? And assume it's already done outside out cloud formation? (This is a one-time thing either way). Something similar to this "AddDefaultAuthorizerToCorsPreflight" flag?
Steps to reproduce the issue:
- Create an lambda authorizer in Account A
- Trying to deploy a SAM template in Account B referencing the token authorizer in Account A
- See the failure in cloud formation saying it does not have permission to modify the resource-based policy of authorizer
Observed result: Unable to modify authorizer resource-based policy in Account A
Expected result: Able to modify given appropriate cross-account permission setup, or allow disable this step of updating the authorizer's resource policy.
Update: Looked into code here, can we update the logic here such that we only attempt to update authorizer's resource based policy when the authorizer lives in the same AWS account? Maybe just update this logic here that also skip when the AWS account of the authorizer.function_arn does not contain the current AWS account ID?
Just stumbled across the same problem.
~~The workaround is to mix the SAM Serverless::Api with the classic cloudformation ApiGateway::Authorizer resource.~~
Edit: After further testing this seems to also not be possible. You can add a Authorizer to the API (via the ApiGateway::Authorizer resource) but you are not able to attach it to the Serverless::Api (via DefaultAuthorizer) nor the Serverless::Function (as ApiAuth)
imo modifying the policy should be optional. Looking forward to the discussion here
If the outcome of this issue results in code changes, I'll happily contribute as this issue is really bothering me and my team :smile:
Also running into this issue
Ended up creating a very simple custom macro to do this for me.
Macro stack:
Description: Remove Authorizer Lambda Permissions
AWSTemplateFormatVersion: "2010-09-09"
Transform: [AWS::Serverless-2016-10-31]
Resources:
RemoveAuthorizerLambdaPermissionsFunction:
Type: AWS::Serverless::Function
Properties:
Description: CFN Macro function that removes AWS::Lambda::Permission resources associated with lambda authorizers
Runtime: python3.7
Handler: index.handler
InlineCode: |
def handler(event, context):
print("Got a request", str(event))
# Get list of resources to be deleted
resources = [name for name in event['fragment']['Resources'] if name.endswith('AuthorizerPermission')]
# Delete them from template
for resource in resources:
print('Deleting authorizer permission:', resource)
event['fragment']['Resources'].pop(resource)
# Return template to CFN
return { "requestId": event["requestId"], "status": "success", "fragment": event["fragment"] }
RemoveAuthorizerLambdaPermissionsMacro:
Type: AWS::CloudFormation::Macro
Properties:
Name: RemoveAuthorizerLambdaPermissions
Description: Removes AWS::Lambda::Permission resources associated with lambda authorizers
FunctionName:
Ref: RemoveAuthorizerLambdaPermissionsFunction
Once the above stack is deployed, you can simply add the macro to to your API stack's Transform
:
AWSTemplateFormatVersion: "2010-09-09"
Transform: [AWS::Serverless-2016-10-31, RemoveAuthorizerLambdaPermissions]
DeidApi:
Type: AWS::Serverless::Api
Properties:
Name: my-api
Auth:
DefaultAuthorizer: MyFn
Authorizers:
MyTokenFn:
...
Not ideal but it works for our use case 🤷
If you happen to have multiple authorizers and one of them is in the sample account, you'll need to explicitly create the permission resource rather than rely on SAM's generated resource (which the macro will delete). As long as the naming convention doesn't match what the macro looks for it should work fine.
+1 It would be beneficial for orgs where there is a centrally managed authorizer to be able to deploy stacks that aren't trying to also create the permission.
@sriram-mv I'm having this exact same issue. Any updates on this subject?
I thik it should be possible to add an attribute like "AddPermissions" which defaults to true (to maintain current behaviour) here: https://github.com/aws/serverless-application-model/blob/e62dcfc6ed2ea3b4f3473e7797ee0663f4e06302/samtranslator/model/api/api_generator.py#L1113-L1133