Amazon Web Services ブログ

SaaS 認証: Amazon Cognito ユーザープールを使ったアイデンティティ管理

この記事は、SaaS authentication: Identity management with Amazon Cognito user pools を翻訳したものです。

Amazon Cognito は、数百万人のユーザーにスケールできるカスタマーアイデンティティおよびアクセス管理 (CIAM) サービスです。Cognito 開発者ガイドでは利用可能なマルチテナンシーモデルについて詳しく説明されていますが、どのモデルを使うべきかを判断するのは時に難しい場合があります。このブログ記事では、各モデルを使う際のガイダンスを提供し、お客様の意思決定に役立つよう、長所と短所を確認します。

Cognito の概要

Amazon Cognito は、Web およびモバイルアプリのユーザーアイデンティティ管理とアクセス制御を行います。Cognito のユーザープールを使えば、アプリにサインアップ、サインイン、アクセス制御を追加できます。Cognito ユーザープールは、特定の AWS リージョン内のユーザーディレクトリで、ユーザーはアプリケーションに対して認証とユーザー登録ができます。さらに、Cognito ユーザープールは OpenID Connect (OIDC) のアイデンティティプロバイダー (IdP) でもあります。アプリユーザーは、ユーザープールに直接サインインするか、サードパーティの IdP を経由して連携できます。Cognito は、認証が成功すると、バックエンド API やリソースへのセキュアなアクセスに使えるユーザープールトークンを発行します。

Cognito は 3 種類のトークンを発行します:

  • ID トークン – 名前、メールアドレス、電話番号などのユーザーアイデンティティクレームが含まれます。このトークンタイプは、ユーザーを認証し、アプリや API ゲートウェイでの認可決定を可能にします。
  • アクセストークン – ユーザークレーム、グループ、許可されたスコープが含まれます。このトークンタイプは、認証されたユーザーとアプリケーションの権限に基づいて、API 操作へのアクセスを許可します。また、アプリケーションやサービス内で、ユーザーベースの詳細なアクセス制御を可能にします。
  • リフレッシュ (更新) トークン – ID トークンとアクセストークンの有効期限が切れた場合に、新しいトークンを取得します。アクセストークンと ID トークンは短命ですが、リフレッシュトークンは長命です。デフォルトでは、リフレッシュトークンはユーザーがサインインしてから 30 日後に期限切れになりますが、これは 60 分から 10 年の範囲で設定できます。

トークンの使用方法とその内容の詳細については、Cognito 開発者ガイドを参照してください。

マルチテナンシーアプローチ

Software as a Service (SaaS) アーキテクチャでは、しばしばサイロ、プール、ブリッジのデプロイメントモデルが使われます。これらのモデルは、Cognito のような CIAM サービスにも適用されます。サイロモデルは、テナントを専用リソースに分離します。プールモデルは、リソースをテナント間で共有します。ブリッジモデルは、サイロ化されたコンポーネントとプール化されたコンポーネントを接続させて使います。この記事では、SaaS アイデンティティ管理における Cognito のサイロモデルとプールモデルを比較します。

リソースの持ち方を複数のティアごとに分けることで、サイロモデルとプールモデルを組み合わせることも可能です。たとえば、機密性の高いテナントデータ用のサイロ化されたティアと、共有機能用のプール化されたティアを持つことができます。これはサイロモデルに似ていますが、ティアに接続するためのルーティングの複雑さが加わります。複数のプールやサイロがある場合、これは純粋なサイロモデルと同様のアプローチですが、管理するコンポーネントが増えます。

これらのモデルの詳細については、AWS SaaS Lens を参照してください。

以下のセクションでは、5 つのパターンを詳しく説明し、それぞれのパターンが使える状況、長所と短所を探っています。この記事の残りの部分では、これらのさまざまなパターンの詳細を掘り下げ、独自の要件と制約に最もよく合ったものを選択できるようにしています。

パターン 1: カスタム属性を使った SaaS アイデンティティの表現

SaaS アプリケーションでマルチテナンシーを実装するには、テナントコンテキスト (訳者注: テナント識別子やティア) をユーザーのアイデンティティ (訳者注: メールアドレスなどのユーザー属性) に関連付ける必要があります。これにより、SaaS アプリケーションを構成するマルチテナントポリシーや戦略を実装できます。Cognito には、アイデンティティを表す情報であるユーザープール属性があります。名前やメールアドレスなどの標準属性はユーザーのアイデンティティを記述するものです。Cognito はまた、ユーザーとテナントの関係を保持するための tenantId などのカスタム属性をサポートしています。

Amazon Cognito でカスタム属性をマルチテナンシーに使うことで、各ユーザーのテナントコンテキストをユーザープロファイルに保存できます。

マルチテナンシーを有効にするには、tenantId のようなカスタム属性をユーザープロファイルに追加します。新規ユーザー登録時に、この tenantId 属性にユーザーが所属するテナントを示す値を設定できます。たとえば、tenantId が “1234” のユーザーは Tenant A に、tenantId が “5678” のユーザーは Tenant B に所属します。

この tenantId 属性値は、ユーザー認証成功後に ID トークンで返されます (この値はトークン生成前の Lambda トリガーを使ってアクセストークンにも追加できます)。アプリケーションはこのクレームを検査し、ユーザーが所属するテナントを判断できます。tenantId 属性は通常 SaaS プラットフォームレベルで管理され、ユーザーやアプリケーション層からは読み取り専用です (注: SaaS プロバイダーは tenantId 属性を読み取り専用に設定する必要があります)。

テナント ID を保存するだけでなく、カスタム属性を使ってさらにテナントコンテキストをモデル化できます。たとえば tenantNametenantTiertenantRegion などの属性を定義し、アプリケーションに関連する情報コンテキストを適切に設定できます。ただし、カスタム属性をデータベースのように使わないよう注意が必要です。アイデンティティを表すものであり、アプリケーションデータを保存するものではありません。カスタム属性には、付与するアクセス権限の決定と JSON Web トークン (JWT) をコンパクトに保てる範囲の情報を含めるべきです。また、 Cognito ディレクトリに保存される情報は比較的静的である必要があります。頻繁に変化するデータを更新するには、ディレクトリを変更する必要があり、面倒です。

カスタム属性自体は、Amazon Cognito ユーザープールの作成時に定義する必要があり、最大 50 のカスタム属性を作成できます。プールが作成されると、これらのカスタム属性フィールドがそのユーザープールの全ユーザープロファイルに存在するようになります。ただし、まだ値は設定されていません。実際のテナント属性値は、ユーザープールに新しいユーザーが作成された時にのみ設定されます。これには 2 つの方法があります。

  1. ユーザー登録時に、確認後の Lambda トリガーを使って、ユーザーの入力に基づき適切なテナント属性値を設定できます。
  2. 管理者ユーザーが AdminCreateUser API 操作で新しいユーザーをプロビジョニングし、その時にテナント属性値を指定できます。

ユーザー作成後、必要に応じて管理者が AdminUpdateUserAttributes API 操作、またはユーザーが UpdateUserAttributes API 操作でカスタムテナント属性値を更新できます。ただし、ポイントはカスタム属性自体はユーザープール作成時に事前定義する必要があり、値はユーザー作成とプロビジョニングフローの後に設定されることです。図 1 は、カスタム属性が ID トークンに関連付けられ、その後ダウンストリームのアプリケーションで使用される様子を示しています。

図 1: カスタム属性を使ってテナントコンテキストを関連付ける

図 1: カスタム属性を使ってテナントコンテキストを関連付ける

図 1 に示すように:

  • ユーザープロファイルからのカスタムテナント属性値が、ユーザー認証成功後に生成される Cognito ID トークンに含まれます。これらの値は、Amazon API Gateway などの他の AWS サービスのアクセス制御に使用できます。
  • Amazon API Gateway に Lambda オーソライザー関数を設定し、ID トークン署名を検証 (この目的には aws-jwt-verify ライブラリを使用できます) し、各リクエストのテナント ID クレームを検査できます。
  • Lambda オーソライザー関数は、ID トークンから抽出したテナント ID 値に基づき、認証済みユーザーがアクセスを許可されているバックエンドリソースやサービスを判断できます。

この方法を使うと、このブログ記事で説明されているように、ユーザークレームに加えてテナントクレームをコンテキストとして使用することで、細かいアクセス制御を提供できます。ユーザーアイデンティティと関連テナントの詳細を 1 つのトークンに埋め込むこのパターンを、AWS では SaaS アイデンティティ と呼んでいます。

