Dev Study
AWSサービスの内部原理 コース

60. AWSへのリクエストは毎回署名される — SigV4のHMAC導出チェーン

AWSにAPIリクエストを送るたび、シークレットキーは一度もネットワークに流れないのに「本人だ」と証明できます。その仕組みを、リクエストの正規化からHMACの鍵導出チェーンまで図で追っていきます。

① シークレットキーは送らない

素朴な発想鍵をそのまま送る?
クライアント側で署名を作る
SigV4の発想秘密は送らず「使った計算結果」だけ送る
2つから署名(計算結果)を計算
シークレットキー手元に保持
リクエスト内容送りたい中身
AWSが保管済みの同じ鍵で同じ計算を再現
署名だけ送信鍵本体はネットワークを流れない
一致 → 通す鍵の所持を証明できた
不一致 → 拒否鍵を知らない相手
  • 公式の言い回し「You don't use your secret access key to sign API requests. Instead, you use the SigV4 signing process.」— シークレットキーそのものではなく、それを使った導出結果で署名する。
  • 「AWS then replicates this process and verifies the signature, granting or denying access accordingly.」— AWS側は同じ計算を再現して照合する。

SigV4は「秘密を送らずに、秘密の所持を証明する」仕組みで、クライアントとAWSが同じシークレットキーで同じ計算を再現し、結果の一致を鍵の所持証明とします(チャレンジレスポンス認証に通じる発想)。API Gateway編で見たTLSが「通信路そのもの」を暗号化するのに対し、SigV4はリクエスト1本ごとに誰が出したか(認証)と中身が変わっていないか(完全性)を保証し、両者は重ねて使われます。

② リクエストを正規化する(canonical request)

生のHTTPリクエストヘッダの順序・大小文字・空白がバラバラ
このままでは client と AWS で計算結果がズレる
この順に改行で連結
HTTPメソッドGET / PUT / DELETE …
正規URI/bucket/photo.jpg
正規クエリキー名で辞書順ソート
正規ヘッダ小文字・辞書順・trim
署名対象ヘッダhost;x-amz-date …
本文ハッシュHex(SHA256Hash(本文))
全体を SHA-256 でハッシュ
canonical request6要素を改行で連結した文字列
1本のハッシュ小文字16進の文字列に凝縮
  • 6要素は改行(\n)で連結する: HTTPMethod \n CanonicalURI \n CanonicalQueryString \n CanonicalHeaders \n SignedHeaders \n HashedPayload。
  • ヘッダ名は小文字化・辞書順、値は前後空白trim・連続空白を1つに。必須は host(HTTP/1.1)または :authority(HTTP/2)と、リクエストに含める全ての x-amz-* ヘッダ。Content-Type ヘッダが存在する場合はそれも含める必要がある。
  • クエリ文字列はキー名で辞書順ソート(エンコード後にソート)。
  • 本文が無いGETなどは空文字のハッシュ Hex(SHA256Hash("")) を使う。
  • S3は本文ハッシュを載せる x-amz-content-sha256 ヘッダが必須(本文が無ければ空文字のハッシュ)。

「揃った1つの形」に直す(正規化)のは、クライアントとAWSが別々に計算しても同じ入力から始めるためで、最後にリクエスト全体をSHA-256で1本のハッシュに凝縮します。SHA-256はKinesis/FIFO編で重複排除に登場した「同じ入力なら必ず同じ出力、1文字でも変われば全く別の値」のハッシュで、その性質をここでは「中身が1バイトでも書き換わったら別のハッシュになる」改ざん検知に使います。

③ string to sign を組み立てる

アルゴリズム名AWS4-HMAC-SHA256
リクエスト日時20130524T000000Z (UTC・ISO 8601)
credential scopeYYYYMMDD/region/service/aws4_request
例: 20220830/us-east-1/ec2/aws4_request
②のハッシュcanonical request のSHA-256
string to sign「署名される内容」そのもの
  • アルゴリズム名はSigV4で AWS4-HMAC-SHA256(SigV4aは AWS4-ECDSA-P256-SHA256)。
  • credential scopeのregion/service/終端文字列は小文字。終端文字列は固定で aws4_request。
  • 日時は現在のUTC時刻をISO 8601形式(例 20130524T000000Z)。
  • credential scopeは「resulting signatureを指定Regionとserviceに限定する」ためのもの、と公式が明記。

string to signは「これから署名する内容」を1つの文字列にまとめたものです。日時とcredential scope(日付/リージョン/サービス)を含めることで、この署名が「いつ・どこ・どのサービス向け」かがそのまま署名対象に焼き込まれます。

④ 署名キーをHMACの連鎖で導出する

