0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Well-Architected Agent に自作のマルチテナント SaaS(ボイラープレート)をレビューさせてみた

0
Posted at

はじめに

直近、マルチテナント SaaS のボイラープレートを 2 回に分けて作ってきました。

1 作目は Amazon CloudFront のマルチテナントディストリビューションと AWS Lambda の Lambda Authorizer でバックエンド API をテナント分離する回、2 作目はその続きでフロント(React SPA)と認証まわりを同じサブドメイン識別で分離する回でした。

作ってきた中では、Lambda を Lambda-lith 構成にするか、Amazon Cognito を Pooled のままにするか、オリジン保護をどうするか、などの決定をしてきたのですが、SNS 上で Well-Architected Agent が 登場したのを目にしました。

公式なドキュメントがまだ見当たらないのですが、 botocore では 1.43.70(2026 年 8 月 12 日)で追加されている模様です。

ちょうど自分が作ったものをレビューしてもらうのにうってつけなので、このボイラープレートを Well-Architected Agent でレビューしてみます。

リポジトリは前作までと同じものです。

この記事で学べること

  • Well-Architected Agent のエージェントプロファイル作成からアーキテクチャレビュー実行までの最小の流れ
  • 自作の IaC ワークロード(AWS CDK(Cloud Development Kit))をレビューにかける手順
  • 出てきた推奨事項を、自分の設計意図と突き合わせた所感

前提知識・条件

  • 前 2 作の構成(CloudFront マルチテナントディストリビューション、Amazon API Gateway、Lambda Authorizer、Cognito)を前提にします。
  • Well-Architected Agent は本記事執筆時点でプレビューです。バージニア北部(us-east-1)やオレゴン(us-west-2)などで対応しています。今回はオレゴンで検証しました。
  • 検証日: 2026 年 9 月 29 日

Well-Architected Agent とは

これまで Well-Architected といえば、Well-Architected ツールや公式ドキュメントを見ながら質問に答えていく、対話形式で作業が中心だったと思います。

Well-Architected Agent は、環境や IaC を渡すと、そこから推奨事項まで生成してくれる機能のようです。

対象の柱はコンソール上だと 4 つでした。コスト最適化・セキュリティ・パフォーマンス・信頼性です(コンソール上の表記は「耐障害性」)。

CleanShot 2026-09-30 at 05.38.26.png

運用優秀性が選択肢に出てきません。

API の pillars には OPERATIONAL_EXCELLENCE の enum 自体は存在しているので、プレビュー段階の UI 都合なのかもしれません。

提供状況はプレビューで、本記事執筆時点では公式ドキュメントもまだ見当たりませんでした。

ここから先はコンソールの表記を頼りに手探りで進めます。

レビュー対象のおさらい

まず、何をレビューさせるのかを再掲します。

前 2 作で作ったのは、テナント別サブドメイン({tenant}.example.com)でエッジからテナントを識別するマルチテナント SaaS です。

[Client] https://{tenant}.example.com
   |  HTTPS(ワイルドカード証明書 *.example.com)
   v
[CloudFront マルチテナントディストリビューション]
   |  Host から tenant を解決し X-Tenant-Id 付与 / X-Origin-Verify 付与
   v
[API Gateway (REST API)]
   |  Lambda Authorizer で認可(X-Origin-Verify 検証 + JWT 検証 + テナント一致)
   v
[Lambda (Node.js + Hono / Lambda-lith)]

このとき下した主な設計判断を書いておきます。

  • Lambda は関数分割せず Lambda-lith(1 関数に Hono で全ルート集約)。全ルートが同一実行ロールを共有する。
  • Cognito は 1 つの User Pool を全テナントで共有する Pooled モデル。テナント分離は App Client 単位 + アプリ側の custom:tenantId 突合で担保。
  • オリジン保護は API Gateway リソースポリシーや AWS WAF ではなく、CloudFront が付与するシークレットヘッダー X-Origin-Verify を Lambda Authorizer で検証する方式。
  • 単一リージョン(アジアパシフィック(東京)リージョン、ap-northeast-1)。DR は組んでいない。

