運び屋 (A carrier(forwarder) changed his career to an engineer)

AWS / Storage / Community / Cloud Native / Kubernetes / コンテナ / SRE / DevOps

ファイルポータルを何の上に作るか?Nx Plugin for AWS 1.0 / AWS Blocks / Amplify Gen 2 に同じ 4 機能を実装して比べた(ファイルポータル Part 7)

はじめに

Nx Plugin for AWS が 1.0 になり、AWS Blocks が preview で登場したことで、AWS でアプリを作り始める入口が 3 つになりました。今回はこれら 3 つの構築ツールを同じ規模まで生成し、同じ物差しでリソースを数え、実際にデプロイして 4 つの機能を実装し、最後に削除するという一連の流れを比較してみました。

本記事はシリーズの続きですが、「FSx for ONTAP S3 Access Point の上にファイルポータルが動いている」という前提さえ押さえていただければ、この記事単体で読める構成にしています。

執筆のきっかけは、AWS SA の方が書かれたZenn の記事を読んだことでした。他の方の比較検証は非常に参考になりますが、自分のプロジェクトの判断材料としては、やはり自身の手で「デプロイして消す」ところまでやってみないと本当のところは分かりません。

Part 1 では「ファイルポータルを何で作るか」というアプリケーション層の話をしましたが、今回はその構築ツールそのものに焦点を当てます。

本記事では以下の内容を中心に検証結果をまとめています。

  • 3 つの生成物のリソース数と、既定値から発生する固定費
  • 実機でのデプロイと動作確認
  • 同じ 4 機能を 3 つのツールで実装した際の差異
  • スタックを削除しても残ってしまうリソースと、正しい片付けの順序

※なお、各ツールの優劣、Nx や Monorepo の詳細な解説、生成コードの事後追従については本記事のスコープ外としています。

先に検証から得られた結論をまとめると、以下のようになります。

  • 構築ツールの選択は、あとで取り消せる範囲の判断です。データ経路は 3 者共通であり、ツールを乗り換えてもデータ基盤(FSx for ONTAP)側は作り直す必要がありません。
  • 差が出るのは「作れるか」ではなく、選んだあとに何が固定されるかです。デプロイは 3 つとも問題なく通りました。
  • 生成物の既定値によって、リクエストが 0 でも毎月の固定費が発生します。
  • スタックを削除しても残るリソースがあり、2 種類に分かれますRetain と削除保護は生成物の既定値なので生成コード側で外せます。テンプレートに存在しないロググループは CDK 内部のもので、こちらは外す経路がありません。回避できないのは KMS の待機期間だけです。
  • KMSなど、リソースによっては「削除完了(DELETE_COMPLETE)」が「即時削除」ではなく「削除予約(30日待機)」を意味する罠があります。

ツールを乗り換えても作り直しにならないデータ基盤

構成要素の差を、同一スコープ(Web + 認証 + API + テーブル)で並べてみます。S3 Access Point より背後にあるデータ経路はこのポータルの実構成で、3 パターンとも共通です。

Amplify Gen 2 でファイルポータルを組んだ場合の構成要素。Web ブラウザから AWS Amplify、AWS AppSync、AWS Lambda を経て Amazon S3 Access Point、Amazon FSx for NetApp ONTAP、NFS / SMB クライアントへ至る。AWS Amplify の横に Amazon Cognito、AWS Lambda の横に Amazon DynamoDB。既定で作られる AWS WAF とカスタマー管理 KMS 鍵はいずれも 0 件 図1: Amplify Gen 2 でファイルポータルを組んだ場合の構成要素

Amplify Gen 2 はこのポータルが実際に動いているフレームワークです。境界リソース(AWS WAF、顧客管理の KMS 鍵)は既定で作られません。認証は Amazon Cognito で、ティアは既定の ESSENTIALS です。

AWS Blocks の production preset でファイルポータルを組んだ場合の構成要素。Web ブラウザから Amazon CloudFront、Amazon API Gateway、AWS Lambda 13 関数を経て Amazon S3 Access Point、Amazon FSx for NetApp ONTAP、NFS / SMB クライアントへ至る。Amazon Cognito は無く、認証は Amazon DynamoDB 4 テーブルのうち 2 本が担う。カスタマー管理 KMS 鍵は 1 本 図2: AWS Blocks (production preset) でファイルポータルを組んだ場合の構成要素

