サーバーレスアーキテクチャにおけるセキュリティの2つの質問

清水崇之氏(以下、清水):では3つ目の相談にいきたいと思います。いただいた質問・相談が「サーバーレスアーキテクチャにおけるセキュリティについて」という非常にざっくりしたものになっているんですが、今回はサーバーレスのセキュリティというテーマなので、AWSの考えるサーバーレスのセキュリティについてまずはお話ししようと思います。

下川賢介氏(以下、下川):(スライドを示して)「AWS Lambda/責任共有モデル」とタイトルに書いてありますが、実はこの前にEC2とかVMベースの責任共有モデルも公開されています。それと見比べてもらうと、黄色のAWSが管理している範囲がLambdaの場合は多くなっています。

例えばプラットフォームの管理とか、オペレーティングシステムやネットワークの設定の管理、そういった黄色で着色されている部分は、AWSのマネージドな環境が提供されています。

では、お客さまの管理すべきものは何なのかと言うと、上の青色の枠で囲われているブロックです。このあたりが、お客さまが自分自身で管理する部分になります。

例えばアプリケーションのアイデンティティとアクセス。認証・認可をどう作るかみたいなところとか、あとはアプリケーションの管理。そもそもソースコードなどはAWSが提供するわけにはいかないので、アプリケーションのソースコードやデプロイのアーティファクトみたいなものも、お客さまが提供することになります。

あとはオブザーバビリティみたいなところですね。モニタリングやログの記録というところも、お客さまのほうで標準出力する仕掛けは必要かなと思います。

清水:ありがとうございます。では、TECH PLAYさんから今回の相談について話ししてもらえますでしょうか。

鈴木康広氏(以下、鈴木):はい。実はTECH PLAYは、実はもう8年とか9年とか運用しているサービスなんですが、けっこうモノリシックなアーキテクチャの上で長年運用されてきました。今裏側で、中村(中村航也氏)などが中心になって少し大きめのプロジェクトを動かしています。これを例えばユーザーサイドとか管理機能といった感じの機能ごとに切り分ける。

さらにその中でも、先ほどもありましたが、フロントエンドとバックエンドをきちんと切り離して運用していこうというようなプロジェクトが進行している最中です。バックエンドとかについては、管理機能で一部サーバーレスアーキテクチャを導入できるんじゃないかと考えています。

管理機能というところなので、お客さまは登録してもらった情報を見ることができたり、運営されるイベントの情報が見えたりするので、けっこうセンシティブな領域だと思っています。

ここでユーザーの個人情報、お預かりしている情報などが不正なアクセスによって流出するということは、絶対に避けたいと考えています。

まだ実装をガリガリ進めるフェーズではありませんが、どんなかたちでやっていくかを、中村に簡単に設計してもらいました。じゃあここから中村さん、いいですか?

中村航也氏(以下、中村):現在弊社で構築予定のサーバーレスアーキテクチャのシステムについて、TECH PLAYの中村からお伝えします。(スライドを示して)先ほど説明にあったFargateを使ったサービスとは異なり、こちらは完全にTECH PLAYの社内の人間が使用する、バックオフィス用のシステムのアーキテクチャ図です。

こちらのバックオフィス用のシステムは深夜や休日にはまったく使用されることはなく、またユーザー数も多く見積もって数十人程度と非常に小規模なものであるため、サーバーレスアーキテクチャがマッチしているのではないかとみて導入を考えています。

構成としてはオーソドックスなサーバーレスアプリケーションとなっていて、フロントエンドはReact.jsで実装し、S3のバケットにアップロードして静的なファイルをCloudFrontで公開するような実装になっています。バックエンドは、API Gatewayを経由してLambda関数を呼び出すような構成になっています。

先ほど説明があったとおり、一部のLambda関数はAurora DBに保存されているユーザー情報など、非常に機密性の高い情報にアクセスするような構成になっています。

先ほどのスライドから、バックエンドに注目して説明します。

こちらのバックエンドについては、大きく3種類のユーザーに分けてアクセスを制限しようと考えています。まず、右の図の一番上に記載されている管理ユーザーはいわゆるadmin権限を持つユーザーであり、ユーザー情報などの機密性の高い情報を取り扱うLambda関数を含め、すべてのLambda関数にアクセス可能にしたいです。

上から2番目の運用者はそれ以外の社内ユーザーであり、日常的な業務で機密性の高い情報にアクセスする必要がないため、そのような情報を取り扱うLambda関数にはアクセスできなくして、それ以外のLambda関数にはアクセス可能にしたいです。

図の一番下に書いてある3番目の不正なユーザーは、完全に外部の悪意を持ったユーザーであり、このユーザーにはあらゆる情報の参照や改ざんを行えないようにする必要があるため、すべてのLambda関数にアクセスできないようにしたいです。3番目の不正なユーザーにアクセスされてしまうと情報が不正に流出したりするので、絶対に防ぎたいところです。

そこで、今回はこのアーキテクチャについて2点相談させてください。1つ目は、管理者や運用者以外の不正なユーザーからのアクセスを防止するアーキテクチャにはどのようなものが最適かということで、サーバーレスと親和性の高い認証基盤を提供するソリューションがあれば教えていただきたいです。

2つ目は、管理者と運用者それぞれにできること・できないこと(ロール)を割り当てたい場合、どのように実現するのがよいか。先ほどお伝えしたとおり、管理者は機密性の高い情報を含むすべてのLambda関数にアクセス可能、運用者はそれ以外のLambda関数にアクセス可能な状態にするにはどうすればよいのか。以上2点について相談させてください。

清水:ありがとうございます。

下川:今2つの質問が来ていますが、上は恐らく認証の話かなと思っています。認証されていないユーザーをここでは不正なユーザーと呼んでいて、認証、アイデンティティが特定されているようなユーザーを、管理者か運用者というところで割り当てているのかなと思います。

下の質問は、認証されているユーザーがいる上で、そのユーザーが取れる行動の範囲、アクションの範囲というかアクセスできるリソースの範囲なので、こちらが認可の話かなと思います。なので、認証と認可の2つの質問をいただいているように思えます。

ここでいうと、Lambda、アクセスパターンに×が描かれているリソースと×が描かれていないリソースとがありますが、どのLambdaにアクセスできるかというのが認可の話です。そもそもこのAPIが呼び出せるかどうかは認証の話です。それを理解した上で、先ほどのAPI Gatewayにはどんな認証があるのかという話に入りたいと思います。

Cognitoオーソライザーを活用した認証

実はAPI GatewayのAPI設定で、認証・認可の設定ができます。今日はAPI Gatewayの詳しい中身まではなかなかお話しできませんが、API GatewayはRESTとWeb SocketとHTTP APIという、3つのプロトコルをサポートしています。(スライドを示して)今日はこの中の一番左のRESTプロトコルに絞ってお話しします。

RESTの場合、オーソライザーという認証・認可を司るような機能にアタッチできて、(そこで)いろいろなオーソライザーがアタッチできます。1つは1番と書かれているIAMです。2番目がLambdaオーソライザー、3番目がCognitoオーソライザーです。

今日は1つずつ詳しく説明できませんが、3番目のCognitoオーソライザーが今日はマッチしそうなので、これを中心に話そうと思います。

これがどんなものなのか。まずはCognitoというサービスが何かというところですが、これはユーザーのアイデンティティ情報を管理する、IdPを司るようなものです。例えばユーザーがログインする時に照らし合わせるようなIDとパスワードを管理するといった機能を持っています。

ここでIDとパスワードを登録しておくと、それだけで認証行為をユーザーに提供することができ、その認証をパスすると「認証OKです」というようなトークンが払い出されます。そのトークンをもってCognitoと統合されたAPI Gatewayのエンドポイントにアクセスすると、「認証OKですね」とパスできます。これがCognitoオーソライザーです。なので、認証だけでよければCognitoオーソライザーの機能でいけます。

認可までやりたい場合はIAMアクセス権限を活用するのがおすすめ

下川:ここから深い話になりますが、実はCognitoにはもう1つ機能があり、ユーザーごとにグループを組むことができます。先ほど管理者や運用者というようなパターンが出てきましたが、例えば田中さんや伊藤さんが管理者で、鈴木さんや佐藤さんが運用者というかたちでユーザーのグループを組むことができて、ユーザーのグループごとにロール(権限)を与えることができます。

権限を与えると、その権限ごとにIAM権限、これもAWSの言葉で恐縮ですが、IAMの権限を割り振ることができます。なので1番に行って、IAMのアクセス権限で、そのパーミッション(許可)が割り当てられたロールを司るリクエストなら裏側のLambdaに通すというリクエストパターンを作ることができます。

なので、認証だけであればCognitoオーソライザーで、認証・認可までやりたければ1番のIAMアクセス権限でやっていくのがいいんじゃないかなと思いました。いずれにせよ、Cognitoというサービスを使って、API Gatewayと連携させて使うのがいいんじゃないかと思います。

ちなみに今は、認証機能は何で作られようとしているのかなど、何か想定はありますか。

中村:そうですね。今は完全にモノリシックなサービスで、Aurora DBにユーザー情報とIDパスワードが入っているところと疎通するような構成になるということは想定はしたんですけれど。

下川:なるほど。今後もそのデータベースに入っているIDとパスワードの突合でログインさせるような機能を継続していく感じですかね?

中村:それもありますし、完全にバックオフィスの機能なので、Cognitoに移管してしまうと言うのもあります。

