📖

re:Invent 2025: AWS LambdaのTenant Isolation Modeによるマルチテナント分離

に公開

はじめに

海外の様々な講演を日本語記事に書き起こすことで、隠れた良質な情報をもっと身近なものに。そんなコンセプトで進める本企画で今回取り上げるプレゼンテーションはこちら!

re:Invent 2025 の書き起こし記事については、こちらの Spreadsheet に情報をまとめています。合わせてご確認ください

📖re:Invent 2025: AWS re:Invent 2025 - Secure Multi-tenant SaaS with AWS Lambda: A Tenant Isolation Deep Dive (CNS381)

この動画では、AntonとBillがLambdaの新機能Tenant Isolation Modeを紹介し、マルチテナントSaaSアプリケーションにおけるテナント分離の課題と解決策を解説しています。従来のシングルテナント関数モデルやカスタムフレームワークによる分離手法の限界を説明した上で、Tenant Isolation Modeがテナントごとに独立した実行環境を自動的に作成し、CPU、メモリ、ディスクを完全に分離する仕組みを実演します。API Gatewayとの統合方法、CloudWatch Logsを使ったテナント固有のオブザーバビリティ、usage plansによるノイジーネイバー対策、STSを活用したテナントスコープの認証情報取得など、実装の詳細が具体的なコード例とともに示されます。デモではJWTトークンを使った認証フローで、異なるテナントが独立した実行環境で処理される様子が確認できます。

https://www.youtube.com/watch?v=FWxwfcI7FTA
※ こちらは既存の講演の内容を最大限維持しつつ自動生成した記事になります。誤字脱字や誤った内容が記載される可能性がありますのでご留意下さい。

本編

Thumbnail 0

セッション開始とJoeの物語:共同生活で学ぶテナント分離の必要性

はい、ご来場いただき本当にありがとうございます。皆さんに聞こえているようですね。さて、本日のセッションでは、私たちが最近ローンチしたこの新しいものについてお話しします。ただし、単なる機能についてお話しするのではなく、全体的なユースケース、つまりLambdaを使った安全なマルチテナントSaaSアプリケーションの構築についてお話しし、SaaSアプリケーションにおいてテナント分離をどのように実現するかについて深く掘り下げていきます。まず問題について取り上げ、次に既存のソリューションについて説明し、そして新しいソリューションについてお話しします。私はAntonです。ServerlessのPrincipal Solutions Architectをしています。こちらはBillで、ほぼ私の同僚です。私たちは二人ともServerlessとSaaSについてとても熱心に取り組んでいます。そして、この時点で皆さんはおそらく、あの三人目の男、Joeって誰だろうと思っているでしょう。では、Joeを紹介しましょう。彼は普通のJoeです。ここから私たちのストーリーが始まります。

Thumbnail 60

Thumbnail 80

Thumbnail 90

Thumbnail 100

さて、Joeは郊外のどこかにある一戸建ての家で静かな生活を送っています。しかし、彼の心の奥底には、いつか有名なクラウドアーキテクトになるという大きな夢があります。そのため、毎晩Joeは自分の個室でクラウドアーキテクチャに関する本を読み、 AWSでプロトタイプを構築しています。ある時点で、夢を追求することを決意した彼は、都会の大きな大学に入学します。 そして新しい住居に引っ越します。彼はルームメイトに会うことをとても楽しみにしていましたが、Joeはすぐに共同 生活が自分が想像していたものとは全く違うことに気づきます。彼は騒がしい隣人の問題を発見します。基本的に、自分がやろうとしていることに集中できないのです。

Thumbnail 120

Thumbnail 130

Thumbnail 140

また、彼は一緒に住んでいるテナントの一人が時々その共有環境を 少し汚れたままにしておくことの意味も学びます。これもあなたが特に楽しんでいるものではありません。そしてある日、ベンチに座って、彼は考えます。共有環境に何らかのテナント分離 があればいいのにと。ここでJoeはシングルテナント環境とマルチテナント環境の違いを発見しました。私たちがここで言おうとしている例えは理解していただけると思います。 プライベートな生活と共同生活です。

Thumbnail 150

シングルテナント環境とマルチテナント環境の違い:コストと分離のトレードオフ

シングルテナント環境、専用環境またはサイロ環境とも呼ばれますが、 すべてのテナントが独自の専用リソース、コンピュート、ストレージなどを持っています。このモデルはこれらのリソースに対して最高レベルの分離を提供しますが、規模が大きくなるとかなり高額になる可能性もあります。テナントごとにそれらのリソースを維持する必要があります。テナントが増えれば増えるほど、維持する必要のあるリソースも増えます。

Thumbnail 180

一方、マルチテナントモデル、共有環境またはプール環境とも呼ばれますが、 これらの懸念を克服するのに役立ちます。このモデルでは、クラウドリソースを複数のテナント間で効率的に共有できます。たとえば、異なるテナントから来るリクエストが同じコンピュートユニット、同じ関数、同じコンテナ、同じEC2インスタンス、基本的に共有コンピュートによって処理される可能性があります。その結果、コストは低くなり、運用はよりシンプルになり、それほど多くのインフラストラクチャを維持する必要がなくなります。

Thumbnail 230

とはいえ、このモデルには独自の考慮事項が伴います。つまり、複数のテナントがリソースを再利用することになるわけです。これらのテナント間で一定レベルの分離を維持する必要があります。取り組みがいのある問題ですね。さて、Joeは卒業して、クラウドエンジニアとしての最初の仕事を見つけました。そして、どうなったと思いますか?今や彼の仕事はマルチテナントクラウドアプリケーションを構築することなんです。そしてここでJoeは、マルチテナントアプリケーションの構築が実際にはかなり厄介になり得ることを発見するわけです。

Thumbnail 250

Joeの挑戦:ServerlessとSaaSの相性、そしてコスト効率の実現

その通りです、ありがとうAnton。さて、私たちはJoeが好きです。Joeはいい奴ですからね。私たちはJoeと一緒に学校に行きます。彼がSaaSを構築する経験について、マルチテナンシーについて学んだことについて、少し学んでいきましょう。そして彼は、ある会社に入社するところから始まりました。彼らが何をしたいのかについて少し学びました。彼らには、彼に達成してほしいビジネス要件がありました。彼は単に技術に飛び込んで技術について学ぶだけではいけませんでしたが、それでも達成しなければならない技術要件もありました。

Thumbnail 270

さて、Lambdaについて、Serverlessについて話すという目的において、ビジネスの観点から達成したかったこと、そして技術的な観点からそれらをどのように達成したかという点で、私が焦点を当てたい主要な課題がいくつかあります。Joeの旅という観点では、彼の会社は迅速にイノベーションを起こしたいと考えていました。顧客に新機能を素早く提供し、競合他社の先を行き、アプリケーションを常に新鮮に保ち、顧客を満足させ続けるという良い仕事をしたかったのです。

そのためには、共有環境を持ちたいと考えていましたが、すべてを完全に分離したいとも考えていました。分離の面ですべてが完璧であることを要求する顧客がいて、ノイジーネイバー問題には対処できませんでした。

Thumbnail 320

そして、ノイジーネイバーが何を意味するかは皆さんご存知ですよね。1つのテナントまたは1つの顧客があまりにも多くのアクティビティを行っている場合、それが他の顧客に影響を与えるべきではありません。これらがJoeが直面した主要な課題の一部です。そして彼はserverless派です。serverlessが大好きなんです。これらすべてを読み上げるつもりはありませんが、もちろんserverlessとSaaSは自然にフィットします。ここに理由がいくつか挙げられていますが、一般的にこれを要約すると、serverlessから得られる運用効率とコスト効率が本当に素晴らしくフィットするということです。

Thumbnail 360

さて、サーバーレスとは何かを考えてみると、それはSaaSに非常に似ています。クラウドで生まれたものです。サーバーレスのオンプレミス版というものは存在しません。もちろんLambdaをエミュレートすることはできますし、異なる環境で実行することもできますが、これはクラウドで生まれたテクノロジーなのです。素晴らしいですし、彼はこれを気に入っていて、これらすべての原則を受け入れています。そして私は、サーバーレスとSaaSは非常に相性が良く、コストがその理由の一つになり得ると言いました。では、これを見て、皆さんが取り組んできたサーバーフルな環境について少し考えてみてください。

Thumbnail 400

サーバーフルな環境を構築する場合、スケールする能力があるかもしれません。もちろん、必要に応じてスケールアップやスケールダウンができます。コンテナでもできますし、単純なコアインスタンスでもできます。しかし、そうする際には、ピーク要件に対してリアクティブにスケールアップしているのです。この時間帯にこれだけの潜在的な負荷がある。そのトラフィックをすべて処理するために必要な数のサーバーやコンテナをセットアップするわけです。そしてもちろん、これらのスパイクに対して料金を支払っているわけですよね。アイドル状態で待機しているインフラストラクチャに対して料金を支払っているのです。

Thumbnail 430

Thumbnail 440

つまり、必要なインフラストラクチャをすべて立ち上げて、常時稼働させ続けているお客様もいらっしゃいます。おそらくこのチャートほど効率的でさえないかもしれません。一方、サーバーレスはコストと使用率がほぼ均等にスケールします。使用量が増えるにつれて、インスタンスの数が増えるにつれて、それを処理する必要さえありません。そしてもちろん、それらに対して支払うコストは、使用率とほぼ連動しています。つまり、サーバーレスはコストと使用量の最適な比率を実現でき、これはSaaSに最適です。特にスパイキーなワークロードが見られるSaaSには最適なのです。

Thumbnail 450

Thumbnail 460

Lambdaの同時実行とFirecracker microVMによる分離アーキテクチャ

Lambdaはどのようにしてこれを実現しているのでしょうか?コストと使用率が連動するこの美しく均等なチャートを実現するために、どのように実行を行っているのでしょうか?Lambdaの同時実行数について少し考えてみましょう。いくつかの呼び出しをお見せしますが、これらを関数の呼び出しと呼びます。リクエストが入ってくると、それを処理します。そして1つのリクエストが入ってくると、ここに紫色で表示されますが、これは私たちがいる環境、この線上の環境が、現在アクティブでお客様のリクエストを処理していることを意味します。そしてグレーの部分がありますが、これはアイドル状態を表します。このチャートを見る際には、これを覚えておいてください。

Thumbnail 480

Thumbnail 490

これは非常にシンプルなチャートなので、すぐに見ていけます。1つのリクエストが入ってきたら、1つの環境で処理します。別のリクエストが入ってきたら、どうしますか?同じ環境で処理します。今アイドル状態なので、同じ環境にそのまま入れます。続けていくと、別のリクエストが入ってくるかもしれませんが、今度は2番目のリクエストと同時に入ってきます。どうしますか?もちろん別の環境を立ち上げることができます。

Thumbnail 530

では、別の環境を立ち上げているのでしょうか?正確には違います。Lambdaとその背後にある実行エンジンが私たちの代わりにやってくれているんです。私が積極的に選択して、「ねえ、別の環境を立ち上げてくれ」と言ったわけではありません。いいえ、それは全てバックグラウンドで魔法のように起こっただけです。そして今では私たちのほとんどにとって、これは当たり前のように思えますよね?これが起こることを受け入れられます。これが登場した時はかなり魔法のようでしたし、これらすべての実行とSaaSで実現できるスケールについて考える上で、今でも非常にクールなことです。

Thumbnail 540

Thumbnail 550

続けましょう。さて、今度は別の呼び出しが入ってきます。最初の環境は今空いているので、最初の環境でそれを実行するだけです。別の呼び出しが入ってきて、同時に2つです。まあ、2つの空いている環境があるので、もちろん両方ともそれらの環境で処理できます。続けましょう。3つの実行がある場合はどうなるでしょうか?もちろん、別の環境が立ち上がります。

さて、これはある程度明白に思えますよね、オーケー、これは問題ない。Bill、なぜこんなことを言っているんだ?と。まあ、いくつかあります。1つは、あのアイドル状態のバーを見てください。私たちはその消費に対して、つまりそれらの実行環境に対して、追加の呼び出しを入れることができるにもかかわらず、料金を支払っていません。そして2つ目は、ここで私たちは何もする必要がなかったということです。これは全て自動的に起こりました。そしてその自動魔法的な部分がSaaSの会話に関連しているのは、私たちがこれを代わりにやってもらえるという幸運に恵まれただけでなく、特定の実行がどこに行くかを制御しなかったからです。そしてマルチテナント環境では、それが重要なんです。

Thumbnail 600

さて、サーバーレスの最大の秘密ですが、ここで猫を袋から出すつもりはないと思いますが、実際にはフードの下にはサーバーのフリートが存在しているということです。もしこれを知らなかったなら、がっかりさせて申し訳ありません。実際にはサーバーレスではないんです。EC2が存在していて、何千ものEC2がありますよね?私たちにはLambdaフリートをサポートするEC2の全フリートがあり、それは良いことです。

私たちがそれを知る必要がないという事実、つまりLambdaが実際にEC2を使用していることを理解せずに一生を過ごすことができ、それがあなたにとって秘密のままでいられるということは、実際には私たちにとって利益なんです。そしてこれが私たちが作りたかったものです。しかし、フードの下を掘り下げてみましょう。今は無知のベールを取り除いて、ああ、今度は実際にここで何が起こっているのかを理解したいと言いましょう。なぜなら、繰り返しになりますが、分離の観点から、これは特に重要だからです。

Thumbnail 630

Thumbnail 670

Thumbnail 680

これらの個々のEC2の中を見てみましょう。これは単なるベアメタルのEC2です。EC2の中には、もちろんホストOSがあり、ここで一定レベルの分離を提供しています。その上にカーネルがありますが、重要なのは、その上でFirecracker microVMを使用していることです。そしてFirecracker microVMは、それぞれの周りに強力な分離を持っています。これらのFirecracker microVM間では何も共有されていません。つまり、マルチテナントであろうとなかろうと、あらゆる種類の呼び出しを処理するために重要な分離のレイヤーがすでに存在しているということです。この中、つまりmicroVMの中には、ゲストカーネルがあります。私たちのランタイム、マネージドランタイムを使用している場合は、 そこに私たちのランタイムもあります。そしてLambda extensionsを使用している場合は、それもあります。まだ使っていない方はぜひ、本当にクールですよ。そしてその上に、あなたの関数コードが存在します。つまり、 これらすべての異なるレイヤーが、まるでロシアのマトリョーシカ人形のように、複数の分離レイヤーを提供しているんです。このスタック全体を見渡して、ほら、これはこれから保護されている、これはこれから保護されている、と言えるわけです。私たちは本当に強力な分離を作り出しました。これは繰り返しになりますが、SaaSプロバイダーやあらゆるプロバイダーにとって重要ですが、特にマルチテナントソリューションにおいて重要です。

Thumbnail 700

Thumbnail 720

Thumbnail 730

これらの境界をもう少し詳しく見てみましょう。関数間では、同じ実行環境を関数間で共有することは決してありません。つまり、同じ共有実行環境が複数のLambda間で共有されることは絶対にないということです。そして同じ関数内でも、完全な分離があります。このクリックで表示されますが、完全なグリッドがありますよね。 それらは決して同じ実行環境を共有していません。そして同じ関数内でも、CPU、ディスク、メモリを共有することは決してありません。 これにより、少し異なる視覚化が得られ、私たちが直面している問題空間、そしてJoeが優れたLambda開発者およびアーキテクトになる方法を学ぶ際に直面するかもしれない課題について、異なる考え方ができます。

