TECH PLAY

電通総研

電通総研 の技術ブログ

835

はじめに エンタープライズ 第一本部の佐藤です。 本記事は 電通 総研 Advent Calendar 2025 13日目の記事です。 さくらのクラウド がアプリケーションの実 行基 盤となる「AppRun」等の正式なサービスを2025年12月9日から開始しています。 この記事は、AppRunの使用を通じて国産 クラウド の現在地を把握してみるのが本旨となります。 はじめに AppRun 概要 コンテナレジストリのデモ 概要 イメージの作成 レジストリの作成 ユーザーの作成 イメ―ジのpush AppRunのデモ 起動の設定 起動確認 デプロイ戦略 今回作成したリソースの料金 感想 AppRun 概要 「AppRun」は、コンテナイメージをもとにアプリケーションを自動デプロイし、スケーリングや運用管理をシームレスに実行できるマネージドサービスです。 引用元: https://www.sakura.ad.jp/corporate/information/newsreleases/2025/12/09/1968222395/ このAppRunのデモの前に さくらのクラウド 上にイメージをpushしておく必要があるので、以下の手順を実施しています。 コンテナ レジストリ のデモ 概要 「コンテナ レジストリ 」はDockerなどのコンテナエンジンが扱うイメージファイルを保管する レジストリ 機能を さくらのクラウド 上で提供するサービスです。 引用元: https://manual.sakura.ad.jp/cloud/appliance/container-registry/index.html イメージの作成 デモで使用するコンテナのイメージを作成します。 今回試すサーバーはgoで以下のように記述しました。 package main import ( "fmt" "net/http" "log" ) func main() { http.HandleFunc( "/" , func (w http.ResponseWriter, r *http.Request){ log.Printf( "%s %sのリクエストがありました" , r.Method, r.URL.Path) fmt.Fprintf(w, "こんにちは!さくらのクラウド!" ) }) http.HandleFunc( "/health" , func (w http.ResponseWriter, r *http.Request){ log.Printf( "%s からヘルスチェック" , r.RemoteAddr) w.WriteHeader(http.StatusOK) fmt.Fprintf(w, "OK" ) }) log.Println( "Starting server on : 30080" ) err := http.ListenAndServe( ":30080" , nil ) if err != nil { log.Fatal(err) } } イメージをビルドし、 server-demo と名前を付けています。 レジストリ の作成 次にこのイメージをpushする レジストリ を作成します。 手順 通りに作成します。 以下のような画面で作成しました。 📝(余談)アイコンは自分で作成できるので マニュアル を参考に手書きの実家の犬アイコンを自作しました。 ユーザーの作成 以下の画像のユーザーのタブで新規に作成しました。 ユーザー作成時に指定したユーザー名とパスワードでDockerのログインを実施します。 イメ―ジのpush 次にdockerコマンドで server-demo イメージにタグを付与します。 docker tag server-demo:latest <レジストリ名>/server-demo:latest レジストリ へのログインを実施します。 コマンドは以下を実施します。 docker login [コンテナレジストリ名] Username: [ユーザ名] Password: [パスワード] タグ付けした server-demo イメージをpushします。 docker push <レジストリ名>/server-demo:latest このイメージが GUI のコンテナ レジストリ から確認できるのかなと思いましたが、私は見つけられませんでした。 AppRunのデモ 起動の設定 アプリケーションの作成画面で共有型を選択し、起動します。 以下のようにアプリケーションの設定をしました。 コンテナの設定は以下のとおりです。 IPアドレス の指定等も項目でありますが、家のネットワークは IPアドレス が固定できないのでスキップしました。 ログの送信はfluentbit, opentelemetry-collectorを使用するとありましたが、標準/エラー出力はそのままログに記録されるので今回はこれを有効にして確認することにしました。 メトリクスの送信はPrometheus, opentelemetry-collectorが使用できるのですが、検証のための実装が手間だったので省きました。 ログやメトリクスを収集するモニタリングスイートの詳細は https://manual.sakura.ad.jp/cloud/appliance/monitoring-suite/index.html を参照してください。 この設定でアプリケーションを作成し、起動を確認してみます。 起動確認 画像のように起動を確認することができました。 ブラウザで公開URLにアクセスしたところレスポンスも表示されました。 ちなみにログでは以下のようになっています。 10秒間隔でヘルスチェックをしていますが、2025-12-15 00:27:11を最後にこれが止まっており、 トラフィック がないので最初に設定したゼロスケールが実行されていることが確認できます。 この状態で再度URLにアクセスするとレスポンスが返るまで体感で5~6秒かかりました。 デプロイ戦略 アプリケーションの構成を変更してデプロイから、新たなイメージをデプロイします。 新たなイメージは以下の記述を変えただけです。 fmt.Fprintf(w, "こんにちは!さくらのクラウド!v2" ) バージョン情報を確認するとv2が増えました。 この時点ですでに変更済みですが、操作の項目から トラフィック 管理を押下し、50%で分配するようにしました。 2回に1回は以下のようになりました。 今回作成したリソースの料金 サービス 料金 補足 コンテナ レジストリ 月額220円 ストレージ5GiB/1 レジストリ (超過分は1GiBごと22円) AppRun(共有型/0.5vCPU × 1GiB メモリ) 約5円/1時間 - モニタリングスイート(ログ) 月額110円 ユーザ領域 ストレージ1GiB/1件 参照: https://cloud.sakura.ad.jp/products/container-registry/ https://www.sakura.ad.jp/corporate/information/newsreleases/2025/12/09/1968222395/ https://cloud.sakura.ad.jp/news/2025/11/11/3service_formalization/ 感想 ベータ版の時から結構良く見られた感想ですが、設定項目が少なくて簡単でした。 ドキュメントが日本語話者が書いた日本語なのも理解しやすさに貢献していると思います。 設定項目が少ないメリットの一方で、それは柔軟性・拡張性との トレードオフ なのでここは手放しに素晴らしいとは言えないですね。 IaC化も Terraform for さくらのクラウド(v2) で、できます。 個人的にはゼロスケールしてくれるのがいいなと感じており、個人レベルのサービス立ち上げ時に トラフィック がないのに ランニングコスト だけがかかる問題を解消できそうです。 今回の検証で興味が出てきたので、体系的にサービスの概要をつかめるように さくらのクラウド検定 を受けてみようかなと思います。 受験費用が一般 11,000円(税込)で「 さくらのクラウド 」クーポン 50,000円分(一般・学生共通)がもらえるのがいいですね。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @sato.yu レビュー: @miyazawa.hibiki ( Shodo で執筆されました )
こんにちは、 電通 総研のグループ経営ソリューション事業部でエンジニアをしている大浦です。 本記事は 電通総研 Advent Calendar 2025 12日目の記事です。 昨日の記事は、上野さんによる TanStack AI × Amazon Bedrockで作るAIチャットボット でした。 フロントエンドを起点に AI を組み立てる アーキテクチャ の考え方が興味深く面白かったです。 今回は、 モノリス で作られたアプリから、1つの機能をマイクロサービスとして切り出す判断についてお話します。 1 はじめに 1.1 注意点 2 そもそもマイクロサービスを切り出すべきか 2.1 モノリスで得られるPros 2.1.1 安定性 2.1.2 デプロイ容易性 2.1.3 実装容易性 2.2 モノリスのCons 2.2.1 認知負荷の増加 2.2.2 リードタイムの増加、リリースサイクルの長期化 2.2.3 柔軟なスケールが実施できない 2.2.4 ライブラリの衝突 3 切り出すと判断したら何を切り出すか 3.1 切り出す価値が高い機能 3.1.1 リリースサイクルや設定変更の周期が製品本体とは違う 3.1.2 機能固有の依存を持つ 3.1.3 機能単位でスケールアウトなどの構成を取りたい 3.1.4 特定の環境でのみ利用される機能 3.2 切り出しやすい機能 4 どのように切り出すか 4.1 モノリスで実現した場合 4.1.1 通知サービスのインターフェース 4.1.2 通知サービスの実行クラス 4.1.3 build.gradleの依存 4.2 マイクロサービスによる切り出しを行った場合 4.2.1 (補足) マイクロサービスの実装言語としてGoを選んだ理由 4.2.1.1 Goは単一バイナリとして配布できる 4.2.1.2 高並行な I/O 処理を素直に書ける 4.2.1.3 起動が速く、リソース特性が読みやすい 4.2.2 モノリス側(Spring) 4.2.3 切り出したマイクロサービス側 4.3 この例についての補足 (本番運用を考えた場合) 5 まとめ 1 はじめに SaaS アプリケーションの構成として、マイクロサービス化を進めているというサービスについて目にする機会が増えました。 あわせて「最初からマイクロサービスで作るのではなく、 モノリス で作り始めて必要になったらマイクロサービス化しましょう」という意見を聞くことも多いかと思います。 Martin Fowlerも以下のように述べています。 「成功したマイクロサービスのほとんどは、最初からマイクロサービスだったわけではない。 まずモノリスとして作られ、それが肥大化して“割らざるを得なくなった”結果として生まれている。」 「逆に、最初からマイクロサービスとして作られたシステムで、うまくいった例はほとんど聞かない。 私の知る限り、そうした多くは深刻な問題を抱えることになっている。」 ※原文は以下の2点(著者意訳) 1.Almost all the successful microservice stories have started with a monolith that got too big and was broken up 2.Almost all the cases where I've heard of a system that was built as a microservice system from scratch, it has ended up in serious trouble. ref) https://martinfowler.com/bliki/MonolithFirst.html マイクロサービスに分割断面を見出し「分割する」という話は書籍やネットで見つけることができます。 ( ドメイン 境界で切りましょう。チーム構成で切りましょう。など) 本記事では、大きな分割断面を見つけるのではなく、 モノリス をマイクロサービス化するための第一歩として 「機能を切り出す」ということにフォーカスした話をします。 ビジネスの拡大に合わせて成長してきた モノリス アプリを前提に以下の3点を扱います。 そもそもマイクロサービスを切り出すべきか 切り出すと判断したら何を切り出すか どのように切り出すか 1.1 注意点 以降は筆者が今までに モノリス から機能を切り出す or 切り出さない判断をしてきた中で考えてきたことを元に記載しています。 正解を提示するよりは、判断のための問いや観点を共有することを目的としています。 もし、誰かにとって議論のきっかけになればとても嬉しいです。 2 そもそもマイクロサービスを切り出すべきか 「プロジェクト開始早々にマイクロサービスにするな。」という意見が広く納得されている背景として、 モノリス ならではの Pros/Cons があります。 マイクロサービス化は、「現状の モノリス から得られるProsを失ってでも、Consを解消する価値がある」と合意出来ている場合に実施を検討します。 2.1 モノリス で得られるPros 2.1.1 安定性 エンタープライズ アプリでは基本的に、ACID特性を持つ トランザクション が重要です。 モノリス 構成(=多くの場合単一のDBで構成)である限り、 トランザクション の整合性をシンプルに保てます。 もし機能を 疎結合 にするために複数のDBにまたがった トランザクション を構成する場合には、分散 トランザクション や結果整合性など、より複雑な判断が必要です。 2.1.2 デプロイ容易性 モノリス は通常デプロイ単位が1つであり、実行や停止、スケールをまとめて実施できます。ログも集めやすいです。 特にオンプレミス環境での動作が求められる場合には、デプロイ単位が1つであることで、運用における各種手順を容易にできるなどのメリットもあります。 2.1.3 実装容易性 モノリス は基本的に、 コンパイル 時にアプリ全体が含まれます。 Java などの静的型付け言語では、型やインターフェースの不一致を実行前に コンパイル エラーとして検知できます。 2.2 モノリス のCons 2.2.1 認知負荷の増加 製品のコードベースが大きくなるにつれて、1つの機能変更の影響範囲が広がりやすくなります。 これは、コードベースの認知負荷の増加に繋がります。 2.2.2 リードタイムの増加、リリースサイクルの長期化 変更時の影響範囲の広がりは、修正時のビルド時間、検証事項の増加、変更時の 回帰テスト 範囲の増加に繋がります。 この結果、リードタイムが伸び、変更が慎重に実施されることでリリースサイクルが長くなる、という問題に繋がります。 これは、新機能の知見を持ったチームがPoCを実施する場合の足かせになります。 2.2.3 柔軟なスケールが実施できない 単一ファイルとしてデプロイする以上、特定の機能だけスケールさせる。といったことはできません。 例えば、特定の時期にだけ重い処理がある場合でも、アプリケーション全体をまとめてスケールアップさせる必要があります。 また、単一デプロイ単位で大きくなるとメモリフットプリントが増加し、スケール時に重要な起動時間の増加にもつながります。 2.2.4 ライブラリの衝突 外部ライブラリなどの依存追加により、ライブラリの衝突などがおこるようになる可能性が高まります。 3 切り出すと判断したら何を切り出すか では、製品が育ってきて モノリス の辛みが顕在化してきた場合に、どの機能を切り出すかを考えてみます。 切り出しは多くの場合、少なくとも以下の2軸を検討する必要があります。 切り出す価値があるか 切り出しやすいか 以下に、切り出す価値が高いと考える機能の性質を記載します。 切り出す価値が、切り出しやすさやマイクロサービス化の辛みを引き受けてでも実現する価値があるかを検討し、切り出しポイントを決めましょう。 3.1 切り出す価値が高い機能 3.1.1 リリースサイクルや設定変更の周期が製品本体とは違う 競争優位性を得るために迅速な フィードバックループ を回すことが求められる機能は、切り出して本体と独立してリリースできるとビジネス上の効果が高いです。 「○○機能チーム」など特定のチームが担当している機能の場合には、他チームとのコミュニケーションパスを限定することで生産性を高めることにつながることもあります。 3.1.2 機能固有の依存を持つ サードパーティー SDK が必要である機能や、外部サービスへの依存が強い機能を切り出すと、製品本体の依存関係を単 純化 できます。 依存ライブラリが増えると、ライブラリ衝突のような問題に突き当たることがあり、依存が増えるごとにリスクは高まります。 また、もしライブラリの 脆弱性 などが出た場合にも影響範囲の局所化や修正の反映が迅速になります。 ライブラリ依存を増やさないようにするための手段としての切り出しも価値があると考えています。 3.1.3 機能単位でスケールアウトなどの構成を取りたい BI処理など、データの増加に伴いリソース使用量や時間の増加が大きい機能は、切り出すと個別のワークロードを見たスケール判断ができます。 また、月末だけ高負荷がかかるなど ピーキー な振る舞いを持つ機能は、メインのアプリはそのままでスケールアップ/スケールアウトが実現できます。 3.1.4 特定の環境でのみ利用される機能 アドオンやオプション機能など、利用有無が顧客や環境によって異なる機能を切り出せると、製品本体品質の維持につながります。 本体から分離することで、認知負荷やテスト範囲を抑えられます。 もし モノリス の中で実現する場合、アドオンやオプションの変更が製品本体の再テストやバージョンアップの足かせとなることがあります。 3.2 切り出しやすい機能 切り出しやすさについても記載します。 ただ、切り出しやすさよりも切り出す価値の方が重要です。 切り出す価値が高い機能であっても、以下のような性質がある場合には切り出しコストに見合わないことが多く、切り出しを行わない根拠になると考えます。 データの所有権が分離できない 厳密な同期 トランザクション が必須 境界仕様が頻繁に変わる 4 どのように切り出すか ここでは、具体例として Spring Framework で作成されている経費申請アプリケーションの通知機能を切り出します。 Slack, Teams, LINE, メールと、複数の通知先をもつケースを想定しています。 最初に留意点を記載します。 以下の通知は、マイクロサービス分割の中でも比較的易しい題材となります。 = 状態をほぼ持たず、結果整合性を許容しやすく、失敗しても業務停止になりにくい だからこそ、 モノリス からの最初の切り出しを試すうえで有効と考えます。 また、本番運用をするうえで考慮が必要なポイントについては、「4.3 この例についての補足 (本番運用を考えた場合)」として後述しています。 4.1 モノリス で実現した場合 まずは、Spring Bootで作られた モノリス アプリです。 マイクロサービスとして切り出す前の状態として提示しています。 ※今後の説明に重要な部分のみ記載しています。 ※通常のSpringアプリの範囲なので全ては説明していません。 もし動くコードを見たい場合は、以下のコードと共に生成AIに聞くことで生成してくれると思います。 4.1.1 通知サービスのインターフェース Java においては以下のようなインターフェースがあります。 public enum NotificationChannel { SLACK, TEAMS, LINE, EMAIL } public record NotificationRequest( NotificationChannel channel, String to, // SlackのチャンネルID / メールアドレス / LINEのuserId など String subject, // 表題 String message // 本文 ) {} public interface NotificationService { void send(NotificationRequest request); } 4.1.2 通知サービスの実行クラス NotificationServiceを実装したクラスNotificationServiceImplは以下です。 ※大規模 エンタープライズ アプリケーションであればStrategyパターンを用いて、各通知先ごとにクラスを作る構成にすることが多いと考えますが、ここでは簡単のため、全ての実処理をNotificationServiceImpl内に記載しています。 // package jp.co.example.notification.infrastructure; @Service public class NotificationServiceImpl implements NotificationService { @Override public void send(NotificationRequest request) { switch (request.channel()) { case SLACK -> sendSlack(request); case TEAMS -> sendTeams(request); case LINE -> sendLine(request); case EMAIL -> sendEmail(request); default -> throw new IllegalArgumentException( "Unsupported channel: " + request.channel()); } } private void sendSlack(NotificationRequest request) { // Slack用の通知処理 } private void sendTeams(NotificationRequest request) { // Teams用の通知処理 } private void sendLine(NotificationRequest request) { // Line用の通知処理 } private void sendEmail(NotificationRequest request) { // Eメール用の通知処理 } } 4.1.3 build.gradleの依存 各種通知処理に SDK を利用する場合、build.gradleやpom. xml にSlackやLineなどの SDK への依存が追加されます。 この通知のためにしか使わない多くの SDK が追加され、Jar Hellの危険が増します。 4.2 マイクロサービスによる切り出しを行った場合 ここでは、実際の通知処理をGoで書かれたマイクロサービスに切り出してみます。 4.2.1 (補足) マイクロサービスの実装言語としてGoを選んだ理由 マイクロサービス側の実装言語は、必ずしも Go である必要はありません。 Java 、Kotlin、Node.js、 Python など、要件を満たす選択肢は複数あります。 チームの技術スタックを統一したい場合や、重厚な ドメイン ロジックを持つ機能を切り出す場合には、 Java を選ぶことも十分に妥当と考えます。 本記事の例でGoを選んでいる理由は、 「通知機能を切り出したマイクロサービス」という文脈において、運用・構成のコストが低い と判断しているためです。 具体例をいくつか挙げます。 4.2.1.1 Goは単一バイナリとして配布できる Goでビルドしたアプリケーションは、単一の実行バイナリとして配布できます。 JVM やランタイム、依存ライブラリを別途考慮する必要がなく、以下のような運用上のメリットがあります。 デプロイ、プロセス常駐のための運用手順が単純 実行環境の差異によるトラブルが起きにくい 4.2.1.2 高並行な I/O 処理を素直に書ける 通知処理は、多くの場合(CPUバウンドではなく) I/O バウンドです。 Webhookや外部 API 呼び出しを多数並列に処理するケースでは、goroutineによる軽量スレッドが実装と保守の両面で扱いやすいと感じています。 (また主観ですが、async/awaitや.then()などを駆使するよりも個人的にgoroutineの方が読みやすいです)。 4.2.1.3 起動が速く、リソース特性が読みやすい Goアプリケーションは起動が速く、メモリ使用量も比較的予測しやすいです。 これは、以下のような場面で効いてきます。 オートスケール時の立ち上がり 障害復旧時の再起動 4.2.2 モノリス 側(Spring) まず、 Java 側は通知を呼び出すだけにします。 = 通知処理を切り出したマイクロサービスに委譲する。 @Service public class NotificationServiceImpl implements NotificationService { private final RestTemplate restTemplate; private final String baseUrl = "http://localhost:8081" ; // goプロセスのURL, 本来は設定から読み込む @Override public void send(NotificationRequest request) { try { String url = baseUrl + "/api/v1/notify" ; restTemplate.postForLocation(url, request); log.info( "Notification delegated: channel={}, to={}" , request.channel(), request.to()); } catch (RestClientException e) { log.error( "Notification delegation failed: channel={}, to={}" , request.channel(), request.to(), e); // 恐らくここは設計判断が必要、ログだけ出して握り潰す?業務エラーにする? throw new RuntimeException( "Failed to delegate notification" , e); } } } 通知を依頼するためのHTTPリクエストを投げるだけになっています。 実際に通知をする処理を委譲したことで、通知先毎の各種 SDK はアプリ本体側では不要になりました。 実際に送信されるリクエストは以下のような構造になる想定です 例) Slackへの承認依頼Post { " channel ": " SLACK ", " to ": " U0456ABCD ", " subject ": " 経費申請の承認依頼 ", " message ": " 【承認依頼】 \n 申請者: 山田太郎 \n 申請番号: EXP-2025-00123 \n 金額: 12,480円 \n 申請日: 2025/02/10 \n\n 以下のリンクから内容を確認し、承認または差戻しをお願いします。 \n https://expense.example.com/approval/EXP-2025-00123 " } 4.2.3 切り出したマイクロサービス側 Go側では、通知リクエストから適切な通知先に通知を送ります。 package main import ( "encoding/json" "log" "net/http" ) // 通知のリクエスト構造 type NotificationRequest struct { Channel string `json:"channel"` To string `json:"to"` Subject string `json:"subject"` Message string `json:"message"` } func main() { http.HandleFunc( "/api/v1/notify" , NotifyHandler) log.Println( "Notification Service running on :8081" ) if err := http.ListenAndServe( ":8081" , nil ); err != nil { log.Fatal(err) } } func NotifyHandler(w http.ResponseWriter, r *http.Request) { var req NotificationRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { log.Println( "Invalid request:" , err) http.Error(w, "invalid request" , http.StatusBadRequest) return } // 即レスポンスを返す(Spring側を待たせない) w.WriteHeader(http.StatusAccepted) // 通知を非同期で処理(goroutine利用) go func (req NotificationRequest) { switch req.Channel { case "SLACK" : sendSlack(req) case "TEAMS" : sendTeams(req) case "LINE" : sendLine(req) case "EMAIL" : sendEmail(req) default : log.Printf( "[goroutine] unsupported channel: %s \n " , req.Channel) return } log.Printf( "[goroutine] completed notification: channel=%s to=%s \n " , req.Channel, req.To) }(req) } func sendSlack(req NotificationRequest) { // Slack SDK or Webhook を呼ぶ処理 log.Printf( "[Slack] sending to %s \n message: \n %s \n " , req.To, req.Message) } func sendTeams(req NotificationRequest) { // Teams SDK or Webhook を呼ぶ処理 log.Printf( "[Teams] sending to %s \n message: \n %s \n " , req.To, req.Message) } func sendLine(req NotificationRequest) { // Line SDK or Webhook を呼ぶ処理 log.Printf( "[LINE] sending to %s \n message: \n %s \n " , req.To, req.Message) } func sendEmail(req NotificationRequest) { // Eメールを送信する処理 log.Printf( "[Email] sending to %s \n subject=%s \n message: \n %s \n " , req.To, req.Subject, req.Message) } 4.3 この例についての補足 (本番運用を考えた場合) 前述のGo実装は説明用の最小構成です。 もしこのまま本番に出してしまうと、以下のような問題が起きます。 goroutine実行中にプロセスが落ちた場合、 モノリス 側では成功したように見えるが実際には通知されない。(アプリ側のみ正常終了など) 二重送信が発生しても止められない。(通知処理完了後にアプリ側の処理が異常終了、マイクロサービス側のみ正常終了など) 障害時に「どの申請の通知が失敗したか」追えない。 上記に対応しようとする場合は、以下のような対応が検討対象になります。 相関IDの追加 申請番号など、 モノリス 側との一連の処理を紐づける情報を加える。 リトライ + バックオフ + デッドレターキュー(DLQ)の追加 通知先サービスが一時的に落ちたときのために再処理を可能にする仕組みを加える。 マイクロサービス側のプロセスが落ちても適切に動作するように、マイクロサービス側でDBを持つなど。 べき等キーの追加 申請書番号 + イベント種別 + 通知先 などを覚えておき、通知済みの場合は通知しない。 メトリクスとアラートの設定 通知の成功率や遅延、DLQ件数 などを監視対象にする。 このように、割と簡単な例でも本番で運用する場合には考慮すべきポイントが数多くあります。 この辺りは、 モノリス のConsとマイクロサービスのProsだけを見ている場合に見落とすことがあります。 できる限り、切り出した場合の大変さについても切り出しの検討段階で考慮したいですね。 5 まとめ 今回は、 モノリス で作られたアプリから、1つの機能をマイクロサービスとして切り出す判断について書いてきました。 そもそもマイクロサービスを切り出すべきか → マイクロサービス化する場合は、 モノリス のPros / Consを意識する。 → 特に、 モノリス のProsを考える。 切り出すと判断したら何を切り出すか → 切り出すことで得られる価値が高い機能を切り出す。 → 価値が高い機能であっても、切り出しやすさを含め トレードオフ を見る。 どのように切り出すか → 第一歩は、状態をほぼ持たず、結果整合性を許容しやすく、失敗しても業務停止になりにくい機能を対象にする。 → 本番運用において、マイクロサービス化で問題となる特別な考慮ポイントについて十分に検討する。 最後に、ここまではおおむねアーキテクトの観点でのみ切り出す判断を書いてきています。 実際のプロダクト開発においては、失うProsが運用に直撃します。 そのため、切り出し判断はアーキテクトだけでなく、保守/運用・SRE・QA・プロダクトチームなどを巻き込んで合意することになると思います。 今後も、製品の成功のために出来ることを考え周囲と議論しながら、製品開発を推進していきたいと考えています。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @oura.osamu レビュー: @nagamatsu.yuji ( Shodo で執筆されました )
こんにちは。 電通 総研の金融IT本部(兼XI本部)の上野です。 本記事は 電通総研 Advent Calendar 2025 11日目の記事です。 最近一番嬉しかったことと言えば、 AWS のコンソール検索で「ECR」と入力すると一発と入力するとコンテナ レジストリ へ飛べるようになったことです。 「ECSからの遷移」や「container registry」と検索していたのは私だけではないはずです。 さて、本日は最近登場したTanStackエコシステムの一つ、 TanStack AI を利用してチャットボットを作ってみました。様々なエコシステムで知られるTanStackですが、AIアプリケーション開発の分野に参入していました。 本記事では、TanStack AI の特徴や Vercel AI SDK との違いを解説し、 Amazon Bedrock と組み合わせてファイル添付対応のチャットボットを構築する方法を紹介します。 TanStack AIとは 主な特徴 TanStack AI が生まれた背景 TanStack AI vs Vercel AI SDK TanStack AI を選ぶべきケース Vercel AI SDK を選ぶべきケース TanStack AI の実装例 クライアント実装例 サーバー実装例 Vercel AI SDKの利用例(比較用) クライアント側の実装例 サーバー側の実装例 Amazon Bedrock とは Amazon Bedrock の特徴 Amazon Bedrock を使うメリット 他のクラウド AI サービスとの比較 利用可能なモデル 主な機能比較 選定の指針 TanStack AI × Amazon Bedrockとの接続 サーバー側の実装例 Amazon Bedrock アダプタークラス Express サーバー クライアント側の実装例 カスタム Connection Adapter useChat フックの使用 実装にあたってのポイント(1)StreamChunk の形式 実装にあたってのポイント(2)Extended Thinking(思考プロセス)のサポート ファイル添付のサポート デモ まとめ TanStack AIとは TanStack AI は、複数の AI プロバイダーに対応した統一インターフェースを提供する オープンソース SDK です。 TanStack AI Alpha: Your AI, Your Way において「AI ツールのスイスを目指す」と述べており、「特定のベンダーやプラットフォームに依存しない中立的な設計を意識して作られた」という意味だと理解しています。 TanStack AI takes a different approach. We're building the Switzerland of AI tooling. An honest, open source set of libraries (across multiple languages) that works with your existing stack instead of replacing it. 主な特徴 ベンダーロックインなし: OpenAI、Anthropic、 Google Gemini、Ollama など複数のプロバイダーに対応 完全な型安全性: TypeScript でエンドツーエンドの型安全を実現 フレームワーク 非依存:React、Solid、Vanilla JS など任意の環境で利用可能 マルチモーダル対応:テキスト、画像、音声、動画、ドキュメントをサポート MIT ライセンス: 完全な オープンソース TanStack AI が生まれた背景 TanStack の創設者 Tanner Linsley 氏は、既存の AI SDK (Vercel AI SDK ) に対する懸念から TanStack AI を開発しました。 TanStack AI は、これらの課題を解決する「中立的な」 SDK として設計されています。Cloudflare や Netlify がスポンサーとして参加しているのも、オープンで移植可能なツールが彼らのプラットフォームにも恩恵をもたらすからだと考えています。 TanStack AI vs Vercel AI SDK 項目 TanStack AI Vercel AI SDK 哲学 中立・ オープンソース Next.js/Vercel エコシステム統合 プロバイダー数 4(OpenAI, Anthropic, Gemini, Ollama) 多数 ストリーミング制御 ステート管理して明示的に管理 HTTP ストリーム生成までを強くサポート 成熟度 アルファ版(2025年後半〜) 安定版 デプロイ先 どこでも( AWS , Cloudflare, Netlify 等) どこでも、ただしVercel 最適化 現時点では圧倒的にVercel AI SDK が高機能ですが、Vercel提供の SDK はどうしてもプラットフォーム依存部分が出てきます。 標準 OSS として利用可能ではありますが、Next.jsと密接に統合されており、Vercelデプロイ時に最適化されています。例えばVercel Functionsの タイムアウト 指定などもセットで利用可能になっている等、Vercelデプロイしない場合は不要な機能がいくつかあります。 TanStack AI を選ぶべきケース Vercel 以外の環境( AWS 、Cloudflare 等)にデプロイする 将来的にプロバイダーを切り替える可能性がある TanStack エコシステムを使用している Vercel AI SDK を選ぶべきケース Next.js + Vercel で開発している 今すぐ本番環境で使いたい(TanStack AI はまだアルファ版) 多数のプロバイダーに対応したい 豊富なドキュメントと事例が必要 TanStack AI の実装例 クライアント実装例 import { useChat } from '@tanstack/ai-react' import { fetchServerSentEvents } from '@tanstack/ai-react/connection' function Chat () { const { messages , sendMessage , isLoading } = useChat( { connection : fetchServerSentEvents( '/api/chat' ), } ) const handleSubmit = ( e : React.FormEvent ) => { e. preventDefault () const input = e. currentTarget . querySelector ( 'input' ) if (input?.value) { sendMessage(input.value) input.value = '' } } return ( < div > < div className = "messages" > { messages. map (( msg ) => ( < div key = { msg. id } className = { `message ${ msg.role } ` } > { msg.content } </ div > )) } </ div > < form onSubmit = { handleSubmit } > < input type = "text" placeholder = "メッセージを入力..." /> < button type = "submit" disabled = { isLoading } > 送信 </ button > </ form > </ div > ) } サーバー実装例 import { chat, toStreamResponse } from '@tanstack/ai' import { openai } from '@tanstack/ai-openai' export async function POST ( request : Request ) { const { messages } = await request.json() const response = await chat( { provider : openai( { apiKey : process .env.OPENAI_API_KEY } ), model : 'gpt-4o' , messages , } ) return toStreamResponse(response) } Vercel AI SDK の利用例(比較用) TanStack AIとの差分 submit時の sendMessage(input.value) 相当の処理は、 useChat フックがよしなにやってくれる。 クライアント側の実装例 import { useChat } from 'ai/react' export function Chat () { const { messages , input , handleInputChange , handleSubmit , isLoading , } = useChat( { api : '/api/chat' , } ) return ( < div > < div className = "messages" > { messages. map (( msg ) => ( < div key = { msg. id } className = { `message ${ msg.role } ` } > { msg.content } </ div > )) } </ div > < form onSubmit = { handleSubmit } > < input type = "text" placeholder = "メッセージを入力..." value = { input } onChange = { handleInputChange } /> < button type = "submit" disabled = { isLoading } > 送信 </ button > </ form > </ div > ) } サーバー側の実装例 import { streamText } from 'ai' import { openai } from '@ai-sdk/openai' export async function POST(req: Request) { const { messages } = await req.json() const result = streamText({ model: openai('gpt-4o'), messages, }) // ストリーミングレスポンスをそのまま返す return result.toDataStreamResponse() Amazon Bedrock とは Amazon Bedrockは、 AWS が提供するフルマネージド AI サービスです。Anthropic Claude、Meta Llama、 Amazon Titanなど、複数の基盤モデルを統一された API で利用できます。 Amazon Bedrock の特徴 マルチモデル : 複数ベンダーのモデルを同一 API で利用 IAM 統合 : AWS の認証・認可基盤を活用 VPC 対応 : PrivateLink でセキュアな接続 リージョン : 東京(ap-northeast-1)で利用可能 従量課金 : AWS 請求に統合、予測可能なコスト管理 Amazon Bedrock を使うメリット AWS の IAM による認証・認可を利用したい VPC PrivateLink でセキュアな接続をしたい AWS の請求に統合してコスト管理をしたい CloudTrail で アクセスログ を取得したい 他の クラウド AI サービスとの比較 マルチモデル AI サービスは各 クラウド ベンダーが提供しています。 AWS の Bedrock、 Google Cloud の Vertex AI、 Microsoft の Azure AI Foundry(旧 Azure AI Studio)を比較してみます。 ※名称や提供モデル・機能は逐次変化するため、公式の情報を参照してください。 利用可能なモデル プロバイダー Amazon Bedrock Vertex AI Azure AI Foundry Anthropic Claude ✅ Claude 4, 3.5, 3 系 ✅ Claude 3.5, 3 系 ❌ OpenAI GPT ❌ ❌ ✅ GPT-4o, GPT-4, GPT-3.5 Google Gemini ❌ ✅ Gemini 2.0, 1.5 ❌ Meta Llama ✅ Llama 3系 ✅ Llama 3系 ✅ Llama 3系 Mistral ✅ Mistral Large, Small ✅ Mistral ✅ Mistral Large 自社モデル Amazon Nova, Triton Gemini Phi-4, Phi-3 主な機能比較 機能 Amazon Bedrock Vertex AI Azure AI Foundry 統一 API Converse API Gemini API / Model Garden Azure OpenAI + Azure AI Inference ファインチューニング 可 可 可 RAG 機能 Knowledge Bases Vertex AI Agent Builder(統合中?Vertex AI Search) Azure AI Search 連携 エージェント Bedrock Agents Vertex AI Agent Builder Azure AI Foundry Agent Service ガードレール Guardrails for Bedrock Responsible AIツール群 Content Safety ※ファインチューニングはモデルによって可不可があります。 選定の指針 現時点ではモデルベースで利用基盤を選ぶことになるかと思います。 実際は各サービスのモデルカタログを見ながら、要件にあったモデルが使えるかどうか、対象のリージョンで提供されているかどうかを加味して比較する必要があります。 Claude を使いたい : Amazon Bedrock または Vertex AI OpenAI GPT を使いたい :Azure AI Foundry Gemini を使いたい :Vertex AI 今回は使い慣れた AWS 環境で Claude を利用したかったため、 Amazon Bedrock を選択しました。 TanStack AI × Amazon Bedrockとの接続 TanStack AI と Amazon Bedrock を接続する方法を説明する前に、TanStack AI の 2 層構造+呼び出すAIプロバイダーで、合計3つの役割に分かれていることを理解する必要があります。 クライアント層 useChat + Connection Adapter (SSE/HTTP/WebSocket) SSE ストリームのリクエストとレスポンスハンドリング fetchServerSentEvents 、 fetchHttpStream など サーバー層 chat() + Provider Adapter (OpenAI/Anthropic/etc) @tanstack/ai-openai 、 @tanstack/ai-anthropic など AI プロバイダー OpenAI / Anthropic / Google Gemini / Ollama サポートされていない場合は自前で実装が必要 TanStack AI は現在アルファ版であり、公式にサポートされているAIプロバイダーは以下の 4 つです: OpenAI ( @tanstack/ai-openai ) Anthropic ( @tanstack/ai-anthropic ) Google Gemini ( @tanstack/ai-gemini ) Ollama ( @tanstack/ai-ollama ) Amazon Bedrock 用のアダプターは公式には提供されていません 。Anthropic の Claude を使いたい場合、 @tanstack/ai-anthropic で直接 Anthropic API に接続することは可能ですが、 Amazon Bedrock 経由で利用したい場合はカスタムアダプターを実装する必要があります。 TanStack AIは公式にカスタム可能と謳っているため、本来クライアント層/サーバー層ともに Bedrockのアダプターを作成して接続したかったのですが、TanStack AIが未だα版であり、公開情報も少ないためにサーバサイドは自前で接続処理を設けます。 今回の実装方針は以下のとおりです。 サーバー側 : Amazon Bedrock SDK を直接使用し、TanStack AI の StreamChunk 形式で通信する クライアント側 :TanStack AI の useChat フック + カスタム Connection Adapter でレスポンスを受け取る この方法により、TanStack AI の useChat フックの恩恵(メッセージ管理、ローディング状態、型安全性)を受けながら、 Amazon Bedrock と接続できます。 サーバー側の実装例 Amazon Bedrock アダプタークラス AWS SDK を使用して Amazon Bedrock の Converse API を呼び出し、TanStack AI の StreamChunk 形式でストリームを返します。 import { BedrockRuntimeClient, ConverseStreamCommand, } from '@aws-sdk/client-bedrock-runtime' export interface StreamChunk { type : 'content' | 'thinking' | 'done' | 'error' id ?: string model ?: string timestamp ?: number delta ?: string // 増分トークン content ?: string // 累積コンテンツ role ?: string // 'assistant' finishReason ?: string error ?: string } // Adapterと言っているが、TanStack AIとのアダプタではなく単にawsのsdkから接続するBedrockへのAdapter export class BedrockAdapter { private client : BedrockRuntimeClient private modelId : string async * chatStream ( messages , options ): AsyncGenerator < StreamChunk > { const command = new ConverseStreamCommand( { modelId : this .modelId, messages : this .formatMessages(messages), additionalModelRequestFields : options.enableThinking ? { thinking : { type : 'enabled' , budget_tokens : 5000 } } : undefined , } ) const response = await this .client. send (command) for await ( const event of response.stream!) { if (event.contentBlockDelta?.delta) { const delta = event.contentBlockDelta.delta if ( 'thinking' in delta) { yield { type : 'thinking' , delta : delta.thinking, ... } } else if ( 'text' in delta) { yield { type : 'content' , delta : delta.text, role : 'assistant' , ... } } } if (event.messageStop) { yield { type : 'done' , finishReason : 'end_turn' } } } } } Express サーバー Bedrock アダプターを使用し、SSE 形式でクライアントに送信します。 import express from 'express' import { bedrock } from './adapters/bedrock-adapter.js' const app = express() const adapter = bedrock( { region : process .env.AWS_REGION || 'us-east-1' , modelId : process .env.BEDROCK_MODEL_ID || 'claude-sonnet-4' , } ) app.post( '/api/chat' , async ( req , res ) => { const { messages } = req. body // SSE ヘッダー設定 res.setHeader( 'Content-Type' , 'text/event-stream' ) res.setHeader( 'Cache-Control' , 'no-cache' ) res.setHeader( 'Connection' , 'keep-alive' ) const stream = adapter.chatStream(messages, { systemPrompt : 'Hello World' , enableThinking : true , } ) for await ( const chunk of stream) { res. write ( `data: ${ JSON . stringify (chunk) } \n\n ` ) if (chunk. type === 'done' || chunk. type === 'error' ) break } res.end() } ) クライアント側の実装例 カスタム Connection Adapter TanStack AI の ConnectionAdapter インターフェースを実装し、サーバーからのレスポンスを処理します。 import { useChat, type ConnectionAdapter } from '@tanstack/ai-react' import type { UIMessage, ModelMessage, StreamChunk } from '@tanstack/ai' // カスタム Connection Adapter function createBedrockConnection(): ConnectionAdapter { return { async *connect( messages: UIMessage[] | ModelMessage[], _data?: Record < string , unknown > , abortSignal?: AbortSignal ): AsyncIterable < StreamChunk > { // メッセージを Bedrock 形式に変換 const chatMessages = messages.map (( msg ) => ( { role : msg.role, content : extractTextContent(msg), } )) const response = await fetch ( '/api/chat' , { method : 'POST' , headers : { 'Content-Type' : 'application/json' } , body : JSON . stringify ( { messages : chatMessages } ), signal : abortSignal, } ) const reader = response. body ?.getReader() const decoder = new TextDecoder () let buffer = '' while ( true ) { const { done , value } = await reader!.read() if (done) break buffer += decoder. decode (value, { stream : true } ) const lines = buffer. split ( ' \n ' ) buffer = lines. pop () || '' for ( const line of lines) { if (line. startsWith ( 'data: ' )) { const data = JSON . parse (line. slice ( 6 )) as StreamChunk yield data } } } } , } } useChat フックの使用 カスタム Connection Adapter を useChat に渡して使用します。 function App () { const connection = useMemo(() => createBedrockConnection(), [] ) // TanStack AI の useChat フック const { messages , sendMessage , isLoading } = useChat( { connection , } ) return ( < div > { messages. map (( message ) => ( < div key = { message. id } className = { message.role } > { message.parts. map (( part , idx ) => { if (part. type === 'thinking' ) { return < div key = { idx } className = "thinking" > { part.content } </ div > } if (part. type === 'text' ) { return < div key = { idx } > { part.content } </ div > } return null } ) } </ div > )) } < form onSubmit = { ( e ) => { e. preventDefault () sendMessage(input) } } > < input type = "text" /> < button disabled = { isLoading } > 送信 </ button > </ form > </ div > ) } 実装にあたってのポイント(1)StreamChunk の形式 TanStack AI の useChat が正しく動作するためには、サーバーから返す SSE が以下の StreamChunk 形式に準拠している必要があります: // ContentStreamChunk { type : 'content' , delta: '新しい' , content: '新しい' , role: 'assistant' , id, model, timestamp } // ThinkingStreamChunk { type : 'thinking' , delta: '考え中...' , content: '考え中...' , id, model, timestamp } // DoneStreamChunk { type : 'done' , finishReason: 'end_turn' , id, model, timestamp } // ErrorStreamChunk { type : 'error' , error: 'エラーメッセージ' } この形式に準拠していれば、 useChat は自動的にメッセージを UIMessage に変換し、 thinking は ThinkingPart として、 content は TextPart として管理されます。 実装にあたってのポイント(2)Extended Thinking(思考プロセス)のサポート Claude Sonnet 4 / Opus 4 では Extended Thinking 機能が利用可能です。この機能を有効にすると、Claude が回答を生成する前の「思考過程」をストリーミングで取得できます。 // Thinking 有効時のレスポンス例 { type : 'thinking' , delta: 'ユーザーは...' , content: 'ユーザーは...' } { type : 'thinking' , delta: 'について質問して' , content: 'ユーザーは...について質問して' } { type : 'content' , delta: 'こんにちは!' , content: 'こんにちは!' } { type : 'content' , delta: 'ご質問に' , content: 'こんにちは!ご質問に' } { type : 'done' , finishReason: 'end_turn' } UI 側で thinking タイプのチャンクを別途表示することで、AI の思考過程を可視化できます。 ファイル添付のサポート これだけだと面白くないので、ファイル添付をサポートしてみます。 こちらもサーバーサイドが TanStack AI の場合はカスタムが難しそうですが、今回はサーバについてはBedrockの SDK を利用しているだけなので、クライアント側でファイル情報を管理する変更がほとんどです。 なお、Bedrock では Claude 系のモデルの場合以下の形式をサポートしています。 カテゴリ 形式 画像 JPEG , PNG , GIF, WebP ドキュメント PDF, CSV , DOC, DOCX, XLS, XLSX, HTML, TXT, MD 1. 添付ファイルの管理 TanStack AI の sendMessage はテキストのみを受け取るため、添付ファイルは別途管理します。 // 添付ファイルの型定義 interface Attachment { type : 'image' | 'document' mediaType : string // 'image/png', 'application/pdf' など data : string // Base64 エンコード済みデータ name : string } function App () { const [ pendingAttachments , setPendingAttachments ] = useState< Attachment []>( [] ) const attachmentsRef = useRef< Attachment []>( [] ) // ... } 2. ref を使った添付ファイルの受け渡し // カスタム Connection Adapter(添付ファイル対応) function createBedrockConnection ( getAttachments : () => Attachment []): ConnectionAdapter { return { async * connect ( messages , _data , abortSignal ) { const chatMessages = messages. map (( msg , index ) => ( { role : msg.role, content : extractTextContent(msg), // 最後のユーザーメッセージにのみ添付ファイルを付与 ...(msg.role === 'user' && index === messages. length - 1 ? { attachments : getAttachments() } : {} ), } )) // fetch でサーバーに送信... } , } } // 使用側 const connection = useMemo( () => createBedrockConnection(() => attachmentsRef. current ), [] ) 3. 送信時のタイミング制御 sendMessage を呼ぶ 前に attachmentsRef で管理するファイルを送信します。 const handleSendMessage = async () => { // 送信前に attachmentsRef を設定(connect 関数から参照される) attachmentsRef. current = [ ...pendingAttachments ] // UI 表示用に保存 setAttachments(( prev ) => [ ...prev, ...pendingAttachments ] ) // 入力をクリア setInput( '' ) setPendingAttachments( [] ) // メッセージ送信(この時点で connect が呼ばれ、attachmentsRef を参照) await sendMessage(messageText) // 送信完了後にクリア attachmentsRef. current = [] } 4. サーバ側での添付 サーバー側では、添付ファイルを追加する formatMessages関数を設け、 Converse API に渡す前にメッセージを整形します。 private formatMessages(messages: ChatMessage[]): BedrockMessage[] { return messages. map (( msg ) => { const content: ContentBlock [] = [] // テキストコンテンツ if (msg.content) { content. push ( { text : msg.content } ) } // 添付ファイル if (msg.attachments) { for ( const attachment of msg.attachments) { if (attachment. type === 'image' ) { content. push ( { image : { format : this .getImageFormat(attachment.mediaType), source : { bytes : Buffer .from(attachment.data, 'base64' ) } , } , } ) } else if (attachment. type === 'document' ) { content. push ( { document : { format : this .getDocumentFormat(attachment.mediaType), name : sanitizeDocumentName(attachment. name ), source : { bytes : Buffer .from(attachment.data, 'base64' ) } , } , } ) } } } return { role : msg.role, content } } ) } デモ まとめ TanStack AI と Amazon Bedrock を組み合わせることで、以下のメリットが得られます TanStack AI による型安全性、React フック、ストリーミング制御 Bedrock の エンタープライズ 機能(IAM 認証、 VPC 統合、ガバナンス) カスタムアダプターの実装は手間がかかりますが、TanStack AI の設計思想(AsyncGenerator パターン、StreamChunk 型)に従えば比較的シンプルに実装できます。 TanStack AI はまだアルファ版ですが、将来的には公式で Bedrock アダプターがサポートされる可能性もあります。それまでは、今回紹介したようなカスタムアダプターで対応できます。 ただし結論として、現時点で Bedrock等公式に接続が提供されていないAI基盤を利用する場合はVercel AI SDK を利用したほうが簡潔な構成にできます。 TanStack AIの一番の課題として、接続先のアダプタを自前で構える必要がある点が現時点でかなりの ボトルネック となります。 しかし、Vercel エコシステムにロックインされてしまわないためにも、TanStack AI の今後の進歩には期待しています。 以上、拝読ありがとうございました。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 執筆: @kamino.shunichiro レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
はじめに こんにちは。 エンタープライズ 第一本部・テクノロ ジー ビジネスユニット・テクノロ ジー ビジネス2部の多田圭佑です。 掲題の構成でシステムを構築するにあたり、基本的な構成であるにもかかわらず思わぬところでつまずいてしまったので、将来同じような問題に遭遇した方向けに書いています。 5分程度でサクッと読めますので、お付き合いいただければ幸いです。 本記事は 電通総研 Advent Calendar 2025 10日目の記事です。 つまずいたこと2つ 先に私がつまずいたことの2つを述べます。 CloudFront経由だと画面遷移でエラーになる 画像が表示されない システム構成 以下のような、 AWS では一般的な構成です。 (Internet) -> CloudFront -> ALB -> ECS ECS上にReact Router v7(SSR。ビルドツールはVite)を使用したシステムが稼働しており、それをCloudFront経由で公開しています。 CloudFrontはこのシステム以外でも使用しており、特定のパスパターンに合致した場合のみこのシステムにルーティングするよう設定しています。 1. CloudFront経由だと画面遷移でエラーになる 事象 前提としてCloudFrontでのパスパターンは後段で維持されます。 例えば、パスパターンを「aaa/bbb」としたときは以下のように転送されます。 ( HTTPS の終端はALBで、バックエンド(ECS)との通信はプライベートネットワーク内のHTTPです) AWS サービス URL CloudFront https://example.cloudfront.net/aaa/bbb ALB https://hogehoge.region.elb.amazonaws.com/aaa/bbb ECS http://localhost:8888/aaa/bbb 逆に言えば、CloudFrontを経由した場合は http://localhost:8888/aaa にはアクセスできません。 当初、私がルーティングを実装した際は以下のように routes.ts を設定しました。 こうすることで /aaa/bbb をベースとしてその配下のパスにアクセスできます。 export default [ route( '/healthcheck' , 'routes/healthcheck.tsx' ), // healthcheck用 ...prefix( 'aaa/bbb' , [ index( 'routes/index.tsx' )) route( '/ccc' , 'routes/ccc.ts' ), route( '/ddd' , 'routes/ddd.ts' ), ] ), ] satisfies RouteConfig; ただ、CloudFront経由だとインデックスへのアクセスは問題ないのですが、そこからの画面遷移に失敗していました。 ローカルやALB経由だと問題ありませんでした。 原因 React Router v7のルート・コードスプリット( 遅延ルート )では、クライアントは起動時に /__manifest というエンドポイントから「ルートID → チャンクURL」のマップを取得します。 今回はパスパターン経由で公開しているため /__manifest にアクセスしようとするとパスパターンに合致しないため404となってしまい、その結果チャンクのURLが分からずに動的 import が失敗していました。 ローカルやALB経由だとパスパターンの制約がないため問題がありませんでした。 対応 React Router v7では、アプリケーションのベースパスを指定する basename という設定があります。 今回の構成では、CloudFrontから /aaa/bbb というパスパターン経由でこのWebアプリケーションにアクセスしているため、この basename を設定することで問題を解決しました。 具体的には、 react-router.config.ts に以下のように設定を追加しました。 import type { Config } from "@react-router/dev/config" ; export default { ssr : true , basename : "/aaa/bbb" , // その他の設定... } satisfies Config; routes.ts は以下のようにシンプルになりました。 export default [ route( '/healthcheck' , 'routes/healthcheck.tsx' ), // healthcheck用。/aaa/bbb/healthcheck route( '/ccc' , 'routes/ccc.ts' ), route( '/ddd' , 'routes/ddd.ts' ), ] satisfies RouteConfig; この設定により、React Routerは /__manifest へのアクセスを /aaa/bbb/__manifest として解決するようになり、CloudFront 経由でも正しく マニフェスト ファイルを取得できるようになりました。 また、リンクやナビゲーションも自動的に /aaa/bbb を基準としたパスで動作するようになるため、ルーティング全体が正常に機能するようになりました。 2. 画像が表示されない 事象 ルーティングの問題は解決しましたが、今度は画像が表示されない問題が発生しました。 /images/icon.svg を取得しようとして404となっていました。 原因 原因を調査したところ、画像などの静的アセットファイルはReact Routerのルーティングとは別に扱われるため、 basename の設定だけでは対応できないことがわかりました。 静的ファイルは通常 public ディレクト リに配置されますが、これらのファイルへのパスも /aaa/bbb の プレフィックス を考慮する必要があります。しかし、ビルド時に生成される静的アセットへの参照パスは、 basename の設定では反映されません。 解決方法 この問題を解決するために、以下の対応を行いました。 1. Vite の base 設定を追加 vite.config.ts に base オプションを追加して、静的アセットのベースパスを明示的に設定しました。 ( react-router.config.ts とは若干異なるため注意です) import { defineConfig } from "vite" ; import { reactRouter } from "@react-router/dev/vite" ; export default defineConfig( { base : "/aaa/bbb" , plugins : [ reactRouter() ] , // その他の設定... } ); この設定により、ビルド時に生成される静的アセットへの参照パスに /aaa/bbb の プレフィックス が自動的に付与されるようになります。 2. 画像パスの設定 コンポーネント 内で画像を参照する際は、以下のように画像を直接インポートすることで、Vite が自動的に適切なパスに変換してくれます。 import iconSvg from "/images/icon.svg" ; function MyComponent () { return < img src = {iconSvg} alt = "Icon" />; // <img src="/aaa/bbb/images/icon.svg" /> } 以下のように 環境変数 を使用して文字列ベースで解決する方法もあります。こちらは動的に画像パスを生成する必要がある場合に有効です。 function MyComponent () { return < img src = { ` $ { import . meta . env . BASE_URL} / images / icon.svg `} alt="Icon" />; } まとめ CloudFrontのパスパターンを使用している場合は basename の設定が必要でした。この設定により /__manifest がprefix付きとなり、 マニフェスト ファイルの取得やルーティングが正常に動作します。 また、静的ファイルの参照についても同様に basename を考慮した設定が必要になります。 これから同様の構成でシステムを構築される方の参考になれば幸いです。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @tada.keisuke レビュー: @kinjo.ryuki ( Shodo で執筆されました )
はじめに こんにちは。クロス イノベーション 本部 クラウド イノベーション センター3年目の宮崎です。 AWS re:Invent 2025 で発表された AWS DevOps Agent を触ってみたので、概要を記載したいと思います。 AWS re:Invent 2025については、同じくクロス イノベーション 本部エンジニアリングテクノロ ジー センターの宮原さんが、速報記事を書いているので、是非下記の記事もご覧ください! AWS re:Invent2025 Keynote現地速報 また、 AWS re:Inventがそもそもどのようなものか把握したい方は、過去の私の記事もご覧いただけると幸いです。 AWS re:Invent 2024とAWS GameDayについて 本記事は 電通総研 Advent Calendar 2025 9日目の記事です! 記事の目的 新しいエージェントについての紹介 AWS DevOps Agentの機能やセットアップの流れの紹介 AWS DevOps Agentの位置づけ まず前提として、 AWS は re:Invent 2025で「Frontier Agents」という新しいコンセプトを掲げ、次の3つの新しいエージェントサービスを発表しました。 Kiro autonomous agent AWS Security Agent AWS DevOps Agent Frontier Agentsは、 AWS 公式のページでは「介入を必要とせずに何時間も動作する、自律的で大規模にスケーラブルなAIエージェント」という、新しいクラスのエージェントと定義しています。 従来の 「人間をサポートする AI アシスタント」から一歩進み、「チームのメンバーとして成果を出すことを期待されるデジタルワーカー」的な位置づけのサービス群だと捉えています。 引用:自律的で大規模に拡張可能なAIエージェント - Frontier agents – AWS フロンティアエージェントは、目標達成のために独立して動作し、同時実行タスクに対応するために大規模にスケールし、介入なしに数時間または数日間持続的に動作する自律システムです。個々のタスクを支援する従来のAIアシスタントとは異なり、フロンティアエージェントはチームの延長として機能し、多様なユースケースにわたって包括的な成果をもたらします。 この中で、AWS DevOps AgentFrontier agent – AWS DevOps Agent – AWSはシステムの障害対応(インシデントレスポンス)を加速し、将来の問題を未然に防ぐための運用エージェントで、具体的には、チケットなどをトリガーに自動でエージェントが起動し、メトリクス、ログ、最近のデプロイ履歴(GitHub)、トレース情報などを自動で分析し根本原因を特定・ユーザーに通知を行います。 また、システムの構成要素とその相互関係、デプロイ履歴を含むマップを自動構築し、影響範囲を正確に把握することが可能になります。 AWS DevOps Agent は、その中でも運用・インシデント対応を担う役割を持つ Frontier Agent です。 監視ツールやログを横断して自動で調査・分析し、インシデントの原因特定と復旧案、さらに再発防止策まで提案してくれる AWS の生成AIエージェントサービスとなっています。 インシデントの対応において、様々な情報を人間が行き来して疲弊するのではなく、人間は判断に注力できる未来はすぐそこに来ていると感じています。 インシデント対応における、以下のような課題を人間の介入無しに解決できることを狙っていると思われます。 課題 インシデント調査に時間がかかる CloudWatch / Datadog / New Relic / その他監視ツール / デプロイ履歴 / Runbook などを人がいちいち行き来して調べるのは大変。 ⇒ AWS DevOps Agentがこれらをまとめて見て、根本原因候補を自動で絞り込む。 夜間・休日オンコール負荷が高い問題 24/7 で人を張り付けるのはしんどいしコストも高い。 ⇒ AWS DevOps Agentが常時起動のオンコール要員として自動で調査開始し、対応案まで出してくれるので、 MTTR (復旧時間)を短縮しつつ負荷も軽減。 再発防止・改善の振り返りが十分にできていない インシデント後に振り返りや今後に向けた改善等をきちんとやる時間がない。 ⇒ AWS DevOps Agentが過去インシデントを横串で分析し、監視や構成・デプロイの改善案を提案してくれる。 AWS DevOps Agentの機能 参考: https://docs.aws.amazon.com/ja_jp/devopsagent/latest/userguide/what-is.html 上記の公式ドキュメントベースでご説明します: 1. 常時稼働の自動インシデント対応 アラートやチケットをトリガーに、自動で調査開始し、メトリクス、ログ、トレース、デプロイ履歴、コード、Runbook などを突き合わせ、原因候補と影響範囲を特定することができます。具体的な緩和策や復旧手順、 ロールバック 案までプランとして提示することが可能です。 2. チャットベースの インタラクティブ 調査 専用の DevOps Agent Web アプリ(Agent Space)から、視覚的に調査の状況や、人間が追加チャットでどこまで調査したか、他に影響はないか等も確認ができます。また、別チャットにて追加の調査や指摘もすることが可能です。 3. トポロジ学習とマルチツール連携 AWS リソースや各サービスの トポロジ(関係性)を自動で学習します。 CloudWatch、Datadog、New Relic、Dynatrace、Splunk などのオブザーバビリティツール、監視設定と連携し横断的に相関をとることも可能なようです。 4. 予防・再発防止のための改善提案 調査後に改善の提案を確認できます。また、過去インシデントのパターンを分析し、改善案を自動で提示することが可能です。 AWS DevOps Agentの管理・認証 今回、実際の検証を実施した際はIAM認証(既存のマネジメントコンソールのセッション)にて初期設定を実施しました。一方で、少し経つと AWS DevOps Agent Spaceウェブアプリのセッションが切れてしまいました。そこで、 AWS の公式ドキュメントを確認すると、IAM認証でのアクセスは30分までに制限されていました。 そのため、本番環境等において複数人に展開する場合はIAM Identity Centerが推奨されているようです。外部プロバイダーとの連携により集中管理することが可能になり、最大12時間のセッションが提供されます。 Setting Up IAM Identity Center Authentication AWS DevOps Agentのセットアップ手順 ※現状パブリックプレビュー期間中のため、 AWS DevOps Agent自体の使用料は発生しませんが、他のサービスへのクエリや API 呼び出し時に当該サービスから料金が掛かる場合は使用料金が発生します。 引用:Public preview pricing and limits マネジメントコンソールの検索欄に、 AWS DevOpsを入力すると出てきました。 現在はプレビュー版になっておりリージョンが制限されているので、 バージニア 北部に遷移します。 サービスページから「Begin setup」を押下し、エージェントスペースを作成します。 Agent Spaceの名前を設定し、画面に従って設定をします。 問題なく作成後、Agent Spaceの画面に遷移すれば完了です。 機能検証前の実施内容 AWS DevOps Agentを試す前に、調査対象となる環境、および仮トラブルを AWS DevOps Agentの公式ドキュメントの内容に基づき準備しました。 環境準備の詳細手順は以下のリンクからご覧ください。 Creating a test environment 内容は、準備されているIaCコードを用いてCloud FormationでEC2やLambdaの環境をデプロイ後、用意されたトラブルに対して AWS DevOps Agentを利用し、代表機能を見ていけるというものになっています。 AWS DevOps Agentを試したいが、対象のシステム環境がない方 が試す場合に打って付けです。 ※実際のアプリケーション等の検証環境がある方はそちらで検証した方が、実際の業務で何がどこまでできそうか把握しやすいと思います。 実際の調査の流れ 作成したAgent Spacesから画面右上の「Operator access 」を押下します。 すると別タブで AWS DevOps Agentの画面に遷移します。erator access から作成したエージェントに質問をします。 質問内容 以下を項目ごとに入力します。 (実際のプロンプトは対象の環境やエラーの状況によって変えてください。 今回は AWS DevOps Agentの公式ドキュメントの内容に基づき準備した場合のプロンプトになっています。) ※今後、日本語対応されるまでは調査したい内容を日本語から英語へ翻訳する1アクションが必要になりそうです。 Investigation details: Investigate high CPU utilization on test EC2 instance and Lambda error rate spikes generated by test stacks. Investigation starting point: Start from CloudWatch alarms AWS -AIDevOps-EC2-CPU-Test and AWS -AIDevOps-Lambda-Error-Test which are currently in ALARM. 内容を確認後「Start Investigation」を押下し、調査を開始します。 タイムライン形式で何の情報をインプットに、どのようなステップで調査をしているか、最終的に何を根本原因と判断したかまで等が把握できます。 視覚的で内容も把握しやすいものとなっています。 調査結果が約5分~10分ほどで出ます。 詳細を確認すると根本原因について記載しています。 実際のインシデントが起こった流れについても、詳細に記載されていました。 また、調査は並行で走らせることができました。 ※現状、同時に実行できるインシデント解決調査タスクの数は 3 までとなっています。 実際の本番利用においては、エラーに関連するリソースの指定や環境の指定により調査対象をプロンプトによって指定する等で、異なる視点からの調査を並行して実施することもできそうです。 まとめ AWS DevOps Agentは設定が簡単で、実際のエラーの 調査内容/理由 を時系列に沿ってUIで分かりやすく、詳細に解説してくれました。調査は並行で走らせることができ、根本原因が約5分~10分で直ぐに把握が可能です。 AWS DevOps Agentはインシデントの調査・根本原因の特定はもちろん、ポストモーテム(システムにトラブルや障害が発生したあとに行う事後分析)に非常に有効だと思いました。 そして何より、「チームのメンバーとして成果を出すことを期待されるデジタルワーカー」的な位置づけのサービスとして AWS DevOps Agentで一次調査を任せることができるレベルだと言うことが分かりました。 現状、二次対応で実際のリソースの設定変更などについてはKiro CLI (旧 Amazon Q Developer CLI )で AWS CLI の認証情報との組み合わせにより設定変更や環境参照なども可能になっています。 日本語対応やリージョンの拡大を期待しつつ、 AWS DevOps Agentがインシデント対応のプロセスにおいてどの部分まで担っていけるのか、 AWS の他サービス(Kiro CLI , Amazon Q Develper等)やAI機能が備わってきているオブザーバビリティ・インシデント対応周りの SaaS サービスとの棲み分け等について、引き続き Watch して確認して行ければと思っています。 参考記事 AWS公式資料:Frontier agents AWS公式資料:AWS DevOps Agent helps you accelerate incident response and improve system reliability (preview) AWS公式資料:AWS DevOps Agent (Preview) AWS公式ドキュメント:AWS DevOps Agent パブリックプレビューの価格と制限 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @miyazaki.hirotoshi レビュー: @handa.kenta ( Shodo で執筆されました )
はい、こんにちはー!コーポレート本部サイバーセキュリティ推進部の福山です。 本記事は 電通総研 Advent Calendar 2025 10日目の記事です。 今回は、当社もThird Sponsorとして協賛させていただいた、国内最大級の国際的なセキュリティカンファレンスである 「CODE BLUE」 に初めて参加してきたので、そのレポートになります。 CODE BLUEをあまり知らない方向けに、簡単ではありますが紹介いたします。 CODE BLUEとは Contests/Workshops Hacking Active Directory インターポールAIクエスト TRAPA Cyber Range Exercise 最後に CODE BLUEとは CODE BLUEは、世界トップクラスの情報セキュリティ専門家が集まり、最先端の技術や脅威動向に関する講演・情報交換が行われる、国際的なセキュリティカンファレンスです(会場は ベルサール高田馬場 で2日間開催)。 海外の著名な研究者や国内のトップエンジニアによるセッションが用意されており、最終日には登壇者および参加者同士で交流するPartyも設けられています。 また、実践的なスキルを磨けるコンテストおよびワークショップが用意されており、実際に手を動かして学べる点も、CODE BLUEの大きな魅力だと感じました。 今回はコンテストおよびワークショップに焦点を当てて紹介します。 Contests/Workshops 今回は3つのコンテストおよびワークショップに参加させていただきました。どれも非常に学びの深い内容でした! Hacking Active Directory このワークショップでは、攻撃者目線で Active Directory (AD)環境に侵入し、特権昇格や横展開を行う手法をハンズオン形式で体験できます。 また、攻撃に対する緩和策についても触れられていました。 ※こちらのワークショップは人数制限があり、当日現地予約という形式になっていました。 初日の午前中に2日間全ての枠が埋まるほどの人気ぶりでした。 参加者は Webブラウザ から Apache Guacamole環境にアクセスし、Kali Linux を操作します。 (※図は IBM X-Force Red提供資料より引用) 外部公開された脆弱なWebサーバが侵入の起点というシナリオで、大まかに以下のフェーズで内容が構成されていました。 フェーズ 技法 使用ツール 主な目的 初期侵入 (Initial Access ) LLMNR / NBT-NS Poisoning responder, hashcat ネットワーク上の認証ハッシュを窃取し、平文パスワードを取得。 内部偵察 (Reconnaissance) SMB Recon & AD偵察 NetExec, BloodHound 共有フォルダの探索、ADの構成や攻撃経路の可視化。 権限昇格 (Privilege Escalation) Kerberoasting Impacket GetUserSPNs, hashcat SPNを持つアカウントのサービスチケットを収集・復号し、サービスアカウントのパスワードを取得。 攻撃者がどのようにAD環境で足場を築き、権限を広げていくのかを実体験できるようになっています。 また、攻撃者視点を学んだ後、それに対する具体的な緩和策が解説されました。 攻撃技法 緩和策 LLMNR / NBT-NS Poisoning グループポリシーでLLMNRを無効化し、 ネットワークアダプタ 設定でNBT-NSを無効化する。 Kerberoasting サービスアカウントのパスワードを30文字以上の複雑なものにする。 RC4 暗号化を無効化し、より強固な暗号化方式を使用する。 ※対策が難しい場合は、 Windows イベントID 4768(Kerberos認証チケット要求)や4769(サービスチケット要求)を監視し、 RC4 -HMACの使用や短時間での複数のSPN要求を検知する。 「攻撃者がどのようにしてADを狙うのか」「この緩和策がなぜ必要なのか」といった点が深く腹落ちするワークショップでした。 インターポールAIクエスト こちらは過去に 国際刑事警察機構 (インターポール)向けに提供されたCTFをアレンジしたものとなっており、AIとサイバー犯罪がテーマとなっていました。 基調講演でも取り上げられた「AIとセキュリティ」に焦点が当てられているだけに、興味をそそる内容だったと思います。 会場の Wi-Fi 経由で、2日間どこからでもアクセスできました。 AIクエスト世界の被害者(生成AI)に、チャットベースで被害状況などを ヒアリ ングしながらサイバー犯罪を読み解いていく、対話型のCTFです。 被害者のお孫さんとの家族写真が暗号化されて見られなくなってしまったという相談から始まり、1問目からTorへのアクセスを要求されるという、非常に興味深い問題設定でした。 もちろん、実際の生成AIサービスのように聞けばなんでも教えてくれるノリではなく、質問をクリアするとヒントを1個聞く権限が付与されるといったルールになっていました。 最後まで到達できず厳しい結果に終わりましたが、自力での解決を強いられるところに、現実のサイバー捜査の厳しさ・情報収集の難しさを実感できました。 TRAPA Cyber Range Exercise こちらはTRAPA が提供するサイバーレンジを利用した、ブルーチーム向けの実践的な演習に参加しました。 APTグループに攻撃を受けた仮想環境で、ログ解析、インシデント対応、被害拡大の防止措置を行うという、非常にリアルなシミュレーションとなっています。 こちらも会場の Wi-Fi 経由で、2日間どこからでもアクセスできました。 侵害を受けた環境はオンプレ構成となっており、インターネットとの間に DMZ があり、外部からのリクエストによって Proxyサーバ が侵入の起点になるといったシナリオでした。 SOCルームというダッシュボードで攻撃事象の確認やインシデントの調査結果を記録し(正解したらポイントを獲得)、 ログ調査にはSplunkを使って、 ファイアウォール ログや Windows ホストモニターなどを活用して演習を進めていきました。 複数の資産にまたがるログと時間制限の中では、ログを読むスピードが求められます。 こちらも最後まで到達できず厳しい結果に終わりましたが、調査に行き詰ったときにはTRAPA提供のAIに聞くとアド バイス がもらえたので面白かったです。 最後に 簡単ですが、Contests/Workshopsの紹介でした。 改めて自身の実力不足を痛感しつつも、初めてのCODE BLUEは結果として想像以上に楽しく、まるで海外カンファレンスに参加しているような刺激を受けました。 運営の皆様に心から感謝します。 本記事では紹介しませんでしたが、各セッションについても普段は聞けない興味深い内容が多く、大きな学びになりました。 ワークショップやコンテストについては開催する側も面白そうだなと思ったので、次回以降チャンスがあればチャレンジしてみたいです。 それでは、来年のCODE BLUE 2026でお会いしましょう! 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @fukuyama.kenta ( Shodo で執筆されました )
はじめに はじめまして。グループ経営ソリューション事業部の三谷です。 この記事では、 電通 総研で監視ツールとして利用しているDatadogについてどのようなサービスなのか基本的な情報と、導入手順をまとめた記事になります。 Datadogとは Datadog は、 クラウド やコンテナ環境向けの「監視・可観測性プラットフォーム」です。 サーバ・コンテナ・ ミドルウェア ・アプリケーション・ クラウド サービスからデータを集めて、1 つの画面で横断的に可視化・分析できる SaaS 型のサービスです。 Datadog が扱う主なデータは次の 4 種類に整理できます。 メトリクス CPU 使用率、メモリ使用量、ディスク I/O、リクエスト数、レイテンシなどの時系列データ。 ログ アプリケーションログ、 アクセスログ 、システムログ、 ミドルウェア ログなど。 トレース ( APM ) 1リクエストがどのサービス・コンテナを通過したか、その経路と各 区間 のレイテンシ。 つまり、アプリケーションの動作をトレースして、どこで遅延やエラーが発生しているかをDatadogから調査が可能です。 イベント デプロイ、スケールアウト/イン、障害、設定変更などの「出来事」を表す情報。 私は今まで、監視は主にCloudWatchを利用していました。CloudWatchだと、 AWS アカウントを跨いだ一元監視が難しく「ほかの AWS アカウントではどうなっているんだっけ・・・」と調査のために比較したいとき、 AWS アカウントを切り替えながら確認が必要で非常に手間がかかっていました。 Datadogではその問題は発生せず、複数の AWS アカウントのデータを一目で確認することができます。 Datadogでなにができるか(どのように監視するか) Datadog による監視の全体像は、大きく分けて4つの段階があります。 1. データを集める Agent による収集 監視対象のサーバやコンテナにDatadog Agentを導入すると、標準で次の情報を収集できます。 OS レベルのメトリクス CPU、メモリ、ディスク、ネットワーク I/O など コンテナメトリクス コンテナごとの CPU / メモリ / ネットワーク利用状況 ミドルウェア メトリクス nginx, Redis, PostgreSQL , MySQL などの各種インテグレーションを通じたメトリクス ログ・トレースの収集 Datadog はログ・トレースも一元的に扱えます。 ログの収集の例として下記の構成があります。 Datadog Agentでのログ収集 CloudWatch Logsや FireLens + Fluent Bit でのログ収集 それを Datadog に転送して保存・検索・解析 2. タグで関連づける Datadog では、すべてのメトリクス・ログ・トレース・イベントをタグで管理しています。 タグ設計が監視の品質を左右する、重要な設計要素になります。 たとえば、以下の調査を行いたい場合、Datadogだけで調査が完結します。 「ECSの特定タスクで500エラーが増えたタイミングで、CPU・メモリ利用率はどうだったか」 「その直前にデプロイやスケールイベントは発生していなかったか」 「どのリリースバージョンからエラー率が上がっているか」 代表的なタグ(例): 環境別 env:prod , env:staging , env:dev サービス別 service:my-api , service:batch-worker クラスタ ー別 cluster:my-ecs-cluster 3. 可視化・分析する 収集したデータはDatadogのコンソール上でダッシュボードを作成することが可能です。 ダッシュボードでの管理例 ECS / Fargate 向けの標準ダッシュボードを作る クラスタ 全体の CPU / メモリ使用率 サービスごとの runningタスク数 カスタムダッシュボード 本番環境 env:prod に特化したダッシュボードを作る リクエスト数 エラー率 CPU / メモリ使用率 4. モニター(アラート)で通知する 可視化して満足していても意味がないので、 閾値 や条件を定義して必要な通知を行う必要があります。Datadogではモニターと呼ぶ機能がこれに該当します。 代表的なモニターの例(ECS タスクの場合) ECS サービスのタスク数監視 条件例: running_tasks < desired_tasks が 5 分以上継続したらアラート エラー率監視 条件例: service:my-api AND env:prod の 5xx 発生率が一定以上でアラート 通知先 各種ツールへの通知が可能です。なおJiraと連携することで、Datadogにてアラート発生時にJiraのチケットを自動起票することも可能です。 https://www.atlassian.com/ja/devops/observability-tutorials/jira-datadog-integration 社内でJira自動起票について少し検討したことがありました。便利ではあるものの、長時間アラートが出た場合連続して同じチケットが起票されるのでは等、導入における考慮すべき点が多く、導入は一旦ステイとなりました。 また、オンコールについてもDatadog On-Callというサービスが存在しており一元管理することが可能です。 https://docs.datadoghq.com/ja/service_management/on-call/ ECSサービスの監視を実際にやってみる Datadogの基本的な機能が分かったところで、今回はDatadog Agentを導入してECSサービスの監視を行いたいと思います。 前提条件 AWS アカウントを持っていること Datadogアカウントを作成済みであること Datadogの API キーを取得済みであること Datadog AgentとDatadogが通信可能であること Datadogは収集するデータによって使用するポートが異なります。今回利用するAgentは TCP /443を使用します。 詳細はDatadogのドキュメントをご確認ください。 https://docs.datadoghq.com/ja/agent/configuration/network/ AWS での作業 タスク定義の作成 まず、ECSで使用するタスク定義を作成します。 今回のタスク定義では、以下の2つのコンテナを設定しました。 Datadog Agentコンテナ イメージ URI : public.ecr.aws/datadog/agent:latest Apache コンテナ イメージ URI : public.ecr.aws/docker/library/httpd:latest ※今回はECRのパブリックイメージを使用しました。 Datadogでの監視を有効化するため、Datadog Agentコンテナに以下の 環境変数 を設定します。 DD_API_KEY : Datadogの API キー DD_SITE : Datadogのサイト(例: datadoghq.com ) ECS_FARGATE : true クラスタ ーの作成 次に、ECS クラスタ ーを作成します。 任意の クラスタ ー名を入力し、その他デフォルトの設定で作成します。 サービスの作成 作成した クラスタ ー上でサービスを起動します。 サービス作成時の設定項目: タスク定義ファミリー : 先ほど作成したタスク定義を選択 環境 : 「起動タイプ」を選択 ネットワーキング : VPC を選択 サブネットを選択 適切なセキュリティグループを選択 (添付画像は入力前のものです) その他の項目はデフォルトのまま作成 サービスが正常に開始すると上図のようになります。 Datadogコンソールでの確認 監視を開始するためにDatadog側で必要な作業はほぼありません。 API キーさえ用意できれば、Agent導入後すぐに監視が始まります。 AWS マネジメントコンソールからサービス起動は確認できたので、Datadogからも確認してみます。 DatadogコンソールにてInfrastructure→Containers→ECS Explorer から起動したサービスが確認できます。 監視対象のサービスが見えました。CPU/メモリも取得できていそうです。 これで基本的な監視設定が完了しました。 APM など高度な監視には詳細な設定が必要ですが、基本的な監視であれば簡単に導入して監視を始められることがわかりました。 さいごに 今回はDatadogの仕組みについての基本的機能の概要と簡単なサービス監視までを実施しました。 Datadogは、最初の14日間はトライアル期間であり、すべての機能が無料で使用できます。 皆様もよいDatadogライフをお過ごしください。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @mitani.kyoka レビュー: @kinjo.ryuki ( Shodo で執筆されました )
はじめに こんにちは、XI本部エンジニアリングテクノロ ジー センターの徳山広士です。 この記事では、データ基盤/データ分析基盤におけるデータパイプラインのAI駆動開発の手法を提案します。 「 ODCS (Open Data Contract Standard) 」フォーマットの"Data Contract"を仕様書として生成AIへ与えてデータパイプラインのコードを生成させる手法です。 Data Contractは、データの仕様(テーブル構造、カラム定義、データ型など)と品質要件を YAML 形式で定義する標準フォーマットです。 当記事の主な内容は、Data Contractやローカル開発環境などの基礎的な説明から当件のAI駆動開発方法、コード生成に成功した検証結果についてです。 想定読者: データエンジニア、データマネジメント業務担当者 当記事で得られる知見: データパイプラインのAI駆動開発の勘所 前提知識: データパイプライン(ETL/ ELT 処理)の基礎知識 一般的に労力と時間のかかるデータマネジメント・サイクルをAI駆動開発によって加速できればと考えて、データエンジニアリングのAI駆動開発手法を探求し、この記事にまとめました。 データパイプラインのAI駆動開発実現の課題 生成AIに何を伝えるべきか アプリケーションのAI駆動開発においては、 ドメイン や ユースケース 、機能、制約などを生成AIに説明することでコード生成するアプローチを見聞きします。では、 データエンジニアリングにおいては何を説明すれば良いのか?どのように指示を出せば包括的に開発してくれるのか? これが最初に直面した課題でした。 自然言語 のプロンプトで目的の SQL クエリについて説明する方法も考えましたが、複雑なロジックの表現が困難であり、細かい要件が伝わらず、プロンプトの再現性・再利用性にも疑問がありました。 アプローチ: データ アーキテクチャ とデータモデルを伝える この課題に対して、データエンジニアリングの観点から「データ アーキテクチャ 」と「データモデル」の2つの軸で情報を整理し、データ基盤/データ分析基盤の全体像と開発方法を生成AIに伝えるアプローチを採用しました。 データ アーキテクチャ の説明 生成AIが全体像を理解するための情報: データレイヤー構造と各レイヤーの責務: raw, staging, core, martなど データストアの構成: データレイク, データウェアハウス, データマートなど 各データストアのデータフォルダ構成: "raw/システム名/YYYYMMDD"など データ処理アプローチ: ELT など インフラストラクチャ構成: 各データストアの物理実装で利用の SaaS など データパイプライン構成技術: dagster , dbt core など これらの内容を プロジェクトドキュメント(DESIGN.md等) として整備しました。 データモデルの説明 生成AIがデータパイプラインで実現すべき対象の情報: データの構成: テーブル, カラム, リレーションシップなど データ仕様: データ型, 主キー等の制約, 変換ロジックなど データ品質仕様: 満たすべき基準, テストルールなど これらを Data Contract(ODCS形式) としてドキュメント整備しました。 この2つを組み合わせることで、生成AIはデータパイプラインの実行環境全体の設計意図を理解し、データ基盤/データ分析基盤に適した具体的な実装を行えるようになりました。 データパイプライン作成依頼 生成AIへの開発依頼は、データパイプラインの要件を ADR (Architecture Decision Record) に記述し、その ADR で定義されたデータパイプラインを関連するData Contractにもとづいて開発するように生成AIへ依頼する方法を採用しました。 ADR に少なくとも以下の内容を書くようにしました。 データパイプラインの作成対象のデータ名 データ提供の背景や目的, データ利用の ユースケース ADR の記載内容の参考イメージ タイトル: P001 ECビジネスデータパイプライン構造 ステータス: Accepted コンテキスト: Eコマースビジネスパイプラインのデータ統合対象のデータを決める必要がある。 決定事項: Eコマースビジネスパイプラインは、web_salesとweb_returnsを対象とした構成にする。 検証内容の詳細 実際の検証環境や要件、作成対象のデータなどを説明します。 検証では TPC-DS (*1)のデータを使用し、生成AIには Claude Code(Sonnet 4.5, Anthropic) を使用しました。 web_salesテーブルの更新用のソースデータを変換してweb_salesへ統合するデータパイプラインの SQL クエリを生成します。 ※1 TPC -DS は Transaction Processing Performance Council ( TPC ) の商標です。 本記事は TPC ベンチマーク 結果の公表を目的としたものではありません。 ローカル開発環境 データパイプラインのデプロイ先は AWS やAzure、 Google Cloudなどの SaaS ですが、AI駆動開発を効率化するためにデプロイ先を模したローカル完結型の開発環境を整備しました。 データレイク兼データウェアハウス: DuckDB データ モデリング : dbt core オーケストレータ: dagster データ品質テスト: Soda Core DuckDBで構成 : SaaS への外部通信を排除し、生成AIの生産性を最大化。 SaaS で巨大になりがちなデータレイクやデータウェアハウスをコンパクトなDuckDBで代用しました。 コードベースのツール選定 : 生成AIがコードを直接参照・実装できるよう、全てコードベースのツールを採用。 GUI のETLツールは、生成AIとの連携で独自 SDK / API 経由が必要となり生産性の低下が懸念されるため使用しませんでした。 ツールによるインフラストラクチャの抽象化 : デプロイ先の SaaS とは物理的な環境構成が異なりますが、dbt coreなどのソフトウェアが抽象化し環境差分を吸収してくれます。 データ アーキテクチャ 概要 データパイプラインのデプロイ先のデータ分析基盤のデータ アーキテクチャ を図にしたものです。論理構成の主要部分のみを抜粋し、簡潔な内容を掲載しております。 データレイヤー: "raw", "staging", "core", "mart" の4層 データストア: データレイクとデータウェアハウス データ処理アプローチ: ELT データパイプライン構成技術: Dagster, dbt core, Soda Core インフラストラクチャ: AWS とAzure, Google Cloudの3大 クラウド サービスでそれぞれ実施、詳細は割愛 データモデル web sales ※一部のカラムは割愛 ディメンショナル モデリング されたスター スキーマ 構造となっており、複数の サロゲートキー を持っています。データ構造は把握しやすいもののETL/ ELT 処理の観点では10個以上のテーブル結合や中間テーブルを介したテーブル結合、一部カラムの演算処理が必要な複雑な構造になっています。 作成対象のデータパイプライン rawレイヤー 生データのデータファイルが外部テーブル (External table) としてデータウェアハウスに既にテーブル化されており、そのテーブルを参照すれば良いため、処理の実装は不要。 stagingレイヤー rawレイヤーのデータをもとにマスターデータとの結合によるデータ取得や演算処理などの ビジネスロジック をdbtの SQL クエリモデルとして実装 SELECT対象のカラム数: 35個 テーブル結合数: 12個 coreレイヤー stagingレイヤーのデータをもとに増分処理でデータ更新する処理をdbtの SQL クエリモデルとして実装 SELECT対象のカラム数: 38個 テーブル結合数: 0個 実装ルール SELECT文でカラムの型キャストを明記 SELECT文でカラムの名称をAS文で指定 CTE (Common Table Expression) でソースデータ定義 coreレイヤーでは増分処理を実装 生成AIへの依頼 前述の「 アプローチ: データアーキテクチャとデータモデルを伝える 」に記載のドキュメントに加えて、開発 ガイドライン も整備し開発依頼を行いました。 生成AIへ提供した情報 プロジェクトドキュメント Data Contract 開発 ガイドライン (開発規約や トラブルシューティング など) ADR (Architecture Decision Record) プロンプト 実際のプロンプト 以下のファイルを読み込んで、当プロジェクトについて理解してください。 - ./docs/DESIGN.md - ./docs/DATAMODEL_GENERATION_GUIDELINES.md ADRで定義されたデータパイプラインを関連する`Data Contract`にもとづいて作成します。 今回は、ADRの"./docs/adr/pipelines/P001-ecommerce-business-pipeline-structure.md"で決定したデータパイプラインを作成してください。 実際のData Contractのサンプル "ws_item_sk"という主要なカラムのData Contractを一部抜粋したものです。より詳しい内容と解説は 詳細解説 にて後述します。 - name : ws_item_sk businessName : ウェブ販売商品サロゲートキー logicalType : string physicalType : STRING primaryKey : true primaryKeyPosition : 1 transformSourceObjects : - core_tpcds.item.i_item_sk transformLogic : SELECT i_item_sk FROM s_web_order JOIN s_web_order_lineitem ON (word_order_id = wlin_order_id) LEFT JOIN item ON (wlin_item_id = i_item_id AND i_rec_end_date IS NULL ) relationships : - type : foreignKey to : - core_tpcds.item.i_item_sk quality : - type : library rule : duplicateCount name : "主キー重複チェック(ws_item_sk)" dimension : uniqueness mustBe : 0 severity : error businessImpact : "重複レコードによりファクトテーブルのデータ整合性が崩れ、売上集計に誤差が生じる" 生成されたコード stagingレイヤー 12テーブルを結合し、35カラムを生成する SQL クエリです。Data Contractの transformLogic で定義した変換ロジックが正確に反映されています。 with s_web_order as ( select * from {{ source( ' raw_tpcds ' , ' s_web_order_1 ' ) }} ), s_web_order_lineitem as ( select * from {{ source( ' raw_tpcds ' , ' s_web_order_lineitem_1 ' ) }} ) SELECT d1.d_date_sk::STRING AS ws_sold_date_sk, t_time_sk::STRING AS ws_sold_time_sk, d2.d_date_sk::STRING AS ws_ship_date_sk, i_item_sk::STRING AS ws_item_sk, c1.c_customer_sk::STRING AS ws_bill_customer_sk, c1.c_current_cdemo_sk::STRING AS ws_bill_cdemo_sk, c1.c_current_hdemo_sk::STRING AS ws_bill_hdemo_sk, c1.c_current_addr_sk::STRING AS ws_bill_addr_sk, c2.c_customer_sk::STRING AS ws_ship_customer_sk, c2.c_current_cdemo_sk::STRING AS ws_ship_cdemo_sk, c2.c_current_hdemo_sk::STRING AS ws_ship_hdemo_sk, c2.c_current_addr_sk::STRING AS ws_ship_addr_sk, wp_web_page_sk::STRING AS ws_web_page_sk, web_site_sk::STRING AS ws_web_site_sk, sm_ship_mode_sk::STRING AS ws_ship_mode_sk, w_warehouse_sk::STRING AS ws_warehouse_sk, p_promo_sk::STRING AS ws_promo_sk, word_order_id::STRING AS ws_order_number, wlin_quantity:: INTEGER AS ws_quantity, i_wholesale_cost:: DECIMAL ( 7 , 2 ) AS ws_wholesale_cost, i_current_price:: DECIMAL ( 7 , 2 ) AS ws_list_price, wlin_sales_price:: DECIMAL ( 7 , 2 ) AS ws_sales_price, ((i_current_price:: DECIMAL ( 7 , 2 ) - wlin_sales_price:: DECIMAL ( 7 , 2 )) * wlin_quantity:: INTEGER ):: DECIMAL ( 7 , 2 ) AS ws_ext_discount_amt, (wlin_sales_price:: DECIMAL ( 7 , 2 ) * wlin_quantity:: INTEGER ):: DECIMAL ( 7 , 2 ) AS ws_ext_sales_price, (i_wholesale_cost:: DECIMAL ( 7 , 2 ) * wlin_quantity:: INTEGER ):: DECIMAL ( 7 , 2 ) AS ws_ext_wholesale_cost, (i_current_price:: DECIMAL ( 7 , 2 ) * wlin_quantity:: INTEGER ):: DECIMAL ( 7 , 2 ) AS ws_ext_list_price, (i_current_price:: DECIMAL ( 7 , 2 ) * web_tax_percentage:: DECIMAL ( 7 , 2 )):: DECIMAL ( 7 , 2 ) AS ws_ext_tax, wlin_coupon_amt:: DECIMAL ( 7 , 2 ) AS ws_coupon_amt, (wlin_ship_cost:: DECIMAL ( 7 , 2 ) * wlin_quantity:: INTEGER ):: DECIMAL ( 7 , 2 ) AS ws_ext_ship_cost, (wlin_sales_price:: DECIMAL ( 7 , 2 ) * wlin_quantity:: INTEGER - wlin_coupon_amt:: DECIMAL ( 7 , 2 )):: DECIMAL ( 7 , 2 ) AS ws_net_paid, (((wlin_sales_price:: DECIMAL ( 7 , 2 ) * wlin_quantity:: INTEGER ) - wlin_coupon_amt:: DECIMAL ( 7 , 2 )) * ( 1 + web_tax_percentage:: DECIMAL ( 7 , 2 ))):: DECIMAL ( 7 , 2 ) AS ws_net_paid_inc_tax, (((wlin_sales_price:: DECIMAL ( 7 , 2 ) * wlin_quantity:: INTEGER ) - wlin_coupon_amt:: DECIMAL ( 7 , 2 )) - (wlin_quantity:: INTEGER * i_wholesale_cost:: DECIMAL ( 7 , 2 ))):: DECIMAL ( 7 , 2 ) AS ws_net_paid_inc_ship, ((wlin_sales_price:: DECIMAL ( 7 , 2 ) * wlin_quantity:: INTEGER ) - wlin_coupon_amt:: DECIMAL ( 7 , 2 ) + (wlin_ship_cost:: DECIMAL ( 7 , 2 ) * wlin_quantity:: INTEGER ) + i_current_price:: DECIMAL ( 7 , 2 ) * web_tax_percentage:: DECIMAL ( 7 , 2 )):: DECIMAL ( 7 , 2 ) AS ws_net_paid_inc_ship_tax, (((wlin_sales_price:: DECIMAL ( 7 , 2 ) * wlin_quantity:: INTEGER ) - wlin_coupon_amt:: DECIMAL ( 7 , 2 )) - (i_wholesale_cost:: DECIMAL ( 7 , 2 ) * wlin_quantity:: INTEGER )):: DECIMAL ( 7 , 2 ) AS ws_net_profit, s_web_order.processing_date::STRING AS processing_date, current_timestamp :: TIMESTAMP AS ingested_at FROM s_web_order LEFT JOIN {{ ref( ' date_dim ' ) }} d1 ON ( cast (word_order_date AS date ) = d1.d_date) LEFT JOIN {{ ref( ' time_dim ' ) }} ON (word_order_time = t_time) LEFT JOIN {{ ref( ' customer ' ) }} c1 ON (word_bill_customer_id = c1.c_customer_id) LEFT JOIN {{ ref( ' customer ' ) }} c2 ON (word_ship_customer_id = c2.c_customer_id) LEFT JOIN {{ ref( ' web_site ' ) }} ON (word_web_site_id = web_site_id AND web_rec_end_date IS NULL ) LEFT JOIN {{ ref( ' ship_mode ' ) }} ON (word_ship_mode_id = sm_ship_mode_id) JOIN s_web_order_lineitem ON (word_order_id = wlin_order_id) LEFT JOIN {{ ref( ' date_dim ' ) }} d2 ON ( cast (wlin_ship_date AS date ) = d2.d_date) LEFT JOIN {{ ref( ' item ' ) }} ON (wlin_item_id = i_item_id AND i_rec_end_date IS NULL ) LEFT JOIN {{ ref( ' web_page ' ) }} ON (wlin_web_page_id = wp_web_page_id AND wp_rec_end_date IS NULL ) LEFT JOIN {{ ref( ' warehouse ' ) }} ON (wlin_warehouse_id = w_warehouse_id) LEFT JOIN {{ ref( ' promotion ' ) }} ON (wlin_promotion_id = p_promo_id) coreレイヤー stagingレイヤーのデータを増分処理でcoreレイヤーに取り込む SQL クエリです。dbtのincrementalモデルを使用しています。 {{ config( materialized= ' incremental ' , unique_key=[ ' ws_item_sk ' , ' ws_order_number ' ], on_schema_change= ' fail ' , incremental_strategy= ' merge ' if target. type != ' duckdb ' else ' delete+insert ' ) }} -- Incrementalモデル:staging層からデータを取得 select ws_sold_date_sk::STRING as ws_sold_date_sk, ws_sold_time_sk::STRING as ws_sold_time_sk, ws_ship_date_sk::STRING as ws_ship_date_sk, ws_item_sk::STRING as ws_item_sk, ws_bill_customer_sk::STRING as ws_bill_customer_sk, ws_bill_cdemo_sk::STRING as ws_bill_cdemo_sk, ws_bill_hdemo_sk::STRING as ws_bill_hdemo_sk, ws_bill_addr_sk::STRING as ws_bill_addr_sk, ws_ship_customer_sk::STRING as ws_ship_customer_sk, ws_ship_cdemo_sk::STRING as ws_ship_cdemo_sk, ws_ship_hdemo_sk::STRING as ws_ship_hdemo_sk, ws_ship_addr_sk::STRING as ws_ship_addr_sk, ws_web_page_sk::STRING as ws_web_page_sk, ws_web_site_sk::STRING as ws_web_site_sk, ws_ship_mode_sk::STRING as ws_ship_mode_sk, ws_warehouse_sk::STRING as ws_warehouse_sk, ws_promo_sk::STRING as ws_promo_sk, ws_order_number::STRING as ws_order_number, ws_quantity:: INTEGER as ws_quantity, ws_wholesale_cost:: DECIMAL ( 7 , 2 ) as ws_wholesale_cost, ws_list_price:: DECIMAL ( 7 , 2 ) as ws_list_price, ws_sales_price:: DECIMAL ( 7 , 2 ) as ws_sales_price, ws_ext_discount_amt:: DECIMAL ( 7 , 2 ) as ws_ext_discount_amt, ws_ext_sales_price:: DECIMAL ( 7 , 2 ) as ws_ext_sales_price, ws_ext_wholesale_cost:: DECIMAL ( 7 , 2 ) as ws_ext_wholesale_cost, ws_ext_list_price:: DECIMAL ( 7 , 2 ) as ws_ext_list_price, ws_ext_tax:: DECIMAL ( 7 , 2 ) as ws_ext_tax, ws_coupon_amt:: DECIMAL ( 7 , 2 ) as ws_coupon_amt, ws_ext_ship_cost:: DECIMAL ( 7 , 2 ) as ws_ext_ship_cost, ws_net_paid:: DECIMAL ( 7 , 2 ) as ws_net_paid, ws_net_paid_inc_tax:: DECIMAL ( 7 , 2 ) as ws_net_paid_inc_tax, ws_net_paid_inc_ship:: DECIMAL ( 7 , 2 ) as ws_net_paid_inc_ship, ws_net_paid_inc_ship_tax:: DECIMAL ( 7 , 2 ) as ws_net_paid_inc_ship_tax, ws_net_profit:: DECIMAL ( 7 , 2 ) as ws_net_profit, processing_date::STRING as processing_date, ingested_at:: TIMESTAMP as ingested_at, current_timestamp :: TIMESTAMP as inserted_at, current_timestamp :: TIMESTAMP as updated_at from {{ ref( ' web_sales_view ' ) }} {% if is_incremental() %} -- incrementalの場合、processing_dateでフィルタリング where processing_date = ' {{ var("processing_date", "20240101") }} ' {% endif %} 詳細解説 Data Contractとは? Data Contractは、データの提供者と利用者の間でデータ仕様やデータ品質要件を合意するための標準フォーマットです。 フォーマットの既定の項目を使ってデータ仕様やデータ品質要件を定義することができます。 既定の項目がサポートしているものは、テーブル スキーマ や各種の論理名、データの粒度などの メタデータ に加えて、サンプルデータ、データ品質ルールなど多岐に渡ります。 当検証では「 ODCS (Open Data Contract Standard) 」という YAML 形式のフォーマットを使用します。ODCSは Linux Foundation傘下のBitolプロジェクトがサポートする代表的な仕様です。 当記事では、Data Contractを生成AIへ与えるコンテキストとして活用します。Data Contractの作成自体は設計プロセスで生成AIに行わせることも可能です(別記事で説明予定)。 今回使用のData Contractの主要項目 主に使用した項目と各項目の簡単な説明を記載します。 name: カラム物理名 businessName: カラム論理名 logicalType: 論理データ型 physicalType: 物理データ型 transformSourceObjects: カラムのデータを作成する際に必要なソースデータに関する情報 transformLogic: カラムのデータを作成する際に必要なデータ変換ロジック relationships: カラムのリレーションシップ情報 quality: カラムのデータ品質要件 実際のData Contract 以下、代表的な2つのカラムのData Contractを抜粋します。 主キー兼外部キーの例: ws_item_sk こちらは前述のData Contractの詳述です。 複合主キーの一部であり外部キーでもあるカラムです。3テーブルの結合と、3種類のデータ品質テストが定義されています。 - name : ws_item_sk businessName : ウェブ販売商品サロゲートキー logicalType : string physicalType : STRING primaryKey : true primaryKeyPosition : 1 transformSourceObjects : - core_tpcds.item.i_item_sk transformLogic : SELECT i_item_sk FROM s_web_order JOIN s_web_order_lineitem ON (word_order_id = wlin_order_id) LEFT JOIN item ON (wlin_item_id = i_item_id AND i_rec_end_date IS NULL ) relationships : - type : foreignKey to : - core_tpcds.item.i_item_sk customProperties : - target_contract_id : "core_tpcds.item" - target_contract_path : "./core_tpcds/item.yaml" - target_property : "i_item_sk" quality : - type : library rule : duplicateCount name : "主キー重複チェック(ws_item_sk)" dimension : uniqueness mustBe : 0 severity : error businessImpact : "重複レコードによりファクトテーブルのデータ整合性が崩れ、売上集計に誤差が生じる" - type : library rule : nullCount name : "主キーNULLチェック(ws_item_sk)" dimension : completeness mustBe : 0 severity : error businessImpact : "NULL値が存在すると商品別売上分析が不可能になる" - type : sql name : "商品マスタ参照整合性チェック" dimension : consistency query : | SELECT COUNT(*) FROM ${object} ws LEFT JOIN item i ON ws.ws_item_sk = i.i_item_sk WHERE ws.ws_item_sk IS NOT NULL AND i.i_item_sk IS NULL mustBe : 0 severity : error businessImpact : "参照整合性が崩れると商品マスタとの結合で欠損が発生し、商品情報を取得できない売上データが生じる" 複雑な計算ロジックの例: ws_net_profit 純利益は複数のソースから計算され、計算整合性と平均値の妥当性の両方がチェックされます。 - name : ws_net_profit businessName : ウェブ純利益 logicalType : number physicalType : DECIMAL(7, 2) transformSourceObjects : - raw.s_web_order_lineitem.wlin_sales_price - raw.s_web_order_lineitem.wlin_quantity - raw.s_web_order_lineitem.wlin_coupon_amt - core_tpcds.item.i_wholesale_cost transformLogic : SELECT (((wlin_sales_price::DECIMAL(7,2) * wlin_quantity::INTEGER) - wlin_coupon_amt::DECIMAL(7,2)) - (i_wholesale_cost::DECIMAL(7,2) * wlin_quantity::INTEGER))::DECIMAL(7,2) FROM s_web_order JOIN s_web_order_lineitem ON (word_order_id = wlin_order_id) LEFT JOIN item ON (wlin_item_id = i_item_id AND i_rec_end_date IS NULL ) quality : - type : sql name : "純利益計算整合性チェック" dimension : accuracy query : | SELECT COUNT(*) FROM ${object} WHERE ws_net_profit IS NOT NULL AND ws_net_paid IS NOT NULL AND ws_ext_wholesale_cost IS NOT NULL AND ABS(ws_net_profit - (ws_net_paid - ws_ext_wholesale_cost)) > 0.01 mustBe : 0 severity : error businessImpact : "計算式が不正確な場合、利益分析の信頼性を損なう" - type : sql name : "純利益平均値チェック" dimension : accuracy query : | SELECT AVG(ws_net_profit) FROM ${object} WHERE ws_net_profit IS NOT NULL mustBeBetween : [ -100, 1000 ] severity : warning businessImpact : "平均利益が異常値の場合、価格設定や原価データに問題がある可能性" transformSourceObjectsとtransformLogicの重要性 当検証で特に試行錯誤したのが、この2つのプロパティの記述でした。 当初の仮説 : 各プロパティでデータ仕様を記述し、relationshipsプロパティでデータ間の関係性を記述すれば、生成AIがJOIN処理やカラム毎の計算ロジック、変換ロジックを類推できるのではないか 実際の課題 : データ仕様やリレーションシップ(データモデル上の関係性)とETL/ ELT 処理(データ変換ロジック)の間には隔たりがある 例えば、 ws_item_sk カラムは item テーブルと外部キー関係にありますが、実際のデータ取得には s_web_order → s_web_order_lineitem → item という3テーブルの結合が必要です。 これは生成AIに分かってもらえそうで分かってもらえませんでした。 s_web_order と item の2つのテーブルを無理に結合しようとしてしまいますし、チャットで説明して改善しても後で忘れて問題が再発し、忘れないように記録してもらっても個別のケースの実装方法として記録されて他ケースへの応用が懸念されました。 他に、生成AIは サロゲートキー どうしでテーブル結合したり、主キーで結合するように指示して改善しても今度は肝心の サロゲートキー を取得してくれなかったりしました。 また、カラムの演算処理は間違った内容が実装されるか全く実装されないかでした。 そのため、以下の2つのプロパティを使うようにしました: transformSourceObjects : データの出所(ソーステーブル・カラム)を明示 transformLogic : 具体的な変換ロジック(JOIN条件、フィルタ、計算式など)を記述 これにより、生成AIは「何を参照して、どう変換するか」を正確に理解し、意図通りの SQL を生成できるようになりました。 transformSourceObjectsとtransformLogicの作成方法 transformSourceObjectsプロパティとtransformLogicプロパティの作成自体をデータモデルの設計過程で生成AIと共に行います。 もし、データソース側のシステムで業務知識 (例. 純利益の計算式) が何かドキュメントなどに整理されてあれば、その内容をもとに生成AIが両プロパティを定義できる可能性があります。 また、例えばディメンショナル モデリング であれば、データ粒度 (Grain) の定義やConformance Matrixなどを機械判読可能なファイル形式で生成AIと共に作成し、それら成果物をソースとして生成AIが両プロパティを作成できる可能性があります。 relationshipsプロパティは ODCS v3.1.0 にリリース予定 ODCSの現在の最新公式バージョンはv3.0.2ですが、このバージョンには relationshipsプロパティが存在しません 。 ODCS v3.1.0でrelationshipsプロパティが実装される予定で、当検証ではODCSの v3.1.0 を先行的に使用しています。 v3.1.0での追加予定: ODCS v3.1.0 RFC0013 その他のプロパティの作成方法 nameプロパティやphysicalTypeプロパティなどの基礎的なプロパティの作成は、データソースのDBの スキーマ 情報や生データのデータファイルをソースとして生成AIに与えることで半自動生成もしくは自動生成が可能です。 Excel などの固有ソフトウェアのファイル形式の場合は、機械判読可能なオープンなファイル形式への変換が必要です。 さいごに 検証の振り返り 本記事では、Data Contract(ODCS形式)を活用したデータパイプラインのAI駆動開発手法を検証しました。 成果として得られたこと : 12テーブル結合、35カラムの複雑な SQL クエリを生成AIが正確に生成 Data Contractに定義した型キャスト、計算ロジック、JOIN条件が意図通りに実装 増分処理やdbtのincremental設定も適切に生成 成功要因 : データ アーキテクチャ とデータモデルの2軸でコンテキストを整理 データ項目やデータ型、制約などの スキーマ 情報に加えて、 transformSourceObjects と transformLogic でデータリネージを明示 ローカル完結型の開発環境で生成AIの試行錯誤を高速化 所感 データエンジニアリングのAI駆動開発に向けたドキュメント整備方法の1つを見出すことができて良かったと思います。 データ基盤/データ分析基盤を概念的に分解し、既存の専門用語に当てはめて構造化して説明することで生成AIが体系的かつ詳細に理解するようになることが実感できました。 また、特定の製品・サービスに依存せずに進められましたので、再利用性が比較的に高いと考えており、今後の応用として関連の製品・サービスと連携しDataOpsやAIOpsへ昇華できればと期待しています。 データマネジメントのより広い範囲への活用の可能性 本記事ではデータパイプラインのコード生成に焦点を当てましたが、Data Contract自体の生成やデータ品質テストの自動生成など、より広い範囲への活用も考えられます。実際にData Contractの quality プロパティを応用したデータ品質テストコードの生成を検証しており、その内容は別途記事化の予定です。 また、データの意味的な定義やデータ統合に関する マッピング 情報などを整備してData Contractを拡張することで、例えばデータマネジメント全般における機械判読可能なドキュメントとしての活用やAI伴走型の分析データモデル開発への応用も検討しています。 データエンジニアとして、データマネジメントにおけるData Contractと生成AIの活用可能性については、今後も継続的に検証を進めていく予定です。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @shikarashika レビュー: @yamada.y ( Shodo で執筆されました )
はじめに 金融IT本部 2年目の坂江 克斗です。 業務にてDNSSECを使用する機会があり、とても面白い内容だったのでまとめてみました。 初学者の視点で疑問に感じる部分も含め、基本的な概念から丁寧に解説できればと思います。 (概要説明が不要な方は、Terraformによる実装の章のみご参照ください) 本記事は 電通総研 Advent Calendar 2025 5日目の記事です。 はじめに DNSの概要 DNSとは 名前解決の流れ (DNSサーバとリゾルバ、レジストラの関係) DNSSECの概要 通常のDNSの脆弱性 DNSSECで登場するリソース DNSSECの署名検証フロー (補足)DNSSECが確認できるサイト AWSにおけるDNSSECの実装方法 (Terraform) 前提 Terraformの実装 Applyの結果 Destroyの結果 おわりに DNS の概要 DNS とは DNS (Domain Name System)は、インターネット上で人間が読みやすい名前( ドメイン 名)と IPアドレス を対応付ける仕組みです。 コンピュータは通信の際に使用する IPアドレス (数値やビット形式)の方が便利ですが、人間にとっては「 example.com 」のような文字列( ドメイン 名)の方が読みやすく便利です。 DNS は、こうした人間に分かりやすい ドメイン 名から機械が扱う IPアドレス に変換( 名前解決 )する役割を担っています。 なお、 ドメイン 名を省略せずに完全な形で記載したものを FQDN (Fully Qualified Domain Name) と呼びます。 名前解決の流れ ( DNS サーバとリゾルバ、 レジストラ の関係) 全ての ドメイン 名と対応する IPアドレス を一つのサーバで管理するのは、データ量や処理速度の面から現実的ではありません。 そのため DNS では、「.」で区切られた各 ドメイン ごとに専用のサーバ(後述する権威サーバ)が分散して管理を行っています。 各権威サーバが独立して情報を持つだけでは、名前解決をする際に直接目的の権威サーバにアクセスする必要があり、全ての権威サーバのアドレスを把握しておかなければならず、現実的ではありません。 そのため、親 ドメイン の権威サーバが子 ドメイン の権威サーバのアドレスを持つ、つまりある ドメイン (例:com)に「○○.」を加えた ドメイン (例:sample.com)の権威サーバの場所を持つことで、親から子を辿り目的の権威サーバまでアクセスする仕組みが使用されています。 親 ドメイン から子 ドメイン に向かって根が張っているようなこの仕組みにより、どんなに長い ドメイン 名に対しても目的の権威サーバまで効率的にたどり着ける構成になっています。 上記の内容を現実のリソースに合わせて具体的に示します。 ドメイン 解決で登場するリソース名とその関係は、以下の図に示す形になります。 権威サーバに聞きまわって解決するのはフルサービスリゾルバ( 再帰 リゾルバ とも呼ばれます)が担当していることが分かります。 特に、権威サーバの中でも最初にアクセスする「.」 ドメイン を管理するサーバを ルートサーバ と呼び、ルートサーバがレコードとして管理する「.com」や「.jp」等を TLD ( トップレベルドメイン ) と呼びます。 また、先述した権威サーバの宛先情報を持つのが NSレコード であり、 ドメイン 名と IPアドレス を紐付けるのが A/AAAAレコード ( IPv4 だとA、 IPv6 だとAAAA)となります。 NSレコードの補足 NSレコードには ドメイン 名が値として設定されます。そのため、子 ドメイン にアクセスする場合は、親 ドメイン に登録されたNSレコードを取得した後、NSレコードに設定されていた ドメイン 名をさらに名前解決する必要があります。 もし、その ドメイン 名が子 ドメイン と同じゾーンに属している場合、再度親 ドメイン から解決する循環参照に陥ってしまいます。この問題を防ぐために、親 ドメイン 側にNSレコードとともに Glueレコード (権威サーバの ドメイン に対応するA/AAAAレコード) を設定する必要があります。 ルートサーバや TLD 用の権威サーバは特に名前解決の根幹となるサーバであり、ゾーン情報が適切に管理される必要があります。 現在は ICANN (The Internet Corporation for Assigned Names and Numbers) によりルートサーバを管理、各 TLD の権威サーバ・ゾーン情報の管理を レジストリ が担当し、消費者への仲介を レジストラ が担当しています。 細かい話になりましたが、ここでは ドメイン のレコードを管理・応答するのが権威サーバ、権威サーバが管理する論理的な ドメイン 単位の管理領域をゾーン( AWS ではホストゾーン)、名前解決を頑張るのがフルサービスリゾルバとだけ覚えていただければ十分です。 DNSSECの概要 通常の DNS の 脆弱性 DNS によって、ユーザは ドメイン から情報 ( IPアドレス 等) を取得します。 しかし、セキュリティ攻撃によってレコード情報が改ざんされると、例えば ドメイン 解決により取得した IPアドレス を使用した場合に悪意のあるWebサイト(フィッシングサイト等)にアクセスさせられる可能性もあります。 改ざんが発生するセキュリティ攻撃の例としては以下の図に示す、 DNS ハイジャックによるゾーン情報の改ざん、 DNS キャッシュポイズニング、中間者攻撃(の一例)等があげられます。 では、レコード情報が改ざんされていることをどのように検出すればよいでしょうか? 今回紹介するDNSSEC (Domain Name System Security Extensions) は、まさにこの問題を解決するための仕組みになります。 以下は JPRS によるDNSSECの説明となります。 DNS 応答に 電子署名 を追加し、問い合わせ側で検証することで DNS の攻撃耐性を向上させる、セキュリティ 拡張機能 です。DNSSECは、受け取った DNS レコードの出自(送信元で登録したデータであること)・完全性(データの欠落や改ざんのないこと)を問い合わせ側で検証できるようにするための機能を DNS に追加します。 ざっくりしたイメージとしては、親から子への信頼の連鎖(信頼チェーン)を構成し、改ざんされたとしても信頼が崩れた箇所で改ざんを検知できるものとなっています。 ただし、以下に示す前提の上でDNSSECがセキュリティを担保している点に注意してください。 クライアントから正しいフルサービスリゾルバへ接続していること フルサービスリゾルバから正しいルートサーバへ接続していること ルートサーバが正しい情報を持っていること 次節から具体的に説明します。 DNSSECで登場するリソース おさえるべきリソースは、2種類の鍵と3種類のレコードとなります。 リソースの一覧表および設定フローのイメージ図を以下に示します。 種類 名称 親/子 役割 鍵 ZSK (Zone Signing Key) 子 ゾーン内の リソースレコードに署名 するための非対称鍵(公開鍵・ 秘密鍵 のペア) KSK (Key Signing Key) 子 ZSKの公開鍵自体を署名 するための非対称鍵 レコード RRSIG (Resource Record Signature) 子 リソースレコードセット(同じレコード名、Typeでまとめた塊)毎に、 ZSKの 秘密鍵 により作成した署名 を持つレコード。署名とともに署名元のレコード、鍵の情報も持つ。 DNSKEY 子 ゾーンの公開鍵(ZSKとKSKの公開鍵) を持つレコード。レコードのFlagが256のものがZSK、257のものがKSK DS (Delegation Signer) 親 子ゾーンのKSK の ハッシュ値 を持つレコード。信頼チェーンの肝 ZSKとKSKの補足 DNSKEYレコード(ZSK) をそのままDSレコードとの紐付けに使用すれば、KSKが必要ないと思われます。しかし、実際にはセキュリティとメンテナンス性の観点から役割が分かれています。 RFC 4641 を参考に、私はZSK・KSKの推奨方針を以下のように解釈しています。 ・ 署名(暗号化)の管理観点で鍵をこまめにローテーションすべきである。しかし、ローテーション毎に親ゾーンのDSレコード更新が発生すると運用コストが高くなる。 ・ そのため、ZSKとKSKの2つの鍵ペアを用い、ZSKを頻繁にローテーションし、KSKを長期間使用する方針が推奨される。これにより、親ゾーンのDSレコード更新頻度を下げる。 ・ KSKはZSKの署名に使用されるのみであり、大量のデータ署名には使用しない。そのため、強度の高い鍵(より大きなビット長のキーマテリアル)を採用できる。 ・ KSKの使用頻度の低さから、ZSKよりも安全な場所(HSM)に保管できる。 DNSSECの署名検証フロー 前節で示した設定フローイメージを基に考えると、aa.comのAレコードを解決する際の署名検証は以下のような流れで行われます。 親ゾーンのDSレコードと子ゾーンのDNSKEYレコード(KSK)を検証し、子ゾーンのKSKの正当性を確認します。 子ゾーンのKSKを使用して、子ゾーンのDNSKEYレコード(ZSK)とRRSIGレコードを検証し、子ゾーンのZSKの正当性を確認します。 子ゾーンのZSKを使用して、子ゾーンのAレコードとRRSIGレコードを検証し、子ゾーンのAレコードの正当性を確認します。 上記は1組の親子ゾーンに対しての検証フローになりますが、ルートゾーンからの検証も同様の仕組みで行われます。 ただし、ルートゾーンのKSK、ZSK、DSレコードは信頼できる前提となっています。 このDSレコードによる署名検証の連鎖こそがDNSSECの信頼チェーンの肝であり、DNSSECで一番面白いと思うポイントになります。 以上がDNSSECの概要となります。 (補足)DNSSECが確認できるサイト DNSSECが適用されているかどうかは、digコマンドでレコードを確認していくことでも可能ですが、 DNSViz がオススメです。 確認したい ドメイン 名を入力し、以下に示すAnalyzeタブにてAnalyzeボタンを押下します。 ※明示的にAnalyzeボタンを押下しない限り、情報が更新されないことに注意 処理が終わった後に、Continueボタンを押下すると、DNSSECの設定状況が図でわかりやすく表示されます。 AWS におけるDNSSECの実装方法 (Terraform) 前提 Route53( レジストラ としての AWS )で購入した ドメイン とその サブドメイン にDNSSECを設定します。 Route53の場合は、 ZSKをAWSが管理している ため、以降の手順でZSKに関する設定はありません。 コンソールでの設定方法は AWS公式ドキュメント に示されているため、今回はTerraformに絞っています。 Terraformの実装 小規模なのでlocalで構成します。基本設定は以下になります。 terraform { required_version = "~> 1.14.0" required_providers { aws = { version = "6.23.0" source = "hashicorp/aws" } } } provider "aws" { region = "ap-northeast-1" } provider "aws" { alias = "global" region = "us-east-1" } locals { domain = "ks-sample.com" subdomain = "subdomain.${local.domain}" } data "aws_caller_identity" "current" {} ホストゾーンの定義をします。Route53の購入 ドメイン に対しては、自動でホストゾーンが作成されているためdata sourceを使用して取得します。 また、ホストゾーンを作成するだけでは、親 ドメイン 側に サブドメイン の権威サーバの宛先情報(NSレコード)が存在せず サブドメイン の名前解決ができないため、明示的に親ホストゾーンに サブドメイン のNSレコードを追加します( サブドメイン 委譲)。 # Hosted zone data "aws_route53_zone" "registered_domain" { name = local.domain } resource "aws_route53_zone" "subdomain" { name = local.subdomain } resource "aws_route53_record" "subdomain-ns" { zone_id = data.aws_route53_zone.registered_domain.zone_id name = local.subdomain type = "NS" ttl = "30" records = aws_route53_zone.subdomain.name_servers } KMSカスタマー管理キーを定義します。 DNSSECで使用するカスタマー管理キー は、以下の4つの設定が必須となります。 バージニア 北部(us-east-1)で作成 署名用の非対称鍵: SIGN _VERIFY 鍵の形式: ECC _NIST_P256 内部的には署名 アルゴリズム ECDSA_SHA_256を使用。 RFC 8624 を参照すると、 RSA 系に比べて短い署名長かつより高い暗号強度を持つことからECDSA系が推奨されています。 Route53サービスがKMSキーにアクセスするための キーポリシー # KMS key resource "aws_kms_key" "kms_key_global" { provider = aws.global description = "Key for DNSSEC" key_usage = "SIGN_VERIFY" customer_master_key_spec = "ECC_NIST_P256" enable_key_rotation = false policy = jsonencode ( { Statement = [ { Action = [ "kms:DescribeKey" , "kms:GetPublicKey" , "kms:Sign" , ] , Effect = "Allow" Principal = { Service = "dnssec-route53.amazonaws.com" } Sid = "Allow Route 53 DNSSEC Service" , Resource = "*" Condition = { StringEquals = { "aws:SourceAccount" = data.aws_caller_identity.current.account_id } ArnLike = { "aws:SourceArn" = "arn:aws:route53:::hostedzone/*" } } } , { Action = "kms:CreateGrant" , Effect = "Allow" Principal = { Service = "dnssec-route53.amazonaws.com" } Sid = "Allow Route 53 DNSSEC Service to CreateGrant" , Resource = "*" Condition = { Bool = { "kms:GrantIsForAWSResource" = "true" } } } , { Action = "kms:*" Effect = "Allow" Principal = { AWS = "arn:aws:iam::$ { data.aws_caller_identity.current.account_id } :root" } Resource = "*" Sid = "Enable IAM User Permissions" } , ] Version = "2012-10-17" } ) } KSKの作成、DNSSECの有効化(内部的にDNSKEYレコードやRRSIGレコードの作成・署名設定を行う処理をトリガーするものと考えられます)を定義します。 DNSSECの有効化時にKSKが作成済みになっている必要があるため、 hosted_zone_id = aws_route53_key_signing_key.registered_domain.hosted_zone_id のように設定して暗黙的に依存関係を定義します。 # KSK : https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_key_signing_key resource "aws_route53_key_signing_key" "registered_domain" { provider = aws.global hosted_zone_id = data.aws_route53_zone.registered_domain.id key_management_service_arn = aws_kms_key.kms_key_global.arn name = "ksk-$ { replace (local.domain, "." , "-" ) } " } resource "aws_route53_key_signing_key" "subdomain" { provider = aws.global hosted_zone_id = aws_route53_zone.subdomain.id key_management_service_arn = aws_kms_key.kms_key_global.arn name = "ksk-$ { replace (local.subdomain, "." , "-" ) } " } # DNSSEC resource "aws_route53_hosted_zone_dnssec" "registered_domain" { hosted_zone_id = aws_route53_key_signing_key.registered_domain.hosted_zone_id } resource "aws_route53_hosted_zone_dnssec" "subdomain" { hosted_zone_id = aws_route53_key_signing_key.subdomain.hosted_zone_id } 最後にDSレコードの定義をします。 購入 ドメイン の場合は親 ドメイン が TLD となるため、専用の aws_route53domains_delegation_signer_record を使用してDSレコードの作成を行います。一方、 サブドメイン 側は親 ドメイン がRoute 53ホストゾーンの管理内のため、DSレコードを直接作成する形になります。 また、depends_on で定義している依存関係は、以下の状態を満たしたうえでDSレコードを作成するためのものです。 対象ホストゾーンで DNSSEC が有効化されていること NS レコードが作成され、 サブドメイン の名前解決が可能な状態になっていること 親ゾーンから順番に DNSSEC の信頼チェーンを繋げていく(DSレコードを作成する)こと # DS Record # Registered domain TLD専用:https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53domains_delegation_signer_record resource "aws_route53domains_delegation_signer_record" "registered_domain" { depends_on = [ aws_route53_hosted_zone_dnssec.registered_domain ] domain_name = local.domain signing_attributes { algorithm = aws_route53_key_signing_key.registered_domain.signing_algorithm_type flags = aws_route53_key_signing_key.registered_domain.flag public_key = aws_route53_key_signing_key.registered_domain.public_key } } # Subdomain resource "aws_route53_record" "subdomain-ds" { depends_on = [ aws_route53_hosted_zone_dnssec.subdomain, aws_route53domains_delegation_signer_record.registered_domain, aws_route53_record.subdomain-ns ] zone_id = data.aws_route53_zone.registered_domain.zone_id name = local.subdomain type = "DS" ttl = "30" records = [ aws_route53_key_signing_key.subdomain.ds_record ] } Applyの結果 terraform apply を実行すると、エラーなく数分で完了しました。 PS C:/path> terraform apply (中略) Plan: 9 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes (中略) Apply complete! Resources: 9 added, 0 changed, 0 destroyed. Apply直後にDNSVizを確認すると、正常にDNSSECが設定されていることが確認できます。(黄色のWARNマークに関しては、AAAAレコードに関する注意であり今回は関係ありません) Destroyの結果 terraform destroy を実行すると、同様にエラーなく数分で完了しました。 PS C:\path> terraform destroy (中略) Plan: 0 to add, 0 to change, 9 to destroy. Do you really want to destroy all resources? Terraform will destroy all your managed infrastructure, as shown above. There is no undo. Only 'yes' will be accepted to confirm. Enter a value: yes (中略) aws_route53_zone.subdomain: Destruction complete after 33s Destroy complete! Resources: 9 destroyed. destroy直後に ks-sample.com に対してDNSVizを確認すると、DNSSEC設定が削除されていることが確認できます。 NSEC3レコードは「ある名前やタイプのレコードが存在しない」ことを証明するための特殊なレコードで、今回は親ゾーン側でDSレコードが存在しないことを示しています。 おわりに DNSSECに関連するレコードだけを見ていると一見とても難しく感じますが、今回のように図に落としてみると、署名検証の流れがシンプルかつ美しく整理されていることが分かります。 また、実装において依存関係に迷う部分もありましたが、現在は AWS を使用することでDNSSECを簡単に設定できますので、セキュリティ要件にある方は是非参考にしていただければと思います。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @sakae.katsuto レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
こんにちは。コーポレート本部 サイバーセキュリティ推進部の耿です。 本記事は 電通総研 Advent Calendar 2025 4日目の記事です。 AWS ではSecurity Hub CSPMのセキュリティ基準を有効にすると、何もリソースを作成していなくても非準拠の検出結果が複数発生します。この記事では新しいリージョンを使い始める初期に、どのような設定を行うとSecurity Hub CSPMの検出結果になるべく対応できるかをまとめます。対象とするセキュリティ標準は一般的によく使われる AWS Foundational Security Best Practices (以下「FSBP基準」)です。 初期のSecurity Hub CSPMの検出結果に対応する理由 新しい AWS アカウント・リージョンが使えるようになるといきなり システム開発 を始めたくなりますが、その前にまずはConfigとSecurity Hub CSPMのFSBP基準を有効にし、検出結果に対応していきましょう。理由は2つあります。 設定が推奨される項目がある GuardDutyの有効化など、リージョン単位で設定すべき/しておいた方が良い項目を見逃さないようにしておきたいです。 今後作成するイン フラリ ソースに対する検出結果に気づきやすくする 何もリソースを作成していない状態でも、FSBP基準は20個前後の非準拠の検出結果を生成します。これをキレイにし、初期のセキュリティスコアを100に近づけると、今後作成するリソースに対する非準拠の検出結果に気づきやすくなります。非準拠の検出結果に気づきやすいと、検出結果の対応が進みやすくなり、結果としてセキュリティリスクが低減され、 システム開発 に好循環を生み出すことが期待できます。 AWS アカウントレベルですべき設定 新しい AWS アカウントについては、以下の設定をしておきましょう。この記事は以下の対応はされている前提で割愛します。 CloudTrailのマルチリージョンで有効化( CloudTrail.1 ) S3のアカウントレベルのブロックパブリックアクセスを設定( S3.1 ) それでは新しいリージョンでConfigとSecurity Hub CSPMのFSBP基準を有効にしたときに、検出されるセキュリティコン トロール と対応の考え方を見ていきましょう。 (組織や AWS アカウントの設定により、非準拠となる項目が異なる場合があります。また、2025/11の執筆時点の情報です。今後Security Hub CSPMのアップデートにより非準拠となるコン トロール が増える可能性があります。) 初期のSecurity Hub CSPMの検出結果に対応する理由 AWSアカウントレベルですべき設定 GuardDutyを有効にする EBS のデフォルト暗号化を有効にする EBSスナップショットのパブリック共有をブロックする SSM Automationのログ記録を有効にする SSMドキュメントのパブリック共有ブロックを有効にする Inspectorの各種機能を有効にする Macieを有効にする デフォルトVPCを削除する VPCブロックパブリックアクセスを設定する CloudTrail.5を抑制する IAM.6を抑制する 全リージョンに対してループさせる さいごに GuardDutyを有効にする 対応推奨度:必須レベル 対応できるコン トロール : GuardDuty.1 GuardDuty を有効にする必要があります GuardDuty.7 GuardDuty EKS ランタイムモニタリングを有効にする必要があります GuardDuty.11 GuardDuty Runtime Monitoring を有効にする必要があります GuardDuty.12 GuardDuty ECS Runtime Monitoring を有効にする必要があります GuardDuty.13 GuardDuty EC2 Runtime Monitoring を有効にする必要があります AWS アカウントへの脅威を検出するために必須のサービスです。全てのリージョンで必ず有効にしましょう。 GuardDutyには標準機能の他に、任意に有効化・無効化できる 保護プラン があります。該当するリソースがある場合は追加で利用料金がかかりますが、許容できる限り利用をお勧めします。現在はGuardDutyを有効にすると、デフォルトでRuntime Monitoring以外の保護プランも同時に有効になります。 GuardDuty標準機能および、Runtime Monitoringも含めた全ての保護プランを有効にする AWS CLI コマンドです:(CloudShellから実行可) aws guardduty create-detector --enable --finding-publishing-frequency FIFTEEN_MINUTES --features '[{"Name" : "RUNTIME_MONITORING", "Status" : "ENABLED", "AdditionalConfiguration": [{"Name" : "ECS_FARGATE_AGENT_MANAGEMENT", "Status" : "ENABLED"}, {"Name" : "EC2_AGENT_MANAGEMENT", "Status" : "ENABLED"}, {"Name" : "EKS_ADDON_MANAGEMENT", "Status" : "ENABLED"}]}]' 検出結果をS3やEventBridgeに送信する間隔もデフォルトの6時間から15分に変更しています。 Runtime Monitoringを有効にしない場合の AWS CLI コマンドは以下です: aws guardduty create-detector --enable --finding-publishing-frequency FIFTEEN_MINUTES EBS のデフォルト暗号化を有効にする 対応推奨度:やった方が良い 対応できるコン トロール : EC2.7 EBS のデフォルト暗号化を有効にすることをお勧めします そのリージョンで作成されるEBSボリュームをデフォルトで暗号化することができます。EBSボリュームを使うかどうかはシステムに依存しますが、とりあえず設定だけしておくと良いでしょう。 AWS CLI コマンドは以下です: aws ec2 enable-ebs-encryption-by-default EBSスナップショットのパブリック共有をブロックする (2025/12/8に追加されたコン トロール です) 対応推奨度:やった方が良い 対応できるコン トロール : EC2.182 Amazon EBS Snapshots should not be publicly accessible リージョンレベルの設定であり、そのリージョンのEBSスナップショットの意図しないパブリック公開を全てブロックできます。 AWS CLI コマンドは以下です: aws ec2 enable-snapshot-block-public-access --state block-all-sharing SSM Automationのログ記録を有効にする 対応推奨度:やった方が良い 対応できるコン トロール : SSM.6 SSM Automation では CloudWatch ログ記録が有効になっている必要があります SSM Automationを利用するかどうかはシステムに依存しますが、とりあえず設定だけしておくと良いでしょう。 AWS CLI コマンドは以下です: aws ssm update-service-setting --setting-id /ssm/automation/customer-script-log-destination --setting-value CloudWatch SSMドキュメントのパブリック共有ブロックを有効にする 対応推奨度:やった方が良い 対応できるコン トロール : SSM.7 SSM ドキュメントでは、パブリック共有ブロック設定を有効にする必要があります これもとりあえず設定しておいて損はありません。 AWS CLI コマンドは以下です: aws ssm update-service-setting --setting-id /ssm/documents/console/public-sharing-permission --setting-value Disable Inspectorの各種機能を有効にする 対応推奨度:やった方が良い 対応できるコン トロール : Inspector.1 Amazon Inspector EC2 スキャンを有効にする必要があります Inspector.2 Amazon Inspector ECR スキャンを有効にする必要があります Inspector.3 Amazon Inspector Lambda コードスキャンを有効にする必要があります Inspector.4 Amazon Inspector Lambda 標準スキャンを有効にする必要があります 利用しているソフトウェアパッケージや開発したコード上の 脆弱性 を検出するサービスです。特にLambda関数については数が多いと利用料金が高くなる可能性があるため、アカウントの使い方に応じて各種機能を利用するか検討してください。 EC2スキャン、ECRスキャン、Lambda標準・コードスキャンを全て有効にする AWS CLI コマンドは以下です: aws inspector2 enable --resource-types EC2 ECR LAMBDA LAMBDA_CODE ※Lambdaコードスキャンは 利用可能なリージョン がまだ少ないため、利用不可のリージョンでは LAMBDA_CODE 以外の機能を有効にします。 Macieを有効にする 対応推奨度:やった方が良い 対応できるコン トロール : Macie.1 Amazon Macie を有効にする必要があります S3 バケット やS3オブジェクトの数が多いと利用料金が高くなる可能性があるため、アカウントの使い方に応じて利用するか検討してください。 Macieを有効化する AWS CLI コマンドは以下です: aws macie2 enable-macie デフォルト VPC を削除する 対応推奨度:やった方が良い 対応できるコン トロール : EC2.2 VPC のデフォルトのセキュリティグループでは、インバウンドトラフィックまたはアウトバウンドトラフィックを許可しないようにすることをお勧めします EC2.6 すべての VPC で VPC フローログ記録を有効にすることをお勧めします EC2.10 Amazon EC2 サービス用に作成された VPC エンドポイントを使用するようにAmazon EC2 を設定することをお勧めします EC2.15 Amazon EC2 サブネットは、パブリック IP アドレスを自動的に割り当てないことをお勧めします EC2.55 VPCs は ECR API のインターフェイスエンドポイントで設定する必要があります EC2.56 VPCsは Docker Registry のインターフェイスエンドポイントで設定する必要があります EC2.57 VPCsは Systems Manager のインターフェイスエンドポイントで設定する必要があります デフォルト VPC にまつわる様々なコン トロール が非準拠になっているはずです。最近は VPC を使わないシステム構成もよくありますし、必要になったら VPC を作成すれば良いので、各リージョンのデフォルト VPC は削除しておくことをお勧めします。そうすることでこれらの非準拠の検出結果は全て消えてなくなります。 CLI で VPC を削除するにはIGWの削除、サブネットの削除と段階を踏んで行う必要があります。( https://dev.classmethod.jp/articles/delete-default-vpcs-by-cloudshell/ を参考にさせていただきました) AWS CLI コマンドは以下です: aws ec2 describe-vpcs --output text --query "Vpcs[?IsDefault].[VpcId]" | while read vpc; do aws ec2 describe-internet-gateways --output text --filters Name=attachment.vpc-id,Values=${vpc} \ --query "InternetGateways[].[InternetGatewayId]" \ | while read igw; do echo "# deleting igw: ${igw} in ${vpc}" aws ec2 detach-internet-gateway --internet-gateway-id ${igw} --vpc-id ${vpc} aws ec2 delete-internet-gateway --internet-gateway-id ${igw} done aws ec2 describe-subnets --output text --filters Name=vpc-id,Values=${vpc} \ --query "Subnets[].[SubnetId]" \ | while read subnet; do echo "# deleting subnet: ${subnet} in ${vpc}" aws ec2 delete-subnet --subnet-id ${subnet} done echo "# deleting vpc: ${vpc}" aws ec2 delete-vpc --vpc-id ${vpc} done VPC ブロックパブリックアクセスを設定する 対応推奨度:使い方による 対応できるコン トロール : EC2.172 EC2 VPC ブロックパブリックアクセス設定はインターネットゲートウェイトラフィックをブロックする必要があります VPC ブロックパブリックアクセスはややこしい機能です。設定する場合は仕組みをよく理解したうえで設定しましょう( このドキュメント などを参考に)。 VPC 利用の有無、利用有の場合の通信方向に応じて設定の可否を判断してください。 双方向モードのブロックを設定する場合の AWS CLI コマンドは以下です: aws ec2 modify-vpc-block-public-access-options --internet-gateway-block-mode block-bidirectional Ingress -Onlyモードのブロックを設定する場合の AWS CLI コマンドは以下です: aws ec2 modify-vpc-block-public-access-options --internet-gateway-block-mode block-ingress CloudTrail.5を抑制する 対応推奨度:使い方による 対応できるコン トロール : CloudTrail.5 CloudTrail 証跡は Amazon CloudWatch Logs と統合する必要があります 特定のオペレーションを監視する場合などは、CloudTrail証跡をCloudWatch Logsに連携すると設定しやすいです。 特にそのような要件がない場合は検出結果を抑制しておきましょう。 CloudTrail.5 を抑制する AWS CLI コマンドは以下です: aws securityhub get-findings --output json --filters '{"ComplianceSecurityControlId":[{"Value":"CloudTrail.5","Comparison":"EQUALS"}]}' \ | jq -c '.Findings[]' \ | while read -r finding; do id=$(echo ${finding} | jq -r '.Id') productArn=$(echo ${finding} | jq -r '.ProductArn') aws securityhub batch-update-findings --finding-identifiers Id=$id,ProductArn=$productArn --workflow '{"Status": "SUPPRESSED"}' done IAM.6を抑制する 対応推奨度:使い方による 対応できるコン トロール : IAM.6 ルートユーザーに対してハードウェア MFA を有効にする必要があります ルートユーザにMFAを設定するのは必須ですが、 ハードウェア MFAを使っていない場合はこのコン トロール が非準拠になります。 ハードウェア MFAでなくても良い場合は検出結果を抑制しましょう。 IAM.6 を抑制する AWS CLI コマンドは以下です: aws securityhub get-findings --output json --filters '{"ComplianceSecurityControlId":[{"Value":"IAM.6","Comparison":"EQUALS"}]}' \ | jq -c '.Findings[]' \ | while read -r finding; do id=$(echo ${finding} | jq -r '.Id') productArn=$(echo ${finding} | jq -r '.ProductArn') aws securityhub batch-update-findings --finding-identifiers Id=$id,ProductArn=$productArn --workflow '{"Status": "SUPPRESSED"}' done 全リージョンに対してループさせる 以上のコマンドを単一リージョンではなく、 AWS アカウント内で有効な全リージョンに対して一気に実行したい場合は、各 AWS CLI コマンドに --region オプションを付与してループさせれば良いです。 (サービスが対応していないリージョンがあればエラーになるかもしれません) aws ec2 describe-regions --output text --query "Regions[].[RegionName]" \ | while read region; do # 実行したいコマンドを --region ${region} オプションを付けて書く done さいごに システム開発 中にSecurity Hub CSPMの検出結果を効率的に対応していくために、 AWS アカウントやリージョンを使い始める初期段階でできる限り非準拠の検出結果をなくしていきましょう! 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 執筆: @kou.kinyo レビュー: @miyazawa.hibiki ( Shodo で執筆されました )
みなさん、こんにちは。XI イノベーション 本部エンジニアリングテクノロ ジー センターの宮原です。 アメリ カ、ラスベガスにて12/1(月)から始まった AWS re:Invent2025に参加しております。 現地時間の12/2(火)の8:00からのキーノートに先ほど参加し、キーノート終了後速報でこちらのテックブログを書いております! キーノート内での新サービス・機能の発表の中でいくつかピックアップし、サマリー形式でお伝えできればと思います! 所感 新サービス・機能の発表 Amazon Nova 2 Amazon Nova Forge Policy in AgentCore AgentCore Evaluations Kiro autonomous agent AWS Security Agent AWS DevOps Agent Database Saving Plan まとめ 所感 今回のキーノート2時間のうちの9割がAIについての内容でした。 例年のキーノートではコンピューティングやストレージ、データベースについての新サービス・機能の発表が多くある印象ですが今回は9割がAIに関連するものでありAIの躍動を感じております。 AI以外のリリースもあったのですが、そちらの発表に割かれた時間は2時間のキーノートのうち最後のわずか10分だけでした。。。 (タイマーが表示されて10分でその他のリリースを発表するぜ、となり会場が湧きました) キーノートの発表から AWS でもAI関連の開発や発表が最優先となっていることが伺えました。 新サービス・機能の発表 キーノートの中で発表のあった新サービス・機能の中でも個人的に注目度の高いものをピックアップしてお伝えできればと思います。 Amazon Nova 2 Amazon Bedrockで選択できる AWS モデルで有名な Amazon Novaの新しいバージョンの発表がありました。 Amazon Nova 2はコストと精度の観点でバランスがいいモデルとして紹介があり今回の Amazon Nova 2でも速度の点やワークロードに応じてモデルが選択可能であることを強調していました。 従来 Amazon NovaはLite、Proなどいくつかモデルの種類があり、 Amazon Nova 2でも複数の種類のモデルがあります。発表スライドの中から Amazon Nova 2でも以下のモデルがあることを確認しています。 Lite コスト、速度重視 Pro 複雑な推論、精度重視 Sonic Speach to Speachなどの用途 Omni マルチモーダルの入出力 新種のモデルとして Amazon Nova 2 Omni が発表されています。 リリースのドキュメント を確認したところこちらのモデルではテキスト、画像、動画、音声を受け取り、画像、テキストを出力可能なようです。 Amazon Nova 2 Omni を利用して音声や画像などのマルチモーダルの入力を受けとり即時で要約するような事例も紹介されていました。 また、マルチモーダルな入出力に対応するモデルは業界初であることも強調されていました。 Amazon Nova Forge Amazon Nova Forgeは企業独自のカスタムモデルを開発するためのモデルです。 Amazon Nova Forgeのベースのモデルを Amazon SageMakerなどでト レーニン グし独自のカスタムモデルを開発します。 ドメイン に特化した情報などモデルの知識ではカバーできない領域でRAGを利用することは広く広まっていますが、 Amazon Nova ForgeではRAGのアプローチとは別の方法(カスタムモデル)で課題を解決します。 RAGとの精度比較のスライドはなく、今後もRAGとカスタムモデルでどちらの方が精度が出るかの議論が続きそうです。 Policy in AgentCore Amazon Bedrock AgentCoreの機能としてPolicy in AgentCoreの発表がありました。 こちらは Amazon Bedrock Agent Coreの上で動作するAIエージェントを コンプライアンス 要件に基づいて制御するための機能になります。 多くのAIエージェントは動作の中で様々なToolを呼び出しますがこのToolを実行条件に応じて制御します。 制御ポリシーについてはAamazon Verified Permissionでも採用されているCederの形式で記述します。 Amazon Bedrock AgentCoreでToolは AWS Lambdaとして実装されることが多いですが、少なくとも AWS Lambdaの実行制御は可能であると感じました。 AgentCore Evaluations Amazon Bedrock AgentCoreの機能としてAgentCore Evaluationsの機能も発表されました。 こちらは Amazon Bedrock AgetCoreで動作するAIエージェントの評価を実施するための機能になります。 Amazon Bedrock Knowledge Baseでも似たような機能がありますが、同様にLLM as a judgeを利用しながら開発したAIエージェントの品質を評価します。 Kiro autonomous agent Kiroに関連する発表も後半にありました。キーノート会場にはエンジニアが多いということもありKiroに関連する発表も注目度が高いように感じました。 Kiroを利用することで仕様駆動開発が促進され生産性の向上が期待できるという謳い文句です。 仕様駆動開発を利用して生産性が最も向上するのは仕様を確定させた後でKiroに長時間コードを生成させる、さらにそれらを並列に実行させることであると話していました。 そのような長時間の生成に特化したものがKiro autonomous agentです。 AWS Security Agent Kiroに関連する発表の中で AWS Security Agentの発表もありました。 AWS の開発でもセキュリティの要件は最も重要視されるべき要件であるとの前置きがあり、 AWS Security Agentの発表がありました。 こちらの機能を利用することで生成したコードのセキュリティチェックを実行するようです。 実際にどのようにAIが利用されているかまでは発表の中では把握しきれませんでしたが、特定のセキュリティ要件を満たしているかどうかをチェックしてくれそうです。 AWS DevOps Agent こちらもKiroに関連する発表の中で発表がありました。 AWS DevOps Agentは本番環境でのインシデントに対して、 Amazon CloudWatchなどと連携し、エラーの原因を自律的に特定し修正するための機能です。 こちらを利用することでオンコールの際のアラート対応の負荷も軽減されそうです。 Database Saving Plan 2時間の発表の最後の10分の発表の中でも最後の発表がこちらのDatabase Saving Planでした。 EC2などSaving Plan同様に一定の利用をコミットを確定することでコストメリットを享受できるものです。 データベースは途中で利用をやめることも少ないため、Database Saving Planの恩恵は大きそうです。 まとめ キーノートで発表があった新サービス・機能の中から独断でピックアップして概要レベルでまとめてみました。 個人的にも利用したことがあるサービス、興味のあるサービスである、Bedrock、Bedrock AgentCore、Kiroの発表が多くワクワクするキーノートでした。 また、我々エンジニアもフロントエンド、バックエンド、インフラ・SREなどのロール関係なくAIをより活用しなくてはならないなと改ためて思いました。 引き続き現地でAIに関連する技術のキャッチアップをしてこようと思います!以上、現地からの速報でした! 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @miyahara.hikaru レビュー: @miyazaki.hirotoshi ( Shodo で執筆されました )
こんにちは、HCM事業部の中西です。POSITIVEというHRソリューションのUXデザイナーをしています。 この記事では、 Figma Makeの機能について検証した結果をお届けします。 この記事は、 電通総研Advent Calendar 2025 12月3日の投稿です 🎄 昨日は @エンタープライズ第一本部の宮澤響 さんの「 Amazon ECS操作時に「おや?」となった3つの事象 」 でした!ぜひご覧ください🥳 Figma Makeとは 背景・課題 目指したゴールは2点 検証内容 プロンプトでどのくらい精度が変わるのか検証 簡易的なプロンプト 生成画面 より詳細な情報を詰め込んだプロンプト 生成画面 コードの検証 考察 要件整理 / 情報アーキテクチャフェーズでの使いどころ ワイヤーフレームフェーズでの使いどころ 良いところと今後の課題 Pros Cons おわりに Figma Makeとは Figma Make は、 Figma 社が提供するAIデザイン生成ツールです。 テキストで指示(プロンプト)を入力すると、UIデザインや画面構成、 コンポーネント などを自動生成してくれます。 他のデザイン生成ツールと比較したときに特に優れていると感じた点は以下のとおり。 デザインシステムの公開ライブラリをデザインに反映できる 生成したデザインデータを Figma のフレームに還元できる この機能により、製品のエンハンスプロジェクトの デザイン ガイドライン に沿った形でAIがデザイン案を生成してくれて、デザインを変更したいところはデザイナーが手を加えて修正できる ようになります。 背景・課題 私たちのプロジェクトでは、現在下図のような流れでPM、エンジニア、デザイナーが協力してプロダクトを作り上げていきます。 要件整理と 情報アーキテクチャ のフェーズは担当範囲がグラデーションになっており、案件によって各メンバーが共創することもあれば、デザイナーがワイヤーから形にすることもあり、効率的なコラボレーションが課題となっていました。 また、要件整理や 情報アーキテクチャ 段階では、 画がないために具体的なイメージを共有しづらく、認識のズレが生じる こともありました。 Figma Makeではアイディアを即時に画面に起こしてくれるため、この機能を活用して要件整理から ワイヤーフレーム までの検証ができたら、専門性の違うメンバー間でのディスカッションの場にも役立つと思いました。 目指したゴールは2点 検討段階のアイディアを可視化し、UIの認識合わせをスピーディに行う(認識違いや制約・構造上できないを早めに把握) プロンプトだけで業務アプリの高精度なワイヤーを作り、ワイヤー制作における 工数 を削減する 検証内容 まず、プロンプトの質によって精度はどう変わるのかを実際に試してみました。 Figma 公式では、使用にあたり 8つのTips を提案しています。 要約:8つの重要な使い方 初回プロンプトに詳細を詰め込む 既存のデザインファイルを整理してから持ち込む 複雑なアプリケーションは小さなステップに分解して進める 自社/既存の コンポーネント を活用して一貫性を保つ “Point & Edit”機能で視覚的な微調整を行う コードタブを活用して視覚外の編集も行う(開発スキル不要でも扱える) リアルまたは疑似データを統合してプロトタイプのリアリティを高める Figma Make をハンドオフ支援ツールとして使う プロンプトでどのくらい精度が変わるのか検証 まずはプロンプトの詳細度によってどの程度精度に変化があるのか検証してみました。 はじめに、簡易的なプロンプトで試してみます。 Figma Makeにはデザインシステムのライブラリを読み込ませる機能もありますが、今回はUI コンポーネント の「shadcn/ui」を読み込ませました。 簡易的なプロンプト 生成画面 一見すると良さそうなUIが表示されましたが、よく見るとナビゲーションなどはなく、各カード コンポーネント に「開く」ボタンが配置され、 実際のアプリケーションとしてはまだ不完全な状態 です。一度生成されたUIに関してひとつひとつ指摘し修正を重ねるより、 最初のプロンプトでできるだけ詳細な要件を伝えておく方が、効率的に理想のUIを実現できる ことが分かります。 より詳細な情報を詰め込んだプロンプト 公式に記載されている情報や、 Figma Makeのブログなどを参考に詳細なプロンプトは以下の情報をまとめました。 ## プロジェクト概要 -従業員がさまざまな人事・ 労務 手続きをするためのWebアプリのUIデザインを作成します。 # プラットフォーム仕様 - Web(PC画面) # 目的と使用例 - 申請・通知・評価・組織情報・個人情報・誓約書・ 雇用契約 が一画面でアクセス - 従業員の“1点起点”としてのポータル設計 - 他社サービスとのシームレスな連携 - 入力の正確さに対する直感的な視覚フィードバック # 主要な機能の一覧 - 画面左側にサイドナビゲーション - 見出し「ダッシュボード」 - サイドナビゲーション内のカテゴリは2種類。「よく使うメニュー」と「すべてのメニュー」 - 画面中央上部によく使うアプリケーションをアイコン+カード型で表示 - 画面中央下部に会社からの通知を表示 # ヘッダー内の要素 - ロゴ(左上、24pxマージン) - ログインユーザーの会社名選択セレクトボックス - FAQページへの「?」アイコンを表示 ## サイドナビゲーションメニュー項目一覧 # 1.「よく使うメニュー」項目一覧 -勤怠管理 -申請 -給与明細 -経費精算 # 2.「すべてのメニュー」項目一覧 -勤怠管理 -通知 -申請 -年末調整 -給与明細 -経費精算 # トーク ン - カラー: theme.primary, theme.error - フォント: body-md, heading-lg # 技術仕様・制約 - レイアウトは垂直方向に中央寄せ - コンテナ幅720px - デザインはデザインシステム「Shadcn UI」を使用 # 期待する動作 - 「サイドナビゲーション」メニューをクリックすると アコーディオン が開き、サブメニューが表示される 生成画面 ナビゲーションメニューが追加され、会社からの通知欄では、通知内容からテキストリンクで詳細ページに遷移できる仕様になりました。ワイヤーとしては十分ですが、さらにデザインカンプの品質に近づけるため、プロンプトを追加してみます。 カーソルを変更したい箇所に合わせて、プロンプトを入力するだけで変更ができる仕様になっています。 ですが、カラーの変更にはHEXやバリアントの 命名 を渡す必要があり、 「これは Figma のデザインファイルでやったほうが早い」 というのが率直な感想です。 また、小さなことですがカーソルの入力フィールドは確定の意味で一度「Enter」を押すとプロンプトが送信されてしまい、もう一度最初からやり直しということが何度かありました。 コードの検証 これまでデザインカンプを「 CSS Variables」などの Figma プラグイン で生成したことがありましたが、一部の変数だけが :root { --... } に出力されず、値が欠落・空になる、またはVariablesの変数の参照先を取得できず、異なる値を返すため出力された色が異なる、という事象がありました。今回は 生成されたグローバル css が正しく出力できているか も確認しました。 Figma Makeではすべてのグローバル css が正しく出力されていました。 考察 今回 Figma Makeを実際に触ってみて、その可能性と実務での使いどころが見えてきました。 要件整理 / 情報アーキテクチャ フェーズでの使いどころ まだ固まっていないアイディアを可視化させ、必要な機能の抽出に活用できる と感じました。 実際にPMやエンジニアと、ユーザー行動のシナリオについてMakeを囲みながら議論を深めることで、プロダクトの方向性や優先順位を明確にすることができました。 ※余談ですが、こういうとき誰かが「やりましょう!」と声をかけると、みんな面白そうに集まってくれるのが、弊社のいいところだなと思います。 ワイヤーフレーム フェーズでの使いどころ 最初にしっかり情報を渡すことで、初期段階での画面構成の検討や、複数のレイアウトパターンを素早く比較したい場合に威力を発揮してくれます。 詳細プロンプトを毎回入力するのは大変なので、 トーク ンや技術仕様・制約などはテンプレート機能を活用するとさらに他メンバーも触りやすいと感じました! なにより、デザインデータに引き継げるのはデザイナーの作業にとって非常に時短になり助かります。 良いところと今後の課題 Pros アイディア出しに活用できる ワイヤーを爆速で作れる 非デザイナーでも使える Cons 品質を保つにはデザイナーの細かい調整が必要 おわりに Figma Make は「デザイン業務を効率化するツール」という印象が強かったのですが、実際に使ってみると、 他職種のメンバーとのコミュニケーションをスムーズにし、アイディア出しを活発にするための“共通の思考ツール”としても活用できると感じました。 今回は生成されたコードが開発環境でどの程度使えるか、という検証までには至りませんでしたが、デザイナーだけでなく、エンジニアも実際の開発フローに組み込めるのかといった点については、今後さらに以下の内容を検証していこうと思います。 電通 総研Advent Calendar 2025はまだまだ続きます! 明日の アドベントカレンダー は、 @Kinyo Kou さんの「 新しいAWSリージョンを使い始める初期のSecurity Hub CSPM検出結果に対応したい 」です!お楽しみに😆✨ 最後までお読みいただきありがとうございました! 電通 総研では仲間を募集しています✨興味を持っていただけた方は、ぜひ採用サイトをご覧ください! 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @nakanishi.yoko レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
はいどーもー! エンタープライズ 第一本部の宮澤響です! 本記事は 電通総研 Advent Calendar 2025 2日目の記事です! 記念すべき1日目である昨日の記事は、米田光佑さんの「 AWS Well-Architected のオートメーション(自動化)に触れてみる 」でした! IaCのコードを AWS Well-Architected Frameworkのベストプラクティスに照らして自動的に評価・診断できるツール「Well-Architected IaC Analyzer」の特徴や活用方法が分かりやすく解説されている記事ですので、ぜひご一読ください! ということで、本記事では、 AWS マネジメントコンソール上から Amazon Elastic Container Service(以下、ECS)を操作する際に「おや?」となった3つの事象をご紹介します! なお、本記事の情報は、2025年11月末時点のものとなりますので、ご承知おきください。 初回のECSクラスター作成時にエラー 事象 原因 解決方法 雑感 ECSタスクがプロビジョニングと停止を繰り返すもログが出力されていない 事象 原因 解決方法 雑感 ECSサービス作成画面でALBを新規作成するとエラー 事象 原因 解決方法 雑感 おわりに 初回のECS クラスタ ー作成時にエラー 事象 過去に一度もECS クラスタ ーを作成したことのない AWS アカウントでECS クラスタ ーの新規作成を実行した際、以下のようなエラーが発生しました。 クラスタ ー xxx の作成中にエラーが発生しました。 Resource handler returned message: "Invalid request provided: CreateCluster Invalid Request: Unable to assume the service linked role. Please verify that the ECS service linked role exists. (Service: AmazonECS; Status Code: 400; Error Code: InvalidParameterException; Request ID: xxx; Proxy: xxx)" (RequestToken: xxx, HandlerErrorCode: InvalidRequest) エラーメッセージを確認する限り、ECSサービスリンクロールを引き受けられていないようです。 しかし、ECSサービスリンクロールは、ECS クラスタ ー作成時に自動作成されるものです。[ 参考 ] 実際、今回も正しい設定値で自動作成されています。 原因 タイミングの問題でした。 ECS クラスタ ーを作成する際、裏ではECSサービスリンクロールを作成する処理やECS クラスタ ーを作成する処理などが並行して実行されます。 そのため、タイミングによってはECSサービスリンクロールの作成完了よりも先にECS クラスタ ーの作成処理が開始されてしまい、ECSサービスリンクロールが存在しないと判定されてしまうことがある、ということのようです。 解決方法 再実行すればOKです。 初回のエラーが発生した直後には既にECSサービスリンクロールが作成されているため、それ以降は特に問題なくECS クラスタ ーを作成できます。 雑感 私が新人研修用の AWS アカウントを16アカウント準備した際、16アカウント全てで上記のエラーに遭遇したため、かなり高い確率で発生するエラーなのではないかと考えられます。 ECSタスクがプロビジョニングと停止を繰り返すもログが出力されていない 事象 下図のように、ECSタスクがプロビジョニングと停止を繰り返すにもかかわらず、CloudWatch Logsにログが一切出力されていない、という事態が発生しました。 なお、デプロイ失敗のエラーとして画面に表示されたメッセージは以下のとおり「サーキットブレーカーが作動したよ」という内容だったため、サーキットブレーカーが止めてくれなければ、永遠にプロビジョニングと停止を繰り返していたと思われます。 miyazawa-test-service-xxx のデプロイ中にエラーが発生しました Resource handler returned message: "Error occurred during operation 'ECS Deployment Circuit Breaker was triggered'." (RequestToken: xxx, HandlerErrorCode: GeneralServiceException) 原因 ECSタスク定義を作成する際に、 awslogs-create-group : true という設定を削除していたためでした。 awslogs-create-group に true を設定すると、 awslogs-group で指定した名称のロググループが存在しない場合、ロググループを自動作成してくれます。[ 参考 ] 今回、私は、最低限の設定で検証したかったため、「削除」ボタンが表示されている(=必須ではない)項目は削除してしまおう、と安易に削除していました。 なお、ログは出力されなかったものの、 前回のステータス の部分にカーソルを重ねてみると、ヒントが隠されていました。 解決方法 以下のいずれかの方法で、無事にECSタスクが起動され、ログも出力されました。 awslogs-create-group : true を設定する awslogs-group の値と同名のロググループを事前に作成しておく 雑感 まずはログを確認する、という感覚で生きているため、そもそもログが出力されない本事象では、少し困惑しました。 AWS マネジメントコンソール上のどこにどのような情報が表示されるのかを把握しておくことの重要性を改めて実感しました。 ECSサービス作成画面でALBを新規作成するとエラー 事象 ALB+ECSの構成で各リソースを作成する場合、ALBやターゲットグループを先に作成してから、ECSサービスを作成するのが一般的です。 しかし、ECSサービス作成画面には、ALBやターゲットグループをその場で新規作成できる欄が存在します。 そのため、そこからの作成を実際に試してみたところ、想定どおりの疎通が確認できない、という事態が発生しました。 なお、構成の概要や設定値は以下のとおりです。 各種リソースの設定が想定どおりであれば、問題なく疎通できるものとします。 ALBはパブリックサブネットに配置 ECSタスクはプライベートサブネットに配置 ALBのSGでは、インターネットからのアクセスを許可 ECSタスクのSGでは、ALBのSGからのアクセスを許可 原因 ALBに対して、ECSタスクと同一のサブネット配置、同一のSGが設定されてしまうことが原因でした。 つまり、以下のような状態となっていました。 想定していた設定 実際の設定 サブネット パブリック プライベート SG ALB用 ECSタスク用 解決方法 前述のとおり、ALBやターゲットグループを先に作成してから、ECSサービスを作成するしかなさそうです。 雑感 改めて考えてみたら、確かに画面上にALBのサブネットやSGを設定できる項目がなかったんですよね。 他にも、ALBのヘルスチェックの成功コードなども設定できないようでした。 そのため、「ALBとECSタスクに同一のサブネット配置、同一のSGが設定され、ヘルスチェックの成功コードも200固定でOK」といった前提条件を満たす状況に限り、ECSサービス作成画面からのALB作成が有効なようです。 …そう多くはない状況な気はしますが。笑 おわりに 本記事では、 AWS マネジメントコンソール上からECSを操作する際に「おや?」となった3つの事象をご紹介しました。 昨日の記事がIaCに関する内容だったこともあり、イマドキ手動で環境構築すな!IaCで管理せい!というお声が聞こえてきそうですが、実際にIaCのコードを実装する前に、 AWS マネジメントコンソール上で手順や設定値を確認することはあると思います。 その際に、たまたま同じような事象に遭遇されましたら、本記事の内容を思い出していただけると幸いです。 さて、 電通 総研 Advent Calendar 2025 3日目となる明日の記事は、中西陽子さんの「【新機能】 Figma Makeの使いどころ」です! 2日連続で AWS 関連の記事でしたが、明日は心機一転、AIデザイン生成ツールに関する興味深い記事となります! お楽しみに! 最後までお読みいただき、本当にありがとうございました! 私たちは共に働いていただける仲間を募集しています! みなさまのご応募、お待ちしています! 株式会社電通総研 新卒採用サイト 株式会社電通総研 キャリア採用サイト 執筆: @miyazawa.hibiki レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
XI本部 クラウド イノベーション センター所属、2年目の米田です。 皆さんは、普段どのように自分たちの クラウド インフラ設計を評価されてますでしょうか。 AWS では Well-Architected Framework に基づき、設計の健全性やベストプ ラク ティスへの準拠状況を体系的にチェックすることが推奨されています。 そんな中で、Infrastructure as Code(IaC)を対象に自動解析を行える Well-Architected IaC Analyzer(以下 IaC Analyzer) というツールがあり、Well-Architected フレームワーク に基づいたインフラスト ラク チャの評価をより効率化できたので、共有したいと思います。 具体的に本記事では、IaC Analyzer を使った IaC テンプレートの解析やレビューのポイントを整理しつつ、その特徴や実践的な活用方法をわかりやすく紹介します。 これから IaCや クラウド のレビューに携わる方にとって、参考になる内容になれば幸いです。 そもそも AWS の Well‑Architected とは? アーキテクチャ評価ツール アーキテクチャ評価の自動化 IaC Analyzer の概要 セットアップ 使ってみる まとめ 参考 そもそも AWS の Well‑Architected とは? クラウド 設計を語るとき、「ただ動く」だけのインフラではなく、安全性・信頼性・効率性・コスト・持続可能性など、さまざまな観点をバランスよく満たす構造を目指す必要があります。 AWS が提唱する Well‑Architected フレームワーク (Well‑Architected Framework) は、そのための ガイドライン とチェックリストを提供する枠組みです。 公式ドキュメントによれば、Well‑Architected Framework は「 AWS でシステムを構築する際に行う設計判断の長所と短所を理解する」ためのもの。これを駆使することで、安全で信頼性が高く、かつコスト効率にも優れた クラウド 設計を実現できるようになる、とあります。 The AWS Well-Architected Framework helps you understand the pros and cons of decisions you make while building systems on AWS . By using the Framework you will learn architectural best practices for designing and operating reliable, secure, efficient, cost-effective, and sustainable systems in the cloud. ( AWS 公式ドキュメントより引用) Well‑Architected は、6つの「柱(Pillars)」を基本構成要素として定義しています。これらは設計・運用を評価するための主要な観点であり、それぞれに対応するベストプ ラク ティスがあります。 運用上の優秀性(Operational Excellence) 日常の運用、モニタリング、変更管理、継続的改善などを通じて、効率よく運用を最適化する。 セキュリティ(Security) アイデンティティ 管理、データ保護、アクセス制御、監査などでリスクを低減する。 信頼性(Reliability) 障害対策、フェイルオーバー、自動復旧などで、高可用性を確保する。 パフォーマンス効率(Performance Efficiency) リソース選定や アーキテクチャ 設計を通じて、性能を最適化する。 コスト最適化(Cost Optimization) 必要なコストを抑えつつ、無駄のない構成を実現する。 持続可能性(Sustainability) 環境負荷 を考慮した設計を行い、長期的な運用を支える。 この6つの柱を基にして アーキテクチャ を評価します。 アーキテクチャ 評価ツール AWS Well-Architected Framework を活用するうえで中心的な存在となるのが、 AWS マネジメントコンソールから利用できる Well-Architected Tool です。このツールを使うことで、 フレームワーク の各柱(Pillar)やレンズ(Lens)に基づいた設問に回答し、ワークロードの健全性を体系的に把握できます。 利用手順は非常に単純で、 AWS コンソールから「 AWS Well-Architected Tool」を開いたら、まずは ワークロード (評価対象となるシステムやアプリケーション)を定義します。そして、特定の ユースケース 向けに拡張された専門的なチェック項目のセット( レンズ )を選択します。このレンズは AWS 公式が用意しているコンテンツもありますが、独自のカスタムレンズを作成することも可能です。当然ですが AWS Well-Architected Framework レンズは AWS 公式から用意されているのでそのまま選択していただけます。最後に各柱(Pillar) ごとに複数の質問が提示されるので、「はい / いいえ / 該当なし」などで回答します。 回答結果から、 AWS が定義する High(Medium)-Risk Issue(高(中)リスク項目) が自動的に抽出されますので、その結果によりセキュリティ・運用・信頼性・コストなどの観点で、どこに課題が潜んでいるのかを可視化できます。そして必要に応じて課題に対する対策を協議する、というところまでが一般的な流れかと思います。 このWell-Architected Toolの利用により、セキュリティや可用性など、忘れがちな重要ポイントを漏らさずレビューすることができます。なによりも無料です! ただし、一度実施したことのある方はご存じかもしれませんが、このWell-Architected Toolを使用した評価は 多少時間がかかる作業 であり、質問に回答するために複数の設計書や アーキテクチャ 図、IaC(CloudFormation/Terraform など ) の記述コードを往復して確認しなければなりません。また質問数も多く、プロジェクト規模によっては 1 回のレビューに数時間かかることもあるかなと思います。 まさにここが、本記事で紹介する Well-Architected IaC Analyzer が補完するポイントです。 アーキテクチャ 評価の自動化 Well-Architected Tool が「設計レビューの枠組み」を提供する一方で、その評価にはどうしても人手による確認作業が多く、 工数 が膨らみがちです。そこで今回は、 AWS が公開した オープンソース の Well-Architected IaC Analyzer を利用してみます。具体的には、CloudFormation や Terraform などの Infrastructure as Code(IaC)を自動解析し、Well-Architected の観点でレビュー結果を生成してくれる ソリューションです。 IaC Analyzer の概要 IaC Analyzer は、 IaC テンプレートや アーキテクチャ 図、PDF などをアップロードすると、それらの内容を AI(厳密には、 Amazon Bedrock の LLM)で解析し、Well-Architected Framework に沿った改善点やリスクを自動抽出 してくれます。レビュー対象には以下が含まれます。 IaCコードファイル(CloudFormation、Terraform、 AWS CDK など) PDFファイル(システム説明資料、システム アーキテクチャ 図など) 上記に加えて、サポートドキュメント機能もあり、プロジェクトに関連する技術仕様書や API ドキュメントなどを.pdf .txt . png .jpg . jpeg 形式でアップロードすることで、さらにレビュー精度を上げることができるようです。こちらについては後ほど少し詳しく検証してみたいと思います。 以下が実際のアプリケーション画面になります。操作方法も個人的には直感的で分かりやすい UI になっていると思います。 セットアップ 実際にセットアップするにあたって、CDKを利用する方法もあるようですが、今回は最も簡単にCloudFormationより直接スタックを作成する方法で検証してみました。 GitHub リポジトリ (参考)よりCloudFormationのテンプレートファイルを yaml 形式でダウンロードすることができますので、CloudFormationコンソールよりテンプレートをアップロードし、簡単にスタックを作成できます。スタック作成後は、ECSをはじめとした複数の AWS リソースが作成されますので、確認してみてください。アプリケーション自体は OSS ですが、CloudFormationでいくつかの AWS リソースが立ち上がるのでその分のコストは発生する点に注意です。 私の立ち上げた環境は以下のとおりです。 作成先リージョンは北米リージョン(東京リージョンだとスタック作成に失敗した、、、) 一時的に利用する想定なので認証設定はなし 作成が成功すると2つのスタックが作成されておりました。 スタック作成後は、コンソールのoutputよりフロントのURLが取得できます。そちらにアクセスすることでアプリケーションを立ち上げることができます。 使ってみる 実際にIaC Analyzerを使用してIaCコードからWell-Architected フレームワーク に基づいて、 クラウド 設計の評価を実施してみます。 最初に対象となるファイルをアップロードします。ファイルのアップロードにはサイズ制限があり、感覚ですが大体5~10MBほどのファイルをアップロードすると、レビュー時間が長くなったり、そもそもファイルアップロードができなかったりするので注意が必要です。とはいえ、Zip形式でのファイルアップロードもサポートされているので、サイズの大きなIaC ファイルをアップロードする際には圧縮してサイズを小さくすることで対応できます。(ちなみにpdfファイルの場合は最大5ファイルの、各ファイルサイズ上限が4.5MBと明記されてました) 今回は検証用として以下のようなよく見る? アーキテクチャ 構成をIaC Analyzerにかけてみました。 ※ここでは実際のものより少し簡略化した アーキテクチャ 構成図を掲載しています。 以下は今回の検証用に設定したIaC Analyzerのパラメータ設定です。 柱:Security レンズ: AWS Well-Architected Framework 出力言語:日本語 サポートドキュメント:なし ワークロード:事前に用意したワークロードを設定(空白のままにしておけば新規に自動作成) 全ての設定ができたのでいざ実行、ところがいきなりエラーが発生。調べたところ原因はどうやら Amazon Bedrockを利用するにあたっての ユースケース の詳細を申請していないことにありました。冒頭でもお伝えしましたが、このIaC Analyzerは裏で Amazon BedrockのClaudeが動いており、 初回利用時には ユースケース の詳細を AWS やAnthropicに共有する必要がある そうです。 申請手順は簡単でBedrockのコンソールより送信フォームへ遷移できるので、フォームに必要な項目を入力して送信します(参考資料を参照)。 それでは申請しなおして改めてレビューを実行。今度はうまく評価され、分析結果とAIによるレポートが正常に表示されました。レポート内容は想像していた以上に詳細に記載されており、かなり参考になります。一方でレビューにはかなり時間がかかる模様、、、大体50KBのファイルの6つの柱の評価に20~30分ほど要しました。 結果はレポートとしてダウンロードすることも可能ですし、Well-Architected Tool タブより Well-Architected Toolに直接書き込むことも可能 なようです。画面からは現在の回答数やRisk数も確認できました(今回はセキュリティに絞ったのでその項目だけ回答が完了していることがわかります)。個人的にはこれが一番便利な機能だと思っており、これまで手動で行っていた評価作業が自動評価&自動入力されるため、質問項目と自身のIaCコード/設計書を往復して時間をかけて入力するという作業がかなり低減されました。 ただし、あくまでも AI による自動評価であるため、 最終的な確認や判断は人間が行う 必要があります。実際に出力された分析結果を見ると、High / Medium Riskと判定された数が想像以上に多く見られました。その理由の多くは、IaC だけでは判断できない背景情報が考慮されていないことにあります。 例えば、 Security Hub の有効化 や Inspector・ AWS Config の設定 などは IaCコード には含まれていないため、「実装していない」と判定されてしまうことがあるようです。こうした IaCコードからは読み取れない項目については、別途人の手で補完・修正する必要があります。 とはいえ、分析結果には「なぜ不適切と判断されたのか」の理由まで明示されているため、指摘内容を参考に修正作業を進めることで、従来よりもはるかに効率的にレビューを行うことができます。なにより、 コードから自動で読み取れる項目は IaC Analyzer が入力してくれる ので、レビューにかける 工数 は大幅に削減できます。 最後にせっかくなので、サポートドキュメントがあるとどの程度精度が変わるのか検証してみました。方法としては先ほどのパラメータ設定に加えて、サポートドキュメントに アーキテクチャ 構成図を貼り付けて再評価するというものです。 結果としては、Riskと判断された数が減少してました。先ほどのサポートドキュメントなしだったときと比較して、もう少しだけ実態にあった評価がなされたのかなと思います。 例えば、先ほどベストプ ラク ティスに適さないと指摘された項目も、今度は適していると判断されたようです。 とはいえまだRisk数としては多いように見えますし、 アーキテクチャ 図にあってもIaCコードにないから不適切と判断された項目もありました。やはりまだ人の手で最終確認する必要はありそうですね。 当然ですが、IaCコードに情報が含まれていればいるほど良い精度で評価してくれるようなので、関連するコードは全てIaC Analyzerに渡してあげた方がよさげです。 クラウド 設計に関連しそうな情報は全てZipにまとめてしまいましょう! まとめ 今回はWell-Architected フレームワーク の基本的な考え方と、評価を自動化するための簡単なツール(IaC Analyzer)について紹介しました。 これまで長時間かけて手作業で実施していたWell-Architected Toolを用いた クラウド アーキテクチャ 設計の評価が、IaC Analyzerの導入により効率的に評価できるようになりました。これからの本作業の負担が大きく軽減されることが期待できます。本記事ではSecurityを軸に紹介させていただきましたが、今後機会があれば他の柱での評価結果なども共有できればと思います。 ただ本記事でも触れましたが、自動的に評価してくれるとはいえ時間がかかってしまうのが少し懸念であり、レビューが完了したら通知されるような機能があればより使いやすいのかなと感じました。。。 またネットワークが不安定な環境では、レビュー結果の取得に失敗する可能性があるため、安定した環境設備も重要ですね。 ともあれ、ぜひ近年大きく進歩したAIの力に触れてみてください。 参考 https://docs.aws.amazon.com/ja_jp/wellarchitected/latest/framework/welcome.html https://github.com/aws-samples/well-architected-iac-analyzer https://repost.aws/ja/knowledge-center/bedrock-access-anthropic-model 執筆: @yoneda.kosuke レビュー: @miyazaki.hirotoshi ( Shodo で執筆されました )
はじめに こんにちは。今回の記事は以下の新卒1年目の2人による共同執筆となります。 クロス イノベーション 本部 エンジニアリングテクノロ ジー センター 大岡叡 HCM事業部 製品企画開発室 基盤開発グループ  伊藤真 幸 休日に私たち2人でBedrock勉強会を行いました。大岡がBedrock Flowsを、伊藤がナレッジベース、ガードレールをそれぞれ担当し、調査・検証した内容をお互いに共有しました。この記事ではその内容をお届けします。 想定読者は「Bedrockでモデル呼び出しの経験はあるが、各種機能についてはあまり知らない方」です。新人の システム開発 研修でもBedrockやVertex AIを活用するチームが多くありましたが、基本的なモデル呼び出しにとどまるケースがほとんどでした。この記事を通じて、Bedrockへの理解が深まるきっかけになれば幸いです。 はじめに ナレッジベース 概要 検証内容 気付き ガードレール 概要 検証内容 気付き Bedrock Flows 概要 検証内容 気づき まとめ ナレッジベース 概要 ナレッジベースとは、 企業独自の情報(社内文書やFAQ等)を基にした回答の生成(RAG)の実装を簡素化 する、 Amazon Bedrockの機能です。 以下がナレッジベースのイメージ図になります。 AWS公式ブログ より引用 ナレッジベースは以下3つの項目を最低限設定することで作成できます。 S3やRedshift等にデータ(.pdf、. csv 等)を配置する データを生成AIが利用しやすい形(ベクトルデータ)に変換するための埋め込みモデルを選択 ベクトルデータを保存するためのベクトルデータベースを選択 今回初めてS3を触ったような AWS 初学者の私でも、ナレッジベースを利用することでRAGを簡単に実装 することができました。 検証内容 検証として、データベースに登録されている社員情報(テストデータ)をAIモデルとの対話形式で簡単に検索できるナレッジベースを作成し、 AWS 上での動作テストまで実施しました。 【ナレッジベースの作成手順】 社員情報のファイルを csv 形式で作成し、S3の汎用 バケット にアップロード 社員情報の例) 項目 値 社員番号 E001 名前 山田太郎 部署 営業部 役職 部長 年次 15 所属拠点 東京本社 メールアドレス yamada.taro@ example.com 電話番号 03-1234-5678 住所 東京都 千代田区 丸の内1-1-1 雇用区分 正社員 在籍ステータス 在籍中 上長社員番号 EX001 スキル 営業戦略・顧客管理・プレゼンテーション 情報区分 一般 閲覧レベル レベル3 入社日 2010-04-01 クレジットカード番号 4111111111111111 有効期限 2026-12 備考 優秀な営業成績を持つベテラン社員 Amazon Bedrockのナレッジベースから「作成」を押下し、ベクトルストアを含むナレッジベースを選択 データソースにS3を使用 S3の URI に、1.で配置したデータの URI を設定 埋め込みモデルにTitan Text Embeddings V2を使用 ベクトルストアに Amazon OpenSearch Serverlessを使用 上記以外はデフォルト設定で、ナレッジベースを作成 作成したナレッジベースを選択し、データソースを同期 以上で、ナレッジベースの作成が完了しました。 ここから、ナレッジベースのテストを行っていきます。 今回の検証では、生成AIモデルは Amazon Nova Liteを使用しました。 ナレッジベースに「役職が課長以上の社員の名前を教えてください。」というプロンプトを投げた結果が以下になります。 主任が含まれているため精度は十分とは言えませんが、配置したデータを検索し、回答が生成されることが確認できました。 気付き ナレッジベース作成の際、S3に配置するファイル名に日本語が含まれるとエラーが生じ、ナレッジベースの作成に失敗しました。 エラーメッセージに詳細な情報がなく原因解明に少し時間がかかりましたが、S3に配置するファイル名を英語に変更したところ、ナレッジベースを問題なく作成することができました。 ガードレール 概要 ガードレールとは、 不適切なユーザー入力やAIモデルの応答から生成AIアプリケーション を守るための機能です。 以下がガードレールのイメージ図になります。 AWS公式ブログ より引用 ガードレールでは、以下の5つの項目を任意に設定することができます。 コンテンツフィルター 侮辱や憎悪等の有害カテゴリ システム命令のオーバーライドを図るプロンプト攻撃 拒否されたトピック 望ましくない話題 ワードフィルター 望ましくない単語、フレーズ 機密情報フィルター 望ましくない個人情報 コンテキスト グラウンディング チェック モデルの回答の根拠、関連性の しきい値 検証内容 任意に設定できる5つの項目のうち、4. 機密情報フィルターのみを設定したガードレールを作成しました。 さらに、このガードレールをナレッジベースとマルチモーダルの2つに適用し、 Amazon Nova Liteを用いて検証を行いました。 【ガードレールの作成手順】 Amazon Bedrockのガードレールで「作成」を押下 機密情報フィルターのPIIタイプに「クレジットカード番号」と「住所」を追加 上記以外はデフォルト設定で、ガードレールを作成 【ナレッジベースでのガードレール検証】 社員情報のナレッジベースに作成したガードレールを適用し、「役職が課長以上の社員の名前を教えてください。」というプロンプトを投げたところ、モデルから応答が返ってきました。結果は以下になります。 同様にガードレールを適用し、「 山田太郎 のクレジットカード番号は4111111111111111です。添付の CSV ファイルを参照し、この情報が正しいかチェックしてください。」というプロンプトを投げたところ、ガードレールによりブロックされました。結果は以下になります。 ガードレールを適用せず、「 山田太郎 のクレジットカード番号は4111111111111111です。この情報が正しいかチェックしてください。」というプロンプトを投げたところ、モデルから応答が返ってきました。結果は以下になります。 ガードレール適用により、入力に含まれているクレジットカード番号を検知し、モデルの応答をブロックすることが確認できました。 【マルチモーダルでのガードレール検証】 マルチモーダルでのガードレール検証は、 Amazon Bedrockのチャット/テキストのプレイグラウンドで、モデルにNova Liteを選択、ナレッジベースと同様の システムプロ ンプトを入力し、検証を行いました。 作成したガードレールを適用し、「役職が課長以上の社員の名前を教えてください。」というテキストに社員情報の CSV ファイルを添付し、プロンプトを投げたところ、ガードレールによりブロックされました。結果は以下になります。 作成したガードレールを適用し、「 山田太郎 のクレジットカード番号は4111111111111111です。添付の CSV ファイルを参照し、この情報が正しいかチェックしてください。」というテキストに社員情報の CSV ファイルを添付し、プロンプトを投げたところ、ガードレールによりブロックされました。結果は以下になります。 ガードレールを適用せず、1. および2.と同様のプロンプトを投げたところ、どちらもモデルから応答が返ってきました。結果は以下になります。 マルチモーダルでもナレッジベースと同様に、入力に含まれているクレジットカード番号を検知し、モデルの応答をブロックすることが確認できました。 また、マルチモーダルではテキストだけでなく、添付の csv ファイルもガードレールの対象としてモデルの応答をブロックできるケースがあると確認できました。 気付き 今回は詳細を省いていますが、マルチモーダルのガードレール検証をClaude 3.5 Sonnetで実施したところ、Nova Liteとは違う結果になりました。Nova Liteでは「役職が課長以上の社員の名前を教えてください。」というプロンプトに対してモデルからの応答がブロックされましたが、Claude 3.5 Sonnetでは応答がブロックされませんでした。 AIモデルによって添付ファイルの展開の仕方が違うなどの原因が考えられるため、今後さらに調査・検証をしていきたいと思います。 Bedrock Flows 概要 Bedrock Flowsとは、 ローコードでワークフローを構築できるツール です。類似サービスで言うと、Difyなどが挙げられます。 Bedrock Flowsについて AWS 公式サイトでは以下のように説明されています。 Amazon Bedrock Flows では、ノードを接続して生成 AI ワークフローを構築できます。各ノードは、 Amazon Bedrock または関連リソースを呼び出すフローのステップに対応します。ノードへの入力とノードからの出力を定義するには、式を使用して入力の解釈方法を指定します。 ( AWS公式サイト より引用) どのように構築できるかというと、以下のようにノードを線でつないでワークフローを構築できます。 執筆時点(2025/11)で利用できるノードは以下のとおりです。 【フローロジックを制御するノード】 ノードタイプ 概要 Flow Input フローの開始点。InvokeFlowリクエストからデータを受け取る Flow Output フローの終了点。結果を返す Condition 条件に応じて処理を分岐 Iterator 配列の各要素を順次処理 Collector Iteratorの結果を配列として収集 DoWhile 条件が満たされるまでループ処理を実行 【フロー内のデータを処理するノード】 ノードタイプ 概要 Prompt 定義されたプロンプトでモデルを呼び出しレスポンスを生成 Agent エージェントを呼び出してタスクを実行 Knowledge Base ナレッジベースからデータを取得 S3 Storage S3 バケット にデータを保存 S3 Retrieval S3 バケット からデータを取得 Lambda Function Lambda関数を呼び出してカスタムロジックを実行 Inline Code フロー内で直接コードを実行 Lex Lexボットで発話を処理し インテント を識別 検証内容 Bedrock Flowsの検証として、カスタマーサポート回答システムを実装しました。その概要と動作結果を報告します。 本検証では以下のようなフローを実装しました。ユーザーの問い合わせに対して問い合わせカテゴリーを識別し、ナレッジベースを呼び出してS3にあるドキュメントから回答に役立ちそうな情報を取得し、最後にナレッジベースの出力とユーザーの問い合わせ内容を組み合わせて、適切な回答を出力する、これがワークフローの全体図です。 続いて、ワークフローのノードごとの処理について以下で説明します。 InputNode ノードタイプ:Flow Input 役割:顧客の問い合わせを受ける 出力:問い合わせテキスト(String) QuestionClassifierNode ノードタイプ:Prompt 役割:問い合わせのカテゴリーを識別する モデル: Amazon Nova Pro 入力:問い合わせテキスト(String) 出力:問い合わせカテゴリー("technical", "billing", "general" のいずれか) プロンプト: あなたは顧客からの問い合わせを分類する専門家です。以下の問い合わせ内容を分析し、最も適切なカテゴリを1つ選択してください。 問い合わせ内容: {{inquiry}} 【カテゴリの判定基準】 **technical** - 技術的な問題やシステムの使い方: - ログイン、パスワード、認証に関する問題 - アプリケーションのインストール、設定、アップデート - エラーコード、エラーメッセージ - システム要件、動作環境 - API、データバックアップ、セキュリティ設定 - 動作が遅い、フリーズする等のパフォーマンス問題 - 機能の使い方、操作方法 **billing** - 料金・請求・支払いに関する問題: - 請求、支払い、決済、料金 - プラン変更、アップグレード、ダウングレード - 領収書、請求書の発行 - 返金、キャンセル、無料トライアル - クレジットカード情報の更新 - 請求サイクル、支払い方法 **general** - サービス全般やアカウント管理: - サービスの概要、機能説明 - アカウント登録、初期設定 - サポート窓口、営業時間の問い合わせ - プライバシーポリシー、利用規約 - 対応言語、モバイルアプリ - 解約、アカウント削除 - その他、上記に該当しない一般的な質問 【回答形式】 以下のいずれか1つのみを出力してください(説明や追加テキストは不要): - technical - billing - general CategoryCondition ノードタイプ:Condition 役割:問い合わせのカテゴリーから移動するナレッジベースを決定する 入力:問い合わせカテゴリー("technical", "billing", "general" のいずれか) 条件: カテゴリーが"technical"ならTechnicalKnowledgeBaseノードに移動 カテゴリーが"billing"ならBillingKnowledgeBaseノードに移動 その他はGeneralKnowledgeBaseノードに移動 Knowledge Baseノード(3つ - 条件分岐で1つのみ実行) TechnicalKnowledgeBase ノードタイプ:KnowledgeBase 役割:問い合わせの回答に必要なS3に配置されている技術FAQファイルの情報を検索する 入力:問い合わせテキスト(String) 出力:ナレッジベースの検索結果(String) BillingKnowledgeBase ノードタイプ:KnowledgeBase 役割:問い合わせの回答に必要なS3に配置されている請求FAQファイルの情報を検索する 入力:問い合わせテキスト(String) 出力:ナレッジベースの検索結果(String) GeneralKnowledgeBase ノードタイプ:KnowledgeBase 役割:問い合わせの回答に必要なS3に配置されている一般FAQファイルの情報を検索する 入力:問い合わせテキスト(String) 出力:ナレッジベースの検索結果(String) ResponseFormatterノード(3つ - 各KnowledgeBase専用) ノードタイプ:Prompt 役割:問い合わせ内容とナレッジベースの検索結果から最終的な回答を生成する モデル: Amazon Nova Pro 入力: 問い合わせテキスト(String) ナレッジベースの検索結果(String) 出力:最終的な回答(String) プロンプト(カテゴリーが"technical"の場合): あなたはカスタマーサポート担当者です。お客様からの技術的な問い合わせに対して、技術サポートナレッジベースから検索結果を取得しました。 この検索結果を基に、お客様に分かりやすく丁寧な回答を作成してください。 お客様の問い合わせ: {{inquiry}} ナレッジベースの検索結果: {{kb_result}} 【回答作成のガイドライン】 - 段階的な手順を明確に説明 - 検索結果に含まれる情報を正確に伝える - 手順がある場合は番号付きで提示 - 検索結果がない場合は、サポート窓口への案内を含める 丁寧で分かりやすい回答を日本語で作成してください: OutputNode (3つ - 各パス専用) ノードタイプ:Flow Output 入力:最終的な回答(String) このフローをマネジメントコンソールでテストしました。その結果を以下に示します。詳細は省きますが、適切に回答をカテゴリー分類してナレッジベースから情報を取得し、回答を生成できることを確認しました。( エイリアス を作成することでクライアントアプリケーションから呼び出すことも可能ですが、今回はそこまでやっていません。) 気づき terraform apply は通るが、マネジメントコンソールでフローのテストをするとエラーが発生するケースがあること (前提として、今回はTerraformでフローを実装しました。) 例えば、以下のような仕様に反する設定があっても terraform apply は通り、マネジメントコンソールでテストするとエラーが発生します。 Prompt ノードの入力に複数ノードの出力を接続 Condition ノードに「else」に相当する条件(default条件)が設定されていない 今後、TerraformでBedrock Flowsを実装する時はこの点に注意しようと思いました。 AWS Provider の GitHub リポジトリ で Bedrock Flows の実装を確認した結果、フロー作成・更新時には CreateFlow 、 GetFlow 、 UpdateFlow の API を呼び出す仕様であることが分かりました。よって、これらの API ではフローが仕様に沿っていなくてもエラーを返さないことがあると今回の検証で分かりました。 まとめ 二人でBedrockの機能について調査・検証した内容をご紹介しました。 この記事の執筆を通じて、ナレッジベース、ガードレール、Bedrock Flowsを実際に使ってみて理解を深めることができました。 ここまでお読みいただきありがとうございました。 皆さんのBedrockへの理解が深まるきっかけになれば幸いです。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @ooka.toru レビュー: @miyazawa.hibiki ( Shodo で執筆されました )
こんにちは、 電通 総研 コーポレート本部 サイバーセキュリティ推進部の櫻井です。 本記事ではISC2 CCSP試験を紹介します。 なお、本記事でご紹介する資格の情報は2025年7月時点のものとなります。 ISC2 CCSP試験とは? CCSPは正式名称Certified Cloud Security Professionalであり、ISC2(アイ エス シーツー)が認定している クラウド サービスを安全に利用するために必要な知識を体系化した資格となります。 クラウド 上でのインフラ設計だけでなく クラウド がどのように構成されているのかや クラウド 上のアプリケーション設計に関する要素も含まれていますので、一般的な クラウド 関連の試験とは要素が異なります。 ※1 CCSP®とは 試験向けに利用したコンテンツや学習期間 筆者のキャリア オンプレ& クラウド 、ネットワーク&セキュリティ等いろいろな分野に関わってきたエンジニアです。担務領域に関しては特にこだわりなくなんとなく興味を持った資格は取得してます。(※ My credly) 利用したコンテンツ CCSPは2015年に提供開始(※2)していますが、同じくISC2が提供している CISSP 向けのコンテンツと比べると全体的に量は少ないです。 筆者が利用したものは以下となります。 市販の書籍として以下の二つが提供されており、両方とも利用しました。どちらも数少ない日本語で提供されているドキュメントですので、利用することをお勧めします。ただし、公式問題集については問題を解く観点や視点が重要であり、全く同じ問題は出題されないと考えた方が良いです。 CCSP CBK 公式ガイドブック(※3) 日本語ドキュメントとしてよく整理されていますが、かなりのボリュームがあるので辞書代わりとして活用しました。 CCSP 公式問題集(※4) 一通り解いてみることをお勧めします。 Udemyのコンテンツでは こちら のコンテンツを翻訳で利用しましたが、比較的に高額なのでセールのタイミングで購入するのがお勧めです。Udemy上でも英語のものであれば、それなりに数が存在します。 主に日本語翻訳後の教材を利用しましたが、英語版の原文で学習することが理想的だと思います。 時間に余裕がある方はISC2サイト内の学習コンテンツや市販されている「ISC2 CCSP Certified Cloud Security Professional Official Study Guide」をセルフ翻訳やAI翻訳を活用してじっくり学習しましょう。 ※2 ISC2の体制と沿革 ※3 CCSP CBK 公式ガイドブック ※4 CCSP 公式問題集 学習期間 期間は2か月、50時間程度の学習で試験に臨みました。 筆者の場合はバックグランドとなるインフラ、 クラウド 、ガバナンスといった学習を省いていますので、ISC2の出題方式に関する理解と既存知識とのギャップを埋めるために要した時間となります。 CCSP ドメイン 別の要素技術 CCSPの範囲は クラウド 以外の領域も含むためそれなりの広さがあります。ただし、 ドメイン に関しては一般的な技術、管理領域との対応が取れており、項目別に何を学習すればよいかはわかりやすいと思います。 筆者視点ではありますが、一般的な クラウド エンジニア視点で比較的難易度が高いのは ドメイン 3と ドメイン 4 と考えています。また、 ドメイン 6 は一般的な開発者、設計者からは遠い分野ですのでかなりの方が初めて触れるコンテンツとなる可能性が高いです。 ドメイン 3は クラウド プラットフォームの構成要素について理解する必要があります。すなわち、 クラウド を構成しているオンプレミスの機器、物理インフラ、仮想化レイヤ、ゲストOSレイヤすべての理解が必要です。 ドメイン 4は クラウド アプリケーションは クラウド 上で稼働させるアプリケーションを主題としていますが、従来のアプリケーションの開発手法やテスト技術に関する理解が必要です。 ドメイン 6で出題される法律に関してはグローバルもしくは米国の法律となるために日本国内の法律とのギャップを埋める必要が生じます。 総じて既に クラウド ベンダー資格を取得している方が問題をみると、かなりの割合の問題に違和感を感じるかもしれません。違和感を感じた方は、まずはITインフラとは何か?開発・設計とは何か?と システム開発 に関する基礎的な学習を行うことをお勧めします。 筆者の感覚ではCCSPは各領域の積み上げが必要な認定試験であり、 クラウド とは何で構成されているかを理解したうえで クラウド の安全な利用法と クラウド セキュリティの実装方法に関する知識を問う試験だと思います。 (※5、※6) # ドメイン 名 概略 (筆者のまとめ) 1 クラウド の概念、 アーキテクチャ 、設計 クラウド の概念、設計原則 2 クラウド データセキュリティ データセキュリティの概要と要素技術(暗号化等)、情報保護 3 クラウド プラットフォーム & インフラセキュリティ クラウド の構成要素、オンプレデータセンターを含む物理および理でのセキュリティコン トロール 4 クラウド アプリケーション セキュリティ アプリケーションの開発、設計手法、およびSDLC 5 クラウド オペレーション クラウド の運用、サプライヤ管理 6 クラウド ガバナンス - 法律、リスク、 コンプライアンス クラウド の法的要件、データ フォレンジック や監査 ※5 CCSP CBK 6ドメイン概要 ※6 CCSP ドメインガイドブック 試験自体の個人所感(試験予約、試験当日の動き、時間配分と感想) 試験予約 筆者はISC2の試験は初めてでしたのでISC2サイトのメンバーページのアカウント登録から始める必要がありました。(アカウント登録だけなら無料) アカウント登録については氏名、メールアドレス等の基本情報を入力で問題ありません。特に詰まるポイントはないと思います。 (注意)住所については合格後に認定証が届くため、ちゃんと入力しましょう。(※7)筆者の場合は米国からの配送となっていました。認定証と一緒にピンバッジも届きます。 その上でCCSP試験の予約を行います。 ISC2サイトでCCSPの受験チケットを購入した後、ピアソンVueのサイトで予約を行いますが、従来のCBT方式の試験とは異なり、テストセンタが PPC (Pearson Professional Centers ※8)に限定されています。主に関東、関西以外に在住の方はスケジュールに注意が必要です。 予約可能な試験枠は確認できる限りは午前(08:00)・午後(14:00)の2枠となっており、私の都合の良い日程が午前の枠だけでしたので午前の枠で申し込みを行いました。 ※7 英語での住所の書き方と注意点! ※8 ピアソン・プロフェッショナル・センター 試験当日の動き 試験日は7月上旬、8:00開始の試験でしたのでいつもよりかなり早起きをしました。新宿会場の最寄り駅は 新宿駅 ではありませんので極端に込み合うことはありませんが、早めに会場入りすることをお勧めします。 時間配分と感想 計125問を解き終えて、15分程度を残して終了しました。 以下は筆者の感想です。 事前に公式問題集等でかなりの分量を解きましたが、傾向としては似通った問題はありつつも、全く同じ問題は出題されませんでした。 事前のイメージ通り、 クラウド だけやってきた方には難しく、インフラ・アプリを含め各レイヤの技術を理解できている方は比較的楽かなと感じました。 試験は180分で125問の問題を解きます。注意する点は後から見直しを行うことができませんので、全体の時間配分に注意です。 日本語試験を選択しましたが、英字版の問題文も併せて表示されます。筆者が見た問題の中では日本語翻訳後の表現に困る問題はありませんでしたが、試験中に困った場合には英字版を確認しましょう。 (注意)2025年10月1日より、Computerized Adaptive Testing(CAT)形式の試験がCCSPにも導入されており、筆者が受験した時点と変わっておりますのでご確認ください。 Computerized Adaptive Testing(CAT)試験形式更新のお知らせ – CC、SSCP、CCSP CBT試験合格からISC2メンバー登録に至るまでのフロー概略 登録 CCSPを含むISC2試験の合格後は認定をActivateするためISC2 正規メンバーへの登録を行う必要があります。 試験を受けたのが7月上旬、筆者のcredly上でのCCSP Activate Dateとかなりのずれがあります。このように初回の正規メンバー登録については数か月を要することもありますので、早めに登録フローを実施することを推奨します。 正規メンバー登録しないとcredly上もActivateされません。 登録に必要な情報 登録作業はかなりの準備(※9)が必要です。ざっと登録に必要な情報をまとめてみました。 登録に必要なメールについては合格後にISC2から送付されてきます。直接メール内のリンクを開く感じです。メンバーページへログインしてから確認します。 まず、認定要件(※10)の条件をクリアするための情報を準備する必要があります。 「ITに関する業務に従事した経験が5年以上あること」については筆者の場合は 電通 総研在籍期間が約2年ですので5年の期間規定を満たすために前職の経歴を分けて記載しました。同一企業のみに在籍している方はこの点は楽かなと思います。 「CCSPの6 ドメイン のいずれかに関する業務が1年以上あること」ですのでそれを満たすように経歴(Job History )を入力する必要があります。 上司(supervisor)の連絡先も入力する必要がありますが、個人の連絡先でなくても大丈夫のようです。筆者は前職のsupervisorを アサイ ンできなかったため、ISC2担当者に確認を取り、在籍確認が取れる人事部を連絡先としました。必要な方はISC2担当者に確認をしましょう。 登録申請にあたってはRequest Endorsementでendorser(すなわち既存のISC2 正規メンバー)のID入力求められますが、知り合いがいないとNGではないようです。その場合Job History を保証するための エビデンス や連絡に関して確認される模様です。幸運にも筆者は同部署に複数名のISC2メンバーが在籍していましたのでendorserを依頼しました。 上記までをすべてそろえたうえで、申請を実施します。 筆者の場合は審査終了まで1か月程度要し、完了のメールが届いた段階で年会費(AMF: Annual Maintenance Fees)135米ドルの支払いを行いました。 ※9 認定手続き ※10 認定要件 最後に 読了していただきありがとうございました。ベンダー ニュートラ ルな資格としては有名なCCSPですが、3大ベンダー( AWS 、 Microsoft Azure、 Google Cloud)の資格とは求められる知識が異なるため、各 ドメイン の対策を行うことが必要です。CCSPへの学習を通して、データセンターのインフラや クラウド ガバナンスに興味を持っていただけるエンジニアが増えることを期待しています。 執筆: @sakurai.ryo レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました ) 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト
こんにちは!クロス イノベーション 本部 AIトランスフォーメーションセンターの村本です! 普段は 電通 総研で自社開発をしている生成AIプロダクト「 Know Narrator 」の開発に携わっております。今回は、私たちKnow Narrator開発チームが、普段どのように開発作業に取り掛かっているか紹介します! Know Narratorの開発メンバーによる開発関連コラムは以下にもありますので、合わせてご覧ください。 Vibe Coding(バイブコーディング)会を開催しました | AITC | AI TRANSFORMATION CENTER GitHub Copilot Coding Agentをプロダクト開発で使ってみて | AITC | AI TRANSFORMATION CENTER AITC働き方紹介 vol1 AIプロダクト開発・中堅 | AITC | AI TRANSFORMATION CENTER 株式会社 電通総研 新卒採用サイト Teams開発部屋とは? タイトルにある「Teams開発部屋」とは、単純にTeamsで作成できる会議ルームのことです。チャンネルに紐づける形で、平日の作業中開きっぱなしの会議ルームを作っています。この会議ルームのことを「開発部屋」と言っています。 Know Narratorの開発メンバーは、 MTG などの時間を除き、基本的にこの作業部屋に入った状態で開発に取り組んでいます。わからないことや、話したほうが早いことがあれば、すぐに会話できる環境を用意しているといった形です。 私たちは、いわゆるハイブリッドワーク的な働き方をしているため、このような運用をしております。リモート中心で働くメンバーもいますし、出社中心で働くメンバーもいます。また、開発にはパートナー会社の方にも協力していただいており、コミュニケーションを円滑にとるための工夫として取り入れている仕組みになります。 開発部屋のメリット この開発部屋によるメリットはいろいろあります。 話したいことをすぐに話せる 人が話しているのを聞いて、実装のコツを知ることができたり新たな発見を得ることができたりする 開発部屋のスレッドで開発に関するチャットを行うことで、やりとりを一元管理できる 1点目は想像しやすいかと思います。 2点目に関しては、対面で働いていたら発生していた「盗み聞きからの発見」みたいなものをハイブリッドワークでも実現できたということです。出社していると、隣で会話している内容が耳の中に入ってきて、参考になることがあると思います。開発部屋でも、自分以外のメンバーが仕様に関する相談をしていたり、コードレビューに関する会話をしていたりします。このような会話を聞くだけでも、学べることはたくさんあると思います。これは明確なメリットです。ほかにも、話している内容を知っているメンバーが会話に入っていく、みたいな光景もよく見られます。 3点目に関しては、Teamsではチャンネルに会議を紐づけることで、以下のようにチャンネル上のスレッドとして会議チャットを管理できるようになります。 こちらの会議チャット上で開発に関する基本的なチャットのやり取りを行うことで、「どこのスレッドでチャットすれば?」みたいな些細な悩みをなくすことができます。 例えば、「トピックごとにスレッドを立てましょう」というルールを作れば、「この内容のレベルでスレッド立てる?」という悩みや、「この内容は複数トピックまたぐのだがどこでチャットしよう」という悩みが生まれるでしょう。 私たちの開発部屋スレッドでは、PRを作成した際のレビュー依頼などが飛んでいます。この運用ならば、開発部屋に入っている全員がこのチャットを認識できるので、お互いの進捗を把握することもできます。 開発部屋の運用で気を付けていること つなぎっぱなしは気を遣ってしまう、大変そうだなぁと思う方もいるかもしれません。この部分の対策としては、基本的にマイク・カメラともにOFFにし必要なときだけマイクをONにする。PCの前からいつ離れてもらってもOKという形をとっています。集中したいから一時的にイヤホンを外す、などもOKです。 一応離席する際に「離席」やら「riseki」やらコメントを入れる習慣はあります(risekiは変換が面倒くさかったときに送りがち)。これは「そこにいると思って話しかけたら、実は離席中で返事がなかった」――そんなさみしい思いをしないための習慣だとか、そうでないとか。 また、この開発部屋では会議ツールによくある ブレイクアウト ルームの機能を利用して、自由に出入りできる「開発小部屋」も用意しています。個別の内容や、「全体に聞こえる形で話すのはちょっとなぁ」と思うときなどに利用しています。 このように、開発部屋に入ることが何らかの制限にならないようには気を付けて運用しています。 定期的に開発部屋を作り直し、名前を付けるように 毎日使うところだからこそ愛着を こんな開発部屋ですが、今年の6月くらいまで、ずっと同じ会議ルームを使い続ける運用にしていました。さらに会議名も「開発部屋」とだけ。 私個人的には、「毎日開発メンバーが入ってくる場所なのに少し無機質だなぁ」と感じていました。いかにも作業的な感じがしたのです。 そこで、 定期的(2スプリント毎に)に開発部屋を作り直す! 開発部屋(Teams会議)名にテーマを付けて、開発小部屋( ブレイクアウト ルーム)にも部屋名を付ける! という2つの運用を取り入れました。 上図にもありましたが、実際に以下のような開発部屋が立ち上がっています。 ちょうど開発部屋を作るころに寒くなってきたのと、大量の実装タスクが積まれていたのでこのようなテーマになっています。特定の機能の実装が大きなタスクとなっているときは、その機能に関連するテーマを付けたりします。 開発小部屋はこんな感じ。 過去には「松」、 「竹」 、「梅」で名づけたり、「ブラジル」、「オランダ」のように国名で名づけたりしていました。最近では時期に合わせたものにすることが増えています。 完全に内輪ノリといえば内輪ノリです。ですが、楽しく開発にかかわることは、プロダクト開発・チーム開発において最も大事だと思っているので、内輪ノリもある程度はよいのかと。些細なことかもしれませんが、日ごろから意識していきたいところです。 「○○の話をしたいので “ブラジル” に行きましょうか」 最近の開発部屋内でよく出てくるコメントです。もちろん、「開発小部屋に移って会話しましょうか!」という意味ですが、すこしマイルドな感じがします。感じがするだけです。 旅館やおしゃれなオフィスで、部屋に名前がついてたりするのをイメージしていたりはします。開発チームのメンバーも、この運用を始めた当初は少し恥ずかしそうに「ブラジルで」と話していましたが、最近では普通に話すようになりました。 名前を付ける前は、以下のようなチャットが流れていた開発チームも… 今では以下のような形に 一部のメンバーは「次の名前は何かな」という楽しみを持っているとかいないとか。 定期的に立て直すことでリズムが生まれた これは意図していなかったのですが、開発部屋を定期的に立て直すことで、時間の流れを意識できるようになりました。どういうことかというと、新しく会議ルームが立ち上がることでスレッドも一新されますし、「2スプリント経過した」ということを明確に感じるようになったのです。 Know Narratorはほぼ月一回のアップデート(リリース)を行っています。10月のアップデートが終わっても、すぐに次の11月アップデートに向けて動き出します。このように開発が継続的に続いているのです。この性質に加え、今までは毎日変わらない会議部屋に入っていたことから、ずーっと変化のない感覚があったのかもしれません。 毎日入る会議部屋が定期的に新しくなることで、気分 もリフ レッシュしたかのような感覚を得ることができました。開発部屋のテーマや開発小部屋の名前が、そのときどきに合わせたものになることで、無機質になりがちだった部分に変化を出せたのかなと。 まとめ 内輪ノリに近い形で始めた運用ですが、円滑にコミュニケーションをとること、開発が楽しいと思える環境を作ることは、良い開発チームであるために必要なことだと思っています。 また、Teamsを活用した開発部屋の運用は、チャットツールの運用という面においても比較的効果的な面があるかと思います。スレッドが乱立してどこでチャットしたらいいのかわからない。チャットを見逃してしまう。という課題にもある程度の対策にはなると思います。 この運用も今後ずっと続くとは思っていません。今後もそのときにいる開発メンバーの特性に合わせたスタイルで開発チームの運営をしていきたいですね! 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @naoki.muramoto レビュー: @yamada.y ( Shodo で執筆されました )
こんにちは。 エンタープライズ 第一本部 戦略ソリューション 1 部の英です。 普段はWebアプリや スマホ アプリの案件などを担当しています。あと、趣味でAIを勉強しています。 最近寒いですね。キーボードの下にデスクヒーターを配置したら QOL が爆上がりしたので、是非みなさんも試してみてください。 キーボードを打つ手がポカポカです。では、ポカポカの手で記事を書いていきます。 つい最近、 Amazon のBIツールである Amazon Quick Sightが Amazon Quick Suite にリ ブランディング されました。 東京リージョンではまだ新機能の一部が解放されていないのですが、新しいデザインになっているようなので触ってみましょう。 そして今回は AI駆動開発 の要素も入れてみましょう。 人が頭を使うこと、手を動かすことは最小限 にして AI駆動データ分析基盤 をサクッと構築してみます。 AI Agent は何でも良いのですが、最近勢力を上げてきているOpenAIの Codex を使ってみましょう。 VSCode とも統合されていて使いやすいですからね。 ハンズオン形式で記事を書くのでよかったら手元でも一緒に試してみてください。 ただし有料サービスを使うので、費用が発生する点にはご注意ください。 本日構築するイメージはこんな感じ。 同時接続数やパフォーマンスは気にしなくて良いのでDWHはスキップして良いでしょう。フルサーバレスでいきます。 本日の流れはこんな感じ。 AIに全体構成を考えてもらう AIに必要な権限を聞いて json で吐いてもらう 人が権限の内容を確認し、問題なければIAMを発行して権限を付与する 人が AWS CLI でIAMを設定し、AIにユーザーを伝える AIが分析用のダミーデータ一式を生成するための スクリプト を作成(物流系のデータ) AIが スクリプト からダミーデータを自動生成 AIがローカルのデータをS3に同期 AIがGlue CrawlerでS3のデータからカタログを作成 AIがクエリを考案してAthenaでクエリを投げて結果をS3に保存 人が Amazon Quick SuiteでAthenaをデータソースに設定 AIが分析用のプロンプトを考える AIがグラフを自動生成する(可視化) 人がグラフを評価し、AIにより深い指示を出してデータ分析を進める "AIが" で始まるタスクが圧倒的に多いですね。 人は初期設定やAIのアウトプットの評価に集中することができます。 これぞAI駆動 。 ここからが本題 1. AIに全体構成を考えてもらう まずはChatGPT5.1 Thinking モデルに全体構成を考えてもらいます。 ChatGPT5.1 Thinkingの考案した全体構成をmermaidで可視化してみると以下のような構成でした。 ローカルにデータを吐いて、S3に上げたのちに分析用にデータを分解。 BIは Amazon Quick Suiteを採用してビジネスユーザーが外からデータ閲覧する構成になっています。 イメージ通りの構成ですね。 2. AIに必要な権限を聞いて json で吐いてもらう ここからはCodexで作業します。もうThinkingモードは使いません。 必要な権限を json で吐き出してもらいます。 3. 人が権限の内容を確認し、問題なければIAMを発行して権限を付与する いくつかの権限に分けて出力してくれました。 各ポリシーを作成し、Codex用のIAMに付与します。(不要な権限が含まれていないか目視で確認しましょう) ハマりポイントとしてはGlue Crawlerを実行するためにGlueのサービスロールをパスロールで渡すところでしょうか。 それ以外は一般的なS3、Athena、Glueに対する操作権限です。 ※ バケット 作成後はリソースを絞りましょう 4. 人が AWS CLI でIAMを設定し、AIにユーザーを伝える IAMを作成したらシークレットキーを発行します。 黄色枠にあるように AWS CLI の aws configureでcodexというプロファイル名にシークレットキーを埋め込みます。 これで VSCode (Codex)が自律的に AWS リソースにアクセスして自由にデータを操作できるようになります。 5. AIが分析用のダミーデータ一式を生成するための スクリプト を作成(物流系のデータ) 今回は手元に何もデータがないのでダミーデータから考えねばなりません。 Codexに以下のタスクを依頼してみます。 以下のようなダミーデータ作成用の スクリプト が完成しました。 この スクリプト で生成されるダミーデータは以下の関係性になっています。 dim_:顧客や商品などの実データ fact_:配送や返品などの明細データ(実績データ) 6. AIが スクリプト からダミーデータを自動生成 先ほどの スクリプト でローカルにデータを作成してもらいます。 ローカル環境に以下のようにデータが作成されました。 7. AIがローカルのデータをS3に同期 ローカルに作成したファイルをS3に同期してもらいます。 プロンプトが見切れていますが、ローカルに作成したデータをS3にアップロードすることを指示しました。 AWS コンソールでS3を開き、データが無事に同期されていることを確認します。 8. AIがGlue CrawlerでS3のデータからカタログを作成 GlueのCrawlerの権限はパスロールで渡してあるので、以下の一連の作業をすべて委譲することができます。 S3のデータをスキャンして スキーマ を自動推論し、Data Catalogにテーブルを作成します。 9. AIがクエリを考案してAthenaでクエリを投げて結果をS3に保存 注文件数、配送遅延を分析し、その結果を CSV 形式でS3 バケット に保存します。 S3 バケット のathena-results/に結果が格納されていることを確認。 チャットの方にも5月の配送遅延の平均は122分と記載されていますが、この数値はAthenaで実際にクエリを実行した結果と一致しています。 (ダミーデータの品質がイケてないため、平均遅延2時間という狂った世界になっていますがいったん無視してください。5月に何があったんだ・・・。) ついでに分析用にビューをいくつか作成しておきます。Codex経由で作成しました。 10. 人が Amazon Quick SuiteでAthenaをデータソースに設定 ここから少しだけ人の手による作業が必要です。 AWS コンソールで Amazon Quick Suiteを開きます。 (※ Amazon Quick Sightの開始画面が Amazon Quick Suiteに切り替わっています) ちなみに Amazon Quick Suiteのフル機能は以下のリージョンでのみ提供されており、東京はまだです。 引用: Amaozn Quick Suite 初期設定画面でリージョンを東京に切り替えます。 「アカウント作成」を押下すると以下の画面に遷移します。作成に1分ほどかかります。 アカウント作成が完了。 「 Amazon Quick Suiteに遷移」を押下することで ダッシュ ボードに遷移します。 デフォルトの ダッシュ ボードが開きました。 次は権限の設定を行います。 「Quick Suiteを管理」を押下します。 「 AWS リソース」を選択します。 S3とAthenaを有効にします。 S3は バケット も選択しておきます。 次はSPICE容量を購入します。 SPICE (Super-fast, Parallel, In-memory Calculation Engine) の頭文字から来ています。かっこよすぎる。 いったん1GBを購入。 参考: SPICEの価格 容量が追加されていることを確認。 次はデータソースの接続です。 Athenaを選択して次へ。 データソース名を設定し、「接続を検証」を押下。 検証済みになればOK。 追加したデー タセット を押下。 「デー タセット の作成」を押下。 先ほど作成したビュー(v_fact_shipments)をSPICEに追加します。 迅速な分析のためにSPICEにインポートを選択して「視覚化する」を押下。 取り込みが完了すると以下の画面に遷移します。 この画面でデータの可視化を行います。 棒グラフを手動で追加してみる。 X軸にcarrier_id(配送業者)を追加すると配送業者別のレコード数の棒グラフが表示された。 11. AIが分析用のプロンプトを考える 先ほど作成したビューでどんな可視化が有効か、いくつかパターンを考えてもらいます。 日時の出荷件数の推移を可視化しましょう。 12. AIがグラフを自動生成する(可視化) ビジュアルタブで「構築」を押下する。 画面の右にAmazonQが表示される。 プロンプト①:日別の出荷件数を折れ線グラフで作成してください。期間は2024-05の1か月とします。 ものの数秒でグラフが作成されました。 「ADD TO ANALYSIS」を押下して ダッシュ ボードにグラフを追加してみます。 日別の出荷件数の折れ線グラフ を ダッシュ ボードに追加できました。 プロンプト②:配送業者ごとの平均の遅延(分)を棒グラフで。実績がない行は除外。値は delay_min の平均。大きい順に並べて、数値ラベルも表示して。 とやりたいところですが、「遅延」は計算が必要なので、まずは計算フィールドを作成する必要があります。 計算フィールドも 自然言語 で作成可能です。「+計算フィールド」を押下します。 どんな値が欲しいのかを 言語化 して伝えます。 式が提案されるので、「挿入」を押下する。予定到着時刻と実績到着時刻の差を計算しています。 計算フィールドを設定して「保存」を押下。 計算フィールド(delay_min)が追加されました。 次はこれを使ってグラフを作成します。 先ほどのプロンプトを再実行すると 配送業者別の平均遅延時間のグラフ を追加することができました。 13. 人がグラフを評価し、AIにより深い指示を出してデータ分析を進める では先ほどの配送のビューからより深堀分析を進めます。 いくつかのビューを提案してくれたので作成を依頼します。 権限は渡してあるので作成を進めてくれます。 Glueを確認すると追加で複数のビューが作成されていることを確認できました。 新規ビューのv_shipments_enrichedを選択して、SPICEにインポートする。 先ほどの画面で「デー タセット を追加」を押下する。 SPICEに取り込み済みのv_shipments_enrichedを選択する。 v_shipments_enrichedの可視化方針を決めます。 先ほどと同様に計算フィールドをAmazonQを使って 自然言語 で追加します。 プロンプト③:月別×配送業者のオンタイム率をヒートマップで表示 月別の配送業者別のオンタイム率(予定通りに配送できた割合)をヒートマップで表示することができました。 さいごに 記事が長くなってしまうのでこの辺で終わります。 今回のポイントとしては以下の2点です。 Codex × AWS CLI でデータ分析基盤を自動構築できる AmazonQ in Quick Suiteなら非エンジニアでも簡単にデータの可視化が行える 扱うのに少しだけ AWS の知識が必要ですが、AIの力でデータ分析の 民主化 がまた一歩進んだ感じがあります。 これからも AWS やAI関連の検証記事をたくさん書いていきます。 ↓ のスターを押していただけると嬉しいです。励みになります。 最後まで読んでいただき、ありがとうございました。 エンタープライズ 第一本部では一緒に働いてくださる仲間を募集中です。以下のリンクからお願いします。 私たちは一緒に働いてくれる仲間を募集しています! 中途採用-エンタープライズ第一本部 新卒採用-エンタープライズ第一本部 執筆: 英 良治 (@hanabusa.ryoji) レビュー: @miyazawa.hibiki ( Shodo で執筆されました )
はじめまして。XI本部 クラウド イノベーション センター所属、2年目の米田です。 AWS re:Invent 2024 にて発表され、2025年5月に正式リリースされた「 Amazon Aurora DSQL(以下Aurora DSQL)」について触れる機会がありましたので、こちらで共有いたします 。 今回の記事では特に、 Aurora DSQLの仕様や、Terraformを活用したIaC(Infrastructure as Code)化 の観点から、その特徴や実践ポイントをわかりやすく紹介します。 これから Aurora DSQL の導入を検討されている方にとって、少しでも参考になる内容になれば幸いです。 Aurora DSQLとは データベースへの認証 データベースロール トークン認証 IaC化してみる 実行結果 注意すべきポイント まとめ 参考文献 Aurora DSQLとは Aurora DSQLは、従来のAuroraと比較して、より高可用性なフルマネージドのサーバーレス分散 SQL データベースになります。ここで、フルマネージドサービスとは、 ユーザーがインフラ運用を意識せず、 AWS が裏で全部管理・自動化してくれる サービスのことを指します。具体的には、Aurora DSQLは クラスタ ー管理や容量計画が不要で、データは自動的に複数AZへ分散されるため、運用負荷の大幅な軽減が期待されます。 AWS 公式ドキュメントでも以下のように記載されており、Aurora DSQLが高い可用性とほぼ無制限のスケーラビリティを実現する次世代データベースサービスであることがわかります。 Amazon Aurora DSQL は、 トランザクション ワークロード用に最適化されたサーバーレスの分散リレーショナルデータベースサービスです。Aurora DSQL は実質的に無制限のスケールを提供し、インフラスト ラク チャを管理する必要はありません。アクティブ/アクティブ高可用性 アーキテクチャ は、 99.99 % の単一リージョンと 99.999% のマルチリージョンの可用性を提供します。 ( AWS 公式ドキュメントより引用) 今回触れるきっかけとなったのは、以下3点にメリットを感じてになります。 1,分散データ処理 単一リージョンで 99.99 %、マルチリージョンで99.999%の可用性を提供するアクティブ/アクティブ構成の高可用性を実現してくれます。 2,インフラスト ラク チャの管理が完全に不要 フルマネージドのサーバーレスサービスであるため、パッチ適用/アップグレード/メンテナンス作業が発生せず、バックアップに関しても AWS Backupを利用することで自動化できます。 3,使用量に応じた従量課金制 Aurora DSQLにかかるコストは従量課金制なため、従来のデータベースと比較してコスト効率よく運用することができます。例えば、アクセス頻度がそれほど高くない ユースケース では、常時稼働する インスタンス 単位(時間課金)のデータベースと比べて、Aurora DSQL のような使用量に応じた課金モデルの方が、よりコスト効率よく利用できる可能性があります。 具体的にはDPUと呼ばれるデータベースの処理能力単位に比例して課金されるため、実際に利用する際にはCloudwatchやAurora DSQLの ダッシュ ボードから以下のようなDPU消費メトリクスを確認するのが良いでしょう。 WriteDPU:Aurora DSQL クラスタ ーの書き込み時に使用したDPU ReadDPU:Aurora DSQL クラスタ ーの読み込み時に使用したDPU ComputeDPU:Aurora DSQL クラスタ ーの計算時に使用したDPU データベースへの認証 Aurora DSQLへアクセスするにあたって、誰でもアクセスできてしまってはセキュリティ上好ましくありません。そこで重要になってくるのが データベースロール と トーク ン認証 です。 データベースロール データベースロールとは、その名のとおり実際にデータベースを操作するために必要なロールで、これはIAMロールとはまた別物である点に注意してください。 データベースロールは、全てのアクションが可能な Adminロール と、ユーザが定義した範囲内でアクションが可能な カスタムロール の、2つに分けられます。とりあえずAdminロールを使用してアクセスすれば全てのテーブル操作が可能ですが、 AWS のベストプ ラク ティスに則ってセキュリティ面を考慮すると、必要最低限のアクションを定義したカスタムロールを使用するべきです。 以下の表に、データベースロールごとの主な違いをまとめました。 データベースロール 権限範囲 主な操作 推奨用途 Adminロール 全権限 CREATE、 DROP 、SELECT、INSERT、UPDATE、DELETE等全て 管理者や全てのテーブルにアクセスする必要のあるリソースに対して利用 カスタムロール ユーザー定義 必要な操作のみ許可 Aurora DSQL操作を必要最低限に抑えたい場合に利用 カスタムロールはDSQL クラスタ 内部で作成します。作成した後はIAMロールと紐づけることで、紐づけ先IAMロールにDB操作権限を紐づけることができます。 ※Adminロールはデフォルトで存在しており、作成したり紐づけたりといった作業は不要です トーク ン認証 IAMロールをデータベースロールに紐づけたので、そのIAMロールを用いてAurora DSQLにアクセスしてみよう、と思うかもしれませんが、それではうまくいきません。 実際はAurora DSQLの認証には トーク ン が必要になります。ややこしいかもしれませんが、IAMロールを用いて可能なのはあくまでもAurora DSQLの トーク ンの取得であり、実際にデータベースへアクセスするにはその トーク ンを使用した認証が必要になります。 トーク ンを取得する方法は2通りあり、一つはAdmin権限として取得する方法(Adminロール)、もう一つはカスタムロールで定義した権限内の操作のみを許可する トーク ンを取得する方法(カスタムロール)です。後者の場合の私なりのイメージを図にしました。 Admin権限 トーク ンをリク エス トする場合と、紐づけたカスタムロールで定義した権限 トーク ンをリク エス トする場合とで、エンドポイントが異なります(以下 CLI での実行例) # Adminの場合 aws dsql generate-db-connect-admin-auth-token \ --hostname <DSQL Endpoint> \ --region ap-northeast- 1 \ --expires-in 3600 #トークン期限 # カスタムロールの権限内に限定したトークン取得の場合 aws dsql generate-db-connect-auth-token \ --hostname <DSQL Endpoint> \ --region ap-northeast- 1 \ --expires-in 3600 同様に、IAMロールにアタッチしておくべきアクションもデータベースロールによって異なります。Adminとして トーク ンを取得する場合は dsql:DbConnectAdmin アクションが必要となる一方で、IAMロールに紐づけたカスタムロールに権限を絞る場合は dsql:DbConnect アクションが必要となります。 取得した トーク ンを用いてAurora DSQLに接続し、クエリを実行することで必要な操作を実現します。 このように、IAM認証と トーク ン認証を組み合わせることで、セキュアにAurora DSQLへアクセスすることが可能になります。 IaC化してみる ここまでの流れを実際にIaC化してみようと思います。実装にはTerraformを利用し、プロバイダーはTerraform公式の AWS Providerを用いることにします。 今回はAurora DSQL クラスタ と、データ取得・更新を実施するLambda関数というめちゃくちゃ簡単な アーキテクチャ をTerraformで用意してみました。 今回利用する環境は以下のとおりです provider:hashicorp/ aws version:v6.14.1 まず、 クラスタ の作成にはTerraformの AWS Providerでサポートされている aws _dsql_cluster リソースを利用します。 resource "aws_dsql_cluster" "this" { deletion_protection_enabled = true tags = { Name = "BlogCluster" } } シングルリージョン 削除保護の有効化 タグ設定:TestCluster 次にLambdaにアタッチする実行ロールを作成します。(Lambda関数自体の作成は割愛し、ここではIAMロールの作成だけを記載してます) data "aws_iam_policy_document" "dsql_role_assume_role" { statement { actions = [ "sts:AssumeRole" ] principals { type = "Service" identifiers = [ "lambda.amazonaws.com" ] } } } data "aws_iam_policy_document" "dsql_role" { statement { effect = "Allow" actions = [ "dsql:DbConnect" ] resources = [ "<DSQL Endpoint>" ] } } resource "aws_iam_role" "dsql_role" { name = "dsql-blog-role" assume_role_policy = data.aws_iam_policy_document.dsql_role_assume_role.json } resource "aws_iam_role_policy_attachment" "dsql_role" { role = aws_iam_role.dsql_role.name policy_arn = aws_iam_policy.dsql_role.arn } resource "aws_iam_policy" "dsql_role" { name = "dsql-blog-policy" policy = data.aws_iam_policy_document.dsql_role.json } 最後にAurora DSQLでカスタムロールの作成とIAMロールへの紐づけを実施します。 マッピング 対象のIAMロールは、今回はLambda関数の実行ロールになります。Aurora DSQLへの接続は AWS コンソールより可能で、Cloudshell上でクエリを実行できます。 以下はblog_userというカスタムロールを作成する流れです。 # blog_userというカスタムロールを作成 CREATE ROLE 'blog_user' WITH LOGIN; # カスタムロールとIAMロールのマッピング AWS IAM GRANT 'blog_user' TO '<Lambda IAM Role ARN>' ; # カスタムロールにprivateスキーマへのアクセス権限を付与 GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA private TO 'blog_user' ; ただ、コンソールからの手動作成ではなく、実際はIaCの実行と同時に自動でクエリも実行されることが望ましいと思います。それにより、運用の負担を軽減し、ヒューマンエラーの低減が期待できます。 そこで今回は、Terraformの実行と組み合わせて、自動でカスタムロール作成まで実施してくれるように実装してみました。具体的にはTerraform実行時に外部 スクリプト を呼び出し、リソースの構築と同時に スクリプト で定義したクエリを実行する、といったものです。 以下実装コードになります。 resource "terraform_data" "this" { triggers_replace = { cluster_id = aws_dsql_cluster.this.identifier file_sha256 = filebase64sha256 ( "$ { path.module } /scripts/dsql.sh" ) } #shell scriptを呼び出して実行 provisioner "local-exec" { command = "sh $ { path.module } /scripts/dsql.sh" } } #!/bin/bash # トークン生成 export PGPASSWORD=$(aws dsql generate-db-connect-admin-auth-token \ --expires-in 3600 \ --region ap-northeast- 1 \ --hostname <DSQL Endpoint>) export PGSSLMODE=require # psql でロール作成 psql --dbname postgres --username admin --host <DSQL Endpoint> <<EOF CREATE ROLE blog_user WITH LOGIN; AWS IAM GRANT blog_user TO '<IAM Role ARN>' ; CREATE SCHEMA IF NOT EXISTS private; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA private TO blog_user; \q EOF あとはterraform init→terraform plan→terraform applyの順でコマンドを実行すれば、DSQL クラスタ ーが自動的にプロビジョニングされ、データベースロールの作成とIAMロールへの紐づけ、アクセス権限の付与までの処理が自動で走ります。 これにより手動での操作が軽減され、より効率的にリソースが作成されるようになりました。 実行結果 Lambdaを呼び出して、Aurora DSQLへの接続と基本的なクエリ実行が正常に動作することを確認します。 クリックして展開 import boto3 import ssl import pg8000 def lambda_handler (event, context): # Aurora DSQL 情報 dsql_endpoint = "<DSQL Endpoint>" aws_region = "ap-northeast-1" # トークン生成 dsql_client = boto3.client( 'dsql' , region_name=aws_region) auth_token = dsql_client.generate_db_connect_auth_token( Hostname=dsql_endpoint, ExpiresIn= 900 ) # SSL 設定 ssl_context = ssl.create_default_context() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_REQUIRED # データベース接続 conn = pg8000.connect( host=dsql_endpoint, database= 'postgres' , user= 'blog_user' , password=auth_token, port= 5432 , ssl_context=ssl_context ) # blogテーブルの内容を取得 cursor = conn.cursor() cursor.execute( """ SELECT member_id, title, content FROM private.blog; """ ) columns = [desc[ 0 ] for desc in cursor.description] rows = cursor.fetchall() blogs = [ dict ( zip (columns, row)) for row in rows] cursor.close() conn.close() return { "blogs" : blogs } 以上を実行すると、事前にprivate スキーマ に作成したblogテーブルからデータを取得することができました。 { "blogs" : [ { "member_id" : 1 , "title" : "はじめての投稿" , "content" : "これは最初のブログ記事です。" } , { "member_id" : 2 , "title" : "お知らせ" , "content" : "システムをアップデートしました。" } , { "member_id" : 3 , "title" : "Tips" , "content" : "PostgreSQLでスキーマを使い分けよう。" } ] } 注意すべきポイント 最後に、実際に触ってみてDSQLならではの注意すべき点と感じたポイントをまとめてみました。 接続には トーク ン認証が必須になりますが、 デフォルトで15分、最大で1週間 という期限が設定されています。したがって、定期的に トーク ンの更新処理が発生します。今回はリク エス トの都度 トーク ンを取得してくる想定で実装しましたが、 トーク ンを再利用する場合は注意が必要です。 DSQLは PostgreSQL と互換性があり、大変便利なサービスですが、逆に言えば PostgreSQL 以外のデータベースシステムとは互換性がありません。ですので、 PostgreSQL で対応できない処理に関してはおすすめできません 。 スキーマ の作成は Adminロールでしか実施できません 。カスタムロールで試行しても、権限不足というエラーメッセージが出力されます。したがって、 スキーマ 作成者は誤った操作をしないように注意が必要です。 ただし、本記事でも紹介したようにデータベース操作ごと自動化してしまえば、人的ミスも未然に防ぐことができます。 DSQLでは、 ALTER TABLE で列の型変更や削除、ユニークキーの追加ができません 。したがって、テーブルを編集した場合は、テーブルの削除→新規作成という手順が必要になります。新規作成になるのでテーブル単位の権限を与えていた場合は再度権限を与える必要があります。このことを考えると、カスタムロールに与える権限は スキーマ 単位で与えておくのが良いと思います。 GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA <スキーマ> TO <カスタムロール>; 部分インデックスがサポートされていないので例えば以下のように特定の条件に一致する行のみにインデックスを作成することができません。(これはなにかと不便ですね。。。) CREATE INDEX idx_user_id ON setting_category (category, user_id) WHERE category = '重要' ; 1つの トランザクション で変更可能なテーブル行の最大値が3000行となっているようで、それ以上の処理を実施する際にはページングなどが必要になります。 まとめ 本記事では比較的新しいサービスであるAurora DSQLを触ってみた感想をお伝えしました。 PostgreSQL 互換ということもあって非常に使いやすく、コストも他のデータベースサービスと比べて比較的安価に利用できるサービスだと思います。 今回はIaC化による構築手順についてメインでお伝えしましたが、今後は運用した中で得られた知見やベストプ ラク ティスについても共有していきたいと思います。 もし今後Aurora DSQLの導入を検討されている方に参考になればと思います。 参考文献 https://qiita.com/har1101/items/7dd1a6d803e48e3e0525 https://docs.aws.amazon.com/ja_jp/aurora-dsql/latest/userguide/what-is-aurora-dsql.html https://docs.aws.amazon.com/ja_jp/aurora-dsql/latest/userguide/SECTION_authentication-token.html https://docs.aws.amazon.com/ja_jp/aurora-dsql/latest/userguide/using-database-and-iam-roles.html 執筆: @yoneda.kosuke レビュー: @kobayashi.hinami ( Shodo で執筆されました )
こんにちは、クロス イノベーション 本部 AI トランスフォーメーションセンター所属の山田です。 今回はアプリケーションの認可(Authorization)に関して、Casbin というライブラリを使った設計・実装で紹介したいと思います。 認可(Authorization)と認証(Authentication)について 認可の話をするうえで前提として認可(Authorization)と認証(Authentication)の違いについて再確認しておきます。 認可(Authorization)は認証(Authentication)と混同されがちですが、区別して考えるのが重要です。 アプリケーションの認証は「ユーザーが誰であるか」を確認する役割を果たします。 一方で、認可は「ユーザーが何ができるか」を判断します。 最近のアプリケーションにおいて認証は、IdP(Identity Provider)に委譲するケースが多く、アプリケーションは IdP から発行された トーク ンを検証することで「ユーザーが誰であるか」の認証部分を実装できるようになりました。 一方で認可は依然としてアプリケーション固有のロジックです。 理由は単純で、アプリケーションの中で各ユーザーがどんな操作ができるかはサービスごとに異なるからです。 これらはアプリケーションごとに設計し、実装する必要があります。 認可ロジックの基本要素 実際にシステムで認可を扱う際に最も基礎となる要素を分解すると「ユーザー」、「リソース」、「操作」の 3 つになります。 要素 意味 ユーザー 操作を試みる主体 リソース 操作対象のオブジェクト 操作 リソースに対して行いたい操作 認可における「ユーザー」「リソース」「操作」の関係 具体例にこの 3 つの要素を当てはめて、認可というものが何かを考えてみましょう。 「アリス(ユーザー)が文書 1(リソース)を閲覧(操作)できるか?」 認可とは、この問いに対して 「Yes」か「No」 かを判断する仕組みです。 つまり、認可は「誰が(ユーザー)」「何に対して(リソース)」「何をするか(操作)」の三要素の組み合わせで構成されるルールセットといえます。 このように要素を分解して整理することで、アプリケーションにおいて認可の設計を具体的な ドメイン 設計の一部として考えることができるようになります。 アプリケーション固有のルールも、最終的にはこの三要素の組み合わせとして表現できます。 Casbin とは Casbin はここまで紹介してきた認可の処理をアプリケーションに実装する際に利用できるライブラリです。 Casbin は非常に柔軟なライブラリで大体の認可ロジックを実装できます。 オリジナルの実装は Go 言語ですが、 Java 、 Python 、 JavaScript など他の プログラミング言語 の実装もあります。 casbin.org Casbin の概念 Casbin 利用時は 「Model」、「Policy」、「Enforcer」 という 3 つの要素からなります。 これらの 3 要素の意味はそれぞれ以下です。 要素 意味 Model アクセス制御のモデルを定義するもの Policy 権限データの実体 Enforcer Model と Policy を読み込み、要求に対し認可ロジックを実行するエンジン Casbinにおける「Model」、「Policy」、「Enforcer」の関係 Model はアクセス制御の論理的な骨組みを定義します。 アプリケーションに組み込む場合、Model は静的であり、 model.conf のようなファイルベースで管理されます。 Policy は Model 側で決められた構造に従った実際の権限データの実態です。 こちらは Model とは対照的に動的であることがほとんどです。 Policy も policy.csv のようにファイルベースで管理できますが、データベースでの管理もできます。 Casbin でのアクセス制御モデル Casbin では「Request」、「Policy」、「Matcher」、「Effect」 という 4 つの概念を使ってアクセス制御モデルを構成します。 要素 意味 Request Request は認可判断の入力で、操作を行う主体(sub)、 アクセス先のオブジェクト(obj)、実施する操作(act)が含まれます。 Policy Policy は権限データの構造を定義します。基本的には p={sub, obj, act} ですが、ポリシーのマッチング結果の eft 列を明示的に追加し、 p={sub, obj, act, eft} にもできます。 Matcher Matcher は Request と Policy のマッチングルールを定義します。 Effect Effect は最終的な認可の決定ルールを定義します。 実際のアクセス制御モデルの構成を見ていきましょう。 最も基本のアクセス制御モデルである ACL ( Access Control List:アクセス制御リスト)は以下のようになります。 # Request definition [request_definition] r = sub, obj, act # Policy definition [policy_definition] p = sub, obj, act # Matchers [matchers] m = r.sub == p.sub && r.obj == p.obj && r.act == p.act # Policy effect [policy_effect] e = some(where (p.eft == allow)) ポリシーに以下の権限データが格納されているとします。 p, alice, data1, read p, bob, data2, write この場合、Casbin では以下のように判断できます。 alice は data1 を read できます。 bob は data2 を write できます。 ここまでが Casbin のアクセス制御モデルの基本になります。 Casbin を実際に使ってみる Casbin の概念についてはある程度触れたので実際に Casbin を使ってみましょう。 今回は Casbin の Python 実装である PyCasbin を利用します。 github.com pip install pycasbin model.conf と policy.csv を用意し、それぞれをロードします。 import casbin # Enforcerの初期化 e = casbin.Enforcer(model= "./model.conf" , adapter= "./policy.csv" ) enforcer メソッドを使って権限のチェックを実施します。 # 権限のチェック # 例: "alice"が"data1"に対して"read"権限を持っているか確認 result_1 = e.enforce( "alice" , "data1" , "read" ) assert result_1 == True # 例: "bob"が"data2"に対して"write"権限を持っているか確認 result_2 = e.enforce( "bob" , "data2" , "write" ) assert result_2 == True # 例: "alice"が"data2"に対して"write"権限を持っているか確認 result_3 = e.enforce( "alice" , "data2" , "write" ) assert result_3 == False このようにして、Casbin ではアクセス制御モデルのルールをもとに権限チェックを行えます。 権限データ(Policy)をデータベースから読み取る 次に、より実践的なパターンとして権限データをデータベースから読み取る例を紹介します。 今回は RDB の PostgreSQL を使って権限データを管理します。 説明を省いていましたが、Casbin では Policy の読み取りは、Adapter というモジュールを介して行われます。 CasbinでのAdapterモジュールの位置付け PyCasbin で権限データの管理に RDB を扱う場合には、SQLAlchemyベースでDBとやり取りをする casbin_sqlalchemy_adapter という Adapter モジュールの利用がおすすめです。 github.com 今回は上記の casbin_sqlalchemy_adapter と PostgreSQL への接続に使うために psycopg2 の2つのライブラリを依存関係に追加します。 pip install psycopg2 pip install casbin_sqlalchemy_adapter PostgreSQL を使うために、Adapter で PostgreSQL への接続情報を与えます。 import casbin_sqlalchemy_adapter DB_USER_NAME = "<データベースのユーザー名>" DB_PASSWORD = "<データベースのパスワード>" DB_HOST = "<ホスト名 or IPアドレス>" DB_NAME = "<データベース名>" adapter = casbin_sqlalchemy_adapter.Adapter(f "postgresql+psycopg2://{DB_USER_NAME}:{DB_PASSWORD}@{DB_HOST}:5432/{DB_NAME}" ) e = casbin.Enforcer( "./model.conf" , adapter=adapter) casbin_sqlalchemy_adapter では、上記のように設定すると PostgreSQL のデータベース上に casbin_rule テーブルが自動で作成されます。 作成される casbin_rule テーブルは以下のような構造になります。 Column | Type | Collation | Nullable | Default --------+------------------------+-----------+----------+----------------------------------------- id | integer | | not null | nextval('casbin_rule_id_seq'::regclass) ptype | character varying(255) | | | v0 | character varying(255) | | | v1 | character varying(255) | | | v2 | character varying(255) | | | v3 | character varying(255) | | | v4 | character varying(255) | | | v5 | character varying(255) | | | Indexes: "casbin_rule_pkey" PRIMARY KEY, btree (id) Casbin ではポリシーデータを書き込むメソッドも用意されているため、こちらを利用して、動的に権限データをデータベースに永続化できます。 # 権限データの書き込み added = e.add_policy( "alice" , "data1" , "read" ) # 新規行追加の場合はTrueが返る assert added == True # 権限のチェック result = e.enforce( "alice" , "data1" , "read" ) assert result == True より実践的な使い方(1):RBAC ここまでで ACL ベースのアクセス制御を見てきましたが、実際のアプリケーションではロールベースのアクセス制御である RBAC が用いられることが多いので、RBAC のパターンも紹介します。 RBAC では model.conf に以下のように role_definition を追加し、 matchers でロールまで見るように設定します。 [request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act # ロールの継承関係の定義 [role_definition] g = _, _ [matchers] m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act [policy_effect] e = some(where (p.eft == allow)) RBAC ではロールに対し、操作権限を付与する形になります。 今回は editor と reader という 2 つのロールで考えてみましょう。 editor は data に対し read 、 write が可能、 reader は data に対し、 read だけが可能とします。 一度、権限データはすべて削除した状態とします。 # ロール定義を追加 e.add_policies( [ [ "editor" , "data" , "write" ], [ "editor" , "data" , "read" ], [ "reader" , "data" , "read" ], ] ) この状態で alice には editor ロール、 bob には reader ロールを付与します。 # ユーザーにロールを割り当て e.add_role_for_user( "alice" , "editor" ) e.add_role_for_user( "bob" , "reader" ) ここまででテーブルは以下の状態になります。 id ptype v0 v1 v2 v3 v4 v5 1 p editor data write NULL NULL NULL 2 p editor data read NULL NULL NULL 3 p reader data read NULL NULL NULL 4 g alice editor NULL NULL NULL NULL 5 g bob reader NULL NULL NULL NULL この状態で権限チェックを行います。 # 権限のチェック result_1 = e.enforce( "alice" , "data" , "write" ) assert result_1 == True result_2 = e.enforce( "alice" , "data" , "read" ) assert result_2 == True result_3 = e.enforce( "bob" , "data" , "read" ) assert result_3 == True result_4 = e.enforce( "bob" , "data" , "write" ) assert result_4 == False RBAC の重要なポイントはロールに対しリソースへの操作権限が割り当てられていることです。 RBACのイメージ図 アプリケーションの認可ロジックにおいて RBAC を採用することで、権限制御がユーザーに対して割り当てるロールの変更を行うだけで実現でき管理コストの軽減が見込めます。 ロールの継承について ここまでで紹介した editor のロールは redaer の上位ロールと考えることができます。 これを図で表現すると以下のようになります。 RBACにおけるロールの継承のイメージ図 Casbin では、このようなロールの継承も表現できます。 具体的に見ていきましょう。 editor ロールで data に関する read 操作の権限情報を消し、 editor ロールが reader ロールを継承するように設定をします。 # Editorロールからread権限を削除 e.delete_permission_for_user( "editor" , "data" , "read" ) # editorロールをreaderロールの上位に設定 e.add_role_for_user( "editor" , "reader" ) ここまででテーブルは以下の状態になります。 id ptype v0 v1 v2 v3 v4 v5 1 p editor data write NULL NULL NULL 3 p reader data read NULL NULL NULL 4 g alice editor NULL NULL NULL NULL 5 g bob reader NULL NULL NULL NULL 6 g editor reader NULL NULL NULL NULL この状態で alice が data を read できるかを問い合わせると、 True が返ることが確認できます。 # 権限のチェック result = e.enforce( "alice" , "data" , "read" ) assert result == True ユーザーとロール定義の重複への対処 Casbin では権限の設定はすべて文字列ベースで行われるためロール、ユーザーの区別がありません。 これはすなわち editor や reader というユーザーがいる場合、ロール定義と重複してしまうため正しく権限チェックが行えなくなります。 そこで実際にアプリケーションで権限設定を行う場合は定義に プレフィックス をつけるなどで対応するのが良いでしょう。 例えばロール定義には role: 、ユーザーの定義には user: のような プレフィックス を付けます。 このようにすることで重複に対応できます。 # 権限情報の定義 e.add_policies( [ [ "role:editor" , "data" , "write" ], [ "role:reader" , "data" , "read" ], ] ) # ロール情報の定義 e.add_role_for_user( "role:editor" , "role:reader" ) e.add_role_for_user( "user:alice" , "role:editor" ) e.add_role_for_user( "user:bob" , "role:reader" ) グループ管理への応用 ロールの継承はユーザーを集合したグループへのロール定義に応用できます。 ユーザーはグループに属し、グループに対してロールを付与するというシナリオを考えてみましょう。 今回は alice はグループ red に所属していて、グループ red にロール editor が与えられているとします。 これを図で表現すると以下のようになります。 グループに対してロールを付与する場合のイメージ図 先に紹介したユーザーとロール定義の重複を考慮して、グループの情報には group: という プレフィックス を付けます。 # 権限情報の定義 e.add_policies( [ ["role:editor", "data", "write"], ["role:reader", "data", "read"], ] ) # ロール/グループ情報の定義 e.add_role_for_user("role:editor", "role:reader") e.add_role_for_user("group:red", "role:editor") e.add_role_for_user("user:alice", "group:red") ここまででテーブルは以下の状態になります。 id ptype v0 v1 v2 v3 v4 v5 1 p role:editor data write NULL NULL NULL 2 p role:reader data read NULL NULL NULL 3 g role:editor role:reader NULL NULL NULL NULL 4 g group:red role:editor NULL NULL NULL NULL 5 g user:alice group:red NULL NULL NULL NULL alice はグループ red に所属しているため、 editor 権限を持ち、 data の読み書き操作ができます。 # 権限のチェック result_1 = e.enforce( "user:alice" , "data" , "write" ) assert result_1 == True result_2 = e.enforce( "user:alice" , "data" , "read" ) assert result_2 == True その他に、ユーザーが持つロール、所属しているグループの一覧は get_roles_for_user メソッドで取得可能です。 # ユーザーが所属しているグループ・付与されているロールの一覧の取得 rolls = e.get_roles_for_user( "user:alice" ) assert rolls == [ "group:red" , "role:editor" ] なお上記結果からも分かる通り、Casbin はグループ・ロールを区別しないため、所属しているグループの情報やロールの情報を抽出したい場合は、 プレフィックス まで見る必要があります。 より実践的な使い方(2):権限データのフィルタリング ここまでのやり方では、権限データを読み取るためにテーブルをすべて読み取る必要がありました。 これは少量のデータでは問題になりませんが、運用を見据えてデータ量が増えていくとパフォーマンス面で問題を引き起こす可能性があります。 そこで Casbin では権限データをフィルタリングして必要な権限データだけを読み取る機能をサポートしています。 一部のアダプタ実装では、フィルタされた権限データのロードをサポートしていません。 model.conf を編集し、特定の関心事( ドメイン )での権限データであることを権限判定ロジックに加えます。 この時、データをフィルターしやすいように ptype が p 、 g のどちらの場合でも同じ列に ドメイン の情報が入るようにするのが良いです。 # リクエスト定義にドメインを追加 [request_definition] r = sub, obj, act, domain # 権限データの定義にドメインを追加 [policy_definition] p = sub, obj, domain, act # ロール定義にドメインを追加 [role_definition] g = _, _, _ # 判定ロジックでドメインの一致を追加 [matchers] m = g(r.sub, p.sub, r.domain) && r.domain == p.domain && r.obj == p.obj && r.act == p.act [policy_effect] e = some(where (p.eft == allow)) この状態で、それぞれの ドメイン ごとに権限データを登録します。 # 2つのドメインを定義 domain_1 = "alpha" domain_2 = "beta" # ドメインごとのロールと権限を追加 e.add_policies([ [ "role:editor" , "data" , domain_1, "write" ], [ "role:reader" , "data" , domain_1, "read" ], [ "role:editor" , "data" , domain_2, "write" ], [ "role:reader" , "data" , domain_2, "read" ], ]) # aliceにはdomain_1のeditorロールを、bobにはdomain_2のeditorロールを割り当て e.add_role_for_user_in_domain( "user:alice" , "role:editor" , domain_1) e.add_role_for_user_in_domain( "user:bob" , "role:editor" , domain_2) ここまででテーブルは以下の状態になります。 id ptype v0 v1 v2 v3 v4 v5 1 p role:editor data alpha write NULL NULL 2 p role:reader data alpha read NULL NULL 3 g user:alice role:editor alpha NULL NULL NULL 4 g user:bob role:editor beta NULL NULL NULL ドメイン alpha の権限の検証の際に ドメイン beta の情報は不要であるため、フィルタしてロードすることが考えられます。 この時に使うのが load_filtered_policy メソッドです。 アダプタ側で用意されている Filter クラスを使って、条件を設定し、ロードする権限データを絞り込むことができます。 from casbin_sqlalchemy_adapter.adapter import Filter domain_1 = "alpha" domain_2 = "beta" f = Filter() f.v2 = [domain_1] # domain_1のポリシーのみをロード e.load_filtered_policy( filter =f) # 権限チェック result_1 = e.enforce( "user:alice" , "data" , "write" , domain_1) assert result_1 == True # domain_2のポリシーはロードされていないため、bobには権限がない状態になる bob_roles = e.get_roles_for_user_in_domain( "user:bob" , domain_2) assert bob_roles == [] まとめ 本記事では、アプリケーションの認可を組み込む際に利用できる Casbin というライブラリを紹介しました。 Casbin を利用することで、ロールの継承やグループへの権限の割当なども比較的にシンプルに実装できます。 アプリケーションの認可機能を実装する際には、候補として検討してみてはいかがでしょうか。 私たちは一緒に働いてくれる仲間を募集しています! 電通総研 キャリア採用サイト 電通総研 新卒採用サイト 執筆: @yamada.y レビュー: @miyazawa.hibiki ( Shodo で執筆されました )