AWS Blocks で注目すべきは Amazon Cognito が無いことです。認証は AuthBasic(DynamoDB + JWT)が担うため、マネージドサービスからテーブルへ役割が移ります。4 テーブルのうち 2 本が認証用で、どれも削除保護つきです。

Nx Plugin for AWS でファイルポータルを組んだ場合の構成要素。Web ブラウザから Amazon CloudFront、Amazon API Gateway (tRPC)、AWS Lambda、Amazon DynamoDB を経て Amazon S3 Access Point、Amazon FSx for NetApp ONTAP、NFS / SMB クライアントへ至る。経路上に AWS WAF が 2 本(CLOUDFRONT スコープは us-east-1、REGIONAL)、Amazon Cognito は PLUS で MFA 必須、AWS Key Management Service の鍵が 4 本 図3: Nx Plugin for AWS でファイルポータルを組んだ場合の構成要素

Nx Plugin for AWS は図の通り境界リソースが増えます。AWS WAF が経路上に 2 本(もう 1 本は us-east-1 の別スタック)、Amazon Cognito は PLUS で MFA 必須、KMS 鍵が 4 本作られます。これが後述する固定費の差に直結します。

3 つの図で S3 Access Point より背後のデータ層が共通していることには大きな意味があります。構築ツールを替えても FSx for ONTAP 側は作り直しにならないということです。今回の検証でも、FSx for ONTAP 側にはリソースの作成・削除を一切行っていません。

到達方法も 3 者で共通です。Internet origin の Access Point は、標準の S3 SDK にエイリアスをバケット名として渡すだけで届きます。VPN も SMB マウントも無しに、ブラウザから NAS 上のファイルを探して開いて、置くことができます。フェーズ 3(大容量アップロード等)までは Lambda を VPC に置く必要すらありません。


3つのツールで同じ4機能を実装・比較した結果(2026-09-14)

ここまではツールが生成した初期状態での比較でしたが、導入する人が本当に知りたいのは「自分のアプリを載せたときの差」です。そこで後日、サインイン / 一覧 / 読み取り / アップロードの 4 機能(API 名:listFiles / readFile / uploadFile)をそれぞれ実装し、同じ FSx for ONTAP S3 Access Point に向けて動かしてみました。

検証対象は同じ prefix(13 オブジェクト)、同じファイル(1,615 バイト、text/markdown; charset=utf-8)、同じ 24 バイトの書き込みに統一しています。結果として 3 者すべてで同じ値が返りました。

一覧の画面

AWS Blocks で組んだファイルポータルの一覧画面。prefix の入力欄に reports/2026/05/10/ が入り、13 objects と表示され、compliance-report-<uuid>.md が 13 行、サイズと更新日時つきで並んでいる AWS Blocks で組んだ一覧画面。13件のファイルが並ぶ。

Nx Plugin for AWS で組んだファイルポータルの一覧画面。左に生成された shadcn のサイドバー、本文に同じ prefix と 13 objects、同じ 13 行が並んでいる Nx Plugin for AWS で組んだ一覧画面。shadcn のサイドバーが生成されている。

Amplify Gen 2 のファイルポータルの一覧画面。パンくずが / reports / 2026 / 05 / 10 と辿られ、同じ 13 ファイルが親フォルダへの .. と一緒に並び、各行に star とダウンロードのアイコンがある Amplify Gen 2 の一覧画面。実運用のポータルのため、star やダウンロードアイコン等の機能が追加されている。

読み取りの画面

AWS Blocks の読み取り画面。1615 bytes、text/markdown; charset=utf-8 の表示の下に、日本語のコンプライアンスレポート本文がページ内に描画されている

Nx Plugin for AWS の読み取り画面。ヘッダは portal-web、compliance-report-<uuid>.md の下に 1615 bytes・text/markdown; charset=utf-8 と出て、同じレポート本文がページ内に描画され、その下に Upload の欄が続く

上の 2 つは、レポート本文がページ内に描画されています。対して下の Amplify Gen 2(実運用ポータル)では本文は描画されず、AI Assistant パネルに渡す設計にしています。

Amplify Gen 2 のポータルで同じファイルを開いた画面。本文は描画されず、右側に AI Assistant のパネルが開いて対象ファイル名と「Analyze document」が表示されている