マルチテナント環境での実行環境共有とデータ残留の課題

異なる関数間では、何も共有されません。以上です。終わり。CPUも共有していませんし、ディスクも共有していませんし、メモリも共有していません。それらの間では何も共有されていません。先ほどのFirecrackerのビジュアルに戻ってください。それらすべてのレイヤー、その周りのすべての異なる分離レイヤーがここに適用されます。では、同じ関数についてはどうでしょうか?同じ関数に属する実行環境です。そして、異なる実行環境があったあのチャートを思い出してください。そして、異なる呼び出しがそこでどのように行われていたかを。実際には、潜在的に共有されるものがいくつかあり、これが私たちが扱っている問題空間の1つです。環境変数、IAM実行ロールと権限、そしてコードは、実際に環境間で共有される可能性があります。

Thumbnail 800

Thumbnail 840

では、同じチャートに戻りましょう。先ほど話した9つの実行があり、それらすべてが、私たちが見た同じ紫色のアクティブロールにあります。 しかし、マルチテナント環境では、私たちの世界にはもっと多くの色があります。SaaSプロバイダーにとって、複数の顧客が入ってくるという事実に対処しなければなりません。そして、共有環境での呼び出しは、ランタイムまでそれがどこから来ているのか私には分かりません。そしてこれは重要です。最初の環境は、青、緑、黄色のテナントからの実行を処理しています。そして、時間の経過とともに、異なる環境全体でこれが当てはまります。すべてのテナントは、異なる環境にランダムに着地し、私たちはそれを制御できません。これらの個々の呼び出しのいずれかがどの環境に着地するかを選択することはできません。そして、これが問題の核心なんです。 まあ、本当に問題というわけではありませんが、公平に言えば、対処する必要があることではあります。

Thumbnail 860

Thumbnail 870

では、私たちが話している原則を実証するデモに入りましょう。なぜなら、これらのものが潜在的に共有される可能性があると言うのは一つのことですが、実際にこれが何を意味するのか見てみましょう。シンプルなメモリカウンターがあります。その中には、ディスクカウンターもあり、それらが何を意味するのかお話しします。 それらが実際にやっていることは、言っているように、メモリに何かを書き込むか、ディスクに何かを書き込むかです。ここに包括的なカウンターがあります。かなり基本的ですよね。 メモリカウンターでは、単にメモリカウンターであることを出力し、それを出力し、インクリメントして、メモリに戻して保存しています。そしてディスクも同じです。読み取り、出力、インクリメント、保存、そしてそれらの異なる値を持つ値を返します。

Thumbnail 890

それではJoeを見てみましょう。彼はこれをどうやるか学んでいるところで、もちろん、彼は自分のLambdaランタイム環境に入り、実際にこれが動作する仕組みが彼が考えていた通りであることを証明する小さなテストを作成します。そこで彼は用意したこの非常にシンプルなテストイベントを実行すると、いくつかの出力が見えますよね?

Thumbnail 920

ログにはメモリカウンター、ディスクカウンター、そして怪しいことにundefinedになっているテナントIDが表示されています。おそらく後ほど、実際の影響について考え始めるときに、このテナントIDに何が起こるのかがわかるでしょう。これが実行されるたびに、ディスクとメモリのカウンターがインクリメントされ、どのテナントが呼び出しているかに関係なくインクリメントし続けます。Joeは全く気にしていません。すべて順調で、素晴らしい。彼は自分が設計した通りに動作していることが確認できます。

Thumbnail 950

それでは、Joeが考えるべき懸念事項と、今年のre:Invent 2025に彼が来て、私たちがローンチしたものについて学ぶことになった理由を定義しましょう。これらの各テナントが入ってくると、Joeが作成したLambda関数を呼び出します。さて、これらの呼び出しが発生すると、ディスクにいくつかのものを書き込み、メモリにいくつかのものを書き込みます。そしてJoeはこの関数を嬉々として実行しています。彼は素晴らしい仕事をしたと思っていますし、もちろん彼は勤勉です。私たちは本当にJoeが好きで、彼に成功してほしいと思っています。

Thumbnail 980

Thumbnail 990

しかし残念ながら、Joeはすべてのコードを適切に密閉していませんでした。今でさえ、これを防ぐためにできるベストプラクティスがあります。残念ながら、Joeはそれらを知りませんでした。そのため、青いテナントの呼び出しからいくつかの残り物があり、それらは実行環境に残ります。そして実行環境を思い出してください、私たちが色を追加したとき、多くの異なるテナントがそれぞれの実行環境に入ってきていました。黄色いテナントが入ってきます、同じ問題です。今度はさらに残り物ができました。おそらく彼らは青いテナントからの残り物を見ることができます。緑のテナントが入ってくると、今度は青と黄色のテナントからの残りデータを見ることができるかもしれません。

Thumbnail 1010

さて、このデータは重要なのでしょうか?まあ、そうかもしれません。テナント固有のデータである可能性があり、他のテナントに関する情報、あるいは他のテナントの存在や彼らが誰であるかを明らかにする可能性があり、これらすべては私たちが携わっているビジネスにとって危険なものになり得ます。つまり、ちょっとクレイジーに聞こえますよね?Lambdaには、この問題があるのでしょうか?問題なのでしょうか?いいえ、実際にはそうではありません。これはすべてのアーキテクチャに共通する懸念事項であり、おそらく皆さんのほとんどはこれに気づいていると思います。これがLambdaであることから一歩引いて考えると、コンテナを実行していてディスクに書き込みを行い、複数のコンテナを実行している場合、注意しないと他のコンテナが同じデータを拾い始めることになります。

そしてEC2も同じですよね?つまり、それらの周りには隔離のレベルがあるかもしれません。それらを管理する必要があり、これは私たちがこれまで遭遇したほぼすべてのコンピュート環境に当てはまります。さて、実はJoeはre:Invent 2025に来てくれました。私たちはJoeと一緒に学ぶことができます。Joeは私たちのストーリーのヒーローに戻ることができます。ここでAntonにバトンタッチして、どのようにしてJoeを私たちのストーリーのヒーローに戻したかを話してもらいます。

Thumbnail 1060

既存のソリューション:テナントごとの関数とカスタムテナンシーフレームワーク

ありがとう、Bill。さて、Billが言ったように、これはどのコンピュートを使っても本質的な懸念事項ですよね?複数のテナント間でコンピュートユニットを共有している場合、何か残り物を残していないことを確認する必要があります。実行可能です、完全に実行可能です。誰が責任を持つのか?あなたです。それにどう対処するか見ていきましょう。Lambdaはこの点で実際に非常にユニークです。なぜならLambdaの実行環境は短命だからです。それらは何日も何週間も存在しません。私たちは常にそれらをリサイクルしています。

Thumbnail 1110

ですから、たとえ何か残り物があったとしても、良いことではありません。誤解しないでください、悪いことです。しかし数分後にはリサイクルされます。ですからLambdaは実際にそれを少し重要度の低いものにしていますが、それでも非常に重要です。繰り返しますが、誤解しないでください。では、この問題に対する既存のソリューションは何か見ていきましょう。そうです、既存ということは新しいものもあるということです。皆さんは新しいものを聞きに来ていると思います、そこに向かっています。

さて、技術的な部分に入る前に、これは重要です。私は顧客と仕事をしています、私はSolutions Architectです。ああ、大したことじゃないよ、と言っている顧客がいます。すべてのテナントのすべてのデータはどうせ公開されているから、なぜそれを心配する必要があるの?と。私はそれを信じません。なぜなら、たとえ今日それを処理するユースケースがなくても、明日にはそれを処理する理由が出てきて、あなたはそれを忘れてしまうからです。ですから、マルチテナント環境ではこの問題を無視しないことを強くお勧めします。

Thumbnail 1180

もう一つ私が聞いているのは、これは気に入ると思いますが、私たちにはwikiページがあって、テナント情報を扱うためのすべてのベストプラクティスを文書化しています、と。誰かそれに馴染みがありますか?良い意図は素晴らしいですが、十分ではありません。ガイダンスを提供することでその問題を解決したくはありません。ガイダンス以上の、もっと具体的な何か、実際にあなたのために機能する何かが欲しいのです。Joeはおそらくそれを見逃したでしょう、なぜならオンボーディング資料があまりにも多いからです。では、ソリューションについて話しましょう。さて、最初のソリューションは、ある意味明白です。これはシングルテナントアプローチに戻ることです。いくつかの組織があり、通常それらは最も高いセキュリティ要求を持つ最大の組織ですが、彼らはテナントごとの関数モデルを採用しています。ここにそれを使っている人や聞いたことがある人はいますか?ええ、何人か手が上がっていますね。基本的に、各関数はシングルテナントです。

Thumbnail 1210

Thumbnail 1230

1つの関数が1つのテナントからの呼び出しのみを処理します。これが最も高い分離度です。これ以上分離することはできません。しかし問題は、コストがかかるということです。5つのテナントであれば大した問題ではありません。しかし、500、5,000、または50,000のテナントがあったらどうでしょうか?このアプローチの利点は明らかに強力な分離です。テナントごとに1つの関数があるため、コストの帰属が少し簡単になります。可観測性のためにテナントごとに設定を構成できます。しかし、考慮すべき点もあります。運用の拡散のようなことです。確かにこれらはサーバーレス関数であり、維持すべきインフラはありません。しかし50,000は50,000です。膨大な数です。CDKやTerraformなどの管理を頑張ってください。そしてそれは50,000テナントを持つたった1つの関数に過ぎません。

つまり、スケールでの維持が難しくなります。CI/CDがより複雑になります。30,000の関数を更新する必要がある場合、管理APIの制限に達する可能性があります。テナントごとに専用リソースをプロビジョニングする必要があるため、テナントのオンボーディングが遅くなります。重複、バージョンのずれ、カスタムルーティングレイヤーの必要性があります。このモデルを使用する場合、いくつかの考慮事項があります。そのため、絶対にそのレベルの分離が必要な場合にのみ推奨しています。一般的なモデルではありませんが、確かに業界では使用されています。

Thumbnail 1300

CyberArkの事例とベンダー提供ソリューションへの期待

より一般的なモデルは、複数のテナントがその関数を使用するマルチテナント関数を持つことですが、その関数内に何らかのフレームワークまたはSDKまたはレイヤーがあります。名前の付け方はさまざまです。本質的には、組織が作成したコードの一部であり、その分離を処理します。基本的にはビジネスロジックから切り離されており、たとえば、受信テナントの検証、認証情報のスコープダウン、テナントレベルでのログ記録などを処理します。つまり、開発組織によって実装されたコードの一部であり、基本的にその問題に対処します。

Thumbnail 1350

これは非常に一般的なアプローチです。かなり頻繁に見られます。私が協力している企業の1つで、このアプローチを積極的に使用しているのはCyberArkです。彼らはLambdaを使用しています。彼らはサーバーレスファーストのアイデンティティプロバイダーであり、マルチテナントSaaSプラットフォームでLambdaを使用しています。インフラ管理を最小限に抑え、クリーンなコンピュート分離を可能にするために、彼らはカスタムテナンシーフレームワークを構築しました。これは素晴らしいものです。インターネットで見つけることができます。ああ、ちなみに、最後のスライドには、今日見たすべてのリソース、これらのスライドを含む巨大なQRコードがあることを言い忘れていました。37分後にこれらのスライドを手に入れることができます。

Thumbnail 1390

お客様はこのアプローチを使用しています。かなり人気があり、かなり堅牢です。リソースの再利用率が高い、単価が低いなど、多くの利点があります。数千または数万の関数を管理する必要がないからです。テナントのオンボーディングがはるかに高速です。専用リソースを作成する必要はありません。データベースのレコードだけです。運用がシンプルになり、機能の迅速なロールアウトなどが可能になります。しかし、私たちはアーキテクトですよね。常に「場合による」とトレードオフがあります。考慮すべき点もあります。ノイジーネイバーがいたらどうでしょうか?共有コンピュートを使用している場合、ノイジーネイバーがいる可能性があります。追加のコンピュートレベルの分離が必要になるかもしれません。

それで、私はカスタムテナンシーフレームワークで分離を提供しましたが、それよりも高い分離度が欲しい場合はどうでしょうか?でも、テナントごとに関数を作成するのは避けたいんです。なぜなら、それは保守が大変だからです。残されたものをどうやってクリーンアップするのか?誰がそれに責任を持つのか?テナントごとのオブザーバビリティはどうでしょうか?1つの関数が10,000のテナントで再利用されている場合、どうやってテナントごとに観察するのか?などなど。

Thumbnail 1450

Thumbnail 1470

それで、ランチタイムの間、Joeを覚えていますか?彼は考えていました、テナントのコンピュート分離のためのベンダー提供のソリューションがあったら素晴らしいだろうなと。それで、先週の後半、ランチから戻ってきたとき、彼はLambdaが新しいTenant Isolation Modeを発表したことを知って、非常に興奮しました。さて、Tenant Isolation Modeとは何かを説明するために、30分間話すつもりですが、1枚のスライドで説明します。なぜなら、これは千の言葉に値する絵だからです。

Thumbnail 1500

Tenant Isolation Modeの登場:テナントごとの実行環境分離を実現

これを見たことがあるでしょう。テナントが関数にアクセスしています。新しいTenant Isolation Modeでは、何らかのテナントIDを私たちに渡します。それが何であるかは私たちは気にしません。これについては次のスライドで話しますが、何らかのユニークなテナント識別子を教えていただく必要があります。内部で何が起こるかというと、Lambdaの関数、単一の関数が、各テナントごとに別々の実行環境を作成します。

Thumbnail 1520

Thumbnail 1530

Thumbnail 1540

Thumbnail 1550

Thumbnail 1560

Thumbnail 1570

実行環境は、異なるテナント間で決して再利用されません。その例を見てみましょう。デモが最良の方法です。それで、過去5日間にLambdaを使ったことがある方は、おそらくこれに気づいたでしょう。テナント分離を有効にすると、Tenant IDという新しいプロパティがあります。それで、デモを覚えていますか?それを進化させましょう。Tenant IDを指定します。例えばBlueTenantとしましょう。そして関数を呼び出してみましょう。それで、まずTenant IDがもうundefinedではないことがわかります。そして、カウンターがインクリメントされているのが見えます。なぜなら、BlueTenantがBlueTenantが所有する実行環境にヒットしているからです。5まで行きましょう。その数字、5を覚えておいてください。重要です。上を見てください。テナントをGreenTenantに切り替えます。そして、まったく同じ関数を呼び出します。再デプロイはありません。カウンターがゼロから始まっているのが見えます。カウンターがゼロから始まっているのは、今、GreenTenantに属する実行環境がBlueTenantと重複していないからです。BlueTenantの実行環境はまだそこにあります。ただ、Tenant IDをGreenTenantに変更したので、リクエストがもうそこに行かなくなっただけです。

Thumbnail 1590

Thumbnail 1600

Thumbnail 1610

Thumbnail 1620

それで、そのカウンターを9くらい、9か10まで行かせましょう。戻しましょう。上を見てください。GreenTenantをBlueTenantに戻しています。5を覚えていますか。その関数を呼び出しましょう。6、7、という具合です。すべてのテナント、私たちは皆さんが提供するTenant IDで識別しますが、異なる実行環境を持っています。それをOrangeTenantに変更しましょう。これまで見たことのないものです。呼び出すと、ゼロから始まります。なぜなら、これは新しいテナントだからです。さて、これらのカウンターは単純な例に過ぎませんが、テナント固有の設定、テナント固有のデータ、データベース接続文字列をロードすることを想像してください。テナント固有の情報をキャッシュします。

Thumbnail 1660

以前は、マルチテナント機能の場合、リクエスト間でそれらの残留データをクリーンアップするのはあなた次第でした。まあ、できますよね、完全にできます。新しいことではありません。共有コンピュートでは何年も前からあることです。そして今、私たちがそれらのコンピュート環境を分離するようになりました。つまり、データが異なるテナント間で共有されることは決してありません。では、これが実際にどのように機能するか見てみましょう。

まず、テナント分離モードで関数を作成するにはどうすればよいでしょうか?これは新しいプロパティです。すでにCDKやTerraform、その他いくつかのInfrastructure as Codeツールでサポートされています。文字通り、関数を作成するときに、tenancy configという新しいプロパティを指定します。tenant isolation mode per tenantです。つまり、テナントごとにコンピュートを分離しています。これは新しい関数を作成するときにのみ利用可能です。既存の関数に対して変更できるものではありません。なぜなら、これはセキュリティだからです。この設定を変更して予期しないことが起こるようなゲームはしたくありません。セキュリティは冗談ではありません。

Thumbnail 1700

次に、これらの関数を呼び出すときは、Tenant IDを提供する必要があります。繰り返しますが、パラメータです。特定の関数でテナント分離モードを有効にした場合にのみ必要です。Tenant IDを提供しない場合、デフォルトはありません。パラメータが不足していますというエラーが返されます。これは必須の必須パラメータで、提供する必要があります。それだけです。他には何もありません。以上です。これが作成方法です。これが使用方法です。これは非常に短いセッションになったかもしれません。私たちはこれを非常に、非常にシンプルにしようとしましたが、より高度なトピックに入っていきましょう。

Thumbnail 1760

おそらく、うーん、いいですね、Tenant ID、そのTenant IDを関数に渡しています。コード内からそのTenant IDにアクセスできる可能性はありますか?と尋ねているでしょう。なぜなら、おそらくテナント固有のロジックを実行したいからです。答えはイエスです。そのTenant IDを関数ハンドラーに伝播しています。つまり、contextオブジェクトには、驚くことに、Tenant IDという新しいプロパティがあります。これはあなたが私たちに渡したTenant IDそのものです。したがって、コード内で実際にその情報に簡単にアクセスでき、Tenant IDに基づいて分岐ロジックを実行する必要がある場合に使えます。

Thumbnail 1780

Thumbnail 1790

Thumbnail 1800

では、使用方法について少し話しましょう。まず、テナントを事前登録する必要はありません。テナントのリストを提供するようお願いしていません。事前登録は一切不要です。次に、テナント数は無制限です。制限はありません。10,000テナントのようなクォータはありません。必要なだけのテナント数を使えます。考慮事項はありますが、それについては話しますが、基本的にテナント数は無制限です。

Thumbnail 1820

テナントIDは、最大128文字までの任意の英数字文字列にすることができます。GUIDにすることもできますし、システムに既にある何らかのユニークな識別子にすることもできます。任意の英数字文字列で最大128文字であれば、私たちは気にしません。最後に、これは明らかにZIPとコンテナイメージの両方でサポートされています。この新しい機能を皆さんに楽しんでいただきたいと思っています。

Thumbnail 1840

ここまでは素晴らしいですが、明らかに考慮事項があります。各機能の考慮事項を知ることが常に重要です。まず第一に、テナントごとに分離された実行環境を作成しているため、コールドスタートもテナントごとになります。コンピュート分離が必要なので、テナントが実行環境を共有しなくなるため、コールドスタートもテナントごとに発生するようになります。これは注意すべき重要なポイントです。多くの呼び出しがあるテナントは、おそらくこれに気づかないでしょう。1日に3回程度しか呼び出さないテナントは、おそらく毎回の呼び出しがコールドスタートになるでしょう。これは覚えておくことが重要です。

Thumbnail 1870

Thumbnail 1900

Thumbnail 1920

同時実行数のクォータが適用されます。覚えておいてください、今はより多くの実行環境を作成しています。以前は10個のテナントを1つの実行環境で処理していたかもしれませんが、今は10個のテナントは少なくとも10個の実行環境を意味します。したがって、同時実行数のクォータは引き続き適用されます。アカウントごとの同時実行数クォータ、バーストなど、などです。これについてはドキュメントで非常に詳しく説明しています。Provision Concurrencyは明らかな理由でサポートされていません。Provision Concurrencyは実行環境のプールを事前にウォームアップすることを意味しますが、テナントが誰であるかわからない場合、それを事前にウォームアップすることはできません。したがって、この時点では将来何が起こるかはわかりませんが、現時点ではProvision Concurrencyはこの機能では利用できません。そして、現時点では直接呼び出しまたはAPI Gatewayインテグレーションのみでサポートされています。独自のコントロールプレーンがあってLambdaを呼び出している場合は簡単に実行できますし、API Gatewayを使用している場合は、数スライド後にAPI Gatewayでどのように動作するかをお見せします。

Thumbnail 1940

Thumbnail 1950

Thumbnail 1970

テナントレベルのオブザーバビリティ:ログとメトリクスの活用

では、次の大きな質問は、オブザーバビリティについてはどうでしょうか?コンピュート分離があります。テナントレベルのオブザーバビリティをどのように実現するのでしょうか?まず第一に、まだJSONフォーマットのロギングを使用していない場合は、ぜひ使用してください。JSONフォーマットのロギングを使用することを強くお勧めします。これにより、皆さんの作業が楽になります。これらは、クエリに基づいて情報を照会して受け取ることができるログです。JSONベースのロギングを有効にすると、画面に表示されているように、テナントIDがログに自動的に注入されます。もはや、テナントIDを手動で出力するために、コード内に特殊なログ行を用意する必要はありません。今では自動的にログに注入されます。

Thumbnail 1980

Thumbnail 2000

Thumbnail 2010

Thumbnail 2030

しかし、実際にこれらのログをどのように処理するのでしょうか?実際にどのように活用するのでしょうか?おそらくご存知のように、LambdaはCloudWatch、S3、またはFirehoseにログを自動的に送信できます。デフォルトではCloudWatchです。おそらく最も一般的なものの1つなので、今日はCloudWatchについてお話しします。デフォルトでは、各関数は独自のロググループを取得します。これは何年も前からこのように動作していました。これは新しいことではありません。各関数は専用のロググループを取得します。さて、そのロググループ内には、ログストリームのコレクションが表示されます。これも新しいことではありません。各実行環境は独自のログストリームを取得します。これは何年も前からこのように動作していました。ここまでは新しいことはありません。新しいのは、これらのログストリームがテナント固有になったことです。テナント固有の実行環境があるため、これらのログストリームもテナント固有になります。要約すると、各テナントは複数のログストリームを持ちます。各ログストリームは単一のテナントのみに属します。理解できますか?

Thumbnail 2050

Thumbnail 2070

