署名付き AWS API リクエストを作成する - AWS Identity and Access Management

署名付き AWS API リクエストを作成する

重要

AWS SDK (「サンプルコードとライブラリ」を参照) または AWS コマンドライン (CLI) ツール を使用して API リクエストを AWS に送信する場合、SDK および CLI クライアントが指定したアクセスキーを使用してリクエストを認証するため、このセクションをスキップできます。正当な理由がない限り、常に SDK または CLI を使用することをお勧めします。

複数の署名バージョンをサポートするリージョンでは、リクエストに手動で署名する場合、使用する署名バージョンを指定する必要があります。マルチリージョンアクセスポイントにリクエストを送信すると、SDK と CLI は Signature Version 4A の使用に自動的に切り替えます。追加の設定は不要です。

以下は、署名付きリクエストを作成するプロセスの概要です。署名を計算するには、まず署名する文字列が必要です。次に、署名キーを使用して署名する文字列の HMAC-SHA256 ハッシュを計算します。次の図は、署名用に作成する文字列のさまざまなコンポーネントを含むプロセスを示しています。


                正規リクエスト、署名する文字列、署名キー、および署名の各部分を示す画像。

次の表では、図に示されている関数について説明します。これらの関数のコードを実装する必要があります。詳細については、「AWS SDK のサンプルコード」を参照してください。

機能 説明

Lowercase()

文字列を小文字に変換します。

Hex()

16 進数の小文字エンコード。

SHA256Hash()

セキュアハッシュアルゴリズム (SHA) 暗号化ハッシュ関数。

HMAC-SHA256()

指定した署名キーで SHA256 アルゴリズムを使用して HMAC を計算します。これが最後の署名です。

Trim()

先頭または末尾の空白をすべて削除します。

UriEncode()

すべてのバイトが URI でエンコードされます。UriEncode() は、以下のルールを適用する必要があります。

  • 非予約文字 (「A」-「Z」、「a」-「z」、「0」-「9」、「-」、「.」、「_」および「~」) を除くすべてのバイトが URI でエンコードされます。

  • スペース文字は予約文字であるため、「+」ではなく「%20」としてエンコードする必要があります。

  • URI で エンコードされた各バイトは、「%」とそのバイトの 2 桁の 16 進値で構成されています。

  • 16 進値の文字は大文字である必要があります (例:「%1A」)。

  • オブジェクトキー名以外では、フォワードスラッシュ文字「/」がエンコードされます。例えば、オブジェクトキー名が photos/Jan/sample.jpg の場合、キー名のフォワードスラッシュはエンコードされません。

重要

開発プラットフォームが提供する標準の UriEncode 関数は、実装の違いや基礎となる RFC のあいまいさにより動作しない場合があります。エンコードが確実に機能するように、独自のカスタム UriEncode 関数を作成することをお勧めします。

Java での UriEncode 関数の例については、GitHub ウェブサイトで「Java Utilities」を参照してください。

注記

リクエストに署名するときは、AWS Signature Version 4 または AWS Signature Version 4A のいずれかを使用できます。これら 2 つの大きな違いを決定づけるのは、署名の計算方法です。AWS Signature Version 4A では、署名にはリージョン固有の情報は含まれず、署名の計算には AWS4-ECDSA-P256-SHA256 アルゴリズムが使用されます。

一時的な認証情報

リクエストに署名するために長期的に認証情報を使用する代わりに、AWS Security Token Service (AWS STS) から提供された一時的なセキュリティ認証情報を使用できます。

一時的なセキュリティ認証情報を使用する場合は、認証ヘッダーまたはクエリ文字列にセッショントークンを保持するように X-Amz-Security-Token を追加する必要があります。一部のサービスでは、正規リクエストに X-Amz-Security-Token を追加する必要があります。その他のサービスでは、署名の計算後に、X-Amz-Security-Token を末尾に追加するだけです。詳細については、それぞれ AWS のサービス のドキュメントを確認してください。

署名手順の概要

