TECH PLAY

電通総研

電通総研 の技術ブログ

822

こんにちは、ISID 金融ソリューション事業部の岡崎です。 今回はUE5.2の新機能であるプロシージャルコンテンツ生成 フレームワーク (PCG:Procedural Content Generation Framework)の紹介を行います。 はじめに PCGとはコンテンツ生成に関するルールを作成し、そのルールに沿って植物や岩などのアセットを大量に配置できる機能です。 アセットの種類や位置、大きさなどを指示するルールを作成することで制作時間を大幅に削減でき、 ルールを流用することで大規模なワールド作成なども行えます。 また、変更に対して柔軟に対応しやすいという点もメリットになります。 今回は Gaea という3D地形生成ツールを使用して ランドスケープ を作成しながら、PCGを使用してフォトリアルな森の作り方を説明します。 検証環境/ツール OS: Windows 11 pro GPU : NVIDIA GeForce RTX 4070 Ti Game Engine: Unreal Engine 5.2.0 実装手順 Gaea上で ランドスケープ を作成 ハイトマップをUE5プロジェクトにインポート PCGを使用して森を生成 1. Gaea上で ランドスケープ を作成 まずはUE上でPCGを使用する前に、木々を生やすための土地( ランドスケープ )を作成します。 UEにも ランドスケープ を造形するツールは搭載しているのですが、今回は Gaea という3D地形生成を使用して ランドスケープ を生成します。 こちらの記事 でUEの ランドスケープ 機能を紹介しているので、ぜひこちらもご覧ください。 まずは Gaea をインストールします。 解像度が1024x1024までは無料で使うことができるので、今回は無料版を使用します。 Gaeaを開くと下記のような画面になります。 左のタブの「Geo Primitives」から使用したい地形のモデルを ドラッグ&ドロップ します。 また、いくつかの地形モデルを組み合わせることもできます。 下の図では「Range(山岳)」と「Rocky(岩肌)」のノードを「Combine」を使用して組み合わせてみました。 「Range(山岳)」 「Rocky(岩肌)」 組み合わせた地形 今回の ランドスケープ では、もう少し平地の部分も欲しかったので、 「Range」と「Worselands」の地形ノードを組み合わせて使用しました。 また組み合わせた地形に「FractalTerraces(地層)」のノードや「Erosion(浸食)」のノードを組み合わせ、 よりイメージに近い地形を作成しました。 詳しい地形ノードや効果のノードに関しては こちらの公式リファレンス を参照しました。 次にこれまで作成した地形をUEで使用するためにエクスポート作業を行います。 最終的に作成した「Erosion(浸食)」のノードを右クリックし、Renameを行います。 今回私は「MyWorld」という名前に変更しました。 続いて「MyWorld」を再度右クリックし、Mark for Exportを押下します。 右側のタブにエクスポートの詳細が表示されるので、出力形式を「. png 」に変更します。 また、 UEで推奨しているランドスケープの解像度の値 は1009なので、「Resolution」を「1009」に変更します。 GaeaからUEにデータを移行する際、縦横の比率の変更をする必要があります。 右側の詳細画面のタブを「MyWorld Properties」に切り替え、地形の縦横・高低比率を調査するための「Lv」のボタンを押下します。 すると下記画面のように作成した地形の縦横比率が変わった状態のサンプルが表示されます。 デフォルトのままエクスポートをすると、この状態の地形がUEに入ってしまうので設定を変えていきます。 「Lv」の下にある「Clmp」ボタンを押下し、「Clmp Max」の値を「25%」に変更します。 (この値は作成した ランドスケープ を見ながら適宜調整します) これで元のモデルと同じ縦横比率になるので、このままBuildタブに戻り、「Start Build」を行いファイルを出力します。 続いて出力したファイルをUEにインポートします。 2. ハイトマップをUE5プロジェクトにインポート UEを開き選択モードから ランドスケープ モードに変更します。 新しい ランドスケープ のタブから、「ファイルからインポート」を選択します。 先ほどGaeaでエクスポートした「. png 」ファイルを選択します。 インポート設定画面で、解像度をGaeaで設定した「1009x1009」に変更してインポートします。 インポート後、 ランドスケープ が出現していないように見えますが、「ExponentalHeight」が画面にモヤをかけてしまっており、遠くの ランドスケープ が見えなくなっているだけなので、 選択モードに変更後、上下の位置を変えることで ランドスケープ が見えるようになります。 これでGaeaで作成した ランドスケープ をUE上で使うことができます。 続いて作成した ランドスケープ にPCGで森を作成します。 3. PCGを使用して森を生成 まずPCGで森を作成する前に、作成された ランドスケープ のマテリアルがデフォルトのままで味気ないので、マテリアルを割り当てます。 今回は簡易的に行うため、 アウトライナー で ランドスケープ を選択し、 ランドスケープ マテリアルに任意のマテリアルを選択しました。 次にPCGを使用するために プラグイン の設定をする必要があります。 プラグイン 設定画面から「Procedural Content Generation Framework」をオンにします。UEを再起動させて設定を反映させます。 次に今回フォトリアルな森を作成するために使用するアセットのダウンロードを行います。 Unreal マーケットプレイス から「Megascans Trees(早期アクセス)」を開きダウンロードします。 今回はヨーロッパ風の木を使用しましたが、他に何種類かあったので自分の作りたいイメージに合ったものをダウンロードします。 ダウンロードが完了するとプロジェクトのコンテンツブラウザからダウンロードした木々のアセットを表示できます。 このアセットは後で使うので一旦このまま置いておきます。 UEの編集画面より、PCGで森を生成するための範囲を決めるために「PCGVolume」というアセットを生成します。 画面上部よりアセット追加ボタンを押し、検索して生成してください。 生成した範囲をワールド上に設置し、森を作成したい大きさに任意で設定します。 次に、この範囲とPCGで作成するルールを記載するアセットを紐づけます。 まずルールを記載するためにコンテンツブラウザ内に「PCGグラフ」を作成します。今回は「MyWorldPCG」と 命名 しました。 次に編集画面で アウトライナー より先ほど範囲を決めるために作成した「PCGVolume」を選択し、子要素の「PCGComponent」を選択します。 選択すると、 インスタンス 直下にGraphを選択する欄があるので、先ほど作成した「MyWorldPCG」を選択し、ルールと範囲を紐づけます。 続いて「MyWorldPCG」を編集してルールを作成します。 「MyWorldPCG」を開くとブループリントの編集画面のようなものがでてきます。 まずは「 Surface Sampler」というノードを作成し、「Input」の「Landscape」ピンと繋ぎます。 このノードは Surface (面)に対してルールを適応させていくことができます。 「 Surface Sampler」を選択し、右側の設定画面から「Points Per Squared Meter 」の値を変更します。 この値は、 平方メートルあたりのポイント数を設定できます。今回は一旦「0.01」としました。 次に「Transform Point」ノードを作成し、右につなげます。 ここではアセットの大きさや向きを設定できます。 「Rotation Max」のZ値を360に設定します。これにより生成されたアセットの向きがランダムになります。 また「Scale Min」を0.7に設定します。これにより生成されたアセットの大きさが70~100%の間でランダムになります。 この「Transform Point」を選択した状態で、キーボードの「D」を押下します。 するとノードの右上に水色のマークがついていることを確認できます。これは デバッグ 状態で表示できるモードであるという印です。 UE編集画面に戻ると、「Transform Point」で生成したアセット生成ポイントが デバッグ 状態で見ることができます。(黒や白でブロックが置かれている部分に指定したアセットが表示される予定) 今作成した生成ポイントには大きな木を配置する予定なので、 続けて、小さな木を配置する用のポイントも追加します。 「 Surface Sampler」と「Transform Point」をコピーします。 「 Surface Sampler」の「Points Per Squared Meter 」の値を「0.1」にします。これにより先ほど作成した大きな木用のポイントの10倍の数のアセットが生成できます。 さらに「Point Extents」でブロックの大きさを変更します。デフォルトが「100」だったので半分の「50」に設定します。 この段階でUE編集画面に戻ると下記画像のように変更されます。 同様にさらに小さな草を生やすためのノードもコピーしました。 次に作成したポイントに実際のアセットを割り当てていきます。 「Static Mesh Spawner」ノードを作成します。 右側の設定画面で「Mesh Entries」の右側のプラスボタンを押し、配列を3つ作成します。 追加した配列の内部に入っていき「Description > Static Mesh」の順に開き、先ほど マーケットプレイス から追加した木のアセットを選択します。 木のアセットは「Contents > BlackAlder > Geometry > PivotPainter」の中にあります。 選択して割り当てたら、配列の残った2つにも同様に木のアセットを選択します。 この時、この3つの木のアセットがランダムで生成されるので、使いたい3種類の木のアセットを選択してください。 UE編集画面に戻ると下記画像のように大きな木がランダムで生成されているのを確認できます。 同様に、後2つの「Static Mesh Spawner」ノードを作成します。ここでは小さい木やさらに小さい草木のアセットをそれぞれ配置します。 配置が完了すると以下のようなフォトリアルな森が完成します。 上記の方法で、 数に関しては「Points Per Squared Meter 」の値を変更し 種類に関しては「Description > Static Mesh」のメッシュを変更することで、さまざまな種類の森を簡単に作ることができます。 おわりに UE5.2の新機能であるプロシージャルコンテンツ生成 フレームワーク (PCG:Procedural Content Generation Framework)の紹介を行いました。 画像でお見せしたようなフォトリアルなワールドがとても手軽に作成できるとても便利な機能だと感じました。 ルールベースでコンテンツを生成するので編集や複製なども容易にでき、今後の開発でも色々使用していきたいです。 ルールを作成することで、森の中に道を作成したり、その道にそって草を配置することなどもできるので、 次回はもう少し深掘りしたPCGの使用方法をご紹介します。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ 執筆: @okazaki.wataru 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
こんにちは、ISID 金融ソリューション事業部の岡崎です。 今回はUE5.2の新機能であるプロシージャルコンテンツ生成 フレームワーク (PCG:Procedural Content Generation Framework)の紹介を行います。 はじめに PCGとはコンテンツ生成に関するルールを作成し、そのルールに沿って植物や岩などのアセットを大量に配置できる機能です。 アセットの種類や位置、大きさなどを指示するルールを作成することで制作時間を大幅に削減でき、 ルールを流用することで大規模なワールド作成なども行えます。 また、変更に対して柔軟に対応しやすいという点もメリットになります。 今回は Gaea という3D地形生成ツールを使用して ランドスケープ を作成しながら、PCGを使用してフォトリアルな森の作り方を説明します。 検証環境/ツール OS: Windows 11 pro GPU : NVIDIA GeForce RTX 4070 Ti Game Engine: Unreal Engine 5.2.0 実装手順 Gaea上で ランドスケープ を作成 ハイトマップをUE5プロジェクトにインポート PCGを使用して森を生成 1. Gaea上で ランドスケープ を作成 まずはUE上でPCGを使用する前に、木々を生やすための土地( ランドスケープ )を作成します。 UEにも ランドスケープ を造形するツールは搭載しているのですが、今回は Gaea という3D地形生成を使用して ランドスケープ を生成します。 こちらの記事 でUEの ランドスケープ 機能を紹介しているので、ぜひこちらもご覧ください。 まずは Gaea をインストールします。 解像度が1024x1024までは無料で使うことができるので、今回は無料版を使用します。 Gaeaを開くと下記のような画面になります。 左のタブの「Geo Primitives」から使用したい地形のモデルを ドラッグ&ドロップ します。 また、いくつかの地形モデルを組み合わせることもできます。 下の図では「Range(山岳)」と「Rocky(岩肌)」のノードを「Combine」を使用して組み合わせてみました。 「Range(山岳)」 「Rocky(岩肌)」 組み合わせた地形 今回の ランドスケープ では、もう少し平地の部分も欲しかったので、 「Range」と「Worselands」の地形ノードを組み合わせて使用しました。 また組み合わせた地形に「FractalTerraces(地層)」のノードや「Erosion(浸食)」のノードを組み合わせ、 よりイメージに近い地形を作成しました。 詳しい地形ノードや効果のノードに関しては こちらの公式リファレンス を参照しました。 次にこれまで作成した地形をUEで使用するためにエクスポート作業を行います。 最終的に作成した「Erosion(浸食)」のノードを右クリックし、Renameを行います。 今回私は「MyWorld」という名前に変更しました。 続いて「MyWorld」を再度右クリックし、Mark for Exportを押下します。 右側のタブにエクスポートの詳細が表示されるので、出力形式を「. png 」に変更します。 また、 UEで推奨しているランドスケープの解像度の値 は1009なので、「Resolution」を「1009」に変更します。 GaeaからUEにデータを移行する際、縦横の比率の変更をする必要があります。 右側の詳細画面のタブを「MyWorld Properties」に切り替え、地形の縦横・高低比率を調査するための「Lv」のボタンを押下します。 すると下記画面のように作成した地形の縦横比率が変わった状態のサンプルが表示されます。 デフォルトのままエクスポートをすると、この状態の地形がUEに入ってしまうので設定を変えていきます。 「Lv」の下にある「Clmp」ボタンを押下し、「Clmp Max」の値を「25%」に変更します。 (この値は作成した ランドスケープ を見ながら適宜調整します) これで元のモデルと同じ縦横比率になるので、このままBuildタブに戻り、「Start Build」を行いファイルを出力します。 続いて出力したファイルをUEにインポートします。 2. ハイトマップをUE5プロジェクトにインポート UEを開き選択モードから ランドスケープ モードに変更します。 新しい ランドスケープ のタブから、「ファイルからインポート」を選択します。 先ほどGaeaでエクスポートした「. png 」ファイルを選択します。 インポート設定画面で、解像度をGaeaで設定した「1009x1009」に変更してインポートします。 インポート後、 ランドスケープ が出現していないように見えますが、「ExponentalHeight」が画面にモヤをかけてしまっており、遠くの ランドスケープ が見えなくなっているだけなので、 選択モードに変更後、上下の位置を変えることで ランドスケープ が見えるようになります。 これでGaeaで作成した ランドスケープ をUE上で使うことができます。 続いて作成した ランドスケープ にPCGで森を作成します。 3. PCGを使用して森を生成 まずPCGで森を作成する前に、作成された ランドスケープ のマテリアルがデフォルトのままで味気ないので、マテリアルを割り当てます。 今回は簡易的に行うため、 アウトライナー で ランドスケープ を選択し、 ランドスケープ マテリアルに任意のマテリアルを選択しました。 次にPCGを使用するために プラグイン の設定をする必要があります。 プラグイン 設定画面から「Procedural Content Generation Framework」をオンにします。UEを再起動させて設定を反映させます。 次に今回フォトリアルな森を作成するために使用するアセットのダウンロードを行います。 Unreal マーケットプレイス から「Megascans Trees(早期アクセス)」を開きダウンロードします。 今回はヨーロッパ風の木を使用しましたが、他に何種類かあったので自分の作りたいイメージに合ったものをダウンロードします。 ダウンロードが完了するとプロジェクトのコンテンツブラウザからダウンロードした木々のアセットを表示できます。 このアセットは後で使うので一旦このまま置いておきます。 UEの編集画面より、PCGで森を生成するための範囲を決めるために「PCGVolume」というアセットを生成します。 画面上部よりアセット追加ボタンを押し、検索して生成してください。 生成した範囲をワールド上に設置し、森を作成したい大きさに任意で設定します。 次に、この範囲とPCGで作成するルールを記載するアセットを紐づけます。 まずルールを記載するためにコンテンツブラウザ内に「PCGグラフ」を作成します。今回は「MyWorldPCG」と 命名 しました。 次に編集画面で アウトライナー より先ほど範囲を決めるために作成した「PCGVolume」を選択し、子要素の「PCGComponent」を選択します。 選択すると、 インスタンス 直下にGraphを選択する欄があるので、先ほど作成した「MyWorldPCG」を選択し、ルールと範囲を紐づけます。 続いて「MyWorldPCG」を編集してルールを作成します。 「MyWorldPCG」を開くとブループリントの編集画面のようなものがでてきます。 まずは「 Surface Sampler」というノードを作成し、「Input」の「Landscape」ピンと繋ぎます。 このノードは Surface (面)に対してルールを適応させていくことができます。 「 Surface Sampler」を選択し、右側の設定画面から「Points Per Squared Meter 」の値を変更します。 この値は、 平方メートルあたりのポイント数を設定できます。今回は一旦「0.01」としました。 次に「Transform Point」ノードを作成し、右につなげます。 ここではアセットの大きさや向きを設定できます。 「Rotation Max」のZ値を360に設定します。これにより生成されたアセットの向きがランダムになります。 また「Scale Min」を0.7に設定します。これにより生成されたアセットの大きさが70~100%の間でランダムになります。 この「Transform Point」を選択した状態で、キーボードの「D」を押下します。 するとノードの右上に水色のマークがついていることを確認できます。これは デバッグ 状態で表示できるモードであるという印です。 UE編集画面に戻ると、「Transform Point」で生成したアセット生成ポイントが デバッグ 状態で見ることができます。(黒や白でブロックが置かれている部分に指定したアセットが表示される予定) 今作成した生成ポイントには大きな木を配置する予定なので、 続けて、小さな木を配置する用のポイントも追加します。 「 Surface Sampler」と「Transform Point」をコピーします。 「 Surface Sampler」の「Points Per Squared Meter 」の値を「0.1」にします。これにより先ほど作成した大きな木用のポイントの10倍の数のアセットが生成できます。 さらに「Point Extents」でブロックの大きさを変更します。デフォルトが「100」だったので半分の「50」に設定します。 この段階でUE編集画面に戻ると下記画像のように変更されます。 同様にさらに小さな草を生やすためのノードもコピーしました。 次に作成したポイントに実際のアセットを割り当てていきます。 「Static Mesh Spawner」ノードを作成します。 右側の設定画面で「Mesh Entries」の右側のプラスボタンを押し、配列を3つ作成します。 追加した配列の内部に入っていき「Description > Static Mesh」の順に開き、先ほど マーケットプレイス から追加した木のアセットを選択します。 木のアセットは「Contents > BlackAlder > Geometry > PivotPainter」の中にあります。 選択して割り当てたら、配列の残った2つにも同様に木のアセットを選択します。 この時、この3つの木のアセットがランダムで生成されるので、使いたい3種類の木のアセットを選択してください。 UE編集画面に戻ると下記画像のように大きな木がランダムで生成されているのを確認できます。 同様に、後2つの「Static Mesh Spawner」ノードを作成します。ここでは小さい木やさらに小さい草木のアセットをそれぞれ配置します。 配置が完了すると以下のようなフォトリアルな森が完成します。 上記の方法で、 数に関しては「Points Per Squared Meter 」の値を変更し 種類に関しては「Description > Static Mesh」のメッシュを変更することで、さまざまな種類の森を簡単に作ることができます。 おわりに UE5.2の新機能であるプロシージャルコンテンツ生成 フレームワーク (PCG:Procedural Content Generation Framework)の紹介を行いました。 画像でお見せしたようなフォトリアルなワールドがとても手軽に作成できるとても便利な機能だと感じました。 ルールベースでコンテンツを生成するので編集や複製なども容易にでき、今後の開発でも色々使用していきたいです。 ルールを作成することで、森の中に道を作成したり、その道にそって草を配置することなどもできるので、 次回はもう少し深掘りしたPCGの使用方法をご紹介します。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ 執筆: @okazaki.wataru 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
こんにちは、グループ経営ソリューション( GMS )事業部 グループ経営 コンサルティング 第2ユニット 一般会計 コンサルティング 部 第2グループ、3年目の塚本です。 普段は会計ソリューションである Ci*Xシリーズ の新規開発を担当しています。 ※ Ci*Xシリーズの導入に関して気になる方は川島さんの以下の記事を参考にしてください。 SIerで自社製品導入をする新卒5年目(※IT経験なし)の働き方と今感じること~ちょこっと就活の話も添えて~ 本記事では、業務内容や 1 週間の過ごし方など、私の主な働き方についてざっくりとご紹介します。 IT 企業への就職を検討されている学生の方や、ISID にご興味をお持ちの方の参考になれば幸いです。 目次 目次 自己紹介 仕事内容 新規開発の作業工程 要件定義 設計 実装・単体テスト 結合テスト 製品化 配属後からこれまでの流れ 2年間働いてみて 最後に 自己紹介 私は工学部電気電子系学科出身で、4年間物理学を学んでいました。私の学部では通常であればそのまま院に進学し、メーカーや電気関係の企業に就職することがほとんどです。しかし、院には進学せず学部卒で2021 年に新卒入社しました。入社後に半年間の研修を経て、グループ経営ソリューション事業部に配属されました。 私が院に進学せず、IT企業を目指すことになったきっかけは2つあります。 1つ目は私が所属していた学部では毎年95%以上が院に進学しているという理由から、院に進学するのは当たり前という流れがあり、"〇〇の研究がしたい"というモチベーションの人がほとんどいなかったことです。モチベーション高く仕事をしている企業に就職した方が自己成長に繋がるのではないかと考えました。 2つ目はアルバイト先の塾で、生徒の点数ランキング作成の仕事を手書きという原始的な方法からエクセルの関数などを使って自動化したことにやりがいを感じたことです。 また、大学進学時に経済学部や 経営学 部に進学するか迷っていたこともありもともと会計には興味があったので、グループ経営ソリューション事業部に希望して希望通り配属されています。 自己紹介はこれくらいにして、これから私が所属する第2グループの業務のうち 新規開発 を中心にお話しします。 仕事内容 私が所属する一般会計 コンサルティング 部では自社パッケージの会計システムである Ci*Xシリーズ の 導入・新規開発・保守 を行っています。 その中でも第2グループでは新規開発・運用・保守を行っていて、私は主に 新規開発 に携わりました。 新規開発の作業工程 私のプロジェクトでは、新規開発の作業工程をざっくり分けると以下の8工程です。 このプロジェクトではそれぞれの工程(赤い箱:私が経験した工程)でどのようなことを行ったかを配属から2年の範囲内で説明します。 ※私が経験した内容のみに絞って説明しているので各工程で他に必要なことがあることに注意してください。 要件定義 要件定義では、ユーザーの要求をシステムで実現することを目的に、どのような機能を開発すれば要求を満たすことができるのかを考えるフェーズです。そして、洗い出された要件を要件定義書に文書化します。 メッセージ入力機能を例に挙げると、入力したメッセージをコピー、削除、送信取消、転送できる必要があるかなどを考えます。また、その領域に関して書籍やインターネットで調査し、それでもわからない論点などはその領域に詳しい方に質問をしました。 設計 設計は、要件定義書に記載された要件を満たすように機能を細かく考えるフェーズです。 具体的には、システムを動かす際に矛盾が生じないように、ユーザーがどのように機能を使うか( ユースケース 定義)、画面構成はどうするか、計算ロジックはどうするかなどを考えて以下の資料に記載します。 ユースケース 定義書(ユーザー目線でできることをまとめた資料) ドメイン モデル図(概念クラスの関係性の図をまとめた資料) 概念クラス(概念とその属性をまとめた資料) 画面定義書(画面のイメージや制御についてまとめた資料) ロジック定義書(複雑な処理の仕組みについてまとめた資料) 結合テスト 仕様書( 結合テスト に使用するテストケースをまとめた資料) 実装・ 単体テスト 実装・ 単体テスト は、設計書の設計内容を満たすように実際にコーディングし、設計書通りに動作するか確認するフェーズです。 実装で用いる技術要素は以下です。 バックエンド技術( Java , Spring Boot, Thymeleaf, PostgreSQL 等) フロントエンド技術( HTML5 、TypeScript、Vue.js 等) 結合テスト 結合テスト は、設計で作成した 結合テスト 仕様書に記載されたテストケースに従ってシステムが正しく動作しているかを検証するフェーズです。正しく動いていない場合や、設計書・ 結合テスト 仕様書が間違っている場合は欠陥として報告します。 製品化 製品化ではユーザーがシステムの操作で分からないときに閲覧できるマニュアルを作成します。 マニュアル作成 配属後からこれまでの流れ 配属後半年は簡単なタスクで製品のキャッチアップや技術のレベルアップを進め、 結合テスト を経験しました。その後、1年くらいで要件定義から実装・ 単体テスト までを経験することが出来ました。 業務の種類にもよりますが、まだマネジメント業務がないため MTG は比較的少なく作業がメインです。また、品質の高い実装力をつけるため、隔週で勉強会に参加して自己研鑽しています。 2年間働いてみて 配属から約1年半はテレワークメインでした。メンバーと直接的なコミュニケーションを取る機会がかなり少なかったため、質問しづらい関係性で業務に詰まったときは少し辛い環境でした。しかし、半年くらい前から出社日を合わせてプロジェクトメンバーと直接コミュニケーションを取ったことでリモートワークでも以前より質問がしやすい環境になり、今はかなりいい環境で働けていると思います。 業務ではシステムの新規開発で要件定義から 結合テスト までの工程を経験できたので、同年代の開発者の中では システム開発 に関して凄く幅広い経験をでき、力がかなりつきました。その経験は多くの知識(会計知識から開発の技術知識など)が必要なため、学習などで補ったりすることが大変ではありました。しかし、たくさん知識が付いたことで配属当初では考えられないほどの自信が付き、自己成長によるやりがいも感じています。また、 システム開発 では定番かもしれませんが、自分で設計した機能が実装されて実際に動くところを見ることでもやりがいを感じました。 先輩社員から、「この業界は3年間がインプット期間、4年目以降はアウトプットで結果を出す」と言われています。そのおかげて1つ1つのタスクで色々調べたりメモを残したりしてたくさんインプットできています。4年目からのプレッシャーが少しはありますが、それ以上にこの3年間の成長を実感しました。 自分がやりたいことをできる部署に配属してもらい、配属先でもやりたい業務をたくさん任せてもらいました。自分がやりたい・楽しいと思える仕事にたくさん関わることができ、最高のモチベーションで仕事をすることができています。これからもより楽しく仕事をやっていきたいと思っています。 最後に 就活生のみなさんには、やりたいことを明確にしてほしいと思っています。この記事を見て、第2グループでやっていることと自分のやりたいことが一致するかをぜひ考えてみてください。ISIDではやりたいことを発信していると、やらせてもらえることが多い環境だと思うので少しでもやりたいことができそうだと思った方は、ぜひご応募いただければなと思います。 www.isid.co.jp 執筆: @tsukamoto.sou 、レビュー: @sato.taichi ( Shodo で執筆されました )
アバター
こんにちは、グループ経営ソリューション( GMS )事業部 グループ経営 コンサルティング 第2ユニット 一般会計 コンサルティング 部 第2グループ、3年目の塚本です。 普段は会計ソリューションである Ci*Xシリーズ の新規開発を担当しています。 ※ Ci*Xシリーズの導入に関して気になる方は川島さんの以下の記事を参考にしてください。 SIerで自社製品導入をする新卒5年目(※IT経験なし)の働き方と今感じること~ちょこっと就活の話も添えて~ 本記事では、業務内容や 1 週間の過ごし方など、私の主な働き方についてざっくりとご紹介します。 IT 企業への就職を検討されている学生の方や、ISID にご興味をお持ちの方の参考になれば幸いです。 目次 目次 自己紹介 仕事内容 新規開発の作業工程 要件定義 設計 実装・単体テスト 結合テスト 製品化 配属後からこれまでの流れ 2年間働いてみて 最後に 自己紹介 私は工学部電気電子系学科出身で、4年間物理学を学んでいました。私の学部では通常であればそのまま院に進学し、メーカーや電気関係の企業に就職することがほとんどです。しかし、院には進学せず学部卒で2021 年に新卒入社しました。入社後に半年間の研修を経て、グループ経営ソリューション事業部に配属されました。 私が院に進学せず、IT企業を目指すことになったきっかけは2つあります。 1つ目は私が所属していた学部では毎年95%以上が院に進学しているという理由から、院に進学するのは当たり前という流れがあり、"〇〇の研究がしたい"というモチベーションの人がほとんどいなかったことです。モチベーション高く仕事をしている企業に就職した方が自己成長に繋がるのではないかと考えました。 2つ目はアルバイト先の塾で、生徒の点数ランキング作成の仕事を手書きという原始的な方法からエクセルの関数などを使って自動化したことにやりがいを感じたことです。 また、大学進学時に経済学部や 経営学 部に進学するか迷っていたこともありもともと会計には興味があったので、グループ経営ソリューション事業部に希望して希望通り配属されています。 自己紹介はこれくらいにして、これから私が所属する第2グループの業務のうち 新規開発 を中心にお話しします。 仕事内容 私が所属する一般会計 コンサルティング 部では自社パッケージの会計システムである Ci*Xシリーズ の 導入・新規開発・保守 を行っています。 その中でも第2グループでは新規開発・運用・保守を行っていて、私は主に 新規開発 に携わりました。 新規開発の作業工程 私のプロジェクトでは、新規開発の作業工程をざっくり分けると以下の8工程です。 このプロジェクトではそれぞれの工程(赤い箱:私が経験した工程)でどのようなことを行ったかを配属から2年の範囲内で説明します。 ※私が経験した内容のみに絞って説明しているので各工程で他に必要なことがあることに注意してください。 要件定義 要件定義では、ユーザーの要求をシステムで実現することを目的に、どのような機能を開発すれば要求を満たすことができるのかを考えるフェーズです。そして、洗い出された要件を要件定義書に文書化します。 メッセージ入力機能を例に挙げると、入力したメッセージをコピー、削除、送信取消、転送できる必要があるかなどを考えます。また、その領域に関して書籍やインターネットで調査し、それでもわからない論点などはその領域に詳しい方に質問をしました。 設計 設計は、要件定義書に記載された要件を満たすように機能を細かく考えるフェーズです。 具体的には、システムを動かす際に矛盾が生じないように、ユーザーがどのように機能を使うか( ユースケース 定義)、画面構成はどうするか、計算ロジックはどうするかなどを考えて以下の資料に記載します。 ユースケース 定義書(ユーザー目線でできることをまとめた資料) ドメイン モデル図(概念クラスの関係性の図をまとめた資料) 概念クラス(概念とその属性をまとめた資料) 画面定義書(画面のイメージや制御についてまとめた資料) ロジック定義書(複雑な処理の仕組みについてまとめた資料) 結合テスト 仕様書( 結合テスト に使用するテストケースをまとめた資料) 実装・ 単体テスト 実装・ 単体テスト は、設計書の設計内容を満たすように実際にコーディングし、設計書通りに動作するか確認するフェーズです。 実装で用いる技術要素は以下です。 バックエンド技術( Java , Spring Boot, Thymeleaf, PostgreSQL 等) フロントエンド技術( HTML5 、TypeScript、Vue.js 等) 結合テスト 結合テスト は、設計で作成した 結合テスト 仕様書に記載されたテストケースに従ってシステムが正しく動作しているかを検証するフェーズです。正しく動いていない場合や、設計書・ 結合テスト 仕様書が間違っている場合は欠陥として報告します。 製品化 製品化ではユーザーがシステムの操作で分からないときに閲覧できるマニュアルを作成します。 マニュアル作成 配属後からこれまでの流れ 配属後半年は簡単なタスクで製品のキャッチアップや技術のレベルアップを進め、 結合テスト を経験しました。その後、1年くらいで要件定義から実装・ 単体テスト までを経験することが出来ました。 業務の種類にもよりますが、まだマネジメント業務がないため MTG は比較的少なく作業がメインです。また、品質の高い実装力をつけるため、隔週で勉強会に参加して自己研鑽しています。 2年間働いてみて 配属から約1年半はテレワークメインでした。メンバーと直接的なコミュニケーションを取る機会がかなり少なかったため、質問しづらい関係性で業務に詰まったときは少し辛い環境でした。しかし、半年くらい前から出社日を合わせてプロジェクトメンバーと直接コミュニケーションを取ったことでリモートワークでも以前より質問がしやすい環境になり、今はかなりいい環境で働けていると思います。 業務ではシステムの新規開発で要件定義から 結合テスト までの工程を経験できたので、同年代の開発者の中では システム開発 に関して凄く幅広い経験をでき、力がかなりつきました。その経験は多くの知識(会計知識から開発の技術知識など)が必要なため、学習などで補ったりすることが大変ではありました。しかし、たくさん知識が付いたことで配属当初では考えられないほどの自信が付き、自己成長によるやりがいも感じています。また、 システム開発 では定番かもしれませんが、自分で設計した機能が実装されて実際に動くところを見ることでもやりがいを感じました。 先輩社員から、「この業界は3年間がインプット期間、4年目以降はアウトプットで結果を出す」と言われています。そのおかげて1つ1つのタスクで色々調べたりメモを残したりしてたくさんインプットできています。4年目からのプレッシャーが少しはありますが、それ以上にこの3年間の成長を実感しました。 自分がやりたいことをできる部署に配属してもらい、配属先でもやりたい業務をたくさん任せてもらいました。自分がやりたい・楽しいと思える仕事にたくさん関わることができ、最高のモチベーションで仕事をすることができています。これからもより楽しく仕事をやっていきたいと思っています。 最後に 就活生のみなさんには、やりたいことを明確にしてほしいと思っています。この記事を見て、第2グループでやっていることと自分のやりたいことが一致するかをぜひ考えてみてください。ISIDではやりたいことを発信していると、やらせてもらえることが多い環境だと思うので少しでもやりたいことができそうだと思った方は、ぜひご応募いただければなと思います。 www.isid.co.jp 執筆: @tsukamoto.sou 、レビュー: @sato.taichi ( Shodo で執筆されました )
アバター
こんにちは。ISID 金融ソリューション事業部の若本です。 先日、GPT-4から発展し、 画像も扱うことができるGPT-4 with vision(GPT-4V)が発表 されました。GPT-4Vは大規模マルチモーダルモデル(LMMs: Large multimodal models)と呼ばれるAIモデルの一種であり、GPT-4の入力として「画像」を拡張したものになります。 今日は Microsoft Researchの論文[1]を中心に、Open AIの発表したSystem Card[2]も踏まえ、GPT-4Vでできることや苦手とすること、そして実用上の制限について解説します。 GPT-4Vの特徴 ① 画像とテキストを入力にできる GPT-4Vでは、GPT-4のテキスト入力に加えて画像も入力することが可能になりました。 画像は複数枚入力することが可能であり、かつ、画像とテキストを任意に交互に組み合わせて入力できます。 ② 画像に関する常識を理解している 画像の中の情報を判別するだけでなく、視覚的な常識に基づいて推論を行うことができます。 例)着用している服装から結婚式の画像だと判断する、部屋のレイアウトから気候や家主の特性を判断する、など ③ 多言語/多文化を理解している GPT-4と同様に、画像についても多言語の入力/出力が可能です。例では、手書き文字に近い崩れたフォントについても正しく理解し、多言語で出力されています。 また、特定の文化圏に関する画像についても理解し説明できることが論文中で示されています。 ④ 感情を理解している 画像中の人間の表情から感情を識別できます。他にも、入力した画像コンテンツがどのような印象を相手に与えるのかといった視覚的な感情も解釈することができます。 また、ネット ミーム の説明などユーモアを理解する能力を持っていることも報告されています。 GPT-4Vができるタスク ① 画像/ビデオの説明 撮影条件に大きく左右されず、画像について説明することができます。画像全体のマクロな説明から、画像内の特定のオブジェクトについてのミクロな説明も可能です。 また、フレームごとに画像を与えることで、ビデオも入力し説明できます。画像の例では、シュートのタイミングやゴールの結果まで推論することができており、画像内の空間的な位置関係と画像同士の時間関係を理解できていることがわかります。 ② 物体の位置特定 画像中の物体の位置や、その物体が何か特定できます。画像の例では、画像内に映る複数人の人物の位置を特定し、それぞれ位置座標と説明を出力しています。 上記のようにテキスト形式で位置座標を取得する( バウンディ ングボックス)ことはできますが、GPT-4V単体で出力した バウンディ ングボックスの位置座標は正確でない場合があります。ただし、これはpromptによって改善可能です。 ③ 画像中の文章/記号/表をもとにした推論 画像ベースで非言語知能テスト(以下の例は Raven’s Progressive Matrices )に答えることも可能です。画像内の文章や記号を理解し、解答することが可能です。 PDF化された論文のような複雑な視覚情報でも、一部詳細についてミスは発生したものの大まかには正しく説明されることが示されていました。これらの理解能力を応用することで、Web ブラウジング のようなエージェント操作も実行できる可能性があることが示されています。 ④ 生成AIの出力の改善 画像生成AIに与える指示(prompt)を生成することで、生成AIを用いた画像編集のような ユースケース でより手間をかけない編集が可能になります。画像の例では、暗いトーンでより表紙らしい画像にするための指示をGPT-4Vを用いて生成しています。 ただし、System cardによると、コンテンツ生成について「GPT-4Vは虚偽情報を検出する手段として使用したり、真偽を検証する手段として使用すべきではない」と述べられているため、画像生成の完全な自動化については推奨されていません。 GPT-4Vが比較的苦手とするタスク ① 間違い探し 2つの画像を比較するタスク(間違い探し)はある程度可能ですが、完璧な精度ではないようです。 ② 2023年以降の情報が必要なタスク GPT-4Vは2022年に学習を完了しているため、被災地の写真の説明など、2023年以降の知識が必要なタスクはGPT-4V単体で解くことができません。論文中では、Bing Image Search プラグイン を用いて関連画像を検索した後、GPT-4Vに説明させています。 ③ 専門家の知識が必要なタスク(医療診断) 医療分野における 放射線 報告書の生成タスクを実施し、ある程度の診断精度と高品質なフォーマットから専門家の作業量減少に寄与できる可能性はあるとされる一方、誤識別や数値のミスがありました。 System Cardにおいても、専門家の検証の結果、「医療領域において完璧なパフォーマンスではなく、現在のバージョンのGPT-4Vは医療を遂行するための専門的な医療アド バイス 、診断、治療、判断を代替するには適していない」と結論付けています。 ④ 画像の情報量が多い/読み取れないタスク これまでご紹介したいずれのタスクにおいても、画像内のオブジェクトが非常に混み入っていたり、一目で識別できないほど必要な情報が隠れているとGPT-4Vで推論することは難しくなります。特に、物体のカウントや前述の物体位置検出などでは情報量の多い画像において精度が悪化していました。 制限 Open AIにより、下記のようなクエリには応答しないようチューニングが施されているようです[2]。 身元情報の特定 例)人物の画像をアップロードして誰か特定する、2つの画像を使用して同じ人物かどうかを尋ねるなど 機密情報の窃取 例)年齢、人種など 根拠のない推論を招く幅の広いクエリ 例)画像内の人物にアド バイス してください、など 加えて、GPT-4やDALL·Eの API で用いられているシステム側の分類器も機能し、これまで通り動作します。 その他、筆者の環境ではGPT-4Vが執筆時点で解放されていないため不明ですが、リク エス トには最大画像枚数や画像の解像度などに制限があるかもしれません。 おわりに 今回は、論文をベースにGPT-4Vのできることやその特徴についてご紹介しました。promptのコツなども紹介されており、cookbookとしても非常に参考になる論文ですので、興味のある方はぜひご一読をおすすめします。 また、Conclusionには、今後のLMMsの進化として 1) 画像を生成する、2)ビデオ/オーディオなど別の情報を入力として増やす、などが述べられていました。今後、より進化したLMMsの登場により、さらに広範囲に我々の生活にAIが浸透していくことが期待されます。 参考文献 [1]: The Dawn of LMMs: Preliminary Explorations with GPT-4V(ision) [2]: GPT-4V(ision) System Card 執筆: @wakamoto.ryosuke 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
こんにちは。ISID 金融ソリューション事業部の若本です。 先日、GPT-4から発展し、 画像も扱うことができるGPT-4 with vision(GPT-4V)が発表 されました。GPT-4Vは大規模マルチモーダルモデル(LMMs: Large multimodal models)と呼ばれるAIモデルの一種であり、GPT-4の入力として「画像」を拡張したものになります。 今日は Microsoft Researchの論文[1]を中心に、Open AIの発表したSystem Card[2]も踏まえ、GPT-4Vでできることや苦手とすること、そして実用上の制限について解説します。 GPT-4Vの特徴 ① 画像とテキストを入力にできる GPT-4Vでは、GPT-4のテキスト入力に加えて画像も入力することが可能になりました。 画像は複数枚入力することが可能であり、かつ、画像とテキストを任意に交互に組み合わせて入力できます。 ② 画像に関する常識を理解している 画像の中の情報を判別するだけでなく、視覚的な常識に基づいて推論を行うことができます。 例)着用している服装から結婚式の画像だと判断する、部屋のレイアウトから気候や家主の特性を判断する、など ③ 多言語/多文化を理解している GPT-4と同様に、画像についても多言語の入力/出力が可能です。例では、手書き文字に近い崩れたフォントについても正しく理解し、多言語で出力されています。 また、特定の文化圏に関する画像についても理解し説明できることが論文中で示されています。 ④ 感情を理解している 画像中の人間の表情から感情を識別できます。他にも、入力した画像コンテンツがどのような印象を相手に与えるのかといった視覚的な感情も解釈することができます。 また、ネット ミーム の説明などユーモアを理解する能力を持っていることも報告されています。 GPT-4Vができるタスク ① 画像/ビデオの説明 撮影条件に大きく左右されず、画像について説明することができます。画像全体のマクロな説明から、画像内の特定のオブジェクトについてのミクロな説明も可能です。 また、フレームごとに画像を与えることで、ビデオも入力し説明できます。画像の例では、シュートのタイミングやゴールの結果まで推論することができており、画像内の空間的な位置関係と画像同士の時間関係を理解できていることがわかります。 ② 物体の位置特定 画像中の物体の位置や、その物体が何か特定できます。画像の例では、画像内に映る複数人の人物の位置を特定し、それぞれ位置座標と説明を出力しています。 上記のようにテキスト形式で位置座標を取得する( バウンディ ングボックス)ことはできますが、GPT-4V単体で出力した バウンディ ングボックスの位置座標は正確でない場合があります。ただし、これはpromptによって改善可能です。 ③ 画像中の文章/記号/表をもとにした推論 画像ベースで非言語知能テスト(以下の例は Raven’s Progressive Matrices )に答えることも可能です。画像内の文章や記号を理解し、解答することが可能です。 PDF化された論文のような複雑な視覚情報でも、一部詳細についてミスは発生したものの大まかには正しく説明されることが示されていました。これらの理解能力を応用することで、Web ブラウジング のようなエージェント操作も実行できる可能性があることが示されています。 ④ 生成AIの出力の改善 画像生成AIに与える指示(prompt)を生成することで、生成AIを用いた画像編集のような ユースケース でより手間をかけない編集が可能になります。画像の例では、暗いトーンでより表紙らしい画像にするための指示をGPT-4Vを用いて生成しています。 ただし、System cardによると、コンテンツ生成について「GPT-4Vは虚偽情報を検出する手段として使用したり、真偽を検証する手段として使用すべきではない」と述べられているため、画像生成の完全な自動化については推奨されていません。 GPT-4Vが比較的苦手とするタスク ① 間違い探し 2つの画像を比較するタスク(間違い探し)はある程度可能ですが、完璧な精度ではないようです。 ② 2023年以降の情報が必要なタスク GPT-4Vは2022年に学習を完了しているため、被災地の写真の説明など、2023年以降の知識が必要なタスクはGPT-4V単体で解くことができません。論文中では、Bing Image Search プラグイン を用いて関連画像を検索した後、GPT-4Vに説明させています。 ③ 専門家の知識が必要なタスク(医療診断) 医療分野における 放射線 報告書の生成タスクを実施し、ある程度の診断精度と高品質なフォーマットから専門家の作業量減少に寄与できる可能性はあるとされる一方、誤識別や数値のミスがありました。 System Cardにおいても、専門家の検証の結果、「医療領域において完璧なパフォーマンスではなく、現在のバージョンのGPT-4Vは医療を遂行するための専門的な医療アド バイス 、診断、治療、判断を代替するには適していない」と結論付けています。 ④ 画像の情報量が多い/読み取れないタスク これまでご紹介したいずれのタスクにおいても、画像内のオブジェクトが非常に混み入っていたり、一目で識別できないほど必要な情報が隠れているとGPT-4Vで推論することは難しくなります。特に、物体のカウントや前述の物体位置検出などでは情報量の多い画像において精度が悪化していました。 制限 Open AIにより、下記のようなクエリには応答しないようチューニングが施されているようです[2]。 身元情報の特定 例)人物の画像をアップロードして誰か特定する、2つの画像を使用して同じ人物かどうかを尋ねるなど 機密情報の窃取 例)年齢、人種など 根拠のない推論を招く幅の広いクエリ 例)画像内の人物にアド バイス してください、など 加えて、GPT-4やDALL·Eの API で用いられているシステム側の分類器も機能し、これまで通り動作します。 その他、筆者の環境ではGPT-4Vが執筆時点で解放されていないため不明ですが、リク エス トには最大画像枚数や画像の解像度などに制限があるかもしれません。 おわりに 今回は、論文をベースにGPT-4Vのできることやその特徴についてご紹介しました。promptのコツなども紹介されており、cookbookとしても非常に参考になる論文ですので、興味のある方はぜひご一読をおすすめします。 また、Conclusionには、今後のLMMsの進化として 1) 画像を生成する、2)ビデオ/オーディオなど別の情報を入力として増やす、などが述べられていました。今後、より進化したLMMsの登場により、さらに広範囲に我々の生活にAIが浸透していくことが期待されます。 参考文献 [1]: The Dawn of LMMs: Preliminary Explorations with GPT-4V(ision) [2]: GPT-4V(ision) System Card 執筆: @wakamoto.ryosuke 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
こんにちは、X イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの福山です。 今回は、弊社CSIRTチームの一機能として活動している「 脆弱性 管理チーム」の活動に関する内容となります。 昨今では、Log4shellやSpring4shellなど、影響範囲の広い 脆弱性 が後を絶ちません。 これらの緊急度の高い 脆弱性 情報が公開された場合を想定した、情報収集〜現場対応までのCSIRT目線での模擬訓練を、FutureVulsを含めて実施してみましたので紹介したいと思います。 FutureVulsとは FutureVulsを導入した経緯 事前準備 模擬訓練 情報収集 トリアージ 全社周知 個別周知 対応状況の確認 対応結果 見つかった課題 最後に FutureVulsとは フューチャー株式会社が開発する OSS の 脆弱性 スキャナVulsがベースになっており、組織単位で継続的に 脆弱性 管理するための 脆弱性 管理サービスです。 参考: https://vuls.biz/ FutureVulsの主な特徴についてピックアップします。 スキャンについて 検知精度、検知スピードに優れており、サーバへの負荷が軽い。 スキャナを導入せずに手動でソフトウェア情報を登録し、管理することも可能。 検出された情報について ソフトウェア情報の一括管理や、複数グループを束ねたグループセットでの横断検索が可能。 参考: グループセット 検出された 脆弱性 情報を一覧で一括管理が可能。 自動 トリアージ について 脆弱性 の危険度合いをスコアで示すCVSSによる従来の評価手法では、以下の点が考慮されていません。 脆弱性 の悪用の容易さ 実際の資産が攻撃を受ける環境にあるか 資産価値 攻撃を受けた際の業務影響度合い また、現場でどのように対応すべきかの判断がもう一段階必要となってきます。 そこで2019年12月、これらを解決する新しい評価手法「SSVC(Stakeholder-Specific Vulnerability Categorization)」が米 カーネギーメロン大学 ソフトウェア工学 研究所によって提案されました。 SSVCでは意思決定ツリーを用いて「immediate」「out_of_cycle」「scheduled」「defer」の4段階で対応優先度を導出します。 FutureVulsにはSSVCの機能が早くも導入されており、各 脆弱性 に対して4段階評価で対応優先度が自動で付与されることで、現場の負担を減らすことができます。 参考: SSVC(Stakeholder-Specific Vulnerability Categorization)を活用した脆弱性管理 FutureVulsを導入した経緯 FutureVulsを活用した 脆弱性 管理チームの緊急時運用フローを確認したい 弊社ではNIST NVD、 JVN iPediaから収集した情報と、シートに入力された各プロジェクトのソフトウェア情報を突き合わせ、該当する 脆弱性 情報の個別周知運用を行っていました。 ただし以下の課題があり、その要件を満たすべく2023年7月よりFutureVulsに本番移行することが決まりました。 <FutureVuls導入前の課題> より正確かつ最新のソフトウェア情報を管理したい 該当する 脆弱性 情報をよりタ イムリ ーに周知したい 各プロジェクトに個別に対応判断を委ねず、判断基準を設けたい 対応状況をより正確に把握したい 事前準備 訓練に使用する 脆弱性 はSpring4Shell(CVE-2022-22965)を採用 Spring4Shellの採用に至った条件は以下 仮想の 脆弱性 ではなく、既存の 脆弱性 を利用した方がやりやすい 社内で利用されているソフトウェア 擬似サーバへの CPE 登録が想定されるもの 参考: 擬似サーバとは リモートコード実行が可能な 脆弱性 で、PoCが公開されているもの 公表された時点でCVE未採番で、セキュリティパッチが公開されていないもの 事前にプロジェクトに協力を募り、3プロジェクトからの協力を取り付ける FutureVulsの擬似サーバを利用し、 CPE 形式でソフトウェア情報を登録 プロジェクトA Spring Framework 5.3.17 OracleJDK 9 Apache HTTP Server 2.4.53 Apache Tomcat 9.0.60 プロジェクトB Spring Boot 2.5.0 OpenJDK 9 nginx 1.6.0 Apache Tomcat 9.0.59 プロジェクトC Spring Framework 5.2.0 OracleJDK 8 Apache HTTP Server 2.4.52 Apache Tomcat 9.0.59 模擬訓練 模擬訓練の流れは以下となります。 情報収集 -> トリアージ -> 全社周知 -> 個別周知 -> 対応状況の確認 なお、全社周知と個別周知の役割の違いは以下です。 全社周知 個別周知 ・ゼロデイ 脆弱性 等、CVEが採番される前の段階でも情報をいち早く整理し伝える ・該当プロジェクトに直接周知することで、対応が必要であることを認識していただく ・影響を受ける条件や、PoCの再現結果を掲載する ・該当プロジェクトの対応状況を可視化する ・FutureVulsを利用しない社員向けにも周知する 以上を踏まえて、実際の訓練の内容に移ります。 情報収集 社内で利用されているソフトウェアにおいて、ゼロデイ 脆弱性 や影響範囲の広い 脆弱性 情報が公開されていないか、複数のWebサイトでチェックしています。 よく参考にしている情報発信元を紹介します。 CyberSecurityHelp:独自の 脆弱性 DBを公開しており、リスク評価、パッチの提供有無、Atack Vector 、Public exploit(実際の悪用有無)、Exploit availability(PoC、攻撃コードの有無)、回避策などの情報をタ イムリ ーに提供するサイトで、公開されるタイミングはCVE採番後。 URL: https://www.cybersecurity-help.cz/ Lunasec:米セキュリティ企業。2021年に公開されたLog4Shellの際にもブログをいち早く公開しており、影響を受ける条件、PoC、回避策などをわかりやすくブログにまとめている URL: https://www.lunasec.io/docs/blog/spring-rce-vulnerabilities/ Bleeping Computer: 脆弱性 情報を含む最新のセキュリティニュースをいち早く提供する海外サイト URL: https://www.bleepingcomputer.com/tag/vulnerability/ Security Next: 脆弱性 情報を含む最新のセキュリティニュースを日本語でいち早く提供するサイト URL: https://www.security-next.com/135304 piyolog: 脆弱性 情報を含む最新のセキュリティニュースがわかりやすく日本語で解説されたブログ URL: https://piyolog.hatenadiary.jp/entry/2022/04/01/065946 GitHub Advisory Database: GitHub Security Advisoriesで公開された 脆弱性 や、依存関係を追跡して得られた依存先ソフトウェアの 脆弱性 を一覧表示する URL: https://github.com/advisories ただし、これらはあくまで参考情報ですので、最終的に一次情報源の確認は必須です。 公的機関( JPCERT/CC 、 JVN 、 IPA 、NIST NVD) 開発元(今回はSpring) URL: https://spring.io/security/ トリアージ これまでの情報を整理した上で、全社周知要否( トリアージ )を2つの観点で実施します。 影響範囲の確認 各プロジェクトにおける利用状況を確認するため、FutureVulsのグループセットからソフトウェア名で検索します。 参考: グループセット内のソフトウェア名検索 緊急度合いの確認 脆弱性 管理チームで利用している緊急度 判断表 をもとに、緊急度を確認します。 No RCE PoC 開発元の評価 緊急度 1 可能 有 高以上 緊急 2 可能 無 高以上 高 3 不可 有 高以上 高 4 不可 無 高以上 中 5 可能 有 中以下 高 6 可能 無 中以下 中 7 不可 有 中以下 中 8 不可 無 中以下 中 9 可能 有 未評価 緊急 10 可能 無 未評価 高 11 不可 有 未評価 高 12 不可 無 未評価 中 公表時点では、No.9の「緊急」に該当しました。 トリアージ の結果、全社周知が必要と判断したため次のステップに進みます。 全社周知 全社周知の準備を進めつつ、MITRE社によるCVE採番状況のチェックもしながら状況変化をキャッチアップします。 URL: https://cve.mitre.org/cve/search_cve_list.html PoC、回避策の検証 まずはPoCを探すところからですが、例として以下の リポジトリ では、 GitHub で公開されているPoCを自動収集しています。 URL: https://github.com/nomi-sec/PoC-in-GitHub/tree/master 当時、実際に対応した際は以下のPoCが出回っており、こちらを実施しました。 LunaSec社も改善に加わっているようです。(※中には悪意のあるPoCを公開している リポジトリ もあるため、コードの中身をよく読んで、社内と隔離されたネットワーク上で実行するようにする) URL: https://github.com/reznok/Spring4Shell-POC dockerを利用するため容易に実施できるものになっています。(環境構築に時間が掛かる場合があります) また、Lunasecによると、脆弱パターンの ブラックリスト を記載したInitBinderを挿入することが緩和策になると謳っています。 全社周知(社内 ポータルサイト へのニュース掲載) 内容としては以下の項目をまとめています。 脆弱性 の概要(RCEの可否、PoCの有無も含む) 影響を受けるソフトウェアバージョンおよび条件 根本対策(パッチ公開情報) 回避策(PoCの実施結果) 攻撃の兆候がないかログの確認を依頼(SOCがあれば活用) 参考情報 CVE採番後の対応 MITER社から公開されるCVE採番情報を確認したら、以下のチェックおよび対応します。 公的機関、開発元から情報が公開・更新されているか 情報収集の際にチェックした各発信元の情報が更新されているか パッチのリリース状況 社内 ポータルサイト に投稿した記事に追記 個別周知 次に、 脆弱性 バージョンを利用している該当プロジェクトに対して個別周知、対応期限を設定します。 オーガニゼーショントピック(CVE別にトピックを立てて情報共有できる機能)の投稿 参考: トピックによる情報共有・注意喚起 送信すると、該当するグループの全メンバへメールが発報されます。 また、SlackやTeamsへの連携も可能です。 Slack連携: https://help.vuls.biz/manual/notification/slack_app/ Teams連携: https://help.vuls.biz/manual/notification/teams/ スペシャ ル警戒タグの設定 こちらの機能を簡単にご紹介します。 脆弱性 単位で独自のタグを付けられる 例えば、「全社周知対象(トピック掲載あり)」や「緊急対応必須」として、ユーザへの情報認識を早めたり、CSIRT側で後から状況を見返す時に便利になると思います。 タグは1つのCVE-IDに対して複数設定できます。 対応期限を設定でき、該当タスクの対応期限を一括で上書き更新できる CVE検知済みのグループに対して設定された旨の通知ができる(通知の際、コメントは不可) 参考: スペシャル警戒タグ機能 今回の対応期限は判断日の5営業日後としました。 各プロジェクトの 脆弱性 情報のサマリに警戒タグが入りました。 対応状況の確認 最後に各プロジェクトの対応状況を後追いします。 FutureVulsではタスクステータスを用いて、対応状況を管理できます。 タスク対応の流れは以下です。 引用: ステータス 次のアクションとして、 スペシャ ル警戒タグで設定した対応期限を超過したタスクに対してリマインドします。 対応期限の翌営業日になったら、グループセットのタスクタブから、フィルターでCVE-2022-22965のタスクステータスが「NEW(新規)」と「INVESTIGATING(調査中)」を抽出します。 タスクに一括チェックした上で、タスクを編集からコメントを送信することで、該当グループの所属メンバ全員にメールを送信できます。 その後はタスクのコメント上でのやり取りも可能です。 対応結果 模擬訓練に参加したプロジェクトの対応結果は以下のようになりました。 プロジェクト 結果 ソフトウェア別の対応 プロジェクトA CPE スキャン(*)にて検出され、対応完了 Spring Framework 5.3.17が検出対象となったため、最新バージョンに CPE を更新し、クローズ プロジェクトB CPE スキャンでは検出できず、個別連絡にて対応依頼の上、完了 Spring Boot 2.5.0は Spring Framework に依存しているが、 CPE スキャンでは検出されず。原因と対応策は下記課題3を参照。Spring Bootの最新バージョンに CPE を更新。 プロジェクトC CPE スキャンにて検出され、対応完了 JDK 8は影響を受けないが検出対象となった。原因と対応策は下記課題4を参照。タスクのステータスを「NOT_AFFECTED(影響なし)」に変更し、クローズ。 * CPE スキャン:擬似サーバ上にソフトウェア名、バージョン情報を手動登録し、日次でスキャンさせる機能。 参考: CPEスキャン 見つかった課題 模擬訓練を通して発見した課題についてまとめます。 No 課題 対応策 補足 1 CVE未採番の状態でもユーザへ第一報を通知したい グループセットのソフトウェアタブで「Spring」と検索し、該当するプロジェクトメンバに連絡する FutureVulsのオーガニゼーショントピックや スペシャ ル警戒タグはCVE採番済みの 脆弱性 に対してしか利用できない。現状はチャットなど別の手段で連絡するしかない。 2 対応済みのプロジェクトにもオーガニゼーショントピックが通知されてしまう オーガニゼーショントピックをなるべく早めに発報することで、対応済み案件へ通知される確率を下げる。またトピック内に注意書きを入れる。 オーガニゼーショントピックは 脆弱性 単位で通知する機能となっており、各タスクのステータスまでチェックしないため、既に対応がクローズしている案件にも通知されるため、注意が必要。 3 Spring Bootの脆弱バージョンを CPE スキャンしても、CVE-2022-22965が検出されない 依存ライブラリスキャンを利用する CPE スキャンは登録したライブラリや フレームワーク の依存ライブラリの 脆弱性 までは検知できない。依存ライブラリスキャンの手法の1つとして GitHub Security Alerts連携 がある。PoCで利用したSpring Bootのpom. xml をスキャン対象の GitHub リポジトリ に手動であげるとFutureVuls側で検出されることを確認。 4 JDK 8であれば影響を受けないはずだが検出されてしまう トピック内に影響を受ける条件を記載し、プロジェクト側にステータスを「NOT_AFFECTED(影響なし)」に変更してもらうようにする FutureVulsには外部条件を考慮した検知の仕組みは現状ないため、ステータスを変更してもらう必要がある 最後に 今回、 脆弱性 対応模擬訓練を行うことで、FutureVulsを活用した緊急時の一連のフローを確認することができました。 また、課題はいくつか見つかりましたが、運用でカバーできそうであることもわかりました。 FutureVulsはリリース頻度が高いため、このあたりの課題が機能アップデートによって解消されることに期待したいと思います! 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア 執筆: @fukuyama.kenta ( Shodo で執筆されました )
アバター
こんにちは、X イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの福山です。 今回は、弊社CSIRTチームの一機能として活動している「 脆弱性 管理チーム」の活動に関する内容となります。 昨今では、Log4shellやSpring4shellなど、影響範囲の広い 脆弱性 が後を絶ちません。 これらの緊急度の高い 脆弱性 情報が公開された場合を想定した、情報収集〜現場対応までのCSIRT目線での模擬訓練を、FutureVulsを含めて実施してみましたので紹介したいと思います。 FutureVulsとは FutureVulsを導入した経緯 事前準備 模擬訓練 情報収集 トリアージ 全社周知 個別周知 対応状況の確認 対応結果 見つかった課題 最後に FutureVulsとは フューチャー株式会社が開発する OSS の 脆弱性 スキャナVulsがベースになっており、組織単位で継続的に 脆弱性 管理するための 脆弱性 管理サービスです。 参考: https://vuls.biz/ FutureVulsの主な特徴についてピックアップします。 スキャンについて 検知精度、検知スピードに優れており、サーバへの負荷が軽い。 スキャナを導入せずに手動でソフトウェア情報を登録し、管理することも可能。 検出された情報について ソフトウェア情報の一括管理や、複数グループを束ねたグループセットでの横断検索が可能。 参考: グループセット 検出された 脆弱性 情報を一覧で一括管理が可能。 自動 トリアージ について 脆弱性 の危険度合いをスコアで示すCVSSによる従来の評価手法では、以下の点が考慮されていません。 脆弱性 の悪用の容易さ 実際の資産が攻撃を受ける環境にあるか 資産価値 攻撃を受けた際の業務影響度合い また、現場でどのように対応すべきかの判断がもう一段階必要となってきます。 そこで2019年12月、これらを解決する新しい評価手法「SSVC(Stakeholder-Specific Vulnerability Categorization)」が米 カーネギーメロン大学 ソフトウェア工学 研究所によって提案されました。 SSVCでは意思決定ツリーを用いて「immediate」「out_of_cycle」「scheduled」「defer」の4段階で対応優先度を導出します。 FutureVulsにはSSVCの機能が早くも導入されており、各 脆弱性 に対して4段階評価で対応優先度が自動で付与されることで、現場の負担を減らすことができます。 参考: SSVC(Stakeholder-Specific Vulnerability Categorization)を活用した脆弱性管理 FutureVulsを導入した経緯 FutureVulsを活用した 脆弱性 管理チームの緊急時運用フローを確認したい 弊社ではNIST NVD、 JVN iPediaから収集した情報と、シートに入力された各プロジェクトのソフトウェア情報を突き合わせ、該当する 脆弱性 情報の個別周知運用を行っていました。 ただし以下の課題があり、その要件を満たすべく2023年7月よりFutureVulsに本番移行することが決まりました。 <FutureVuls導入前の課題> より正確かつ最新のソフトウェア情報を管理したい 該当する 脆弱性 情報をよりタ イムリ ーに周知したい 各プロジェクトに個別に対応判断を委ねず、判断基準を設けたい 対応状況をより正確に把握したい 事前準備 訓練に使用する 脆弱性 はSpring4Shell(CVE-2022-22965)を採用 Spring4Shellの採用に至った条件は以下 仮想の 脆弱性 ではなく、既存の 脆弱性 を利用した方がやりやすい 社内で利用されているソフトウェア 擬似サーバへの CPE 登録が想定されるもの 参考: 擬似サーバとは リモートコード実行が可能な 脆弱性 で、PoCが公開されているもの 公表された時点でCVE未採番で、セキュリティパッチが公開されていないもの 事前にプロジェクトに協力を募り、3プロジェクトからの協力を取り付ける FutureVulsの擬似サーバを利用し、 CPE 形式でソフトウェア情報を登録 プロジェクトA Spring Framework 5.3.17 OracleJDK 9 Apache HTTP Server 2.4.53 Apache Tomcat 9.0.60 プロジェクトB Spring Boot 2.5.0 OpenJDK 9 nginx 1.6.0 Apache Tomcat 9.0.59 プロジェクトC Spring Framework 5.2.0 OracleJDK 8 Apache HTTP Server 2.4.52 Apache Tomcat 9.0.59 模擬訓練 模擬訓練の流れは以下となります。 情報収集 -> トリアージ -> 全社周知 -> 個別周知 -> 対応状況の確認 なお、全社周知と個別周知の役割の違いは以下です。 全社周知 個別周知 ・ゼロデイ 脆弱性 等、CVEが採番される前の段階でも情報をいち早く整理し伝える ・該当プロジェクトに直接周知することで、対応が必要であることを認識していただく ・影響を受ける条件や、PoCの再現結果を掲載する ・該当プロジェクトの対応状況を可視化する ・FutureVulsを利用しない社員向けにも周知する 以上を踏まえて、実際の訓練の内容に移ります。 情報収集 社内で利用されているソフトウェアにおいて、ゼロデイ 脆弱性 や影響範囲の広い 脆弱性 情報が公開されていないか、複数のWebサイトでチェックしています。 よく参考にしている情報発信元を紹介します。 CyberSecurityHelp:独自の 脆弱性 DBを公開しており、リスク評価、パッチの提供有無、Atack Vector 、Public exploit(実際の悪用有無)、Exploit availability(PoC、攻撃コードの有無)、回避策などの情報をタ イムリ ーに提供するサイトで、公開されるタイミングはCVE採番後。 URL: https://www.cybersecurity-help.cz/ Lunasec:米セキュリティ企業。2021年に公開されたLog4Shellの際にもブログをいち早く公開しており、影響を受ける条件、PoC、回避策などをわかりやすくブログにまとめている URL: https://www.lunasec.io/docs/blog/spring-rce-vulnerabilities/ Bleeping Computer: 脆弱性 情報を含む最新のセキュリティニュースをいち早く提供する海外サイト URL: https://www.bleepingcomputer.com/tag/vulnerability/ Security Next: 脆弱性 情報を含む最新のセキュリティニュースを日本語でいち早く提供するサイト URL: https://www.security-next.com/135304 piyolog: 脆弱性 情報を含む最新のセキュリティニュースがわかりやすく日本語で解説されたブログ URL: https://piyolog.hatenadiary.jp/entry/2022/04/01/065946 GitHub Advisory Database: GitHub Security Advisoriesで公開された 脆弱性 や、依存関係を追跡して得られた依存先ソフトウェアの 脆弱性 を一覧表示する URL: https://github.com/advisories ただし、これらはあくまで参考情報ですので、最終的に一次情報源の確認は必須です。 公的機関( JPCERT/CC 、 JVN 、 IPA 、NIST NVD) 開発元(今回はSpring) URL: https://spring.io/security/ トリアージ これまでの情報を整理した上で、全社周知要否( トリアージ )を2つの観点で実施します。 影響範囲の確認 各プロジェクトにおける利用状況を確認するため、FutureVulsのグループセットからソフトウェア名で検索します。 参考: グループセット内のソフトウェア名検索 緊急度合いの確認 脆弱性 管理チームで利用している緊急度 判断表 をもとに、緊急度を確認します。 No RCE PoC 開発元の評価 緊急度 1 可能 有 高以上 緊急 2 可能 無 高以上 高 3 不可 有 高以上 高 4 不可 無 高以上 中 5 可能 有 中以下 高 6 可能 無 中以下 中 7 不可 有 中以下 中 8 不可 無 中以下 中 9 可能 有 未評価 緊急 10 可能 無 未評価 高 11 不可 有 未評価 高 12 不可 無 未評価 中 公表時点では、No.9の「緊急」に該当しました。 トリアージ の結果、全社周知が必要と判断したため次のステップに進みます。 全社周知 全社周知の準備を進めつつ、MITRE社によるCVE採番状況のチェックもしながら状況変化をキャッチアップします。 URL: https://cve.mitre.org/cve/search_cve_list.html PoC、回避策の検証 まずはPoCを探すところからですが、例として以下の リポジトリ では、 GitHub で公開されているPoCを自動収集しています。 URL: https://github.com/nomi-sec/PoC-in-GitHub/tree/master 当時、実際に対応した際は以下のPoCが出回っており、こちらを実施しました。 LunaSec社も改善に加わっているようです。(※中には悪意のあるPoCを公開している リポジトリ もあるため、コードの中身をよく読んで、社内と隔離されたネットワーク上で実行するようにする) URL: https://github.com/reznok/Spring4Shell-POC dockerを利用するため容易に実施できるものになっています。(環境構築に時間が掛かる場合があります) また、Lunasecによると、脆弱パターンの ブラックリスト を記載したInitBinderを挿入することが緩和策になると謳っています。 全社周知(社内 ポータルサイト へのニュース掲載) 内容としては以下の項目をまとめています。 脆弱性 の概要(RCEの可否、PoCの有無も含む) 影響を受けるソフトウェアバージョンおよび条件 根本対策(パッチ公開情報) 回避策(PoCの実施結果) 攻撃の兆候がないかログの確認を依頼(SOCがあれば活用) 参考情報 CVE採番後の対応 MITER社から公開されるCVE採番情報を確認したら、以下のチェックおよび対応します。 公的機関、開発元から情報が公開・更新されているか 情報収集の際にチェックした各発信元の情報が更新されているか パッチのリリース状況 社内 ポータルサイト に投稿した記事に追記 個別周知 次に、 脆弱性 バージョンを利用している該当プロジェクトに対して個別周知、対応期限を設定します。 オーガニゼーショントピック(CVE別にトピックを立てて情報共有できる機能)の投稿 参考: トピックによる情報共有・注意喚起 送信すると、該当するグループの全メンバへメールが発報されます。 また、SlackやTeamsへの連携も可能です。 Slack連携: https://help.vuls.biz/manual/notification/slack_app/ Teams連携: https://help.vuls.biz/manual/notification/teams/ スペシャ ル警戒タグの設定 こちらの機能を簡単にご紹介します。 脆弱性 単位で独自のタグを付けられる 例えば、「全社周知対象(トピック掲載あり)」や「緊急対応必須」として、ユーザへの情報認識を早めたり、CSIRT側で後から状況を見返す時に便利になると思います。 タグは1つのCVE-IDに対して複数設定できます。 対応期限を設定でき、該当タスクの対応期限を一括で上書き更新できる CVE検知済みのグループに対して設定された旨の通知ができる(通知の際、コメントは不可) 参考: スペシャル警戒タグ機能 今回の対応期限は判断日の5営業日後としました。 各プロジェクトの 脆弱性 情報のサマリに警戒タグが入りました。 対応状況の確認 最後に各プロジェクトの対応状況を後追いします。 FutureVulsではタスクステータスを用いて、対応状況を管理できます。 タスク対応の流れは以下です。 引用: ステータス 次のアクションとして、 スペシャ ル警戒タグで設定した対応期限を超過したタスクに対してリマインドします。 対応期限の翌営業日になったら、グループセットのタスクタブから、フィルターでCVE-2022-22965のタスクステータスが「NEW(新規)」と「INVESTIGATING(調査中)」を抽出します。 タスクに一括チェックした上で、タスクを編集からコメントを送信することで、該当グループの所属メンバ全員にメールを送信できます。 その後はタスクのコメント上でのやり取りも可能です。 対応結果 模擬訓練に参加したプロジェクトの対応結果は以下のようになりました。 プロジェクト 結果 ソフトウェア別の対応 プロジェクトA CPE スキャン(*)にて検出され、対応完了 Spring Framework 5.3.17が検出対象となったため、最新バージョンに CPE を更新し、クローズ プロジェクトB CPE スキャンでは検出できず、個別連絡にて対応依頼の上、完了 Spring Boot 2.5.0は Spring Framework に依存しているが、 CPE スキャンでは検出されず。原因と対応策は下記課題3を参照。Spring Bootの最新バージョンに CPE を更新。 プロジェクトC CPE スキャンにて検出され、対応完了 JDK 8は影響を受けないが検出対象となった。原因と対応策は下記課題4を参照。タスクのステータスを「NOT_AFFECTED(影響なし)」に変更し、クローズ。 * CPE スキャン:擬似サーバ上にソフトウェア名、バージョン情報を手動登録し、日次でスキャンさせる機能。 参考: CPEスキャン 見つかった課題 模擬訓練を通して発見した課題についてまとめます。 No 課題 対応策 補足 1 CVE未採番の状態でもユーザへ第一報を通知したい グループセットのソフトウェアタブで「Spring」と検索し、該当するプロジェクトメンバに連絡する FutureVulsのオーガニゼーショントピックや スペシャ ル警戒タグはCVE採番済みの 脆弱性 に対してしか利用できない。現状はチャットなど別の手段で連絡するしかない。 2 対応済みのプロジェクトにもオーガニゼーショントピックが通知されてしまう オーガニゼーショントピックをなるべく早めに発報することで、対応済み案件へ通知される確率を下げる。またトピック内に注意書きを入れる。 オーガニゼーショントピックは 脆弱性 単位で通知する機能となっており、各タスクのステータスまでチェックしないため、既に対応がクローズしている案件にも通知されるため、注意が必要。 3 Spring Bootの脆弱バージョンを CPE スキャンしても、CVE-2022-22965が検出されない 依存ライブラリスキャンを利用する CPE スキャンは登録したライブラリや フレームワーク の依存ライブラリの 脆弱性 までは検知できない。依存ライブラリスキャンの手法の1つとして GitHub Security Alerts連携 がある。PoCで利用したSpring Bootのpom. xml をスキャン対象の GitHub リポジトリ に手動であげるとFutureVuls側で検出されることを確認。 4 JDK 8であれば影響を受けないはずだが検出されてしまう トピック内に影響を受ける条件を記載し、プロジェクト側にステータスを「NOT_AFFECTED(影響なし)」に変更してもらうようにする FutureVulsには外部条件を考慮した検知の仕組みは現状ないため、ステータスを変更してもらう必要がある 最後に 今回、 脆弱性 対応模擬訓練を行うことで、FutureVulsを活用した緊急時の一連のフローを確認することができました。 また、課題はいくつか見つかりましたが、運用でカバーできそうであることもわかりました。 FutureVulsはリリース頻度が高いため、このあたりの課題が機能アップデートによって解消されることに期待したいと思います! 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア 執筆: @fukuyama.kenta ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 2023年6月に Amazon Verified Permissions というサービスがGAしましたが、まだ利用している方は少ないのではないでしょうか。 アプリケーションとは切り離して認可ポリシーを管理できるこのサービスですが、ではどうやってポリシーや スキーマ を管理したら良いか考えたところ、 AWS CDK が便利だったので、今回の記事ではその方法を紹介します。 Amazon Verified Permissions とは スキーマ Amazon Verified Permissions を CDK でデプロイする ディレクトリ構成 Cedar 言語の VS Code 拡張 スキーマ定義 ポリシー CDK コンストラクト SDKで認可を判定させてみた さいごに Amazon Verified Permissions とは ポリシーを事前に登録することで、アプリケーションの認可の判定を、アプリケーションの外側で行うことができるマネージドサービスです。 ポリシーは Cedar という DSL で記述します。例えば次のようなポリシー: permit ( principal in MyApp::User::"alice", action in [MyApp::Action::"GET"], resource in MyApp::Album::"animals" ); これは alice というユーザーに animals というアルバムへの GET アクセスを permit (許可する)という意味になります。 principal 「誰に」、 resource 「どのリソースに対する」、 action 「どんな操作」を許可・拒否するかを基本的には書いていくことになります。 定義したポリシーに対して、アプリケーションコードから認可結果を判定させるリク エス トを送信できます。 例として次のように AWS SDK for JavaScript の IsAuthorizedCommand を使って、特定の状況における認可を判定させることができます。 // authorize.ts import { VerifiedPermissionsClient , IsAuthorizedCommand } from "@aws-sdk/client-verifiedpermissions" ; const client = new VerifiedPermissionsClient ( { region: "ap-northeast-1" } ); const command = new IsAuthorizedCommand ( { policyStoreId: "DUMMYSTOREID" , principal: { entityType: "MyApp::User" , entityId: "alice" } , action: { actionType: "MyApp::Action" , actionId: "GET" } , resource: { entityType: "MyApp::Album" , entityId: "animals" } , } ); client.send ( command ) .then (( result ) => { console .log ( result.decision ); // ALLOW } ); この場合ユーザーは alice 、操作対象のリソースは animals というアルバム、操作は GET なので、先ほど例に示した許可ポリシーに当てはまり、コマンドの結果の decision プロパティには ALLOW が返ってきます。(拒否される場合は DENY が返ります。) この結果を見て、後続の処理は完全にアプリケーション側の裁量で行うことになります。 ( principal を Cognito と連携したり、 principal や resource に属性を追加したり、 context でコンテキストを追加したりすることもできますが、今回はこれぐらいのシンプルな説明に留めておきます。) スキーマ Amazon Verified Permissions には スキーマ と呼ばれる概念があります。 スキーマ は前述の principal 、 resource 、 action のフォーマットを定義するものです。言葉で説明しても理解が難しいと思うので、実際にマネジメントコンソールで見てみると分かりやすいと思います。 定義済みの スキーマ の画面です。 principal と resource で使った User や Album は「エンティティタイプ」セクションで定義し、 action で使った GET は「アクション」セクションで定義します。マネジメントコンソールで追加した スキーマ 定義は JSON フォーマットと相互変換可能であり、上の スキーマ 定義は次の JSON と同等です。(画面の「 JSON モード」から確認でき、 決まったフォーマット が使われます) { " MyApp ": { " actions ": { " GET ": { " appliesTo ": { " context ": { " attributes ": {} , " type ": " Record " } , " resourceTypes ": [ " Album " ] , " principalTypes ": [ " User " ] } } } , " entityTypes ": { " User ": { " memberOfTypes ": [] , " shape ": { " attributes ": {} , " type ": " Record " } } , " Album ": { " shape ": { " type ": " Record ", " attributes ": {} } , " memberOfTypes ": [] } } } } Amazon Verified Permissions を CDK でデプロイする Amazon Verified Permissions の スキーマ ( JSON )とポリシー(Cedar)はいずれも宣言型のコードで表現されるので、そのデプロイを CDK で行うと相性が良いのではないかと思いました。そう考えた理由は以下です。 認可のための スキーマ やポリシーは、アプリケーションデータのように頻繁に変わるわけではない そのためコード リポジトリ で管理し、レビューと変更を確認できる状態にしたい コード リポジトリ で管理するなら、デプロイも自動化したい IaC でデプロイしよう まず、 Amazon Verified Permissions のリソース構築は CloudFormation ではサポート されています。しかし、 JSON のスキーマ定義 や Cedar のポリシー定義 を String で記載する必要があり、CloudFormation テンプレートで管理するのはつらそうです。そこで プログラミング言語 で IaC を実現できる CDK を活用して、管理しやすくしてみましょう。 ディレクト リ構成 以下の CDK アプリの リポジトリ 構成で話を進めます。(重要なファイル/ ディレクト リ以外は省略しています。) sample-app/  ├ .vscode/  │ └ settings.json <- VS Code で Cedar を書きやすくするための設定ファイル  ├ bin/  │ └ my-app.ts  ├ cedar/  │ ├ 0001.cedar <- ポリシーその1  │ ├ 0002.cedar <- ポリシーその2  │ └ cedarschema.json <- スキーマ定義  ├ lib/  │ ├ constructs/  │ │ └ my-construct.ts <- Verified Permissionsリソースをデプロイするコンストラクト  │ └ my-stack.ts  ├ cdk.context.json  ├ cdk.json  ├ package.json  ├ tsconfig.json  └ yarn.lock Cedar 言語の VS Code 拡張 Cedar 言語を書きやすくするための VS Code 拡張があります。とりあえず入れておきましょう。 https://marketplace.visualstudio.com/items?itemName=cedar-policy.vscode-cedar 続いて .vscode/settings.json に以下の設定を追加します。ポリシーや スキーマ 定義の文法が正しくないときや、 スキーマ 定義に一致しないポリシーを書いたときにエラーを出してくれるようになります。保存時にファイルのフォーマットもそろえてくれます。 // .vscode/settings.json { " [cedar] ": { " editor.tabSize ": 2 , " editor.wordWrapColumn ": 80 , " editor.formatOnSave ": true , " editor.defaultFormatter ": " cedar-policy.vscode-cedar " , } , " cedar.schemaFile ": " /cedar/cedarschema.json ", " cedar.autodetectSchemaFile ": true , } スキーマ 定義 前述の例の JSON スキーマ 定義をそのまま cedar/cedarschema.json に書きます。 cedarschema.json もしくは *.cedarschema.json というファイル名にすることで、 Cedar の JSON スキーマ ファイルとして VS Code 拡張に認識されるようになります。 // cedar/cedarschema.json { " MyApp ": { " actions ": { " GET ": { " appliesTo ": { " context ": { " attributes ": {} , " type ": " Record " } , " resourceTypes ": [ " Album " ] , " principalTypes ": [ " User " ] } } } , " entityTypes ": { " User ": { " memberOfTypes ": [] , " shape ": { " attributes ": {} , " type ": " Record " } } , " Album ": { " shape ": { " type ": " Record ", " attributes ": {} } , " memberOfTypes ": [] } } } } ポリシー ポリシーを2つ追加してみます。 *.cedar 拡張子のファイル名が Cedar のポリシーファイルとして VS Code 拡張に認識されます。1つの *.cedar ファイルには1つのポリシーしか書けないので、2つのファイルを追加します。 1つ目は alice というユーザーに animals というアルバムへの GET アクセスを許可するポリシーです。( cedar/0001.cedar ) コメントも自由に書けるので、ポリシーの説明などを記載しておくと後から分かりやすいでしょう。 // alice に animals アルバムへのアクセスを許可する permit ( principal in MyApp::User::"alice", action in [MyApp::Action::"GET"], resource in MyApp::Album::"animals" ); 2つ目は bob というユーザーに flowers というアルバムへの GET アクセスを許可するポリシーです。( cedar/0002.cedar ) // bob に flowers アルバムへのアクセスを許可する permit ( principal in MyApp::User::"bob", action in [MyApp::Action::"GET"], resource in MyApp::Album::"flowers" ); CDK コンスト ラク ト いよいよ Verified Permissions のリソースを CDK でデプロイするコンスト ラク トです。 CDK v2.94.0 では Verified Permissions のコンスト ラク トは4つ利用できますが、L2 コンスト ラク トはなく、いずれも L1 です。 CfnPolicyStore CfnPolicy CfnPolicyTemplate CfnIdentitySource 今回は上の2つを利用します。 まずは Verified Permissions のポリシーストアを作成します。 // lib/constructs/my-construct.ts import * as fs from "fs" ; import * as path from "path" ; import * as vp from "aws-cdk-lib/aws-verifiedpermissions" ; import { Construct } from "constructs" ; export class VerifiedPermissionsConstruct extends Construct { constructor( scope: Construct , id: string ) { super( scope , id ); const cedarDir = path.join ( __dirname , ".." , ".." , "cedar" ); // スキーマ定義をファイルから読み込む const schema = fs.readFileSync ( path.join ( cedarDir , "cedarschema.json" ), "utf-8" ); // ポリシーストア const policyStore = new vp.CfnPolicyStore ( this , "PolicyStore" , { validationSettings: { mode: "STRICT" } , schema: { cedarJson: schema } , } ); // ... } } スキーマ 定義はポリシーストア作成時に渡す必要があり、 fs モジュールの readFileSync メソッドで先ほど定義した cedarschema.json ファイルを読み込ませています。 デプロイすると、マネジメントコンソールでも作成されたポリシーストアを確認できました。ポリシーストア ID は自動で採番されます。 続いてポリシーを追加していきます。以下のコードは、 cedar ディレクト リにある *.cedar ファイルのみをループして読み込んで、ファイルの数だけポリシーをポリシーストアに追加しています。 // lib/constructs/my-construct.ts export class VerifiedPermissionsConstruct extends Construct { constructor( scope: Construct , id: string ) { // ... // cedar ディレクトリのファイル一覧を読み込む const files = fs.readdirSync ( cedarDir ); files .filter (( file ) => file.endsWith ( ".cedar" )) // .cedar ファイルのみを抽出 .map (( file ) => { const content = fs.readFileSync ( path.join ( cedarDir , file ), "utf-8" ); // ポリシー new vp.CfnPolicy ( this , `Policy- ${ file.split( "." )[ 0 ] } ` , { policyStoreId: policyStore.attrPolicyStoreId , // ポリシーストア ID を参照 definition: { static : { statement: content } } , // 静的ポリシーを追加 } ); } ); } } ポリシーのリソースIDはファイル名を利用して付けることで重複がないようにしています。また map 関数で cedar ディレクト リ内の全 Cedar ファイルをループして処理することで、ポリシーを追加・削除したいときは cedar ディレクト リ内を変更するだけでよく、CDK コードの修正は必要ありません。このようなことができるのも プログラミング言語 で処理を書ける CDK ならではの強みです。 デプロイすると、定義した通りのポリシーがコンソールでも確認できました。ポリシー ID は自動で採番されています。 以上で CDK を使った Verified Permission の構築は完了です。 SDK で認可を判定させてみた 構築した Verified Permissions を確認するために、簡単にローカル環境から SDK でリク エス トを投げてみます。 // authorize.ts import { VerifiedPermissionsClient , IsAuthorizedCommand } from "@aws-sdk/client-verifiedpermissions" ; const client = new VerifiedPermissionsClient ( { region: "ap-northeast-1" } ); const command = new IsAuthorizedCommand ( { policyStoreId: "DUMMYSTOREID" , // マネジメントコンソールから確認できるポリシーストアID principal: { entityType: "MyApp::User" , entityId: "alice" } , action: { actionType: "MyApp::Action" , actionId: "GET" } , resource: { entityType: "MyApp::Album" , entityId: "animals" } , } ); client.send ( command ) .then (( result ) => { console .log ( result.decision ); // ALLOW console .log ( JSON .stringify ( result.determiningPolicies )); // [{"policyId":"JLu29q39V62CChNcpFgk3x"}] } ); ユーザーが alice 、リソースが animals アルバムの場合、判定結果は ALLOW となり、どのポリシーで判定されたのかも determiningPolicies プロパティで確認できます。 今度は alice に許可していない flowers アルバムへの認可を判定させてみます。 // authorize.ts const command = new IsAuthorizedCommand ( { policyStoreId: "DUMMYSTOREID" , principal: { entityType: "MyApp::User" , entityId: "alice" } , action: { actionType: "MyApp::Action" , actionId: "GET" } , resource: { entityType: "MyApp::Album" , entityId: "flowers" } , } ); client.send ( command ) .then (( result ) => { console .log ( result.decision ); // DENY console .log ( JSON .stringify ( result.determiningPolicies )); // [] } ); どのポリシーにも当てはまらないため determiningPolicies は空の配列であり、判定結果はデフォルトの DENY となりました。 ちなみに GetPolicyCommand を使うことで、ポリシーの内容を SDK からも取得することができます。 // authorize.ts const command = new GetPolicyCommand ( { policyStoreId: "DUMMYSTOREID" , policyId: "JLu29q39V62CChNcpFgk3x" , } ); client.send ( command ) .then (( result ) => { console .log ( result.definition?. static ?.statement ); } ); // (結果) // // alice に animals アルバムへのアクセスを許可する // permit ( // principal in MyApp::User::"alice", // action in [MyApp::Action::"GET"], // resource in MyApp::Album::"animals" // ); さいごに まだまだ利用が少ないと思われる Amazon Verified Permissions ですが、CDK を使って管理・デプロイすることと相性が良く、使ってみたいという気持ちになりました。 DSL なので提供されている VS Code 拡張を利用したいですし、そうするとファイルの読み込みや、ポリシーファイルの数だけループ処理ができる CDK でデプロイするのが最も便利だと感じました。 Amazon Verified Permissions 自体も、工夫次第では様々な使い方ができそうなので、今後が楽しみなサービスです。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア 執筆: @kou.kinyo 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 2023年6月に Amazon Verified Permissions というサービスがGAしましたが、まだ利用している方は少ないのではないでしょうか。 アプリケーションとは切り離して認可ポリシーを管理できるこのサービスですが、ではどうやってポリシーや スキーマ を管理したら良いか考えたところ、 AWS CDK が便利だったので、今回の記事ではその方法を紹介します。 Amazon Verified Permissions とは スキーマ Amazon Verified Permissions を CDK でデプロイする ディレクトリ構成 Cedar 言語の VS Code 拡張 スキーマ定義 ポリシー CDK コンストラクト SDKで認可を判定させてみた さいごに Amazon Verified Permissions とは ポリシーを事前に登録することで、アプリケーションの認可の判定を、アプリケーションの外側で行うことができるマネージドサービスです。 ポリシーは Cedar という DSL で記述します。例えば次のようなポリシー: permit ( principal in MyApp::User::"alice", action in [MyApp::Action::"GET"], resource in MyApp::Album::"animals" ); これは alice というユーザーに animals というアルバムへの GET アクセスを permit (許可する)という意味になります。 principal 「誰に」、 resource 「どのリソースに対する」、 action 「どんな操作」を許可・拒否するかを基本的には書いていくことになります。 定義したポリシーに対して、アプリケーションコードから認可結果を判定させるリク エス トを送信できます。 例として次のように AWS SDK for JavaScript の IsAuthorizedCommand を使って、特定の状況における認可を判定させることができます。 // authorize.ts import { VerifiedPermissionsClient , IsAuthorizedCommand } from "@aws-sdk/client-verifiedpermissions" ; const client = new VerifiedPermissionsClient ( { region: "ap-northeast-1" } ); const command = new IsAuthorizedCommand ( { policyStoreId: "DUMMYSTOREID" , principal: { entityType: "MyApp::User" , entityId: "alice" } , action: { actionType: "MyApp::Action" , actionId: "GET" } , resource: { entityType: "MyApp::Album" , entityId: "animals" } , } ); client.send ( command ) .then (( result ) => { console .log ( result.decision ); // ALLOW } ); この場合ユーザーは alice 、操作対象のリソースは animals というアルバム、操作は GET なので、先ほど例に示した許可ポリシーに当てはまり、コマンドの結果の decision プロパティには ALLOW が返ってきます。(拒否される場合は DENY が返ります。) この結果を見て、後続の処理は完全にアプリケーション側の裁量で行うことになります。 ( principal を Cognito と連携したり、 principal や resource に属性を追加したり、 context でコンテキストを追加したりすることもできますが、今回はこれぐらいのシンプルな説明に留めておきます。) スキーマ Amazon Verified Permissions には スキーマ と呼ばれる概念があります。 スキーマ は前述の principal 、 resource 、 action のフォーマットを定義するものです。言葉で説明しても理解が難しいと思うので、実際にマネジメントコンソールで見てみると分かりやすいと思います。 定義済みの スキーマ の画面です。 principal と resource で使った User や Album は「エンティティタイプ」セクションで定義し、 action で使った GET は「アクション」セクションで定義します。マネジメントコンソールで追加した スキーマ 定義は JSON フォーマットと相互変換可能であり、上の スキーマ 定義は次の JSON と同等です。(画面の「 JSON モード」から確認でき、 決まったフォーマット が使われます) { " MyApp ": { " actions ": { " GET ": { " appliesTo ": { " context ": { " attributes ": {} , " type ": " Record " } , " resourceTypes ": [ " Album " ] , " principalTypes ": [ " User " ] } } } , " entityTypes ": { " User ": { " memberOfTypes ": [] , " shape ": { " attributes ": {} , " type ": " Record " } } , " Album ": { " shape ": { " type ": " Record ", " attributes ": {} } , " memberOfTypes ": [] } } } } Amazon Verified Permissions を CDK でデプロイする Amazon Verified Permissions の スキーマ ( JSON )とポリシー(Cedar)はいずれも宣言型のコードで表現されるので、そのデプロイを CDK で行うと相性が良いのではないかと思いました。そう考えた理由は以下です。 認可のための スキーマ やポリシーは、アプリケーションデータのように頻繁に変わるわけではない そのためコード リポジトリ で管理し、レビューと変更を確認できる状態にしたい コード リポジトリ で管理するなら、デプロイも自動化したい IaC でデプロイしよう まず、 Amazon Verified Permissions のリソース構築は CloudFormation ではサポート されています。しかし、 JSON のスキーマ定義 や Cedar のポリシー定義 を String で記載する必要があり、CloudFormation テンプレートで管理するのはつらそうです。そこで プログラミング言語 で IaC を実現できる CDK を活用して、管理しやすくしてみましょう。 ディレクト リ構成 以下の CDK アプリの リポジトリ 構成で話を進めます。(重要なファイル/ ディレクト リ以外は省略しています。) sample-app/  ├ .vscode/  │ └ settings.json <- VS Code で Cedar を書きやすくするための設定ファイル  ├ bin/  │ └ my-app.ts  ├ cedar/  │ ├ 0001.cedar <- ポリシーその1  │ ├ 0002.cedar <- ポリシーその2  │ └ cedarschema.json <- スキーマ定義  ├ lib/  │ ├ constructs/  │ │ └ my-construct.ts <- Verified Permissionsリソースをデプロイするコンストラクト  │ └ my-stack.ts  ├ cdk.context.json  ├ cdk.json  ├ package.json  ├ tsconfig.json  └ yarn.lock Cedar 言語の VS Code 拡張 Cedar 言語を書きやすくするための VS Code 拡張があります。とりあえず入れておきましょう。 https://marketplace.visualstudio.com/items?itemName=cedar-policy.vscode-cedar 続いて .vscode/settings.json に以下の設定を追加します。ポリシーや スキーマ 定義の文法が正しくないときや、 スキーマ 定義に一致しないポリシーを書いたときにエラーを出してくれるようになります。保存時にファイルのフォーマットもそろえてくれます。 // .vscode/settings.json { " [cedar] ": { " editor.tabSize ": 2 , " editor.wordWrapColumn ": 80 , " editor.formatOnSave ": true , " editor.defaultFormatter ": " cedar-policy.vscode-cedar " , } , " cedar.schemaFile ": " /cedar/cedarschema.json ", " cedar.autodetectSchemaFile ": true , } スキーマ 定義 前述の例の JSON スキーマ 定義をそのまま cedar/cedarschema.json に書きます。 cedarschema.json もしくは *.cedarschema.json というファイル名にすることで、 Cedar の JSON スキーマ ファイルとして VS Code 拡張に認識されるようになります。 // cedar/cedarschema.json { " MyApp ": { " actions ": { " GET ": { " appliesTo ": { " context ": { " attributes ": {} , " type ": " Record " } , " resourceTypes ": [ " Album " ] , " principalTypes ": [ " User " ] } } } , " entityTypes ": { " User ": { " memberOfTypes ": [] , " shape ": { " attributes ": {} , " type ": " Record " } } , " Album ": { " shape ": { " type ": " Record ", " attributes ": {} } , " memberOfTypes ": [] } } } } ポリシー ポリシーを2つ追加してみます。 *.cedar 拡張子のファイル名が Cedar のポリシーファイルとして VS Code 拡張に認識されます。1つの *.cedar ファイルには1つのポリシーしか書けないので、2つのファイルを追加します。 1つ目は alice というユーザーに animals というアルバムへの GET アクセスを許可するポリシーです。( cedar/0001.cedar ) コメントも自由に書けるので、ポリシーの説明などを記載しておくと後から分かりやすいでしょう。 // alice に animals アルバムへのアクセスを許可する permit ( principal in MyApp::User::"alice", action in [MyApp::Action::"GET"], resource in MyApp::Album::"animals" ); 2つ目は bob というユーザーに flowers というアルバムへの GET アクセスを許可するポリシーです。( cedar/0002.cedar ) // bob に flowers アルバムへのアクセスを許可する permit ( principal in MyApp::User::"bob", action in [MyApp::Action::"GET"], resource in MyApp::Album::"flowers" ); CDK コンスト ラク ト いよいよ Verified Permissions のリソースを CDK でデプロイするコンスト ラク トです。 CDK v2.94.0 では Verified Permissions のコンスト ラク トは4つ利用できますが、L2 コンスト ラク トはなく、いずれも L1 です。 CfnPolicyStore CfnPolicy CfnPolicyTemplate CfnIdentitySource 今回は上の2つを利用します。 まずは Verified Permissions のポリシーストアを作成します。 // lib/constructs/my-construct.ts import * as fs from "fs" ; import * as path from "path" ; import * as vp from "aws-cdk-lib/aws-verifiedpermissions" ; import { Construct } from "constructs" ; export class VerifiedPermissionsConstruct extends Construct { constructor( scope: Construct , id: string ) { super( scope , id ); const cedarDir = path.join ( __dirname , ".." , ".." , "cedar" ); // スキーマ定義をファイルから読み込む const schema = fs.readFileSync ( path.join ( cedarDir , "cedarschema.json" ), "utf-8" ); // ポリシーストア const policyStore = new vp.CfnPolicyStore ( this , "PolicyStore" , { validationSettings: { mode: "STRICT" } , schema: { cedarJson: schema } , } ); // ... } } スキーマ 定義はポリシーストア作成時に渡す必要があり、 fs モジュールの readFileSync メソッドで先ほど定義した cedarschema.json ファイルを読み込ませています。 デプロイすると、マネジメントコンソールでも作成されたポリシーストアを確認できました。ポリシーストア ID は自動で採番されます。 続いてポリシーを追加していきます。以下のコードは、 cedar ディレクト リにある *.cedar ファイルのみをループして読み込んで、ファイルの数だけポリシーをポリシーストアに追加しています。 // lib/constructs/my-construct.ts export class VerifiedPermissionsConstruct extends Construct { constructor( scope: Construct , id: string ) { // ... // cedar ディレクトリのファイル一覧を読み込む const files = fs.readdirSync ( cedarDir ); files .filter (( file ) => file.endsWith ( ".cedar" )) // .cedar ファイルのみを抽出 .map (( file ) => { const content = fs.readFileSync ( path.join ( cedarDir , file ), "utf-8" ); // ポリシー new vp.CfnPolicy ( this , `Policy- ${ file.split( "." )[ 0 ] } ` , { policyStoreId: policyStore.attrPolicyStoreId , // ポリシーストア ID を参照 definition: { static : { statement: content } } , // 静的ポリシーを追加 } ); } ); } } ポリシーのリソースIDはファイル名を利用して付けることで重複がないようにしています。また map 関数で cedar ディレクト リ内の全 Cedar ファイルをループして処理することで、ポリシーを追加・削除したいときは cedar ディレクト リ内を変更するだけでよく、CDK コードの修正は必要ありません。このようなことができるのも プログラミング言語 で処理を書ける CDK ならではの強みです。 デプロイすると、定義した通りのポリシーがコンソールでも確認できました。ポリシー ID は自動で採番されています。 以上で CDK を使った Verified Permission の構築は完了です。 SDK で認可を判定させてみた 構築した Verified Permissions を確認するために、簡単にローカル環境から SDK でリク エス トを投げてみます。 // authorize.ts import { VerifiedPermissionsClient , IsAuthorizedCommand } from "@aws-sdk/client-verifiedpermissions" ; const client = new VerifiedPermissionsClient ( { region: "ap-northeast-1" } ); const command = new IsAuthorizedCommand ( { policyStoreId: "DUMMYSTOREID" , // マネジメントコンソールから確認できるポリシーストアID principal: { entityType: "MyApp::User" , entityId: "alice" } , action: { actionType: "MyApp::Action" , actionId: "GET" } , resource: { entityType: "MyApp::Album" , entityId: "animals" } , } ); client.send ( command ) .then (( result ) => { console .log ( result.decision ); // ALLOW console .log ( JSON .stringify ( result.determiningPolicies )); // [{"policyId":"JLu29q39V62CChNcpFgk3x"}] } ); ユーザーが alice 、リソースが animals アルバムの場合、判定結果は ALLOW となり、どのポリシーで判定されたのかも determiningPolicies プロパティで確認できます。 今度は alice に許可していない flowers アルバムへの認可を判定させてみます。 // authorize.ts const command = new IsAuthorizedCommand ( { policyStoreId: "DUMMYSTOREID" , principal: { entityType: "MyApp::User" , entityId: "alice" } , action: { actionType: "MyApp::Action" , actionId: "GET" } , resource: { entityType: "MyApp::Album" , entityId: "flowers" } , } ); client.send ( command ) .then (( result ) => { console .log ( result.decision ); // DENY console .log ( JSON .stringify ( result.determiningPolicies )); // [] } ); どのポリシーにも当てはまらないため determiningPolicies は空の配列であり、判定結果はデフォルトの DENY となりました。 ちなみに GetPolicyCommand を使うことで、ポリシーの内容を SDK からも取得することができます。 // authorize.ts const command = new GetPolicyCommand ( { policyStoreId: "DUMMYSTOREID" , policyId: "JLu29q39V62CChNcpFgk3x" , } ); client.send ( command ) .then (( result ) => { console .log ( result.definition?. static ?.statement ); } ); // (結果) // // alice に animals アルバムへのアクセスを許可する // permit ( // principal in MyApp::User::"alice", // action in [MyApp::Action::"GET"], // resource in MyApp::Album::"animals" // ); さいごに まだまだ利用が少ないと思われる Amazon Verified Permissions ですが、CDK を使って管理・デプロイすることと相性が良く、使ってみたいという気持ちになりました。 DSL なので提供されている VS Code 拡張を利用したいですし、そうするとファイルの読み込みや、ポリシーファイルの数だけループ処理ができる CDK でデプロイするのが最も便利だと感じました。 Amazon Verified Permissions 自体も、工夫次第では様々な使い方ができそうなので、今後が楽しみなサービスです。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア 執筆: @kou.kinyo 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
アバター
XI本部 スマート ソサエティ センターの飯田です。 私は「DigSports」というAIによって運動能力を測定し、どのスポーツに向いているかを提案する製品のプロダクトオーナーを担当しています。 DigSportsは、運動が苦手な子どもたちや運動から遠ざかってしまった働く世代の方々に対して、自分に合ったスポーツを見つけられる機会を提供し、運動を始めるきっかけや運動習慣化を後押ししています。 isid-ssc.jp そんなDigSportsなのですが、技術的な アーキテクチャ をガラッと変えた新しいバージョンをリリースしました。 AIで適性のあるスポーツを判定する「DigSports」の新バージョンを提供開始 本エントリーでは、新バージョン開発をプロダクトオーナーとして経験した悩みや苦悩を書いてみます。 不安との闘い 要約すると、「不安との闘い」が悩みの根源でした。 技術的なこと、BizDev的なこと、営業戦略、様々な部分で決断が求められました。 自分の選択が間違っていないか? 機能開発の優先度を間違えてないか? 「UX的に良いものをつくる」「技術的に良いものをつくる」「つくったものを広める」そのバランスが良いものになっているか? ...等です。 アジャイル で試行錯誤しながらプロダクトを カイゼン していけるとしても、投資対効果を最大にするために妥当な判断ができているか、「これでいい!」「あ、やっぱダメかも」を繰り返しながら、開発を進めていました。 その中で感じた書いてみます。 1. 資産を作っているか?負債を作っていないか? DigSportsは エンタープライズ なプロダクトと毛色が違うため、 エンタープライズ 製品に比べ、ソフトウェアの規模はそこまで大きくありません。そのため、開発にあたっては「修正対応のしやすさのため、シンプルさを維持する」ことを意識しています。 また、技術的な側面だけでなく、ビジネス開発の観点からもシンプルさを意識しています。 アジャイル など試行錯誤していく開発アプローチは、開発・修正のサイクルを短く回すことができますが、 一方、資産となる市場販売目的のソフトウェア開発にかかった費用は、 3年間の減価償却が行われます。 つまり、今回の開発コストが3年間に按分されることになるので、不要なものを開発すると“ゴミ”・“負債”を作っていることになるので、“資産”として意味のあるものを残していかないといけません。 「今、行おうとしている開発は、改善なのか?改悪なのか?」 もちろん不確実性の中での判断なので、正解はありませんが、3年後を意識して決断していくのは悩みがつきませんでした。 2. 同じ結論になったとしても、1周回ってくると景色やブレなさが違う そのように「資産を作れているか?」と悩みながら進めていく中で、ユーザー・顧客の反応や開発メンバーとの議論は、悩みながら決断をしていく際の大きな拠り所でした。 ユーザー・顧客の反応を見る前後でアイディアが変わらなかったとしても、 ヒアリ ングや議論を経てみると、一周回って自分自身への納得感(ひいては、他人に説得する際の自信)がついている感覚がありました。 3. 「ユーザーの声を聞いている」ということに逃げていないか プロダクト開発における教科書的な模範解答としては「ユーザーの声を聞いて、 アジャイル 的に PDCA を回して改善する」だと思います。実際、DigSportsのリニューアルにおいてもそこは意識しながら進めました。 しかし、ふとした時に、「ユーザーがXXXって言っていたから」というフレーズを多用している自分に気がつきました。 よくよく考えてみると「ユーザーの声を聞いている」という言い訳を手に入れたことによって、自分で意思決定せず、意思を持った決断から逃げていました。プロダクトオーナとしては、考え抜いて意思決定を全うするべきです。 それからは、“ ヒアリ ングの結果”という第三の何かに委ねてしまっていないか?という不安を意識して意思決定するようになりました。 迷ったら議論できる仲間・戻ってくれる軸があるといい プロダクト開発は、正解が見えない不確実性が高い中で判断を迫られることが多く、いろいろな不安と闘いながら意思決定をしました。判断に迷ったときや自信を持てない時、立ち戻ることができる基準や製品コンセプトを拠り所としました。 それでも自分の意思決定がブレてしまっていると感じた時は、一緒に開発していた社内のデザインチーム・社外の開発パートナーさんと相談し、自分の意思決定を整えてもらいました。 DigSportsのリニューアルは製品コンセプトや仲間のおかげで、悩みながらも良い意思決定・開発ができたと思っています。 機会があれば、リニューアルしたDigSportsをぜひご体験ください! www.isid.co.jp 最後に、私たちは一緒に働いてくれる仲間を募集しています! デジタル技術を社会課題解決につなげるようなプロジェクトを推進していきたいプロジェクトマネージャーやエンジニアを募集しています。 ぜひご応募ください! スマートシティ導入コンサルタント/スマートシティ戦略コンサルタント 執筆: @iida.michitaka 、レビュー: @takeda.hideyuki ( Shodo で執筆されました )
アバター
XI本部 スマート ソサエティ センターの飯田です。 私は「DigSports」というAIによって運動能力を測定し、どのスポーツに向いているかを提案する製品のプロダクトオーナーを担当しています。 DigSportsは、運動が苦手な子どもたちや運動から遠ざかってしまった働く世代の方々に対して、自分に合ったスポーツを見つけられる機会を提供し、運動を始めるきっかけや運動習慣化を後押ししています。 smart-society.dentsusoken.com そんなDigSportsなのですが、技術的な アーキテクチャ をガラッと変えた新しいバージョンをリリースしました。 AIで適性のあるスポーツを判定する「DigSports」の新バージョンを提供開始 | お知らせ | 電通総研 本エントリーでは、新バージョン開発をプロダクトオーナーとして経験した悩みや苦悩を書いてみます。 不安との闘い 要約すると、「不安との闘い」が悩みの根源でした。 技術的なこと、BizDev的なこと、営業戦略、様々な部分で決断が求められました。 自分の選択が間違っていないか? 機能開発の優先度を間違えてないか? 「UX的に良いものをつくる」「技術的に良いものをつくる」「つくったものを広める」そのバランスが良いものになっているか? ...等です。 アジャイル で試行錯誤しながらプロダクトを カイゼン していけるとしても、投資対効果を最大にするために妥当な判断ができているか、「これでいい!」「あ、やっぱダメかも」を繰り返しながら、開発を進めていました。 その中で感じた書いてみます。 1. 資産を作っているか?負債を作っていないか? DigSportsは エンタープライズ なプロダクトと毛色が違うため、 エンタープライズ 製品に比べ、ソフトウェアの規模はそこまで大きくありません。そのため、開発にあたっては「修正対応のしやすさのため、シンプルさを維持する」ことを意識しています。 また、技術的な側面だけでなく、ビジネス開発の観点からもシンプルさを意識しています。 アジャイル など試行錯誤していく開発アプローチは、開発・修正のサイクルを短く回すことができますが、 一方、資産となる市場販売目的のソフトウェア開発にかかった費用は、 3年間の減価償却が行われます。 つまり、今回の開発コストが3年間に按分されることになるので、不要なものを開発すると“ゴミ”・“負債”を作っていることになるので、“資産”として意味のあるものを残していかないといけません。 「今、行おうとしている開発は、改善なのか?改悪なのか?」 もちろん不確実性の中での判断なので、正解はありませんが、3年後を意識して決断していくのは悩みがつきませんでした。 2. 同じ結論になったとしても、1周回ってくると景色やブレなさが違う そのように「資産を作れているか?」と悩みながら進めていく中で、ユーザー・顧客の反応や開発メンバーとの議論は、悩みながら決断をしていく際の大きな拠り所でした。 ユーザー・顧客の反応を見る前後でアイディアが変わらなかったとしても、 ヒアリ ングや議論を経てみると、一周回って自分自身への納得感(ひいては、他人に説得する際の自信)がついている感覚がありました。 3. 「ユーザーの声を聞いている」ということに逃げていないか プロダクト開発における教科書的な模範解答としては「ユーザーの声を聞いて、 アジャイル 的に PDCA を回して改善する」だと思います。実際、DigSportsのリニューアルにおいてもそこは意識しながら進めました。 しかし、ふとした時に、「ユーザーがXXXって言っていたから」というフレーズを多用している自分に気がつきました。 よくよく考えてみると「ユーザーの声を聞いている」という言い訳を手に入れたことによって、自分で意思決定せず、意思を持った決断から逃げていました。プロダクトオーナとしては、考え抜いて意思決定を全うするべきです。 それからは、“ ヒアリ ングの結果”という第三の何かに委ねてしまっていないか?という不安を意識して意思決定するようになりました。 迷ったら議論できる仲間・戻ってくれる軸があるといい プロダクト開発は、正解が見えない不確実性が高い中で判断を迫られることが多く、いろいろな不安と闘いながら意思決定をしました。判断に迷ったときや自信を持てない時、立ち戻ることができる基準や製品コンセプトを拠り所としました。 それでも自分の意思決定がブレてしまっていると感じた時は、一緒に開発していた社内のデザインチーム・社外の開発パートナーさんと相談し、自分の意思決定を整えてもらいました。 DigSportsのリニューアルは製品コンセプトや仲間のおかげで、悩みながらも良い意思決定・開発ができたと思っています。 機会があれば、リニューアルしたDigSportsをぜひご体験ください! www.isid.co.jp 最後に、私たちは一緒に働いてくれる仲間を募集しています! デジタル技術を社会課題解決につなげるようなプロジェクトを推進していきたいプロジェクトマネージャーやエンジニアを募集しています。 ぜひご応募ください! スマートシティ導入コンサルタント/スマートシティ戦略コンサルタント 執筆: @iida.michitaka 、レビュー: @takeda.hideyuki ( Shodo で執筆されました )
アバター
こんにちは、X(クロス) イノベーション 本部 クラウド イノベーション センターの田村です。 Microsoft Fabric では Git 統合が提供されており、 ワークスペース 内のアイテムに対して Git によるソース管理が可能です。 本記事では、実際に Git 統合を利用したソース管理の手順や制約事項についてご紹介します。 「 Microsoft Fabric とは?」という方は下記の紹介記事や Microsoft Fabric のドキュメントをご参照ください。 Microsoft Fabric を利用して自分の勤怠データを分析する Microsoft Fabric とは なお、本記事に記載されている情報は 2023 年 8 月時点のものとなります。 Microsoft Fabric のアップデートや一般公開(GA)で情報が更新される場合もありますのでご注意ください。 Microsoft Fabric の Git 統合について 概要 ソース管理対象 制約事項 Git 統合の実践 Azure Repos の準備 Microsoft Fabric ワークスペースと Git リポジトリの接続 アイテムに対する変更適用 ソース管理時の注意点 まとめ Microsoft Fabric の Git 統合について 概要 Git 統合は Microsoft Fabric の ワークスペース と Git リポジトリ を接続することで実現します。 両者を接続することで ワークスペース 内のアイテムが Git リポジトリ と同期され、アイテムの変更差分が検出されます。 また、Git におけるコミットやコミット前の変更取り消しは Microsoft Fabric の UI 上から実施できるように設計されています。 ソース管理対象 Git 統合はプレビュー中のため、ソース管理がサポートされる Microsoft Fabric のアイテムは 2 つのみとなっています。 レポート:デー タセット をもとに Power BI により可視化されたグラフや表、マップなどのビジュアル群 デー タセット :Power BI での検出・可視化が可能となったデータソース 現時点ではデータ分析における可視化領域のみで Git 統合を利用できますが、 Microsoft のドキュメント には次の記載があるため、今後サポート対象となるアイテムの追加に期待したいと思います。 現在、プレビュー段階ではいくつかのアイテムのみがサポートされていますが、一覧のサポートされているアイテムは増えています。 制約事項 ワークスペース と接続できる Git リポジトリ は Azure Repos のみがサポートされており、 GitHub 上の リポジトリ は現在サポート外となっています。 Microsoft Fabric のコミュニティサイト では、 GitHub を含めたサポートの拡大要望が寄せられていますが、 Microsoft 側の対応可否や時期は不明です。 Support GitHub in the git integration for workspaces Support for git repositories other than Azure DevOps Git 統合の実践 Azure Repos の準備 前述したとおり Git 統合にてサポートされるのは Azure Repos のみであるため、そちらで Git リポジトリ を準備します。 Azure Repos とは、 Microsoft が提供する DevOps 支援サービスである Azure DevOps に含まれる Git の ホスティング サービスです。 Azure DevOps Services Azure Repos – Git リポジトリ 今回は検証のために Azure DevOps プロジェクトを作成し、Azure Repos 上で Git 統合用の リポジトリ を構成しました。 プロジェクト名と Git リポジトリ 名は msfabric-test としています。 Azure Repos の初期設定については下記ドキュメントをご参照ください。 Azure Repos の使用を開始する なお、以降 Azure Repos に対する操作はすべてプロジェクト管理者権限で実施しています。 Microsoft Fabric ワークスペース と Git リポジトリ の接続 こちら のドキュメントに従って接続設定を実施します。 以降の Microsoft Fabric における操作は、作業者アカウントに ワークスペース の管理者権限があることを前提としています。 Microsoft Fabric の[ ワークスペース の設定] > [Git 統合]より、接続先の Azure Repos の情報を入力し[接続と同期]を実行します。 同期が完了すると、 ワークスペース 内のレポートとデー タセット が Azure Repos の Git リポジトリ へ反映されます。 このとき、末尾が .Dataset の ディレクト リと .Report の ディレクト リにデー タセット とレポートの構成ファイルがそれぞれ格納されています。 アイテムに対する変更適用 レポートとデー タセット に対してそれぞれ変更を加え、ソース管理の流れを確認します。 検証用のデー タセット は Microsoft Fabric のチュートリアル で提供されている 卸売業の売上データ を利用しました。 売上データが格納された 1 つのファクトテーブルと、商品や顧客、従業員といった情報が格納された 5 つのディメンションテーブルで構成されています。 検証用のレポートは前述のデー タセット から自動生成しており、複数のグラフとカードおよびテキストビジュアルから構成されています。 まずはデー タセット に対して変更を加えてみます。 今回は、 Microsoft Fabric の GUI からデー タセット に構成されているリレーションシップを 1 件削除し、構成ファイルにどのような変更があるか確認しました。 デー タセット に変更を加えると、 ワークスペース のアイテム一覧画面で検出されます。 同画面でトピックブランチへチェックアウトして変更をコミットすると、同期先の Azure Repos にて変更された構成ファイルや箇所を確認できます。 検証用のデー タセット は 4 つのファイルで構成されており、リレーションシップの設定については model.bim というファイルのみに変更が適用されていました。 各ファイルの説明を下表に記載します。 ファイル名  必須  説明 model.bim 〇 データベースオブジェクトの定義が Tabular Model Scripting Language(TMSL)で記述されている definition.pbidataset 〇 デー タセット に関連付けられた Q&A や スキーマ 共有に関する設定が記述されている item.config.json ファイルのバージョン情報と同期先の ワークスペース ID が記述されている item.metadata.json Git 統合されているアイテムの種別(ここではデー タセット )とアイテム名、説明が記述されている 上記をふまえると、デー タセット に対して想定される下記のような操作については、その変更が model.bim の記述に反映されると推測できます。 テーブルの追加・削除 データの挿入・更新や削除 データモデルでのメジャー作成 リレーションシップの変更 次にレポートに対しても変更を加えます。 Microsoft Fabric の Power BI にて、前述したレポートに下図のカードとグラフビジュアルを追加しました。 デー タセット に対する変更と同様、上記の変更は ワークスペース のアイテム一覧画面で検出され、コミット後に Azure Repos 側で詳細を確認できます。 検証用のレポートは 5 つのファイルで構成されており、今回の変更については report.json というファイルのみに変更が適用されていました。 各ファイルの説明を下表に記載します。 ファイル名  必須  説明 CY23SU08.json レポートのカスタムテーマ、イメージ、カスタムビジュアルなどの固有情報が記述されている definition.pbir 〇 参照するデー タセット に関する情報が記述されている report.json 〇 レポートに含まれるページ、ビジュアルの情報が記述されている item.config.json ファイルのバージョン情報と同期先の ワークスペース ID が記述されている item.metadata.json Git 統合されているアイテムの種別(ここではレポート)とアイテム名、説明が記述されている 今回はレポートのビジュアルに関する変更のみを実施したため、 report.json の記述のみが影響を受けたと考えられます。 また、デー タセット およびレポートの設定によっては上記に加えて追加の構成ファイルが必要になる場合もあります。 詳細は下記ドキュメントをご参照ください。 Git 統合ソース コード フォーマット Power BI Desktop プロジェクト データセット フォルダー Power BI Desktop プロジェクト レポート フォルダー 変更内容をコミットした後は、Pull Request による一般的なレビュー手順に沿って main ブランチへ変更を適用できました。 トピックブランチとマージ先のブランチ( main )およびレビュアーを指定し、Pull Request を作成 レビュアーは Pull Request の内容を確認し、指摘やコメントをレビュイーに伝える レビューに問題がなければレビュアーの承認をもって Pull Request を完了し、変更を main ブランチへマージする また、今回は実施しませんでしたが Microsoft Fabric では Azure Pipelines を利用したテスト・デプロイの自動化についてもサポートしています。 Azure Pipelines は Azure Repos と同様 Azure DevOps に含まれるサービスのため、Git 統合とうまく組み合わせて CI/CD 環境を構築することで開発やテストの効率化が期待できます。 Azure Pipelines デプロイ パイプラインの概要 ソース管理時の注意点 Microsoft Fabric 上ではレポートやデー タセット といったアイテムの構成ファイルを管理していないため、Git クライアントアプリケーションのように具体的な変更箇所がわかりません。 そのため、作業者自身が変更内容を正しく把握し、適切なコミットメッセージの記述等で円滑なコミュニケーションを図るといった意識が重要になります。 また、 Microsoft Fabric の UI で可能な Git 操作は現状 git commit と git checkout のみです。 コミットの取り消しやリベースなどの操作が必要になった際は、Git コマンドライン ツールや Git クライアントアプリケーションを Azure Repos と併用する必要があります。 まとめ 本記事では、 Microsoft Fabric の Git 統合を利用したソース管理について、実際に利用した際の手順や注意事項、所感についてご紹介しました。 これまで Power BI のデー タセット やレポートといったアイテムはテキストベースでのソース管理ができませんでしたが、Git 統合により GUI 上で可能になった点は魅力的だと感じています。 一方で、一般的なソース管理ではコミットの取り消しやその他 Git コマンドを利用した作業も多いため、Git クライアントや コマンドライン ツールと併用した管理方法も選択肢になり得ます。 現時点では可視化領域のアイテムのみが Git 統合に対応していますが、将来的にはデータ加工や変換、分析といった領域で必要となる ETL パイプラインやデータフロー、各種クエリについてもソース管理の対象となることを期待します。 私たちは一緒に働いてくれる仲間を募集しています! クラウドアーキテクト 執筆: @tamura.kohei 、レビュー: @kano.nanami ( Shodo で執筆されました )
アバター
こんにちは、X(クロス) イノベーション 本部 クラウド イノベーション センターの田村です。 Microsoft Fabric では Git 統合が提供されており、 ワークスペース 内のアイテムに対して Git によるソース管理が可能です。 本記事では、実際に Git 統合を利用したソース管理の手順や制約事項についてご紹介します。 「 Microsoft Fabric とは?」という方は下記の紹介記事や Microsoft Fabric のドキュメントをご参照ください。 Microsoft Fabric を利用して自分の勤怠データを分析する Microsoft Fabric とは なお、本記事に記載されている情報は 2023 年 8 月時点のものとなります。 Microsoft Fabric のアップデートや一般公開(GA)で情報が更新される場合もありますのでご注意ください。 Microsoft Fabric の Git 統合について 概要 ソース管理対象 制約事項 Git 統合の実践 Azure Repos の準備 Microsoft Fabric ワークスペースと Git リポジトリの接続 アイテムに対する変更適用 ソース管理時の注意点 まとめ Microsoft Fabric の Git 統合について 概要 Git 統合は Microsoft Fabric の ワークスペース と Git リポジトリ を接続することで実現します。 両者を接続することで ワークスペース 内のアイテムが Git リポジトリ と同期され、アイテムの変更差分が検出されます。 また、Git におけるコミットやコミット前の変更取り消しは Microsoft Fabric の UI 上から実施できるように設計されています。 ソース管理対象 Git 統合はプレビュー中のため、ソース管理がサポートされる Microsoft Fabric のアイテムは 2 つのみとなっています。 レポート:デー タセット をもとに Power BI により可視化されたグラフや表、マップなどのビジュアル群 デー タセット :Power BI での検出・可視化が可能となったデータソース 現時点ではデータ分析における可視化領域のみで Git 統合を利用できますが、 Microsoft のドキュメント には次の記載があるため、今後サポート対象となるアイテムの追加に期待したいと思います。 現在、プレビュー段階ではいくつかのアイテムのみがサポートされていますが、一覧のサポートされているアイテムは増えています。 制約事項 ワークスペース と接続できる Git リポジトリ は Azure Repos のみがサポートされており、 GitHub 上の リポジトリ は現在サポート外となっています。 Microsoft Fabric のコミュニティサイト では、 GitHub を含めたサポートの拡大要望が寄せられていますが、 Microsoft 側の対応可否や時期は不明です。 Support GitHub in the git integration for workspaces Support for git repositories other than Azure DevOps Git 統合の実践 Azure Repos の準備 前述したとおり Git 統合にてサポートされるのは Azure Repos のみであるため、そちらで Git リポジトリ を準備します。 Azure Repos とは、 Microsoft が提供する DevOps 支援サービスである Azure DevOps に含まれる Git の ホスティング サービスです。 Azure DevOps Services Azure Repos – Git リポジトリ 今回は検証のために Azure DevOps プロジェクトを作成し、Azure Repos 上で Git 統合用の リポジトリ を構成しました。 プロジェクト名と Git リポジトリ 名は msfabric-test としています。 Azure Repos の初期設定については下記ドキュメントをご参照ください。 Azure Repos の使用を開始する なお、以降 Azure Repos に対する操作はすべてプロジェクト管理者権限で実施しています。 Microsoft Fabric ワークスペース と Git リポジトリ の接続 こちら のドキュメントに従って接続設定を実施します。 以降の Microsoft Fabric における操作は、作業者アカウントに ワークスペース の管理者権限があることを前提としています。 Microsoft Fabric の[ ワークスペース の設定] > [Git 統合]より、接続先の Azure Repos の情報を入力し[接続と同期]を実行します。 同期が完了すると、 ワークスペース 内のレポートとデー タセット が Azure Repos の Git リポジトリ へ反映されます。 このとき、末尾が .Dataset の ディレクト リと .Report の ディレクト リにデー タセット とレポートの構成ファイルがそれぞれ格納されています。 アイテムに対する変更適用 レポートとデー タセット に対してそれぞれ変更を加え、ソース管理の流れを確認します。 検証用のデー タセット は Microsoft Fabric のチュートリアル で提供されている 卸売業の売上データ を利用しました。 売上データが格納された 1 つのファクトテーブルと、商品や顧客、従業員といった情報が格納された 5 つのディメンションテーブルで構成されています。 検証用のレポートは前述のデー タセット から自動生成しており、複数のグラフとカードおよびテキストビジュアルから構成されています。 まずはデー タセット に対して変更を加えてみます。 今回は、 Microsoft Fabric の GUI からデー タセット に構成されているリレーションシップを 1 件削除し、構成ファイルにどのような変更があるか確認しました。 デー タセット に変更を加えると、 ワークスペース のアイテム一覧画面で検出されます。 同画面でトピックブランチへチェックアウトして変更をコミットすると、同期先の Azure Repos にて変更された構成ファイルや箇所を確認できます。 検証用のデー タセット は 4 つのファイルで構成されており、リレーションシップの設定については model.bim というファイルのみに変更が適用されていました。 各ファイルの説明を下表に記載します。 ファイル名  必須  説明 model.bim 〇 データベースオブジェクトの定義が Tabular Model Scripting Language(TMSL)で記述されている definition.pbidataset 〇 デー タセット に関連付けられた Q&A や スキーマ 共有に関する設定が記述されている item.config.json ファイルのバージョン情報と同期先の ワークスペース ID が記述されている item.metadata.json Git 統合されているアイテムの種別(ここではデー タセット )とアイテム名、説明が記述されている 上記をふまえると、デー タセット に対して想定される下記のような操作については、その変更が model.bim の記述に反映されると推測できます。 テーブルの追加・削除 データの挿入・更新や削除 データモデルでのメジャー作成 リレーションシップの変更 次にレポートに対しても変更を加えます。 Microsoft Fabric の Power BI にて、前述したレポートに下図のカードとグラフビジュアルを追加しました。 デー タセット に対する変更と同様、上記の変更は ワークスペース のアイテム一覧画面で検出され、コミット後に Azure Repos 側で詳細を確認できます。 検証用のレポートは 5 つのファイルで構成されており、今回の変更については report.json というファイルのみに変更が適用されていました。 各ファイルの説明を下表に記載します。 ファイル名  必須  説明 CY23SU08.json レポートのカスタムテーマ、イメージ、カスタムビジュアルなどの固有情報が記述されている definition.pbir 〇 参照するデー タセット に関する情報が記述されている report.json 〇 レポートに含まれるページ、ビジュアルの情報が記述されている item.config.json ファイルのバージョン情報と同期先の ワークスペース ID が記述されている item.metadata.json Git 統合されているアイテムの種別(ここではレポート)とアイテム名、説明が記述されている 今回はレポートのビジュアルに関する変更のみを実施したため、 report.json の記述のみが影響を受けたと考えられます。 また、デー タセット およびレポートの設定によっては上記に加えて追加の構成ファイルが必要になる場合もあります。 詳細は下記ドキュメントをご参照ください。 Git 統合ソース コード フォーマット Power BI Desktop プロジェクト データセット フォルダー Power BI Desktop プロジェクト レポート フォルダー 変更内容をコミットした後は、Pull Request による一般的なレビュー手順に沿って main ブランチへ変更を適用できました。 トピックブランチとマージ先のブランチ( main )およびレビュアーを指定し、Pull Request を作成 レビュアーは Pull Request の内容を確認し、指摘やコメントをレビュイーに伝える レビューに問題がなければレビュアーの承認をもって Pull Request を完了し、変更を main ブランチへマージする また、今回は実施しませんでしたが Microsoft Fabric では Azure Pipelines を利用したテスト・デプロイの自動化についてもサポートしています。 Azure Pipelines は Azure Repos と同様 Azure DevOps に含まれるサービスのため、Git 統合とうまく組み合わせて CI/CD 環境を構築することで開発やテストの効率化が期待できます。 Azure Pipelines デプロイ パイプラインの概要 ソース管理時の注意点 Microsoft Fabric 上ではレポートやデー タセット といったアイテムの構成ファイルを管理していないため、Git クライアントアプリケーションのように具体的な変更箇所がわかりません。 そのため、作業者自身が変更内容を正しく把握し、適切なコミットメッセージの記述等で円滑なコミュニケーションを図るといった意識が重要になります。 また、 Microsoft Fabric の UI で可能な Git 操作は現状 git commit と git checkout のみです。 コミットの取り消しやリベースなどの操作が必要になった際は、Git コマンドライン ツールや Git クライアントアプリケーションを Azure Repos と併用する必要があります。 まとめ 本記事では、 Microsoft Fabric の Git 統合を利用したソース管理について、実際に利用した際の手順や注意事項、所感についてご紹介しました。 これまで Power BI のデー タセット やレポートといったアイテムはテキストベースでのソース管理ができませんでしたが、Git 統合により GUI 上で可能になった点は魅力的だと感じています。 一方で、一般的なソース管理ではコミットの取り消しやその他 Git コマンドを利用した作業も多いため、Git クライアントや コマンドライン ツールと併用した管理方法も選択肢になり得ます。 現時点では可視化領域のアイテムのみが Git 統合に対応していますが、将来的にはデータ加工や変換、分析といった領域で必要となる ETL パイプラインやデータフロー、各種クエリについてもソース管理の対象となることを期待します。 私たちは一緒に働いてくれる仲間を募集しています! クラウドアーキテクト 執筆: @tamura.kohei 、レビュー: @kano.nanami ( Shodo で執筆されました )
アバター
はじめに ISID X(クロス) イノベーション 本部 の池田です。 Azure Portal から Azure Load Testing を操作する方法については以下の記事もご覧ください。 tech.isid.co.jp 負荷試験 の計画の中でいろいろな利用パターンでの試験により環境を分析するケースがあります。 しかし、Azure Portal からの操作では JMeter スクリプト のアップロードや参照できるリソース選択など選択項目が多く、複数パターンを何度も手動で作成するのは手間です。 そこで CLI から操作して複数テストを一括登録する方法を試しましたのでご紹介します。 利用ツール 通常のAzureリソースの CLI 操作としては、Azure CLI や Azure Power Shell, ARMテンプレート を利用するのが一般的です。しかし、2023年2月にGAしたばかりの Azure Load Testing においては 2023年5月時点でこれらのツールでAzureリソース作成はできるものの詳細な設定ができませんでした。Azure Load Testing REST API では先行してテスト作成の機能が提供されていたため、こちらを利用して作成します。(現在はAzure CLI によるテスト作成もサポートされるようになっています) 今回の スクリプト 実行環境は以下のとおりです。 スクリプト の記載は環境依存のものが含まれますので、参考にされる際はご自身の環境に合わせて調整してください。 PowerShell 7.3.4 azure-cli 2.49.0 curl 8.0.1 (Windows) libcurl/8.0.1 Schannel WinIDN 試験環境の概要 今回使用するテスト環境の構成は以下のとおりです。App Service 既定のWebサイトをテスト対象としてAzure Load TestingからHTTPリク エス トを連続送信します。その上でAzureリソースの負荷状況を Azure Load Testing の ダッシュ ボードに表示する構成となります。 Azure Load Testingリソースの作成 Azureリソース作成はAzure CLI で機能提供されていましたので、この部分はこちらのコマンドを利用して作成します。 az load create --name ${loadTestName} -- resource-group ${resourceGroupName} --location eastasia データプレーン URI の取得 Azure リソースマネージャーに対する要求では az rest コマンドを利用すると認証ヘッダーを自動付与できて便利です。 az rest で REST API を呼び出して作成されたリソースのデータプレーンエンドポイントを取得します。 $loadTest = ( az rest ` --method get ` --uri https: // management.azure.com / subscriptions / ${subscriptionId} / resourceGroups / ${resourceGroupName} / providers / Microsoft.LoadTestService / loadTests / ${loadTestName} ? api-version = 2022 - 12 - 01 ` | ConvertFrom-Json ) $Endpoint = $loadTest .properties.dataPlaneURI $Endpoint 以下のような出力が得られます。これでデータプレーン操作に必要なエンドポイントが取得できました。 XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.eastasia.cnt-prod.loadtesting.azure.com データプレーン用アクセス トーク ンの取得 ここからは Azureリソースマネージャー へのアクセスではなくデータプレーンエンドポイントへの操作となります。データプレーン用のアクセス トーク ンを取得する必要があります。 必要なアクセス トーク ン Azure Load Testing REST API のリファレンスを参照すると、「 https://cnt-prod.loadtesting.azure.com/.default%E3%80%8D%E3%82%92Scope%E3%81%A8%E3%81%97%E3%81%9F%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%A8%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82 Load Test Administration - Create Or Update Test アクセス トーク ンの取得 az account get- access -token コマンドを利用して、該当スコープに対するアクセス トーク ンを取得します。 ( 参考: az account get-access-token ) $accessToken = (az account get-access-token ` --scope 'https://cnt-prod.loadtesting.azure.com/.default' ` --query 'accessToken' ` --output tsv) テストの構成 データプレーンエンドポイントとアクセス トーク ンがそろいましたので、続いてデータプレーンの操作をします。 データプレーンはTemplateファイルを用意してそれを curl コマンドで投げ込む形で操作します。 ID採番 まずは、テストIDとして使用するGuidを採番します。 $testId = ( New-Guid ) テスト作成 実際にAzure Load Testing REST API を呼び出してテストを作成していきます。 (参考: Load Test Administration - Create Or Update Test ) curl ` --request PATCH ` --header "Authorization: Bearer $accessToken " ` --header "Content-Type: application/merge-patch+json" ` --url "https:// ${Endpoint} /tests/ ${testId} ?api-version=2022-11-01" ` -- upload-file TestTemplate.json 送信ファイルに記述するパラメータが以下となります。Azure Portal 上で作成したテストの内容を API で取得して参考にしつつ作るのがおすすめです。 (参考: Load Test Administration - Get Test ) { "displayName": "displayName_test1", "description": "", "keyvaultReferenceIdentityType": "SystemAssigned", "passFailCriteria": { "passFailMetrics": {} }, "loadTestConfiguration": { "engineInstances": 10, "splitAllCSVs": false, "quickStartTest": false } } アプリ コンポーネント 登録 次にテスト結果画面に表示するアプリ コンポーネント (Azure リソースのコレクション)を登録します。 (参考: Load Test Administration - Create Or Update App Components ) curl ` --request PATCH ` --header "Authorization: Bearer $accessToken " ` --header "Content-Type: application/merge-patch+json" ` --url "https:// ${Endpoint} /tests/ ${testId} /app-components?api-version=2022-11-01" ` -- upload-file AppComponents.json アプリ コンポーネント は以下のように列挙していく形で登録します。参考とする既存設定の取得 API は以下です。 (参考: Load Test Administration - Get App Components ) { "components": { "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda": { "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda", "resourceName": "app-demo-ikeda", "resourceType": "Microsoft.Web/sites", "resourceGroup": "rg-load-test", "subscriptionId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "kind": "app" }, "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo": { "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo", "resourceName": "plan-load-demo", "resourceType": "Microsoft.Web/serverfarms", "resourceGroup": "rg-load-test", "subscriptionId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "kind": "app" } } } メトリック登録 続いて、テスト結果画面に表示するメトリックを登録します。 (参考: Load Test Administration - Create Or Update Server Metrics Config ) curl ` --request PATCH ` --header "Authorization: Bearer $accessToken " ` --header "Content-Type: application/merge-patch+json" ` --url "https:// ${Endpoint} /tests/ ${testId} /server-metrics-config?api-version=2022-11-01" ` -- upload-file ServerMetricsConfig.json 前段で登録したアプリ コンポーネント に対するメトリックを列挙します。参考とする既存設定の取得 API は下記です。 (参考: Load Test Administration - Get Server Metrics Config ) { "metrics": { "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda/providers/microsoft.insights/metricdefinitions/Http5xx": { "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda/providers/microsoft.insights/metricdefinitions/Http5xx", "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda", "metricNamespace": "microsoft.web/sites", "name": "Http5xx", "aggregation": "Total", "resourceType": "microsoft.web/sites" }, "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda/providers/microsoft.insights/metricdefinitions/Requests": { "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda/providers/microsoft.insights/metricdefinitions/Requests", "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda", "metricNamespace": "microsoft.web/sites", "name": "Requests", "aggregation": "Total", "resourceType": "microsoft.web/sites" }, "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda/providers/microsoft.insights/metricdefinitions/HttpResponseTime": { "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda/providers/microsoft.insights/metricdefinitions/HttpResponseTime", "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda", "metricNamespace": "microsoft.web/sites", "name": "HttpResponseTime", "aggregation": "Average", "resourceType": "microsoft.web/sites" }, "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo/providers/microsoft.insights/metricdefinitions/CpuPercentage": { "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo/providers/microsoft.insights/metricdefinitions/CpuPercentage", "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo", "metricNamespace": "microsoft.web/serverfarms", "name": "CpuPercentage", "aggregation": "Average", "resourceType": "microsoft.web/serverfarms" }, "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo/providers/microsoft.insights/metricdefinitions/MemoryPercentage": { "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo/providers/microsoft.insights/metricdefinitions/MemoryPercentage", "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo", "metricNamespace": "microsoft.web/serverfarms", "name": "MemoryPercentage", "aggregation": "Average", "resourceType": "microsoft.web/serverfarms" } } } JMeter スクリプト 登録 以下の操作でテストで実行する JMeter スクリプト をアップロードします。 (参考: Load Test Administration - Upload Test File ) curl ` --request PUT ` --header "Authorization: Bearer $accessToken " ` --header "Content-Type: application/octet-stream content" ` --url "https:// ${Endpoint} /tests/ ${testId} /files/ ${NAME_JMX} ?api-version=2022-11-01&fileType=JMX_FILE" ` -- upload-file lt-demo .jmx こちらが JMeter で作成した JMX ファイルです。今回はHTTP Getリク エス トをループするシンプルな スクリプト を使用しています。 <?xml version="1.0" encoding="UTF-8"?> <jmeterTestPlan version="1.2" properties="5.0" jmeter="5.5"> <hashTree> <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true"> <stringProp name="TestPlan.comments"></stringProp> <boolProp name="TestPlan.functional_mode">false</boolProp> <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp> <boolProp name="TestPlan.serialize_threadgroups">false</boolProp> <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"> <collectionProp name="Arguments.arguments"/> </elementProp> <stringProp name="TestPlan.user_define_classpath"></stringProp> </TestPlan> <hashTree> <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true"> <stringProp name="ThreadGroup.on_sample_error">continue</stringProp> <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true"> <boolProp name="LoopController.continue_forever">false</boolProp> <intProp name="LoopController.loops">-1</intProp> </elementProp> <stringProp name="ThreadGroup.num_threads">10</stringProp> <stringProp name="ThreadGroup.ramp_time">1</stringProp> <boolProp name="ThreadGroup.scheduler">false</boolProp> <stringProp name="ThreadGroup.duration"></stringProp> <stringProp name="ThreadGroup.delay"></stringProp> <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp> </ThreadGroup> <hashTree> <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP Request" enabled="true"> <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"> <collectionProp name="Arguments.arguments"/> </elementProp> <stringProp name="HTTPSampler.domain">app-demo-ikeda.azurewebsites.net</stringProp> <stringProp name="HTTPSampler.port">443</stringProp> <stringProp name="HTTPSampler.protocol">https</stringProp> <stringProp name="HTTPSampler.contentEncoding"></stringProp> <stringProp name="HTTPSampler.path"></stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> <boolProp name="HTTPSampler.use_keepalive">true</boolProp> <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> <stringProp name="HTTPSampler.embedded_url_re"></stringProp> <stringProp name="HTTPSampler.connect_timeout"></stringProp> <stringProp name="HTTPSampler.response_timeout"></stringProp> </HTTPSamplerProxy> <hashTree/> </hashTree> </hashTree> </hashTree> </jmeterTestPlan> テストの実行 テスト実行 ボディ部にテストIDを指定することで登録したテスト内容を実行できます。テスト表示名は スクリプト 内で日時から作成しています。 (参考: Load Test Run - Create Or Update Test Run ) curl ` --request PATCH ` --header "Authorization: Bearer $accessToken" ` --header "Content-Type: application/merge-patch+json" ` --url "https://${Endpoint}/test-runs/$(New-Guid)?api-version=2022-11-01" ` --data "{'testId': '${testId}','displayName':'TestRun_$((Get-Date).ToString("yyyy/MM/dd_HH:mm:ss"))'}" 実行結果の確認 Azure Portal での確認 Azure Portal 上で作成したテストが実行されていることを確認できます。 アプリ コンポーネント テスト画面の「アプリ コンポーネント 」から REST API で登録したアプリ コンポーネント が確認できます。 メトリックの構成 同じく「メトリックの構成」から表示メトリックも反映されていることが確認できます。 備考 ドキュメントが整備されていない場合、 API の利用方法を調べるのにブラウザのDevToolsでAzure Portal の通信内容を見るのも参考になります。今回もAzure Portal 上での設定項目と API 項目に差異があり、通信内容を見てみると新しい Preview バージョンの API を利用していました。新しいサービスではドキュメント化が遅れているケースもありますので必要に応じて参考にしましょう。 まとめ Azure Load Testing の操作を REST API を利用して スクリプト 化することで、複数パターンの試験登録が簡単にできるようになりました。新しいサービスでは周辺ツールがまだ提供されていないケースもありますが、ベースとなる REST API が先行して提供されていることがあります。 REST API による操作も活用することでAzureでできることが広がります。ご参考になれば幸いです。 私たちは同じチームで働いてくれる仲間を探しています。 クラウド アーキテクトの業務に興味がある方のご応募をお待ちしています。 クラウドアーキテクト 執筆: @ikeda.jun 、レビュー: @mizuno.kazuhiro ( Shodo で執筆されました )
アバター
はじめに ISID X(クロス) イノベーション 本部 の池田です。 Azure Portal から Azure Load Testing を操作する方法については以下の記事もご覧ください。 tech.isid.co.jp 負荷試験 の計画の中でいろいろな利用パターンでの試験により環境を分析するケースがあります。 しかし、Azure Portal からの操作では JMeter スクリプト のアップロードや参照できるリソース選択など選択項目が多く、複数パターンを何度も手動で作成するのは手間です。 そこで CLI から操作して複数テストを一括登録する方法を試しましたのでご紹介します。 利用ツール 通常のAzureリソースの CLI 操作としては、Azure CLI や Azure Power Shell, ARMテンプレート を利用するのが一般的です。しかし、2023年2月にGAしたばかりの Azure Load Testing においては 2023年5月時点でこれらのツールでAzureリソース作成はできるものの詳細な設定ができませんでした。Azure Load Testing REST API では先行してテスト作成の機能が提供されていたため、こちらを利用して作成します。(現在はAzure CLI によるテスト作成もサポートされるようになっています) 今回の スクリプト 実行環境は以下のとおりです。 スクリプト の記載は環境依存のものが含まれますので、参考にされる際はご自身の環境に合わせて調整してください。 PowerShell 7.3.4 azure-cli 2.49.0 curl 8.0.1 (Windows) libcurl/8.0.1 Schannel WinIDN 試験環境の概要 今回使用するテスト環境の構成は以下のとおりです。App Service 既定のWebサイトをテスト対象としてAzure Load TestingからHTTPリク エス トを連続送信します。その上でAzureリソースの負荷状況を Azure Load Testing の ダッシュ ボードに表示する構成となります。 Azure Load Testingリソースの作成 Azureリソース作成はAzure CLI で機能提供されていましたので、この部分はこちらのコマンドを利用して作成します。 az load create --name ${loadTestName} -- resource-group ${resourceGroupName} --location eastasia データプレーン URI の取得 Azure リソースマネージャーに対する要求では az rest コマンドを利用すると認証ヘッダーを自動付与できて便利です。 az rest で REST API を呼び出して作成されたリソースのデータプレーンエンドポイントを取得します。 $loadTest = ( az rest ` --method get ` --uri https: // management.azure.com / subscriptions / ${subscriptionId} / resourceGroups / ${resourceGroupName} / providers / Microsoft.LoadTestService / loadTests / ${loadTestName} ? api-version = 2022 - 12 - 01 ` | ConvertFrom-Json ) $Endpoint = $loadTest .properties.dataPlaneURI $Endpoint 以下のような出力が得られます。これでデータプレーン操作に必要なエンドポイントが取得できました。 XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.eastasia.cnt-prod.loadtesting.azure.com データプレーン用アクセス トーク ンの取得 ここからは Azureリソースマネージャー へのアクセスではなくデータプレーンエンドポイントへの操作となります。データプレーン用のアクセス トーク ンを取得する必要があります。 必要なアクセス トーク ン Azure Load Testing REST API のリファレンスを参照すると、「 https://cnt-prod.loadtesting.azure.com/.default%E3%80%8D%E3%82%92Scope%E3%81%A8%E3%81%97%E3%81%9F%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%A8%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82 Load Test Administration - Create Or Update Test アクセス トーク ンの取得 az account get- access -token コマンドを利用して、該当スコープに対するアクセス トーク ンを取得します。 ( 参考: az account get-access-token ) $accessToken = (az account get-access-token ` --scope 'https://cnt-prod.loadtesting.azure.com/.default' ` --query 'accessToken' ` --output tsv) テストの構成 データプレーンエンドポイントとアクセス トーク ンがそろいましたので、続いてデータプレーンの操作をします。 データプレーンはTemplateファイルを用意してそれを curl コマンドで投げ込む形で操作します。 ID採番 まずは、テストIDとして使用するGuidを採番します。 $testId = ( New-Guid ) テスト作成 実際にAzure Load Testing REST API を呼び出してテストを作成していきます。 (参考: Load Test Administration - Create Or Update Test ) curl ` --request PATCH ` --header "Authorization: Bearer $accessToken " ` --header "Content-Type: application/merge-patch+json" ` --url "https:// ${Endpoint} /tests/ ${testId} ?api-version=2022-11-01" ` -- upload-file TestTemplate.json 送信ファイルに記述するパラメータが以下となります。Azure Portal 上で作成したテストの内容を API で取得して参考にしつつ作るのがおすすめです。 (参考: Load Test Administration - Get Test ) { "displayName": "displayName_test1", "description": "", "keyvaultReferenceIdentityType": "SystemAssigned", "passFailCriteria": { "passFailMetrics": {} }, "loadTestConfiguration": { "engineInstances": 10, "splitAllCSVs": false, "quickStartTest": false } } アプリ コンポーネント 登録 次にテスト結果画面に表示するアプリ コンポーネント (Azure リソースのコレクション)を登録します。 (参考: Load Test Administration - Create Or Update App Components ) curl ` --request PATCH ` --header "Authorization: Bearer $accessToken " ` --header "Content-Type: application/merge-patch+json" ` --url "https:// ${Endpoint} /tests/ ${testId} /app-components?api-version=2022-11-01" ` -- upload-file AppComponents.json アプリ コンポーネント は以下のように列挙していく形で登録します。参考とする既存設定の取得 API は以下です。 (参考: Load Test Administration - Get App Components ) { "components": { "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda": { "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda", "resourceName": "app-demo-ikeda", "resourceType": "Microsoft.Web/sites", "resourceGroup": "rg-load-test", "subscriptionId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "kind": "app" }, "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo": { "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo", "resourceName": "plan-load-demo", "resourceType": "Microsoft.Web/serverfarms", "resourceGroup": "rg-load-test", "subscriptionId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "kind": "app" } } } メトリック登録 続いて、テスト結果画面に表示するメトリックを登録します。 (参考: Load Test Administration - Create Or Update Server Metrics Config ) curl ` --request PATCH ` --header "Authorization: Bearer $accessToken " ` --header "Content-Type: application/merge-patch+json" ` --url "https:// ${Endpoint} /tests/ ${testId} /server-metrics-config?api-version=2022-11-01" ` -- upload-file ServerMetricsConfig.json 前段で登録したアプリ コンポーネント に対するメトリックを列挙します。参考とする既存設定の取得 API は下記です。 (参考: Load Test Administration - Get Server Metrics Config ) { "metrics": { "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda/providers/microsoft.insights/metricdefinitions/Http5xx": { "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda/providers/microsoft.insights/metricdefinitions/Http5xx", "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda", "metricNamespace": "microsoft.web/sites", "name": "Http5xx", "aggregation": "Total", "resourceType": "microsoft.web/sites" }, "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda/providers/microsoft.insights/metricdefinitions/Requests": { "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda/providers/microsoft.insights/metricdefinitions/Requests", "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda", "metricNamespace": "microsoft.web/sites", "name": "Requests", "aggregation": "Total", "resourceType": "microsoft.web/sites" }, "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda/providers/microsoft.insights/metricdefinitions/HttpResponseTime": { "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda/providers/microsoft.insights/metricdefinitions/HttpResponseTime", "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/sites/app-demo-ikeda", "metricNamespace": "microsoft.web/sites", "name": "HttpResponseTime", "aggregation": "Average", "resourceType": "microsoft.web/sites" }, "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo/providers/microsoft.insights/metricdefinitions/CpuPercentage": { "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo/providers/microsoft.insights/metricdefinitions/CpuPercentage", "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo", "metricNamespace": "microsoft.web/serverfarms", "name": "CpuPercentage", "aggregation": "Average", "resourceType": "microsoft.web/serverfarms" }, "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo/providers/microsoft.insights/metricdefinitions/MemoryPercentage": { "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo/providers/microsoft.insights/metricdefinitions/MemoryPercentage", "resourceId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-load-test/providers/Microsoft.Web/serverfarms/plan-load-demo", "metricNamespace": "microsoft.web/serverfarms", "name": "MemoryPercentage", "aggregation": "Average", "resourceType": "microsoft.web/serverfarms" } } } JMeter スクリプト 登録 以下の操作でテストで実行する JMeter スクリプト をアップロードします。 (参考: Load Test Administration - Upload Test File ) curl ` --request PUT ` --header "Authorization: Bearer $accessToken " ` --header "Content-Type: application/octet-stream content" ` --url "https:// ${Endpoint} /tests/ ${testId} /files/ ${NAME_JMX} ?api-version=2022-11-01&fileType=JMX_FILE" ` -- upload-file lt-demo .jmx こちらが JMeter で作成した JMX ファイルです。今回はHTTP Getリク エス トをループするシンプルな スクリプト を使用しています。 <?xml version="1.0" encoding="UTF-8"?> <jmeterTestPlan version="1.2" properties="5.0" jmeter="5.5"> <hashTree> <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true"> <stringProp name="TestPlan.comments"></stringProp> <boolProp name="TestPlan.functional_mode">false</boolProp> <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp> <boolProp name="TestPlan.serialize_threadgroups">false</boolProp> <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"> <collectionProp name="Arguments.arguments"/> </elementProp> <stringProp name="TestPlan.user_define_classpath"></stringProp> </TestPlan> <hashTree> <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true"> <stringProp name="ThreadGroup.on_sample_error">continue</stringProp> <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true"> <boolProp name="LoopController.continue_forever">false</boolProp> <intProp name="LoopController.loops">-1</intProp> </elementProp> <stringProp name="ThreadGroup.num_threads">10</stringProp> <stringProp name="ThreadGroup.ramp_time">1</stringProp> <boolProp name="ThreadGroup.scheduler">false</boolProp> <stringProp name="ThreadGroup.duration"></stringProp> <stringProp name="ThreadGroup.delay"></stringProp> <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp> </ThreadGroup> <hashTree> <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP Request" enabled="true"> <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"> <collectionProp name="Arguments.arguments"/> </elementProp> <stringProp name="HTTPSampler.domain">app-demo-ikeda.azurewebsites.net</stringProp> <stringProp name="HTTPSampler.port">443</stringProp> <stringProp name="HTTPSampler.protocol">https</stringProp> <stringProp name="HTTPSampler.contentEncoding"></stringProp> <stringProp name="HTTPSampler.path"></stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> <boolProp name="HTTPSampler.use_keepalive">true</boolProp> <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> <stringProp name="HTTPSampler.embedded_url_re"></stringProp> <stringProp name="HTTPSampler.connect_timeout"></stringProp> <stringProp name="HTTPSampler.response_timeout"></stringProp> </HTTPSamplerProxy> <hashTree/> </hashTree> </hashTree> </hashTree> </jmeterTestPlan> テストの実行 テスト実行 ボディ部にテストIDを指定することで登録したテスト内容を実行できます。テスト表示名は スクリプト 内で日時から作成しています。 (参考: Load Test Run - Create Or Update Test Run ) curl ` --request PATCH ` --header "Authorization: Bearer $accessToken" ` --header "Content-Type: application/merge-patch+json" ` --url "https://${Endpoint}/test-runs/$(New-Guid)?api-version=2022-11-01" ` --data "{'testId': '${testId}','displayName':'TestRun_$((Get-Date).ToString("yyyy/MM/dd_HH:mm:ss"))'}" 実行結果の確認 Azure Portal での確認 Azure Portal 上で作成したテストが実行されていることを確認できます。 アプリ コンポーネント テスト画面の「アプリ コンポーネント 」から REST API で登録したアプリ コンポーネント が確認できます。 メトリックの構成 同じく「メトリックの構成」から表示メトリックも反映されていることが確認できます。 備考 ドキュメントが整備されていない場合、 API の利用方法を調べるのにブラウザのDevToolsでAzure Portal の通信内容を見るのも参考になります。今回もAzure Portal 上での設定項目と API 項目に差異があり、通信内容を見てみると新しい Preview バージョンの API を利用していました。新しいサービスではドキュメント化が遅れているケースもありますので必要に応じて参考にしましょう。 まとめ Azure Load Testing の操作を REST API を利用して スクリプト 化することで、複数パターンの試験登録が簡単にできるようになりました。新しいサービスでは周辺ツールがまだ提供されていないケースもありますが、ベースとなる REST API が先行して提供されていることがあります。 REST API による操作も活用することでAzureでできることが広がります。ご参考になれば幸いです。 私たちは同じチームで働いてくれる仲間を探しています。 クラウド アーキテクトの業務に興味がある方のご応募をお待ちしています。 クラウドアーキテクト 執筆: @ikeda.jun 、レビュー: @mizuno.kazuhiro ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 Terraform で Amazon RDS インスタンス / クラスタ ーを作る時に、 password または master_password 属性に指定したマスターユーザーのパスワードが tfstate ファイルに平文で残ってしまう問題がありました。 (参考) https://speakerdeck.com/harukasakihara/sekiyuanaterraformfalseshi-ifang-ji-mi-qing-bao-wokodonihan-mezuhuan-jing-gou-zhu-surunihadousitaraiifalse しかしこれも過去の話。Terraform AWS Provider v4.61.0 からこの問題を解消する方法が提供されているので、それについてご紹介します。 RDS と Secrets Manager の統合 manage_master_user_password を使わない場合 manage_master_user_password を使った場合 aws_rds_cluster にも利用できる KMSキーを指定する 既存の Secrets Manager シークレットを利用する場合 既存のDBに使ったらどうなるか スナップショットからリストアする時の挙動 さいごに RDS と Secrets Manager の統合 事の始まりは 2022年12月に発表された Amazon RDS と AWS Secrets Manager の統合 というアップデートでした。DB 作成時に、RDS への API コールにてマスターユーザーのパスワードを Secrets Manager で作成・保存してくれるようになりました。 Terraform AWS Provider でもこれへの 対応 として、2023年3月にリリースされた v4.61.0 で manage_master_user_password 属性が aws_rds_cluster と aws_db_instance で利用できるようになりました! 実際にリソースを作成して試してみます。 manage_master_user_password を使わない場合 以下のように平文で password を指定し、 aws_db_instance リソースを作成してみます。(BADプ ラク ティスです) resource "aws_db_instance" "my-db-1" { allocated_storage = 10 engine = "mysql" engine_version = "5.7" instance_class = "db.t3.micro" username = "master" # password に平文でパスワードを記述する悪い例 password = "MyPassword123" vpc_security_group_ids = [ aws_security_group.db.id ] skip_final_snapshot = true db_subnet_group_name = "db-subnet-group" } デプロイ後の terraform.tfstate ファイルには、次のとおり平文でパスワード文字列が記録されてしまっています。 例のように .tf ファイルに直接 password を書くのは最悪ですが、他の回避策(Variablesを利用して apply 時にターミナルで指定する、Secrets Manager シークレットに先に登録してから Datasource で取得する、etc)をとったところでどうしても tfstate ファイルに記録されてしまうのは問題でした。 manage_master_user_password を使った場合 password 属性を削除し、 manage_master_user_password 属性に true を設定します。 resource "aws_db_instance" "my-db-2" { allocated_storage = 10 engine = "mysql" engine_version = "5.7" instance_class = "db.t3.micro" username = "master" # manage_master_user_password を利用する manage_master_user_password = true vpc_security_group_ids = [ aws_security_group.db.id ] skip_final_snapshot = true db_subnet_group_name = "db-subnet-group" } デプロイすると、Secrets Manager にシークレットが作成されていることがわかります。 シークレットのキーには username と password が登録されており、 password は RDS が生成したランダムな値になっていました。また 7日間の間隔でシークレットローテーションも設定されていました。 デプロイ後の terraform.tfstate ファイルでは、 password は null となっており、実際のパスワード文字列はどこにも記録されていません。 aws _rds_cluster にも利用できる aws_rds_cluster リソースに対しても、従来の master_password の代わりに manage_master_user_password を利用できるようになっています。 (参考) https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster#rdsaurora-managed-master-passwords-via-secrets-manager-default-kms-key KMSキーを指定する master_user_secret_kms_key_id 属性を利用することで、デフォルトキーではなく指定した KMS キーでシークレットの暗号化をすることもできます。 (参考) https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance#managed-master-passwords-via-secrets-manager-specific-kms-key https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster#rdsaurora-managed-master-passwords-via-secrets-manager-specific-kms-key 既存の Secrets Manager シークレットを利用する場合 今回は試していませんが、 master_user_secret の設定ブロックを使うと、既存の Secrets Manager シークレットをマスターユーザーのパスワードにできるようです。 (参考) https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance#master_user_secret 既存のDBに使ったらどうなるか 既に password や master_password を使って作成した DB に対して、 manage_master_user_password を利用する方法に切り替えることは可能です。DB は再作成されませんが、マスターユーザーのパスワードは新規に作成され(現在のパスワードは引き継がれずに) Secrets Manager に新しいシークレットとして保存されるようです。既存の DB で manage_master_user_password を使う方法に切り替える場合は、アプリケーションの動作や運用に影響がないか慎重に確認しましょう。 スナップショットからリストアする時の挙動 manage_master_user_password を利用して作成した DB のスナップショットからリストアする場合、マスターユーザーのパスワードは少し特殊な状態になるようです。次のように manage_master_user_password = true を使ってスナップショットから DB インスタンス を作成しても、Secrets Manager にパスワードは統合されず、RDS がパスワードを管理している状態で DB が復元しました。パスワードはスナップショット取得時点のものでした。 data "aws_db_snapshot" "my-snapshot" { db_snapshot_identifier = "snapshot1" } resource "aws_db_instance" "my-db-from-snapshot" { allocated_storage = 10 engine = "mysql" engine_version = "5.7" instance_class = "db.t3.micro" username = "master" # snapshot_identifier を利用してリストアする時、 # manage_master_user_password 属性を使っても # パスワードが Secrets Manager で管理されない。 manage_master_user_password = true skip_final_snapshot = true db_subnet_group_name = "db-subnet-group" # スナップショットから復元する snapshot_identifier = "$ { data.aws_db_snapshot.my-snapshot.id } " } この現象は GitHub の Issue にも報告されており、記事執筆時点では未解決です。ただし tfstate ファイルに記録された password は null だったため、Terraform AWS Provider のバグというよりは RDS の制約なのかもしれません。 リストアした DB のパスワードも Secrets Manager で管理するためには、今のところの次の ワークアラウンド が良さそうです。 manage_master_user_password を付けずに Terraform でスナップショットをリストア( apply ) スナップショット取得時点のパスワードを、RDS が管理している状態でリストアされる manage_master_user_password = true を付けてもう一度 apply する マスターユーザーのパスワードは新規に作成されて Secrets Manager に保存される data "aws_db_snapshot" "my-snapshot" { db_snapshot_identifier = "snapshot1" } resource "aws_db_instance" "my-db-from-snapshot" { allocated_storage = 10 engine = "mysql" engine_version = "5.7" instance_class = "db.t3.micro" username = "master" # リストア時は manage_master_user_password を付けずに apply # リストア後 manage_master_user_password を付けて再度 apply # manage_master_user_password = true skip_final_snapshot = true db_subnet_group_name = "db-subnet-group" snapshot_identifier = "$ { data.aws_db_snapshot.my-snapshot.id } " } さいごに Terraform において tfstate ファイルに平文の DB パスワードが残ってしまう問題を簡単に解消する manage_master_user_password 属性についてご紹介しました。今後新たに Terraform で RDS インスタンス / クラスタ ーを作る時には、ぜひ利用を検討しましょう。ただしスナップショットからリストアする時の動きは(記事執筆時点で)少し特殊なので要注意です。 お読みいただいてありがとうございました。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア 執筆: @kou.kinyo 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 Terraform で Amazon RDS インスタンス / クラスタ ーを作る時に、 password または master_password 属性に指定したマスターユーザーのパスワードが tfstate ファイルに平文で残ってしまう問題がありました。 (参考) https://speakerdeck.com/harukasakihara/sekiyuanaterraformfalseshi-ifang-ji-mi-qing-bao-wokodonihan-mezuhuan-jing-gou-zhu-surunihadousitaraiifalse しかしこれも過去の話。Terraform AWS Provider v4.61.0 からこの問題を解消する方法が提供されているので、それについてご紹介します。 RDS と Secrets Manager の統合 manage_master_user_password を使わない場合 manage_master_user_password を使った場合 aws_rds_cluster にも利用できる KMSキーを指定する 既存の Secrets Manager シークレットを利用する場合 既存のDBに使ったらどうなるか スナップショットからリストアする時の挙動 さいごに RDS と Secrets Manager の統合 事の始まりは 2022年12月に発表された Amazon RDS と AWS Secrets Manager の統合 というアップデートでした。DB 作成時に、RDS への API コールにてマスターユーザーのパスワードを Secrets Manager で作成・保存してくれるようになりました。 Terraform AWS Provider でもこれへの 対応 として、2023年3月にリリースされた v4.61.0 で manage_master_user_password 属性が aws_rds_cluster と aws_db_instance で利用できるようになりました! 実際にリソースを作成して試してみます。 manage_master_user_password を使わない場合 以下のように平文で password を指定し、 aws_db_instance リソースを作成してみます。(BADプ ラク ティスです) resource "aws_db_instance" "my-db-1" { allocated_storage = 10 engine = "mysql" engine_version = "5.7" instance_class = "db.t3.micro" username = "master" # password に平文でパスワードを記述する悪い例 password = "MyPassword123" vpc_security_group_ids = [ aws_security_group.db.id ] skip_final_snapshot = true db_subnet_group_name = "db-subnet-group" } デプロイ後の terraform.tfstate ファイルには、次のとおり平文でパスワード文字列が記録されてしまっています。 例のように .tf ファイルに直接 password を書くのは最悪ですが、他の回避策(Variablesを利用して apply 時にターミナルで指定する、Secrets Manager シークレットに先に登録してから Datasource で取得する、etc)をとったところでどうしても tfstate ファイルに記録されてしまうのは問題でした。 manage_master_user_password を使った場合 password 属性を削除し、 manage_master_user_password 属性に true を設定します。 resource "aws_db_instance" "my-db-2" { allocated_storage = 10 engine = "mysql" engine_version = "5.7" instance_class = "db.t3.micro" username = "master" # manage_master_user_password を利用する manage_master_user_password = true vpc_security_group_ids = [ aws_security_group.db.id ] skip_final_snapshot = true db_subnet_group_name = "db-subnet-group" } デプロイすると、Secrets Manager にシークレットが作成されていることがわかります。 シークレットのキーには username と password が登録されており、 password は RDS が生成したランダムな値になっていました。また 7日間の間隔でシークレットローテーションも設定されていました。 デプロイ後の terraform.tfstate ファイルでは、 password は null となっており、実際のパスワード文字列はどこにも記録されていません。 aws _rds_cluster にも利用できる aws_rds_cluster リソースに対しても、従来の master_password の代わりに manage_master_user_password を利用できるようになっています。 (参考) https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster#rdsaurora-managed-master-passwords-via-secrets-manager-default-kms-key KMSキーを指定する master_user_secret_kms_key_id 属性を利用することで、デフォルトキーではなく指定した KMS キーでシークレットの暗号化をすることもできます。 (参考) https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance#managed-master-passwords-via-secrets-manager-specific-kms-key https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster#rdsaurora-managed-master-passwords-via-secrets-manager-specific-kms-key 既存の Secrets Manager シークレットを利用する場合 今回は試していませんが、 master_user_secret の設定ブロックを使うと、既存の Secrets Manager シークレットをマスターユーザーのパスワードにできるようです。 (参考) https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance#master_user_secret 既存のDBに使ったらどうなるか 既に password や master_password を使って作成した DB に対して、 manage_master_user_password を利用する方法に切り替えることは可能です。DB は再作成されませんが、マスターユーザーのパスワードは新規に作成され(現在のパスワードは引き継がれずに) Secrets Manager に新しいシークレットとして保存されるようです。既存の DB で manage_master_user_password を使う方法に切り替える場合は、アプリケーションの動作や運用に影響がないか慎重に確認しましょう。 スナップショットからリストアする時の挙動 manage_master_user_password を利用して作成した DB のスナップショットからリストアする場合、マスターユーザーのパスワードは少し特殊な状態になるようです。次のように manage_master_user_password = true を使ってスナップショットから DB インスタンス を作成しても、Secrets Manager にパスワードは統合されず、RDS がパスワードを管理している状態で DB が復元しました。パスワードはスナップショット取得時点のものでした。 data "aws_db_snapshot" "my-snapshot" { db_snapshot_identifier = "snapshot1" } resource "aws_db_instance" "my-db-from-snapshot" { allocated_storage = 10 engine = "mysql" engine_version = "5.7" instance_class = "db.t3.micro" username = "master" # snapshot_identifier を利用してリストアする時、 # manage_master_user_password 属性を使っても # パスワードが Secrets Manager で管理されない。 manage_master_user_password = true skip_final_snapshot = true db_subnet_group_name = "db-subnet-group" # スナップショットから復元する snapshot_identifier = "$ { data.aws_db_snapshot.my-snapshot.id } " } この現象は GitHub の Issue にも報告されており、記事執筆時点では未解決です。ただし tfstate ファイルに記録された password は null だったため、Terraform AWS Provider のバグというよりは RDS の制約なのかもしれません。 リストアした DB のパスワードも Secrets Manager で管理するためには、今のところの次の ワークアラウンド が良さそうです。 manage_master_user_password を付けずに Terraform でスナップショットをリストア( apply ) スナップショット取得時点のパスワードを、RDS が管理している状態でリストアされる manage_master_user_password = true を付けてもう一度 apply する マスターユーザーのパスワードは新規に作成されて Secrets Manager に保存される data "aws_db_snapshot" "my-snapshot" { db_snapshot_identifier = "snapshot1" } resource "aws_db_instance" "my-db-from-snapshot" { allocated_storage = 10 engine = "mysql" engine_version = "5.7" instance_class = "db.t3.micro" username = "master" # リストア時は manage_master_user_password を付けずに apply # リストア後 manage_master_user_password を付けて再度 apply # manage_master_user_password = true skip_final_snapshot = true db_subnet_group_name = "db-subnet-group" snapshot_identifier = "$ { data.aws_db_snapshot.my-snapshot.id } " } さいごに Terraform において tfstate ファイルに平文の DB パスワードが残ってしまう問題を簡単に解消する manage_master_user_password 属性についてご紹介しました。今後新たに Terraform で RDS インスタンス / クラスタ ーを作る時には、ぜひ利用を検討しましょう。ただしスナップショットからリストアする時の動きは(記事執筆時点で)少し特殊なので要注意です。 お読みいただいてありがとうございました。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア 執筆: @kou.kinyo 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター
みなさんこんにちは! ISID 金融ソリューション事業部の松崎です。 前回 の記事では、「フォトグラメトリによる3Dモデル作成ワークフロー(後編)」と題し、 フォトグラメトリで使用する写真撮影後の現像や加工手法、RealityCaptureを使ってのモデル作成方法について紹介しました。 まだご覧になっていない方は、是非読んでいただけると嬉しいです! 今回は、回転台とグリーンバックを使ったお手軽フォトグラメトリ方法を紹介します。 はじめに フォトグラメトリにおいて、「写真撮影」は手間のかかる工程の1つです。 なぜなら、フォトグラメトリでは物体を様々なアングルで撮影する必要があるからです。 1、2つの物体を対象としている場合ならまだしも、小物を量産するなどで対象物体が何個もある場合は、撮影だけで非常に時間がかかってしまいます。 今回は、そんな撮影の手間を大幅に減らす方法を試してみました。 具体的な方法としては、「回転台を使って物体側を回転させる」というものです。 物体の方を回転させてしまえば、カメラは固定したまま様々なアングルで撮影することが出来ますので、簡単にハイクオリティな撮影が可能になります。 しかし、通常フォトグラメトリでは物体を静止させる必要があります。 理由としては、物体の位置・向きや背景情報を使って写真の撮影位置を推定しているからです。 物体の位置や向きが途中で変わってしまうと、背景情報との整合性が保てなくなり、位置推定が出来なくなってしまいます。 そこで、今回はグリーンバックを使用しました。 あらかじめ背景をグリーンバックで統一しておき、現像時にマスク化を行います。 これにより、対象物体の位置・向きのみを用いて撮影位置を推定させることが出来ます。 以下、その手順を説明していきます。 手順 写真撮影 RAW現像 マスク・切り抜き処理 モデル作成 使用機材 回転台 3DCGモデルを作成したい対象物体を載せる回転台です。 後に写真の回転台部分もマスク化処理をかけることを考えると、単色のものが望ましいです。 また、種類によって「プレートの大きさ」「耐荷重」「回転できる角度」などが異なります。 乗せる物体をある程度想定し、適切なものを購入しましょう。 参考までに、私達が所持している回転台のスペックを記載します。 プレートの大きさ:40cm 耐荷重:100kg 回転できる角度:0.1°~90° グリーンバック 回転台や対象物体の背景に設置するグリーンバックです。 グリーンバックは、なるべくシワや折り目がないようにしましょう。 (クロマキー合成をするわけではないので、過剰に気にする必要はないです) 私達の購入したグリーンバックは、購入時は折り目とシワがクッキリとついてしまっていました。 色々とシワ解消方法を試しましたが、衣類用のスチームアイロンを使用するのが最も効果的でした。 三脚 カメラを固定する用の三脚です。 今回はカメラを乗せて置いておくだけですので、ある程度の高さ調節機能があれば良いです。 1.写真撮影 まず初めに写真撮影を行います。 前述した通り、以下のように「カメラ/三脚」「対象物」「回転台」「グリーンバック」を配置しました。 三脚の最低高さが30㎝ほどあり、回転台を床に置くとかなり下向きな視点になってしまう為、ローテーブルの上に回転台を置いています。 上記の配置にて撮影した写真例を以下に示します。 ブログに載せる過程で画質が下がっておりますが、実際にはテーブルやグリーンバックまで鮮明に撮影しております。 回転台を用いた撮影では、 対象物と周囲の境界が明確になること を心がけました。 (今回は黒・白・緑で周囲が埋まる様にした) これにより、マスク処理を行う際に対象物が正確にマスクされやすくなります。(詳細は3章にて説明します) 今回は裏面も含めてモデル化を行いますので、対象物を裏返した状態でも撮影を行いました。 全て合計すると、230枚ほど撮影しています。(回転台は約7度ずつ回転) 以前、回転台を使わずに撮影した際は1時間以上かかりましたが、今回は 20分 ほどで撮影完了しました。 以上で、写真撮影は完了です。 2.RAW現像 次に、写真のRAW現像を行います。 今回は簡略化して紹介していますので、RAW現像に関する詳細な手順を知りたい方は こちらの記事 をご参照ください。 撮影した写真を Adobe Bridgeにて開き、ファイル名を一括変更します。 ファイル名を変更した写真を Adobe Lightroom で開き、 ヒストグラム を見ながら明暗・色味を調整して現像します。 RAW現像を行い、下記のようにJPG形式のファイルを生成しました。 3.マスク・切り抜き処理 写真のRAW現像が完了しましたら、マスク・切り抜き処理を行います。 なお、マスク・切り抜きには以下のアプリを使用します。 Adobe Photoshop (Win/ mac 対応 有料:1078円/月 ※2023年7月現在) まず初めに、 Adobe Photoshop を起動します。 起動しましたら、「ウィンドウ → アクション」でアクションウィンドウを表示させます。 アクションとは Photoshop の自動化ツールの1つです。 今回は、「RAW現像した写真からモデル化対象物のみを切り抜く処理」をアクションとして記録していきます。 アクションウィンドウが表示されましたら、「新規アクションを作成」を選択します。 アクションの設定画面が表示されますので、アクション名を入力して、アクションの記録を開始します。 今回は、「背景削除」と 命名 しました。 記録が開始されましたら、先ほどRAW現像したファイルの一つを開きます。 「ファイル → 開く」でファイル選択画面を表示し、RAW現像したファイルが格納されているフォルダから、1つ選択します。 (この1つは、上記フォルダ内のファイルであればどれでも大丈夫です) ファイルが開けましたら、「選択範囲 → 選択とマスク」を押下しマスク選択状態にします。 「被写体を選択」モードにした上で、画面上の被写体(モデル化の対象物)を左クリックします。 この際、被写体とその周辺の境界が曖昧ですと、被写体の選択範囲が正確に推定されないことがあります。 被写体の選択範囲が正確でない場合は、写真撮影をやり直すことが望ましいです。 (他の写真でも同様の事象が発生する可能性が高い為) 被写体が選択できましたら「出力設定 → 不要なカラーの除去」にチェックを入れ、「OK」を押してマスク選択を終了します。 「ファイル → コピーを保存」を選択し、RAW現像ファイルが格納されているフォルダと同じ ディレクト リに別フォルダを作成して保存します。ファイル形式は JPEG を選択します。 「保存」を押すと、 JPEG オプションが表示されます。今回は最高画質を選択しました。 保存が完了しましたら、アクションの記録を停止します。 これにて、「RAW現像した写真からモデル化対象物のみを切り抜く処理」をアクションとして記録できました。 記録したアクションを利用して、RAW現像したすべての写真に切り抜き処理を適用させます。 「ファイル → 自動処理 → バッチ」を選択します。 バッチでは、以下のように設定を行います。 アクション:背景削除(上記で記録したアクション) ソース:フォルダ ソースフォルダ選択:RAW現像した写真が格納されているフォルダ(Developed) "開く"コマンドを無視:ON 実行後:フォルダ 実行後フォルダ選択:アクション記録中に作成した別フォルダ(Masked) "別名で保存"コマンドを省略:ON 設定が完了しましたら、「OK」を押して自動処理が完了するまで待ちます。 約230枚の自動処理に 1時間30分 ほどかかりました。 自動処理が完了すると、以下のように対象物のみ切り抜かれたファイルが作成されています。 念のため、対象物が正確に切り抜かれていることを確認します。 下図のように不自然に白くなっている部分がある場合などは、手動で切り抜き処理をやり直します。 何度試しても上手く切り抜けない写真は、テクスチャ作成時に使用しないなどの対処を検討しましょう。 4.モデル作成 前章にてモデル化に必要な素材写真がそろいましたので、RealityCaptureを用いてモデル・テクスチャを作成します。 今回は簡略化して紹介していますので、モデル・テクスチャの作成に関する詳細な手順を知りたい方は こちらの記事 をご参照ください。 RealityCaptureを開き、対象物を切り抜いた写真が格納されているファイルを取り込みます。 続いて、アライメントを実行します。 アライメントの結果、2つの コンポーネント が作成されました。(所要時間:3分) これは、対象物の表面・裏面を両方撮影している為です。 このままでは表面・裏面のモデルがそれぞれ作成されてしまうので、コン トロール ポイントを用いて2つの コンポーネント をマージします。 コン トロール ポイントとは、写真や コンポーネント 上に目印となるポイントを設定できる機能です。 コンポーネント 間の共通ポイントをコン トロール ポイントとして指定することで、異なる コンポーネント をマージすることが出来ます。 まず、「IMAGE 2D → TOOLS → Add Control Points」を選択し、コン トロール ポイント設定状態にします。 コンポーネント 1にコン トロール ポイントを設定していきます。 画面上の点群から、コン トロール ポイントとして設定する点を左クリックします。 コン トロール ポイントの設定基準としては、以下を意識しましょう。 両方の コンポーネント に存在する点 対象物の中で特徴的な点(角部分や、色が変化している部分) 今回は、コン トロール ポイントを3点設定しました。 3次元の コンポーネント をマージすることを踏まえると、最低3点は設定することが望ましいです。 同様に、 コンポーネント 0にもコン トロール ポイントを設定します。 コンポーネント 1で設定したコン トロール ポイントと同じ部分を設定しましょう。 ( コンポーネント 間でコン トロール ポイントの位置が異なると、ズレた状態でマージされてしまいます) 次に、設定したコン トロール ポイントと各写真の位置推定結果に差がないことを検証します。 写真1枚ごとに「+」を押し、提案された全ての写真に対して検証を行いましょう。 検証結果に問題がない場合は、「アライメント → コンポーネント のマージ」から コンポーネント のマージを行います。 コンポーネント がマージされ、表面・裏面の両方が含まれる新規 コンポーネント が作成されました。 マージ時にズレが発生していないことを確認した後、「Mesh Model → High Detail」を選択しメッシュモデルを作成します。 メッシュモデルが作成できました。(所要時間:80分) 次に、「Mesh Model → Tecture」からテクスチャを作成します。 テクスチャが作成されました。(所要時間:20分) 以上で、3DCGモデルの作成完了です。 おわりに 本記事では、回転台とグリーンバッグを用いたお手軽フォトグラメトリ方法について紹介しました。 回転台を使った撮影方法と、通常の撮影方法における「写真撮影~現像などの後処理」までの所要時間は以下になります。 通常方式:写真撮影(約80分) + 後処理(約20分)= 約100分(人の作業時間:100分) 回転台方式:写真撮影(約20分) + 後処理(約20分+約90分)= 約130分(人の作業時間:40分) 回転台方式では撮影時間を短縮できる一方、 Photoshop での切り抜き処理に時間を要してしまい、合計所要時間では通常方式が早い結果となりました。 一方、通常の撮影方法では人が100分間作業し続ける必要があるのに対し、回転台方式では後処理の90分間を Photoshop が自動的に進めてくれます。人が作業する時間で考えると、回転台方式が圧倒的に早い結果となりました。 実際に運用する際は、 Photoshop での処理中に次の撮影を行うなど、時間を工夫して効率化を図ることが望ましいです。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ 参考文献 ・ 初歩からのフォトグラメトリ~RealityCaptureの使い方(ターンテーブル編) ・ フォトグラメトリによる3Dモデル作成ワークフロー(後編) ・ Adobe Photoshop 公式サイト ・ 最新版Photoshopの「選択とマスク」で画像を切り抜く方法 ・ Photoshopのアクション機能(自動処理)を使って複数の画像を一括編集する方法 ・ はじめてのRealityCapture - 完全なモデルを作成する手順 執筆: @matsuzaki.shota 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
みなさんこんにちは! ISID 金融ソリューション事業部の松崎です。 前回 の記事では、「フォトグラメトリによる3Dモデル作成ワークフロー(後編)」と題し、 フォトグラメトリで使用する写真撮影後の現像や加工手法、RealityCaptureを使ってのモデル作成方法について紹介しました。 まだご覧になっていない方は、是非読んでいただけると嬉しいです! 今回は、回転台とグリーンバックを使ったお手軽フォトグラメトリ方法を紹介します。 はじめに フォトグラメトリにおいて、「写真撮影」は手間のかかる工程の1つです。 なぜなら、フォトグラメトリでは物体を様々なアングルで撮影する必要があるからです。 1、2つの物体を対象としている場合ならまだしも、小物を量産するなどで対象物体が何個もある場合は、撮影だけで非常に時間がかかってしまいます。 今回は、そんな撮影の手間を大幅に減らす方法を試してみました。 具体的な方法としては、「回転台を使って物体側を回転させる」というものです。 物体の方を回転させてしまえば、カメラは固定したまま様々なアングルで撮影することが出来ますので、簡単にハイクオリティな撮影が可能になります。 しかし、通常フォトグラメトリでは物体を静止させる必要があります。 理由としては、物体の位置・向きや背景情報を使って写真の撮影位置を推定しているからです。 物体の位置や向きが途中で変わってしまうと、背景情報との整合性が保てなくなり、位置推定が出来なくなってしまいます。 そこで、今回はグリーンバックを使用しました。 あらかじめ背景をグリーンバックで統一しておき、現像時にマスク化を行います。 これにより、対象物体の位置・向きのみを用いて撮影位置を推定させることが出来ます。 以下、その手順を説明していきます。 手順 写真撮影 RAW現像 マスク・切り抜き処理 モデル作成 使用機材 回転台 3DCGモデルを作成したい対象物体を載せる回転台です。 後に写真の回転台部分もマスク化処理をかけることを考えると、単色のものが望ましいです。 また、種類によって「プレートの大きさ」「耐荷重」「回転できる角度」などが異なります。 乗せる物体をある程度想定し、適切なものを購入しましょう。 参考までに、私達が所持している回転台のスペックを記載します。 プレートの大きさ:40cm 耐荷重:100kg 回転できる角度:0.1°~90° グリーンバック 回転台や対象物体の背景に設置するグリーンバックです。 グリーンバックは、なるべくシワや折り目がないようにしましょう。 (クロマキー合成をするわけではないので、過剰に気にする必要はないです) 私達の購入したグリーンバックは、購入時は折り目とシワがクッキリとついてしまっていました。 色々とシワ解消方法を試しましたが、衣類用のスチームアイロンを使用するのが最も効果的でした。 三脚 カメラを固定する用の三脚です。 今回はカメラを乗せて置いておくだけですので、ある程度の高さ調節機能があれば良いです。 1.写真撮影 まず初めに写真撮影を行います。 前述した通り、以下のように「カメラ/三脚」「対象物」「回転台」「グリーンバック」を配置しました。 三脚の最低高さが30㎝ほどあり、回転台を床に置くとかなり下向きな視点になってしまう為、ローテーブルの上に回転台を置いています。 上記の配置にて撮影した写真例を以下に示します。 ブログに載せる過程で画質が下がっておりますが、実際にはテーブルやグリーンバックまで鮮明に撮影しております。 回転台を用いた撮影では、 対象物と周囲の境界が明確になること を心がけました。 (今回は黒・白・緑で周囲が埋まる様にした) これにより、マスク処理を行う際に対象物が正確にマスクされやすくなります。(詳細は3章にて説明します) 今回は裏面も含めてモデル化を行いますので、対象物を裏返した状態でも撮影を行いました。 全て合計すると、230枚ほど撮影しています。(回転台は約7度ずつ回転) 以前、回転台を使わずに撮影した際は1時間以上かかりましたが、今回は 20分 ほどで撮影完了しました。 以上で、写真撮影は完了です。 2.RAW現像 次に、写真のRAW現像を行います。 今回は簡略化して紹介していますので、RAW現像に関する詳細な手順を知りたい方は こちらの記事 をご参照ください。 撮影した写真を Adobe Bridgeにて開き、ファイル名を一括変更します。 ファイル名を変更した写真を Adobe Lightroom で開き、 ヒストグラム を見ながら明暗・色味を調整して現像します。 RAW現像を行い、下記のようにJPG形式のファイルを生成しました。 3.マスク・切り抜き処理 写真のRAW現像が完了しましたら、マスク・切り抜き処理を行います。 なお、マスク・切り抜きには以下のアプリを使用します。 Adobe Photoshop (Win/ mac 対応 有料:1078円/月 ※2023年7月現在) まず初めに、 Adobe Photoshop を起動します。 起動しましたら、「ウィンドウ → アクション」でアクションウィンドウを表示させます。 アクションとは Photoshop の自動化ツールの1つです。 今回は、「RAW現像した写真からモデル化対象物のみを切り抜く処理」をアクションとして記録していきます。 アクションウィンドウが表示されましたら、「新規アクションを作成」を選択します。 アクションの設定画面が表示されますので、アクション名を入力して、アクションの記録を開始します。 今回は、「背景削除」と 命名 しました。 記録が開始されましたら、先ほどRAW現像したファイルの一つを開きます。 「ファイル → 開く」でファイル選択画面を表示し、RAW現像したファイルが格納されているフォルダから、1つ選択します。 (この1つは、上記フォルダ内のファイルであればどれでも大丈夫です) ファイルが開けましたら、「選択範囲 → 選択とマスク」を押下しマスク選択状態にします。 「被写体を選択」モードにした上で、画面上の被写体(モデル化の対象物)を左クリックします。 この際、被写体とその周辺の境界が曖昧ですと、被写体の選択範囲が正確に推定されないことがあります。 被写体の選択範囲が正確でない場合は、写真撮影をやり直すことが望ましいです。 (他の写真でも同様の事象が発生する可能性が高い為) 被写体が選択できましたら「出力設定 → 不要なカラーの除去」にチェックを入れ、「OK」を押してマスク選択を終了します。 「ファイル → コピーを保存」を選択し、RAW現像ファイルが格納されているフォルダと同じ ディレクト リに別フォルダを作成して保存します。ファイル形式は JPEG を選択します。 「保存」を押すと、 JPEG オプションが表示されます。今回は最高画質を選択しました。 保存が完了しましたら、アクションの記録を停止します。 これにて、「RAW現像した写真からモデル化対象物のみを切り抜く処理」をアクションとして記録できました。 記録したアクションを利用して、RAW現像したすべての写真に切り抜き処理を適用させます。 「ファイル → 自動処理 → バッチ」を選択します。 バッチでは、以下のように設定を行います。 アクション:背景削除(上記で記録したアクション) ソース:フォルダ ソースフォルダ選択:RAW現像した写真が格納されているフォルダ(Developed) "開く"コマンドを無視:ON 実行後:フォルダ 実行後フォルダ選択:アクション記録中に作成した別フォルダ(Masked) "別名で保存"コマンドを省略:ON 設定が完了しましたら、「OK」を押して自動処理が完了するまで待ちます。 約230枚の自動処理に 1時間30分 ほどかかりました。 自動処理が完了すると、以下のように対象物のみ切り抜かれたファイルが作成されています。 念のため、対象物が正確に切り抜かれていることを確認します。 下図のように不自然に白くなっている部分がある場合などは、手動で切り抜き処理をやり直します。 何度試しても上手く切り抜けない写真は、テクスチャ作成時に使用しないなどの対処を検討しましょう。 4.モデル作成 前章にてモデル化に必要な素材写真がそろいましたので、RealityCaptureを用いてモデル・テクスチャを作成します。 今回は簡略化して紹介していますので、モデル・テクスチャの作成に関する詳細な手順を知りたい方は こちらの記事 をご参照ください。 RealityCaptureを開き、対象物を切り抜いた写真が格納されているファイルを取り込みます。 続いて、アライメントを実行します。 アライメントの結果、2つの コンポーネント が作成されました。(所要時間:3分) これは、対象物の表面・裏面を両方撮影している為です。 このままでは表面・裏面のモデルがそれぞれ作成されてしまうので、コン トロール ポイントを用いて2つの コンポーネント をマージします。 コン トロール ポイントとは、写真や コンポーネント 上に目印となるポイントを設定できる機能です。 コンポーネント 間の共通ポイントをコン トロール ポイントとして指定することで、異なる コンポーネント をマージすることが出来ます。 まず、「IMAGE 2D → TOOLS → Add Control Points」を選択し、コン トロール ポイント設定状態にします。 コンポーネント 1にコン トロール ポイントを設定していきます。 画面上の点群から、コン トロール ポイントとして設定する点を左クリックします。 コン トロール ポイントの設定基準としては、以下を意識しましょう。 両方の コンポーネント に存在する点 対象物の中で特徴的な点(角部分や、色が変化している部分) 今回は、コン トロール ポイントを3点設定しました。 3次元の コンポーネント をマージすることを踏まえると、最低3点は設定することが望ましいです。 同様に、 コンポーネント 0にもコン トロール ポイントを設定します。 コンポーネント 1で設定したコン トロール ポイントと同じ部分を設定しましょう。 ( コンポーネント 間でコン トロール ポイントの位置が異なると、ズレた状態でマージされてしまいます) 次に、設定したコン トロール ポイントと各写真の位置推定結果に差がないことを検証します。 写真1枚ごとに「+」を押し、提案された全ての写真に対して検証を行いましょう。 検証結果に問題がない場合は、「アライメント → コンポーネント のマージ」から コンポーネント のマージを行います。 コンポーネント がマージされ、表面・裏面の両方が含まれる新規 コンポーネント が作成されました。 マージ時にズレが発生していないことを確認した後、「Mesh Model → High Detail」を選択しメッシュモデルを作成します。 メッシュモデルが作成できました。(所要時間:80分) 次に、「Mesh Model → Tecture」からテクスチャを作成します。 テクスチャが作成されました。(所要時間:20分) 以上で、3DCGモデルの作成完了です。 おわりに 本記事では、回転台とグリーンバッグを用いたお手軽フォトグラメトリ方法について紹介しました。 回転台を使った撮影方法と、通常の撮影方法における「写真撮影~現像などの後処理」までの所要時間は以下になります。 通常方式:写真撮影(約80分) + 後処理(約20分)= 約100分(人の作業時間:100分) 回転台方式:写真撮影(約20分) + 後処理(約20分+約90分)= 約130分(人の作業時間:40分) 回転台方式では撮影時間を短縮できる一方、 Photoshop での切り抜き処理に時間を要してしまい、合計所要時間では通常方式が早い結果となりました。 一方、通常の撮影方法では人が100分間作業し続ける必要があるのに対し、回転台方式では後処理の90分間を Photoshop が自動的に進めてくれます。人が作業する時間で考えると、回転台方式が圧倒的に早い結果となりました。 実際に運用する際は、 Photoshop での処理中に次の撮影を行うなど、時間を工夫して効率化を図ることが望ましいです。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ 参考文献 ・ 初歩からのフォトグラメトリ~RealityCaptureの使い方(ターンテーブル編) ・ フォトグラメトリによる3Dモデル作成ワークフロー(後編) ・ Adobe Photoshop 公式サイト ・ 最新版Photoshopの「選択とマスク」で画像を切り抜く方法 ・ Photoshopのアクション機能(自動処理)を使って複数の画像を一括編集する方法 ・ はじめてのRealityCapture - 完全なモデルを作成する手順 執筆: @matsuzaki.shota 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター