2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

API Gateway の Lambda Authorizer をRuby で実装してみる

Posted at

概要

API Gateway の機能である Lambda Authorizer を Ruby で実装してみました。
オーソライザーの中身は AWS Cognito を利用したトークンベースで行っています。

デプロイには Serverless を使用しました。
コードはこちらでも公開しています。

Lambda Authorizer とは

Lambda 関数を使用してAPIへのアクセスを制御する API Gateway の機能です。
API Gateway Lambda オーソライザーの使用

Authorizer 関数の実装

ここでは Cognito ユーザープールのトークンを使ってクライアントを認可しています。
リクエストヘッダーに含まれるベアラートークンを検証し、成功すればIAMポリシーを返してAPIへのアクセスを許可します。

auth.rb
require 'jwt'
require 'open-uri'

ISS = "https://cognito-idp.#{ENV['COGNITO_USER_POOL_ID'].gsub(/(?<=\d)(.*)/, '')}.amazonaws.com/#{ENV['COGNITO_USER_POOL_ID']}"

def authorize(event:, context:)
  puts 'Auth function invoked'

  token = event['authorizationToken'][7..-1]
  header = Base64.urlsafe_decode64(token.split('.')[0])
  kid = JSON.parse(header, symbolize_names: true)[:kid]

  res = OpenURI.open_uri("#{ISS}/.well-known/jwks.json")
  keys = JSON.parse(res.read, symbolize_names: true)[:keys]

  key = keys.find { |k| k[:kid] == kid }
  pem = JWT::JWK.import(key).public_key

  begin
    decoded = JWT.decode token, pem, true, verify_iat: true, iss: ISS, verify_iss: true, algorithm: 'RS256'
  rescue JWT::JWKError => e
    puts "Provided JWKs is invalid: #{e}"
    return generate_policy(nil, 'Deny', event['methodArn'])
  rescue JWT::DecodeError => e
    puts "Failed to authorize: #{e}"
    return generate_policy(nil, 'Deny', event['methodArn'])
  end

  generate_policy(decoded[0]['sub'], 'Allow', event['methodArn'])
end

def generate_policy(principal_id, effect, resource)
  auth_response = { principalId: principal_id }
  auth_response[:policyDocument] = {
    Version: '2012-10-17',
    Statement: [
      { Action: 'execute-api:Invoke', Effect: effect, Resource: resource }
    ]
  }
  auth_response
end

認可後に実行される Lambda 関数の実装

handler.rb
def private_endpoint(event:, context:)
  { statusCode: 200, body: 'Only logged in users can see this' }
end

デプロイする

APIの構築に必要なAWSのリソースを定義したファイルを作成します。
8行目のCOGNITO_USER_POOL_IDの値を実際のユーザープールIDに置き換える必要があります。

privateEndpointeventsにあるauthorizerでこの関数が実行される前に呼び出される Lambda Authorizer の設定を行なっています。
Serverlessフレームワークを使えば簡単にこうした設定をすることができます。

serverless.yml
service: aws-ruby-cognito-custom-authorizers

provider:
  name: aws
  runtime: ruby2.5

  environment:
    COGNITO_USER_POOL_ID: COGNITO_USER_POOL_ID

plugins:
  - serverless-hooks-plugin

custom:
  hooks:
    package:initialize:
      - bundle install --deployment

functions:
  auth:
    handler: auth.authorize
  privateEndpoint:
    handler: handler.private_endpoint
    events:
      - http:
          path: api/private
          method: get
          authorizer: auth
          cors:
            origins:
              - '*'
            headers:
              - Content-Type
              - X-Amz-Date
              - Authorization
              - X-Api-Key
              - X-Amz-Security-Token

Gemfileを作成し、必要なライブラリをインストールします。

bundle init
echo \"jwt\" >> Gemfile
bundle

デプロイするには以下のコマンドを実行します。

npm install -g serverless
npm install --save serverless-hooks-plugin
sls deploy

APIのテスト

curlコマンドを使ってAPIのテストをすることができます。
<id_token>には Cognito ユーザーのIDトークンをコピーしてください。
APIのURLはデプロイ後にコンソールに表示されるURLに置き換えます。

curl --header "Authorization: bearer <id_token>" https://{api}.execute-api.{region}.amazonaws.com/api/privat

おわり

AWS上に作成したリソースは以下のコマンドで削除できます。

sls remove
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?