余談ですが、撮影の副産物として、自分のポータルのアクセシビリティ不具合が 1 件見つかりました。ファイル行の書類アイコンが aria-label="Download <ファイル名>" を名乗っているのに、実際の動作は「AI 処理用の選択」になってしまうというものです。title 属性には両方書いてあるものの、スクリーンリーダーが読み上げるのは Download だけなので、視覚支援を利用する方にはダウンロードのつもりで AI 処理を実行させてしまいます。執筆時点では未修正で、修正対象として記録しています。 3 者を並べる作業をしていなければ、たぶん気づきませんでした。

アップロードの画面

AWS Blocks のアップロード画面。見出しは File Portal — AWS Blocks、prefix が portal-parity/blocks/ で 1 object、書き込んだ note-2026-09-14.txt が 35 B で一覧に出ている。下にファイル名と本文の入力欄と Upload ボタンがあり、書き込みは portal-parity/blocks/ の外に出せないという注記が添えられている

Nx Plugin for AWS のアップロード画面。見出しは File Portal on Nx Plugin for AWS、副題は Amazon FSx for NetApp ONTAP S3 Access Point, via tRPC procedures。prefix が portal-parity/nx/ で 1 object、書き込んだ note-2026-09-14.txt が 24 バイトで一覧に出ている

上の 2 枚はアップロード成功直後の画面です。 下の Amplify の画面は、同名ファイルの上書きをサーバ側で拒否した際の状態です(ツールの差ではなく、私が実装した挙動の差です)。

Amplify Gen 2 のアップロード画面。左サイドバーに All Files・Favorites・Recent・Upload・AI Processing・Job History・Snapshots・Lock・ARP/AI・Version Diff が並ぶ。アップロードキューの note-2026-09-14.txt は 24 B で、状態が Overwrite prevented、進捗 0%。下に Overwrite prevented for all files. の警告が出ている

IAM権限の記述におけるツールの差異

S3 Access Pointへの到達方法は 3 者で同じですが、IAM の記述には注意が必要です。3 者とも「アクセスポイント形式」の ARN でないと通りません。