出発点の鍵"AWS4" + シークレットキー
前段の結果を鍵に / データ=リージョン "us-east-1"
DateKey日付でスコープされた鍵
前段の結果を鍵に / データ=サービス "ec2"
DateRegionKeyリージョンまで限定
前段の結果を鍵に / データ="aws4_request"(固定)
DateRegionServiceKeyサービスまで限定
SigningKey特定の日・リージョン・サービスにしか効かない鍵
  • 各段は「前段の出力を鍵、次の要素をデータ」としてHMAC-SHA256を掛ける連鎖。公式:「The result of each call to the hash function becomes the input for the next call.」
  • 初段の鍵だけが "AWS4" + シークレットキーの連結。以降は前段の出力が鍵になる。
  • 最終段のデータは固定文字列 "aws4_request"。導出に使う入力は日付(YYYYMMDD)・リージョンコード(例 us-east-1)・サービスコード(例 ec2)。
  • HMAC(鍵付きハッシュ / メッセージ認証コード)が暗号基礎の新顔。②のSHA-256は「鍵なしハッシュ」で誰でも同じ値を計算できるが、HMACは鍵を知る者しか正しい値を出せない。「鍵を持っていることの証明」と「中身が変わっていないことの証明」を同時に成立させ、SigV4はそれを鍵の導出にも最終署名にも使う。

シークレットキーそのものは一度もHMACの「データ」側に置かず、最初の鍵材料として使うだけです。日付→リージョン→サービスと段階的に絞り込むため、出来上がるSigningKeyは「その日・そのリージョン・そのサービス」専用——万一漏れても翌日には無効で、他リージョン・他サービスには効かず、被害がスコープに限定されるのがこのチェーンの意味です。

⑤ 署名を計算してAuthorizationヘッダに載せる

SigningKey④で導出
string to sign③で組立
Authorization ヘッダに載せる
signaturebinary を小文字16進に変換
一時認証情報のとき
CredentialAKIA.../20220830/us-east-1/ec2/aws4_request
先頭にアルゴリズム名 AWS4-HMAC-SHA256
SignedHeadershost;x-amz-date
Signature計算した署名
X-Amz-Security-Tokenセッショントークンを追加
  • 最終署名は signature = HMAC-SHA256(SigningKey, string to sign)。SigV4の「最終署名はHMAC-SHA256」と公式が明記。結果はbinary→小文字16進。
  • Authorizationヘッダはアルゴリズム名とCredentialの間にカンマ無し、それ以外はカンマ区切り。
  • 認証情報はAuthorizationヘッダ、またはURLのクエリ文字列(X-Amz-Algorithm, X-Amz-Credential, X-Amz-Signature 等)でも表現できる。
  • 一時認証情報(STS発行)のときは X-Amz-Security-Token にセッショントークンを載せる。サービスによっては canonical request に含める必要があり、別のサービスでは署名計算後に付けるだけでよい——要件はサービスごとに確認。

SigningKeyでstring to signをHMAC-SHA256すれば署名の完成です。AWS側はリクエストに含まれるCredential情報から同じSigningKeyを再導出し、同じstring to signで署名を再計算して照合——一致すれば通し、しなければ拒否します。

⑥ 署名が守る3つのこと と SigV4a

なりすまし防止署名を作れる=シークレットキーの所持者
改ざん防止メソッド・パス・ヘッダ・本文が署名対象。1バイトでも変わればハッシュがズレて拒否
リプレイ防止タイムスタンプが署名に焼き込まれ、原則5分を過ぎたリクエストは拒否
SigV4aECDSA(NIST P-256)の非対称署名
1つの署名を複数リージョンで検証できる。AWSは公開鍵だけ保管すればよい
  • リプレイ防止: 公式「In most cases, a request must reach AWS within five minutes of the time stamp in the request. Otherwise, AWS denies the request.」= 原則、タイムスタンプから5分以内にAWSへ到達する必要がある。
  • 改ざん防止: 「some of the request elements are used to calculate a hash (digest) of the request」— リクエスト要素からハッシュを作り照合、不一致なら拒否。
  • なりすまし防止: 署名はアクセスキー(アクセスキーID+シークレットアクセスキー)で作る。一時認証情報ならセキュリティトークンも必要。
  • SigV4a: シークレットアクセスキーからECDSA(NIST P-256)の鍵ペアを導出。AWSは公開鍵のみ保管すればよく、公開鍵では署名を作れない。SDK/CLIがマルチリージョン署名を要する機能(S3マルチリージョンアクセスポイント等)を呼ぶと自動でSigV4aに切り替わる。アルゴリズム名は AWS4-ECDSA-P256-SHA256。

1本の署名が、鍵の所持証明(なりすまし防止)・リクエスト要素のハッシュ(改ざん防止)・タイムスタンプの5分失効(リプレイ防止)を同時に成立させます。SigV4aはこの発想を非対称鍵に拡張し、1つの署名を複数リージョンで検証できるようにしたもので、本編では位置づけの紹介にとどめます。

公式ドキュメントで詳しく ↗