API Gateway の REST API を特定の IAM プリンシパルだけに制限する方法 ── IAM 認可とリソースポリシー
記事の「実践」を 1 項目ずつ進めるためのページです。AWS マネジメントコンソールで操作したら、右の一覧にチェックを入れてください。チェックはこのブラウザに保存されます。
前提条件
- リージョン:
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 ポリシーでの許可も、リソースポリシーでの許可も無いためです。