個別のユーザープール、共有プール、カスタム属性を使うマルチテナンシーアプローチは、いずれもユーザーのアイデンティティにテナントコンテキストを埋め込むことに依存しています。これは、Cognito が認証後に発行する JWT にテナント情報が入ったクレームを含めることで実現されます。
JWT はユーザー名、メールアドレスなどのユーザーアイデンティティ情報をエンコードします。テナント識別子やメタデータを含むカスタムクレームを追加することで、テナントコンテキストがユーザーアイデンティティに密接に関連付けられます。JWT に埋め込まれたテナントコンテキストにより、アプリケーションは各ユーザーに関連付けられたテナントに基づいてアクセス制御と認可を実装できます。

発行された JWT のユーザーアイデンティティ情報とテナントコンテキストの組み合わせが SaaS アイデンティティ、つまりユーザーとテナントの両次元にまたがる統合アイデンティティを表します。アプリケーションはこの SaaS アイデンティティを使って、マルチテナントのロジックやポリシーを実装します。

パターン 2: 共有ユーザープール (プールモデル)

単一で共有された Amazon Cognito ユーザープールは、マルチテナント SaaS アプリケーションのアイデンティティ管理を簡素化します。1 つに統合されたプールでは、変更と設定がテナント全体に一か所で適用されるため、オーバーヘッドを削減できます。

たとえば、パスワードの複雑さのルールやその他の設定をユーザープールレベルで 一度定義すると、これらの設定がテナント間で共有されます。新しいテナントを追加する際は、既存の共有プールの設定を使用するため、テナントごとに同じ設定をしなくて済み、効率化されます。新しいテナントをオンボーディングする際に、テナントごとに個別のプールをデプロイする必要がなくなります。

さらに、共有プールから発行されるトークンは、同じ発行者 (Issuer) によって署名されます。共有プールを使用する場合、トークンはテナント固有の発行者にはなりません。共通のアイデンティティニーズを持つ SaaS アプリでは、テナントごとのカスタマイズができなくなりますが、共有マルチテナントプールを使用することは、迅速なオンボーディングに適しています。

プールモデルの長所:

  • このモデルでは、テナントに対して単一の共有ユーザープールを使用します。これにより、複数のユーザープールを設定する代わりに、ユーザー属性を設定するだけでオンボーディングが簡素化されます。
  • テナントは同じアプリケーションクライアントとユーザープールを使用して認証するため、SaaS クライアントの設定が単純になります。

プールモデルの短所:

  • 1 つのプールを共有するため、パスワードポリシーや MFA などの設定は統一され、テナントごとのカスタマイズは不可となります。
  • リソースクォータの一部 (アプリケーションクライアントの数やカスタム属性の数など) はユーザープールレベルで管理されるため、このモデルを採用する際はクォータを慎重に検討する必要があります。

パターン 3: グループベースのマルチテナンシー (プールモデル)

Amazon Cognito ユーザープールでは、管理者がグループを追加し、ユーザーをグループに関連付けることができます。これにより、Cognito によって管理され、ID トークン内で利用可能な特定の属性 (cognito:groupscognito:roles) が導入されます (アクセストークンには cognito:groups 属性のみが含まれます)。 これらのグループを使用して、各テナントごとにグループを作成することで、マルチテナンシーを実現できます。ユーザーは、カスタムの tenantId 属性の値に基づいて、適切なテナントグループに割り当てることができます。次に、アプリケーションは、トークンにエンコードされたユーザーのテナントグループメンバーシップに基づいてリソースとデータへのアクセスを制限する認可ロジックを実装できます。これにより、Cognito のネイティブグループ構造を利用してテナント分離とアクセス制御を提供し、カスタム属性に完全に依存する必要がなくなります。

トークンに含まれるグループ情報は、ダウンストリームのサービスで認可決定に使用できます。グループは、より細かいアクセス制御のためにカスタム属性と組み合わせて使用されることが多くあります。たとえば、AWS SaaS Factory チームが開発した SaaS Factory Serverless SaaS – Reference Solution では、テナントアイデンティティはカスタム tenantId によって決定しますが、テナント内でのユーザーの役割は Cognito グループを使用して指定されています。このリファレンスソリューションにおいて、テナントアイデンティティ属性はテナント分離を提供し、グループは特定のテナント内で適用される個々のユーザーの役割とアクセス権限を定義しています。