手順 1: 正規リクエストを作成する

リクエストのコンテンツ (ホスト、アクション、ヘッダーなど) を標準的な正規形式に変換します。正規リクエストは、署名する文字列を作成するのに使用される入力の 1 つです。詳細については、「AWS API リクエスト署名の要素」を参照してください。

手順 2: 正規リクエストのハッシュを作成する

署名キーは、最初のハッシュオペレーションのキーとして AWS のシークレットアクセスキーを使用して、リクエスト日、リージョン、およびサービスに対する一連のキー付きハッシュオペレーション (HMAC オペレーション) を実行することによって抽出します。

手順 2: 署名文字列を作成する

正規リクエストに加えてアルゴリズム、リクエスト日、認証情報スコープ、正規リクエストのダイジェスト (ハッシュ) などの追加情報を使用して、署名する文字列を作成します。

手順 4: 署名を計算する

署名キーを取得したら、署名文字列にキー付きハッシュ操作を実行することで、署名を計算します。取得した署名キーを、この操作のハッシュキーとして使用します。

手順 5: リクエストヘッダーに署名を追加します。

署名を計算したら、それをリクエストの HTTP ヘッダーまたはクエリ文字列に追加します。

手順 1: 正規リクエストを作成する

次の文字列を改行文字で区切って連結し、正規リクエストを作成します。これにより、計算する署名と AWS が計算する署名が一致することが保証されます。

