概要
社内のシステムどうしをつなぐ API や、取引先の AWS アカウントからだけ呼ばせたい API では、「インターネットの誰でも呼べる」状態は困ります。Amazon API Gateway の REST API には、呼び出し元を絞る方法がいくつかあります。
呼び出し元が IAM のユーザーやロールなら、メソッドの認可を IAM 認可(AWS_IAM) にして、リクエストに Signature Version 4(SigV4) の署名を付けさせ、さらに API のリソースポリシーで呼んでよいプリンシパルを指定します。別の AWS アカウントの IAM ユーザーに限定したい場合も、この組み合わせを使います。
この記事では、API Gateway の認可の種類と、IAM 認可とリソースポリシーがどう組み合わさるか(同じアカウントと別アカウントの違い)を整理します。実践では、IAM 認可を有効にした API を、リソースポリシーで許可したロールからは呼べて、ほかのロールや署名なしのリクエストからは呼べないことを確かめます。

クラウドおさる門をくぐるには通行手形(署名)を見せ、さらに門の内側に貼った名簿(リソースポリシー)に名前が載っていなければならぬ。今日はその二重の関所を作るでござるよ。
この記事のメリット
- API Gateway の REST API の認可の種類(IAM、Cognito ユーザープール、Lambda オーソライザー)を使い分けられるようになる
- IAM 認可と SigV4 署名の関係を説明できるようになる
- リソースポリシーで、API を呼べるプリンシパルを指定できるようになる
- 同じアカウントと別のアカウントで、IAM ポリシーとリソースポリシーの評価がどう違うかが分かる
執筆者とキャラクター紹介
執筆者:土肥(とひ)
株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。


クラウドおさる



はじめましてでござる。弊猿はクラウドおさる。IT インフラが異常に発達した猿山から、雲に乗って地上の AWS を学びに降りてきたのでござる。



基礎編や Cloud Practitioner の記事では、とひさんに素朴な疑問をぶつける役でござるな。Security - Specialty などの記事では、要所でワンポイントや注意点をひとこと添えるでござる。



猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。
技術解説
REST API の認可の種類
| 認可 | 呼び出し元 | 呼び出し元がやること |
|---|---|---|
IAM 認可(AWS_IAM) | IAM ユーザー・ロール(別アカウントも可) | リクエストに SigV4 で署名する |
Cognito ユーザープールオーソライザー(COGNITO_USER_POOLS) | Cognito ユーザープールのユーザー | ID トークンまたはアクセストークンをヘッダーに付ける |
| Lambda オーソライザー | 独自のトークンや認証方式を使うユーザー | Lambda が検証できるトークンなどを付ける |
呼び出し元が IAM のユーザーやロールなら、IAM 認可を使います。Cognito のユーザープールや ID プールに IAM ユーザーを「追加」することはできないので、Cognito のオーソライザーで IAM ユーザーに限定するのは筋違いです。
SigV4 の署名
IAM 認可にしたメソッドは、AWS の認証情報(アクセスキー・シークレットキー・セッショントークン)で SigV4 の署名を付けたリクエストしか受け付けません。署名の無いリクエストには 403 と {"message":"Missing Authentication Token"} が返ります。
署名は SDK や AWS CLI が自動で付けるほか、curl の --aws-sigv4 オプションでも付けられます。署名に使った認証情報のプリンシパル(どの IAM ユーザー・ロールか)が、そのまま認可の判断に使われます。
リソースポリシーと IAM ポリシーの組み合わせ
API Gateway のリソースポリシーは、API 側に付けるポリシーで、「どのプリンシパルが、どの API・メソッドを呼んでよいか」を書きます。IAM 認可と組み合わせたときの評価は、呼び出し元が同じアカウントか別のアカウントかで変わります。
| 呼び出し元 | 許可されるための条件 |
|---|---|
| API と同じアカウント | 呼び出し元の IAM ポリシーまたはリソースポリシーのどちらかで許可されていればよい(明示的な拒否が無いこと) |
| 別のアカウント | 呼び出し元の IAM ポリシーとリソースポリシーの両方で許可されている必要がある |
別のアカウントの IAM ユーザーだけに API を開くなら、次の 2 つをそろえます。
- API 側: メソッドを IAM 認可にし、リソースポリシーで相手アカウントの IAM ユーザー(
arn:aws:iam::<相手のアカウントID>:user/<ユーザー名>)にexecute-api:Invokeを許可する - 相手側: その IAM ユーザーに、API の ARN への
execute-api:Invokeを許可する IAM ポリシーを付け、SigV4 で署名して呼ぶ