やってみた

セットアップ

セットアップの詳細は先に検証されている記事があるので、そちらが分かりやすいです。
本記事は要点だけにします。
(とても尊敬している方の記事なのでそのまま紹介させてもらいます。)

まずエージェントプロファイルを作ります。適当に作ってみます。

CleanShot 2026-09-29 at 05.18.31.png

CleanShot 2026-09-29 at 05.21.29-1.png

指定した内容は次のとおりです。

項目 値
プロファイル名 multi-tenant
柱 コスト最適化 / セキュリティ / パフォーマンス / 信頼性の 4 つ
監視対象アカウント・リージョン 自アカウント × ap-northeast-1
実行ロール ExecutionRoleForWellArchitectedAgent(コンソールが自動生成)
アクセスロール AccessRoleForWellArchitectedAgent

現時点で東京リージョンは利用不可ですが、エージェントプロファイルを作るリージョンと、監視対象リージョンは別に指定可能です。

今回はプロファイルをオレゴン(us-west-2)に置き、監視対象に東京(ap-northeast-1)を指定しました。ワークロードが東京にあっても、Agent を動かすリージョンはそれに縛られません。

プロファイルを作ると「推奨事項を生成するために必要なアクション」というバナーが出て、アカウントアクセス用ロールの作成手順を案内されます。実行ロールとアクセスロールの二段構成の模様です。

警告も出ましたが、今回はクロスアカウントではないので、不要と判断してスキップしました。

Kiro 2026-09-29 05.37.24.png

Kiro 2026-09-29 05.37.25.png

レビューしてみる

アーキテクチャレビューには IaC アセットが必要で、事前に Zip 化して Amazon S3 にアップロードしておきます。git archive で固めています。

Kiro 2026-09-29 05.43.44.png

Kiro 2026-09-29 05.43.45.png

レビュー時には Well-Architected レンズを指定できるようですが、本記事執筆時点では Well-Architected フレームワークのみでした。
サーバーレスレンズや SaaS レンズが選べると、このワークロードには刺さりそうです。

アプリケーションコンテキストも指定できます。

CleanShot 2026-09-29 at 18.10.43.png

ただしこのドロップダウンは既存のものを選ぶだけで、ここから作れません。

実体は API 上の AgentContext(contextType は APPLICATION のみ)で、エージェントプロファイル配下のリソースです。
プロファイルを作った時点で「Default Application」が自動生成されており、中身は監視対象のアカウントとリージョンだけでした。選択肢がこの 1 件しか無いのはそのためです。

APIをのぞいてみると、CreateAgentContext の content に渡せる項目はもっとあります。

項目 内容
accountIds / regions 対象アカウント・リージョン
awsServices / resourceTypes / resourceTags 対象サービス・リソース型・フィルタリングタグ
applicationOverview / architectureOverview アプリケーション概要・アーキテクチャ概要
industry / applicationType / criticality 業種・アプリケーション種別・ミッションクリティカル度
additionalContext 追加コンテキスト

業種やミッションクリティカル度を効かせるには、これらを入れたコンテキストを別途作る必要がありそうですが、
コンソールに作成画面はなさそうな感じです。

今回は自動生成された状態のまま回したので、業種やミッションクリティカル度は未設定です。ここを埋めると精度が変わるのかは試せていません。

作成し、しばらく待つと「進行中」と出ます。

CleanShot 2026-09-29 at 05.51.58.png

実行から推奨事項の生成完了まで約 30 分でした。GetAgentRecommendation の createdAt が 06:15(JST)で、レビューを投げたのが 05:43 頃です。

結果

10 件出てきました。

CleanShot 2026-09-29 at 16.18.16.png

CleanShot 2026-09-29 at 16.18.51.png