<HTTPMethod>\n <CanonicalURI>\n <CanonicalQueryString>\n <CanonicalHeaders>\n <SignedHeaders>\n <HashedPayload>
  • HTTPMethod – GETPUTHEADDELETE などの HTTP メソッド。

  • CanonicalUri – 絶対パスコンポーネント URI の URI エンコード版 (ドメイン名の後の「/」から始まり、文字列の末尾まで、またはクエリ文字列パラメータがある場合は疑問符文字 (「?」) まで)。絶対パスが空値の場合は、フォワードスラッシュ文字 (/) を使用します。次の例の URI、/examplebucket/myphoto.jpg は絶対パスであるため、ユーザーは絶対パス内の「/」をエンコードしないでください。

    http://s3.amazonaws.com/examplebucket/myphoto.jpg
  • CanonicalQueryString – URI エンコードされたクエリ文字列パラメータ。それぞれの名前と値を個別に URI エンコードします。また、正規クエリ文字列内のパラメータをキー名のアルファベット順にソートする必要があります。ソートはエンコード後に行われます。次のサンプル URI のクエリ文字列は次のとおりです。

    http://s3.amazonaws.com/examplebucket?prefix=somePrefix&marker=someMarker&max-keys=2

    正規クエリ文字列は次のとおりです (この例では、読みやすいように改行が追加されています)。

    UriEncode("marker")+"="+UriEncode("someMarker")+"&"+ UriEncode("max-keys")+"="+UriEncode("20") + "&" + UriEncode("prefix")+"="+UriEncode("somePrefix")

    リクエストがサブリソースをターゲットにしている場合、対応するクエリパラメータ値は空の文字列 ("") になります。例えば、次の URI は examplebucket バケット上の ACL サブリソースを特定してします。

    http://s3.amazonaws.com/examplebucket?acl

    この場合の CanonicalQueryString は次のとおりです。

    UriEncode("acl") + "=" + ""

    URI に「?」が含まれていない場合は、リクエストにクエリ文字列が存在しないため、正規クエリ文字列を空の文字列 ("") に設定します。「\n」は引き続き含める必要があります。

  • CanonicalHeaders – リクエストヘッダーとその値のリスト。個々のヘッダー名と値のペアは改行文字 (「\n」) で区切られます。以下は正規ヘッダーの例です。

    Lowercase(<HeaderName1>)+":"+Trim(<value>)+"\n" Lowercase(<HeaderName2>)+":"+Trim(<value>)+"\n" ... Lowercase(<HeaderNameN>)+":"+Trim(<value>)+"\n"

    CanonicalHeaders リストには以下が含まれている必要があります。

    • HTTP host ヘッダー。

    • Content-Type ヘッダーがリクエスト内に存在する場合は、それを CanonicalHeaders リストに追加する必要があります。

    • リクエストに含める予定の x-amz-* ヘッダーも追加する必要があります。例えば、一時的なセキュリティ認証情報を使用している場合は、リクエストに x-amz-security-token を含める必要があります。このヘッダーを CanonicalHeaders リストに追加する必要があります。

    注記

    x-amz-content-sha256 ヘッダーは Amazon S3 AWS リクエストに必要です。これにより、リクエストペイロードのハッシュが指定されます。ペイロードがない場合は、空の文字列のハッシュを指定する必要があります。

    各ヘッダー名は次の条件を満たす必要があります。

    • 小文字が使用されていること。

    • アルファベット順に表示されていること。

    • 後にコロン (:) が指定されていること。

    値については、次の操作を行う必要があります。

    • 先頭または末尾のスペースをすべて削除する。

    • 連続するスペースを 1 つのスペースに変換する。

    • 複数値ヘッダーの値をカンマで区切る。

    • host ヘッダー (HTTP/1.1) または :authority  ヘッダー (HTTP/2)、および任意の x-amz-* ヘッダーを署名に含める必要があります。署名には、content-type のような他の標準ヘッダーを指定することもできます。

    この例で使用されている関数 Lowercase() と Trim() は、前のセクションで説明されています。

    以下は CanonicalHeaders 文字列の例です。ヘッダー名は小文字で、ソートされています。

    host:s3.amazonaws.com x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date:20130708T220855Z

    注記

    認証署名を計算する目的では、host ヘッダーと任意の x-amz-* ヘッダーだけが必要です。ただし、データの改ざんを防ぐために、すべてのヘッダーを署名計算に含めることを検討する必要があります。

  • SignedHeaders – アルファベット順にソートされ、セミコロンで区切られた小文字のリクエストヘッダー名のリスト。リスト内のリクエストヘッダーは、CanonicalHeaders 文字列に含めたヘッダーと同じです。例えば、前の例の場合、SignedHeaders の値は次のようになります。

    host;x-amz-content-sha256;x-amz-date
  • HashedPayload — HTTP リクエスト本文のペイロードをハッシュ関数への入力として使用して作成された文字列。この文字列には小文字の 16 進数文字を使用します。

    Hex(SHA256Hash(<payload>)

    リクエストにペイロードがない場合は、空の文字列のハッシュを次のように計算します。

    Hex(SHA256Hash(""))

    ハッシュは次の値を返します。

    e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

    例えば、PUT リクエストを使用してオブジェクトをアップロードする場合、本文にオブジェクトデータを指定します。GET リクエストを使用してオブジェクトを取得する場合、空の文字列ハッシュを計算します。

手順 2: 正規リクエストのハッシュを作成する

ペイロードのハッシュを作成する際に使用したのと同じアルゴリズムを使用して、正規リクエストのハッシュ (ダイジェスト) を作成します。正規リクエストのハッシュは、小文字の 16 進数文字の文字列として表す必要があります。

手順 3: 署名文字列を作成する

次の文字列を改行文字で区切って連結して、文字列を作成します。この文字列は改行文字で終わらせないようにしてください。

Algorithm \n RequestDateTime \n CredentialScope \n HashedCanonicalRequest
  • Algorithm — 正規リクエストのハッシュを作成するために使用されるアルゴリズム。SHA-256 では、アルゴリズムは AWS4-HMAC-SHA256 です。

  • RequestDateTime — 認証情報のスコープで使用される日付と時刻。この値は、ISO 8601 形式の現在の UTC 時刻です (例: 20130524T000000Z)。

  • CredentialScope — 認証情報のスコープ。これにより、生成される署名は指定されたリージョンとサービスに制限されます。文字列の形式は YYYYMMDD/region/service/aws4_request です。

  • HashedCanonicalRequest — 正規リクエストのハッシュ。この値はステップ 2 で計算されます。

以下は署名する文字列の例です。

"AWS4-HMAC-SHA256" + "\n" + timeStampISO8601Format + "\n" + <Scope> + "\n" + Hex(SHA256Hash(<CanonicalRequest>))

手順 4: 署名を計算する

AWS Signature Version 4 では、リクエストの署名に AWS アクセスキーを使用するのではなく、リクエストに追加する認証情報として、特定のリージョンとサービスにスコープされた署名キーを作成します。

DateKey = HMAC-SHA256("AWS4"+"<SecretAccessKey>", "<YYYYMMDD>") DateRegionKey = HMAC-SHA256(<DateKey>, "<aws-region>") DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>, "<aws-service>") SigningKey = HMAC-SHA256(<DateRegionServiceKey>, "aws4_request")