同じ山の猿なら「通行手形」か「門の名簿」のどちらかで通れるが、よその山の猿は両方そろわねば通れぬのでござる。試験では、この「または」と「かつ」の違いを取り違えやすいでござるぞ。
リソースポリシーの書き方
リソースポリシーは JSON で書き、Resource に API の ARN(execute-api:/<ステージ>/<メソッド>/<リソースパス> の形で、コンソールでは API の部分を省略して書けます)を指定します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:role/dva-api-allowed-role" },
"Action": "execute-api:Invoke",
"Resource": "execute-api:/*"
}
]
}リソースポリシーを変えたら、API をデプロイし直すまで反映されません。
実践
用意済みの REST API dva-iam-api(GET /hello を Lambda につないだ API。認可は「なし」)を、IAM 認可に変えます。リソースポリシーで dva-api-allowed-role だけを許可し、3 つの呼び出し方で結果が変わることを CloudShell で確かめます。
今回はアカウントを 1 つしか使わないので、「別のアカウントの IAM ユーザー」の代わりに、同じアカウントの 2 つのロールで試します。どちらのロールにも execute-api:Invoke を許可する IAM ポリシーは付けていないので、許可はリソースポリシーだけで決まります。
前提条件
- リージョン:
ap-northeast-1(東京) - 以下のリソースが作成済みであること
まだ用意していない場合は、「作り方の参考」の記事の手順で作れます。リソース名は、この記事の名前に読み替えてください。
| リソース種別 | リソース名 | 内容 | 作り方の参考 |
|---|---|---|---|
| Lambda 関数 | dva-iam-api-fn | 呼び出し元の ARN(requestContext.identity.userArn)を返す | AWS Lambda で関数を作成しイベント駆動で実行する |
| REST API | dva-iam-api | リソース /hello の GET を dva-iam-api-fn に Lambda プロキシ統合。認可は「なし」。ステージ dev にデプロイ済み | Amazon API Gateway で REST API を作成しリクエストを処理する |
| IAM ロール | dva-api-allowed-role / dva-api-other-role | このアカウントから引き受けられるロール。どちらも権限のポリシーは無し | AWS IAM でユーザー・ロール・ポリシーを作成しアクセス制御する |
作成するリソース一覧
| リソース種別 | リソース名 | 用途 |
|---|---|---|
| リソースポリシー | (dva-iam-api に設定) | dva-api-allowed-role にだけ呼び出しを許可する |
手順 1: メソッドの認可を IAM にする
AWS マネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。上部の検索バーに API Gateway と入力し、「API Gateway」を選択します。
API の一覧から dva-iam-api を開きます。「リソース」で /hello の GET を選択し、「メソッドリクエスト」タブの「メソッドリクエストの設定」で「編集」をクリックします。「メソッドリクエストを編集」の画面で、「認可」を「なし」から AWS IAM に変えて「保存」をクリックします。


手順 2: リソースポリシーを設定する
左側ナビゲーションの「リソースポリシー」を選択し、「ポリシーを作成」をクリックします。次のポリシーを入力します。<アカウントID> は自分のアカウント ID に置き換えます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::<アカウントID>:role/dva-api-allowed-role" },
"Action": "execute-api:Invoke",
"Resource": "execute-api:/*"
}
]
}

「変更を保存」をクリックします。保存すると、Resource の execute-api:/* は arn:aws:execute-api:ap-northeast-1:<アカウントID>:<api-id>/* の完全な ARN に展開されて表示されます。続けて「リソース」に戻り、「API をデプロイ」をクリックして、ステージ dev を選んで「デプロイ」をクリックします。認可の変更もリソースポリシーも、デプロイして初めて反映されます。デプロイの直後は古い設定のまま応答することがあるので、次の手順は 30 秒ほど待ってから試します。
手順 3: 署名なしで呼ぶ
コンソール上部の CloudShell のアイコンから CloudShell を開きます。API の URL を変数に入れて、署名を付けずに呼び出します。<api-id> は API の一覧の「ID」で確認できます。
URL=https://<api-id>.execute-api.ap-northeast-1.amazonaws.com/dev/hello
curl -s -w '\n%{http_code}\n' $URL{"message":"Missing Authentication Token"} と 403 が返ります。IAM 認可のメソッドは、署名の無いリクエストを受け付けません。
手順 4: 許可したロールで署名して呼ぶ
dva-api-allowed-role を引き受けて一時的な認証情報を取り、curl の --aws-sigv4 で署名して呼び出します。
ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
read AK SK ST < <(aws sts assume-role \
--role-arn arn:aws:iam::$ACCOUNT:role/dva-api-allowed-role \
--role-session-name handson \
--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' --output text)
curl -s -w '\n%{http_code}\n' $URL \
--aws-sigv4 "aws:amz:ap-northeast-1:execute-api" \
--user "$AK:$SK" -H "x-amz-security-token: $ST"200 と、"caller" に dva-api-allowed-role を引き受けたセッションの ARN が入った応答が返ります。


手順 5: 許可していないロールで署名して呼ぶ
同じ手順で、dva-api-other-role を引き受けて呼び出します。
read AK SK ST < <(aws sts assume-role \
--role-arn arn:aws:iam::$ACCOUNT:role/dva-api-other-role \
--role-session-name handson \
--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' --output text)
curl -s -w '\n%{http_code}\n' $URL \
--aws-sigv4 "aws:amz:ap-northeast-1:execute-api" \
--user "$AK:$SK" -H "x-amz-security-token: $ST"署名は正しいのに、403 と、このロールが execute-api:Invoke を実行する権限を持っていない旨のメッセージ(... is not authorized to perform: execute-api:Invoke ...)が返ります。dva-api-other-role には IAM ポリシーでの許可も、リソースポリシーでの許可も無いためです。





手形の無い者は門前払い、手形があっても名簿に無ければやはり門前払い。名簿に載った者だけが通れたでござる。よその山の猿を通すときは、相手の山でも「この門をくぐってよい」と書いてもらう、と覚えておくでござるよ。
まとめ
| 呼び出し元 | 使う認可 |
|---|---|
| IAM ユーザー・ロール(別アカウントを含む) | IAM 認可(AWS_IAM)+ SigV4 署名 + リソースポリシー |
| Cognito ユーザープールのユーザー | Cognito ユーザープールオーソライザー(トークンをヘッダーに付ける) |
| 独自のトークン・認証方式 | Lambda オーソライザー |
- IAM 認可のメソッドは SigV4 で署名したリクエストだけを受け付ける。署名が無いと
Missing Authentication Token(403) - リソースポリシーで、API を呼べるプリンシパルを指定できる。変更は API の再デプロイで反映される
- 同じアカウントの呼び出し元は、IAM ポリシーかリソースポリシーのどちらかで許可されればよい
- 別のアカウントの呼び出し元は、IAM ポリシーとリソースポリシーの両方で許可されている必要がある
- Cognito のユーザープールや ID プールに IAM ユーザーを追加して認可することはできない
参照先
- API Gateway で REST API へのアクセスを制御および管理する – Amazon API Gateway
- IAM アクセス許可を使用して REST API へのアクセスを制御する – Amazon API Gateway
- API Gateway リソースポリシーを使用して REST API へのアクセスを制御する – Amazon API Gateway
- API Gateway リソースポリシーが認可ワークフローに与える影響 – Amazon API Gateway
- AWS API リクエストに対する Signature Version 4 – AWS Identity and Access Management