図2は、グループがユーザーに関連付けられ、その後 Lambda オーソライザーがそれぞれの認証済みユーザーがアクセスを許可されているバックエンドリソースとサービスを決定する方法を示しています。

図 2: グループベースのマルチテナンシー

図 2: グループベースのマルチテナンシー

このモデルでは、グループはロールベースの制御を提供し、テナント ID などのカスタム属性はテナント分離を実施するために必要な情報を提供します。認可決定は、ユーザーのグループメンバーシップと属性値を評価することで、各テナントとユーザーに合わせた細かいアクセス制御を提供します。つまり、グループは直接的にロールベースのチェックを可能にし、カスタム属性はテナントの条件付きアクセスのための広範なコンテキストを提供します。両者を組み合わせることで、マルチテナントアプリケーションで細かい認可を実装するために必要なデータを提供できます。

グループベースのマルチテナンシーの長所:

  • このモデルでは、複数テナントに対して単一の共有ユーザープールを使用するため、オンボーディングはユーザー属性の設定で済み、複数のプールを構成する必要がありません。
  • テナントは同じアプリケーションクライアントとプールを通して認証を行うため、SaaSクライアントの構成が簡素化されます。

グループベースのマルチテナンシーの短所:

  • 1 つのプールを共有するため、パスワードポリシーや MFA などの設定は統一され、テナントごとのカスタマイズは不可となります。
  • ユーザープールあたり最大10,000グループの制限があります。

パターン 4: テナントごとに専用のユーザープールを用意する (サイロモデル)

Cognito でのマルチテナントアイデンティティのもう1つのよくある方法は、各テナントに対して個別のユーザープールをプロビジョニングすることです。Cognito のユーザープールはユーザーディレクトリなので、個別のプールを使用することで最大の分離が可能になります。ただし、この方法ではアプリケーション側でテナントのルーティングロジックを実装し、ユーザーのテナントに基づいて認証対象のユーザープールを決定する必要があります。

テナントルーティング

テナントごとに個別のユーザープール (または後で説明するアプリケーションクライアント) を使用する場合、アプリケーションには各ユーザーを適切なプール (またはクライアント) にルーティングするロジックが必要です。このアプローチでは、次のようなオプションを使用できます:

  • URL にサブドメインを使用してテナントにマッピングします。たとえば、tenant1.myapp.com は Tenant 1 のユーザープールにルーティングされます。これにはサブドメインをテナントプールにマッピングする必要があります。
  • テナントごとに一意のメールドメインを使用します。たとえば、@tenant1.com は Tenant 1 のプールに行きます。これにはメールドメインをプールにマッピングする必要があります。
  • ユーザーにテナントをドロップダウンリストから選択させます。これにはテナントの選択肢を設定する必要があります。
  • ユーザーにテナント ID コードを入力させます。これにはコードをプールにマッピングする必要があります。

選択したアプローチに関係なく、主な要件は次のとおりです:

  • テナントを識別するデータポイント (サブドメイン、メール、選択、コードなど)
  • ユーザーからテナント識別情報を取得し、対応するユーザープールを検索してルーティングするためのマッピングデータセット
  • 適切なユーザープールにリダイレクトするためのルーティングロジック

たとえば、AWS SaaS Factory Serverless Reference Architecture では、図 3 に示すアプローチを使用しています。

図 3: テナントごとに専用のユーザープール

図 3: テナントごとに専用のユーザープール

ワークフローは次のとおりです:

  1. ユーザーはサインイン時にテナント名を入力します。
  2. テナント名からユーザープール ID、アプリケーションクライアント ID、API URL などのテナント固有の情報を取得します。
  3. テナント固有の情報が SaaS アプリに渡され、正しいユーザープールとアプリクライアントで認証を初期化し、認可コードフローを初期化するために使用されます。
  4. アプリは Cognito のホストされた UI に認証のためにリダイレクトします。
  5. ユーザー資格情報が検証され、Cognito から OAuth コードが発行されます。
  6. OAuth コードが Cognito の JWT と交換されます。
  7. JWT を使用してユーザーをマイクロサービスにアクセスするために認証します。

テナントごとにプールを 1 つずつ持つモデルの長所:

  • ユーザーは単一のディレクトリに存在し、クロステナントでの可視性はありません。トークンはそのプールに固有の鍵で発行され、署名されます。
  • 各プールでは、パスワードルールや MFA 要件などのセキュリティポリシーをテナントごとにカスタマイズできます。
  • プールは、データ保管の要件を満たすために異なる AWS リージョンでホストできます。