それでは、もう少し深く掘り下げていきましょう。 さて、皆さんおそらくご存知かと思いますが、これらの名前は完全にランダムというわけではありません。実際には意味があるんです。まず日付から始まり、次に関数名、そして関数のバージョン、最後にランダムな実行環境IDが続きます。この構造を理解していれば、クエリをもう少しパワフルにすることができます。例えば、開発シナリオから始めましょう。テナント固有のログをリアルタイムで観察したいとします。そこでLive Tailを使うことができます。これはCloudWatchの機能ですし、Lambdaコンソールにも組み込まれています。ロググループを選択できます。覚えておいてください、ロググループは関数と同じですから、複数のロググループ、つまり複数の関数を選択できます。ログストリームも選択できます。つまり、特定のテナントに属するストリームを選択できるということです。そして、

Thumbnail 2120

例えば、テナントIDをフィルターパターンとして指定することもできます。ここではblueテナントであることがわかっています。その結果、こうなります。ここではlogs tailを使っているので、ログをライブで取得でき、特定のテナントIDのログだけを取得できます。このフィルタリングを使わない場合、繰り返しになりますが、すべてのログを取得することになります。しかし、特定のテナントに対してテナント固有の可観測性が必要な場合は、このフィルタリングで簡単に実現できます。テナントIDを指定するだけで、フィルタリングしてくれます。

Thumbnail 2160

Thumbnail 2180

しかし、これはライブログです。もし3週間分や3ヶ月分のログがあって、特定のテナントのログを取得したい場合はどうでしょうか?そういう場合はCloudWatch Logs Insightsを使うことができます。繰り返しになりますが、これはすべてクエリベースのロギングです。ここにLogs Insightsクエリの例があります。これで特定のテナントのログストリームのリストを取得できます。頭の中で考えているんです、よし、blueテナントがある。この特定のテナントに属するすべてのログストリームを見たい、と。例えば、このクエリを実行すると、こんな感じの結果が得られます。そのテナントに属する3つのログストリームが取得できたのがわかります。時間や数で制限できます、標準的なクエリですね。そして、ここでログカウントも確認できます。つまり、特定のテナントに属するログストリームを確認できるわけです。

Thumbnail 2200

Thumbnail 2230

もっとシンプルにすることもできます。どのログストリームかを見ることに興味がない場合はどうでしょう?特定のテナントのログを見たいだけで、それらが異なるログストリームにどう分散しているかは気にしない場合です。なぜなら、明らかに各テナントは複数の実行環境を持つからです。それぞれがテナント固有ですが、複数あります。だからクエリを実行して、BlueTenanのすべてのメッセージを取得して、1000件に制限したいとします。ここで、クエリはCloudWatchロググループとログストリームに保存されているテナント固有のログを返してくれます。さて、サードパーティの可観測性プロバイダーを使っている場合、非常によく似た機能があるでしょう、何らかのフィルタリング機能です。なぜなら、繰り返しになりますが、構造化ログでは、テナントIDはJSONオブジェクトのプロパティの1つに過ぎないからです。クエリするのは非常に簡単です。

Thumbnail 2260

Thumbnail 2280

Thumbnail 2300

しかし、ログ以外ではどうでしょうか?もう少し洗練された高度なことで、他に何ができるでしょうか?そうですね、テナント固有のカスタムビジネスメトリクスを送信するのはどうでしょう?では、ここにいる方でPowertools for AWS Lambdaを使っている人は?かなり多くの方が知っていますね。ここに興味深い例があります。Powertoolsはオープンソースライブラリで、Lambdaで使用でき、多数の言語とランタイムをサポートしています。ここにNode.jsの例があります。新しいmetricsオブジェクトを作成しています。なぜなら、テナント固有のメトリクスを発行し始めたいからです。ログではなく、メトリクスです。ハンドラーの中で、メトリクスにテナントディメンションを追加しています。この時点から、関数から発行するすべてのメトリクスはテナント固有になります。テナント固有でない一般的なメトリクスを発行することもできますが、今やテナント固有のメトリクスも発行できるようになりました。これは非常に強力です。つまり、一番下で成功した予約を追加してそれらのメトリクスを公開できます。そして今、その情報をテナントごとに取得できるようになります。つまり、テナントごとの可観測性のストーリーも非常に強力なんです。

Thumbnail 2330

Thumbnail 2340

Thumbnail 2360

API Gatewayとの統合:テナントIDの伝播とテナントスコープ認証情報

API Gatewayとの統合について少しお話ししましょう。これは非常に一般的なシナリオです。 テナントがAPIを経由してLambdaに到達する場合ですね。ご存知のように、テナント分離モードが有効になっている場合、Lambdaは各呼び出しに対してテナントIDパラメータが送信されることを期待します。しかし、実際にワイヤープロトコルレベルではどのように動作するのでしょうか?詳細に入っていきましょう。プロトコルの 観点から言うと、テナントIDがLambdaに伝播される方法は、X-Amz-Tenant-Idと呼ばれるHTTPヘッダーを使用することです。そして、そのヘッダーの値は、BlueTenantやGreenTenant、または指定した任意の値になります。

Thumbnail 2390

Thumbnail 2400

しかし、大きな疑問は、元のリクエストでその値はどこから来るのかということです。Lambdaが何を期待しているかはわかりますが、異なるユースケースがあるかもしれません。例えば、 HTTPヘッダーを使用してテナントIDを渡す場合、またはクエリパラメータ、またはパスパラメータを使う場合はどうでしょうか?これらすべてが可能です。ドメインプレフィックスを使用したい場合はどうでしょうか? テナントを識別する方法として、各テナントにドメイン、サブドメインを作成していて、それをテナントIDとして使用したい場合は?可能です。

Thumbnail 2410

Lambda authorizerから来る情報についてはどうでしょうか? JWTクレームやアカウント、その他の情報についてはどうでしょうか?これらすべてが可能です。それでは、どのように行うか見ていきましょう。

Thumbnail 2420

まず、用語を定義しましょう。 これは、今後5分ほど使用するAPI Gatewayの用語です。これを理解することが重要です。API Gatewayへのインバウンドリクエストは、メソッドリクエストと呼びます。なぜなら、GETやPOSTなどの特定のHTTPメソッドにヒットするからです。つまり、インバウンドはメソッドリクエスト、API GatewayからLambdaへのアウトバウンドは、インテグレーションリクエストと呼ばれます。これは下流のバックエンド統合だからです。

Thumbnail 2450

簡単ですね。私がやりたいことは、 例えば、任意の例です。メソッドリクエストから何らかのカスタムヘッダーを取得したいのですが、x-tenant-idを使用しています。これは任意の名前です。好きな名前を付けることができます。単に例として使っているだけです。そのインバウンドのx-tenant-idの値を取得して、Lambdaに送られるX-Amz-Tenant-Idヘッダーの値として使用したいのです。これが達成したいことです。どうやって行うのでしょうか?

例としてCDKを使用します。もちろん、他のインフラストラクチャーアズコードでも実行できますし、コンソールでクリックして操作することもできます。まず最初に、リソースを作成してそのリソースにGETメソッドを作成する際に、指定することができます。これが最初に用語の説明をしなければならなかった理由なんですが、method.request.header.x-tenant-id trueと指定できます。この設定は基本的にAPI Gatewayに対して、このx-tenant-idヘッダーを期待していて、それが必須であることを伝えています。trueは必須を意味します。なぜなら、テナントIDなしでリクエストを処理したくないからです。

Thumbnail 2510

2つ目はインテグレーションを設定する際です。繰り返しになりますが、これが最初に用語の部分をやらなければならなかった理由です。integration request headerのX-Amz-Tenant-Idを、method request headerのx-tenant-idの値にマッピングしたいと言っているわけです。本質的には、それがLambdaに、つまり下流のインテグレーションに渡したいヘッダーであり、これが使用したい値のソースであると言っているのです。そしてこれは、任意のカスタムHTTPヘッダーをテナント識別子としてマッピングする方法の一例に過ぎません。

Thumbnail 2550

これは単なる一例です。この値は、先ほど言ったように、多くの異なるソースから取得できます。任意のリクエストヘッダー、任意のリクエストクエリパラメータ、パスパラメータ、リクエストボディ、オーソライザーのプリンシパルID、またはオーソライザーから返す任意のカスタムプロパティを使用できます。ドメインプレフィックスもそのために使用できます。基本的に、API Gatewayでアクセスできるものは何でも、テナントIDの値として使用できます。サンプルを公開しています。最後にリンクが表示されます。オーソライザーを通じてそれを実現する方法を示すサンプルコードを公開しています。JWTトークンとオーソライザー、どうやるのか?とてもシンプルです、数行のコードです。

Thumbnail 2590

すでにAPI Gatewayについて話しているので、ノイジーネイバー問題に対処しましょう。これは以前に議論したことの1つです。API Gatewayは使用量プランを作成する機能を提供しています。例えば、これは一般的なアプローチです。シルバー、ゴールド、ブロンズティアのような異なるティアがあり、それぞれのティアに対してリクエストレートを定義できます。例えば、1秒あたり10リクエスト、30、20などです。

これらのティアをテナントにマッピングすると、ノイジーネイバーに対する保護が得られます。API Gatewayを使えば、これらのリクエストがLambdaに到達する前にノイジーネイバー保護を実装できます。コードで何かする必要はなく、APIレベルで行うだけで、サービスがそれを処理してくれます。そして繰り返しになりますが、以前使用したのと同じテナントID、つまりクライアントリクエストから入ってくるものを使用できます。同じテナントIDを使用して、そのテナントがどのプランに関連付けられているかを識別できます。つまり、API Gatewayはここでも役立ちます。

Thumbnail 2660

Thumbnail 2680

では次に進みましょう。簡単な質問です。実際のアプリケーションについて話すとき、この図に何が欠けているでしょうか? ストレージ、つまり依存関係ですね。アーキテクチャはLambdaで終わりではありません。Lambdaは真空の中で動いているわけではありません。何かを実行します。データベースやS3のような下流にアクセスする必要があります。何かと通信する必要があるんです。ですから明らかに、Lambdaがアクセスする必要のある依存関係がいくつかあります。ここにあるように、S3バケット、DynamoDB、SQS、そして他にもたくさんあります。

従来はどうやっていたでしょうか?まあ、SDKを使いますよね。そしてIAMはどう管理するか?Function execution roleを使います。これは重要です。セキュリティの観点から非常に重要です。Function execution roleはfunction execution roleです。Tenant execution roleではありません。つまり、関数レベルで適用されるものです。

Function execution roleが許可することは何でも、すべてのテナントが実行できるようになります。これは関数レベルの構成要素です。Billが以前示したものと非常によく似ています。例えば、環境変数も関数レベルの構成要素であり、テナントレベルの構成要素ではありません。しかし大きな疑問は、もう少しきめ細かくできないか、ということです。では、どうやってできるか見てみましょう。

Thumbnail 2740

Thumbnail 2750

Thumbnail 2760

Thumbnail 2770

Thumbnail 2800

典型的なシナリオとして、クライアントがJWTを使用する場合を考えてみましょう。認可のための非常に一般的なシナリオです。さて、API Gatewayを使用しているので、トークンはLambda Authorizerまで伝播されますよね?そしてそのAuthorizer内でいくつかのかなりクールなことができます。まず第一に、明らかにトークンを検証します。それがAuthorizerをそこに置いている理由です。つまり、そのトークンから情報を抽出したいわけです。Cognitoやあなたが使用している任意のアイデンティティプロバイダーに対して検証できます。ですから最初にすることは、明らかにそのトークンを検証し、おそらくいくつかのアイデンティティを抽出することです。第二に、オプションとして、そこにカスタムロジック、適用したいカスタムポリシーがあるかもしれません。つまり、このトークンが有効であるだけでなく、そのトークンに対する権限、カスタム権限は何か、ということです。おそらくDynamoDBに保存しているかもしれませんし、何か外部システムがあるかもしれません。その特定のトークンに対する追加の権限を検証します。しかし次のことは実際にかなりクールです。STSからテナントスコープの短期間の認証情報を取得できるんです。

Thumbnail 2820

Thumbnail 2860

つまりこの時点で、ここの3番目の箇条書きに到達する頃には、そのテナントを検証済みです。このテナントが実際に主張している通りの人物であることがわかっており、彼らのポリシーが彼らが要求していることを実行することを許可しています。ですからここでできることは、function execution roleではなく、このテナントに固有のテナントスコープの認証情報を取得しましょう、ということです。そしてその情報をAPI GatewayからLambdaに伝播します。つまり実際に意味することは、今やLambda関数は2セットの認証情報を持っているということです。Function execution roleは、テナント固有ではないアクションを関数が実行することを許可します。すべてのテナントがアクセスする必要のある情報を持つ共有ストレージにアクセスできることは、すべてのテナントにとってかなり一般的です。しかしテナントスコープの認証情報は、実際にはこの特定のテナントだけがアクセスできるデータにのみアクセスできるように関数を制限します。この例を見てみましょう。

では、これがどのように動作するか見ていきましょう。BlueTenantからリクエストが来ています。そのテナントはAPI Gatewayにヒットします。API GatewayはリクエストをLambdaに転送します。明らかに、BlueTenantの実行環境が使用されています。この時点で、そのBlueTenantの実行環境は共有バケットにアクセスできます。そこに共有バケットがありますね。関数実行ロールを使用してその共有バケットにアクセスします。しかし、それに加えて、Blueバケットにもアクセスできます。なぜでしょうか?それは、Blueバケットへのアクセスを許可するテナントスコープの認証情報があるからです。できないことは、GreenバケットやYellowバケットへのアクセスです。なぜなら、現在のこのリクエストでその関数が利用できる権限には、2つの異なるテナントに属するこれら2つのバケットへのアクセスを許可するものがないからです。

Thumbnail 2910

Thumbnail 2940

そして、次のリクエストがYellowTenantから来たとき、例えば、それはYellowの実行環境によって処理されます。Yellowの実行環境は共有バケットにアクセスできます。誰でも共有バケットにはアクセスできます。Blueにはアクセスできず、Greenにもアクセスできませんが、Yellowバケットにはアクセスできます。なぜなら、関数レベルの認証情報があり、そしてテナントスコープの認証情報があるからです。さて、そろそろまとめに入る時間です。残り約10分ですね。ですから、明らかに、これが実際に動作することを証明するために、エンドツーエンドのデモをお見せする必要があります。そして、これ全体がGitLabで利用可能です。すぐにご覧いただけます。

Thumbnail 2960

Thumbnail 2970

Thumbnail 3000

エンドツーエンドデモとまとめ:Joeのハッピーエンドと今後の展望

デモをお見せする前に、何が起こるのかを説明したいと思います。なぜなら、デモは私がPostmanを通じて3つのリクエストを送信するようなものになるからです。内部で何が起こっているかを理解していないと、それほど印象的ではありません。まず、2つのテナントがあり、テナントIDをJWTクレームとして渡します。そのJWTを受け取るAuthorizer関数があり、それを検証します。これらは本物の、ちゃんとしたJWTです。それを検証し、テナントIDを含むコンテキストを返します。ここではusage identifier keyは使用していません。オプションなので。このデモのためには使用していませんが、基本的に、usage plansも導入したい場合は使用できます。つまり、Authorizerレスポンスから返されるコンテキストにはテナントIDが含まれています。次に何をするか?Lambda integrationを定義するとき、integration.request.header.x-amz-tenant-idと言っていて、その値はcontext authorizer tenant IDから来ています。