内訳はコスト最適化 9 件、セキュリティ 1 件。優先度は中 8 件、低 2 件。信頼性とパフォーマンスは 0 件でした。

# 推奨事項 柱 優先度 労力 影響 ROI 見積もり
1 Add S3 lifecycle rules to SiteBucket to expire stale SPA artifacts コスト最適化 中 小 中 S3 ストレージ 30〜60% 削減
2 Add AWS Budgets and Cost Anomaly Detection to all CDK stacks コスト最適化 中 小 高 Bill shock リスク解消
3 Make CloudWatch Log Group retention configurable per environment コスト最適化 中 小 中 dev/staging のログコスト約 75% 減
4 Apply cost allocation tags to all BackendStack and FrontendStack resources コスト最適化 中 小 高 無駄の可視化
5 Enable API Gateway stage throttling and per-tenant usage plans on the v1 stage コスト最適化 中 中 高 上限なしコストリスクの抑制
6 Enable CUR data exports and hourly Cost Explorer granularity for the workload コスト最適化 中 中 高 無駄の可視化
7 Set a CloudFront price class on the MultiTenant distribution to reduce data transfer costs コスト最適化 中 小 中 CloudFront 転送 20〜40% 削減
8 Establish data-driven sizing and a metric feedback loop for all Lambda functions コスト最適化 中 小 中 GB-s 20〜40% 削減
9 Restrict the AnyPrincipal API Gateway policy and scope Lambda execution roles セキュリティ 低 中 高 過剰権限の除去
10 Introduce AWS Organizations account structure for BackendStack and FrontendStack コスト最適化 低 大 高 非本番環境 20〜35% 削減

指摘が具体的だった

description と insights に、対象ファイルと行番号、コード上の根拠まで書かれていました。

CleanShot 2026-09-29 at 16.24.52.png

たとえば 1 件目は SiteBucket(edge.ts 120 行目)に lifecycleRules がなく、さらに SiteAssetsDeployment(286 行目)と SiteHtmlDeployment(298 行目)が prune: false なので、デプロイごとにオブジェクトが増え続ける、というところまで指摘しています。

各件が根拠にしたコードは次のとおりです。

