これは ビットバンク株式会社 Advent Calendar 2020 の 6 日目の記事です。
はじめに
はじめまして。ビットバンクでインフラ構築や業務効率化等を担当しています Leyla です。
弊社では AWS 基盤を主に利用しますが、AWS で足りない機能を外部サービスで補う時があります。
外部サービスには公式で連携しているのが一番ですが、中には自力でなんとかしないといけないときがあります。
そんなときに ApiGateway + Lambda は外部サービスからイベント形式の処理を実行するのに便利ですが、APIGateway などで外部公開してしまうと認証認可の概念を導入しないと第三者に悪用される可能性があります。
そこで今回は外部サービスから Lambda を実行する際の認証認可について概念図を用いていくつかパターンを作成してみました。
- ノーガード戦法
- id/password
- IAM 認証(署名リクエスト)
- IAM の Credential
ノーガード戦法
Requestor は APIGateway に HTTP リクエストを送信します。
APIGateway は HTTP リクエストを受け取り、Lambda に attach されている権限を元に AWS リソースにアクセスします。
第三者にリクエスト先の URL を知られなければシンプルなアーキテクチャで見通しも良く素晴らしいと思います。
しかし軽くした開発コストの代償に無視できないセキュリティリスクがあるようです。
id/password
APIGateway は認証認可機能があり、使用することで意図していないリクエストを除外します。
Cognito はサーバーレス基盤上にユーザーの DB(UserPool)を作成することができます。
Cognito のユーザーにはユーザー名、パスワード、その他属性を付与することができます。
APIGateway のカスタム認証を用いて Cognito のユーザーに紐づいている属性を参照し、属性毎に API を許可、拒否することができます。
しかし、1 ユーザーのためだけに Cognito を使うにはアーキテクチャが壮大すぎるでしょう。
IAM 認証(署名リクエスト)
AWS の APIGateway には IAM 認証機能があり、署名付きのリクエストヘッダを付与して送信することで IAM のポリシーによる API の認証認可が可能となります。
欠点は仕組みが複雑なことと sha256 のハッシュ関数が使える環境であることです。
これがベストプラクティスのように思えるのですが、任意のヘッダ情報を付与しての HTTP リクエストが送信できない場合などは使用できません。
IAM の Credential
IAMUser には Credential(認証情報)を発行することでその IAMUser に付与されている権限を実行できる機能があります。
KMS の Decrypt 権限を含まない IAM から Credential を生成し、生成されたアカウントで KMS 共通鍵を作成した後暗号化して HTTP リクエストで送信します。
Lambda 側は KSM の Decrypt 権限を所持しており、受信した HTTP リクエストに含まれている暗号化された Credential を復号します。その後 Lambda は復号化された Credential を元にセッションを作成して IAMUser としてリクエストをします。
欠点はマネージドではなく自力で KMS から複合するロジックを実装しないといけない点と Credential をローテーションするコストがあります。
また IAM の User でセッションを作成すると CloudTrail で UserIdentity の Type が AssumedRole ではなく IAMUser になります。そのため userIdentity の arn から AssumeRole 元の名前がなくなり、AWS の Lambda から実行されていると判断するには CloudTrail の UserAgent しかなく、証跡の追跡がしづらいです。
まとめ
いかがでしたでしょうか?
どの手法にもメリットデメリットがあり、銀の弾丸はないように思えます。
外部サービス側の制約に合わせてオリジナルのアーキテクチャを組んでみましょう。