AWS SAMでLambdaオーソライザーを「適用するAPI」と「適用しないAPI」を作ってみた

AWS SAMでLambdaオーソライザーを適用したAPIと適用しないAPIを作ってみました。
2021.11.02

CognitoやAuth0を使って、API GatewayのLambdaオーソライザーで「OK・NG」を判断することは多いと思います。 このとき、一部のAPIを公開したくなったので、試してみました。

概要図

OpenAPIを使った場合は、下記をご覧ください。

おすすめの方

  • AWS SAMでLambdaオーソライザーを作りたい方
  • AWS SAMで一部のAPI(Lambda)にLambdaオーソライザーを適用したくない方

サーバーレスアプリを作成する

sam init

sam init \
    --runtime python3.8 \
    --name Lambda-Authorizer-Sample \
    --app-template hello-world \
    --package-type Zip

SAMテンプレート

Lambda自体は3つ作成します。

  • Lambdaオーソライザー
  • GET /hello用(Authorizerあり)
  • GET /hello2用(Authorizerなし)

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Lambda-Authorizer-Sample

Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: dev
      Auth:
        DefaultAuthorizer: MyLambdaAuthorizer
        Authorizers:
          MyLambdaAuthorizer:
            FunctionArn: !GetAtt AuthorizerFunction.Arn
            Identity:
              ReauthorizeEvery: 0

  # Lambda Authorizer
  AuthorizerFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: authorizer.lambda_handler
      Runtime: python3.8
      Timeout: 5

  AuthorizerFunctionLogGroup:
      Type: AWS::Logs::LogGroup
      Properties:
        LogGroupName: !Sub /aws/lambda/${AuthorizerFunction}

  # API: GET /hello (Authorizerあり)
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.8
      Timeout: 5
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
            RestApiId: !Ref MyApi

  HelloWorldFunctionLogGroup:
      Type: AWS::Logs::LogGroup
      Properties:
        LogGroupName: !Sub /aws/lambda/${HelloWorldFunction}

  # API: GET /hello2 (Authorizerなし)
  HelloWorld2Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.8
      Timeout: 5
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello2
            Method: get
            RestApiId: !Ref MyApi
            Auth:
              Authorizer: NONE

  HelloWorld2FunctionLogGroup:
      Type: AWS::Logs::LogGroup
      Properties:
        LogGroupName: !Sub /aws/lambda/${HelloWorld2Function}

Outputs:
  HelloWorldApi:
    Value: !Sub "https://${MyApi}.execute-api.${AWS::Region}.amazonaws.com/dev/hello"

Lambdaコード

Authorizer

authorizationabcならOKとしています。

authorizer.py

def lambda_handler(event, context):
    token = event['authorizationToken']
    effect = 'Deny'
    if token == 'abc':
        effect = 'Allow'

    return {
        'principalId': '*',
        'policyDocument': {
            'Version': '2012-10-17',
            'Statement': [
                {
                    'Action': 'execute-api:Invoke',
                    'Effect': effect,
                    'Resource': event['methodArn']
                }
            ]
        }
    }

GET /hello

GET /hello2と共通です。

app.py

import json

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps({
            'message': 'hello world',
        }),
    }

デプロイ

sam build

sam package \
    --output-template-file packaged.yaml \
    --s3-bucket cm-fujii.genki-deploy

sam deploy \
    --template-file packaged.yaml \
    --stack-name Lambda-Authorizer-Sample-Stack \
    --s3-bucket cm-fujii.genki-deploy \
    --capabilities CAPABILITY_NAMED_IAM \
    --no-fail-on-empty-changeset

動作確認

APIエンドポイントを取得する

aws cloudformation describe-stacks \
    --stack-name Lambda-Authorizer-Sample-Stack \
    --query 'Stacks[].Outputs'

GET /hello

Authorizationあり(OK)

curl https://xxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hello \
  --header 'authorization: abc'
{"message": "hello world"}

Authorizationあり(NG)

curl https://xxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hello \
  --header 'authorization: xxx'
{"Message":"User is not authorized to access this resource with an explicit deny"}

Authorizationなし(NG)

curl https://xxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hello
{"message":"Unauthorized"}

GET /hello2

Authorizationなし(OK)

curl https://xxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hello2
{"message": "hello world"}

さいごに

参考