リージョン文字列のリストについては、「AWS 全般のリファレンス」の「リージョンのエンドポイント」を参照してください。

各ステップで、必要なキーとデータを使用してハッシュ関数を呼び出します。ハッシュ関数を呼び出すたびに、その結果はハッシュ関数への次の呼び出しの入力になります。

入力必須
  • シークレットアクセスキーを含む文字列 Key

  • 認証情報の範囲で使用される日付を含んだ YYYYYMMDD 形式の文字列 Date

  • リージョンコードを含む文字列 Region (例: us-east-1)

  • サービスコードを含む文字列 Service (例: ec2)

  • 上記の手順で作成したトピックを選択します。

署名を計算するには
  1. 「AWS4」とシークレットアクセスキーを連結します。データとしてのキーおよび日付文字列として、連結した文字列を備えたハッシュ関数を呼び出します。

    kDate = hash("AWS4" + Key, Date)
  2. データとしてのキーおよびリージョン文字列として、前回の結果を備えたハッシュ関数を呼び出します。

    kRegion = hash(kDate, Region)
  3. データとしてのキーおよびサービス文字列として、前回の結果を備えたハッシュ関数を呼び出します。

    kService = hash(kRegion, Service)
  4. データとしてのキーおよび「aws4_request」として、前回の結果を備えたハッシュ関数を呼び出します

    kSigning = hash(kService, "aws4_request")
  5. データとしての署名用キーおよび文字列として、前回の結果を備えたハッシュ関数を呼び出します。その結果、署名はバイナリ値になります。

    signature = hash(kSigning, string-to-sign)
  6. 署名を 2 進数から 16 進数表現に、小文字に変換します。

手順 5: リクエストヘッダーに署名を追加します。

例: 認証ヘッダー

以下の例は、DescribeInstances アクションに対する Authorization ヘッダーを示しています。読みやすいように、この例では改行でフォーマットされています。コードでは、これは連続した文字列である必要があります。アルゴリズムと Credential の間にカンマはありません。ただし、他の要素はカンマで区切られている必要があります。

Authorization: AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20220830/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=calculated-signature
例: クエリ文字列に認証パラメータを含むリクエスト

次の例は、認証情報を含む DescribeInstances アクションのクエリを示しています。読みやすいように、この例は改行でフォーマットされており、URL はエンコードされていません。コードでは、クエリ文字列は URL エンコードされた連続した文字列である必要があります。

https://ec2.amazonaws.com/? Action=DescribeInstances& Version=2016-11-15& X-Amz-Algorithm=AWS4-HMAC-SHA256& X-Amz-Credential=AKIAIOSFODNN7EXAMPLE/20220830/us-east-1/ec2/aws4_request& X-Amz-Date=20220830T123600Z& X-Amz-SignedHeaders=host;x-amz-date& X-Amz-Signature=calculated-signature

AWS SDK 内のソースコード

AWS SDK には、AWS API リクエストに署名する方法を示す GitHub のソースコードが含まれています。コードの例については、「AWS サンプルリポジトリ内のプロジェクト例」を参照してください。