我有以下 Cloudformation 模板,该模板使用自定义 Lambda 授权方部署 HTTP API 网关,该授权方可传送到 SQS 队列。我使用此处未显示的另一个 lambda 处理队列中的消息。当我在没有启用授权的情况下部署此模板时(在路线中将
AuthorizationType
从 CUSTOM
设置为 NONE
,并注释掉 AuthorizerId: !Ref APIAuthorizer
),整个过程正常进行,我看到我的消息流从 API Gateway 通过 SQS 流向订阅 Lambda 进行处理。但是,当我启用授权时,我看到我的消息进入 Auth Lambda,然后在 Postman 中收到内部服务器错误。
自定义身份验证显然存在问题,但是,在尝试了几天不同的操作后,我找不到问题的原因。
我的理解是我只需要在返回的策略中授权routeArn,但是,也许我还需要为SQS权限做一些事情?
这是我的模板(不包括最终的 lambda)。
Queue:
Type: AWS::SQS::Queue
Properties:
QueueName: my-queue
QueuePolicy:
DependsOn: ["Queue"]
Type: AWS::SQS::QueuePolicy
Properties:
PolicyDocument:
Statement:
- Action: SQS:*
Effect: Allow
Principal: '*'
Resource: !GetAtt Queue.Arn
Version: '2012-10-17'
Queues:
- !Ref Queue
ApiGatewayToSQSRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- apigateway.amazonaws.com
Action:
- sts:AssumeRole
RoleName: ApiGatewayToSQSRole
Policies:
- PolicyName: ApiGatewayLogsPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action: sqs:SendMessage
Effect: Allow
Resource: !GetAtt 'Queue.Arn'
- Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:DescribeLogGroups
- logs:DescribeLogStreams
- logs:PutLogEvents
- logs:GetLogEvents
- logs:FilterLogEvents
Effect: Allow
Resource: "*"
ApiGateway:
Type: 'AWS::ApiGatewayV2::Api'
DeletionPolicy: Delete
Properties:
Name: "API Gateway to SQS"
ProtocolType: 'HTTP'
ApiGatewayStage:
Type: AWS::ApiGatewayV2::Stage
Properties:
ApiId: !Ref ApiGateway
StageName: dev
AutoDeploy: true
Integration:
Type: AWS::ApiGatewayV2::Integration
Properties:
ApiId: !Ref ApiGateway
CredentialsArn: !GetAtt ApiGatewayToSQSRole.Arn
PayloadFormatVersion: "1.0"
IntegrationType: AWS_PROXY
IntegrationSubtype: SQS-SendMessage
RequestParameters:
QueueUrl: !Ref Queue
MessageBody: $request.body
Route:
Type: AWS::ApiGatewayV2::Route
DependsOn:
- ApiGateway
- Integration
Properties:
ApiId: !Ref ApiGateway
RouteKey: 'POST /send'
AuthorizationType: CUSTOM
AuthorizerId: !Ref APIAuthorizer
Target: !Sub integrations/${Integration}
APIAuthorizer:
Type: AWS::ApiGatewayV2::Authorizer
Properties:
Name: APIAuthorizer
ApiId: !Ref ApiGateway
AuthorizerType: REQUEST
AuthorizerUri: !Join
- ""
- - "arn:"
- !Ref "AWS::Partition"
- ":apigateway:"
- !Ref "AWS::Region"
- ":lambda:path/2015-03-31/functions/"
- !GetAtt AuthorizerFunction.Arn
- /invocations
AuthorizerResultTtlInSeconds: 300
AuthorizerPayloadFormatVersion: 2.0
EnableSimpleResponses: true
IdentitySource:
- $request.header.authorization
AuthorizePermission:
Type: AWS::Lambda::Permission
DependsOn:
- ApiGateway
- AuthorizerFunction
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref AuthorizerFunction
Principal: apigateway.amazonaws.com
AuthHandlerServiceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: 'sts:AssumeRole'
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Version: 2012-10-17
ManagedPolicyArns:
- !Join
- ''
- - 'arn:'
- !Ref 'AWS::Partition'
- ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
AuthorizerFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: authorizer-lambda
Role: !GetAtt [AuthHandlerServiceRole, Arn]
CodeUri: functions/core_authorizer_lambda
Handler: index.handler
Runtime: python3.11
Tags:
Name: authorizer-lambda
project: my-project
这是我的授权者 lambda 函数
def generate_policy(principal_id: Union[int, str, None], effect: str, resource: str) -> dict:
""" return a valid AWS policy response """
auth_response = {'principalId': principal_id}
if effect and resource:
policy_document = {
'Version': '2012-10-17',
'Statement': [
{
'Sid': 'InvokeAPIStatement',
'Action': 'execute-api:Invoke',
'Effect': effect,
'Resource': resource
}
]
}
auth_response['policyDocument'] = policy_document
return auth_response
def handler(event, context) -> dict:
try:
print("event:", event)
print("context:", context)
route_arn = event.get('routeArn')
return generate_policy('me', 'Allow', route_arn)
except Exception as e:
logging.exception(e)
return {
'statusCode': 500
}
我用
调用它{
"body": "Hey aws! How are you today?",
"headers": {
"Accept": "application/json",
"authorization": "Bearer <token>"
}
}
我尝试了不同的模板设置,并尽可能简化一切。
不要使用
route_arn = event.get('routeArn')
,而是使用 methodArn
作为政策中的 Resource
。
这是您需要更改的代码。
methodArn = event.get('methodArn')
return generate_policy('me', 'Allow', methodArn)