テナントごとにプールを 1 つずつ持つモデルの潜在的な短所:

  • アカウントあたりのプール数に制限があります (デフォルトは 1,000 プール、最大は 10,000 プールです)。
  • 複数のプール、特にカスタマイズされた設定のプールを作成するには、追加の自動化が必要です。
  • アプリケーションは、認証リクエストを正しいユーザープールに向けるためのテナントルーティングを実装する必要があります。
  • 各プールの設定が個別に管理され、テナントルーティング機能が追加されるため、トラブルシューティングが難しくなる可能性があります。

まとめると、個別のユーザープールはテナントの分離を最大化しますが、より複雑なプロビジョニングとルーティングが必要になります。大規模なマルチテナントデプロイメントの場合は、プール数の制限も考慮する必要があるかもしれません。

パターン 5: テナントごとのアプリケーションクライアント (ブリッジモデル)

グループとカスタム属性を使用する以外に、単一のユーザープールでテナントごとに個別のアプリケーションクライアントを使用することでも、テナントの分離を実現できます。アプリケーションクライアントの Cognito 設定 (OAuth スコープ、ホストされた UI のカスタマイズ、セキュリティポリシーなど) は、テナントごとに固有のものにできます。また、アプリケーションクライアントを使用すれば、テナントごとに外部 IdP のフェデレーションも可能です。ただし、パスワードポリシーなどのユーザープールレベルの設定は共有されたままです。

図 4 は、単一のユーザープールに複数のアプリケーションクライアントを設定する方法を示しています。それぞれのアプリケーションクライアントは、各テナントに割り当てられています。ただし、このアプローチでは、アプリケーション内でテナントをどのアプリケーションクライアントにマッピングするかを判断するためのロジックを実装する必要があります (共有ユーザープールの場合と同様のアプローチです)。ユーザーが認証されると、Amazon API Gateway に Lambda オーソライザー関数を設定して ID トークンの署名を検証できます。その後、Lambda オーソライザー関数は、認証されたユーザーがアクセスを許可されているバックエンドリソースとサービスを判断できます。

図 4: アプリケーションクライアントベースのマルチテナンシー

図 4: アプリケーションクライアントベースのマルチテナンシー

SAML または OpenID Connect フェデレーションを使って独自の IdP を利用したいテナントの場合は、ユーザーをテナントの連携 IdP にリダイレクトして認証する専用のアプリケーションクライアントを作成できます。これには以下のような主なメリットがあります:

  • アプリケーションクライアントに単一の外部 IdP が有効化されている場合、ホストされた UI は自動的にユーザーをリダイレクトし、Cognito のサインイン画面を表示しません。これにより、テナントにとっては馴染みのあるサインイン体験が提供され、テナント IdP にセッションが既にある場合は、シームレスな体験になります。
  • ユーザーの追加や離脱、パスワードの管理など、ユーザーアクティビティの管理は、テナント側の IdP で完全に処理されます。SaaS プロバイダーはこれらのプロセスに関与する必要がありません。

重要なのは、フェデレーションを使用する場合でも、Cognito は外部認証が成功すると引き続きトークンを発行することです。つまり、SaaS プロバイダーは、IdP に関係なく、認可時に Cognito から発行される一貫したトークンを検証できます。

属性マッピング

外部 IdP と連携する場合、Amazon Cognito は発行するトークンに属性を動的にマッピングできます。これにより、IdP で作成されたグループ、メールアドレス、ロールなどの属性が認証時に Cognito に渡され、トークンに追加されます。

マッピングは、サインイン時に毎回行われ、既存のマッピング済み属性を上書きして IdP の最新の値と同期します。したがって、マッピング済み属性に関連する外部 IdP での変更は、サインイン後に Cognito に反映されます。メールアドレスのようにサインインに必要なマッピング済み属性がある場合、IdP に同等の属性があってマッピングする必要があります。Cognito の対象属性は変更可能に設定する必要があります。作成後は不変の属性はマッピングによっても上書きできません。

