API Gateway の REST API を特定の IAM プリンシパルだけに制限する方法 ── IAM 認可とリソースポリシー

目次

概要

社内のシステムどうしをつなぐ API や、取引先の AWS アカウントからだけ呼ばせたい API では、「インターネットの誰でも呼べる」状態は困ります。Amazon API Gateway の REST API には、呼び出し元を絞る方法がいくつかあります。

呼び出し元が IAM のユーザーやロールなら、メソッドの認可を IAM 認可(AWS_IAM) にして、リクエストに Signature Version 4(SigV4) の署名を付けさせ、さらに API のリソースポリシーで呼んでよいプリンシパルを指定します。別の AWS アカウントの IAM ユーザーに限定したい場合も、この組み合わせを使います。

この記事では、API Gateway の認可の種類と、IAM 認可とリソースポリシーがどう組み合わさるか(同じアカウントと別アカウントの違い)を整理します。実践では、IAM 認可を有効にした API を、リソースポリシーで許可したロールからは呼べて、ほかのロールや署名なしのリクエストからは呼べないことを確かめます。

IAM 認可 + リソースポリシー:名簿に載ったロールの署名付きリクエストだけが通る
IAM 認可 + リソースポリシー:名簿に載ったロールの署名付きリクエストだけが通る
クラウドおさる

門をくぐるには通行手形(署名)を見せ、さらに門の内側に貼った名簿(リソースポリシー)に名前が載っていなければならぬ。今日はその二重の関所を作るでござるよ。

この記事のメリット

  • 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 つをそろえます。

  1. API 側: メソッドを IAM 認可にし、リソースポリシーで相手アカウントの IAM ユーザー(arn:aws:iam::<相手のアカウントID>:user/<ユーザー名>)に execute-api:Invoke を許可する
  2. 相手側: その 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 をデプロイし直すまで反映されません。

新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

実践

ハンズオンガイド7 ステップ画面 4 枚

コンソールの横に開いて、チェックしながら進めましょう。

ガイドを開く

別タブで開きます。チェックはこのブラウザに保存されます。

用意済みの 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 APIdva-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 に変えて「保存」をクリックします。

メソッドリクエストの設定画面(認可に AWS IAM を選択した状態)
メソッドリクエストの設定画面(認可に 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:/*"
        }
    ]
}
リソースポリシーの編集画面(dva-api-allowed-role に execute-api:Invoke を許可)
リソースポリシーの編集画面(dva-api-allowed-role に execute-api:Invoke を許可)

「変更を保存」をクリックします。保存すると、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 が入った応答が返ります。

CloudShell の実行結果(署名なしは 403、許可したロールの署名付きは 200)
CloudShell の実行結果(署名なしは 403、許可したロールの署名付きは 200)

手順 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 ポリシーでの許可も、リソースポリシーでの許可も無いためです。

CloudShell の実行結果(許可していないロールの署名付きは 403)
CloudShell の実行結果(許可していないロールの署名付きは 403)
クラウドおさる

手形の無い者は門前払い、手形があっても名簿に無ければやはり門前払い。名簿に載った者だけが通れたでござる。よその山の猿を通すときは、相手の山でも「この門をくぐってよい」と書いてもらう、と覚えておくでござるよ。

まとめ

呼び出し元使う認可
IAM ユーザー・ロール(別アカウントを含む)IAM 認可(AWS_IAM)+ SigV4 署名 + リソースポリシー
Cognito ユーザープールのユーザーCognito ユーザープールオーソライザー(トークンをヘッダーに付ける)
独自のトークン・認証方式Lambda オーソライザー
  • IAM 認可のメソッドは SigV4 で署名したリクエストだけを受け付ける。署名が無いと Missing Authentication Token(403)
  • リソースポリシーで、API を呼べるプリンシパルを指定できる。変更は API の再デプロイで反映される
  • 同じアカウントの呼び出し元は、IAM ポリシーかリソースポリシーのどちらかで許可されればよい
  • 別のアカウントの呼び出し元は、IAM ポリシーとリソースポリシーの両方で許可されている必要がある
  • Cognito のユーザープールや ID プールに IAM ユーザーを追加して認可することはできない

参照先

キャリア相談
クラウドおさる

独学の先に、AWS の仕事がある ── ジュニアおさるのキャリア相談

CLF には受かったけれど、次に何をすればいいのか分からない。独学で AWS を学ぶジュニアおさるの相談に、株式会社ジェニュイン代表の土肥が答えています。

  • ✓資格はゴールか、CLF の次に何から手を付けるか
  • ✓EC2 の次に作ってみる構成と、IaC・コスト管理
  • ✓実務経験ゼロでも、面接で話せる「これまで」の作り方
新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

株式会社ジェニュイン(https://genuine-pt.jp)の代表取締役.

2018年〜インフラエンジニアとしてキャリアをスタートし、オンプレミスのネットワーク・サーバ環境で3年半、クラウド環境で4年半の8年間エンジニアとして従事。
2021年に佐藤氏の創業した株式会社Luxyを引き継ぎ、代表に就任。
その後アガルートグループ内の株式会社ジェニュインと合併。
合併後同社代表に就任。

目次