Я использую AWS SAM для некоторых ламб и авторизатора. Подтверждено, что API-шлюз использует авторизатор, используя Postman (а не функцию тестирования в консоли), и подтвердил, что журналы отображаются в функции авторизатора. Пока не делал ничего особенного с авторизатором, просто пытаюсь передать обратно динамически сгенерированный заголовок WWW-Authenticate, если был недействительный или отсутствующий токен (просто обрабатываем Authorization: bearer
[нет текста после носителя] прямо сейчас в качестве примера).
Все эти выходные я бился головой об стену, похоже, не могу заставить авторизатор передать обратно какое-либо значение для контекста. Я пробовал несколько вещей, таких как $context.authorizer.challenge
и $event.requestContext.authorizer.challenge
, помещая их в тело и заголовок, даже пробовал $context.authorizer.principalId
, который тоже ничего не генерирует.
Код авторизатора обрабатывает запрос:
func (a *authHandler) Handler(request events.APIGatewayCustomAuthorizerRequest) (events.APIGatewayCustomAuthorizerResponse, error) {
fmt.Printf("checking auth\n")
token := request.AuthorizationToken
tokenSlice := strings.Split(token, " ")
var bearerToken string
if len(tokenSlice) > 1 {
bearerToken = tokenSlice[len(tokenSlice)-1]
}
if bearerToken == "" {
fmt.Printf("about to return policy for empty token")
// I've tried multiple combinations of Deny/Allow, context maps, error response, etc.
return generatePolicy("user", "Deny", request.MethodArn, map[string]interface{}{"challenge": "testing"}), errors.New("Unauthorized")
}
return generatePolicy("user", "Allow", request.MethodArn, map[string]interface{}{"name": bearerToken}), nil
}
func generatePolicy(principalID, effect, resource string, context map[string]interface{}) events.APIGatewayCustomAuthorizerResponse {
authResponse := events.APIGatewayCustomAuthorizerResponse{PrincipalID: principalID}
if effect != "" && resource != "" {
authResponse.PolicyDocument = events.APIGatewayCustomAuthorizerPolicy{
Version: "2012-10-17",
Statement: []events.IAMPolicyStatement{
{
Action: []string{"execute-api:Invoke"},
Effect: effect,
Resource: []string{resource},
},
},
}
}
authResponse.Context = context
return authResponse
}
Это просто заполнитель, который должен возвращать Unauthorized
, если получен пустой носитель токена, например Authorization: bearer
.
template.yaml:
Resources:
BaseApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Auth:
DefaultAuthorizer: TokenAuthorizer
Authorizers:
TokenAuthorizer:
FunctionPayloadType: TOKEN
FunctionArn: !GetAtt AuthTokenFunction.Arn
Identity:
Headers:
GatewayResponses:
UNAUTHORIZED:
StatusCode: 401
ResponseParameters:
Headers:
Access-Control-Expose-Headers: "'WWW-Authenticate'"
WWW-Authenticate: "context.authorizer.challenge"
Principal-ID: "context.authorizer.principalId"
ResponseTemplates:
"application/json": '{ "message": $context.error.messageString, "testing": "test", "challenge": $context.authorizer.challenge, "challengeEvent": $event.requestContext.authorizer.challenge }'
AuthTokenFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: cmd/lambda/auth
Handler: services-auth
Runtime: go1.x
Role: !GetAtt ParameterAuthTokenFunctionRole.Arn
Tracing: Active
Environment:
Variables:
APP_CONFIG_PATH: 'parameterAuthToken'
AWS_XRAY_TRACING_NAME: 'AuthTokenFunction'
ParameterAuthTokenFunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Principal:
Service:
- 'lambda.amazonaws.com'
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
Policies:
-
PolicyName: 'ParameterAuthTokenParameterAccess'
PolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Action:
- 'ssm:GetParameter*'
#Resource: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/prod/parameterAuthToken*'
Resource: '*'
-
PolicyName: 'ParameterAuthTokenXRayAccess'
PolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Action:
- 'xray:PutTraceSegments'
- 'xray:PutTelemetryRecords'
Resource: '*'
ParameterAuthTokenEncryptionKeyAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: 'alias/ParameterAuthTokenKey'
TargetKeyId: !Ref ParameterAuthTokenEncryptionKey
ParameterAuthTokenEncryptionKey:
Type: AWS::KMS::Key
Properties:
Description: 'Encryption key for secret config values for the Parameter Auth Token'
Enabled: True
EnableKeyRotation: False
KeyPolicy:
Version: '2012-10-17'
Id: 'key-default-1'
Statement:
-
Sid: 'Allow administration of the key & encryption of new values'
Effect: Allow
Principal:
AWS:
- !Sub 'arn:aws:iam::${AWS::AccountId}:user/anthony-local'
Action:
- 'kms:Create*'
- 'kms:Encrypt'
- 'kms:Describe*'
- 'kms:Enable*'
- 'kms:List*'
- 'kms:Put*'
- 'kms:Update*'
- 'kms:Revoke*'
- 'kms:Disable*'
- 'kms:Get*'
- 'kms:Delete*'
- 'kms:ScheduleKeyDeletion'
- 'kms:CancelKeyDeletion'
Resource: '*'
-
Sid: 'Allow use of the key'
Effect: Allow
Principal:
AWS: !GetAtt ParameterAuthTokenFunctionRole.Arn
Action:
- 'kms:Encrypt'
- 'kms:Decrypt'
- 'kms:ReEncrypt*'
- 'kms:GenerateDataKey*'
- 'kms:DescribeKey'
Resource: '*'
GhostFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: cmd/lambda/ghost
Handler: services-ghost
Runtime: go1.x
Tracing: Active
Events:
GetGhost:
Type: Api
Properties:
Path: /ghost/{id}
Method: GET
RestApiId: !Ref BaseApi
Auth:
Authorizer: TokenAuthorizer
Ответ:
401 Unauthorized
Headers:
WWW-Authenticate:
Principal-ID:
Access-Control-Expose-Headers: WWW-Authenticate
x-amzn-ErrorType: UnauthorizedException
Body:
{ "message": "Unauthorized", "testing": "test", "challenge": , "challengeEvent": }
И некоторые скриншоты консоли:
введите описание изображения здесь
Есть подсказки? Я собираюсь отказаться от авторизатора и добавить в свой лог c в каждую лямбда-функцию. Кажется, там намного проще сделать что-то вроде применения заголовка.