Thumbnail 3030

これがこのスライドの最も重要な部分です。これが明確であることを願います。ここで、AuthorizerレスポンスからテナントIDを取得し、そのヘッダーとしてLambda関数へのリクエストを行うために使用すると言っているのです。これは1行の設定のようなもので、ここで魔法全体が起こっているのです。これを設定すると、API GatewayからLambdaへのリクエストは実際にそのX-Amz-Tenant-IdヘッダーをBlueTenantと言って持つことになります。

つまり、Authorizerでトークンを検証します。テナントIDを返します、まあ、テナントIDとして使用したい文字列を返します。まったく同じテナントIDを返す必要はありません。機密情報かもしれません。匿名化したいかもしれませんし、そこからハッシュを生成したいかもしれません。ユニークな文字列である限り、それがあなたにとって何を意味するかは気にしません。何でも構いません。そして、そのBlueTenantは私のマルチテナント関数まで伝播されます。それはBlueTenantの実行環境によって処理されます。

Thumbnail 3070

Thumbnail 3090

Thumbnail 3100

それでは、魔法が内部でどのように動作するかを理解したところで、実際に魔法を見てみましょう。 さて、今回はPostmanを使います。なぜなら、API Gatewayを使用しているので、もはやただのLambdaではないからです。ここでいくつかのリクエストを送信していますが、まだトークンを持っていないため、message unauthorizedが返ってきています。ここで確認できますね。では、authorizationヘッダーを追加しましょう。私はJWTの大ファンでして、これはJWTで、 お察しの通り、BlueTenantを表しています。そして同じ状況です。まだカウンターが動いていて、45などとなっています。 BlueTenantは5で止まっていたことを覚えておいてください。

Thumbnail 3110

Thumbnail 3120

Thumbnail 3130

今度はGreenTenantに属する別のトークンに置き換えます。では、新しいリクエストを送信しましょう。 これがGreenTenantであることがわかりますね。そしてカウンターはゼロから始まっています。なぜでしょうか?もう一度言いますが、GreenTenantは異なる実行環境のセットを取得しているからです。仮想リソースは共有されていません。 CPU、メモリ、ディスク、テナント間で共有されているものは何もありません。10まで到達しました。では、BlueTenantに戻しましょう。実行すると、6、7と続いています。 というように続きます。つまり、基本的には以前見たデモと同じですが、今回はAPI Gatewayとの完全な統合があり、認証コンポーネントも含まれています。

Thumbnail 3160

これは20数分前にお見せしたスライドです。マルチテナント関数モデルには利点がありますが、考慮事項もあります。この25分ほどで、テナント分離モードによって、これらの考慮事項のほとんどに対処できたことを証明できたと思います。 API Gateway usage plansとの統合を通じて、ノイジーネイバーの潜在的な問題に対処しました。アーキテクチャが追加のコンピュート分離を必要とする可能性がある問題に対処しました。これはコードで処理するものではなく、私たちが提供するものです。今、それが手に入りました。

残留物のクリーンアップについては、残留物をクリーンアップすることは依然として良い習慣ですが、今ではその重要度を下げることができました。なぜなら、コンピュート環境はテナント間で決して共有されないからです。バグを導入したとしても、そのバグを修正することは依然として良いアイデアですが、私たちはそれをあまり重要ではないものにしました。テナントごとの可観測性は難しいという点については、今ではテナントごとのログがあり、テナントごとのメトリクスを出力でき、それらすべてが手に入ります。

非常に公平に言うと、テナント固有の機能ロールアウトは難しいです。これは黄色にしておきましょう。これは私たちが解決した問題とは正確には言えません。関数コード内にテナント情報があるため、より簡単にはなっていますが、それでもif tenant ID equalsやcase tenant IDのようなことをする必要があります。コード内で何かをする必要はありますが、少し簡単にはなっています。ですから、公平を期すために、黄色のままにしておきます。

Thumbnail 3240

さて、ここで私たちのストーリーはハッピーエンドを迎えます。Joeは、彼のチームが何十万もの関数、つまり重複したコードを持つ個別の関数を作成する必要のない方法を見つけました。彼らは少数の関数を作成するだけでよく、Lambdaが各テナントに対して個別の実行環境を提供してくれます。つまり、テナントコンピュート分離モードは本質的に、Joeのチームにビジネス価値の提供に集中する能力を与えてくれたわけです。彼らはより速くイノベーションを起こせるようになりました。これは以前彼らが解決しなければならなかった別の問題でしたが、今では本当に重要なことに集中できるようになったのです。

Thumbnail 3280

結論として、ワークロードのテナント分離要件と、アーキテクチャにおける実装の詳細を理解してください。このテナント分離モードについて、その、これはYouTubeに載るので引用しないでくださいね、引用しないでください。私の知る限り、Lambdaは単一のコンピュートユニット関数内でテナントレベルのコンピュート分離を提供する唯一のサービスだと認識しています。個人的には他に何もそれを行うものを知りません。しかし、それがすべてのユースケースの100%を解決するという意味ではありません。

場合によっては、顧客の厳しい要件として、テナントごとに関数を用意する必要があるかもしれません。時には、関数ごとの分離だけでなく、異なるアカウント間での分離を求められることもあります。ですから、まず最初に理解すべきことは、顧客が何を求めているのか、そしてその顧客の要求を最も効率的な方法でどう満たすかということです。テナント分離モードは、それをより効率的にするのに役立ちます。

Thumbnail 3330

2つ目は、より高度なベンダー提供のコンピュート分離を必要とするマルチテナントアプリケーションに対して、テナント分離モードを活用してください。以前はこれがブロッカーだったかというと、必ずしもそうではありませんでしたが、誰がその責任を負っていたかというと、あなたでした。今、私たちはそれをお手伝いすると言っています。テナントごとにベンダー提供のコンピュート分離を提供します。

Thumbnail 3360

Thumbnail 3370

3つ目は、SaaSアプリケーションにおけるより強固なセキュリティのために、テナントモニタリングやAPI Gateway統合のような組み込みのオブザーバビリティ機能を使用してください。さて、このスライドには、これに関連する非常に興味深い他のセッションがいくつかありますが、今は木曜日の午後なので、おそらく皆さんはライブではなくYouTubeでご覧になることになるでしょう。

Thumbnail 3380

もしまだ Serverless Landをご存知でない方は、これは私たちのソリューションアーキテクトやデベロッパーアドボケートが管理しているウェブサイトです。何百、いや何千もの情報、サンプル、リファレンスアーキテクチャが掲載されています。私たちは毎週YouTubeとTwitchでServerless Office Hoursを開催していて、そこでは新機能の一つ一つについて詳しく話しています。マーケティングなしで、非常に技術的な内容です。もしまだ登録されていない方は、ぜひ登録することを強くお勧めします。

そして最後に、お約束していたけれどもまだお見せしていなかったもの、それがこの巨大なQRコードです。これで今日ご覧いただいたすべてのもの、スライド、サンプルコード、追加のリンク、すべてが手に入ります。本当にすべてです。お越しいただき本当にありがとうございました。お役に立てたことを願っています。この新しい機能について学んでいただけたことを願っています。私とBill、そしてIrish、彼はこの素晴らしい機能のプロダクトマネージャーですが、もし何か質問があれば、すぐ外にいますので、どんな質問にも喜んでお答えします。すぐ外にいますので。本当にありがとうございました。そしてre:Inventを楽しんでください。


※ こちらの記事は Amazon Bedrock を利用し、元動画の情報をできる限り維持しつつ自動で作成しています。

Discussion