重要: SaaS アイデンティティの場合、テナント属性は外部 IdP からマッピングするのではなく、Cognito で定義する必要があります。これにより、テナントが値を改ざんするのを防ぎ、分離を維持できます。ただし、グループやロールなどのユーザー属性は、テナントの IdP からマッピングしてアクセス許可を管理できます。これにより、テナントは独自の IdP グループを使用してアプリケーションのロールを設定できます。

ブリッジモデルの長所:

  • このモデルでは、OAuth スコープ、UI、IdP などのテナント固有の設定が可能です。
  • テナントユーザーは外部 IdP を通じて馴染みのあるワークフローにアクセスでき、外部 IdP を使用する場合、テナントユーザー管理は外部で行われます。
  • カスタムクレームマッピングは必要ありませんが、オプションで使用できます。
  • Cognito はトークンを発行して認可を行えます。

ブリッジモデルの短所:

  • ユーザーをテナントごとの正しいアプリクライアントにルーティングする必要があります。
  • ユーザープールごとのアプリクライアント数に制限があります。
  • パスワードポリシーなどの一部のユーザープール設定は共有されたままです。
  • 動的なグループクレームの変更はできません。

まとめ

このブログ記事では、Amazon Cognito ユーザープールが SaaS ソリューションのマルチテナント ID をどのように有効にできるかについて、さまざまな方法を探りました。単一の共有ユーザープールは管理を簡素化しますが、ユーザープールレベルのポリシーをカスタマイズするオプションが制限されます。一方、個別のプールは分離と構成の柔軟性を最大化しますが、複雑さが増します。複数のアプリケーションクライアントを使用すると、外部 IdP や OAuth スコープなどのカスタマイズされたオプションと、ユーザープールの集中管理ポリシーとのバランスを取ることができます。カスタムクレームマッピングは柔軟性がありますが、追加のロジックが必要です。

これら 2 つのアプローチを組み合わせることもできます。たとえば、一部の上位層のテナントには専用のユーザープールを用意し、他のテナントはマルチテナントプールを共有するなどです。最適な選択は、特定のテナントのニーズと必要なカスタマイズ次第です。

このブログ記事では主に静的なアプローチについて説明しましたが、トークン生成前の Lambda トリガーを使用してトークンを動的に変更し、クレームを追加、変更、削除することもできます。このトリガーは、ID トークンとアクセストークンの両方でグループメンバーシップを上書きすることもできます (訳者注: アクセストークンのカスタマイズには、Cognito の高度なセキュリティ機能を有効化する必要があります)。その他のクレーム変更は ID トークンにのみ適用されます。このトリガーの一般的な使用例は、テナント属性をトークンに動的に注入することです。

SaaS アーキテクチャとテナントの要件に対して、それぞれのアプローチの長所と短所を評価してください。ハイブリッドモデルが最適な場合が多くあります。Cognito のユーザープール、IdP、トリガーなどの構成要素を使用すると、テナント全体で認証と認可を細かく調整できます。

これらのトピックの詳細については、Cognito 開発者ガイドの 一般的な Amazon Cognito シナリオ と関連ブログ記事 How to Use Cognito Pre-Token Generation trigger to Customize Claims in ID Tokens を参照してください。

 

Shubhankar Sumar

Shubhankar Sumar

Shubhankar はAWSのシニアソリューションアーキテクトで、英国の企業ソフトウェアや SaaS のお客様と協力して、セキュアで拡張性があり、効率的で費用対効果の高いシステムを設計するのを支援しています。彼は多くの SaaS ソリューションを構築してきた経験豊富なソフトウェアエンジニアです。Shubhankar の専門分野は、クラウド上でマルチテナントプラットフォームを構築することです。また、顧客とも密接に連携して、SaaS アプリケーションに GenAI 機能を導入することにも取り組んでいます。

Owen Hawkins

Owen Hawkins

Owen は20年以上の情報セキュリティの経験を持ち、AWS のプリンシパル・ソリューション・アーキテクトとして深い専門知識を持っています。彼はデジタルバンキングのセキュリティに関する豊富な経験を活かして、ISV の顧客に密接に協力しています。Owen は SaaS およびマルチテナントアーキテクチャに特化しています。彼は企業がクラウドを安全に活用できるようにすることに情熱を持っています。複雑な課題を解決することは Owen にとって大きな喜びであり、AWS でアプリケーションを保護し実行するための革新的な方法を見つけることにやりがいを感じています。

翻訳はソリューションアーキテクト 中山 七美 が担当しました。原文はこちらです。