下川:わかりました。そうですね。もしマネージドにそういったアイデンティティの管理をしていきたいのであればCognitoを使ってもらうとか。

先ほどスキップしましたが、2番のLambdaオーソライザーという機能があって、今日は深くサービスを紹介する回ではありませんが、これはちょっと言っておかないといけないと思いました。

Lambdaオーソライザーとは何かと言うと、API Gatewayがリクエストを受けるとバックエンドサービス、例えばバックエンドのLambdaにつなげる前に、API Gateway自体が認証・認可のためのLambda関数を起動することができます。これをLambdaオーソライザーと呼びます。そのLambdaの中で何をやるかと言うと、誰がどこにアクセスしようとしているかを見て、本当にそのアイデンティティがアクセスしていいのかを検証できます。

検証先はどこにあるかと言うと、Lambdaから、例えばデータベースを覗いてそこに一致するユーザーがいるのかを見てもらって、一致すればバックエンドに通す、一致しなければ通さないという機能を、2番はカスタムで実装できます。これをLambdaオーソライザーといいます。

データベースで独自の認証を作っていく場合には、2番が該当するのではないかと思います。情報量が多くなってしまって恐縮なのですが。

福井厚氏(以下、福井):そうですね。

Cognitoオーソライザーでのユーザーの追加・削除

福井:何かそのあたりで不明点があれば質問いただければと思います。

中村:Cognitoオーソライザーは、ユーザーの追加や削除はどういったかたちで実行できますか。

福井:いわゆるIdPのユーザーの追加・削除ということでよいですか?

中村:そうです。認証に使うユーザー。

福井:それについてはAPIが用意されているので、そのAPIを呼び出せばユーザーの追加や削除が行えるし、ユーザー自身が自分を登録させることもできます。その際に2段階認証や多要素認証を使って認証させることもできるようになっています。

中村:ということは、CognitoのAPIを適切に呼び出すような作りにしておけば、変な話、アプリケーション上で他のユーザーの権限や新しいアカウントを作ったり削除したりも(できるということですか)。

福井:できます。

ユーザー管理はスタックを分けるのがおすすめ

中村:先ほどの話に関連すると思うんですが、CognitoもSAMで管理することができますか?

下川:そうですね。CognitoもCloud Formationで管理できるリソースになっているので、同じようにAWS SAMでもテンプレートに記述することはできます。

中村:仮にAWS SAMでデプロイして、そのデプロイしたものを削除した時に、ユーザー情報だけ残すといった使い方もできますか?

下川:削除というのはCognitoのユーザーの削除ですか?

中村:SAMのリソース一式を削除した時に、ユーザー情報が巻き込まれて一緒に削除されてしまうことは避けたいんですけれど。

下川:なるほど。そうですね、それは消えてしまいますね。

福井:消えてしまいますね。

下川:プラクティスが2つあって、1つはアプリケーション。Lambdaの開発サイクルはすごく高い頻度でリリース・デプロイされるものだと思うんですが、そのスタックとCognitoや認証基盤みたいなもののスタックは分けておいて、仮にアプリケーション側、Lambda側のスタックを削除する。それは意図的にやるのか間違えてやってしまうのかはわかりませんが、削除した時にもCognito側に影響が出ないようにスタックを分けておくといいのかなというのが1つ。

もう1つは、Cognito側がユーザー登録、新しいアイデンティティが登録されるタイミングでLambda関数をトリガーできるので、そこで、例えばRDSやDynamoDBなど、何かデータストアにアイデンティティをバックアップ的に置いておいて、何かあった時、有事の際にはそちらから復元させるという方法があると思います。

中村:アプリケーションとCognitoのスタックを分けておくという。

福井:そうですね。はい。

中村:Cognitoの認証情報を他に出しておいて、いざという時はそこから復元できるようにするという2種類のアプローチ。

福井:はい。

下川:そうですね。今Cognitoの話をしましたが、基本的にスタックを分けるのはよいプラクティスになっていると思います。ライフサイクルが違うようなリソースに関しては、適切にスタックを分ける、粒度を分けておいて管理していくのがいいと思います。

Cloud FormationのDeletion PolicyもSAMで使用可能

青山稜河氏(以下、青山):Cloud FormationのDeletion PolicyはSAMで使えないんですか?

下川:使えます。Deletion Policyに対応しているリソースであれば使えます。

福井:はい。それも使えますが、やはり基本的には分けたほうがいいかなと。

下川:Deletion Policyについて、(話に)ついてこられない視聴者がいるかもしれないので、簡単に説明しておきます。今のようにスタックを削除した時に、そのスタックの中にあるリソースまで削除するか、それともとどめておくか。スタックは削除されるが、そのスタックの中の特定のリソースはとどめておくような設定ができます。これが先ほどのDeletion Policyです。

(次回に続く)