# 根拠にしたコード
1 edge.ts の SiteBucket に lifecycleRules なし + 2 つの BucketDeployment が prune: false
2 BackendStack / FrontendStack に Budgets・Cost Anomaly Detection の宣言なし
3 api.ts / auth.ts / authorizer.ts の 3 つの LogGroup で logs.RetentionDays.ONE_MONTH がハードコード
4 backend-stack.ts / frontend-stack.ts の super() に tags を渡していない
5 Api の deployOptions(stageName: 'v1')に throttle 系プロパティなし
6 metricsEnabled: true とログ保持設定はあるが CUR エクスポート未設定
7 edge.ts の CfnDistribution(Edge.MultiTenant)の distributionConfig に priceClass なし
8 constructs/api.ts の Api.Handler が memorySize: 256 と timeout: 29 秒 を静的リテラルで指定
9 Api のリソースポリシーに new iam.AnyPrincipal() + Effect.ALLOW + execute-api/*
10 backend-stack.ts / frontend-stack.ts の StackProps に env.account の区別なし

設計意図との照合

指摘を見てみると、コスト最適化に 9 件が集中していますね。

気にしていた、設計判断(lith 構成、Pooled Cognito、単一リージョン)よりも、コストのガードレールと可観測性の不足を指摘されました。

Budgets、コスト配分タグ、CUR、throttling など、ボイラープレートに入れていなかった運用側の仕組みが多いです。

信頼性とパフォーマンスは 0 件でした。

セキュリティの柱は #9 のみです。

指摘事項を直してみる

推奨事項には「修復を開始」というアクションがあります。自動で構成を書き換えてくれるわけではなく、修復手順をガイドしてくれるものでした。

CleanShot 2026-09-29 at 16.25.18.png

こんな感じで修復の方法をステップで教えてくれます。修復手順は CLI / CONSOLE / IAC の 3 タイプで提供されていました。

CleanShot 2026-09-29 at 16.26.22.png

項目ごとに対応状況をマークして進捗を管理し、完了したら「完了としてマークする」で一覧から消えます。アーカイブから戻すこともできる模様です。

API でも取れる

コンソールだけでなく API でも取得できました。ListAgentRecommendations で一覧、GetAgentRecommendation で 1 件の詳細(insights / roi / impactDetails / remediations)が取れます。

Agent 系のオペレーションは 23 個ありました。主に使うのは次のあたりです。

やること API
プロファイル一覧 ListAgentProfiles
推奨事項の一覧 ListAgentRecommendations
推奨事項の詳細 GetAgentRecommendation
修復ステップ ListAgentRecommendationItems
完了マーク UpdateAgentRecommendationStatus
フィードバック送信 PutAgentRecommendationFeedback

API で修復方針が取れるので、1 件ずつ AI に渡して PR にできます。優先度中の #1〜#3 を 1 件 1 PR で対応してみました。

手順は毎回同じで、GetAgentRecommendation の remediations から type: IAC のステップを取り出し、それをコンテキストに実装します。CDK リポジトリに落とすなら IAC が一番使えます。

結果として、3 件すべてで Agent の手順そのままでは使えず、手直しが必要でした。

# 推奨事項 PR Agent の手順への修正
1 Add S3 lifecycle rules to SiteBucket #9 提案 3 ルールのうち 2 つを不採用
2 Add AWS Budgets and Cost Anomaly Detection #10 4 点(うち 1 件はデプロイが失敗するバグ)
3 Make CloudWatch Log Group retention configurable #11 2 点(context の読み取り)

#1 SiteBucket のライフサイクルルール

一例で解説してみます。

Agent が提案したルールは 3 つ。うち 2 つは採用していません。SiteBucket はバージョニングを有効にしておらず、非現行バージョンと削除マーカーのどちらも存在しないためです。

  • noncurrentVersionExpiration(不採用)
  • expiredObjectDeleteMarker(不採用)
  • abortIncompleteMultipartUploadAfter(採用)

Agent は「prune: false によって版が蓄積する」と説明していましたが、実際に残るのはハッシュ名が変わった旧アセットで、これは現行オブジェクトであってバージョンではありません。
根拠のコードは正確に指していたのに、そこから導いた因果が間違っていました。

abortIncompleteMultipartUploadAfter(マルチパートアップロードの残骸を消すルール)は追加しましたが、あまり効果はなさそうです。

「prune: true」 にする対応でも良さそうです。

まとめ

連載で作ってきたマルチテナント SaaS ボイラープレートを、プレビューの Well-Architected Agent にかけてみました。

  • 自分が割り切った判断(lith、Pooled Cognito、単一リージョン)のうち、指摘があったのは Lambda サイジングと実行ロールの 2 件。コスト最適化に 9 件が集中し、本番稼働に向けた対応が不足していたことがわかる。
  • 指摘の粒度は高く、ファイル名・行番号・プロパティ名まで正確。一方で原因の説明と修復コードは検証が必要そう。
  • プレビューの所感として、公式ドキュメントは未整備、料金は未確認。CLI も botocore 1.43.70 以降が必要でした。ここは GA を待ちたいところ。

質問形式で自分の理解を確かめる従来の Well-Architected とは違って、作ったものを渡すと勝手に見てくれる体験は良いです。

ただし、最近は個々のモデルも相当に進化している中、自前で作ってしまった方が自由度や精度が高いものが作れそうな感じはします。

特に修正方法に関して、そのままでは適用できない部分があったので、ここらは自前で APIなど駆使し、Claude OPUS 5.5 などと決定していくのが良さそうです。

最後まで読んでいただきありがとうございました!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?