10
1

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 1 year has passed since last update.

Linkbal(リンクバル)Advent Calendar 2022

Day 1

AWSのSigV4署名を付与してIAM認証のAPI GatewayにHTTPリクエストを送るRubyとGoのサンプルコード

Last updated at Posted at 2022-11-30

この記事は、リンクバルアドベントカレンダー2022の1日目の記事です。

はじめに

SigV4署名を付与してIAM認証のAPI GatewayにHTTPリクエストをするRubyとGoのサンプルコードを紹介します!

AWSのAPIを使うには、SigV4署名が必要です。AWS CLIやAWS SDKは、SigV4署名をよしなにやってくれるので、APIを使う側がSigV4署名を意識することはありません。

しかし、IAM認証をしたAPI GatewayのAPIをリクエストするときなど、単純なHTTPリクエストの際には、自前で署名を付与する必要があります(AWSのAPIには、SigV4署名を付けてAPI Gatewayをリクエストしてくれる便利なものは存在しません)。

署名の付与は自前ですが、署名をするためのライブラリは用意されているので、そちらを使えばすんなり署名ができます。

Ruby

ドキュメント

サンプルコード

重要な部分はコメントで説明しています。

require 'aws-sdk-core'
require 'net/http'
require 'uri'
require 'json'
require 'yaml'

# SigV4署名を行うオブジェクトを作成
signer = Aws::Sigv4::Signer.new(
  service: 'execute-api',# API GatewayのAPIを呼ぶためのserviceの指定
  region: 'ap-northeast-1',
  credentials_provider: Aws::Credentials.new('xxx', 'xxxxx'), # 認証情報の取得。詳細は後述。
)

# API Gatewayのエンドポイント
api_url = 'https://xxx.execute-api.ap-northeast-1.amazonaws.com/xxx/xxx'
body_data = {
  hoge: "xxxx",
  foo: "xxx"
}
req_body = body_data.to_json

# SigV4署名を行う。HTTP Method, URL, bodyを引数に渡す
# signature.headers が、SigV4署名されたhttp headerです
signature = signer.sign_request(
  http_method: 'POST',
  url: api_url,
  body: req_body,
)

signature.headers['Content-Type'] = 'application/json'

uri = URI.parse(api_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

# 署名されたheaderを、HTTPリクエストのheaderに追加
response = http.post(uri.path, req_body, signature.headers)

credentials_providerについて

credentials_providerは、以下の5種類があります。
漏洩のリスクやキーの管理など、主にセキュリティ的に InstanceProfileCredentialsECSCredentials の利用が望ましいです。極力アクセスキーを利用するのは避けましょう。

Go

ドキュメント

サンプルコード

注意:SDKがv1のコードです

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
)

type RequestStruct struct {
	Hoge string `json:"hoge"`
	Foo  string `json:"foo"`
}

func main() {
    // API Gatewayのエンドポイントを指定
	apiURL := "https://xxx.execute-api.ap-northeast-1.amazonaws.com/xxx"
	data := RequestStruct {
		Hoge: "xxx",
		Foo:  "yyy",
	}

	body, err := json.Marshal(data)
	if err != nil {
		fmt.Printf("error: %+v\n", err)
	}

	// *Reader型のreqBodyを作成
	reqBody := strings.NewReader(string(body))

	req, err := http.NewRequest(http.MethodPost, apiURL, reqBody)
	if err != nil {
		fmt.Printf("error: %+v\n\n", err)
	}
	req.Header.Set("Content-Type", "application/json")

	// 認証情報を取得
	sess := session.Must(session.NewSession())
	creds := stscreds.NewCredentials(sess, "arn:aws:iam::xxxxxxxx:role/xxxxxxxxxxxx")

	// SigV4署名を行うsignerを作成
	signer := v4.NewSigner(creds)

    // SigV4署名
	signer.Sign(
		req, // *http.Request
		reqBody, // io.ReadSeeker
		"execute-api", // AWSのService
		"ap-northeast-1", // region
		time.Now(), // 署名時刻
	)

	client := new(http.Client)
	res, err := client.Do(req)
	if err != nil {
		fmt.Printf("error: %+v\n\n", err)
	}

	defer res.Body.Close()
}

SDKがv2だと書き方が変わるため、ドキュメントや以下のような記事をご覧ください。

Credentialsについて

Rubyと同じく方法がいくつかあるので、ドキュメントをご覧ください!(ぶん投げ)

クラスメソッドさんの記事がわかりやすいです。

とりあえずリクエストだけしたいとき

そんなときは curl"--aws-sigv4" オプションを付ければ、可能らしいです。

また、awscurl というSigV4署名を付けてcurlしてくれるツールもあります。profileなどの指定が、aws cliと同じ用にできるのでらくちんです。

おわりに

IAMの理解が浅いと、Credentialの取得やAPI Gatewayのリソースポリシーの書き方などでつまずきます。僕はつまずきました。よくわかっていない方は、まずはIAMを理解するのがおすすめです!

参考

API Gatewayのリクエストではありませんが、いろいろな言語の参考になるサンプルコードです。

Pythonのサンプルコード

Node.jsのサンプルコード

Java

もしSigV4署名を自前で実装したい場合のサンプルコード

10
1
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
10
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?