Serverless Frameworkで作成したAPI GatewayにIAMによるアクセス制御を行う

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

API GatewayにはIAMでアクセスを制限する機能があります。

IAM アクセス権限により API へのアクセスを制御する

Serveress Frameworkで作成したAPIに、この機能によるアクセス制限を追加し、動作を確認するまでの手順について書いていきます。

手順について

LambdaとAPI Gatewayの構築

まずはServerless Frameworkでアクセス制限なしのLambdaとAPI Gatewayを作成します。Lambdaの言語はPython3系とします。

Serverless Frameworkをインストールします。今回は作業するローカルフォルダにインストールしました。

$ npm install serverless

バージョンを確認します。

$ ./node_modules/.bin/serverless --version
1.24.1

テンプレートを作成します。

$ ./node_modules/.bin/serverless create --template aws-python3

Lambdaのhandlerは自動生成されるものをそのまま使います。

import json


def hello(event, context):
    body = {
        "message": "Go Serverless v1.0! Your function executed successfully!",
        "input": event
    }

    response = {
        "statusCode": 200,
        "body": json.dumps(body)
    }

    return response

    # Use this code if you don't use the http event with the LAMBDA-PROXY
    # integration
    """
    return {
        "message": "Go Serverless v1.0! Your function executed successfully!",
        "event": event
    }
    """

serverless.ymlを編集し、リージョンとAPI Gatewayの設定を行います。

provider:
  name: aws
  runtime: python3.6

# you can overwrite defaults here
#  stage: dev
  region: ap-northeast-1 # リージョン指定

(中略)

functions:
  hello:
    handler: handler.hello
    events: # ここから4行をAPI GatewayのGETメソッドを作成するために追加
      - http:
          path: hello
          method: get

デプロイを行います。

$ ./node_modules/.bin/serverless deploy

動作確認を行います。

$ curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hello | jq .
{
  "message": "Go Serverless v1.0! Your function executed successfully!",
  "input": {
    "resource": "/hello",
    "path": "/hello",
    "httpMethod": "GET",
    (以下略)
  }
}

ここではまだIAMによるアクセス制御は行なっていないため、curlでGETをできています。

IAMでのアクセス制御を追加

serverless.ymlのAPI Gatewayの設定に、IAMでのアクセス制御を追加します。

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get
          authorizer: aws_iam # これを追加

デプロイを行います。

$ ./node_modules/.bin/serverless deploy

動作確認を行います。

$ curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hello | jq .
{
  "message": "Missing Authentication Token"
}

先ほどと異なり、今度はcurlでのGETをできません。

署名バージョン 4を使用してAPIにアクセスする

上記のAPIにアクセスするには署名バージョン 4による署名が必要となります。今回はRubyのaws-sigv4と言うgemを使って実行してみました。

gemのインストールを行います。

Gemfile

# A sample Gemfile
source "https://rubygems.org"

# gem "rails"
gem 'aws-sigv4'
gem 'aws-sdk', '~> 2'
$ bundle install --path vendor/bundle

APIにアクセスするプログラムは以下のようになります。

main.rb

require 'aws-sigv4'
require 'open-uri'
require 'aws-sdk'

ec2 = Aws::EC2::Client.new
credentials = ec2.config[:credentials].credentials

signer = Aws::Sigv4::Signer.new(
  service: 'execute-api',
  region: 'ap-northeast-1',
  access_key_id: credentials.access_key_id,
  secret_access_key: credentials.secret_access_key,
)

url = signer.presign_url(
  http_method: 'GET',
  url: 'https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hello',
)

open(url){|io|
  puts io.read
}

以下のコマンドで実行します。

$ bundle exec ruby main.rb | jq .
{
  "message": "Go Serverless v1.0! Your function executed successfully!",
  "input": {
    "resource": "/hello",
    "path": "/hello",
    "httpMethod": "GET",
(以下略)

無事、APIにアクセスすることができました。