arn:aws:s3:<region>:<account-id>:accesspoint/<name>          # ListBucket
arn:aws:s3:<region>:<account-id>:accesspoint/<name>/object/* # GetObject, PutObject

バケット形式(arn:aws:s3:::<alias>)で記述すると、デプロイ自体は成功してしまいますが、実行時に list / get / put の 3 操作すべてが AccessDenied で落ちるという分かりにくい挙動になります。

特に AWS Blocks の FileBucket.fromExisting(alias) は内部でバケット形式の権限を生成してしまうため、ローカルテストは通るのにデプロイ後に動かなくなるという罠を踏みました。

不正入力が弾かれる「層」の違い

任意のディレクトリを遡るような不正な入力(../escape.txt)を試したところ、ツールによって拒否する層が異なることが分かりました。

入力 Nx Plugin for AWS AWS Blocks
../escape.txt HTTP 403 {"message":"Forbidden"} (WAFでブロック) アプリケーションのドメインエラー
空のファイル名 HTTP 400 + アプリケーションのエラー アプリケーションのドメインエラー

Nx の生成物では、AWS WAF が Lambda の手前でリクエストをブロックしました。多層防御が既定で有効なのは素晴らしいですが、拒否の理由が汎用の HTTP 403 になるため、エラー調査の起点が「自分のコード」から「WAFのメトリクス」に変わる点は運用上の留意事項です。

4機能実装時の計測スコア(デプロイ時間とリソース数)

デプロイ時間 リソース数 業務用 Lambda
AWS Blocks(production preset) 318 秒 82 1 本(API 全体)
Nx Plugin for AWS(sandbox) 307 秒 100 5 本(手続きごと)

※Amplify Gen 2 については、すでに実運用しているポータルを利用したため、今回の初期構築時の計測(デプロイ時間・リソース数)からは除外しています。

注目すべきは、AWS Blocks でローカルの e2e テストが通ったからといって、実環境で Access Point に届く保証はないという点です。モック環境でのテストはあくまでモック内に閉じてしまうためです。


初期状態(スターター)でのデプロイ検証(2026-09-13)

CloudFormation テンプレートの生成(synth)だけで検証を終えてしまうと、実際にリソースを削除する際の課題に気づくことができません。そこで、今回は 3 つのツールすべてにおいて、機能を追加する前の初期生成されたままの状態で、実際の AWS 環境へデプロイを行いました。

生成物 リソース デプロイ 動作確認
AWS Blocks(sandbox preset) 83 JSON-RPC で signUp 等が 200
AWS Blocks(production preset) 117 1,228 秒 5 操作すべて 200。CloudFront 配信も 200
Nx Plugin for AWS 86 317 秒 TOTP 登録 → Identity Pool 経由で API が 200

デプロイ自体はいずれも問題なく成功しました。Blocks の production preset のデプロイ時間が長いのは、DynamoDB が GSI を 1 本ずつ作成するためです。


リクエストゼロでも発生する固定費

生成物の既定値は、テンプレートに明記されていなくても月額に効いてきます。構築ツールを選ぶ時点で決まってしまうので、作り始める前に見ておく値です。

リクエストが 1 件も来ていない状態での、各ツールの固定費は以下の通りです(FSx for ONTAP 側の費用は含みません)。

生成物 WAF KMS CMK 月額の固定費
Nx Plugin for AWS 3 ACL + 6 ルール = $21 4 本 $4 $25 から
AWS Blocks(production preset) なし 1 本 $1 $1
Amplify Gen 2(スターター) なし なし $0

Nx の初期費用が高いのは「本番で必要になるセキュリティが最初から入っている」からです。ただ、検証用に立てて放置すると意外とコストがかかる点には注意が必要です。


実運用に向けて今後追加が必要な機能

ポータルとしての機能拡張をフェーズ別に整理しました。自分の要件がどのフェーズで止まるかによって、ツールの選定基準も変わります。

フェーズ 追加する機能 VPC 接続 新しく要るもの
1 ページング・検索・並び替え 不要 なし
2 ダウンロードと共有リンク 不要 presigned URL と有効期限の方針
3 大きいファイルのアップロード 不要 マルチパート等
4 ONTAP の情報表示 必要 管理 LIF への到達、関数の分離
5 ONTAP の操作 必要 監査ログ、不可逆操作の承認
6 AI 処理 対象による 確信度の閾値、データ分類

フェーズ 4 からは ONTAP の管理 LIF に届く必要があり、ここでLambda を VPC に置く判断が発生します。ここから NAT Gateway などの固定費も乗ってくるため、フェーズ 5 以降を見据えるなら、初期段階から「S3 Access Point 用の関数」と「ONTAP 管理用の関数」を分離しておく設計が推奨されます。


評価環境の後片付け — 削除しても残るもの

ここはポータルの運用ではなく、評価に使った環境を戻すときの話です。作ったら数年動かすものなので、削除するのは試している段階だけです。それでも、いくら残るかは試す前に知っておきたい値でした。

スタックを削除したあとに何が残るかを確認したところ、テンプレートの静的解析(synth)では見えなかったリソースが多数見つかりました。

生成物 スタック削除後に残ったもの
Blocks(sandbox preset) ロググループ 5 件
Blocks(production preset) DynamoDB 4 本(削除保護)、ロググループ 8 件、KMS 1 本(待機中)
Nx Plugin for AWS Cognito User Pool 1、DynamoDB 1 本、KMS 4 本、IAM ロール 2 本、ロググループ 7 件

この表の 8 件・9 件は生成物の既定値で、AWS 側の制約ではありません。 Retain も削除保護も生成されたコードが付けているので、消えてよいものは生成コード側で外せます(CDK なら RemovalPolicy.DESTROY、DynamoDB と Cognito の削除保護は該当プロパティを false にする)。既定が保持側に寄っているのは本番を想定した設計で、検証用に使うときだけ意図と噛み合いません。

特に厄介なのがロググループです。CDK やツールのカスタムリソース用 Lambda が初回実行時に無期限で作るため、CloudFormation の管理外となってスタック削除後も残り続けます。対策として、後片付けの最後に以下のコマンドで走査する必要があります。

aws logs describe-log-groups --log-group-name-prefix "/aws/lambda/<stack-name>" \
  --query "logGroups[].[logGroupName,retentionInDays]" --output text

また、削除の順序にも罠があります。Nx の User Pool は削除保護を外さないと消せませんが、その解除に必要な SMS 設定が、上の表で「残ったもの」に挙げた IAM ロール 2 本のうちの 1 本を参照しています。残ったものを片付ける段で IAM ロールを先に消すと、削除保護を外す経路そのものが失われます。 User Pool を消してから IAM ロールを消す、という順序になります。

ロググループは、自分の関数と CDK 内部のもので扱いが違います。 自分で書く Lambda はテンプレートでロググループを宣言できるので残りません(実測でも宣言済みのものは 3 構成すべて消えました)。残るのは CDK 内部のカスタムリソースのぶんで、こちらは自分のコードから宣言する経路がありません。CustomResourceProvider の基底クラスが宣言するのは IAM ロールと Lambda 関数の 2 つだけで、ロググループを含まないためです(custom-resource-provider-base.ts を全文で確認、2026-09-16)。

修正された版は存在しません(2026-09-16 確認)。上流には要望が 2 件 open で立っています(aws-cdk #26553aws-cdk #23909)。3 件目の aws-cdk #24815 は completed でクローズされていますが、クローズ時のコメントで AWS のメンテナが「修正 PR は revert した、これは全カスタムリソースに共通の問題で、追跡を #23909 に移す」と述べています。クローズは出荷の証拠になりません。

AWS サポートには問い合わせていません。Lambda の暗黙生成と無期限の既定はドキュメントに書かれており、CDK が何を宣言するかはソースで読めます。そして CDK の一次窓口は AWS Support ではなく GitHub リポジトリです。出すとしたら、上のどちらの issue にも載っていない「3 構成それぞれで何件残ったか」という実測値になります。


運用時に誤解しやすい2つの仕様

ドキュメント通りに操作しても読み間違えやすい挙動が2点ありましたので、共有しておきます。

罠1:デプロイモードの指定(express等)は後から外せない

Nx が生成する deploy-sandbox は裏で cdk deploy ... --express を実行します。もしデプロイが壊れた場合、「--express を外して再実行」しようとしても、express で更新されたスタックは以降の操作も express であることを要求します。正しい手当ては最初から --express --rollback を併用することです。

罠2:「DELETE_COMPLETE」が即時削除を意味するとは限らない

CloudFormation で DELETE_COMPLETE と表示されても、リソースの種類によっては本当に消えたわけではありません。例えば KMS 鍵の場合、DELETE_COMPLETE は「即時削除」ではなく「削除を予定した(既定 30 日の待機に入った)」ことを意味します。この待機期間は後から短縮できないため、残存リソースの確認は一覧画面等から実状態を見る必要があります。


各ツールの選び方(まとめ)

3 つのサービスは排他的ではなく、目的に応じて選ぶものです。

  • Nx Plugin for AWS: 本番寄りの既定値と堅牢な依存管理が欲しい場合。固定費はやや高め。
  • AWS Blocks: AWS アカウント無しでローカル開発を完結させたい場合(プレビュー版につき Block ID の扱いに注意)。
  • Amplify Gen 2: バックエンド定義とホスティングを一体で手軽に扱いたい場合。

ファイル共有中心なら Nextcloud、AI 処理と ONTAP 管理操作中心なら Amplify Gen 2 という Part 1 での結論自体は変わっていません。今回はその「構築ツール」においてどのような差が出るかを確かめました。


検証環境

項目
計測日 2026-09-13(初期状態の実機)、2026-09-14(4 機能を実装しての実機)
リージョン ap-northeast-1(Nx の CloudFront 用 Web ACL のみ us-east-1)
生成物 Nx Plugin for AWS 1.0(@aws/nx-plugin@1.0.0)、AWS Blocks(preview)、Amplify Gen 2(npm create amplify
ローカル Node.js v26.4.0、npm 11.17.0
価格の取得 AWS Price List API、ap-northeast-1、2026-09-07
後始末 すべて削除済み。KMS 5 本のみ待機期間中(PendingDeletion は課金されません)

リポジトリ側の記録

数値・出典・後片付けの手順はリポジトリに置いてあります。記事より詳しいです。


おわりに

この Part で並べた検証結果は、どれも「既定値」に関する話です。ツールを選んだ時点で最低限かかる固定費と後片付けの手順が決まりますが、それはテンプレートには書かれていません。

今回の検証で最も効いたのは、同じ 4 機能を 3 通り書いてみたことでした。ツールの差は「コードを書く量」ではなく「コードを書く場所」や「エラーを弾く層」として現れます。構築ツールを選ぶということは、障害時に「最初に見る場所」を選ぶことと同義なのかもしれません。

この検証記録が、同じような技術選定で迷っている方の参考になれば幸いです。


検証環境はすべて削除済みです(KMS のみ待機期間中)。数値は特定の環境・条件での実測値であり、ワークロードや構成によって異なります。価格は 2026-09-07 時点の ap-northeast-1 の公表単価です。