TECH PLAY

電通総研

電通総研 の技術ブログ

822

はいどーもー! コミュニケーションIT事業部の宮澤響です! 普段は AppGuard というセキュリティ対策ソフトウェアの導入支援に携わっています! 本記事は 電通国際情報サービス Advent Calendar 2023 4日目(2日目相当)の記事です! 電通国際情報サービス Advent Calendarでは3年連続3回目の二番手(2日目相当の枠での投稿)となりますが、来年からは社名変更に伴いテックブログやAdvent Calendarの名称も変更となるため、晴れて 「 電通国際情報サービス Advent Calendar 永遠の二番手」 の称号を手に入れました。(?) なお、記念すべき1日目である先週金曜日の記事は、米谷典比古さんの「 祝 GA!Microsoft Fabric で今できることをまとめてみた 」でした! データ分析に関する統合環境を提供する SaaS である Microsoft Fabricについて分かりやすく書かれた記事ですので、ぜひご一読ください! ということで、本記事では、 Jira Automation で変数を作成、利用する際の注意点についてご紹介します! Jira Automationとは 簡単なルールを作成してみる 何が間違っているのか おわりに Jira Automationとは Jira Automationとは、Jira上の様々なワークフローを基本的にノーコードで自動化できるサービスです。 例えば、「特定の条件に一致するチケットが起票されたら担当者にメールを送信する」、「あるプロジェクトにチケットが起票されたら別のプロジェクトにも同じチケットを起票する」、といった処理を自動化できるため、Jiraによる課題管理をより効率的に実施できます。 実際、私自身も、普段の業務において、「問い合わせのチケットが起票から3日以上経過してもクローズしていない場合、Slackの指定チャネルに担当者をメンションして状況の報告依頼を投稿する」といった処理を自動化することで、問い合わせ対応の抜け漏れを防いでいます。 なお、Jira Automationは、Jira Cloudには初めから付帯していますが、Jira ServerやJira Data Centerで利用する場合には追加のアプリケーションのインストールが必要となります。( 参考 ) 概要については こちら を、利用方法については こちら を、それぞれご参照ください! 簡単なルールを作成してみる まずはサンプルとして以下のようなルールを作成してみます。 なお、ルールとは、Jira Automationによる自動化の設定の単位です。 Jira Automationの利用方法の紹介記事ではないため詳細は省略しますが、こちらのルールは以下のような内容となります。 (チケット上からの手動実行により以下の処理を開始) 実行元チケットのステータスが DONE の場合 完了! という値をもつ変数 test を作成 実行元チケットのステータスが DONE 以外の場合 未完了! という値をもつ変数 test を作成 変数 test の値を 【】 で囲んで監査ログに出力 ではここで問題です。 ステータスが DONE である以下のチケットに対してこちらのルールを実行すると、監査ログにはどのような値が出力されるでしょうか? 正解は…。 【】 のみが出力されました。 今回の実行元チケットのステータスは DONE であるため、監査ログには 【完了!】 と出力されていてほしいところですが、どうやら何かが間違っているようです。 何が間違っているのか 原因を探るべく、先ほどのルールを以下のように修正してみます。 伝家の宝刀、printf デバッグ です。 (チケット上からの手動実行により以下の処理を開始) 実行元チケットのステータスが DONE の場合 完了! という値をもつ変数 test を作成 変数 test の値を A【】 で囲んで監査ログに出力 実行元チケットのステータスが DONE 以外の場合 未完了! という値をもつ変数 test を作成 変数 test の値を B【】 で囲んで監査ログに出力 変数 test の値を C【】 で囲んで監査ログに出力 出力結果は以下のとおりです。 A の監査ログには 【完了!】 と出力されたのに対し、 C の監査ログには 【】 のみが出力されました。 どうやら、条件分岐の中でしか変数の値が出力されないようです。 ここで気づいたのですが、Jira Automationの変数にも、一般的な プログラミング言語 と同じように、 スコープの概念がある のではないでしょうか。 (スコープ:変数がどこから参照できるかを定めた変数の有効範囲) そして、 変数を作成 という項目名ではあるものの、実際には変数への代入を行っているのではないでしょうか。 であれば、以下のように条件分岐の外側で変数を宣言しておけば、期待どおりの結果が得られそうです。 (チケット上からの手動実行により以下の処理を開始) 初期値! という値をもつ変数 test を作成 実行元チケットのステータスが DONE の場合 完了! という値をもつ変数 test を作成 実行元チケットのステータスが DONE 以外の場合 未完了! という値をもつ変数 test を作成 変数 test の値を 【】 で囲んで監査ログに出力 無事に監査ログに 【完了!】 と出力されました! やはり、Jira Automationの変数にも、一般的な プログラミング言語 と同じように、スコープの概念があるようです。 つまり、今回の例で言えば、 条件分岐の外で作成した変数の値は条件分岐の中からも参照できるが、条件分岐の中で作成した変数の値は条件分岐の外からは参照できない ということです。 最初に例として挙げたルールでは、条件分岐の中( 完了! や 未完了! の部分)で作成した変数を条件分岐の外(監査ログに値を出力する部分)で参照しようとしていたため、正しい出力が得られませんでした。 一方、先ほどのルールでは、あらかじめ条件分岐の外( 初期値! の部分)で変数を作成していたため、監査ログに値を出力する部分でも変数の値を参照でき、正しい出力が得られた、ということになります。 なお、上記の内容は2023年10月末時点では公式ドキュメント( 日本語 / 英語 )に記載がありませんので、プログラミング未経験の方がJira Automationの 変数の作成 を利用する際には、ちょっとした落とし穴になってしまうのではないかと感じました。 おわりに 本記事では、Jira Automationの変数にも、一般的な プログラミング言語 と同じように、スコープの概念があることを検証しました。 Jira Automationを利用される際は、変数のスコープに注意して利用されるとよいのではないかと思います。 電通国際情報サービス Advent Calendar 2023 5日目(3日目相当)となる明日の記事は、柴田崇夫さんの「 TerraformのCustom ConditionsとChecksの紹介 」です! お楽しみに! 最後までお読みいただき、本当にありがとうございました! 私たちは同じ事業部で共に働いていただける仲間を募集しています! みなさまのご応募、お待ちしています! <電通×IT>電通グループ基幹システムプロジェクトマネージャー エンタープライズ向けDX推進リーダー/エンジニア <電通×IT>クラウドアーキテクト <電通×IT>アプリケーションアーキテクト 製品・プラットフォーム開発エンジニア 執筆: @miyazawa.hibiki 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
はいどーもー! コミュニケーションIT事業部の宮澤響です! 普段は AppGuard というセキュリティ対策ソフトウェアの導入支援に携わっています! 本記事は 電通国際情報サービス Advent Calendar 2023 4日目(2日目相当)の記事です! 電通国際情報サービス Advent Calendarでは3年連続3回目の二番手(2日目相当の枠での投稿)となりますが、来年からは社名変更に伴いテックブログやAdvent Calendarの名称も変更となるため、晴れて 「 電通国際情報サービス Advent Calendar 永遠の二番手」 の称号を手に入れました。(?) なお、記念すべき1日目である先週金曜日の記事は、米谷典比古さんの「 祝 GA!Microsoft Fabric で今できることをまとめてみた 」でした! データ分析に関する統合環境を提供する SaaS である Microsoft Fabricについて分かりやすく書かれた記事ですので、ぜひご一読ください! ということで、本記事では、 Jira Automation で変数を作成、利用する際の注意点についてご紹介します! Jira Automationとは 簡単なルールを作成してみる 何が間違っているのか まとめ Jira Automationとは Jira Automationとは、Jira上の様々なワークフローを基本的にノーコードで自動化できるサービスです。 例えば、「特定の条件に一致するチケットが起票されたら担当者にメールを送信する」、「あるプロジェクトにチケットが起票されたら別のプロジェクトにも同じチケットを起票する」、といった処理を自動化できるため、Jiraによる課題管理をより効率的に実施できます。 実際、私自身も、普段の業務において、「問い合わせのチケットが起票から3日以上経過してもクローズしていない場合、Slackの指定チャネルに担当者をメンションして状況の報告依頼を投稿する」といった処理を自動化することで、問い合わせ対応の抜け漏れを防いでいます。 なお、Jira Automationは、Jira Cloudには初めから付帯していますが、Jira ServerやJira Data Centerで利用する場合には追加のアプリケーションのインストールが必要となります。( 参考 ) 概要については こちら を、利用方法については こちら を、それぞれご参照ください! 簡単なルールを作成してみる まずはサンプルとして以下のようなルールを作成してみます。 なお、ルールとは、Jira Automationによる自動化の設定の単位です。 Jira Automationの利用方法の紹介記事ではないため詳細は省略しますが、こちらのルールは以下のような内容となります。 (チケット上からの手動実行により以下の処理を開始) 実行元チケットのステータスが DONE の場合 完了! という値をもつ変数 test を作成 実行元チケットのステータスが DONE 以外の場合 未完了! という値をもつ変数 test を作成 変数 test の値を 【】 で囲んで監査ログに出力 ではここで問題です。 ステータスが DONE である以下のチケットに対してこちらのルールを実行すると、監査ログにはどのような値が出力されるでしょうか? 正解は…。 【】 のみが出力されました。 今回の実行元チケットのステータスは DONE であるため、監査ログには 【完了!】 と出力されていてほしいところですが、どうやら何かが間違っているようです。 何が間違っているのか 原因を探るべく、先ほどのルールを以下のように修正してみます。 伝家の宝刀、printf デバッグ です。 (チケット上からの手動実行により以下の処理を開始) 実行元チケットのステータスが DONE の場合 完了! という値をもつ変数 test を作成 変数 test の値を A【】 で囲んで監査ログに出力 実行元チケットのステータスが DONE 以外の場合 未完了! という値をもつ変数 test を作成 変数 test の値を B【】 で囲んで監査ログに出力 変数 test の値を C【】 で囲んで監査ログに出力 出力結果は以下のとおりです。 A の監査ログには 【完了!】 と出力されたのに対し、 C の監査ログには 【】 のみが出力されました。 どうやら、条件分岐の中でしか変数の値が出力されないようです。 ここで気づいたのですが、Jira Automationの変数にも、一般的な プログラミング言語 と同じように、 スコープの概念がある のではないでしょうか。 (スコープ:変数がどこから参照できるかを定めた変数の有効範囲) そして、 変数を作成 という項目名ではあるものの、実際には変数への代入を行っているのではないでしょうか。 であれば、以下のように条件分岐の外側で変数を宣言しておけば、期待どおりの結果が得られそうです。 (チケット上からの手動実行により以下の処理を開始) 初期値! という値をもつ変数 test を作成 実行元チケットのステータスが DONE の場合 完了! という値をもつ変数 test を作成 実行元チケットのステータスが DONE 以外の場合 未完了! という値をもつ変数 test を作成 変数 test の値を 【】 で囲んで監査ログに出力 無事に監査ログに 【完了!】 と出力されました! やはり、Jira Automationの変数にも、一般的な プログラミング言語 と同じように、スコープの概念があるようです。 つまり、今回の例で言えば、 条件分岐の外で作成した変数の値は条件分岐の中からも参照できるが、条件分岐の中で作成した変数の値は条件分岐の外からは参照できない ということです。 最初に例として挙げたルールでは、条件分岐の中( 完了! や 未完了! の部分)で作成した変数を条件分岐の外(監査ログに値を出力する部分)で参照しようとしていたため、正しい出力が得られませんでした。 一方、先ほどのルールでは、あらかじめ条件分岐の外( 初期値! の部分)で変数を作成していたため、監査ログに値を出力する部分でも変数の値を参照でき、正しい出力が得られた、ということになります。 なお、上記の内容は2023年10月末時点では公式ドキュメント( 日本語 / 英語 )に記載がありませんので、プログラミング未経験の方がJira Automationの 変数の作成 を利用する際には、ちょっとした落とし穴になってしまうのではないかと感じました。 まとめ 本記事では、Jira Automationの変数にも、一般的な プログラミング言語 と同じように、スコープの概念があることを検証しました。 Jira Automationを利用される際は、変数のスコープに注意して利用されるとよいのではないかと思います。 電通国際情報サービス Advent Calendar 2023 5日目(3日目相当)となる明日の記事は、柴田崇夫さんの「 TerraformのCustom ConditionsとChecksの紹介 」です! お楽しみに! 最後までお読みいただき、本当にありがとうございました! 私たちは同じ事業部で共に働いていただける仲間を募集しています! みなさまのご応募、お待ちしています! クラウドアーキテクト アプリケーションアーキテクト 電通グループ向け基幹システムプロジェクトマネージャ 戦略的IT プロジェクトマネージャ/ITコンサルタント 執筆: @miyazawa.hibiki 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
XI 本部  クラウド イノベーション センターの米谷です。本記事は 電通国際情報サービス Advent Calendar 2023 の 1 日目の投稿です。今年の アドベントカレンダー の栄えあるトップバッターを務めさせていただきます。よろしくお願いします。 先日実施された Microsoft の年次テクニカルカンファレンス Ignite にて Microsoft Fabric の GA が発表されました! Microsoft Fabric は Microsoft のデータ関連製品として SQL Server 以来最も インパク トのある製品と言われており、 Ignite の基調講演の中でも取り上げられるなど注目を集めています。 Microsoft Fabric には様々な機能があり GA のタイミングで新しい発表も多くあったため、本稿ではそれらの情報を整理し Microsoft Fabric の特徴や魅力を改めて確認していきたいと思います。 はじめに データ分析基盤を取り巻く課題 Microsoft Fabric のコンセプト OneLake Data Factory Synapse Data Engineering Synapse Data Science Synapse Data Warehouse Synapse Real-Time Analytics Power BI Data Activator Purview まとめ はじめに データ分析基盤を取り巻く課題 機能紹介の前に Microsoft Fabric が登場するに至った背景をおさらいしておきたいと思います。データ分析基盤の構成要素はデータレイク、ETL、データウェアハウス、BI など多岐に渡りそれぞれに適したツールがあります。例えば Microsoft の Azure や Microsoft 365 では以下のようなサービスが提供されています。 データレイク : Azure Data Lake Storage Gen2 ETL : Azure Data Factory データウェアハウス : Azure Syanapse Analytics(専用 SQL プール) BI : Microsoft Power BI データカタログ、データガバナンス : Microsoft Purview これらを適切に組み合わせることではじめてデータ分析基盤ができあがります。Azure の場合上記のサービスは PaaS として提供されており比較的容易に構築できますが、それでも相応に労力の割かれる作業となることは事実であり、データを分析するためのスタートラインに立つまでにやることが多いというのが悩みの種となります。 Microsoft Fabric のコンセプト このような背景の中で発表された Microsoft Fabric は、上述の課題解決を狙いとした以下に示す 4 つのコンセプトを持ちます。 オールインワンの SaaS として提供 レイクセントリックな アーキテクチャ ー あらゆるロールのビジネスユーザーを支援 AI(Copilot) 実装 Microsoft Fabric には DWH、ETL、BI といったデータ分析に必要な機能が全て含まれた形で SaaS として提供されているため、ユーザーは導入後すぐにこれらの機能を使いデータ分析を行うことができます。分析に必要なデータは OneLake と呼ばれる場所で集約・管理され、使う機能によってデータを重複管理する必要はありません。データ分析には様々な役割のユーザーが関わりますが、皆が Microsoft Fabricという一つのサービスでコラボレーションできます。搭載されたAI 機能により、分析作業の質やスピードの向上が期待されます。 以降、各機能紹介の中でこれらのコンセプトがどのように組み込まれているかを都度解説します。 OneLake いよいよここから Microsoft Fabric の各機能の紹介に移っていきます。初めに紹介するのは、上述のレイクセントリックな アーキテクチャ ーで中心的な役割を果たす OneLake です。個人のデータ管理のために使用される OneDrive と対比する形で、組織のデータ分析に使用される場所という意味で OneLake という名称が付けられました。OneLake では Azure Data Lake Storage Gen2 ベースのオブジェクトストレージに分析データが Delta-Parquet 形式で保管されます。オープンスタンダードな形式である Delta-Parquet を用いることで、各機能の API が同一のデータに対してアクセス・分析可能になります。 実際に使用するに当たっては、分析対象となるデータをどのように OneLake に持ってくるか?という取り込みにかかるコストが重要になります。この点における解決策として OneLake ではショートカットと ミラーリング という 2 つの機能を提供しています。ショートカットとは ファイルシステム の シンボリックリンク のようなイメージで、データの実体は取り込み元にあるままで Microsoft Fabric で取り扱えるようにする仕組みです。データを移動させることなく分析ができるという非常に強力な機能となっています。一方の ミラーリング は取り込み元のデータをシームレスに OneLake にコピーする仕組みとなっており、データの取り込み作業の簡略化が期待できます。 現時点でショートカットは Azure Data Lake Storage Gen2 や Amazon S3 、Dataverse が、 ミラーリング は Azure SQL Database や Snowflake 、Azure CosmosDB などがそれぞれ対応しています。今後もショートカットにはオブジェクトストレージ系のサービスが、 ミラーリング にはデータベースや NoSQL 系のサービスが追加されていくのではと予想されます。 Data Factory Microsoft Fabric で ETL の役割を果たすのが Data Factory です。Azure Data Factory と同様に 100 を超えるコネクタを有し、オンプレミスや/ クラウド を問わず様々な場所のデータを Microsoft Fabric と連携させることが可能です。 GUI による処理の定義/パイプライン実行/ログの確認が可能となっており、Dataflow Gen2 という新しいエクス ペリエ ンスの提供に加え、Copilot for Data Factory もパブリックプレビューとなり AI アシスタントを活用したフロー開発が順次利用可能となる予定となっています。 また、GA のタイミングで Virtual Net Data Gateway がパブリックプレビューとなりました。これにより Azure 環境内にある分析データと Microsoft Fabric の通信をよりセキュアに実現できるようになるため、データ連携の選択肢の一つとしての活用が期待されます。 Synapse Data Engineering 大量のデータを変換しレイクハウス アーキテクチャ を構築するデータエンジニアを支援するための機能が Synapse Data Engineering です。Synapse Data Engineering によってデータエンジニアは Notebook を用いた Spark 実行環境を利用可能となります。 現時点で Synapse Data Engineering のランタイムには Spark 3.4、Delta 2.4、 Java 11、 Python 3.10 が含まれており、今後の最新バージョンへの追従は Microsoft Fabric で管理・対応されます。また、ノートブックとレイクハウスの Git 統合、Environment アーティファクト による構成管理、 VS Code 拡張機能 などがパブリックプレビューとなっており、データエンジニア向けの開発環境が順次拡充されていることが伺えます。 Synapse Data Engineering においても Copilot がパブリックプレビューとなっています。これにより Notebook 上で AI と対話しながら任意のコードを記述・実行していくようなことがまもなく実現可能となります。 Synapse Data Science ビジネスにおける洞察・予測のためのデータサイエンス実行管理機能が Synapse Data Science です。データの探索から始まり前処理、モデル作成とその管理までデータサイエンスに必要な機能が網羅的に提供されます。 今回の GA に合わせて Synapse ML 1.0 がリリースされています。これは大規模な 機械学習 のアプリケーションを簡素化する Spark 用の オープンソース ML ライブラリで、MLFlow に加え Azure AI Search でのベクトル検索や Azure Open AI Service 統合のための API などが含まれます。 Synapse Data Engineering の項で述べた Notebook の Copilot は Synapse Data Science でも同様に提供予定となっており、データサイエンス領域における AI 活用を促進する機能がそろった環境といえるかと思います。 Synapse Data Warehouse Microsoft Fabric ではオープン データ形式 をネイティブにサポートする次世代のデータウェアハウスとして Synapse Data Warehouse が提供されます。オープン データ形式 とは OneLake の項で述べた Delta-Parquet 形式のことであり、OneLake 上で管理される Parquet ファイルに対して SQL の API を発行し分析を行うというのが大まかな処理のイメージとなります。 Synapse Data Warehouse についてはパブリックプレビュー後も継続的に機能強化が行われていましたが、今回の GA のタイミングでもいくつか新しい発表がありました。一例をあげると SQLPackage や REST API による プログラマブル な開発のサポート、Query Insights によるソリューション監視、 SQL 動的データ マスキング ( DDM ) を使用したアプリケーションの保護などです。前述の ミラーリング の機能についても、データベースが主対象になりそうなことを踏まえると Synapse Data Warehouse との親和性が高い機能に見えています。 Synapse Real-Time Analytics 昨今の分析に必要なデータは多種多様となっており、IoT デ バイス や API からのリアルタイムデータも例外ではありません。Synapse Real-Time Analytics はログ、イベント、テレメトリといったリアルタイムデータを分析するためのサービスです。 Synapse Real-Time Analytics においてもレイクセントリックな思想は受け継がれており、データが OneLake 上で管理されることに変わりはありません。また、OneLake ショートカットとして Azure Data Explorer のソースデータベースを設定できるため、既存の Azure Data Explorer 環境に対しての KQL 発行といったこれまで Azure 上で実施していた分析エクス ペリエ ンスが Microsoft Fabric 上でも実現可能となっています。 Synapse Real-Time Analytics を理解するうえで重要な要素がイベントストリームです。これは受信したリアルタイムイベントをシームレスに取り込みキャプチャ・変換した後に Microsoft Fabric のさまざまな宛先にルーティングするという、データの中継役を果たします。ソース・宛先ともに複数の形式をサポートしており、リアルタイムデータの分析をする上では欠かせない仕組みといえます。 Power BI Microsoft が長年にわたり提供してきた Power BI が、今回 Microsoft Fabric に統合されました。現在 Power BI をお使いのユーザーは適切なライセンスを割り当てることで自身の環境で Microsoft Fabric の機能を使っていくことが可能になります。 Power BI に関してはパブリックプレビュー公開当初から魅力的な機能が追加されていきました。その一つが Direct Lake モードです。従来の Direct Query モードとインポートモードの長所を掛け合わせた、リアルタイムかつ高速なレポート表示を実現した機能で、今後のレポート開発で標準となっていくことが期待されます。 Power BI Desktop の開発モードで Git 統合がサポートされレポートおよびセマンティックモデル(従来のデー タセット )のバージョン管理が可能となったのも嬉しいアップデートです。現在対応する Git リポジトリ は Azure DevOps のみですが、今後 GitHub への対応がなされていくとより利用の幅が広がってくると思われます。 Data Activator これまで紹介してきた機能は Azure や M365 で類似のサービスが存在していましたが、この項で紹介する Data Activator は Microsoft Fabric で新しく登場した機能です。データ分析においては得られた洞察から何かしらのアクションを起こしていくわけですが、それを人手で実施するのは限界があるため自動化の仕組みが必要となります。 Data Activator はそのようなニーズに応える機能となっており、特定のルールに基づく分析結果をトリガーとしてその後のアクションを実行するまでをノーコードで実装できます。使用例としては、来月の在庫予測が しきい値 を下回りそうな分析結果が出たため Teams で関係者に通知するとともに後続のアクション実行のための API を呼びだすといった処理などが考えられます。 イベントの検知箇所として現在対応しているのは Power BI のセマンティックモデルと Synapse Real-Time Analytics のイベントストリームの 2 か所となっており活用の場面が限られますが、今後拡充されて利用シナリオが広がっていくことを期待したいです。 Purview Power BI と同様に Microsoft Purview も Microsoft Fabric に統合されました。これによって提供されるようになるのが Purview ハブで、これまでデータカタログと監査で分かれていた UI の入り口が一つに統一されます。 Microsoft Fabric 上のアイテムに対してデータカタログおよび監査機能が適用されることとなり、 Microsoft Fabric にデータを集めることで自然にデータガバナンスが向上する仕組みとしていくことも可能といえます。 まとめ 各機能の紹介としては以上となります。ここまで読んでいただくだけでも非常に多くの機能の集合体であることがお分かりいただけたかと思います。個々の機能において紹介しきれていない発表などもたくさんありますので、気になる方は Microsoft の公式ドキュメントやブログもぜひチェックしてみてください。以下にリンクをまとめておきます。 Microsoft Fabric のドキュメント Prepare your data for AI innovation with Microsoft Fabric—now generally available(MSの公式ブログ) Fabric workloads are now generally available!(MSの公式ブログ) 最後までお読みいただきありがとうございました。 アドベントカレンダー は本日から始まり今月いっぱい続いていきます。明日以降も面白い記事が目白押しですので、ぜひご覧ください。 私たちは一緒に働いてくれる仲間を募集しています! クラウドアーキテクト 執筆: @yoneya.fumihiko 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
アバター
XI 本部  クラウド イノベーション センターの米谷です。本記事は 電通国際情報サービス Advent Calendar 2023 の 1 日目の投稿です。今年の アドベントカレンダー の栄えあるトップバッターを務めさせていただきます。よろしくお願いします。 先日実施された Microsoft の年次テクニカルカンファレンス Ignite にて Microsoft Fabric の GA が発表されました! Microsoft Fabric は Microsoft のデータ関連製品として SQL Server 以来最も インパク トのある製品と言われており、 Ignite の基調講演の中でも取り上げられるなど注目を集めています。 Microsoft Fabric には様々な機能があり GA のタイミングで新しい発表も多くあったため、本稿ではそれらの情報を整理し Microsoft Fabric の特徴や魅力を改めて確認していきたいと思います。 はじめに データ分析基盤を取り巻く課題 Microsoft Fabric のコンセプト OneLake Data Factory Synapse Data Engineering Synapse Data Science Synapse Data Warehouse Synapse Real-Time Analytics Power BI Data Activator Purview まとめ はじめに データ分析基盤を取り巻く課題 機能紹介の前に Microsoft Fabric が登場するに至った背景をおさらいしておきたいと思います。データ分析基盤の構成要素はデータレイク、ETL、データウェアハウス、BI など多岐に渡りそれぞれに適したツールがあります。例えば Microsoft の Azure や Microsoft 365 では以下のようなサービスが提供されています。 データレイク : Azure Data Lake Storage Gen2 ETL : Azure Data Factory データウェアハウス : Azure Syanapse Analytics(専用 SQL プール) BI : Microsoft Power BI データカタログ、データガバナンス : Microsoft Purview これらを適切に組み合わせることではじめてデータ分析基盤ができあがります。Azure の場合上記のサービスは PaaS として提供されており比較的容易に構築できますが、それでも相応に労力の割かれる作業となることは事実であり、データを分析するためのスタートラインに立つまでにやることが多いというのが悩みの種となります。 Microsoft Fabric のコンセプト このような背景の中で発表された Microsoft Fabric は、上述の課題解決を狙いとした以下に示す 4 つのコンセプトを持ちます。 オールインワンの SaaS として提供 レイクセントリックな アーキテクチャ ー あらゆるロールのビジネスユーザーを支援 AI(Copilot) 実装 Microsoft Fabric には DWH、ETL、BI といったデータ分析に必要な機能が全て含まれた形で SaaS として提供されているため、ユーザーは導入後すぐにこれらの機能を使いデータ分析を行うことができます。分析に必要なデータは OneLake と呼ばれる場所で集約・管理され、使う機能によってデータを重複管理する必要はありません。データ分析には様々な役割のユーザーが関わりますが、皆が Microsoft Fabricという一つのサービスでコラボレーションできます。搭載されたAI 機能により、分析作業の質やスピードの向上が期待されます。 以降、各機能紹介の中でこれらのコンセプトがどのように組み込まれているかを都度解説します。 OneLake いよいよここから Microsoft Fabric の各機能の紹介に移っていきます。初めに紹介するのは、上述のレイクセントリックな アーキテクチャ ーで中心的な役割を果たす OneLake です。個人のデータ管理のために使用される OneDrive と対比する形で、組織のデータ分析に使用される場所という意味で OneLake という名称が付けられました。OneLake では Azure Data Lake Storage Gen2 ベースのオブジェクトストレージに分析データが Delta-Parquet 形式で保管されます。オープンスタンダードな形式である Delta-Parquet を用いることで、各機能の API が同一のデータに対してアクセス・分析可能になります。 実際に使用するに当たっては、分析対象となるデータをどのように OneLake に持ってくるか?という取り込みにかかるコストが重要になります。この点における解決策として OneLake ではショートカットと ミラーリング という 2 つの機能を提供しています。ショートカットとは ファイルシステム の シンボリックリンク のようなイメージで、データの実体は取り込み元にあるままで Microsoft Fabric で取り扱えるようにする仕組みです。データを移動させることなく分析ができるという非常に強力な機能となっています。一方の ミラーリング は取り込み元のデータをシームレスに OneLake にコピーする仕組みとなっており、データの取り込み作業の簡略化が期待できます。 現時点でショートカットは Azure Data Lake Storage Gen2 や Amazon S3 、Dataverse が、 ミラーリング は Azure SQL Database や Snowflake 、Azure CosmosDB などがそれぞれ対応しています。今後もショートカットにはオブジェクトストレージ系のサービスが、 ミラーリング にはデータベースや NoSQL 系のサービスが追加されていくのではと予想されます。 Data Factory Microsoft Fabric で ETL の役割を果たすのが Data Factory です。Azure Data Factory と同様に 100 を超えるコネクタを有し、オンプレミスや/ クラウド を問わず様々な場所のデータを Microsoft Fabric と連携させることが可能です。 GUI による処理の定義/パイプライン実行/ログの確認が可能となっており、Dataflow Gen2 という新しいエクス ペリエ ンスの提供に加え、Copilot for Data Factory もパブリックプレビューとなり AI アシスタントを活用したフロー開発が順次利用可能となる予定となっています。 また、GA のタイミングで Virtual Net Data Gateway がパブリックプレビューとなりました。これにより Azure 環境内にある分析データと Microsoft Fabric の通信をよりセキュアに実現できるようになるため、データ連携の選択肢の一つとしての活用が期待されます。 Synapse Data Engineering 大量のデータを変換しレイクハウス アーキテクチャ を構築するデータエンジニアを支援するための機能が Synapse Data Engineering です。Synapse Data Engineering によってデータエンジニアは Notebook を用いた Spark 実行環境を利用可能となります。 現時点で Synapse Data Engineering のランタイムには Spark 3.4、Delta 2.4、 Java 11、 Python 3.10 が含まれており、今後の最新バージョンへの追従は Microsoft Fabric で管理・対応されます。また、ノートブックとレイクハウスの Git 統合、Environment アーティファクト による構成管理、 VS Code 拡張機能 などがパブリックプレビューとなっており、データエンジニア向けの開発環境が順次拡充されていることが伺えます。 Synapse Data Engineering においても Copilot がパブリックプレビューとなっています。これにより Notebook 上で AI と対話しながら任意のコードを記述・実行していくようなことがまもなく実現可能となります。 Synapse Data Science ビジネスにおける洞察・予測のためのデータサイエンス実行管理機能が Synapse Data Science です。データの探索から始まり前処理、モデル作成とその管理までデータサイエンスに必要な機能が網羅的に提供されます。 今回の GA に合わせて Synapse ML 1.0 がリリースされています。これは大規模な 機械学習 のアプリケーションを簡素化する Spark 用の オープンソース ML ライブラリで、MLFlow に加え Azure AI Search でのベクトル検索や Azure Open AI Service 統合のための API などが含まれます。 Synapse Data Engineering の項で述べた Notebook の Copilot は Synapse Data Science でも同様に提供予定となっており、データサイエンス領域における AI 活用を促進する機能がそろった環境といえるかと思います。 Synapse Data Warehouse Microsoft Fabric ではオープン データ形式 をネイティブにサポートする次世代のデータウェアハウスとして Synapse Data Warehouse が提供されます。オープン データ形式 とは OneLake の項で述べた Delta-Parquet 形式のことであり、OneLake 上で管理される Parquet ファイルに対して SQL の API を発行し分析を行うというのが大まかな処理のイメージとなります。 Synapse Data Warehouse についてはパブリックプレビュー後も継続的に機能強化が行われていましたが、今回の GA のタイミングでもいくつか新しい発表がありました。一例をあげると SQLPackage や REST API による プログラマブル な開発のサポート、Query Insights によるソリューション監視、 SQL 動的データ マスキング ( DDM ) を使用したアプリケーションの保護などです。前述の ミラーリング の機能についても、データベースが主対象になりそうなことを踏まえると Synapse Data Warehouse との親和性が高い機能に見えています。 Synapse Real-Time Analytics 昨今の分析に必要なデータは多種多様となっており、IoT デ バイス や API からのリアルタイムデータも例外ではありません。Synapse Real-Time Analytics はログ、イベント、テレメトリといったリアルタイムデータを分析するためのサービスです。 Synapse Real-Time Analytics においてもレイクセントリックな思想は受け継がれており、データが OneLake 上で管理されることに変わりはありません。また、OneLake ショートカットとして Azure Data Explorer のソースデータベースを設定できるため、既存の Azure Data Explorer 環境に対しての KQL 発行といったこれまで Azure 上で実施していた分析エクス ペリエ ンスが Microsoft Fabric 上でも実現可能となっています。 Synapse Real-Time Analytics を理解するうえで重要な要素がイベントストリームです。これは受信したリアルタイムイベントをシームレスに取り込みキャプチャ・変換した後に Microsoft Fabric のさまざまな宛先にルーティングするという、データの中継役を果たします。ソース・宛先ともに複数の形式をサポートしており、リアルタイムデータの分析をする上では欠かせない仕組みといえます。 Power BI Microsoft が長年にわたり提供してきた Power BI が、今回 Microsoft Fabric に統合されました。現在 Power BI をお使いのユーザーは適切なライセンスを割り当てることで自身の環境で Microsoft Fabric の機能を使っていくことが可能になります。 Power BI に関してはパブリックプレビュー公開当初から魅力的な機能が追加されていきました。その一つが Direct Lake モードです。従来の Direct Query モードとインポートモードの長所を掛け合わせた、リアルタイムかつ高速なレポート表示を実現した機能で、今後のレポート開発で標準となっていくことが期待されます。 Power BI Desktop の開発モードで Git 統合がサポートされレポートおよびセマンティックモデル(従来のデー タセット )のバージョン管理が可能となったのも嬉しいアップデートです。現在対応する Git リポジトリ は Azure DevOps のみですが、今後 GitHub への対応がなされていくとより利用の幅が広がってくると思われます。 Data Activator これまで紹介してきた機能は Azure や M365 で類似のサービスが存在していましたが、この項で紹介する Data Activator は Microsoft Fabric で新しく登場した機能です。データ分析においては得られた洞察から何かしらのアクションを起こしていくわけですが、それを人手で実施するのは限界があるため自動化の仕組みが必要となります。 Data Activator はそのようなニーズに応える機能となっており、特定のルールに基づく分析結果をトリガーとしてその後のアクションを実行するまでをノーコードで実装できます。使用例としては、来月の在庫予測が しきい値 を下回りそうな分析結果が出たため Teams で関係者に通知するとともに後続のアクション実行のための API を呼びだすといった処理などが考えられます。 イベントの検知箇所として現在対応しているのは Power BI のセマンティックモデルと Synapse Real-Time Analytics のイベントストリームの 2 か所となっており活用の場面が限られますが、今後拡充されて利用シナリオが広がっていくことを期待したいです。 Purview Power BI と同様に Microsoft Purview も Microsoft Fabric に統合されました。これによって提供されるようになるのが Purview ハブで、これまでデータカタログと監査で分かれていた UI の入り口が一つに統一されます。 Microsoft Fabric 上のアイテムに対してデータカタログおよび監査機能が適用されることとなり、 Microsoft Fabric にデータを集めることで自然にデータガバナンスが向上する仕組みとしていくことも可能といえます。 まとめ 各機能の紹介としては以上となります。ここまで読んでいただくだけでも非常に多くの機能の集合体であることがお分かりいただけたかと思います。個々の機能において紹介しきれていない発表などもたくさんありますので、気になる方は Microsoft の公式ドキュメントやブログもぜひチェックしてみてください。以下にリンクをまとめておきます。 Microsoft Fabric のドキュメント Prepare your data for AI innovation with Microsoft Fabric—now generally available(MSの公式ブログ) Fabric workloads are now generally available!(MSの公式ブログ) 最後までお読みいただきありがとうございました。 アドベントカレンダー は本日から始まり今月いっぱい続いていきます。明日以降も面白い記事が目白押しですので、ぜひご覧ください。 私たちは一緒に働いてくれる仲間を募集しています! クラウドアーキテクト 執筆: @yoneya.fumihiko 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
アバター
X イノベーション 本部デジタルエンゲージメントセンターの橋詰です。普段は金融機関向けに Salesforce (Financial Services Cloud)を導入するプロジェクトのPMや、MuleSoft Anypoint Platformを用いたソリューションのビジネス開発などを担当しています。あしかけ2年程かかりましたが、今年、 技術士 ( 情報工学 部門)に合格・登録をすることができました。 技術士 の試験は複数の段階がありまして、2年かかったと言っても実は、一次試験・二次試験(筆記)・二次試験(面接)とそれぞれ一発で合格することができました。 技術士 とはどういった資格なのかと、合格にいたるまでにどんな勉強をしたのかをまとめます。 技術士って何? なぜ受験したの? SIerのエンジニアはどの部門を受けるの? 技術士にはどんな試験があるの? 私がおこなった第一次試験の対策をご紹介 第一次試験の内容 試験の準備 専門科目の対策→普段勉強していれば大丈夫 適性科目の対策→せっかくなので技術者倫理を学ぶ 基礎科目の対策→30代後半はつらい 試験会場の様子 おわりに 技術士 って何? 日本 技術士 会の説明を引用すると、 技術士 とは、 「科学技術に関する技術的専門知識と高等の応用能力及び豊富な実務経験を有し、公益を確保するため、高い技術者倫理を備えた優れた技術者」の育成を図るための、国による資格認定制度( 文部科学省 所管)です。 https://www.engineer.or.jp/contents/about_engineers.html とのことです。知識や実務経験に加えて、技術者としての倫理観を持つことを期待されています。 なぜ受験したの? 受験を考え始めたのは30代中盤でした。当時は「 技術士 」という資格の存在をぼんやりと知っているだけでした。そのころITコンサルの案件でご一緒したエンジニアの先輩方が 技術士 の資格を 保有 していたことや、会社の先輩でもお持ちの方に出会い、触発されたことがきっかけです。中堅エンジニアとして次のステップに進むために挑戦しようと考えました。さらに、技術者倫理について再学習できることと、これまでのエンジニア経験の振り返りに良いと思ったことも動機です。 SIer のエンジニアはどの部門を受けるの? 私は 技術士 の 情報工学 部門: ソフトウェア工学 をターゲットに勉強をしました。IT関連の仕事についている人は技術部門の中の「 情報工学 部門」を目指すことになると思います。さらに技術部門は選択科目に分かれており、コンピュータ科学・ ソフトウェア工学 ・情報システム・情報基盤のいずれかを選ぶことになります。 技術士 にはどんな試験があるの? 簡単にご紹介すると、 第一次試験 基礎科目・適性科目・専門科目に関する択一式試験 第二次試験(筆記) 小論文の論述試験 第二次試験(面接) 面接による口頭試験 が行われます。テストのガイドについては改訂もありますので、日本 技術士 会のホームページをチェックしてください。 https://www.engineer.or.jp/contents/become_engineer.html 私がおこなった第一次試験の対策をご紹介 3つの試験を一回の投稿で書くと長くなりますので、今回は第一次試験の受験対策を紹介します。 第一次試験の内容 第一次試験は択一式試験(つまり、 マークシート 方式)です。基礎科目・適性科目・専門科目の3科目の出題となります。 試験の準備 IT業界では「 技術士 」は比較的マイナーな資格です(一方で「建設」ではかなりメジャー)。そのため、 技術士 情報工学 部門むけの試験勉強に関する情報が少ない状況です。そこで試験対策勉強に必要な情報や傾向を把握するために、網羅的な情報をどうにか収集する必要があります。界隈では有名な「 sukiyaki塾 」というコミュニティサイトでは盛んな情報発信が行われていますのでここは要チェックです。また sukiyaki 塾が出版している試験ガイド本( 独学・過去問で効率的に突破する! 最新版「技術士試験」勉強法 (DOBOOKS) など)もまず通読することがおすすめです。 専門科目の対策→普段勉強していれば大丈夫 さて、個別の対策です。まずは専門科目の対策です。技術部門として自身の専門科目を選択します。私が選択した 情報工学 部門の場合、試験の難易度は「応用 情報処理技術者試験 」の午前試験レベルと認識しておくことが妥当です。普段ITに関する情報のキャッチアップを行い、専門書・技術書を読み、春・秋の 情報処理技術者試験 を受けている人は問題なくクリアできる難易度でした。試験対策用の勉強をする場合は、応用 情報処理技術者試験 の対策本を利用することがおすすめで、そのため学習教材の選択肢も豊富でとっつきやすいです。私は 情報処理技術者試験 の勉強ではTACの教材を利用することが多いため、こちらの問題集( 情報処理技術者試験 ALL IN ONE オールインワン パーフェクトマスター 共通午前1 2024年度版 [出題実績リスト付き 出題可能性が高い問題がわかる!](TAC出版) )を利用しました。 適性科目の対策→せっかくなので技術者倫理を学ぶ 適性科目は、技術者倫理や 技術士 に関連する法律を問う科目です。試験対策は 技術士法 の把握などになります。まずは過去問を解いてみて苦手分野を把握し、知識を補充する対策になります。ぜひおすすめしたいのは、せっかくの機会を利用し「技術者倫理」について数冊本を読んでみることです。会社に勤めている日常で技術者倫理を積極的に学ぶ機会は少ないです。私も貴重な学習機会だと考え、以下のような書籍やサイトを使って学びを深めました。 書籍  技術者倫理の世界 第2版 書籍  失敗学のすすめ (講談社文庫) 最近であれば失敗学に関する新しい書籍が出ています: 新 失敗学 正解をつくる技術 サイト  日本技術士会HP 技術士倫理要領 基礎科目の対策→30代後半はつらい 基礎科目は、科学技術全般に関する基礎知識を問う試験です。実はこの試験が30代後半には一番辛いです。出題範囲は「科学技術全般」(お題目・カテゴリは決まっている)で、難易度は大学学部にて学習する授業のレベル。自分が専門とする分野ならまだしも、物理や化学、電気・電子、環境などの専門外の分野を、30代後半のいま思い出すのはかなり大変でした。学びなおしとなると、範囲も広く、ちょっと途方にくれます・・・。今回はどうにか合格点を取れたので良かったわけですが、学習の過程で下記を感じました。 (そもそも)第一次試験は20代のうちに受験することがおすすめ 大学で学んだ記憶が新しいうちにチャレンジするのが良いですね。 とにかく過去問題をたくさんこなして積み上げる 問題慣れすること、重要テーマを頑張って学びなおし・暗記すること 過去問題については日本 技術士 会のホームページで公開されていますのでこれを利用しましょう。 日本技術士会HP 過去問題(第一次試験) 日本技術士会HP 技術士第一次試験 試験問題の正答 試験会場の様子 先ほども書いた通りIT分野ではマイナーな資格ということもあり、受験者の年齢層は比較的高い印象です。一次試験の会場で見かける他の分野(メジャーな建設や土木など)の受験者には大学生かなという年齢層の人がとても多いです。察するに、一次試験の受験タイミングの理想形は、大学院の入試勉強が終わったあとについでに 技術士 一次試験もチャレンジすることなのかもしれません。その年齢だと専門科目がやや難しく感じるかもしれませんが、年齢が上がった後にぶつかる難関の基礎科目を効率的に勉強・合格できそうです。といっても、私の場合、この資格の存在を知ったのが30代中盤だったわけで…布教活動を頑張ろうと思います。 おわりに 30代後半で受験した 技術士 一次試験の対策方法をまとめました。 普段からITの基礎学習は頑張っておく 適性科目はついでに技術者倫理の勉強をするのがお得 基礎科目は難しいので過去問を頑張ってたくさん解く これで一次試験は独学でもクリアできると思います。なお、当社ではこのような資格取得のための教材費や受験手数料をサポートする制度もあります。今回は下記の支援を受けて受験しました。 資格試験の勉強に利用する書籍の購入費用 試験の受験手数料 加えて、 技術士 合格後の免許登録税なども会社から全額サポートしてもらえました。(合格後の細かいお話は後日書きます) さて次の壁は二次試験(筆記)です。本当の壁はこの筆記です。続きはまた書きたいと思います。 私たちは一緒に働いてくれる仲間を募集しています! Mulesoftコンサルタント(顧客接点DX・CRM領域) CRMソリューションコンサルタント 執筆: @hashizume.hideki 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
X イノベーション 本部デジタルエンゲージメントセンターの橋詰です。普段は金融機関向けに Salesforce (Financial Services Cloud)を導入するプロジェクトのPMや、MuleSoft Anypoint Platformを用いたソリューションのビジネス開発などを担当しています。あしかけ2年程かかりましたが、今年、 技術士 ( 情報工学 部門)に合格・登録をすることができました。 技術士 の試験は複数の段階がありまして、2年かかったと言っても実は、一次試験・二次試験(筆記)・二次試験(面接)とそれぞれ一発で合格することができました。 技術士 とはどういった資格なのかと、合格にいたるまでにどんな勉強をしたのかをまとめます。 技術士って何? なぜ受験したの? SIerのエンジニアはどの部門を受けるの? 技術士にはどんな試験があるの? 私がおこなった第一次試験の対策をご紹介 第一次試験の内容 試験の準備 専門科目の対策→普段勉強していれば大丈夫 適性科目の対策→せっかくなので技術者倫理を学ぶ 基礎科目の対策→30代後半はつらい 試験会場の様子 おわりに 技術士 って何? 日本 技術士 会の説明を引用すると、 技術士 とは、 「科学技術に関する技術的専門知識と高等の応用能力及び豊富な実務経験を有し、公益を確保するため、高い技術者倫理を備えた優れた技術者」の育成を図るための、国による資格認定制度( 文部科学省 所管)です。 https://www.engineer.or.jp/contents/about_engineers.html とのことです。知識や実務経験に加えて、技術者としての倫理観を持つことを期待されています。 なぜ受験したの? 受験を考え始めたのは30代中盤でした。当時は「 技術士 」という資格の存在をぼんやりと知っているだけでした。そのころITコンサルの案件でご一緒したエンジニアの先輩方が 技術士 の資格を 保有 していたことや、会社の先輩でもお持ちの方に出会い、触発されたことがきっかけです。中堅エンジニアとして次のステップに進むために挑戦しようと考えました。さらに、技術者倫理について再学習できることと、これまでのエンジニア経験の振り返りに良いと思ったことも動機です。 SIer のエンジニアはどの部門を受けるの? 私は 技術士 の 情報工学 部門: ソフトウェア工学 をターゲットに勉強をしました。IT関連の仕事についている人は技術部門の中の「 情報工学 部門」を目指すことになると思います。さらに技術部門は選択科目に分かれており、コンピュータ科学・ ソフトウェア工学 ・情報システム・情報基盤のいずれかを選ぶことになります。 技術士 にはどんな試験があるの? 簡単にご紹介すると、 第一次試験 基礎科目・適性科目・専門科目に関する択一式試験 第二次試験(筆記) 小論文の論述試験 第二次試験(面接) 面接による口頭試験 が行われます。テストのガイドについては改訂もありますので、日本 技術士 会のホームページをチェックしてください。 https://www.engineer.or.jp/contents/become_engineer.html 私がおこなった第一次試験の対策をご紹介 3つの試験を一回の投稿で書くと長くなりますので、今回は第一次試験の受験対策を紹介します。 第一次試験の内容 第一次試験は択一式試験(つまり、 マークシート 方式)です。基礎科目・適性科目・専門科目の3科目の出題となります。 試験の準備 IT業界では「 技術士 」は比較的マイナーな資格です(一方で「建設」ではかなりメジャー)。そのため、 技術士 情報工学 部門むけの試験勉強に関する情報が少ない状況です。そこで試験対策勉強に必要な情報や傾向を把握するために、網羅的な情報をどうにか収集する必要があります。界隈では有名な「 sukiyaki塾 」というコミュニティサイトでは盛んな情報発信が行われていますのでここは要チェックです。また sukiyaki 塾が出版している試験ガイド本( 独学・過去問で効率的に突破する! 最新版「技術士試験」勉強法 (DOBOOKS) など)もまず通読することがおすすめです。 専門科目の対策→普段勉強していれば大丈夫 さて、個別の対策です。まずは専門科目の対策です。技術部門として自身の専門科目を選択します。私が選択した 情報工学 部門の場合、試験の難易度は「応用 情報処理技術者試験 」の午前試験レベルと認識しておくことが妥当です。普段ITに関する情報のキャッチアップを行い、専門書・技術書を読み、春・秋の 情報処理技術者試験 を受けている人は問題なくクリアできる難易度でした。試験対策用の勉強をする場合は、応用 情報処理技術者試験 の対策本を利用することがおすすめで、そのため学習教材の選択肢も豊富でとっつきやすいです。私は 情報処理技術者試験 の勉強ではTACの教材を利用することが多いため、こちらの問題集( 情報処理技術者試験 ALL IN ONE オールインワン パーフェクトマスター 共通午前1 2024年度版 [出題実績リスト付き 出題可能性が高い問題がわかる!](TAC出版) )を利用しました。 適性科目の対策→せっかくなので技術者倫理を学ぶ 適性科目は、技術者倫理や 技術士 に関連する法律を問う科目です。試験対策は 技術士法 の把握などになります。まずは過去問を解いてみて苦手分野を把握し、知識を補充する対策になります。ぜひおすすめしたいのは、せっかくの機会を利用し「技術者倫理」について数冊本を読んでみることです。会社に勤めている日常で技術者倫理を積極的に学ぶ機会は少ないです。私も貴重な学習機会だと考え、以下のような書籍やサイトを使って学びを深めました。 書籍  技術者倫理の世界 第2版 書籍  失敗学のすすめ (講談社文庫) 最近であれば失敗学に関する新しい書籍が出ています: 新 失敗学 正解をつくる技術 サイト  日本技術士会HP 技術士倫理要領 基礎科目の対策→30代後半はつらい 基礎科目は、科学技術全般に関する基礎知識を問う試験です。実はこの試験が30代後半には一番辛いです。出題範囲は「科学技術全般」(お題目・カテゴリは決まっている)で、難易度は大学学部にて学習する授業のレベル。自分が専門とする分野ならまだしも、物理や化学、電気・電子、環境などの専門外の分野を、30代後半のいま思い出すのはかなり大変でした。学びなおしとなると、範囲も広く、ちょっと途方にくれます・・・。今回はどうにか合格点を取れたので良かったわけですが、学習の過程で下記を感じました。 (そもそも)第一次試験は20代のうちに受験することがおすすめ 大学で学んだ記憶が新しいうちにチャレンジするのが良いですね。 とにかく過去問題をたくさんこなして積み上げる 問題慣れすること、重要テーマを頑張って学びなおし・暗記すること 過去問題については日本 技術士 会のホームページで公開されていますのでこれを利用しましょう。 日本技術士会HP 過去問題(第一次試験) 日本技術士会HP 技術士第一次試験 試験問題の正答 試験会場の様子 先ほども書いた通りIT分野ではマイナーな資格ということもあり、受験者の年齢層は比較的高い印象です。一次試験の会場で見かける他の分野(メジャーな建設や土木など)の受験者には大学生かなという年齢層の人がとても多いです。察するに、一次試験の受験タイミングの理想形は、大学院の入試勉強が終わったあとについでに 技術士 一次試験もチャレンジすることなのかもしれません。その年齢だと専門科目がやや難しく感じるかもしれませんが、年齢が上がった後にぶつかる難関の基礎科目を効率的に勉強・合格できそうです。といっても、私の場合、この資格の存在を知ったのが30代中盤だったわけで…布教活動を頑張ろうと思います。 おわりに 30代後半で受験した 技術士 一次試験の対策方法をまとめました。 普段からITの基礎学習は頑張っておく 適性科目はついでに技術者倫理の勉強をするのがお得 基礎科目は難しいので過去問を頑張ってたくさん解く これで一次試験は独学でもクリアできると思います。なお、当社ではこのような資格取得のための教材費や受験手数料をサポートする制度もあります。今回は下記の支援を受けて受験しました。 資格試験の勉強に利用する書籍の購入費用 試験の受験手数料 加えて、 技術士 合格後の免許登録税なども会社から全額サポートしてもらえました。(合格後の細かいお話は後日書きます) さて次の壁は二次試験(筆記)です。本当の壁はこの筆記です。続きはまた書きたいと思います。 私たちは一緒に働いてくれる仲間を募集しています! Mulesoftコンサルタント(顧客接点DX・CRM領域) CRMソリューションコンサルタント 執筆: @hashizume.hideki 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
みなさんこんにちは、X(クロス) イノベーション 本部 ソフトウェアデザインセンターの鈴木です。 この度「 AWS Certified Solutions Architect – Professional(以降、SAP-C02)」に合格しました。 この記事では学習した内容や、合格のために必要だと感じたことについてまとめたいと思います。 後半には、若手(社会人歴3年目)の私が、SAP-C02を受検して良かったと感じたことも記載します。 読んでいただいた方の受検の参考に、そして学習へのモチベーションにつながれば幸いです。 筆者について SAP-C02とは? SAP-C02合格までの道のり 学習時間と学習したコンテンツ 書籍 ①AWS認定資格試験テキスト&問題集 AWS認定ソリューションアーキテクト - プロフェッショナル ②AWS認定ソリューションアーキテクト-プロフェッショナル ~試験特性から導き出した演習問題と詳細解説 udemy ③Practice Exam AWS Certified Solutions Architect Professional ④【01版】AWS 認定ソリューションアーキテクト プロフェッショナル模擬試験問題集(全5回分375問) 2回の受検を通して 解けなかった問題や苦手に感じた分野の復習 時間を意識して問題を解き、試験に慣れる 受検してよかったこと AWSサービスを広く学ぶことができた セキュリティやネットワーク、コンテナ技術など基本的なIT技術の知識を得ることができた まとめ 筆者について 新卒3年目 業務での AWS 経験は8ヶ月目(以前はフロントアプリケーション開発に携わっていました) 現在の業務は、 AWS をインフラ基盤とした社内アプリケーションを、フロントエンド・バックエンド・インフラと全体的に開発しています。 SAP-C02とは? SAP-C02の概要は以下のとおりです。詳しくは 公式サイト をご覧ください。 Amazon Web Services ( AWS )の認定資格プログラムの中で、高度な アーキテクチャ スキルと クラウドコンピューティング の専門知識を持つプロフェッショナル向けの資格 問題は75問(択一または多肢選択式)、試験時間は180分 1000点満点で750点が合格ライン SAP-C02合格までの道のり SAP-C02を受検するまでに、 AWS 系の資格は以下の2つを取得しました。 特にアソシエイト資格のSAA-C03は、SAP-C02を受検するにあたりベースとなる知識が求められるため、先に受検しておくことをオススメします。 AWS Certified Cloud Practitioner (CLF-C01) AWS Certified Solutions Architect – Associate (SAA-C03) 本題のSAP-C02は、1回目の受検は704点で不合格、2回目の受検で合格することができました。 1回目の受検から2回目の受検までに行ったことは、「2回の受検を通して」セクションに記載します。 学習時間と学習したコンテンツ 学習時間は、だいたい100 ~ 150時間(2時間×週4~5日×3ヶ月)くらいかかりました。 以下、学習に使用した教材を紹介します。 上からオススメの順に並んでいますので、ご参考にしてみてください。 書籍 ① AWS 認定資格試験テキスト&問題集 AWS 認定ソリューションアーキテクト - プロフェッショナル ⭕️出題範囲を広くカバーしており、よく出題される分野をイラストを交えてまとめてある参考書です。 学習のとっかかりとしてオススメです。 🔺本番レベルの問題数が十分ではないため、他の教材で補う必要があります。 ② AWS 認定ソリューションアーキテクト-プロフェッショナル ~試験特性から導き出した演習問題と詳細解説 ⭕️ ①と比較して、問題の量とその解説が充実しています。 ⭕️ 巻末に付録してある模擬試験は本番レベルで、解説も丁寧です。正解の選択肢だけでなく、不正解の選択肢がなぜダメなのかについてもわかりやすく解説されているため、とても役に立ちました。 🔺出題範囲が旧試験(SAP-C01)を想定しており、新試験(SAP-C02)のカバーされていない範囲は他の問題集で補う必要があります。 udemy ③Practice Exam AWS Certified Solutions Architect Professional 英語の問題集で、2.5回分の演習問題が収録されています。多少読み取りにくくはありますが、 Google翻訳 を使用することで英語が得意でない私でも学習できました。翻訳が怪しいところは英文に戻して読み進めていました。 ⭕️内容としては、実際の試験に出題される問題に近い内容の問題が多く収録されている印象です。また解説欄には、問題に関連する AWS 公式ドキュメントのリンクが掲載されており、わからないところはすぐに公式ドキュメントで調べられてとても良かったです。 ⭕️新試験(SAP-C02)に対応しており、本番に近い内容の問題が多い印象で、英語の問題集ということを差し引いてもオススメできる問題集だと思いました。 ④【01版】 AWS 認定ソリューションアーキテクト プロフェッショナル模擬試験問題集(全5回分375問) ⭕️ 私が試験対策をしていた際、udemyで日本語の問題集はこれ一択でした。5回分の演習問題が収録されており、問題量としては申し分ないでしょう。 5回分の演習問題が収録されているため、試験を想定して時間を意識して解く練習をするのがオススメです。 🔺出題範囲が旧試験(SAP-C01)を想定しており、新試験(SAP-C02)のカバーされていない範囲については他の問題集で補う必要があります。 上記を学習する上で不明点が生じた場合は、まず AWS 公式ドキュメントを調べました。 AWS 公式ドキュメントはとても充実しており、調べたい内容はほとんど文書化されていた印象です。 (公式ドキュメントの情報をもとに問題を作成しているからかもしれませんが) 2回の受検を通して 「SAP-C02合格までの道のり」で記載した通り、2回目の受検で合格しました。1回目の受検から2回目の受検までにしたことは以下のとおりです。 解けなかった問題や苦手に感じた分野の復習 1回目の試験で解けなかった問題や苦手に感じた分野を当日中にメモしておき、集中的に復習しました。"絶対に合格した"という確証がない限り、受検直後にメモしておいた方が賢明です。 時間を意識して問題を解き、試験に慣れる SAP-C02は試験時間が3時間ありますが、各問題の文章量がとても多いため時間に余裕はありません。 (私は見直す時間が全く取れませんでした) そのため「学習時間と学習したコンテンツ」で紹介した③のUdemy教材を新たに学習し、試験のペースを掴むことと長文から顧客要求を素早く理解することを練習しました。 受検してよかったこと 最後に、SAP-C02を受検して良かったことは以下の2点です。 AWS サービスを広く学ぶことができた 本試験は対象サービスの幅が広く、どのようにサービスを組み合わせて顧客要求を達成できるかを問われるため、各サービスへの知識と理解が深まりました。 そのおかげで、学習する前に比べてサービス構成図を見た際にどのようなサービスであるかや、サービス構成上のどこに問題があるかが以前よりわかるようになった気がします。 実際に アーキテクチャ 設計をしないまでも、レビューなどで大いに役立つ知識がつけられたのではないかと思います。 セキュリティやネットワーク、コンテナ技術など基本的な IT技術 の知識を得ることができた 若手ということもあり、セキュリティやネットワーク、コンテナ技術など基本的な IT技術 の知識が乏しかったためとても苦戦しました。しかし、SAP-C02の学習を進めていくうちに副次的に幅広く知識をつけることができました。 (アソシエイト資格と比べると、この辺りの知識がないと解けない問題はたくさんあります) 自分の IT技術 に関する知識の無さに悲しくなることもありましたが、若手の人にこそIT知識の幅を広げるという意味でも本資格に挑戦してみる価値はあると思います。 まとめ 今回は合格体験記と題して、学習した内容や学習して良かったことを紹介いたしました。 学習は大変でしたが、 AWS サービスをより深く学ぶことができ、 IT技術 の知見を広げることができました。 読んでいただいた皆さんの参考に少しでもなれれば幸いです。 最後までお読みいただきありがとうございました。 私たちは一緒に働いてくれる仲間を募集しています! フルサイクルエンジニア 執筆: @suzuki.takuma 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
アバター
みなさんこんにちは、X(クロス) イノベーション 本部 ソフトウェアデザインセンターの鈴木です。 この度「 AWS Certified Solutions Architect – Professional(以降、SAP-C02)」に合格しました。 この記事では学習した内容や、合格のために必要だと感じたことについてまとめたいと思います。 後半には、若手(社会人歴3年目)の私が、SAP-C02を受検して良かったと感じたことも記載します。 読んでいただいた方の受検の参考に、そして学習へのモチベーションにつながれば幸いです。 筆者について SAP-C02とは? SAP-C02合格までの道のり 学習時間と学習したコンテンツ 書籍 ①AWS認定資格試験テキスト&問題集 AWS認定ソリューションアーキテクト - プロフェッショナル ②AWS認定ソリューションアーキテクト-プロフェッショナル ~試験特性から導き出した演習問題と詳細解説 udemy ③Practice Exam AWS Certified Solutions Architect Professional ④【01版】AWS 認定ソリューションアーキテクト プロフェッショナル模擬試験問題集(全5回分375問) 2回の受検を通して 解けなかった問題や苦手に感じた分野の復習 時間を意識して問題を解き、試験に慣れる 受検してよかったこと AWSサービスを広く学ぶことができた セキュリティやネットワーク、コンテナ技術など基本的なIT技術の知識を得ることができた まとめ 筆者について 新卒3年目 業務での AWS 経験は8ヶ月目(以前はフロントアプリケーション開発に携わっていました) 現在の業務は、 AWS をインフラ基盤とした社内アプリケーションを、フロントエンド・バックエンド・インフラと全体的に開発しています。 SAP-C02とは? SAP-C02の概要は以下のとおりです。詳しくは 公式サイト をご覧ください。 Amazon Web Services ( AWS )の認定資格プログラムの中で、高度な アーキテクチャ スキルと クラウドコンピューティング の専門知識を持つプロフェッショナル向けの資格 問題は75問(択一または多肢選択式)、試験時間は180分 1000点満点で750点が合格ライン SAP-C02合格までの道のり SAP-C02を受検するまでに、 AWS 系の資格は以下の2つを取得しました。 特にアソシエイト資格のSAA-C03は、SAP-C02を受検するにあたりベースとなる知識が求められるため、先に受検しておくことをオススメします。 AWS Certified Cloud Practitioner (CLF-C01) AWS Certified Solutions Architect – Associate (SAA-C03) 本題のSAP-C02は、1回目の受検は704点で不合格、2回目の受検で合格することができました。 1回目の受検から2回目の受検までに行ったことは、「2回の受検を通して」セクションに記載します。 学習時間と学習したコンテンツ 学習時間は、だいたい100 ~ 150時間(2時間×週4~5日×3ヶ月)くらいかかりました。 以下、学習に使用した教材を紹介します。 上からオススメの順に並んでいますので、ご参考にしてみてください。 書籍 ① AWS 認定資格試験テキスト&問題集 AWS 認定ソリューションアーキテクト - プロフェッショナル ⭕️出題範囲を広くカバーしており、よく出題される分野をイラストを交えてまとめてある参考書です。 学習のとっかかりとしてオススメです。 🔺本番レベルの問題数が十分ではないため、他の教材で補う必要があります。 ② AWS 認定ソリューションアーキテクト-プロフェッショナル ~試験特性から導き出した演習問題と詳細解説 ⭕️ ①と比較して、問題の量とその解説が充実しています。 ⭕️ 巻末に付録してある模擬試験は本番レベルで、解説も丁寧です。正解の選択肢だけでなく、不正解の選択肢がなぜダメなのかについてもわかりやすく解説されているため、とても役に立ちました。 🔺出題範囲が旧試験(SAP-C01)を想定しており、新試験(SAP-C02)のカバーされていない範囲は他の問題集で補う必要があります。 udemy ③Practice Exam AWS Certified Solutions Architect Professional 英語の問題集で、2.5回分の演習問題が収録されています。多少読み取りにくくはありますが、 Google翻訳 を使用することで英語が得意でない私でも学習できました。翻訳が怪しいところは英文に戻して読み進めていました。 ⭕️内容としては、実際の試験に出題される問題に近い内容の問題が多く収録されている印象です。また解説欄には、問題に関連する AWS 公式ドキュメントのリンクが掲載されており、わからないところはすぐに公式ドキュメントで調べられてとても良かったです。 ⭕️新試験(SAP-C02)に対応しており、本番に近い内容の問題が多い印象で、英語の問題集ということを差し引いてもオススメできる問題集だと思いました。 ④【01版】 AWS 認定ソリューションアーキテクト プロフェッショナル模擬試験問題集(全5回分375問) ⭕️ 私が試験対策をしていた際、udemyで日本語の問題集はこれ一択でした。5回分の演習問題が収録されており、問題量としては申し分ないでしょう。 5回分の演習問題が収録されているため、試験を想定して時間を意識して解く練習をするのがオススメです。 🔺出題範囲が旧試験(SAP-C01)を想定しており、新試験(SAP-C02)のカバーされていない範囲については他の問題集で補う必要があります。 上記を学習する上で不明点が生じた場合は、まず AWS 公式ドキュメントを調べました。 AWS 公式ドキュメントはとても充実しており、調べたい内容はほとんど文書化されていた印象です。 (公式ドキュメントの情報をもとに問題を作成しているからかもしれませんが) 2回の受検を通して 「SAP-C02合格までの道のり」で記載した通り、2回目の受検で合格しました。1回目の受検から2回目の受検までにしたことは以下のとおりです。 解けなかった問題や苦手に感じた分野の復習 1回目の試験で解けなかった問題や苦手に感じた分野を当日中にメモしておき、集中的に復習しました。"絶対に合格した"という確証がない限り、受検直後にメモしておいた方が賢明です。 時間を意識して問題を解き、試験に慣れる SAP-C02は試験時間が3時間ありますが、各問題の文章量がとても多いため時間に余裕はありません。 (私は見直す時間が全く取れませんでした) そのため「学習時間と学習したコンテンツ」で紹介した③のUdemy教材を新たに学習し、試験のペースを掴むことと長文から顧客要求を素早く理解することを練習しました。 受検してよかったこと 最後に、SAP-C02を受検して良かったことは以下の2点です。 AWS サービスを広く学ぶことができた 本試験は対象サービスの幅が広く、どのようにサービスを組み合わせて顧客要求を達成できるかを問われるため、各サービスへの知識と理解が深まりました。 そのおかげで、学習する前に比べてサービス構成図を見た際にどのようなサービスであるかや、サービス構成上のどこに問題があるかが以前よりわかるようになった気がします。 実際に アーキテクチャ 設計をしないまでも、レビューなどで大いに役立つ知識がつけられたのではないかと思います。 セキュリティやネットワーク、コンテナ技術など基本的な IT技術 の知識を得ることができた 若手ということもあり、セキュリティやネットワーク、コンテナ技術など基本的な IT技術 の知識が乏しかったためとても苦戦しました。しかし、SAP-C02の学習を進めていくうちに副次的に幅広く知識をつけることができました。 (アソシエイト資格と比べると、この辺りの知識がないと解けない問題はたくさんあります) 自分の IT技術 に関する知識の無さに悲しくなることもありましたが、若手の人にこそIT知識の幅を広げるという意味でも本資格に挑戦してみる価値はあると思います。 まとめ 今回は合格体験記と題して、学習した内容や学習して良かったことを紹介いたしました。 学習は大変でしたが、 AWS サービスをより深く学ぶことができ、 IT技術 の知見を広げることができました。 読んでいただいた皆さんの参考に少しでもなれれば幸いです。 最後までお読みいただきありがとうございました。 私たちは一緒に働いてくれる仲間を募集しています! フルサイクルエンジニア 執筆: @suzuki.takuma 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
アバター
みなさんこんにちは、 電通国際情報サービス (ISID)X イノベーション 本部ソフトウェアデザインセンターの佐藤太一です。 皆さんは最近発売された 『実践プロパティベーステスト ― PropErとErlang/Elixirではじめよう』 はもう読みましたか? この本は Erlang やElixirを使ってプロパティベーステストというテスト手法について具体的なコードを使って実践的に学習できる本です。非常に素晴らしい本ですが、難しい部分も多いため私は少しずつ読んでいる所です。 この記事では、この本を読むにあたってサンプルコードを動かすための環境を使っているOSに依存せずに作成する方法を説明します。 事前の準備 最小限のDev Container devcontainer.jsonを編集する環境の構築 Erlang用VS Code拡張 テスト用プロファイルで使うライブラリをエディタに認識させる まとめ この記事で紹介している開発環境の構成ファイル .devcontainer/devcontainer.json 事前の準備 この記事が前提とする環境について軽く説明します。 まず、  VS Code  を事前にインストールしておいてください。 次に、 Docker Desktop をインストールして動作する状態にしてください。基本的には単に インストーラ を実行すれば動作する状態になります。 そして、 VS Code に  Dev Containers 拡張をインストールしておいてください。 最後に、作業用のプロジェクト ディレクト リを作成してください。ここでは、pbt という ディレクト リを作成してプロジェクトのルート ディレクト リとしています。 最小限のDev Container まずは、Dev Containerを使って Erlang が提供する公式のDockerイメージを使った開発環境を作成してみましょう。 プロジェクトのルート ディレクト リに、  .devcontainer  という ディレクト リを作って、その中に  devcontainer.json  というファイル名で以下の内容を保存します。 { " name ": " devcontainer-erlang ", " image ": " erlang:slim ", " containerEnv ": { " TZ ": " Asia/Tokyo " } , " runArgs ": [ " --init " ] } name の値は、分かりやすい名前なら何でもいいです。ここでは、devcontainer- erlang としています。 image の値は、 erlang :slim としています。これは公式のイメージ名です。 ベースイメージや Erlang ランタイムのバージョンを別なものにしたい場合には、 https://hub.docker.com/_/erlang から探してください。 containerEnv の値は、コンテナ内で参照される 環境変数 です。ここでは タイムゾーン が  Asia/Tokyo になるよう設定しています。時刻に起因する問題の調査は難しいので、ここで明示的に設定しています。 runArgs の値は、  --init  を渡すことでDockerが  /dev/init  というシグナルハンドリング用のプロセスを起動してくれます。これによってコンテナを安定的にシャットダウンできます。 devcontainer. json を編集する環境の構築 ここから、devcontainer. json を編集しながら開発環境を構築していくので、まずは快適に json ファイルを編集できるようにしましょう。 devcontainer. json には、Dev Containerとして起動した VS Code を構成するための設定項目がありますので、それらを編集します。 { " name ": " devcontainer-erlang ", " image ": " erlang:slim ", " customizations ": { " vscode ": { " settings ": { " editor.renderWhitespace ": " all ", " [json][jsonc] ": { " editor.defaultFormatter ": " esbenp.prettier-vscode ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } } , " extensions ": [ " esbenp.prettier-vscode " ] } } } customizations  というキーがDev Containerの構成を行うための設定項目です。この中に vscode  という項目がありますね。 settings の中では、 VS Code の設定項目を管理します。 editor.renderWhitespace  の値として、  all  を設定しているのは、ファイルの中に紛れ込んだ全角スペースを見つけやすくするためです。私たちが IME を使っている以上、意図しない場所に全角スペースが入り込んでしまい、それによって理解が困難なエラーメッセージを読むことになるのは避けられません。全角スペースが見えていれば、そういったドハマりから抜け出しやすくなります。 [json][jsonc]  の値として、いくつか設定しています。ちなみに、jsoncは、 JSON  with commentsの略称です。 editor.defaultFormatter  の値として、esbenp.prettier- vscode  を設定しています。これによってprettierを使ったフォーマットが行われます。 editor.formatOnSave  の値として、trueを設定することでファイル保存時にフォーマットが行われるようにしています。 editor.codeActionsOnSave  の値として、source.fixAll を有効化することで自動的に補正できるフォーマットエラーをprettierが積極的に補正してくれます。 extensions の中では、Dev Containerとして起動された VS Code にインストールされる VS Code 拡張を列挙します。ここでは、 JSON を自動フォーマットするための  esbenp.prettier-vscode  を設定しています。 Erlang 用 VS Code 拡張 次は、 Erlang 用の VS Code 拡張を追加します。 マーケットプレイス を確認するといくつかの拡張がありますが、一番利用者の多いものを今回は使います。 erlang devcontainer. json のextensionsに拡張を追加すると、以下のようになります。 { " name ": " devcontainer-erlang ", " image ": " erlang:slim ", " customizations ": { " vscode ": { " settings ": { " editor.renderWhitespace ": " all ", " erlang.formattingLineLength ": 200 , " [erlang] ": { " editor.defaultFormatter ": " pgourlain.erlang ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } , " [json][jsonc] ": { " editor.defaultFormatter ": " esbenp.prettier-vscode ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } } , " extensions ": [ " pgourlain.erlang ", " esbenp.prettier-vscode " ] } } } erlang.formattingLineLength の値として、200を設定しています。この設定項目はドキュメントには記載がないので、私の設定値をここに書いています。 [erlang] の値として、いくつか設定しています。何をしているかは [json][jsonc]  の時と同じです。 これで Erlang のアプリケーション開発環境は完成です。しかし、本を読み進めていくと早々に問題にぶつかります。 テスト用プロファイルで使うライブラリをエディタに認識させる 書籍では、PropErというライブラリをrebarというビルドツールに構成するように指示されます。 その結果、rebar.configを以下のように構成します。 { project_plugins , [ rebar3_proper ]} . { profiles , [ { test , [ { erl_opts , [ nowarn_export_all ]} , { deps , [ proper ]} ]} ]} . { erl_opts , [ debug_info ]} . { deps , []} . rebar3では、依存ライブラリをプロファイル毎に管理できるようになっています。 そして、 proper は test プロファイルでのみ参照されます。 ダウンロードされた依存ライブラリは、プロジェクトのルート ディレクト リにある _build ディレクト リ以下に格納されています。 この状態だと、rebarによるビルドは成功するのですが、エディタ上で can't find include lib "proper/include/proper.hrl” といったエラーが出力されます。 このエラーを解決するため VS Code のエディタ上でも、testプロファイル以下にダウンロードされたライブラリを参照するように設定を追加します。 変更した後のdevcontainer. json は以下のようになります。 { " name ": " devcontainer-erlang ", " image ": " erlang:slim ", " customizations ": { " vscode ": { " settings ": { " editor.renderWhitespace ": " all ", " erlang.formattingLineLength ": 200 , " erlang.includePaths ": [ " _build/test/lib " ] , " [erlang] ": { " editor.defaultFormatter ": " pgourlain.erlang ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } , " [json][jsonc] ": { " editor.defaultFormatter ": " esbenp.prettier-vscode ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } } , " extensions ": [ " pgourlain.erlang ", " esbenp.prettier-vscode " ] } } } erlang.includePaths の値として、ライブラリを格納している ディレクト リの 相対パス を記述しています。 まとめ ここまで、Dev Containerで Erlang アプリケーションの開発環境を構築する方法について説明してきました。 普段あまり使っていない プログラミング言語 でも、Dockerベースのコンテナ技術を使えば簡単に開発環境を構築できることがお分かりいただけたんじゃないでしょうか。 特に私が普段使っている Windows では インストーラ を使ったバイナリのインストールは後腐れが残り易いので、本を読み終わったら全てを片付けられて副作用のないDev Containerは非常に便利です。 この記事を読んでいただいたあなたも是非、クリーンな開発環境を構築してプロパティベーステストという応用可能性の高いテスト手法に習熟できることを願っています。 この記事で紹介している開発環境の構成ファイル 最後に作った構成ファイルを紹介します。 .devcontainer/devcontainer. json { " name ": " devcontainer-erlang ", " image ": " erlang:slim ", " customizations ": { " vscode ": { " settings ": { " editor.renderWhitespace ": " all ", " erlang.formattingLineLength ": 200 , " erlang.includePaths ": [ " _build/test/lib " ] , " [erlang] ": { " editor.defaultFormatter ": " pgourlain.erlang ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } , " [json][jsonc] ": { " editor.defaultFormatter ": " esbenp.prettier-vscode ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } } , " extensions ": [ " pgourlain.erlang ", " esbenp.prettier-vscode " ] } } } 執筆: @sato.taichi ( Shodo で執筆されました )
アバター
みなさんこんにちは、 電通国際情報サービス (ISID)X イノベーション 本部ソフトウェアデザインセンターの佐藤太一です。 皆さんは最近発売された 『実践プロパティベーステスト ― PropErとErlang/Elixirではじめよう』 はもう読みましたか? この本は Erlang やElixirを使ってプロパティベーステストというテスト手法について具体的なコードを使って実践的に学習できる本です。非常に素晴らしい本ですが、難しい部分も多いため私は少しずつ読んでいる所です。 この記事では、この本を読むにあたってサンプルコードを動かすための環境を使っているOSに依存せずに作成する方法を説明します。 事前の準備 最小限のDev Container devcontainer.jsonを編集する環境の構築 Erlang用VS Code拡張 テスト用プロファイルで使うライブラリをエディタに認識させる まとめ この記事で紹介している開発環境の構成ファイル .devcontainer/devcontainer.json 事前の準備 この記事が前提とする環境について軽く説明します。 まず、  VS Code  を事前にインストールしておいてください。 次に、 Docker Desktop をインストールして動作する状態にしてください。基本的には単に インストーラ を実行すれば動作する状態になります。 そして、 VS Code に  Dev Containers 拡張をインストールしておいてください。 最後に、作業用のプロジェクト ディレクト リを作成してください。ここでは、pbt という ディレクト リを作成してプロジェクトのルート ディレクト リとしています。 最小限のDev Container まずは、Dev Containerを使って Erlang が提供する公式のDockerイメージを使った開発環境を作成してみましょう。 プロジェクトのルート ディレクト リに、  .devcontainer  という ディレクト リを作って、その中に  devcontainer.json  というファイル名で以下の内容を保存します。 { " name ": " devcontainer-erlang ", " image ": " erlang:slim ", " containerEnv ": { " TZ ": " Asia/Tokyo " } , " runArgs ": [ " --init " ] } name の値は、分かりやすい名前なら何でもいいです。ここでは、devcontainer- erlang としています。 image の値は、 erlang :slim としています。これは公式のイメージ名です。 ベースイメージや Erlang ランタイムのバージョンを別なものにしたい場合には、 https://hub.docker.com/_/erlang から探してください。 containerEnv の値は、コンテナ内で参照される 環境変数 です。ここでは タイムゾーン が  Asia/Tokyo になるよう設定しています。時刻に起因する問題の調査は難しいので、ここで明示的に設定しています。 runArgs の値は、  --init  を渡すことでDockerが  /dev/init  というシグナルハンドリング用のプロセスを起動してくれます。これによってコンテナを安定的にシャットダウンできます。 devcontainer. json を編集する環境の構築 ここから、devcontainer. json を編集しながら開発環境を構築していくので、まずは快適に json ファイルを編集できるようにしましょう。 devcontainer. json には、Dev Containerとして起動した VS Code を構成するための設定項目がありますので、それらを編集します。 { " name ": " devcontainer-erlang ", " image ": " erlang:slim ", " customizations ": { " vscode ": { " settings ": { " editor.renderWhitespace ": " all ", " [json][jsonc] ": { " editor.defaultFormatter ": " esbenp.prettier-vscode ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } } , " extensions ": [ " esbenp.prettier-vscode " ] } } } customizations  というキーがDev Containerの構成を行うための設定項目です。この中に vscode  という項目がありますね。 settings の中では、 VS Code の設定項目を管理します。 editor.renderWhitespace  の値として、  all  を設定しているのは、ファイルの中に紛れ込んだ全角スペースを見つけやすくするためです。私たちが IME を使っている以上、意図しない場所に全角スペースが入り込んでしまい、それによって理解が困難なエラーメッセージを読むことになるのは避けられません。全角スペースが見えていれば、そういったドハマりから抜け出しやすくなります。 [json][jsonc]  の値として、いくつか設定しています。ちなみに、jsoncは、 JSON  with commentsの略称です。 editor.defaultFormatter  の値として、esbenp.prettier- vscode  を設定しています。これによってprettierを使ったフォーマットが行われます。 editor.formatOnSave  の値として、trueを設定することでファイル保存時にフォーマットが行われるようにしています。 editor.codeActionsOnSave  の値として、source.fixAll を有効化することで自動的に補正できるフォーマットエラーをprettierが積極的に補正してくれます。 extensions の中では、Dev Containerとして起動された VS Code にインストールされる VS Code 拡張を列挙します。ここでは、 JSON を自動フォーマットするための  esbenp.prettier-vscode  を設定しています。 Erlang 用 VS Code 拡張 次は、 Erlang 用の VS Code 拡張を追加します。 マーケットプレイス を確認するといくつかの拡張がありますが、一番利用者の多いものを今回は使います。 erlang devcontainer. json のextensionsに拡張を追加すると、以下のようになります。 { " name ": " devcontainer-erlang ", " image ": " erlang:slim ", " customizations ": { " vscode ": { " settings ": { " editor.renderWhitespace ": " all ", " erlang.formattingLineLength ": 200 , " [erlang] ": { " editor.defaultFormatter ": " pgourlain.erlang ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } , " [json][jsonc] ": { " editor.defaultFormatter ": " esbenp.prettier-vscode ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } } , " extensions ": [ " pgourlain.erlang ", " esbenp.prettier-vscode " ] } } } erlang.formattingLineLength の値として、200を設定しています。この設定項目はドキュメントには記載がないので、私の設定値をここに書いています。 [erlang] の値として、いくつか設定しています。何をしているかは [json][jsonc]  の時と同じです。 これで Erlang のアプリケーション開発環境は完成です。しかし、本を読み進めていくと早々に問題にぶつかります。 テスト用プロファイルで使うライブラリをエディタに認識させる 書籍では、PropErというライブラリをrebarというビルドツールに構成するように指示されます。 その結果、rebar.configを以下のように構成します。 { project_plugins , [ rebar3_proper ]} . { profiles , [ { test , [ { erl_opts , [ nowarn_export_all ]} , { deps , [ proper ]} ]} ]} . { erl_opts , [ debug_info ]} . { deps , []} . rebar3では、依存ライブラリをプロファイル毎に管理できるようになっています。 そして、 proper は test プロファイルでのみ参照されます。 ダウンロードされた依存ライブラリは、プロジェクトのルート ディレクト リにある _build ディレクト リ以下に格納されています。 この状態だと、rebarによるビルドは成功するのですが、エディタ上で can't find include lib "proper/include/proper.hrl” といったエラーが出力されます。 このエラーを解決するため VS Code のエディタ上でも、testプロファイル以下にダウンロードされたライブラリを参照するように設定を追加します。 変更した後のdevcontainer. json は以下のようになります。 { " name ": " devcontainer-erlang ", " image ": " erlang:slim ", " customizations ": { " vscode ": { " settings ": { " editor.renderWhitespace ": " all ", " erlang.formattingLineLength ": 200 , " erlang.includePaths ": [ " _build/test/lib " ] , " [erlang] ": { " editor.defaultFormatter ": " pgourlain.erlang ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } , " [json][jsonc] ": { " editor.defaultFormatter ": " esbenp.prettier-vscode ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } } , " extensions ": [ " pgourlain.erlang ", " esbenp.prettier-vscode " ] } } } erlang.includePaths の値として、ライブラリを格納している ディレクト リの 相対パス を記述しています。 まとめ ここまで、Dev Containerで Erlang アプリケーションの開発環境を構築する方法について説明してきました。 普段あまり使っていない プログラミング言語 でも、Dockerベースのコンテナ技術を使えば簡単に開発環境を構築できることがお分かりいただけたんじゃないでしょうか。 特に私が普段使っている Windows では インストーラ を使ったバイナリのインストールは後腐れが残り易いので、本を読み終わったら全てを片付けられて副作用のないDev Containerは非常に便利です。 この記事を読んでいただいたあなたも是非、クリーンな開発環境を構築してプロパティベーステストという応用可能性の高いテスト手法に習熟できることを願っています。 この記事で紹介している開発環境の構成ファイル 最後に作った構成ファイルを紹介します。 .devcontainer/devcontainer. json { " name ": " devcontainer-erlang ", " image ": " erlang:slim ", " customizations ": { " vscode ": { " settings ": { " editor.renderWhitespace ": " all ", " erlang.formattingLineLength ": 200 , " erlang.includePaths ": [ " _build/test/lib " ] , " [erlang] ": { " editor.defaultFormatter ": " pgourlain.erlang ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } , " [json][jsonc] ": { " editor.defaultFormatter ": " esbenp.prettier-vscode ", " editor.formatOnSave ": true , " editor.codeActionsOnSave ": { " source.fixAll ": true } } } , " extensions ": [ " pgourlain.erlang ", " esbenp.prettier-vscode " ] } } } 執筆: @sato.taichi ( Shodo で執筆されました )
アバター
みなさんこんにちは、X(クロス) イノベーション 本部 ソフトウェアデザインセンターの鈴木です。 データベースに Amazon DynamoDB を採用しているWebアプリケーションを、 Amazon RDSを採用したWebアプリケーションにリプレイスしている際に、データ移行で苦戦したことを記事に残します。 背景 実現したいことと、苦戦したこと 実現したいこと アプリケーションとテーブル定義 苦戦したこと 解決方法 要点 DynamoDB→S3へのエクスポート 開発環境へのダウンロード、変換処理 RDSへのインポート まとめ 背景 従来のアプリケーションでは、データベース層にNoSQL型のデータベースであるDynamoDBを採用していました。 しかし、利用ユーザーが増加して パーティション キー以外での検索要件が出てきたことで、フルスキャンをせざるを得ないケースがたびたび発生したためレスポンスタイムやコストの問題が発生していました。 以上のことから、NoSQL型のデータベースより柔軟に検索が可能な、 RDB 型のデータベースであるRDSに移行することとなりました。 実現したいことと、苦戦したこと 実現したいこと 移行元のDynamoDBテーブルからデータをエクスポートし、移行先のアプリケーションのデータベース( PostgreSQL )のテーブル定義に基づいてデータを変換します。最終的には、RDSへデータをインポートすることを目指します。 データの変換・移行には、 AWS Glueや AWS DMS(Database Migration Service)などの AWS サービスを利用することもできます。今回は、開発環境でデータの一部を使いたかったこともあり、開発環境でTypeScriptを用いて変換します。 アプリケーションとテーブル定義 アプリケーションは、Next.js × Prisma を用いて実装しています。 データベースには PostgreSQL を採用しており、記事用に簡略化した移行後のテーブル構成は以下のとおりです。 userテーブルとaccountテーブルがあり、userテーブルのidを外部キーに、accountテーブルとリレーションを築いています。 苦戦したこと DynamoDBからエクスポートしたデータを変換してデータベースにインポートする過程で、SERIAL型であるuserテーブルのidはレコードが作成されるまで確定しません。accountテーブルにレコードを作成する際に、accountテーブルの外部キーであるuser_idは、userテーブルのレコードを作成後にuserテーブルから取得しなければなりません。 また、Webアプリケーションの ソースコード や、アプリケーションが参照しているデータベースの スキーマ にはなるべく手を加えないようにしたいです。 解決方法 要点 今回は次の流れで解決しました。 ①accountテーブルとは別に一時的なaccount_tmpテーブルをデータベースに作成する。 ②userテーブルとaccount_tmpテーブルに変換後のデータをINSERTする。 ③userテーブルからaccount_tmpテーブルのレコードに対応したuser_idを取得して、account_tmpテーブルのレコードをUPDATEする。 ④account_tmpテーブルからaccountテーブルにINSERTする。 以降、詳しくみていきます。( AWS の構成やデータ構造は記事用に簡略化しています) DynamoDB→S3へのエクスポート 記事用にDynamoDBテーブルを作成しました。 パーティション キーにはemailを設定しています。 項目は、以下のとおりです。 email (S) account (L) updated_at (N) created_at (N) test-user1@ example.com [{"name": "test-user1-1"}, {"name": "test-user1-2"}] 1696129200 1696129200 test-user2@ example.com [{"name": "test-user2-1"}] 1696129200 1696129200 test-user3@ example.com [{"name": "test-user3-1"}, {"name": "test-user3-2"}] 1696129200 1696129200 このテー ブルデー タを開発環境に移動させるため、S3 バケット にエクスポートします。 まず、エクスポート用にS3に バケット を作成します。 その後、DynamoDBのコンソール画面から、「エクスポートおよびストリーム」タブから「S3へのエクスポート」を選択することで、先ほど作成したS3 バケット にデータをエクスポートします。 詳しい手順は、詳細は AWSの公式記事 を参照してください。 開発環境へのダウンロード、変換処理 S3のコンソール画面から、先ほどエクスポートしたDynamoDBテーブル情報をダウンロードしてください。 AWS CLI から aws s3 cp s3://[バケット名]/[データが配置されたフォルダパス] [ダウンロード先のフォルダパス] --recursive でもダウンロード可能です。 ダウンロード後のデータは解凍しておいてください。DynamoDBのデータ量が多い場合は複数ファイルに分かれていることもあります。 gunzip ./input/fsjiydg6by6o5cjalruephgpca.json.gz -k 解凍後のデータを開くと、DynamoDBから出力したデータは以下のような形式となっています。DynamoDB JSON 形式と呼ばれるらしいです。 // fsjiydg6by6o5cjalruephgpca.json { " Item ": { " email ": { " S ":" test-user1@example.com " } ," updated_at ": { " N ":" 1696129200 " } ," account ": { " L ": [{ " M ": { " name ": { " S ":" test-user1-1 " }}} , { " M ": { " name ": { " S ":" test-user1-2 " }}}]} ," created_at ": { " N ":" 1696129200 " }} } { " Item ": { " email ": { " S ":" test-user2@example.com " } ," updated_at ": { " N ":" 1696129200 " } ," account ": { " L ": [{ " M ": { " name ": { " S ":" test-user2-1 " }}}]} ," created_at ": { " N ":" 1696129200 " }} } { " Item ": { " email ": { " S ":" test-user3@example.com " } ," updated_at ": { " N ":" 1696129200 " } ," account ": { " L ": [{ " M ": { " name ": { " S ":" test-user3-1 " }}} , { " M ": { " name ": { " S ":" test-user3-2 " }}}]} ," created_at ": { " N ":" 1696129200 " }}} データベース( PostgreSQL )にデータをインポートするため、 CSV 形式に変換します。変換の過程で、DynamoDB JSON 形式を扱いやすい JSON 形式に変換するため @aws-sdk/util-dynamodb というパッケージを用います。 変換に用いた自作の スクリプト を一例として掲載します。 下記のコードをターミナル上で実行し、データを CSV 形式で出力します。 ./node_modules/.bin/ts-node convert.ts ./input ※「./input」はDynamoDBテーブル情報があるフォルダ // convert.ts import * as fs from "fs" ; import * as readline from "readline" ; import { unmarshall } from "@aws-sdk/util-dynamodb" ; import { Parser } from "json2csv" ; // 型を定義 type Account = { name: string ; } type UserTableFormat = { email: string ; createdAt: Date ; updatedAt: Date ; } ; type AccountTableFormat = { name: string ; createdAt: Date ; updateAt: Date ; email: string ; } ; // 出力先のcsvファイルのヘッダーと値を紐づける const userTableFields = [ { label: "email" , value: "email" } , { label: "createdAt" , value: "createdAt" } , { label: "updatedAt" , value: "updatedAt" } , ] ; const accountTableFields = [ { label: "name" , value: "name" } , { label: "createdAt" , value: "createdAt" } , { label: "updatedAt" , value: "updatedAt" } , { label: "email" , value: "email" } , ] ; // 各フォルダ・ファイルを定義 const inputFolder = process .argv [ 2 ] ; const outputFilePath = "./output" ; const outputUserTable = outputFilePath + "/userTable.csv" ; const outputAccountTable = outputFilePath + "/accountTable.csv" ; // 出力先のディレクトリを作成 fs.mkdirSync ( outputFilePath , { recursive: true } ); // 出力ファイルの初期化 fs.writeFileSync ( outputUserTable , "" ); fs.writeFileSync ( outputAccountTable , "" ); // DynamoDBテーブル情報ファイルの一覧を取得 const fileList = fs.readdirSync ( inputFolder ) .filter (( f ) => f.endsWith ( ".json" )); // 変換・書き込み処理 for ( const inputFile of fileList ) { const rs = fs.createReadStream ( inputFolder + "/" + inputFile ); const rl = readline.createInterface ( { input: rs } ); rl.on ( "line" , ( line ) => { // 変換前に余分な文字列を削除 const inputLine = line .slice ( 0 , -1 ) .replace ( /{"Item":/ , "" ) .replace ( /\r?\n/g , "" ); // DynamoDB JSON→JSONに変換 const inputData = unmarshall ( JSON .parse ( inputLine )); // テーブルごとにデータを分割 const userTableRecord: UserTableFormat = { email: inputData.email , createdAt: new Date ( inputData.created_at * 1000 ), updatedAt: new Date ( inputData.updated_at * 1000 ), } ; let accountTableRecords: AccountTableFormat [] | null ; if ( ! inputData.account ) { accountTableRecords = null ; } else { accountTableRecords = inputData.account.map (( a: Account ) => { return { name: a.name , createdAt: new Date ( inputData.created_at * 1000 ), updatedAt: new Date ( inputData.updated_at * 1000 ), email: inputData.email , } } ) } // csv形式にパース const userTableParser = new Parser ( { fields: userTableFields , header: false , withBOM: true } ); const userTableCsv = userTableParser.parse ( userTableRecord ); let accountTableCsv if ( accountTableRecords && accountTableRecords.length > 0 ) { const githubAccountTableParser = new Parser ( { fields: accountTableFields , header: false , withBOM: true } ); accountTableCsv = githubAccountTableParser.parse ( accountTableRecords ); } // テーブルごとにファイル出力 fs.writeFileSync ( outputUserTable , userTableCsv.slice ( 1 ) + "\n" , { flag: "a" } ); if ( accountTableCsv ) { fs.writeFileSync ( outputAccountTable , accountTableCsv.slice ( 1 ) + "\n" , { flag: "a" } ); } } ); } 以上で、データの変換は完了し、outputフォルダに変換後のデータがテーブル単位でファイルとして出力されています。 S3 バケット のルートに「upload」フォルダを作って、これらのファイルをアップロードします。S3のコンソール画面からでも、次の AWS CLI から(以下コマンド)でもアップロード可能です。 aws s3 cp ./output/ s3://[バケット名]/upload/ --recursive RDSへのインポート RDSに対して、 psql コマンドライン を使用してS3にアップロードした csv ファイルデータを反映させていきます。 詳細は省きますが、RDSをプライベートサブネット内に作成している場合、踏み台サーバを使用するなどでデータベースにアクセスしてください。今回は踏み台サーバでポート フォワ ーディングを行い、RDSの対象データベースへ通信できる状態で、以下のコマンドを実行してデータベースに接続します。 パスワードの入力が求められるため、データベースユーザーに対応するパスワードを入力してください。 psql --host=localhost --port=5432 --username=[RDSのユーザー名] --dbname=[RDSのデータベース名] --password postgres 次に、 psql を用いてS3のファイルデータをRDSにインポートするため、以下のコマンドから aws _s3 拡張機能 をインストールします。 CREATE EXTENSION aws_s3 CASCADE; \dx コマンドを実行し、 aws_s3 拡張機能 がインストールされていることを確認します。 postgres=> \dx List of installed extensions Name | Version | Schema | Description -------------+---------+------------+--------------------------------------------- aws_commons | 1.2 | public | Common data types across AWS services aws_s3 | 1.1 | public | AWS S3 extension for importing data from S3 plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language (3 rows) ここが今回の本題です。 課題にも記載しましたが、userテーブルのidはレコードが作成されるまで生成されないため、accountテーブルの外部キーであるuser_idは CSV 形式に変換するタイミングでは確定させることができませんでした。 今回は以下の方法で解決しました。 userテーブルのユニークカラム(email)をフィールドに持つ account_tmpテーブルを作成する。 S3にアップロードした csv ファイルを、userテーブルとaccount_tmpテーブルに取り込む。 userテーブルに作成されたレコードからaccount_tmpテーブルに設定したユニークフィールドをもとにidを取得し、account_tmpテーブルのuser_idを更新する。 account_tmpテーブルのレコードをaccountテーブルにINSERTする。 account_tmpテーブルを削除する。 具体的には以下の SQL ファイルを psql から実行します。 \i data_migration.sql -- data_migration.sql -- 1. account_tmpテーブルを作成する CREATE TABLE " account_tmp " ( " id " SERIAL NOT NULL , " name " TEXT NOT NULL , " user_id " INTEGER , " created_at " TIMESTAMP ( 0 ) NOT NULL DEFAULT CURRENT_TIMESTAMP , " updated_at " TIMESTAMP ( 0 ) NOT NULL DEFAULT CURRENT_TIMESTAMP , " email " TEXT NOT NULL , CONSTRAINT " account_tmp_pkey " PRIMARY KEY ( " id " ) ); -- 2. S3にアップロードしたcsvファイルを、userテーブルとaccount_tmpテーブルに取り込む SELECT aws_s3.table_import_from_s3( ' "account_tmp" ' , -- テーブル名 ' "name", "user_id", "created_at", "updated_at", "email" ' , -- カラム名 ' (format csv) ' , -- ファイル形式 ' bucket-name ' , -- バケット名 ' upload/accountTable.csv ' , -- バケットルートからのファイルパス ' ap-northeast-1 ' -- リージョン ); SELECT aws_s3.table_import_from_s3( ' "user" ' , ' "email", "created_at", "updated_at" ' , ' (format csv) ' , ' bucket-name ' , ' upload/userTable.csv ' , ' ap-northeast-1 ' ); -- 3. ユニークフィールドをもとにidを取得し、account_tmpテーブルのuser_idを更新する UPDATE " account_tmp " SET " userId " = " user " . " id " FROM " user " WHERE " account_tmp " . " email " = " user " . " email " ; -- 4. account_tmpテーブルのレコードをaccountテーブルにINSERTする INSERT INTO " account " ( " name " , " user_id " , " created_at " , " updated_at " ) SELECT " name " , " user_id " , " created_at " , " updated_at " FROM " account_tmp " ; -- 5. account_tmpテーブルを削除する DROP TABLE " account_tmp " ; 以上で無事にRDSへデータを移行できました。 ちなみに開発環境のデータベースに取り込む際は、以下2点を変更してください。 psql でデータベースにログインする際、開発環境のデータベースホスト名・ポート番号・データベース名・ユーザー名に置き換えて実行する。 「data_migration. sql 」の「2. S3にアップロードした csv ファイルを、userテーブルとaccount_tmpテーブルに取り込む」部分を開発環境の csv ファイルからデータを取り込むように修正して、 \i data_migration.sql を実行する。 -- data_migration.sql -- (省略) -- 2. csvファイルをテーブルに取り込む \COPY " account_tmp " ( " name " , " user_id " , " created_at " , " updated_at " , " email " ) FROM ' ./output/accountTable.csv ' DELIMITER ' , ' CSV \COPY " user " ( " email " , " created_at " , " updated_at " ) FROM ' ./output/userTable.csv ' DELIMITER ' , ' CSV -- 3. ユニークフィールドをもとにidを取得し、account_tmpテーブルのuser_idを更新する -- (省略) まとめ 今回は、DynamoDBからRDSへデータを移行する際に苦戦したことを記事に残しました。user_id問題以外にも、DynamoDB JSON の変換方法など色々と勉強になりました。 同じ場面に出くわす機会は少ないと思いますが、どなたかの参考になれば幸いです。 最後までお読みいただきましてありがとうございました。 私たちは一緒に働いてくれる仲間を募集しています! フルサイクルエンジニア 執筆: @suzuki.takuma 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
アバター
みなさんこんにちは、X(クロス) イノベーション 本部 ソフトウェアデザインセンターの鈴木です。 データベースに Amazon DynamoDB を採用しているWebアプリケーションを、 Amazon RDSを採用したWebアプリケーションにリプレイスしている際に、データ移行で苦戦したことを記事に残します。 背景 実現したいことと、苦戦したこと 実現したいこと アプリケーションとテーブル定義 苦戦したこと 解決方法 要点 DynamoDB→S3へのエクスポート 開発環境へのダウンロード、変換処理 RDSへのインポート まとめ 背景 従来のアプリケーションでは、データベース層にNoSQL型のデータベースであるDynamoDBを採用していました。 しかし、利用ユーザーが増加して パーティション キー以外での検索要件が出てきたことで、フルスキャンをせざるを得ないケースがたびたび発生したためレスポンスタイムやコストの問題が発生していました。 以上のことから、NoSQL型のデータベースより柔軟に検索が可能な、 RDB 型のデータベースであるRDSに移行することとなりました。 実現したいことと、苦戦したこと 実現したいこと 移行元のDynamoDBテーブルからデータをエクスポートし、移行先のアプリケーションのデータベース( PostgreSQL )のテーブル定義に基づいてデータを変換します。最終的には、RDSへデータをインポートすることを目指します。 データの変換・移行には、 AWS Glueや AWS DMS(Database Migration Service)などの AWS サービスを利用することもできます。今回は、開発環境でデータの一部を使いたかったこともあり、開発環境でTypeScriptを用いて変換します。 アプリケーションとテーブル定義 アプリケーションは、Next.js × Prisma を用いて実装しています。 データベースには PostgreSQL を採用しており、記事用に簡略化した移行後のテーブル構成は以下のとおりです。 userテーブルとaccountテーブルがあり、userテーブルのidを外部キーに、accountテーブルとリレーションを築いています。 苦戦したこと DynamoDBからエクスポートしたデータを変換してデータベースにインポートする過程で、SERIAL型であるuserテーブルのidはレコードが作成されるまで確定しません。accountテーブルにレコードを作成する際に、accountテーブルの外部キーであるuser_idは、userテーブルのレコードを作成後にuserテーブルから取得しなければなりません。 また、Webアプリケーションの ソースコード や、アプリケーションが参照しているデータベースの スキーマ にはなるべく手を加えないようにしたいです。 解決方法 要点 今回は次の流れで解決しました。 ①accountテーブルとは別に一時的なaccount_tmpテーブルをデータベースに作成する。 ②userテーブルとaccount_tmpテーブルに変換後のデータをINSERTする。 ③userテーブルからaccount_tmpテーブルのレコードに対応したuser_idを取得して、account_tmpテーブルのレコードをUPDATEする。 ④account_tmpテーブルからaccountテーブルにINSERTする。 以降、詳しくみていきます。( AWS の構成やデータ構造は記事用に簡略化しています) DynamoDB→S3へのエクスポート 記事用にDynamoDBテーブルを作成しました。 パーティション キーにはemailを設定しています。 項目は、以下のとおりです。 email (S) account (L) updated_at (N) created_at (N) test-user1@ example.com [{"name": "test-user1-1"}, {"name": "test-user1-2"}] 1696129200 1696129200 test-user2@ example.com [{"name": "test-user2-1"}] 1696129200 1696129200 test-user3@ example.com [{"name": "test-user3-1"}, {"name": "test-user3-2"}] 1696129200 1696129200 このテー ブルデー タを開発環境に移動させるため、S3 バケット にエクスポートします。 まず、エクスポート用にS3に バケット を作成します。 その後、DynamoDBのコンソール画面から、「エクスポートおよびストリーム」タブから「S3へのエクスポート」を選択することで、先ほど作成したS3 バケット にデータをエクスポートします。 詳しい手順は、詳細は AWSの公式記事 を参照してください。 開発環境へのダウンロード、変換処理 S3のコンソール画面から、先ほどエクスポートしたDynamoDBテーブル情報をダウンロードしてください。 AWS CLI から aws s3 cp s3://[バケット名]/[データが配置されたフォルダパス] [ダウンロード先のフォルダパス] --recursive でもダウンロード可能です。 ダウンロード後のデータは解凍しておいてください。DynamoDBのデータ量が多い場合は複数ファイルに分かれていることもあります。 gunzip ./input/fsjiydg6by6o5cjalruephgpca.json.gz -k 解凍後のデータを開くと、DynamoDBから出力したデータは以下のような形式となっています。DynamoDB JSON 形式と呼ばれるらしいです。 // fsjiydg6by6o5cjalruephgpca.json { " Item ": { " email ": { " S ":" test-user1@example.com " } ," updated_at ": { " N ":" 1696129200 " } ," account ": { " L ": [{ " M ": { " name ": { " S ":" test-user1-1 " }}} , { " M ": { " name ": { " S ":" test-user1-2 " }}}]} ," created_at ": { " N ":" 1696129200 " }} } { " Item ": { " email ": { " S ":" test-user2@example.com " } ," updated_at ": { " N ":" 1696129200 " } ," account ": { " L ": [{ " M ": { " name ": { " S ":" test-user2-1 " }}}]} ," created_at ": { " N ":" 1696129200 " }} } { " Item ": { " email ": { " S ":" test-user3@example.com " } ," updated_at ": { " N ":" 1696129200 " } ," account ": { " L ": [{ " M ": { " name ": { " S ":" test-user3-1 " }}} , { " M ": { " name ": { " S ":" test-user3-2 " }}}]} ," created_at ": { " N ":" 1696129200 " }}} データベース( PostgreSQL )にデータをインポートするため、 CSV 形式に変換します。変換の過程で、DynamoDB JSON 形式を扱いやすい JSON 形式に変換するため @aws-sdk/util-dynamodb というパッケージを用います。 変換に用いた自作の スクリプト を一例として掲載します。 下記のコードをターミナル上で実行し、データを CSV 形式で出力します。 ./node_modules/.bin/ts-node convert.ts ./input ※「./input」はDynamoDBテーブル情報があるフォルダ // convert.ts import * as fs from "fs" ; import * as readline from "readline" ; import { unmarshall } from "@aws-sdk/util-dynamodb" ; import { Parser } from "json2csv" ; // 型を定義 type Account = { name: string ; } type UserTableFormat = { email: string ; createdAt: Date ; updatedAt: Date ; } ; type AccountTableFormat = { name: string ; createdAt: Date ; updateAt: Date ; email: string ; } ; // 出力先のcsvファイルのヘッダーと値を紐づける const userTableFields = [ { label: "email" , value: "email" } , { label: "createdAt" , value: "createdAt" } , { label: "updatedAt" , value: "updatedAt" } , ] ; const accountTableFields = [ { label: "name" , value: "name" } , { label: "createdAt" , value: "createdAt" } , { label: "updatedAt" , value: "updatedAt" } , { label: "email" , value: "email" } , ] ; // 各フォルダ・ファイルを定義 const inputFolder = process .argv [ 2 ] ; const outputFilePath = "./output" ; const outputUserTable = outputFilePath + "/userTable.csv" ; const outputAccountTable = outputFilePath + "/accountTable.csv" ; // 出力先のディレクトリを作成 fs.mkdirSync ( outputFilePath , { recursive: true } ); // 出力ファイルの初期化 fs.writeFileSync ( outputUserTable , "" ); fs.writeFileSync ( outputAccountTable , "" ); // DynamoDBテーブル情報ファイルの一覧を取得 const fileList = fs.readdirSync ( inputFolder ) .filter (( f ) => f.endsWith ( ".json" )); // 変換・書き込み処理 for ( const inputFile of fileList ) { const rs = fs.createReadStream ( inputFolder + "/" + inputFile ); const rl = readline.createInterface ( { input: rs } ); rl.on ( "line" , ( line ) => { // 変換前に余分な文字列を削除 const inputLine = line .slice ( 0 , -1 ) .replace ( /{"Item":/ , "" ) .replace ( /\r?\n/g , "" ); // DynamoDB JSON→JSONに変換 const inputData = unmarshall ( JSON .parse ( inputLine )); // テーブルごとにデータを分割 const userTableRecord: UserTableFormat = { email: inputData.email , createdAt: new Date ( inputData.created_at * 1000 ), updatedAt: new Date ( inputData.updated_at * 1000 ), } ; let accountTableRecords: AccountTableFormat [] | null ; if ( ! inputData.account ) { accountTableRecords = null ; } else { accountTableRecords = inputData.account.map (( a: Account ) => { return { name: a.name , createdAt: new Date ( inputData.created_at * 1000 ), updatedAt: new Date ( inputData.updated_at * 1000 ), email: inputData.email , } } ) } // csv形式にパース const userTableParser = new Parser ( { fields: userTableFields , header: false , withBOM: true } ); const userTableCsv = userTableParser.parse ( userTableRecord ); let accountTableCsv if ( accountTableRecords && accountTableRecords.length > 0 ) { const githubAccountTableParser = new Parser ( { fields: accountTableFields , header: false , withBOM: true } ); accountTableCsv = githubAccountTableParser.parse ( accountTableRecords ); } // テーブルごとにファイル出力 fs.writeFileSync ( outputUserTable , userTableCsv.slice ( 1 ) + "\n" , { flag: "a" } ); if ( accountTableCsv ) { fs.writeFileSync ( outputAccountTable , accountTableCsv.slice ( 1 ) + "\n" , { flag: "a" } ); } } ); } 以上で、データの変換は完了し、outputフォルダに変換後のデータがテーブル単位でファイルとして出力されています。 S3 バケット のルートに「upload」フォルダを作って、これらのファイルをアップロードします。S3のコンソール画面からでも、次の AWS CLI から(以下コマンド)でもアップロード可能です。 aws s3 cp ./output/ s3://[バケット名]/upload/ --recursive RDSへのインポート RDSに対して、 psql コマンドライン を使用してS3にアップロードした csv ファイルデータを反映させていきます。 詳細は省きますが、RDSをプライベートサブネット内に作成している場合、踏み台サーバを使用するなどでデータベースにアクセスしてください。今回は踏み台サーバでポート フォワ ーディングを行い、RDSの対象データベースへ通信できる状態で、以下のコマンドを実行してデータベースに接続します。 パスワードの入力が求められるため、データベースユーザーに対応するパスワードを入力してください。 psql --host=localhost --port=5432 --username=[RDSのユーザー名] --dbname=[RDSのデータベース名] --password postgres 次に、 psql を用いてS3のファイルデータをRDSにインポートするため、以下のコマンドから aws _s3 拡張機能 をインストールします。 CREATE EXTENSION aws_s3 CASCADE; \dx コマンドを実行し、 aws_s3 拡張機能 がインストールされていることを確認します。 postgres=> \dx List of installed extensions Name | Version | Schema | Description -------------+---------+------------+--------------------------------------------- aws_commons | 1.2 | public | Common data types across AWS services aws_s3 | 1.1 | public | AWS S3 extension for importing data from S3 plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language (3 rows) ここが今回の本題です。 課題にも記載しましたが、userテーブルのidはレコードが作成されるまで生成されないため、accountテーブルの外部キーであるuser_idは CSV 形式に変換するタイミングでは確定させることができませんでした。 今回は以下の方法で解決しました。 userテーブルのユニークカラム(email)をフィールドに持つ account_tmpテーブルを作成する。 S3にアップロードした csv ファイルを、userテーブルとaccount_tmpテーブルに取り込む。 userテーブルに作成されたレコードからaccount_tmpテーブルに設定したユニークフィールドをもとにidを取得し、account_tmpテーブルのuser_idを更新する。 account_tmpテーブルのレコードをaccountテーブルにINSERTする。 account_tmpテーブルを削除する。 具体的には以下の SQL ファイルを psql から実行します。 \i data_migration.sql -- data_migration.sql -- 1. account_tmpテーブルを作成する CREATE TABLE " account_tmp " ( " id " SERIAL NOT NULL , " name " TEXT NOT NULL , " user_id " INTEGER , " created_at " TIMESTAMP ( 0 ) NOT NULL DEFAULT CURRENT_TIMESTAMP , " updated_at " TIMESTAMP ( 0 ) NOT NULL DEFAULT CURRENT_TIMESTAMP , " email " TEXT NOT NULL , CONSTRAINT " account_tmp_pkey " PRIMARY KEY ( " id " ) ); -- 2. S3にアップロードしたcsvファイルを、userテーブルとaccount_tmpテーブルに取り込む SELECT aws_s3.table_import_from_s3( ' "account_tmp" ' , -- テーブル名 ' "name", "user_id", "created_at", "updated_at", "email" ' , -- カラム名 ' (format csv) ' , -- ファイル形式 ' bucket-name ' , -- バケット名 ' upload/accountTable.csv ' , -- バケットルートからのファイルパス ' ap-northeast-1 ' -- リージョン ); SELECT aws_s3.table_import_from_s3( ' "user" ' , ' "email", "created_at", "updated_at" ' , ' (format csv) ' , ' bucket-name ' , ' upload/userTable.csv ' , ' ap-northeast-1 ' ); -- 3. ユニークフィールドをもとにidを取得し、account_tmpテーブルのuser_idを更新する UPDATE " account_tmp " SET " userId " = " user " . " id " FROM " user " WHERE " account_tmp " . " email " = " user " . " email " ; -- 4. account_tmpテーブルのレコードをaccountテーブルにINSERTする INSERT INTO " account " ( " name " , " user_id " , " created_at " , " updated_at " ) SELECT " name " , " user_id " , " created_at " , " updated_at " FROM " account_tmp " ; -- 5. account_tmpテーブルを削除する DROP TABLE " account_tmp " ; 以上で無事にRDSへデータを移行できました。 ちなみに開発環境のデータベースに取り込む際は、以下2点を変更してください。 psql でデータベースにログインする際、開発環境のデータベースホスト名・ポート番号・データベース名・ユーザー名に置き換えて実行する。 「data_migration. sql 」の「2. S3にアップロードした csv ファイルを、userテーブルとaccount_tmpテーブルに取り込む」部分を開発環境の csv ファイルからデータを取り込むように修正して、 \i data_migration.sql を実行する。 -- data_migration.sql -- (省略) -- 2. csvファイルをテーブルに取り込む \COPY " account_tmp " ( " name " , " user_id " , " created_at " , " updated_at " , " email " ) FROM ' ./output/accountTable.csv ' DELIMITER ' , ' CSV \COPY " user " ( " email " , " created_at " , " updated_at " ) FROM ' ./output/userTable.csv ' DELIMITER ' , ' CSV -- 3. ユニークフィールドをもとにidを取得し、account_tmpテーブルのuser_idを更新する -- (省略) まとめ 今回は、DynamoDBからRDSへデータを移行する際に苦戦したことを記事に残しました。user_id問題以外にも、DynamoDB JSON の変換方法など色々と勉強になりました。 同じ場面に出くわす機会は少ないと思いますが、どなたかの参考になれば幸いです。 最後までお読みいただきましてありがとうございました。 私たちは一緒に働いてくれる仲間を募集しています! フルサイクルエンジニア 執筆: @suzuki.takuma 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 AWS WAF には AWS マネージドルール が複数提供されており、利用することで AWS が定めた条件に一致するリク エス トをブロックしてくれます。各マネージドルールグループには、複数の個別のルールが含まれています。例えば コアルールセット (CRS) マネージドルールグループ には、v1.6 時点で 22 個の個別ルールが含まれています。 マネージドルールグループの個別ルールには、アプリケーションによっては条件が厳しすぎるものもあります。例えば以下の個別ルールによってリク エス トをブロックして欲しくない場合があるかもしれません。 マネージドルール名 検出条件 SizeRestrictions_BODY リク エス トボディサイズが 8 KB を超える場合はブロック EC2MetaDataSSRF_BODY リク エス トボディに「 localhost 」「 127.0.0.1 」の文字列が含まれている場合はブロック(*注1) GenericLFI_BODY リク エス トボディに「../../」の文字列が含まれている場合はブロック、など (*注1) 筆者が確認した条件であり、公式のアナウンスではありません。また他にも条件があるかもしれません。 マネージドルールがアプリケーションの要件に合わない時は、個別のルールのアクションを Count にオーバーライドすることができます。 しかしこれではあらゆる状況においてそのルールによるブロックが無効化されてしまい、マネージドルールを使っている効果が薄れてしまいます。そうではなく、「特定の条件においてのみ」マネージドルールのアクションを Count に変更したい場合があると思います。 こちら でも紹介されているような方法であり、 AWS WAF の ラベル を利用して実現します。 マネージドルールに条件を追加する仕組み まず、特定の条件において「のみ」マネージドルールのアクションを変更するための仕組みを説明します。 マネージドルールの判定条件に一致した場合、一致した目印として特定の「ラベル」がリク エス トに付与されます。ルールアクションを Count にオーバーライドした場合も、ブロックはされなくなりますが「ラベル」は Block の時と変わらず付与されます。例えば EC2MetaDataSSRF_BODY ルールに一致した場合は awswaf:managed:aws:core-rule-set:EC2MetaDataSSRF_Body というラベルが付与されます。付与されたラベルは Web ACL 内の後続のルールからも確認することができます。 マネージドルールグループの後に評価される自作ルールを追加し、Statement に「( Count にオーバーライドした)マネージドルールに一致した場合に付与されるラベル」と「ブロックを有効にしたい条件」を AND 条件で評価させることで、「特定の条件においてのみ」アクションを Count に変更することができます。例えば、リク エス トの URI パスが /api/* であれば EC2MetaDataSSRF_BODY ルールによるブロックを無効にしたいが、他の URI パスではそのまま有効にしたい場合、次の2つの Statement を AND 条件で繋げ、アクションを Block とした自作ルールを追加します。 リク エス トに「awswaf:managed: aws :core-rule-set:EC2MetaDataSSRF_Body」ラベルがある かつ URI パスが /api/* ではない (NotStatement) 場合に、 Block ここからは、これを実際にマネジメントコンソールで試してみます。 (準備)ALBの作成 WAF Web ACL を関連付けるための ALB を作成し、固定レスポンスを返すようにします。 WAF Web ACL 作成 WAF Web ACL を作成し、ALB に関連付けます。 「Create web ACL 」をクリック Web ACL の名前を入力し、前のステップで作成した ALB を関連付け、「Next」をクリック 「Add managed rule groups」をクリック 「 AWS managed rule groups」にある「Core rule set」のスイッチをオン あとはデフォルト設定のまま Web ACL の作成を完了させます。 WAFの動作確認①:マネージドルールの動作確認 WAF Web ACL が関連付けられた状態の ALB にリク エス トを送ってみます。 ボディに何も含まれていない POST リク エス トは、ブロックされることなく ALB に設定した固定レスポンスが返ってきます。 しかしリク エス トボディに「 localhost 」を含めると、WAF にブロックされ 403 が返されます。 個別ルールのアクションのオーバーライド EC2MetaDataSSRF_BODY ルールのアクションを Count にオーバーライドし、リク エス トボディに「 localhost 」があってもブロックされないようにしていきます。 先ほど作成した WAF Web ACL に追加したマネージドルールをチェックし、「Edit」を選択 EC2MetaDataSSRF_BODY ルールアクションを Override to Count に変更し、「Save rule」をクリック 次の画面でも「Save」をクリック WAFの動作確認②:マネージドルール無効化の確認 再びリク エス トボディに「 localhost 」を含めるリク エス トを送信すると、今度はブロックされずに固定レスポンスが返ってきます。 現在、あらゆる状況において EC2MetaDataSSRF_BODY ルールによるブロックが無効化されている状態です。次のステップからは「 URI パスが /api/ から始まる場合に限り、ブロックを無効化する」ようにカスタマイズしていきます。 自作ルールの追加 「Add my own rules and rule groups」をクリック ビジュアルエディタで次のように Statement を組み立て、「Add rule」をクリック 優先順位がマネージドルールグループよりも後ろであることを確認し、「Save」をクリック WAFの動作確認③:自作ルールの確認 再びリク エス トボディに「 localhost 」を含めるリク エス トを送信すると、今度はブロックされました。 しかし、リク エス ト URI を「/ api /hello」とすると、ブロックされずに通過しました。 以上で、マネージドルールグループの個別ルールに条件を追加することができました。 より複雑な条件の場合 以上はシンプルな条件について確認しましたが、条件が複雑な場合の自作ルールの組み方を簡単に説明します。例として以下の場合です。 マネージドルールグループの EC2MetaDataSSRF_BODY ルールと GenericLFI_BODY ルールを対象にしたい リク エス トがこれらのルールに一致した場合、「リク エス ト URI が /api/* 」かつ「 content-type ヘッダーが application/json 」の場合はブロックされないようにしたい。それ以外の場合はブロックしたい このような自作ルールは次のように実現できます。 今のところ AND 条件や OR 条件が多重になるルールはビジュアルエディタで作成できませんので、 JSON エディタに切り替えてルールを編集することになります。 例に示した複雑な条件の自作ルールは、以下のような JSON で作れます。 { " Name ": " custom-body-block ", " Priority ": 1 , " Statement ": { " AndStatement ": { " Statements ": [ { " OrStatement ": { " Statements ": [ { " LabelMatchStatement ": { " Scope ": " LABEL ", " Key ": " awswaf:managed:aws:core-rule-set:EC2MetaDataSSRF_Body " } } , { " LabelMatchStatement ": { " Scope ": " LABEL ", " Key ": " awswaf:managed:aws:core-rule-set:GenericLFI_Body " } } ] } } , { " NotStatement ": { " Statement ": { " AndStatement ": { " Statements ": [ { " ByteMatchStatement ": { " SearchString ": " /api/ ", " FieldToMatch ": { " UriPath ": {} } , " TextTransformations ": [ { " Priority ": 0 , " Type ": " NONE " } ] , " PositionalConstraint ": " STARTS_WITH " } } , { " ByteMatchStatement ": { " SearchString ": " application/json ", " FieldToMatch ": { " SingleHeader ": { " Name ": " content-type " } } , " TextTransformations ": [ { " Priority ": 0 , " Type ": " NONE " } ] , " PositionalConstraint ": " EXACTLY " } } ] } } } } ] } } , " Action ": { " Block ": {} } , " VisibilityConfig ": { " SampledRequestsEnabled ": true , " CloudWatchMetricsEnabled ": true , " MetricName ": " custom-body-block " } } さいごに AWS WAF マネージドルールグループの個別ルールの適用条件を、ラベルと自作ルールを使ってカスタマイズする方法を試しました。最初は難しそうに見えるかもしれませんが、理屈を理解すると柔軟にマネージドルールをカスタマイズできるようになるので、 AWS WAF をより使いこなしたい方はぜひ試してみてください。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア 執筆: @kou.kinyo 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 AWS WAF には AWS マネージドルール が複数提供されており、利用することで AWS が定めた条件に一致するリク エス トをブロックしてくれます。各マネージドルールグループには、複数の個別のルールが含まれています。例えば コアルールセット (CRS) マネージドルールグループ には、v1.6 時点で 22 個の個別ルールが含まれています。 マネージドルールグループの個別ルールには、アプリケーションによっては条件が厳しすぎるものもあります。例えば以下の個別ルールによってリク エス トをブロックして欲しくない場合があるかもしれません。 マネージドルール名 検出条件 SizeRestrictions_BODY リク エス トボディサイズが 8 KB を超える場合はブロック EC2MetaDataSSRF_BODY リク エス トボディに「 localhost 」「 127.0.0.1 」の文字列が含まれている場合はブロック(*注1) GenericLFI_BODY リク エス トボディに「../../」の文字列が含まれている場合はブロック、など (*注1) 筆者が確認した条件であり、公式のアナウンスではありません。また他にも条件があるかもしれません。 マネージドルールがアプリケーションの要件に合わない時は、個別のルールのアクションを Count にオーバーライドすることができます。 しかしこれではあらゆる状況においてそのルールによるブロックが無効化されてしまい、マネージドルールを使っている効果が薄れてしまいます。そうではなく、「特定の条件においてのみ」マネージドルールのアクションを Count に変更したい場合があると思います。 こちら でも紹介されているような方法であり、 AWS WAF の ラベル を利用して実現します。 マネージドルールに条件を追加する仕組み まず、特定の条件において「のみ」マネージドルールのアクションを変更するための仕組みを説明します。 マネージドルールの判定条件に一致した場合、一致した目印として特定の「ラベル」がリク エス トに付与されます。ルールアクションを Count にオーバーライドした場合も、ブロックはされなくなりますが「ラベル」は Block の時と変わらず付与されます。例えば EC2MetaDataSSRF_BODY ルールに一致した場合は awswaf:managed:aws:core-rule-set:EC2MetaDataSSRF_Body というラベルが付与されます。付与されたラベルは Web ACL 内の後続のルールからも確認することができます。 マネージドルールグループの後に評価される自作ルールを追加し、Statement に「( Count にオーバーライドした)マネージドルールに一致した場合に付与されるラベル」と「ブロックを有効にしたい条件」を AND 条件で評価させることで、「特定の条件においてのみ」アクションを Count に変更することができます。例えば、リク エス トの URI パスが /api/* であれば EC2MetaDataSSRF_BODY ルールによるブロックを無効にしたいが、他の URI パスではそのまま有効にしたい場合、次の2つの Statement を AND 条件で繋げ、アクションを Block とした自作ルールを追加します。 リク エス トに「awswaf:managed: aws :core-rule-set:EC2MetaDataSSRF_Body」ラベルがある かつ URI パスが /api/* ではない (NotStatement) 場合に、 Block ここからは、これを実際にマネジメントコンソールで試してみます。 (準備)ALBの作成 WAF Web ACL を関連付けるための ALB を作成し、固定レスポンスを返すようにします。 WAF Web ACL 作成 WAF Web ACL を作成し、ALB に関連付けます。 「Create web ACL 」をクリック Web ACL の名前を入力し、前のステップで作成した ALB を関連付け、「Next」をクリック 「Add managed rule groups」をクリック 「 AWS managed rule groups」にある「Core rule set」のスイッチをオン あとはデフォルト設定のまま Web ACL の作成を完了させます。 WAFの動作確認①:マネージドルールの動作確認 WAF Web ACL が関連付けられた状態の ALB にリク エス トを送ってみます。 ボディに何も含まれていない POST リク エス トは、ブロックされることなく ALB に設定した固定レスポンスが返ってきます。 しかしリク エス トボディに「 localhost 」を含めると、WAF にブロックされ 403 が返されます。 個別ルールのアクションのオーバーライド EC2MetaDataSSRF_BODY ルールのアクションを Count にオーバーライドし、リク エス トボディに「 localhost 」があってもブロックされないようにしていきます。 先ほど作成した WAF Web ACL に追加したマネージドルールをチェックし、「Edit」を選択 EC2MetaDataSSRF_BODY ルールアクションを Override to Count に変更し、「Save rule」をクリック 次の画面でも「Save」をクリック WAFの動作確認②:マネージドルール無効化の確認 再びリク エス トボディに「 localhost 」を含めるリク エス トを送信すると、今度はブロックされずに固定レスポンスが返ってきます。 現在、あらゆる状況において EC2MetaDataSSRF_BODY ルールによるブロックが無効化されている状態です。次のステップからは「 URI パスが /api/ から始まる場合に限り、ブロックを無効化する」ようにカスタマイズしていきます。 自作ルールの追加 「Add my own rules and rule groups」をクリック ビジュアルエディタで次のように Statement を組み立て、「Add rule」をクリック 優先順位がマネージドルールグループよりも後ろであることを確認し、「Save」をクリック WAFの動作確認③:自作ルールの確認 再びリク エス トボディに「 localhost 」を含めるリク エス トを送信すると、今度はブロックされました。 しかし、リク エス ト URI を「/ api /hello」とすると、ブロックされずに通過しました。 以上で、マネージドルールグループの個別ルールに条件を追加することができました。 より複雑な条件の場合 以上はシンプルな条件について確認しましたが、条件が複雑な場合の自作ルールの組み方を簡単に説明します。例として以下の場合です。 マネージドルールグループの EC2MetaDataSSRF_BODY ルールと GenericLFI_BODY ルールを対象にしたい リク エス トがこれらのルールに一致した場合、「リク エス ト URI が /api/* 」かつ「 content-type ヘッダーが application/json 」の場合はブロックされないようにしたい。それ以外の場合はブロックしたい このような自作ルールは次のように実現できます。 今のところ AND 条件や OR 条件が多重になるルールはビジュアルエディタで作成できませんので、 JSON エディタに切り替えてルールを編集することになります。 例に示した複雑な条件の自作ルールは、以下のような JSON で作れます。 { " Name ": " custom-body-block ", " Priority ": 1 , " Statement ": { " AndStatement ": { " Statements ": [ { " OrStatement ": { " Statements ": [ { " LabelMatchStatement ": { " Scope ": " LABEL ", " Key ": " awswaf:managed:aws:core-rule-set:EC2MetaDataSSRF_Body " } } , { " LabelMatchStatement ": { " Scope ": " LABEL ", " Key ": " awswaf:managed:aws:core-rule-set:GenericLFI_Body " } } ] } } , { " NotStatement ": { " Statement ": { " AndStatement ": { " Statements ": [ { " ByteMatchStatement ": { " SearchString ": " /api/ ", " FieldToMatch ": { " UriPath ": {} } , " TextTransformations ": [ { " Priority ": 0 , " Type ": " NONE " } ] , " PositionalConstraint ": " STARTS_WITH " } } , { " ByteMatchStatement ": { " SearchString ": " application/json ", " FieldToMatch ": { " SingleHeader ": { " Name ": " content-type " } } , " TextTransformations ": [ { " Priority ": 0 , " Type ": " NONE " } ] , " PositionalConstraint ": " EXACTLY " } } ] } } } } ] } } , " Action ": { " Block ": {} } , " VisibilityConfig ": { " SampledRequestsEnabled ": true , " CloudWatchMetricsEnabled ": true , " MetricName ": " custom-body-block " } } さいごに AWS WAF マネージドルールグループの個別ルールの適用条件を、ラベルと自作ルールを使ってカスタマイズする方法を試しました。最初は難しそうに見えるかもしれませんが、理屈を理解すると柔軟にマネージドルールをカスタマイズできるようになるので、 AWS WAF をより使いこなしたい方はぜひ試してみてください。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア 執筆: @kou.kinyo 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
こんにちは!金融ソリューション事業部の孫です。 現在、我々はChatGPT全般の活用を積極的に検討しており、その多様な可能性の中には メタバース におけるChatGPTの利用も含まれています。 この観点から、 AWS 上にサーバーレス アーキテクチャ を採用したChatGPT活用アプリケーションの設計と構築を実施いたしました。 はじめに インフラストラクチャの全体像 実装手順 構築手順 事前準備 手順1. Lambda関数の作成 手順2. DynamoDBの作成 手順3. WebSocket API Gatewayの作成 手順4. SNSトピックの作成 機能検証 セッションテスト 複数のクライアントが同時にセッションを持つテスト 終わりに はじめに ChatGPTベースのアプリケーションを構築する際には、2つの一般的な選択肢があります。 一つは既存のアプリケーションにOpenAI API を直接統合すること、もう一つはOpenAI API をラップしてインフラサービス化にすることです。 今回は、以下の点を考慮して、後者の選択をしました: セキュリティリスク:アプリケーション側でOpenAI API Keyを管理する必要があること コスト管理:OpenAIとのやり取りは有料で、ユーザーの質問の頻度と単語数を制御する必要があること 再利用可能性:開発したソリューションは他のプロジェクトに適用可能で、コストを節約できること 今回は、インフラスト ラク チャを設計する前に、以下の要件を明確にしました: 複数のユーザーが同時に一つのOpenAIアカウントを使用できること 従量課金制を実装し、コストを削減すること サーバーの維持コストを削減すること API トラフィック 制御を実装すること OpenAIへのリク エス トの同時実行数を制限すること これらの要件に基づいて、今回は以下のインフラスト ラク チャ設計を完成させました。 インフラスト ラク チャの全体像 本記事では、下記の構成図に基づき、構築作業を進めていきます。 WebSocket API Gateway :クライアントのリク エス トをバックエンドサービスにルーティングするために使用します。 API リク エス トの トラフィック 制御ができます HTTPの30秒の タイムアウト 制限を解決し、503エラーを減らすために、WebSocket接続方式を選択しました meta_connect_handler :ユーザーの認証機能を提供します。 本記事では、インフラ構築に焦点を当てるため、認証に関する実装は対象外としております meta_handler_chat :ユーザーのリク エス トを Amazon SNS サービスに転送する機能を提供します。 ユーザーのリク エス トは SNS を介して処理されるため、OpenAIサーバーへの即時リク エス トが不要となり、非同期処理になります meta_chat :ユーザーからのリク エス トをOpenAIサーバーに送信し、その結果を受け取る機能を提供します。 本記事においては、 LangChain (version: 0.0.317) フレームワーク を活用して、OpenAI API を介してOpenAIとのやり取りを行います LangChain フレームワーク を使用することで、OpenAI API を直接利用することなく、LLM(Large Language Models)アプリケーションの開発を高速化できます ただし、LangChainのバージョン更新は頻繁に行われるため、本記事で使用している API が将来的に非推奨(deprecated)になる可能性にご注意ください。そのため、特定のバージョンを固定することをお勧めします。 meta_disconnect_handler :ユーザーがログアウトした後、その会話履歴を削除する機能を提供します。 Dynamodb :ユーザーの会話履歴を保存するテーブルを作成します。 SNS :ユーザーのリク エス トを非同期に処理するために使用します。 上記の AWS アーキテクチャ 図に記載した番号①〜⑨に沿って、処理の流れを説明します。 ①: ユーザーはWebSocket URL接続を介してChatGPTサービスの利用を開始する ②: 接続は最初にWebSocketのデフォルトの /$Connect ルートにルーティングされ、 meta_connect_handler で接続の認証を実施する ③: ユーザーは /sendprompt ルートを通じてチャット内容を meta_handler_chat に送信する ④: meta_handler_chat が処理した後、ユーザーリク エス トは SNS サービスのトピックに送信する ⑤: SNS はユーザーリク エス トを サブスクリプション meta_chat Functionに送信する ⑥: meta_chat は Langchain を利用し、OpenAIとの対話機能をそろえ、会話の文脈はDynamoDBに保存される ⑦: OpenAIサーバーは質問回答を返し、WebSocket接続を介してユーザーに返却する ⑧: ユーザーがLogoutしたら、 /$disconnect ルートがトリガーされる ⑨: meta_disconnect_handler はDynamoDBのユーザー会話の文脈を削除し、プロセスが終了する 実装手順 構築手順 以下の手順で構築を行います。 Lambda関数の作成 DynamoDBの作成 WebSocket API Gateway の作成 SNS トピックの作成 事前準備 NodeJS開発環境のセットアップ ローカルに Node.js をダウンロードしてインストールします(18.xバージョンを推奨) 本記事で提供されたコードは、Lambdaにコピーすることでそのまま クラウド 環境でビルド・運用が可能です ただし、後述するLangChainレイヤーの作成プロセスにおいてローカル環境でLangChainパッケージをダウンロードする必要があり、その際にはNodeJS環境が使用されることにご注意ください AWS アカウントの作成 AWS アカウントを持っている場合は、対応不要です AWS アカウントをお持ちでない場合は、 カウント作成の流れ を参考に、アカウントを作成してください ※本検証を行う場合、使用する AWS リソースの利用料金が発生する点にご注意ください OpenAIアカウントの作成 OpenAI API のアカウントを作成し API KEYを入手します API KEYの発行手順は こちら を参照してください 手順1. Lambda関数の作成 meta_connect_handler AWS Lambdaコンソールで meta_connect_handler という名前のLambda関数を作成し、ランタイムとしてNode.js 18.xを選択します。 ※上述した通り、本記事ではインフラ構築に焦点を当てるため、認証に関する実装は対象外です。デフォルトで生成されたコードをそのまま使用してください。 meta_handler_chat 上記と同様に AWS Lambdaコンソールで meta_handler_chat という名前のLambda関数を作成します。 この関数はユーザーリク エス トを受け取り、 SNS サービスのトピックに送信する役割を果たします。 この関数に SNS のPublic権限を追加し、 環境変数 で SNS のARN値( SNS_TOPIC_ARN )を設定してください。 具体的な実装コードは以下のとおりで、ユーザーのメッセージ( event.body.user_msg )を取得し、ユーザー接続情報とメッセージ内容を含む SNS のトピックを発行します。 // aws-sdkパッケージをインポートします import { SNSClient, PublishCommand } from "@aws-sdk/client-sns"; const client = new SNSClient(); const topicArn = process.env.SNS_TOPIC_ARN; export const handler = async(event) => { let body; if (typeof event.body === 'string') { body = JSON.parse(event.body); } else { body = event.body; } // ユーザー接続情報とメッセージ内容を含むSNSのトピックを発行します const command = new PublishCommand({ TopicArn:topicArn, Message:JSON.stringify({ requestContext:event.requestContext, payload: body.user_msg, }) }); let response; try{ await client.send(command); }catch (error) { console.log("Error:", JSON.stringify(error)); } }; meta_chat 同様な手順で AWS Lambdaコンソールで meta_chat という名前のLambda関数を作成します。 この関数はLangchainを使用してOpenAIサーバーとのインタ ラク ションする役割を果たします。 DynamoDBおよびAPIGatewayへのアクセス権限を追加し、OpenAI API KEYを 環境変数 として設定してください。 また、Lambdaではlangchainパッケージがないため、ローカルでダウンロードし、Layerとして関数にアップロードする必要があります。 具体的な手順は以下のとおりです: ローカルで npm install langchain を実行し、langchainをインストールします。 生成された node_module フォルダをZIPのパッケージ化します。 ZIPファイルをLayerにアップロードし、関数でlayer依存関係を設定します。 注意:OpenAIサービスの実行時間は3秒を超える可能性があるため、関数の実行時間設定を調整し(3秒 → 1分 )、 タイムアウト の問題を回避してください。 「コード」タブにて、下記のコードをコピーしてください。 // Langchainとaws-sdkパッケージをインポートします import { ChatOpenAI } from "langchain/chat_models/openai"; import { ConversationChain } from "langchain/chains"; import { BufferMemory } from "langchain/memory"; import { DynamoDBChatMessageHistory } from "langchain/stores/message/dynamodb"; import { ApiGatewayManagementApiClient, PostToConnectionCommand } from "@aws-sdk/client-apigatewaymanagementapi"; export const handler = async (event) => { console.log(JSON.stringify(event)); const body = JSON.parse(event.Records[0].Sns.Message); //SNSのトピックから必要な情報(クライアントの接続情報、ユーザーの質問内容のpayload)を読み取ります const requestContext = body.requestContext; const connectionId = requestContext.connectionId; const user_request = body.payload; // apigateway クライアントの初期化 const apigateway_client = new ApiGatewayManagementApiClient({ endpoint: 'https://'+requestContext.domainName + '/' + requestContext.stage, });  // 文脈保存先としてのDynamoDBを設定し、DynamoDBChatMessageHistoryを初期化します const chatHistory = new DynamoDBChatMessageHistory({ tableName: "Conversations", partitionKey: "ConnectionId", sessionId: connectionId, config: { region: "ap-northeast-1", }, }); // const memory = new BufferMemory({ chatHistory: chatHistory, }); // OpenAI model の初期化 const model = new ChatOpenAI({ modelName: "gpt-3.5-turbo", temperature: 0.5 }); // 初期化されたメモリおよびモデルを利用して、ConversationChainを初期化します。 const chain = new ConversationChain({ memory: memory, llm: model, verbose: true }); try { // OpenAIサーバーにリクエストを送信します const response = await chain.call({ input: user_request, }); // OpenAIからの回答を受け取り、それをクライアントに返却します const api_gateway_input = { ConnectionId: connectionId, Data: JSON.stringify(response) };    const command = new PostToConnectionCommand(api_gateway_input); await apigateway_client.send(command); } catch (error) { console.log("Error:", JSON.stringify(error)); } }; meta_disconnect_handler meta_disconnect_handler という名前のLambda関数を作成し、主にユーザーの会話履歴をクリアするために使用されます。 meta_chat と同様に、DynamoDBへのアクセス権限を追加してください。 具体的なコードは以下のとおりです。 // Langchainパッケージをインポートします import { BufferMemory } from "langchain/memory"; import { DynamoDBChatMessageHistory } from "langchain/stores/message/dynamodb"; export const handler = async (event) => { console.log(JSON.stringify(event)); const requestContext = event.requestContext; const connectionId = requestContext.connectionId; const chatHistory = new DynamoDBChatMessageHistory({ tableName: "Conversations", partitionKey: "ConnectionId", sessionId: connectionId, config: { region: "ap-northeast-1", }, }); const memory = new BufferMemory({ chatHistory: chatHistory, }); //DynamoDBから該当するユーザーの会話文脈を削除します await memory.chatHistory.clear(); }; 手順2. DynamoDBの作成 AWS 管理コンソール上で Amazon DynamoDB コンソールを開き、 Conversations という名前のテーブルと パーティション キーを ConnectionId に設定します。 通常、 パーティション キーはユーザーIDにすべきですが、今回ではログイン機能がないため、クライアント接続IDを パーティション キーとして使用します。 手順3. WebSocket API Gateway の作成 コンソールからWebSocket API Gateway を作成します。 ルーティングキー $connect 、 $disconnect 、および sendprompt を追加します。 Lambda関数の統合をそれぞれ設定します。 WebSocket URL( wss ://)を記録します。 手順4. SNS トピックの作成 標準の SNS トピックを作成します。 サブスクリプション を作成し、ポリシーのフィールドでlambdaを選択し、 meta_chat のARNリンクをエンドポイントのフィールドに貼り付けます。 SNS トピックARNをコピーし、 lambda_handle_chat の 環境変数 SNS_TOPIC_ARN の値に貼り付けます。 機能検証 セッションテスト wscatツールのインストール npm install -g wscat を実行し、wscatツールをインストールします。これは AWS が提供するWebSocket API をテストするツールです。 参考資料 。 WebSocket URLへの接続 以下のコマンドを使用して API Gateway に接続します: wscat -c 「WebSocket URL(wss://)」 セッションの開始 質問1「what is your name?」および質問2「What did I ask you just now?」に対する回答の関連性を確認します(文脈確認)。 DynamoDBのデータを確認 DynamoDBで会話履歴を確認します。 セッションの終了 [ctrl + c]を押してセッションを終了し、再度DynamoDBを確認して、以前のセッション記録が削除されたことを確認します。 複数のクライアントが同時にセッションを持つテスト 2つのクライアントで実施している会話がそれぞれ独立して行われることを確認するためのシミュレーションを行います。 終わりに この記事では、 AWS 上でChatGPTベースのインフラスト ラク チャの設計および構築について取り上げました。 今後、本インフラ構成において以下の点についてさらなる改善を行う予定です。 OpenAIのアクセスキーを保護するために AWS Secret Serviceを使用します ユーザー数が増えるにつれて、OpenAIの使用制限に達した場合に備えて、シームレスなアカウント切り替えを実装します より正確な回答を提供するためにVectorDBを統合することを検討しています より対話型のユーザーエクス ペリエ ンスを提供するために、ストリーミング応答モデルに移行します これからもChatGPTの応用シナリオについてさらに探求し、その結果をAIに興味を持つ読者と継続的に共有し続ける予定です。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ(Web3/メタバース/AI) 執筆: @chen.sun 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
こんにちは!金融ソリューション事業部の孫です。 現在、我々はChatGPT全般の活用を積極的に検討しており、その多様な可能性の中には メタバース におけるChatGPTの利用も含まれています。 この観点から、 AWS 上にサーバーレス アーキテクチャ を採用したChatGPT活用アプリケーションの設計と構築を実施いたしました。 はじめに インフラストラクチャの全体像 実装手順 構築手順 事前準備 手順1. Lambda関数の作成 手順2. DynamoDBの作成 手順3. WebSocket API Gatewayの作成 手順4. SNSトピックの作成 機能検証 セッションテスト 複数のクライアントが同時にセッションを持つテスト 終わりに はじめに ChatGPTベースのアプリケーションを構築する際には、2つの一般的な選択肢があります。 一つは既存のアプリケーションにOpenAI API を直接統合すること、もう一つはOpenAI API をラップしてインフラサービス化にすることです。 今回は、以下の点を考慮して、後者の選択をしました: セキュリティリスク:アプリケーション側でOpenAI API Keyを管理する必要があること コスト管理:OpenAIとのやり取りは有料で、ユーザーの質問の頻度と単語数を制御する必要があること 再利用可能性:開発したソリューションは他のプロジェクトに適用可能で、コストを節約できること 今回は、インフラスト ラク チャを設計する前に、以下の要件を明確にしました: 複数のユーザーが同時に一つのOpenAIアカウントを使用できること 従量課金制を実装し、コストを削減すること サーバーの維持コストを削減すること API トラフィック 制御を実装すること OpenAIへのリク エス トの同時実行数を制限すること これらの要件に基づいて、今回は以下のインフラスト ラク チャ設計を完成させました。 インフラスト ラク チャの全体像 本記事では、下記の構成図に基づき、構築作業を進めていきます。 WebSocket API Gateway :クライアントのリク エス トをバックエンドサービスにルーティングするために使用します。 API リク エス トの トラフィック 制御ができます HTTPの30秒の タイムアウト 制限を解決し、503エラーを減らすために、WebSocket接続方式を選択しました meta_connect_handler :ユーザーの認証機能を提供します。 本記事では、インフラ構築に焦点を当てるため、認証に関する実装は対象外としております meta_handler_chat :ユーザーのリク エス トを Amazon SNS サービスに転送する機能を提供します。 ユーザーのリク エス トは SNS を介して処理されるため、OpenAIサーバーへの即時リク エス トが不要となり、非同期処理になります meta_chat :ユーザーからのリク エス トをOpenAIサーバーに送信し、その結果を受け取る機能を提供します。 本記事においては、 LangChain (version: 0.0.317) フレームワーク を活用して、OpenAI API を介してOpenAIとのやり取りを行います LangChain フレームワーク を使用することで、OpenAI API を直接利用することなく、LLM(Large Language Models)アプリケーションの開発を高速化できます ただし、LangChainのバージョン更新は頻繁に行われるため、本記事で使用している API が将来的に非推奨(deprecated)になる可能性にご注意ください。そのため、特定のバージョンを固定することをお勧めします。 meta_disconnect_handler :ユーザーがログアウトした後、その会話履歴を削除する機能を提供します。 Dynamodb :ユーザーの会話履歴を保存するテーブルを作成します。 SNS :ユーザーのリク エス トを非同期に処理するために使用します。 上記の AWS アーキテクチャ 図に記載した番号①〜⑨に沿って、処理の流れを説明します。 ①: ユーザーはWebSocket URL接続を介してChatGPTサービスの利用を開始する ②: 接続は最初にWebSocketのデフォルトの /$Connect ルートにルーティングされ、 meta_connect_handler で接続の認証を実施する ③: ユーザーは /sendprompt ルートを通じてチャット内容を meta_handler_chat に送信する ④: meta_handler_chat が処理した後、ユーザーリク エス トは SNS サービスのトピックに送信する ⑤: SNS はユーザーリク エス トを サブスクリプション meta_chat Functionに送信する ⑥: meta_chat は Langchain を利用し、OpenAIとの対話機能をそろえ、会話の文脈はDynamoDBに保存される ⑦: OpenAIサーバーは質問回答を返し、WebSocket接続を介してユーザーに返却する ⑧: ユーザーがLogoutしたら、 /$disconnect ルートがトリガーされる ⑨: meta_disconnect_handler はDynamoDBのユーザー会話の文脈を削除し、プロセスが終了する 実装手順 構築手順 以下の手順で構築を行います。 Lambda関数の作成 DynamoDBの作成 WebSocket API Gateway の作成 SNS トピックの作成 事前準備 NodeJS開発環境のセットアップ ローカルに Node.js をダウンロードしてインストールします(18.xバージョンを推奨) 本記事で提供されたコードは、Lambdaにコピーすることでそのまま クラウド 環境でビルド・運用が可能です ただし、後述するLangChainレイヤーの作成プロセスにおいてローカル環境でLangChainパッケージをダウンロードする必要があり、その際にはNodeJS環境が使用されることにご注意ください AWS アカウントの作成 AWS アカウントを持っている場合は、対応不要です AWS アカウントをお持ちでない場合は、 カウント作成の流れ を参考に、アカウントを作成してください ※本検証を行う場合、使用する AWS リソースの利用料金が発生する点にご注意ください OpenAIアカウントの作成 OpenAI API のアカウントを作成し API KEYを入手します API KEYの発行手順は こちら を参照してください 手順1. Lambda関数の作成 meta_connect_handler AWS Lambdaコンソールで meta_connect_handler という名前のLambda関数を作成し、ランタイムとしてNode.js 18.xを選択します。 ※上述した通り、本記事ではインフラ構築に焦点を当てるため、認証に関する実装は対象外です。デフォルトで生成されたコードをそのまま使用してください。 meta_handler_chat 上記と同様に AWS Lambdaコンソールで meta_handler_chat という名前のLambda関数を作成します。 この関数はユーザーリク エス トを受け取り、 SNS サービスのトピックに送信する役割を果たします。 この関数に SNS のPublic権限を追加し、 環境変数 で SNS のARN値( SNS_TOPIC_ARN )を設定してください。 具体的な実装コードは以下のとおりで、ユーザーのメッセージ( event.body.user_msg )を取得し、ユーザー接続情報とメッセージ内容を含む SNS のトピックを発行します。 // aws-sdkパッケージをインポートします import { SNSClient, PublishCommand } from "@aws-sdk/client-sns"; const client = new SNSClient(); const topicArn = process.env.SNS_TOPIC_ARN; export const handler = async(event) => { let body; if (typeof event.body === 'string') { body = JSON.parse(event.body); } else { body = event.body; } // ユーザー接続情報とメッセージ内容を含むSNSのトピックを発行します const command = new PublishCommand({ TopicArn:topicArn, Message:JSON.stringify({ requestContext:event.requestContext, payload: body.user_msg, }) }); let response; try{ await client.send(command); }catch (error) { console.log("Error:", JSON.stringify(error)); } }; meta_chat 同様な手順で AWS Lambdaコンソールで meta_chat という名前のLambda関数を作成します。 この関数はLangchainを使用してOpenAIサーバーとのインタ ラク ションする役割を果たします。 DynamoDBおよびAPIGatewayへのアクセス権限を追加し、OpenAI API KEYを 環境変数 として設定してください。 また、Lambdaではlangchainパッケージがないため、ローカルでダウンロードし、Layerとして関数にアップロードする必要があります。 具体的な手順は以下のとおりです: ローカルで npm install langchain を実行し、langchainをインストールします。 生成された node_module フォルダをZIPのパッケージ化します。 ZIPファイルをLayerにアップロードし、関数でlayer依存関係を設定します。 注意:OpenAIサービスの実行時間は3秒を超える可能性があるため、関数の実行時間設定を調整し(3秒 → 1分 )、 タイムアウト の問題を回避してください。 「コード」タブにて、下記のコードをコピーしてください。 // Langchainとaws-sdkパッケージをインポートします import { ChatOpenAI } from "langchain/chat_models/openai"; import { ConversationChain } from "langchain/chains"; import { BufferMemory } from "langchain/memory"; import { DynamoDBChatMessageHistory } from "langchain/stores/message/dynamodb"; import { ApiGatewayManagementApiClient, PostToConnectionCommand } from "@aws-sdk/client-apigatewaymanagementapi"; export const handler = async (event) => { console.log(JSON.stringify(event)); const body = JSON.parse(event.Records[0].Sns.Message); //SNSのトピックから必要な情報(クライアントの接続情報、ユーザーの質問内容のpayload)を読み取ります const requestContext = body.requestContext; const connectionId = requestContext.connectionId; const user_request = body.payload; // apigateway クライアントの初期化 const apigateway_client = new ApiGatewayManagementApiClient({ endpoint: 'https://'+requestContext.domainName + '/' + requestContext.stage, });  // 文脈保存先としてのDynamoDBを設定し、DynamoDBChatMessageHistoryを初期化します const chatHistory = new DynamoDBChatMessageHistory({ tableName: "Conversations", partitionKey: "ConnectionId", sessionId: connectionId, config: { region: "ap-northeast-1", }, }); // const memory = new BufferMemory({ chatHistory: chatHistory, }); // OpenAI model の初期化 const model = new ChatOpenAI({ modelName: "gpt-3.5-turbo", temperature: 0.5 }); // 初期化されたメモリおよびモデルを利用して、ConversationChainを初期化します。 const chain = new ConversationChain({ memory: memory, llm: model, verbose: true }); try { // OpenAIサーバーにリクエストを送信します const response = await chain.call({ input: user_request, }); // OpenAIからの回答を受け取り、それをクライアントに返却します const api_gateway_input = { ConnectionId: connectionId, Data: JSON.stringify(response) };    const command = new PostToConnectionCommand(api_gateway_input); await apigateway_client.send(command); } catch (error) { console.log("Error:", JSON.stringify(error)); } }; meta_disconnect_handler meta_disconnect_handler という名前のLambda関数を作成し、主にユーザーの会話履歴をクリアするために使用されます。 meta_chat と同様に、DynamoDBへのアクセス権限を追加してください。 具体的なコードは以下のとおりです。 // Langchainパッケージをインポートします import { BufferMemory } from "langchain/memory"; import { DynamoDBChatMessageHistory } from "langchain/stores/message/dynamodb"; export const handler = async (event) => { console.log(JSON.stringify(event)); const requestContext = event.requestContext; const connectionId = requestContext.connectionId; const chatHistory = new DynamoDBChatMessageHistory({ tableName: "Conversations", partitionKey: "ConnectionId", sessionId: connectionId, config: { region: "ap-northeast-1", }, }); const memory = new BufferMemory({ chatHistory: chatHistory, }); //DynamoDBから該当するユーザーの会話文脈を削除します await memory.chatHistory.clear(); }; 手順2. DynamoDBの作成 AWS 管理コンソール上で Amazon DynamoDB コンソールを開き、 Conversations という名前のテーブルと パーティション キーを ConnectionId に設定します。 通常、 パーティション キーはユーザーIDにすべきですが、今回ではログイン機能がないため、クライアント接続IDを パーティション キーとして使用します。 手順3. WebSocket API Gateway の作成 コンソールからWebSocket API Gateway を作成します。 ルーティングキー $connect 、 $disconnect 、および sendprompt を追加します。 Lambda関数の統合をそれぞれ設定します。 WebSocket URL( wss ://)を記録します。 手順4. SNS トピックの作成 標準の SNS トピックを作成します。 サブスクリプション を作成し、ポリシーのフィールドでlambdaを選択し、 meta_chat のARNリンクをエンドポイントのフィールドに貼り付けます。 SNS トピックARNをコピーし、 lambda_handle_chat の 環境変数 SNS_TOPIC_ARN の値に貼り付けます。 機能検証 セッションテスト wscatツールのインストール npm install -g wscat を実行し、wscatツールをインストールします。これは AWS が提供するWebSocket API をテストするツールです。 参考資料 。 WebSocket URLへの接続 以下のコマンドを使用して API Gateway に接続します: wscat -c 「WebSocket URL(wss://)」 セッションの開始 質問1「what is your name?」および質問2「What did I ask you just now?」に対する回答の関連性を確認します(文脈確認)。 DynamoDBのデータを確認 DynamoDBで会話履歴を確認します。 セッションの終了 [ctrl + c]を押してセッションを終了し、再度DynamoDBを確認して、以前のセッション記録が削除されたことを確認します。 複数のクライアントが同時にセッションを持つテスト 2つのクライアントで実施している会話がそれぞれ独立して行われることを確認するためのシミュレーションを行います。 終わりに この記事では、 AWS 上でChatGPTベースのインフラスト ラク チャの設計および構築について取り上げました。 今後、本インフラ構成において以下の点についてさらなる改善を行う予定です。 OpenAIのアクセスキーを保護するために AWS Secret Serviceを使用します ユーザー数が増えるにつれて、OpenAIの使用制限に達した場合に備えて、シームレスなアカウント切り替えを実装します より正確な回答を提供するためにVectorDBを統合することを検討しています より対話型のユーザーエクス ペリエ ンスを提供するために、ストリーミング応答モデルに移行します これからもChatGPTの応用シナリオについてさらに探求し、その結果をAIに興味を持つ読者と継続的に共有し続ける予定です。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ(Web3/メタバース/AI) 執筆: @chen.sun 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
皆さんこんにちは。グループ経営ソリューション事業部グループ経営 コンサルティング 第2ユニット一般会計 コンサルティング 部第2グループ(FAC2部)に所属している小林です。 FAC2部では自社製品である「Ci X (サイクロス)」という会計システムパッケージの新規開発・導入・保守を行っており、私は主にその保守業務を担当しています。 この記事ではISIDに興味をお持ちの就活生の方々向けに私がISIDに入社して初めて担当した業務から学んだことについて、自身の振り返りの意味も込めてご紹介したいと思います。 あと、Ci Xに関しては こちら も参考にしてみてください! 自己紹介 まずは自己紹介いたします。 私は2022年に新卒入社し、半年の研修を経て、現在は2年目の勤務になります。 大学では院まで進学し、 放射線 系の研究をしていました。 そのままの進路でいくのならば、メーカー勤務や 原子力 関係の企業に就職するのが王道でした。 物理という学問は好きでしたし、研究室も自分で望んで所属しましたが、大学4年間で勉強した物理の理論を、研究室で応用することは少なく、愚直に地味な実験を繰り返す成果の見えない生活が率直に自分には合っていませんでした。そんな時にHP係を担当しまして、学べば学ぶほど、スキルが身に付くのを感じ、研究室のHPを管理したり、学会のHPを作成することが楽しかったのを覚えています。 ささいな理由ではありましたが、本当に自分のやりたいことって何だろうと考えた時に気づいたらIT業界を志すようになっていました。就活では上手くいかないことだらけでしたが、自分の率直な思いを面白いと聞いてくれたのがISIDで、IT経験が特にない私でも希望していた開発の部署に配属させてくれました。 そして現在、私は自社製品の保守業務からスタートしています。 配属されてから一年も経過はしていませんが、業務はかなり幅広いです。 今回はそれについて広く浅く紹介いたします。 保守の仕事内容について 保守業務のおおまかな流れは製品のリリース後、まず、お客様が製品を使用していて何かしらお問い合わせが生じた際にその旨を保守窓口が受け取り、保守チームに対応を要求します。そしてその後、保守チームは再現調査や原因究明を行って不具合かどうかを判断し、必要があれば設計を変更したり、中身の実装を修正したりして仕様変更対応を行い、テストをします。 以下では私が携わった範囲で担当した業務プロセスを私自身の所感も含めて説明します。 1.原因調査 トラブルシューティング の入り口になるプロセスです。起こってしまったトラブルに対して何が原因だったのか監査ログやシステムログなどを通して原因を探ります。 このプロセスはいざやってみるとどの工程の中でも直感とスキル、判断力が必要で、これを即座にできる人は保守としての力が特に強い人なのだと個人的に思っています。 2.設計 もし、仕様変更が必要な場合、設計を修正することがあります。欠陥修正に該当する設計書の内容を読み込んで画面定義やロジックなどどこを修正すべきなのか判断し、修正します。特にロジックが難しく、簿記の知識も絡む箇所もあるので、何度見返しても不明な部分に関しては先輩社員に聞きながら進めていました。 3.実装 上記の設計修正が完了したあと、その設計に基づいて実際に内部の実装も変更します。 実装で用いる技術要素は以下です。 バックエンド技術( Java , Spring Boot, Thymeleaf, PostgreSQL 等) フロントエンド技術( HTML5 、TypeScript、Vue.js 等) 業務は新卒の研修で学んだことが直接生きており、改めて研修の大切さを実感しました。 4.テスト 実装が完了した後はテストを行い、機能に問題がないか不具合チェックをします。直接変更してはいなくともその変更の影響を受けたところに対してバグが出てしまうこともあるため、機能のテストだけでなく、その周辺に関してもテストをします。配属直後はこのプロセスから携わり、Ci*Xがどういう機能を有しているのか学びながらこれらのテストを行っていました。 5.その他 上記以外にも SQL を更新したり、サーバーの管理者としての業務もあります。 SQL にはデータを定義する DDL やデータを操作する DML など種類がありますが、フォルダごとに配置され、一括して リポジトリ にまとめられています。 私はGitを使用してチームメンバーが編集や新規作成した SQL を更新しています。Gitの勉強にもなりますし、 SQL を取り込む際にエラーになることは多々あるので、 SQL の内容について考える機会も多いです。 また、Ci*Xのテスト環境は AWS で運用しており、アプリケーションが動作している環境は Amazon EC2 を使っています。チーム内から依頼されたサーバーの容量拡張や棚卸、新規作成、複製などの業務を担当しています。また、手動で行っていたこれらの業務も今は AWS CDK と GitHub Actionsを用いて ソースコード から自動で行えるように取り組んでいます。 AWS は未経験でしたが、触ってみると楽しいことも多く、 AWS Certified Cloud Practitioner という初級の資格を取りつつ、もっと知識を深めて業務に応用できたらいいなと思っています。 一日の流れ 毎朝、 Jira のチケットの進捗状況を確認します。 朝会終了後はチケットの作業に取り組むことが多いです。 隔週で勉強会があったり、毎週、一般会計 コンサルティング 部の方たちと雑談するような時間もあります。 配属当初は不明点を上司に相談できるような夕会の時間も設けてもらっていました。 FAC2部(保守業務)での働き方の特徴 配属前、開発は設計や実装などある程度の期間を設定し、段階を踏みながら業務を進めていくイメージを持っていましたが、保守業務の特徴は多種多様な角度から不具合の対処やテストを求められることが多く、内容の異なるチケットを抱えていることはよくあることなので、その点において配属直後から幅広い業務に携われていると感じています。 チケットも自分で選択しながら進められますし、先輩社員との1on1で業務やそれ以外に困っていることなどを適宜聞いてくれる場もありますので裁量を持って仕事させてもらえる環境だなと日々感じています。 また、基本的にテレワークがメインになります。出社する必要がないので、そういう点で気楽さを感じています。ただ、テレワークにおけるコミュニケーションはテキストやメールが主となるため、個人の文章力や読解力の差で情報伝達内容の認識に差異や時差が生じてしまったり、情報収集が必要最低限になることが多いなど、難しさも感じています。会議を設定して、あらかじめ質問をまとめ、限られた時間で情報収集する力が求められるなと日々感じています。 最後に 今回は、Ci*Xシリーズの保守業務の内容とその仕事や働き方の特徴についてお伝えしました。 テクニカルな話題が多い中で、少し異色なブログではありましたが、いかがでしたか? 保守業務は様々な角度から問題点が切り込まれるので大変な思いをすることもたくさんありますが、その分、身につくスキルは多いと思います。 これを見てくださっている就活生のみなさんとも共に仕事ができたらなと思います! ありがとうございました! www.isid.co.jp 執筆: @kobayashi.shun 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
皆さんこんにちは。グループ経営ソリューション事業部グループ経営 コンサルティング 第2ユニット一般会計 コンサルティング 部第2グループ(FAC2部)に所属している小林です。 FAC2部では自社製品である「Ci X (サイクロス)」という会計システムパッケージの新規開発・導入・保守を行っており、私は主にその保守業務を担当しています。 この記事ではISIDに興味をお持ちの就活生の方々向けに私がISIDに入社して初めて担当した業務から学んだことについて、自身の振り返りの意味も込めてご紹介したいと思います。 あと、Ci Xに関しては こちら も参考にしてみてください! 自己紹介 まずは自己紹介いたします。 私は2022年に新卒入社し、半年の研修を経て、現在は2年目の勤務になります。 大学では院まで進学し、 放射線 系の研究をしていました。 そのままの進路でいくのならば、メーカー勤務や 原子力 関係の企業に就職するのが王道でした。 物理という学問は好きでしたし、研究室も自分で望んで所属しましたが、大学4年間で勉強した物理の理論を、研究室で応用することは少なく、愚直に地味な実験を繰り返す成果の見えない生活が率直に自分には合っていませんでした。そんな時にHP係を担当しまして、学べば学ぶほど、スキルが身に付くのを感じ、研究室のHPを管理したり、学会のHPを作成することが楽しかったのを覚えています。 ささいな理由ではありましたが、本当に自分のやりたいことって何だろうと考えた時に気づいたらIT業界を志すようになっていました。就活では上手くいかないことだらけでしたが、自分の率直な思いを面白いと聞いてくれたのがISIDで、IT経験が特にない私でも希望していた開発の部署に配属させてくれました。 そして現在、私は自社製品の保守業務からスタートしています。 配属されてから一年も経過はしていませんが、業務はかなり幅広いです。 今回はそれについて広く浅く紹介いたします。 保守の仕事内容について 保守業務のおおまかな流れは製品のリリース後、まず、お客様が製品を使用していて何かしらお問い合わせが生じた際にその旨を保守窓口が受け取り、保守チームに対応を要求します。そしてその後、保守チームは再現調査や原因究明を行って不具合かどうかを判断し、必要があれば設計を変更したり、中身の実装を修正したりして仕様変更対応を行い、テストをします。 以下では私が携わった範囲で担当した業務プロセスを私自身の所感も含めて説明します。 1.原因調査 トラブルシューティング の入り口になるプロセスです。起こってしまったトラブルに対して何が原因だったのか監査ログやシステムログなどを通して原因を探ります。 このプロセスはいざやってみるとどの工程の中でも直感とスキル、判断力が必要で、これを即座にできる人は保守としての力が特に強い人なのだと個人的に思っています。 2.設計 もし、仕様変更が必要な場合、設計を修正することがあります。欠陥修正に該当する設計書の内容を読み込んで画面定義やロジックなどどこを修正すべきなのか判断し、修正します。特にロジックが難しく、簿記の知識も絡む箇所もあるので、何度見返しても不明な部分に関しては先輩社員に聞きながら進めていました。 3.実装 上記の設計修正が完了したあと、その設計に基づいて実際に内部の実装も変更します。 実装で用いる技術要素は以下です。 バックエンド技術( Java , Spring Boot, Thymeleaf, PostgreSQL 等) フロントエンド技術( HTML5 、TypeScript、Vue.js 等) 業務は新卒の研修で学んだことが直接生きており、改めて研修の大切さを実感しました。 4.テスト 実装が完了した後はテストを行い、機能に問題がないか不具合チェックをします。直接変更してはいなくともその変更の影響を受けたところに対してバグが出てしまうこともあるため、機能のテストだけでなく、その周辺に関してもテストをします。配属直後はこのプロセスから携わり、Ci*Xがどういう機能を有しているのか学びながらこれらのテストを行っていました。 5.その他 上記以外にも SQL を更新したり、サーバーの管理者としての業務もあります。 SQL にはデータを定義する DDL やデータを操作する DML など種類がありますが、フォルダごとに配置され、一括して リポジトリ にまとめられています。 私はGitを使用してチームメンバーが編集や新規作成した SQL を更新しています。Gitの勉強にもなりますし、 SQL を取り込む際にエラーになることは多々あるので、 SQL の内容について考える機会も多いです。 また、Ci*Xのテスト環境は AWS で運用しており、アプリケーションが動作している環境は Amazon EC2 を使っています。チーム内から依頼されたサーバーの容量拡張や棚卸、新規作成、複製などの業務を担当しています。また、手動で行っていたこれらの業務も今は AWS CDK と GitHub Actionsを用いて ソースコード から自動で行えるように取り組んでいます。 AWS は未経験でしたが、触ってみると楽しいことも多く、 AWS Certified Cloud Practitioner という初級の資格を取りつつ、もっと知識を深めて業務に応用できたらいいなと思っています。 一日の流れ 毎朝、 Jira のチケットの進捗状況を確認します。 朝会終了後はチケットの作業に取り組むことが多いです。 隔週で勉強会があったり、毎週、一般会計 コンサルティング 部の方たちと雑談するような時間もあります。 配属当初は不明点を上司に相談できるような夕会の時間も設けてもらっていました。 FAC2部(保守業務)での働き方の特徴 配属前、開発は設計や実装などある程度の期間を設定し、段階を踏みながら業務を進めていくイメージを持っていましたが、保守業務の特徴は多種多様な角度から不具合の対処やテストを求められることが多く、内容の異なるチケットを抱えていることはよくあることなので、その点において配属直後から幅広い業務に携われていると感じています。 チケットも自分で選択しながら進められますし、先輩社員との1on1で業務やそれ以外に困っていることなどを適宜聞いてくれる場もありますので裁量を持って仕事させてもらえる環境だなと日々感じています。 また、基本的にテレワークがメインになります。出社する必要がないので、そういう点で気楽さを感じています。ただ、テレワークにおけるコミュニケーションはテキストやメールが主となるため、個人の文章力や読解力の差で情報伝達内容の認識に差異や時差が生じてしまったり、情報収集が必要最低限になることが多いなど、難しさも感じています。会議を設定して、あらかじめ質問をまとめ、限られた時間で情報収集する力が求められるなと日々感じています。 最後に 今回は、Ci*Xシリーズの保守業務の内容とその仕事や働き方の特徴についてお伝えしました。 テクニカルな話題が多い中で、少し異色なブログではありましたが、いかがでしたか? 保守業務は様々な角度から問題点が切り込まれるので大変な思いをすることもたくさんありますが、その分、身につくスキルは多いと思います。 これを見てくださっている就活生のみなさんとも共に仕事ができたらなと思います! ありがとうございました! www.isid.co.jp 執筆: @kobayashi.shun 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 AWS WAF は簡単に Web アプリに WAF を追加でき、かつ値段も他の WAF 製品より安いため、好きな AWS サービスの一つです。そんな AWS WAF ですがしばらく構築・運用し、これを最初から知っておけば・・・と思ったことがあるので 8つご紹介します。 AWS WAF の基本については分かっている前提で、特に説明はいたしません。また2023年10月現在の最新バージョンである、いわゆる「 AWS WAF v2」を対象としています。 その1: AWS マネージドルールのボディサイズ制限が厳しい その2: ファイルアップロードが AWS マネージドルールの XSS に引っかかることがある その3: マネージドルールにはバージョンがある その4: CloudWatch Logs のロググループ名に決まりがある その5: 35個のログストリームに分割される その6: ログに Cookie ヘッダーが記録されてしまう その7: ログ出力条件の EXCLUDED_AS_COUNT とは何か その8: コンソールで作成したルールを JSON 出力すると IaC での書き方がわかる さいごに その1: AWS マネージドルールのボディサイズ制限が厳しい AWS WAF を利用する際に AWS マネージドルール はとても便利です。その中の コアルールセット (CRS) マネージドルールグループ には SizeRestrictions_BODY というリクエストボディのサイズを検査するルールがあり、 8 KB を超えるボディを持つリクエストをブロック します。 ボディサイズが大きいリクエストや、ファイルアップロードにおいては 8 KB を簡単に超えてしまう ことがあるので、本番環境に導入する前に想定するサイズのリクエストがブロックされないかしっかりテストが必要です。 ※このようなルールが設定されている理由は、 AWS WAF は リクエストボディの最初の 8 KB しか検査できない という制約があるためです。リクエストボディの 8 KB 以降の位置に攻撃文字列が含まれていても検査できないため、コアルールセットでは 8 KB を超えるリクエストを一律でブロックすることで対応しています。 ※(2024/3/11追記)ALB以外に関連付けるWAF Web ACL のリクエストボディの検査サイズ制限が 16 KB(64 KBに引き上げ可能)に増えました。 https://aws.amazon.com/about-aws/whats-new/2024/03/aws-waf-larger-body-inspections-regional-resources/ 想定する正当なリクエストが 8 KB を超えてしまう場合、ルールグループ内の SizeRestrictions_BODY ルールのアクションを「Count」にオーバーライドすることで、実質的に除外することができます。ただしボディサイズ制限が全くないのは心許ないので、次のように WAF Web ACL を作ることが考えられます。 コアルールセットマネージドルールグループでは SizeRestrictions_BODY を「Count」にオーバーライドする 適切な値でボディサイズ制限を行う独自ルールを作成する このようなルールを複数作り、リクエストパスに応じて異なるボディサイズの 閾値 を設定することも可能です(例えばファイルアップロードを受け付ける URI パスに対しては 100 KB に制限し、それ以外の URI パスに対しては 8 KB に制限するなど) ボディサイズ制限の 閾値 を 8 KB より大きくする場合、前述の通り、それを超える部分のリクエストボディの中身は他のルールでも検査されないことに留意してください なお、re:Post の次の投稿でも SizeRestrictions_BODY でブロックされた場合の対応方法が記載されています。マネージドルールに一致した際に追加されるラベルと独自ルールを組み合わせて、特定の URI パス(=ファイルアップロードを行う URI パス)ではない場合のみブロックを発動させる方法です。 AWS WAF によってブロックされているファイルをアップロードするにはどうすればよいですか? https://repost.aws/ja/knowledge-center/waf-upload-blocked-files その2: ファイルアップロードが AWS マネージドルールの XSS に引っかかることがある Web アプリに対してバイナリファイルのアップロードをした時に、運悪く コアルールセット (CRS) マネージドルールグループ の CrossSiteScripting_BODY ルールに引っかかってしまったことがありました。そのときのログの一部は次の通りです。バイナリデータが XSS の シグネチャ に一致してしまったようです。 " terminatingRuleMatchDetails ": [ { " conditionType ": " XSS ", " location ": " BODY ", " matchedData ": [ " < ", " \u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000 " ] } ] , re:Post の次の投稿によると、 ファイルアップロードでは CrossSiteScripting_BODY 以外にも SQLi_BODY 、 WindowsShellCommands_BODY 、 GenericLFI_BODY 、 SizeRestrictions_BODY ルールによってブロックされる可能性がある ようです。 AWS WAF によってブロックされているファイルをアップロードするにはどうすればよいですか? https://repost.aws/ja/knowledge-center/waf-upload-blocked-files 投稿では対応方法として「文字列または 正規表現 ( regex ) 一致条件が設定されたセーフリストを使用して、リクエストを許可します。」が紹介されています。マネージドルールに一致した際に追加されるラベルと独自ルールを組み合わせて、リクエストボディに特定の文字列(ファイル拡張子などを想定していると解釈しました)が含まれていない場合のみブロックを発動する方法です。(注:日本語の投稿ではなぜかリクエストヘッダーから特定の文字列を探すとありますが、 英語の投稿 ではリクエストボディから探すと書いてあります。リクエストボディの方がしっくりきています。) あるいは「その1」の SizeRestrictions_BODY の場合と同じように、特定の URI パス(=ファイルアップロードを行う URI パス)ではない場合のみブロックを発動させる方法を取っても良さそうです。 その3: マネージドルールにはバージョンがある マネジメントコンソールでマネージドルールを使っていたらすぐに気が付いたと思うのですが、筆者は CDK で Web ACL を作っていたのでずっと知りませんでした。 マネージドルールにはバージョンが存在します 。 ( AWS マネージドルールのうち「IP レピュテーション、 Bot Control、アカウント乗っ取り防止のルールグループ」にはバージョンが存在しません。バージョンに関わらず、日ごろから頻繁にルールが更新されるためでしょう。) バージョンを特に指定しない場合、そのマネージドルールがデフォルトと設定したバージョンが利用され、ルールプロバイダーがデフォルトバージョンを変更すると構築した Web ACL でも自動的に新しいバージョンに更新されます。自動的に更新されることを避けたい場合は、「静的バージョン」を明示的に指定します。ただしこの場合も、「緊急時の必須の更新」がされる可能性があるそうです。またバージョンの有効期限が切れると、次のような扱いになるようです。 AWS マネージドルールルールグループの場合、 AWS WAF は、有効期限切れのバージョンを使用しているウェブ ACL を、ルールグループのデフォルトバージョンに移動します。 AWS Marketplace ルールグループの場合、プロバイダーは有効期限の処理方法を決定します。詳細については、マネージドルールグループプロバイダーに問い合わせてください。 マネージドルールには SNS トピックが用意されている場合があり、サブスクライブすることでバージョンを含めたルールの更新情報を受け取ることができます。特に静的バージョンを使用する場合はルールバージョンを手動更新することになるので、 SNS トピックをサブスクライブしておくと良いでしょう。 その4: CloudWatch Logs のロググループ名に決まりがある AWS WAF を利用する場合はログをぜひ取っておきたいところですが、CloudWatch Logs に出力する場合、 ロググループ名は aws-waf-logs- で始まる必要があります 。 https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/logging-cw-logs.html#logging-cw-logs-naming マネジメントコンソールでロググループを指定する場合は画面にこの条件が書いてありますし、 aws-waf-logs- で始まるロググループ以外は選択肢に表示されないのでまだ分かりやすいです。 しかし CloudFormation (もちろん CDK も)を利用する場合、 aws-waf-logs- で始まるロググループ以外を Web ACL に関連付けしようとすると、デプロイ時に次のようなエラーになります。「ARN が有効でない」というエラーメッセージでは何がいけないのか全く分からず、どハマりしたことがあるのは自分だけではないはずです。 Resource handler returned message: "Error reason: The ARN isn't valid. A valid ARN begins with arn: and includes other information separated by colons or slashes., field: LOG_ DESTINATION , parameter: arn: aws :logs:ap-northeast-1:111122223333:log-group:waf-logs-xxxxx ちなみにログの出力先が S3 バケット の場合も、 バケット 名は aws-waf-logs- で始まる必要があります。 https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/logging-s3.html#logging-s3-naming その5: 35個のログストリームに分割される (2025/9/5更新)いつ変わったのか分かりませんが、今はWAFのログストリームが分割されなくなっているようです。なお、それでもログの検索はCloudWatch Logs Insightsを利用するのが便利であることには変わりません。 CloudWatch Logs にログを出力すると、 35個のログストリームに分割 され、この数を減らすことはできません 。出力の スループット を高めるためのようです。 近い時刻で発生したログメッセージでも、複数のログストリームに分散して出力されるため、ロググループから特定のログを探すのは難しいです。ログストリームを横断して時系列にログを見たり、特定のログを探したい場合は CloudWatch Logs Insights を利用するのが便利です。以下の公式ブログや re:Post 投稿が参考になります。 Amazon CloudWatch Logs による AWS WAF ログの分析 https://aws.amazon.com/jp/blogs/news/analyzing-aws-waf-logs-in-amazon-cloudwatch-logs/ CloudWatch または Amazon S3 に保存されている AWS WAF ログを分析するオプションは何ですか? https://repost.aws/ja/knowledge-center/waf-analyze-logs-stored-cloudwatch-s3 その6: ログに Cookie ヘッダーが記録されてしまう WAF Web ACL のログを出力すると、 httpRequest.headers フィールドにリクエストヘッダーが記録されます。つまり、 クライアントが送信した Cookie も記録されてしまいます 。 (スクリーンキャプチャの値はダミーです) 例えば分析のためにログを出力したり、共有したりすると有効なセッション ID などセンシティブな情報が漏えいするリスクがあります。 この問題への対応として、ログ出力時に 特定フィールドをマスキング することが可能です。例えば cookie ヘッダーをマスキングするには次のように設定します。 このように設定すると、出力されるログの cookie ヘッダーは REDACTED という文字列に置き換えられます。 ※(追記) Cookie ヘッダーをマスキングするデータ保護機能が増強されました。セッションIDなど特定の Cookie のみを対象としたり、マスキングの代わりにハッシュ化を行うこともできるようになっています。 https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/data-protection-masking.html その7: ログ出力条件の EXCLUDED_AS_COUNT とは何か ログを出力する場合、アクションが特定の条件に該当する場合のみ出力するように設定できます。リクエストが許可された場合のログも全て記録すると量が多くなってしまうので、「ブロック」時と「カウント」時のみ出力したいことがあります。 カウント時の条件は、実は COUNT と EXCLUDED_AS_COUNT の2種類があります 。基本的には COUNT 扱いと考えて良いですが、 EXCLUDED_AS_COUNT として扱われるケースが2つ、以下のブログで説明されています。 AWS WAF のログ分析に関する考慮事項 https://aws.amazon.com/jp/blogs/news/aws-waf-log-analysis-considerations/ マネージドルールグループで ”Set all rule actions to count” で Count に設定した場合 マネージドルールグループで個別のルールを Count に設定した場合 ただし上の AWS のブログは情報が古く、現在個別のルールを Count に設定した場合の動きは少々異なるようです( 参照 )。簡単にまとめると、以下のようになると理解しています: 2022 年 10 月 27 日より前に、 WAF ルールの JSON では ExcludedRules が利用でき、これに含めた個別ルールは EXCLUDED_AS_COUNT 扱いになる マネジメントコンソールで個別ルールを Count に設定すると、 EXCLUDED_AS_COUNT 扱いになる 2022 年 10 月 27 日以降は、 WAF ルールの JSON で ExcludedRules に含めた個別ルールは変わらず EXCLUDED_AS_COUNT 扱いになる WAF ルールの JSON で RuleActionOverrides が新しく利用でき、オーバーライド先をカウントにした場合は COUNT 扱いになる マネジメントコンソールで個別ルールを Count に設定(過去に作成したルールの編集も含めて)すると、 COUNT 扱いに変わる この動きを意識してログ出力条件を作成すると良いと思います。 その8: コンソールで作成したルールを JSON 出力すると IaC での書き方がわかる CloudFormation もしくは CDK で複雑な条件の Web ACL を作成する場合、書き方が分からずに困ることがあります。 例えば「 URI パスが /file/upload 以外へのリクエストでボディサイズが 100 KB 以上の場合にブロックする」ルールは、CDK だとこんな感じで書くことになります。(ルール部分のみ) { name : "SizeConstraint" , priority: 10 , statement: { andStatement: { statements: [ { notStatement : { statement : { byteMatchStatement : { searchString : "/file/upload" , fieldToMatch : { uriPath : {} , } , textTransformations : [ { priority : 0 , type : "NONE" , } , ] , positionalConstraint : "EXACTLY" , } , } , } , } , { sizeConstraintStatement : { fieldToMatch : { body : { oversizeHandling : "CONTINUE" , } , } , comparisonOperator : "GE" , size : 100 * 1000 , textTransformations : [ { priority : 0 , type : "NONE" , } , ] , } , } , ] , } , } , action: { block: {} } , visibilityConfig: { sampledRequestsEnabled: true , cloudWatchMetricsEnabled: true , metricName: "SizeConstraint" , } , } , これをヒントなしで正しく書ける気がしません。一方でマネジメントコンソールでルールを作成すれば、画面の説明に従って割と分かりやすく作成できます。 そこで IaC で WAF のルールを作る場合も、まずはマネジメントコンソールで試しに作成してみて、画面で「ルール JSON エディタ」に切り替えましょう 。 JSON でのルールの書き方を表示してくれます。これをコピーして IaC で利用すると良いでしょう。(CDK に使う場合はプロパティ名の頭文字を大文字から小文字に変換する必要がありますが、自前で書くよりはずっと楽です。) ちなみにルール JSON エディタ画面の説明にもある通り、 JSON を使えばビジュアルエディタではサポートされていないような、深い階層の条件を持つルールを作ることもできます。以下の re:Post 投稿も参考になります。 複雑なカスタム AWS WAF JSON ルールを作成する方法を教えてください。 https://repost.aws/ja/knowledge-center/waf-create-complex-custom-rules さいごに ご紹介した内容はいずれも公式ドキュメントやブログに書いてあることなのですが、WAF を使い始める時は早く構成したい気持ちが先走ってなかなか網羅的にチェックはできませんね。今振り返ると最初に知っておきたかったと感じたことをまとめてみました。誰かの参考になれば嬉しいです。 記事の中に掲載したリンクで特におすすめのものを再掲しておきます。 コアルールセット (CRS) マネージドルールグループ https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/aws-managed-rule-groups-baseline.html#aws-managed-rule-groups-baseline-crs (どのようなルールで検査を行うのか、利用前に一通り把握しておきましょう) AWS WAF によってブロックされているファイルをアップロードするにはどうすればよいですか? https://repost.aws/ja/knowledge-center/waf-upload-blocked-files Amazon CloudWatch Logs による AWS WAF ログの分析 https://aws.amazon.com/jp/blogs/news/analyzing-aws-waf-logs-in-amazon-cloudwatch-logs/ CloudWatch または Amazon S3 に保存されている AWS WAF ログを分析するオプションは何ですか? https://repost.aws/ja/knowledge-center/waf-analyze-logs-stored-cloudwatch-s3 ルールグループ内のアクションオーバーライド https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/web-acl-rule-group-override-options.html 複雑なカスタム AWS WAF JSON ルールを作成する方法を教えてください。 https://repost.aws/ja/knowledge-center/waf-create-complex-custom-rules 以下は、この記事では触れませんでしたが参考となる re:Post の投稿です。 AWS WAF ルールでブロックされているファイルのアップロードを、ルールを除外せずに明示的に許可するには、どうすればよいですか? https://repost.aws/ja/knowledge-center/waf-explicit-allow-file-uploads AWS WAF の HTTP リクエストの XSS または SQLi 検査から特定の URI を除外する方法を教えてください。 https://repost.aws/ja/knowledge-center/waf-exclude-specific-requests-inspection AWS WAF を利用して DDoS 攻撃を緩和するにはどうすればいいですか? https://repost.aws/ja/knowledge-center/waf-mitigate-ddos-attacks 私たちは一緒に働いてくれる仲間を募集しています! 電通総研中途採用ページ 電通総研新卒採用ページ 執筆: @kou.kinyo 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 AWS WAF は簡単に Web アプリに WAF を追加でき、かつ値段も他の WAF 製品より安いため、好きな AWS サービスの一つです。そんな AWS WAF ですがしばらく構築・運用し、これを最初から知っておけば・・・と思ったことがあるので 8つご紹介します。 AWS WAF の基本については分かっている前提で、特に説明はいたしません。また2023年10月現在の最新バージョンである、いわゆる「 AWS WAF v2」を対象としています。 その1: AWS マネージドルールのボディサイズ制限が厳しい その2: ファイルアップロードが AWS マネージドルールの XSS に引っかかることがある その3: マネージドルールにはバージョンがある その4: CloudWatch Logs のロググループ名に決まりがある その5: 35個のログストリームに分割される その6: ログに Cookie ヘッダーが記録されてしまう その7: ログ出力条件の EXCLUDED_AS_COUNT とは何か その8: コンソールで作成したルールを JSON 出力すると IaC での書き方がわかる さいごに その1: AWS マネージドルールのボディサイズ制限が厳しい AWS WAF を利用する際に AWS マネージドルール はとても便利です。その中の コアルールセット (CRS) マネージドルールグループ には SizeRestrictions_BODY というリク エス トボディのサイズを検査するルールがあり、 8 KB を超えるボディを持つリク エス トをブロック します。 ボディサイズが大きいリク エス トや、ファイルアップロードにおいては 8 KB を簡単に超えてしまう ことがあるので、本番環境に導入する前に想定するサイズのリク エス トがブロックされないかしっかりテストが必要です。 ※このようなルールが設定されている理由は、 AWS WAF は リクエストボディの最初の 8 KB しか検査できない という制約があるためです。リク エス トボディの 8 KB 以降の位置に攻撃文字列が含まれていても検査できないため、コアルールセットでは 8 KB を超えるリク エス トを一律でブロックすることで対応しています。 想定する正当なリク エス トが 8 KB を超えてしまう場合、ルールグループ内の SizeRestrictions_BODY ルールのアクションを「Count」にオーバーライドすることで、実質的に除外することができます。ただしボディサイズ制限が全くないのは心許ないので、次のように WAF Web ACL を作ることが考えられます。 コアルールセットマネージドルールグループでは SizeRestrictions_BODY を「Count」にオーバーライドする 適切な値でボディサイズ制限を行う独自ルールを作成する このようなルールを複数作り、リク エス トパスに応じて異なるボディサイズの 閾値 を設定することも可能です(例えばファイルアップロードを受け付ける URI パスに対しては 100 KB に制限し、それ以外の URI パスに対しては 8 KB に制限するなど) ボディサイズ制限の 閾値 を 8 KB より大きくする場合、前述の通り、それを超える部分のリク エス トボディの中身は他のルールでも検査されないことに留意してください なお、re:Post の次の投稿でも SizeRestrictions_BODY でブロックされた場合の対応方法が記載されています。マネージドルールに一致した際に追加されるラベルと独自ルールを組み合わせて、特定の URI パス(=ファイルアップロードを行う URI パス)ではない場合のみブロックを発動させる方法です。 AWS WAF によってブロックされているファイルをアップロードするにはどうすればよいですか? https://repost.aws/ja/knowledge-center/waf-upload-blocked-files その2: ファイルアップロードが AWS マネージドルールの XSS に引っかかることがある Web アプリに対してバイナリファイルのアップロードをした時に、運悪く コアルールセット (CRS) マネージドルールグループ の CrossSiteScripting_BODY ルールに引っかかってしまったことがありました。そのときのログの一部は次の通りです。バイナリデータが XSS の シグネチャ に一致してしまったようです。 " terminatingRuleMatchDetails ": [ { " conditionType ": " XSS ", " location ": " BODY ", " matchedData ": [ " < ", " \u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000 " ] } ] , re:Post の次の投稿によると、 ファイルアップロードでは CrossSiteScripting_BODY 以外にも SQLi_BODY 、 WindowsShellCommands_BODY 、 GenericLFI_BODY 、 SizeRestrictions_BODY ルールによってブロックされる可能性がある ようです。 AWS WAF によってブロックされているファイルをアップロードするにはどうすればよいですか? https://repost.aws/ja/knowledge-center/waf-upload-blocked-files 投稿では対応方法として「文字列または 正規表現 ( regex ) 一致条件が設定されたセーフリストを使用して、リク エス トを許可します。」が紹介されています。マネージドルールに一致した際に追加されるラベルと独自ルールを組み合わせて、リク エス トボディに特定の文字列(ファイル拡張子などを想定していると解釈しました)が含まれていない場合のみブロックを発動する方法です。(注:日本語の投稿ではなぜかリク エス トヘッダーから特定の文字列を探すとありますが、 英語の投稿 ではリク エス トボディから探すと書いてあります。リク エス トボディの方がしっくりきています。) あるいは「その1」の SizeRestrictions_BODY の場合と同じように、特定の URI パス(=ファイルアップロードを行う URI パス)ではない場合のみブロックを発動させる方法を取っても良さそうです。 その3: マネージドルールにはバージョンがある マネジメントコンソールでマネージドルールを使っていたらすぐに気が付いたと思うのですが、筆者は CDK で Web ACL を作っていたのでずっと知りませんでした。 マネージドルールにはバージョンが存在します 。 ( AWS マネージドルールのうち「IP レピュテーション、 Bot Control、アカウント乗っ取り防止のルールグループ」にはバージョンが存在しません。バージョンに関わらず、日ごろから頻繁にルールが更新されるためでしょう。) バージョンを特に指定しない場合、そのマネージドルールがデフォルトと設定したバージョンが利用され、ルールプロバイダーがデフォルトバージョンを変更すると構築した Web ACL でも自動的に新しいバージョンに更新されます。自動的に更新されることを避けたい場合は、「静的バージョン」を明示的に指定します。ただしこの場合も、「緊急時の必須の更新」がされる可能性があるそうです。またバージョンの有効期限が切れると、次のような扱いになるようです。 AWS マネージドルールルールグループの場合、 AWS WAF は、有効期限切れのバージョンを使用しているウェブ ACL を、ルールグループのデフォルトバージョンに移動します。 AWS Marketplace ルールグループの場合、プロバイダーは有効期限の処理方法を決定します。詳細については、マネージドルールグループプロバイダーに問い合わせてください。 マネージドルールには SNS トピックが用意されている場合があり、サブスクライブすることでバージョンを含めたルールの更新情報を受け取ることができます。特に静的バージョンを使用する場合はルールバージョンを手動更新することになるので、 SNS トピックをサブスクライブしておくと良いでしょう。 その4: CloudWatch Logs のロググループ名に決まりがある AWS WAF を利用する場合はログをぜひ取っておきたいところですが、CloudWatch Logs に出力する場合、 ロググループ名は aws-waf-logs- で始まる必要があります 。 https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/logging-cw-logs.html#logging-cw-logs-naming マネジメントコンソールでロググループを指定する場合は画面にこの条件が書いてありますし、 aws-waf-logs- で始まるロググループ以外は選択肢に表示されないのでまだ分かりやすいです。 しかし CloudFormation (もちろん CDK も)を利用する場合、 aws-waf-logs- で始まるロググループ以外を Web ACL に関連付けしようとすると、デプロイ時に次のようなエラーになります。「ARN が有効でない」というエラーメッセージでは何がいけないのか全く分からず、どハマりしたことがあるのは自分だけではないはずです。 Resource handler returned message: "Error reason: The ARN isn't valid. A valid ARN begins with arn: and includes other information separated by colons or slashes., field: LOG_ DESTINATION , parameter: arn: aws :logs:ap-northeast-1:111122223333:log-group:waf-logs-xxxxx ちなみにログの出力先が S3 バケット の場合も、 バケット 名は aws-waf-logs- で始まる必要があります。 https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/logging-s3.html#logging-s3-naming その5: 35個のログストリームに分割される CloudWatch Logs にログを出力すると、 35個のログストリームに分割 され、この数を減らすことはできません 。出力の スループット を高めるためのようです。 近い時刻で発生したログメッセージでも、複数のログストリームに分散して出力されるため、ロググループから特定のログを探すのは難しいです。ログストリームを横断して時系列にログを見たり、特定のログを探したい場合は CloudWatch Logs Insights を利用するのが便利です。以下の公式ブログや re:Post 投稿が参考になります。 Amazon CloudWatch Logs による AWS WAF ログの分析 https://aws.amazon.com/jp/blogs/news/analyzing-aws-waf-logs-in-amazon-cloudwatch-logs/ CloudWatch または Amazon S3 に保存されている AWS WAF ログを分析するオプションは何ですか? https://repost.aws/ja/knowledge-center/waf-analyze-logs-stored-cloudwatch-s3 その6: ログに Cookie ヘッダーが記録されてしまう WAF Web ACL のログを出力すると、 httpRequest.headers フィールドにリク エス トヘッダーが記録されます。つまり、 クライアントが送信した Cookie も記録されてしまいます 。 (スクリーンキャプチャの値はダミーです) 例えば分析のためにログを出力したり、共有したりすると有効なセッション ID などセンシティブな情報が漏えいするリスクがあります。 この問題への対応として、ログ出力時に 特定フィールドをマスキング することが可能です。例えば cookie ヘッダーをマスキングするには次のように設定します。 このように設定すると、出力されるログの cookie ヘッダーは REDACTED という文字列に置き換えられます。 その7: ログ出力条件の EXCLUDED_AS_COUNT とは何か ログを出力する場合、アクションが特定の条件に該当する場合のみ出力するように設定できます。リク エス トが許可された場合のログも全て記録すると量が多くなってしまうので、「ブロック」時と「カウント」時のみ出力したいことがあります。 カウント時の条件は、実は COUNT と EXCLUDED_AS_COUNT の2種類があります 。基本的には COUNT 扱いと考えて良いですが、 EXCLUDED_AS_COUNT として扱われるケースが2つ、以下のブログで説明されています。 AWS WAF のログ分析に関する考慮事項 https://aws.amazon.com/jp/blogs/news/aws-waf-log-analysis-considerations/ マネージドルールグループで ”Set all rule actions to count” で Count に設定した場合 マネージドルールグループで個別のルールを Count に設定した場合 ただし上の AWS のブログは情報が古く、現在個別のルールを Count に設定した場合の動きは少々異なるようです( 参照 )。簡単にまとめると、以下のようになると理解しています: 2022 年 10 月 27 日より前に、 WAF ルールの JSON では ExcludedRules が利用でき、これに含めた個別ルールは EXCLUDED_AS_COUNT 扱いになる マネジメントコンソールで個別ルールを Count に設定すると、 EXCLUDED_AS_COUNT 扱いになる 2022 年 10 月 27 日以降は、 WAF ルールの JSON で ExcludedRules に含めた個別ルールは変わらず EXCLUDED_AS_COUNT 扱いになる WAF ルールの JSON で RuleActionOverrides が新しく利用でき、オーバーライド先をカウントにした場合は COUNT 扱いになる マネジメントコンソールで個別ルールを Count に設定(過去に作成したルールの編集も含めて)すると、 COUNT 扱いに変わる この動きを意識してログ出力条件を作成すると良いと思います。 その8: コンソールで作成したルールを JSON 出力すると IaC での書き方がわかる CloudFormation もしくは CDK で複雑な条件の Web ACL を作成する場合、書き方が分からずに困ることがあります。 例えば「 URI パスが /file/upload 以外へのリク エス トでボディサイズが 100 KB 以上の場合にブロックする」ルールは、CDK だとこんな感じで書くことになります。(ルール部分のみ) { name: "SizeConstraint" , priority: 10 , statement: { andStatement: { statements: [ { notStatement: { statement: { byteMatchStatement: { searchString: "/file/upload" , fieldToMatch: { uriPath: {} , } , textTransformations: [ { priority: 0 , type : "NONE" , } , ] , positionalConstraint: "EXACTLY" , } , } , } , } , { sizeConstraintStatement: { fieldToMatch: { body: { oversizeHandling: "CONTINUE" , } , } , comparisonOperator: "GE" , size: 100 * 1000 , textTransformations: [ { priority: 0 , type : "NONE" , } , ] , } , } , ] , } , } , action: { block: {} } , visibilityConfig: { sampledRequestsEnabled: true , cloudWatchMetricsEnabled: true , metricName: "SizeConstraint" , } , } , これをヒントなしで正しく書ける気がしません。一方でマネジメントコンソールでルールを作成すれば、画面の説明に従って割と分かりやすく作成できます。 そこで IaC で WAF のルールを作る場合も、まずはマネジメントコンソールで試しに作成してみて、画面で「ルール JSON エディタ」に切り替えましょう 。 JSON でのルールの書き方を表示してくれます。これをコピーして IaC で利用すると良いでしょう。(CDK に使う場合はプロパティ名の頭文字を大文字から小文字に変換する必要がありますが、自前で書くよりはずっと楽です。) ちなみにルール JSON エディタ画面の説明にもある通り、 JSON を使えばビジュアルエディタではサポートされていないような、深い階層の条件を持つルールを作ることもできます。以下の re:Post 投稿も参考になります。 複雑なカスタム AWS WAF JSON ルールを作成する方法を教えてください。 https://repost.aws/ja/knowledge-center/waf-create-complex-custom-rules さいごに ご紹介した内容はいずれも公式ドキュメントやブログに書いてあることなのですが、WAF を使い始める時は早く構成したい気持ちが先走ってなかなか網羅的にチェックはできませんね。今振り返ると最初に知っておきたかったと感じたことをまとめてみました。誰かの参考になれば嬉しいです。 記事の中に掲載したリンクで特におすすめのものを再掲しておきます。 コアルールセット (CRS) マネージドルールグループ https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/aws-managed-rule-groups-baseline.html#aws-managed-rule-groups-baseline-crs (どのようなルールで検査を行うのか、利用前に一通り把握しておきましょう) AWS WAF によってブロックされているファイルをアップロードするにはどうすればよいですか? https://repost.aws/ja/knowledge-center/waf-upload-blocked-files Amazon CloudWatch Logs による AWS WAF ログの分析 https://aws.amazon.com/jp/blogs/news/analyzing-aws-waf-logs-in-amazon-cloudwatch-logs/ CloudWatch または Amazon S3 に保存されている AWS WAF ログを分析するオプションは何ですか? https://repost.aws/ja/knowledge-center/waf-analyze-logs-stored-cloudwatch-s3 ルールグループ内のアクションオーバーライド https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/web-acl-rule-group-override-options.html 複雑なカスタム AWS WAF JSON ルールを作成する方法を教えてください。 https://repost.aws/ja/knowledge-center/waf-create-complex-custom-rules 以下は、この記事では触れませんでしたが参考となる re:Post の投稿です。 AWS WAF ルールでブロックされているファイルのアップロードを、ルールを除外せずに明示的に許可するには、どうすればよいですか? https://repost.aws/ja/knowledge-center/waf-explicit-allow-file-uploads AWS WAF の HTTP リク エス トの XSS または SQLi 検査から特定の URI を除外する方法を教えてください。 https://repost.aws/ja/knowledge-center/waf-exclude-specific-requests-inspection AWS WAF を利用して DDoS 攻撃を緩和するにはどうすればいいですか? https://repost.aws/ja/knowledge-center/waf-mitigate-ddos-attacks 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア 執筆: @kou.kinyo 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター