TECH PLAY

SCSKクラウドソリューション

SCSKクラウドソリューション の技術ブログ

1268

こんにちは、SCSK株式会社の谷です。 前回、新たに私たちの部署に新入社員として加わった嶋谷さんが、 Mackerel を使ってAWS環境のDocker情報を可視化する方法と結果 についての記事を掲載しました。 ご覧になっていない方は、ぜひ目を通してみてください。 Mackerel で Docker を監視してみた – TechHarmony 今回は、MackerelにてAWSのサーバーレスサービスを監視し可視化しました。 監視対象のシステムについて 今回の検証のため、AWSが提供しているハンズオンから簡易的なWebアプリを構築しました。 名前を入力しボタンを選択すると、「Hello from Lambda」で始まり入力したテキストが続くメッセージが表示されるWebアプリです。 Webアプリの構成は以下の図になります。   構成しているサービスの中で今回は以下を使用して検証をしました。 Amazon DynamoDB    完全マネージド型の NoSQL データベースサービス Amazon API Gateway   APIの作成および管理を簡単に行えるフルマネージドサービス AWS Lambda        サーバーレスコンピューティングサービス 上記環境の構築手順について、この記事では説明を省略させていただきます。 詳しく知りたい方は、以下に詳細な構築手順が載っていますので、こちらをご覧ください。 AWS で基本的なウェブアプリケーションを構築する Mackerelでの監視設定手順 ここではMackerelで各サービスを監視するための設定手順について記載しています。 設定手順の詳細につきましては、Mackerel公式ヘルプをご参照ください。 AWSインテグレーション – Mackerel ヘルプ 設定手順について興味のない方は、このパートはスキップして「 Mackerel上で監視データの確認 」のパートに飛んでください。 インテグレーション用のIAMロールの作成 (1) Mackerelの管理画面で「オーガニゼーション名」>「AWSインテグレーション」をクリックする。 (2)「新しいAWSインテグレーションを登録」というボタンが表示されるため、それをクリックする。 (3) 基本設定>AWSアカウント 外部IDをコピーする。 (4) AWSのコンソールにログインし、左上の検索バーで「IAM」と入力し、エンターを押す。 (5) 左側のタブからロールを選択し、「ロールを作成」をクリックする。 (6) 以下に沿って入力し、すべて入力後、「次へ」をクリックする。 信頼されたエンティティタイプ : AWSアカウント AWSアカウント         : 別のAWSアカウント アカウントID                        : 217452466226(共通) オプション          : 外部IDを要求する (7) 今回はLambda、API Gateway、DynamoDBを監視したいため、それらに関するReadOnlyロールを選択し、「次へ」をクリックする。 (8) ロール名と説明を適宜入力し、「ロールを作成」をクリックする。 (9) 作成したロールの詳細画面で表示される、ARNをコピーする。 AWSインテグレーションの作成 (1) Mackerelの管理画面に戻り、先ほど開いた「新しいAWSインテグレーションを登録」画面を開く。   そこで、名前の入力とリージョンの選択を行い、ロールARNの欄に先ほどコピーしたARNを貼り付ける。 (2) メトリックを収集するサービスで、Lambda、API Gateway、DynamoDBを選択する。   他の取得可能なサービスにつきましては以下の公式ヘルプの「 対応しているクラウド製品 」を参照ください。       AWSインテグレーション – Mackerel ヘルプ (3) 「タグを指定して登録するホストを絞り込む」にて連携したいリソースのタグ、除外したいタグを入力する。 (4)「作成」をクリックする。 これで、インテグレーションが作成できました! 連携確認 以上で設定は完了です。 ここからは、監視設定を入れたサービスの状態を見てみましょう。 ここまでの手順が完了すると、Mackerelの管理画面の「ホスト」のところですぐに確認することができます。 このように、Lambda、API Gateway、DynamoDBの3つのデータが取れていることがわかります。 Mackerel上で監視データの確認 設定作業はいかがでしたか? 思っていたより簡単に監視ができると感じた方が多いのではないでしょうか。 では、ここからはAWSから連携された監視データがどのように見えているかを、サービスごとに一部抜粋してお見せしたいと思います。 API Gateway MackerelではリソースごとにAPI Gatewayを監視することができます。 API Gatewayでは、基本的に以下のメトリックを取得できます。 詳細はMackerel公式ヘルプをご参照ください。 AWSインテグレーション – API Gateway – Mackerel ヘルプ グラフ名 メトリック 説明 Requests Count 指定期間内のAPIリクエストの合計数 Errors 4XXError クライアント側のエラー数 5XXError サーバー側のエラー数 Cache CacheHitCount APIキャッシュから提供されたリクエストの数 CacheMissCount バックエンドから提供されたリクエストの数 Latency Latency クライアントからリクエストを受け取ってからレスポンスを返すまでの時間 IntegrationLatency バックエンドにリクエストを中継してからレスポンスを受け取るまでの時間 今回は、この中のRequestsのグラフをお見せします。 こちらのグラフは、APIのリクエスト数を可視化したグラフになります。 このデータを見れば、どのタイミングでリクエスト数が増えているかを視覚的に確認することができます。 DynamoDB MackerelではDBリソースごとにをDynamoDBを監視することができます。 DynamoDBでは、基本的に以下のメトリックを取得できます。 詳細はMackerel公式ヘルプをご参照ください。 AWSインテグレーション – DynamoDB – Mackerel ヘルプ グラフ名 メトリック 説明 ReadCapacityUnits ProvisionedReadCapacityUnits プロビジョンドされた読み取りキャパシティユニットの数 ConsumedReadCapacityUnits 読み取り操作で消費されたキャパシティユニットの数 WriteCapacityUnits ProvisionedWriteCapacityUnits プロビジョンドされた書き込みキャパシティユニットの数。 ConsumedWriteCapacityUnits 書き込み操作で消費されたキャパシティユニットの数 Requests ConditionalCheckFailedRequests 条件付き書き込みや更新操作が失敗したリクエストの数 SuccessfulRequestLatency 成功したリクエストのレイテンシー ThrottledRequests スロットルされたリクエストの総数 UserErrors ユーザーによって引き起こされたエラーの数 SystemErrors DynamoDB内部で発生したシステムエラーの数 ThrottleEvents ReadThrottleEvents 読み取り操作がスロットルされた回数 WriteThrottleEvents 書き込み操作がスロットルされた回数 TimeToLiveDeletedItemCount TimeToLiveDeletedItemCount TTL機能によって削除されたアイテムの数 SuccessfulRequestLatency SuccessfulRequestLatency 成功したリクエストのレイテンシー ReturnedItemCount ReturnedItemCount クエリやスキャン操作で返されたアイテムの数 RequestCount ReturnedItemCount クエリやスキャン操作で返されたアイテムの数 TransactionConflict TransactionConflict トランザクションの競合が発生した回数 今回は、この中のWriteCapacityUnitsグラフをお見せします。 こちらのグラフは、DynamoDBへの書き込みで消費されたキャパシティユニット数を示したグラフになっています。 このデータを見ることで、キャパシティを超えるような書き込みが行われていないかを視覚的に確認することができます。 Lambda Mackerelでは関数単位ごとにLambdaを監視することができます。 Lambdaでは、基本的に以下のメトリックを取得できます。 詳細はMackerel公式ヘルプをご参照ください。 AWSインテグレーション – Lambda – Mackerel ヘルプ グラフ名 メトリック 説明 Count Invocations 関数が呼び出された回数 Errors 関数の実行中に発生したエラーの数 DeadLetterErrors デッドレターキューへの送信失敗回数 Throttles スロットルされた呼び出しの数 Duration [ms] Duration 関数の実行時間 Iterator Age [ms] IteratorAge ストリームイベントの処理遅延時間   今回はエラーが分かりやすいようにCountグラフをお見せします。 こちらのグラフは、Lambdaの実行回数(invocations)とエラー回数(errors)を示したグラフになっています。 エラーをグラフ上に表示させるため、14:15頃から LambdaからDynamoDBへの書き込み権限ロールを一時的に削除しました 。 このデータを見れば、いつどのタイミングでエラーが発生し始めたのかを視覚的に確認することができます。 今回ご紹介したグラフはそれぞれ1つずつでしたが、かんたんなカスタムをすれば様々なグラフを作成することも可能です。 興味がある方はぜひ調べてみてください。 終わりに 記事の内容は以上になります。いかがでしたでしょうか。 今回初めてMackerelにて監視設定をいれたのですが、UIも直感的で操作しやすくスムーズに設定を入れることができました! また、公式ドキュメントも豊富でしたので、疑問点や不明点を解決しやすいところも非常にやりやすかったです。 また、Amazon CloudWatchだと少し手間だと感じていましたが、 設定したいメトリクスを簡単に複数まとめて設定できる ところがMackerelの優れている点だと今回設定してみて感じました。 もう少しMackerelを触ってみようと思いますので、また何か気づきがありましたら記事を掲載します。 最後までお付き合いいただき、ありがとうございました。
はじめに 今回は今年の1月にリリースされたアクションプランという機能の説明と使い方を書いていきます。 アクションプランとは アクションプランとは、リスクのあるリソースが一覧化されており、そのリソースに対し最小限のアクションでリスク軽減をできるように調整された効果的な修復手順を提供し、クラウドリソースの保護に役立てることができます。 アクションプランの使い方 ここからはアクションプランの使い方について解説していきます。 アクションプラン担当者の割り振り Prisma Cloud コンソールにログインします。 このとき「System Admin」でログインしていることを確認します。 上のバーから「アクションプラン」を押下します。 以下画像のように遷移します。 各アクションプランには人を割り当てることもできます。 赤線部分の「Unassigned」部分を押下し、担当する人を選択することができます。 担当者を設定した後に「Assigned to me」を押下する自分がどのアクションプランを担当するか確認することができます。 フィルターの「譲受人」の部分でほかの人が担当するアクションプランを確認することもできます。 逆に担当者が割り当てられていないものは「Unassigned Action Plans」から確認することができます。   アクションプランを解決する場合 Prisma Cloud コンソールにログインします。 このとき「System Admin」でログインしていることを確認します。 上のバーから「アクションプラン」を押下します。 以下画像のように遷移します。 対象のアクションプランを押下して展開すると、対象のアクションプランのプライマリアセットと概要、その影響がとがでてきます。 「プライマリアセット」はどのリソースが対象なのか表示されています。 「概要」は影響を受けるリソースの概要の説明が表示されています。 「影響」は攻撃パス、アラート、脆弱性が表示されています。 展開後、「修正方法」を押下すると解決方法の手順が出てくるので手順実行して修正完了です。 ※修正方法に記載がありますが、「大規模な言語モデルやその他の生成AIを活用する場合があり、エラーが含まれる場合があります。」ということなので注意が必要です さいごに アクションプランを使用して簡単にクラウドリソースのリスクを減らせるようになったのでとても良い機能だと思います。 当社では、複数クラウド環境の設定状況を自動でチェックし、設定ミスやコンプライアンス違反、異常行動などのリスクを診断するCSPMソリューションを販売しております。 マルチクラウド設定診断サービス with CSPM| SCSK株式会社 CSPM | Smart One Cloud Security® Powered by Prisma Cloud from Palo Alto Networks | SCSK株式会社 ご興味のある方は是非、お気軽にお問い合わせください。
社内開催の AWS GameDay に参加してきました。AWSのワークショップ形式のイベントは初参加です! 興味はありましたが、普段の案件はWeb/APのインフラ構築案件が多く、使うサービスややり方がほぼ固定で、 参加したは良いけど全然出来なかったらどうしよう、知らないサービスばっかりだったらどうしようと思い、尻込みしていました。 今回社内メンバーのみ、初心者向けの難易度ということで、これを逃したら二度と参加出来る気がしないと思い参加してみました。 自分について 普段はクラウドのインフラ構築案件をしています。 最近はGoogle CloudやAzure案件をやっていますが、5年ほどAWS案件をやっていました。 リーダとして管理や調整が多くなってきており、実際にコードを書いたり画面を触ってどうするみたいなところは時間が取れなくなってきています。 AWS re:Invent 等のスライドを見るようなものには何度か参加したことがありますが、ワークショップ形式は未経験です。 資格はAWS SAP、DOP、SCSを所有しています。   GameDay 概要 実施内容の詳細は公開NGとのことだったのでざっくりとした内容のみです。詳細は実際に参加する際のお楽しみに!とのことでした。 今回は社内のみの個人申し込みで運営の方が3-4人のチームを組んでくれました。 チームでAWS上に作られた仮のシステムで発生している様々な問題を解消していきます。 解消した内容に応じて決められたポイントが入り、その合計点で争うチーム戦です。 問題はある程度道筋を立てられるような流れになっていました。問題文を読んで原因を考え、調査して問題解決を目指していきます。   良かった点 普段の業務ではやらないやり方や使わないサービスの問題もありました。資格勉強で文字しか見ていないようなものを実際に触ってみることが出来てよかったです。 資格取得時に「なんとなくサービスは知っている、そういうことが出来ることは知っている」という知識も意外と役に立ちます。 メンバーによって得意不得意がある中で、「この問題を解きます」「ここどうする???」といった会話をして取り組む問題を決めたりサポートをするところがチームでやっている感があり楽しかったです。 単純に楽しい。私は自分責ではないトラブルを対応するのが大好きなので、今回のGameDayはすごく楽しかったです。   気になった点 初参加なのもあり、楽しかったのであまり気になる点はありませんでしたが 一点だけ申し込み前の葛藤がネックになるのかなあと思いました。 申込時の難易度が不明 自分のレベルと取り組む問題のレベル感がなかなか分かりにくいと思いました。私も今回始まるまでずっとドキドキしていました。 意外と何とかなったのと、いくら悩んでも参加するまでやっぱり分からないのでとりあえず一度参加してみるのがよいと思いました。 今回はアプリ開発レベルのプログラミング知識は不要で、インフラで多少スクリプトの経験があるようなレベル感で十分でした。   ちょっとしたコツ 問題文はよく読むこと! どういうサービスを使うのか、既に用意済みのリソースは何か、作り方に指定は無いか 解くためのヒントが問題文にもあります。 なんでクリアにならないんだろうか?と思ったときに問題文をゆっくり読んでみたらすぐ解決みたいなこともありました。   感想 今回なんとチームの順位が2位でした。4人チームが多い中、3人チームだったのにすごい! 自分が担当した問題の解決順はそこまで早くなかったのですが、他の方がめちゃ早で凄かったです。 知識としては知っているが、いざやってみると細かいやり方が分からない、勘違いをしていたといった点にも気づけました。 是非次は社外イベント等含めワークショップ形式のものに参加してみたいと思います! 2位賞品&参加賞としてAWS保冷バッグ&ステッカーもらいました!
今回は、Prisma CloudのInvestigate機能を利用して、特定の条件に一致するリソースを検索する方法を解説していきます。 Prisma Cloud の Investigate(調査)機能 Prisma CloudのInvestigate(調査)機能を使用すると、シンプルで直感的なインターフェースでクエリを発行することができ、要件にあわせた検索をすることが可能です。Prisma Cloudで発行されるクエリはRQLと呼ばれ、Prisma Cloud独自のものとなっています。 検索方法は、大きく分けると以下の3つがあります。 ① 探したい条件を入力すると表示されるAI支援の提案からクエリを選択して検索する ② クエリの条件をコンソール画面に表示されるフィルター機能で指定して検索する ③ 検索欄にRQL文を直接入力して検索する 今回は上記3つの方法をそれぞれ説明していきます。   検索してみる 今回は分かりやすい例として、「パブリックIPを持っているEC2」をそれぞれの方法で検索してみたいと思います。 AI支援を利用した検索 Prisma Cloudコンソールの調査タブを表示すると、右側に「AI支援が有効」と表示されている検索欄(以下画像参照)が出てきます。 ここに「パブリックIPを持っているEC2」と入力してみます。 すると以下のように、AIによって入力内容に当てはまりそうなクエリが選択肢として表示されてきます。 「AWS EC2 instance is assigned with public IP_RL」という名前のクエリが今回検索したい内容に一致しそうなのでクリックすると、自動でRQL文が入力され、接続しているクラウドアカウント上に存在するパブリックIPを持ったEC2の一覧が表示されます。   フィルタ機能を利用した検索 Prisma Cloudコンソールの調査タブを表示すると、「+クエリの種類を選択してください」というフィルターが表示されます。クエリには以下のような種類があり、その中から要件に当てはまるものを選択します。 クエリタイプ 概要 RQL文の形式 サポートしているモード アセット 包括的なセキュリティコンテキストを含むすべてのクラウドアセットを表示 ー シンプル 設定 クラウド API と JSON ルールに基づいて構成ファイルを検索 “config from cloud.resource where”から始まる シンプル・上級 脆弱性 お使いの環境内で発見された主な脆弱性を調査 ー シンプル ネットワーク設定 ネットワークパスを探索し、インターネットに公開されているアセットを特定 config from network where”から始まる 上級 ネットワークフローログ ネットワークフローログを調査して、インシデントや脅威の検出と調査を行う network from vpc.flow_record where”から始まる 上級 監査イベント 調査とフォレンジックのために監査ログを探索 event from cloud.audit_logs where”から始まる 上級 アプリケーションアセット ソフトウェアデリバリーチェーンとエンジニアリングのアタックサーフェスを調査 ー シンプル 許可(IAM) 取り込まれた IAM ポリシーに基づいてネット リソースのアクセス許可を表示 “config from iam where”から始まる 上級 今回は「パブリックIPを持っている」という”設定”に当てはまるEC2を検索したいので、「設定」を選択します。 検索対象とする期間を選びます。「+追加」をクリックするとフィルタ条件を追加できます。 今回はEC2の設定情報(パブリックIPを持っているかどうか)を条件にしたいので、EC2インスタンスの情報を参照するAPIを指定します。 条件とする詳細な設定値は「JSONルール」フィルターを利用して指定していきます。 JSONルールを選択すると以下のように実際のJSON形式で設定項目が表示されるので、条件にしたい設定項目をクリックします。今回はパブリックIPの値が入る項目をクリックしました。 指定した項目がどのようになっていたら検知するかを指定します。 今回は「publicIP」の項目が存在する=パブリックIPを持っている※ということを検知の条件にしたいので、「exists」を選択しました。 その他の選択肢については、Prisma Cloudの公式ドキュメント( RQL演算子 )を参照ください。 ※パブリックIPがないEC2のJSONにはそもそも「publicIP」の項目がありません 条件を指定できたら「検索」をクリックします。パブリックIPを持ったEC2の一覧が表示されます。   RQL文を直接編集して検索 フィルタ機能を利用した検索の説明で紹介したクエリタイプで、サポートされているモードに「上級」が含まれているクエリタイプの場合は、検索欄にRQL文を直接入力して検索することができます。 「設定」クエリタイプは「上級」モードをサポートしているので実際に試してみます。 PrismaCloudコンソールの「調査」タブを表示し、「+クエリの種類を選択してください」をクリックして「設定」を選択します。 すると、右側に「シンプル」と「上級」を選択できる箇所が出てくるので、「上級」を選択します。 「config from~」から始まるRQL文を入力できる欄が出てきたので、以降のRQL文を入力していきます。 直接テキストを入力していくことも可能ですし、入力しようとすると選択肢が表示されるのでそこから選択してRQLを作成することも可能です。 RQL文が文法的に問題なく検索できる状態まで入力すると、RQLの左横にあるアイコンが緑色に変わります。 緑色になっていることを確認して「検索」をクリックします。 パブリックIPを持ったEC2の一覧が表示されます。   まとめ Prisma CloudのInvestigate(調査)機能を利用して検索をかける方法を3つご紹介しました。調査機能を利用することで、特定の条件に一致するリソースの一覧を簡単に作成できます。また、Prisma Cloudのポリシーはクエリ(RQL)を利用しているため、個々の環境の要件に合わせたカスタムポリシー作成する際にも参考になるかと思います。調査機能を有効活用して、セキュリティとコンプライアンスの強化に役立てましょう。 今後も、Prisma Cloud の活用方法について実用的な情報をお届けできればと思います。 また、当社では、複数クラウド環境の設定状況を自動でチェックし、設定ミスやコンプライアンス違反、異常行動などのリスクを診断するCSPMソリューションを販売しております。 マルチクラウド設定診断サービス with CSPM| SCSK株式会社 マルチクラウド環境のセキュリティ設定リスクを手軽に確認可能なスポット診断サービスです。独自の診断レポートが、運用上の設定ミスや設計不備、クラウド環境の仕様変更などで発生し得る問題を可視化し、セキュリティインシデントの早期発見に役立ちます。 www.scsk.jp ご興味のある方は是非、お気軽にお問い合わせください。
SCSKの畑です。 2個前のエントリ で少し言及した通り、外部公開されるサービスの AWS WAF 設定でハマった話について記載します。 アーキテクチャ図 いつものやつです。今回は AWS WAF 設定に関連する内容ということで、対象は以下構成において外部からアクセス可能なサービスとなる、Amazon CloudFront、Amazon Cognito、AWS AppSync の3つです。   背景 さて、その 2個前のエントリ において、お客さんの環境ポリシーにより CloudFront に AWS WAF を設定する必要があったことを取り上げました。本アプリケーションはインターネット上に公開せず、アクセスできるネットワーク/IP アドレスのレンジを限定する必要があったためですが、アーキテクチャ図の通り Cognito ユーザプール及び AppSync の GraphQL API エンドポイントについても同様にクライアント端末からアクセスすることになるため、AWS WAF を設定する必要がありました。 それらのサービスについても外部からアクセスしてくるのは同じようにクライアント端末の属するネットワークであるため、CloudFront と同じような AWS WAF 設定をすれば良いと考え、お客さんにその旨依頼していたのですが・・   エラー発生(AppSync) お客さんの AWS 環境にアプリケーション一式を移行して動作確認を行っていたところ、バックエンド用 Lambda 処理を伴うクライアント処理時に以下のようなエラーが出力されました。(汎用エラー表示用コンポーネント上での扱いから JSON 形式です) { message: 'Connection failed: {"errors":[{"errorType":"WAFForbiddenException","message":"403 Forbidden" } クライアント端末上のアプリケーションから Lambda を介さない AppSync API は実行できていたため当初はちょっと戸惑ったものの、errorType の通り WAF でアクセス拒否されていることは分かったので、先述の通りクライアント端末以外からのアクセスを許可していない WAF 設定が怪しいことにすぐ思い至りました。確かに Lambda も クライアント端末上のアプリケーションも、AppSync の GraphQL API エンドポイントにアクセスする立場は同じなので、バックエンド用 Lambda についてもクライアント端末と同様に AWS WAF でのアクセス許可が必要なのではないか?という(その時点での)推測です。 バックエンド用 Lambda がエラーで正常動作しない以上、アプリケーションの移行や動作確認も進まないことと同義であるため、いの一番に対応しました。解決策については Cognito 側と全く同じなので後述します。   エラー発生(Cognito ユーザプール) 一方、Cognito ユーザプールについては、バックエンド用 Lambda から boto3 経由でアクセスする処理が正常に動作していたこと、アプリケーションの一連の動作確認でもユーザ認証部分は特に問題がなかったことの2点から、当初はあまり深く理由を考えないまま大丈夫なのかな?と考えていたのですが・・ たまたま違う日に Web ブラウザ上で開いているアプリケーション(ログイン中)をリロードしたところ、TOP ページにリダイレクトしてしまう事象が発生しました。弊社の AWS 環境では事象が再現しなかったためお客さんの AWS 環境の問題と考え、当初は CloudFront や AWS WAF の設定あたりに問題があると考えたのですが、特に原因となるような設定はありませんでした。また、ブラウザのコンソール上にも特にエラーメッセージは表示されていませんでした。 そこで改めて TOP ページへのリダイレクト履歴を Web ブラウザから追いかけたところ (リロードした時点のページ) ⇒ /login(ログイン後の初期処理ページ) ⇒ /(TOPページ) という順番でリダイレクトしていることが分かりました。アプリケーション側のルーティングロジックの詳細は 過去のエントリ で記載していますが、簡単に整理すると /login へのリダイレクト: Cognito ユーザ未認証の場合のリダイレクトパターン / へのリダイレクト: Cognito ユーザ認証済みのリダイレクトパターン となります。 つまり、上記のルーティングロジックに従うと、リロードした時点では Cognito ユーザ未認証と判定されているものの、Cognito ユーザ認証自体は完了しているため / へリダイレクトされる時点では Cognito ユーザ認証済みと判定されていることになります。Nuxt3 によるルーティングはサーバ側でも処理されるため、フロントエンド側の Lambda で Cognito ユーザ未認証とみなされているのではないかと推測しました。そこで、アプリケーションをデプロイした CloudFront  配下のフロントエンド用 Lambda のログを CloudWatch から見てみると・・ 2025-02-18T06:41:20.957Z  9dd22dc5-039f-45ee-86f6-b3ce9230ec0a  INFO  ForbiddenException: Request not allowed due to WAF block.   at file:///var/task/.output/server/node_modules/@aws-amplify/auth/dist/esm/foundation/factories/serviceClients/cognitoIdentityProvider/shared/serde/createUserPoolDeserializer.mjs:11:15   at process.processTicksAndRejections (node:internal/process/task_queues:105:5)   at async fetchUserAttributes (file:///var/task/.output/server/node_modules/@aws-amplify/auth/dist/esm/providers/cognito/apis/internal/fetchUserAttributes.mjs:31:32)   at async runWithAmplifyServerContext (file:///var/task/.output/server/node_modules/aws-amplify/dist/esm/adapter-core/runWithAmplifyServerContext.mjs:20:24)   at async useUserInfo (file:///var/task/.output/server/chunks/build/server.mjs:7155:26)   at async file:///var/task/.output/server/chunks/build/server.mjs:7526:113   at async Object.callAsync (file:///var/task/.output/server/chunks/nitro/nitro.mjs:5850:16)   at async file:///var/task/.output/server/chunks/build/server.mjs:7733:26 { underlyingError: undefined, recoverySuggestion: undefined, constructor: [class AuthError extends AmplifyError] } 1行目にそのものズバリなメッセージ「ForbiddenException: Request not allowed due to WAF block.」が出ている通り、フロントエンド側の Lambda から Cognito ユーザプールへのアクセスが WAF によりブロックされていたことが分かりました。 過去のエントリ に記載している middleware のコード通り、Cognito ユーザ認証されない場合も今回のように WAF でブロックされた場合も同じように例外を catch して /login にリダイレクトしているので、このような挙動になったということになります。 余談ですが、この原因の切り分けもといデバッグにはそこそこ時間を要しました。フロントエンド側 Lambda の CloudWatchLog を見なければいけないというところに思考が至るまでに時間がかかってしまったのが原因です。 普段 Nuxt3 の開発をローカルで実施している時はフレームワーク側が気を利かせてくれて、ローカルで立てている開発用サーバ側のログも Web ブラウザのコンソールで出してくれたりするんですよね。しばらくその感覚でいたので、本来 /login にリダイレクトした際に上記のようなエラーが出ると思っていたのが出なかったこともあり、このロジック以外でリダイレクトしてしまうようなことがあり得るのか?みたいなところに思考が向いてしまっていました。その結果、CloudFront なり AWS WAF の設定あたりを疑うところから始めてしまったという・・ なお、Cognito ユーザの認証処理自体が正常に実施されていた理由もシンプルで、クライアント側の処理だったためです。そもそも、URL を叩いて表示されたログイン画面にユーザ/パスワードを入力してログインしようとしている時点で、クライアント側の処理であることは自明ですね。。また、実装の都合上他の AppSync API を叩くような処理(=Cognito ユーザ認証が必要な処理)は基本的にほぼクライアント側で明示的に実行するようにしているため、本事象の影響は出ていませんでした。このあたりは Nuxt3 で Universal Rendering (Server-Side Rendering) を使用しているが故の内容と思います。 ということで、こちらも後述する解決策により対応したのですが・・納得できない部分が残りました。   エラー内容の深掘(AWS サポート問い合わせ) というのも、先般の通りバックエンドの Lambda 関数から boto3 経由で Cognito ユーザプールにアクセスする処理は元々問題なく動作していたためです。AppSync については、バックエンドの Lambda 関数からも実質的にアプリケーションからのアクセスと同じように GraphQL API を叩くような実装となっており、boto3 は使用していなかった(使えなかった)ため同じように AWS WAF にブロックされることも納得できたのですが、では boto3 経由のアクセスが AWS WAF にブロックされないのは何故なのか? ということで、この点を AWS サポートに問い合わせてみたところ、実に明快な回答を頂きました。というかドキュメントをもうちょっと読んでから問い合わせれば良かったと思ったくらいには明確に書いてあったので、少なからず申し訳ない気分になりましたが・・   Cognito ユーザプールの場合 AWS WAF ウェブ ACL とユーザープールの関連付け - Amazon Cognito AWS WAF ウェブ ACL を Amazon Cognito ユーザープールに関連付けることができます。ウェブ ACL は不要な HTTPS リクエストをブロックしてログに記録できます。 docs.aws.amazon.com 上記 URL に記載の通り、正に今回の事象を端的に説明できる内容でした。 AWS 認証情報による認証を不要とするパブリックなユーザープール API へのリクエストに対しては適用される クライアント端末やフロントエンド用 Lambda で Cognito 認証情報を扱うような処理に該当 AWS 認証情報による認証が必要なユーザープール API へのリクエストに対しては適用されない バックエンド用 Lambda から boto3 を叩くような処理に該当 確かに理屈というか考え方としても納得できるところで、AWS 認証情報による認証が必要な API については認証情報の有無がそのままアクセス制限となりますし、アプリケーションのログイン処理においてはその時点で AWS 認証情報は持たない(ログイン後に Cognito 経由で付与される)以上 API としてはパブリックとすべきであり、その上でアクセス制限をしたい場合の機能として WAF が適用できるというように理解できました。 また、先述したような「boto3 経由のアクセスについて許可されている」という表現ももちろん間違っており、バックエンド用の Lambda において boto3 経由で実行していたのが AWS 認証情報による認証が必要なユーザープール API へのリクエストのみであったため、結果的にそのような挙動になっていたというのが実態でした。これまでのエントリやアーキテクチャ図に記載の通り、バックエンド用 Lambda は AppSync 経由で実行される想定のため、Lambda 内で Cognito の認証情報を直接扱う必要がないことから必然的にそのような実装になったとも言えるかもしれません。   AppSync の場合 AWS WAF を使用して AWS AppSync API を保護する - AWS AppSync GraphQL AWS WAFウェブ ACL を作成し、AppSync API に関連付けて、攻撃から保護する方法について説明します。 docs.aws.amazon.com Welcome - AWS AppSync AWS AppSync provides API actions for creating and interacting with data sources using GraphQL from your application. docs.aws.amazon.com こちらも上記 URL に記載がありましたが、Cognito ユーザプールの場合とは少し考え方が異なるようでした。 AppSync にて作成された GraphQL API に WAF が適用されている場合、同 API へのリクエストに対して一律で WAF が適用される 2つ目 の URL に記載されている API へのリクエストについては WAF は適用されない 考え方としてはシンプルで、GraphQL を含む AppSync API 自体の管理操作自体には WAF が適用されず、作成した AppSync API を叩くような操作については WAF が適用されるというように理解できました。逆に言うと、バックエンド用 Lambda の実行ロールに appsync:GraphQL が付与され対象の GraphQL API を実行できる権限があっても、Cognito の場合と異なり GraphQL API へのアクセスである以上 WAF が適用されるため、先述した通りの挙動となったということですね。作成した GraphQL API のエンドポイント URL が明示的に払い出されることも踏まえ、直感的な仕様だと感じました。 ちなみに気になったのですが、boto3 に AppSync で作成した API を叩くような機能がないのは何故なんでしょうね?主としてフロントエンドを含むアプリケーションから実行される以上(何となく boto3 =管理用のライブラリというイメージがあったこともあり)boto3 の用途にそぐわないからかなと勝手に想像してたのですが、一方で Cognito ユーザプールについてはちゃんとユーザ認証機能あるんですよね。ん?機能としては同じような文脈というか用途じゃないですか?という。 Lambda (Python) から AppSync で作成した API を叩くのに requests パッケージなどが必要となるのですが、Lambda の 標準 Python ランタイムには含まれておらず、レイヤー経由でインポートしないといけなかったりして手間なので、boto3 経由で実行できるようにしても良いんじゃないかと思うんですけど需要がないんですかね?確かにフロントエンドとしての需要は少ないかもですが・・ AppSync - Boto3 1.36.26 documentation boto3.amazonaws.com   解決策 ということで、Lambda 関数から AppSync/Cognito の API エンドポイントを叩きに行く際の IP アドレスについても許可するよう、AppSync 及び Cognito ユーザプールの AWS WAF 設定をお客さんに修正頂いてクローズと相成りました・・が、お気づきの方もいると思いますが、この解決策が取れるかどうかは Lambda 関数がどこに構成されているかに依存します。デフォルトだと VPC 外(AWS が管理しているネットワーク上)に構成される以上 IP アドレスは不定になると思われ、WAF で指定できない可能性がありました。 AWS の IP アドレスレンジは下記 URL の通り JSON 情報として取得できるようですので、Lambda のエンドポイント FQDN を解決した際の IP アドレスがどのレンジ内のものかを突合して、サービス単位での IP アドレスレンジを導入するなどのテクニックがあるようです。ただ、当然ながら IP アドレスのレンジが変更される場合もあるため、静的な AWS WAF 設定として適用することは運用上難しかったものと思います。 AWS IP アドレスの範囲 - Amazon Virtual Private Cloud ip-ranges.json ファイルで、公開されている IP アドレス範囲を使用して、AWS サービスに出入りするトラフィックを特定し制御します。公開されている範囲の変更を経時的にモニタリングします。 docs.aws.amazon.com 幸いアーキテクチャ図の通り、お客さん AWS 環境において Lambda 関数はフロントエンド/バックエンド用どちらも VPC 内のプライベートサブネット上に構成されていたため、Lambda から AppSync/Cognito の API エンドポイントを叩きに行く際のソース IP アドレスとなる、NAT Gateway のパブリック IP アドレスを指定頂き、無事に解決できました。 なお、本アーキテクチャにおいて AppSync や Cognito ユーザプールの API を叩くためにはどちらも認証が必要であるため、エンドポイント自体がインターネットに公開されていても大きな問題ではなかったとは思います。ただ、お客さんの環境ポリシーに適合しなくなることも確かなので、その場合の調整コストなどを鑑みると今回のような構成を取れて良かったというのが正直なところです。   まとめ AppSync についてはアプリケーションの動作に直接的な影響があったこともあってすぐに対応できたのですが、そのタイミングで Cognito についてももう少し深掘りするべきだったというのが反省点です。元々の AWS WAF 導入時の観点が外部アクセスの制限にあったことが多少のエクスキューズにはなるかもしれませんが、構成上同じような事象が発生し得るということまでは気付いていただけに。。 また、AWS WAF を適用できる他のサービスについても、今回のようにリクエストの内容などにより適用される範囲が変わりそうだなと感じたので、もし次に触る機会があれば留意しておきたいと感じました。 本記事がどなたかの役に立てば幸いです。
概要 Azureの既存Prepaymentから新規Azureテナントのサブスクリプションを払い出してみました。 Microsoft Learnに記載されている手順を参照するだけですが、私が対応した際にアカウントやサブスクリプションの関連が理解が浅かったためつまづいたポイントや補足事項を残します。 この手順はいろいろなライセンス形態の中での一例でしかないため、正式な手順はライセンス販売企業様の案内に沿っていただければと思います。 登場するリソース 既存Prepaymentが紐づくテナントA(作成済み前提) テナントAで新規作成するアカウント所有者B 新規作成するテナントB テナントB上で新規作成するサブスクリプションB 用語等については以下公式資料を参照ください。 Microsoft Azure利用ガイド 手順、補足 1.テナントBを新規作成する。 下記URLから新規テナントBを作成する。 Microsoft 365 E3 (Teams なし)     ポイント1→本人確認のセキュリティチェックで電話番号を登録しSMS認証か音声通話認証を実施するのですが、弊社内からは下記のエラーとなりました。弊社プロキシが影響していることを想定し、弊社貸与のスマホのブラウザから実行したところエラーは解消しました。   2.テナントAでアカウントBを新規作成し有効化する。 ・アカウント所有者の登録(エンタープライズ管理者の操作) Azure portal での EA 課金管理 – Microsoft Cost Management | Microsoft Learn ポイント2→アカウントの追加の中で指定する[アカウント所有者のメール]で新規作成したテナントBで登録したユーザのユーザープリンシパル名を指定します。 ←   ポイント3→有効化後テナントBのアカウントのプロパティにテナントAの課金アカウント情報も表示されます。   3.テナントBでサブスクリプションBを新規作成する サブスクリプションの作成(上記操作で登録したアカウント所有者での操作) Enterprise Agreement サブスクリプションを作成する – Azure Cost Management + Billing | Microsoft Learn つまづきポイントは特にありませんでした。   以上、難しい手順はありませんが、それぞれの結び付けを理解していないとどのテナントでどの操作をすればよいかわかりませんでした。もし同じようなところでつまづいている方へこの情報が届けば幸いです。
こんにちは!SCSKの新人、黄です。 前回までの記事では、Rubrikの基本機能と、その強力なランサムウェア対策について詳しくご紹介しました。多くの方に興味を持っていただき、とても嬉しかったです! 「まだ読んでいない!」という方は、ぜひ以下の記事をご覧ください。 Rubrikとは?クラウド&オンプレにも対応する次世代バックアップ管理を紹介 – TechHarmony Rubrikのランサムウェア対策:仕組みとシミュレーションで確認 – TechHarmony さて、今回ご紹介するのは、Rubrikのもう一つの注目機能、「 Rubrik Sensitive Data Discovery 」です。 名前の通り、機密データを検知し、適切に管理できる機能です。 興味がある方は、ぜひ詳しく見ていきましょう! Sensitive Data Discovery とは? 「どこに機密情報があるのか分からない…」 「気づかないうちに重要なデータが公開されていたらどうしよう…」 「膨大なデータの中から機密データを手動で探すのは大変…」 上記のような悩みを解消し、データの安全性を高めるために役立つのが Rubrik Sensitive Data Discovery です。 Sensitive Data Discoveryは、設定したルールに基づいてバックアップデータをスキャンし、機密データを自動的に検出する機能です。 特に以下の 3 つのポイントがメリットです。 バックアップデータを活用したスキャン 通常の業務データに影響を与えず、バックアップデータを活用して機密情報をスキャンできます。 これにより、負担なくデータの安全性を確保できます。 自動検出とリスク分類 設定されたルールにより、氏名やクレジットカード番号などの機密データを自動で検出し、リスクレベルを分類できます 手動での確認作業を減らし、効率的な管理が可能です。 直感的なレポート機能 分析結果はダッシュボードで可視化され、どこにリスクがあるのか一目で把握できます。 これにより、迅速な対策が可能になります。 実際に使ってみた!Sensitive Data Discovery シミュレーション ここまで、Sensitive Data Discoveryについてご紹介してきましたが、 「実際の運用イメージがわからない!」  と感じる方もいらっしゃるのではないでしょうか? そこで今回は、 VMware vSphere上の仮想マシン(VM) を例に、Sensitive Data Discovery を実際に動かすシミュレーションを解説します! このシミュレーションを通じて、どのように機密データが検出され、管理されるのかを具体的にイメージしていただけると思います。 vSphere と RSC(Rubrik Security Cloud) の連携の仕組み 参考資料: vSphere仮想マシン RSCは、 VMware vSphere 環境  とシームレスに連携し、仮想マシン(VM)のデータ保護と管理を実現します。 vCenter Server 接続 RSC は vCenter Server と接続し、VM を自動検出・管理します。 複数クラスター管理 1つの vCenter を複数の Rubrik クラスターで管理可能。VM の保護範囲を柔軟に設定できます。 SLA ドメイン適用 VM に SLA ドメイン(バックアップポリシー)を適用し、自動保護を実現 シミュレーションの全体像 Sensitive Data Discovery を使ったシミュレーションは、以下のような流れで進めてみました。 ステップ1 Sensitive Data Discovery の基本設定 アナライザーとポリシーの作成 ステップ2 初期分析 既存の全バックアップデータを自動スキャン ステップ3 テストデータの準備 機密データあり/なしのファイルを作成 ステップ4 Sensitive Data Discovery実行 機密データの検出 ステップ5 結果確認 ダッシュボードで結果を可視化 ステップ 1: Sensitive Data Discovery の基本設定 まず、RSC コンソールの  「Data Security Posture」  メニューを選択し、Sensitive Data Discovery の設定画面に移動します。 ここでは、Sensitive Data Discovery の  「脳」  とも言える、 アナライザー  と   ポリシー の2つの設定を行います。これらの設定を行うことで、Rubrik が機密データを自動的に検出し、管理できるようになります。 アナライザーの設定 アナライザーは、機密データを検出するためのルールセットです。 Rubrik では、以下の2種類のアナライザーを利用できます。 事前定義済みアナライザー 62種類 のテンプレートから選択可能です。 例えば、 IPアドレス  や  Google APIキー  など、一般的な機密データのパターンを簡単に検出できます。 カスタムアナライザー 独自のルールを追加可能です。特定のキーワードやパターンに基づいて、柔軟に機密データを定義できます。 今回は、 「社外秘」または「部外秘」 というキーワードを含むファイルを検出するカスタムアナライザーを作成しました。 ポリシーの設定 ポリシーは、アナライザーをどのオブジェクトに適用するかを指定します。 これにより、特定の環境に特化したSensitive Data Discoveryが可能になります。 具体的な操作として、 まずポリシーに含まれるアナライザーを確認し、ポリシーの名称を設定します。 今回使用するのはカスタムで作成した 「Japan Confidential」 アナライザーです。 なお、1つのポリシーに複数のアナライザーを含めることも可能です。 次に、分析対象のオブジェクトを指定します。 ここで特に重要なのは、 SLA ドメインルールが設定されているオブジェクトのみが機密データ分析の対象になる という点です。 SLAドメインルールとは、 「このデータをどのように保護するか」を決めるルール のことです。例えば、「毎日バックアップを取る」「1年間保存する」といった設定が含まれます。このルールが適用されていないオブジェクトは分析できないため、事前に設定を確認しておく必要があります。 Rubrik は下図のような 2 つの方法を提供しており、 オブジェクトタイプ別: 特定のオブジェクトを選択する方法 クラスター別: Rubrik CDM を指定し、CDM 配下のすべての SLA ドメインを持つオブジェクトを分析する方法 今回は、特定の vSphere の仮想マシンを分析するため、1 つ目の「 オブジェクトタイプ別 」を選択します。 以下の図のように、Rubrik は複数のプラットフォームと連携しており、異なる環境に存在するオブジェクトも RSC(Rubrik Security Cloud)を通じて一元管理できます。これも Rubrik の大きな利点の一つです。 今回としては、vSphereプラットフォームをクリックして、特定のVMを選択します。 ステップ 2: 初期分析 ポリシー設定後、Rubrik は 自動的に 初期分析を行います。 初期分析では、対象となるVMのすべてのバックアップ世代をスキャンします。 つまり、今後取得するバックアップデータだけでなく、 Sensitive Data Discovery機能を利用する前に取得したバックアップデータも含めて 機密データの有無を分析することも可能です。 ステップ 3: テストデータの準備 検出精度を検証するため、VM 内に以下の2種類のファイルを作成: 機密データあり :「社外秘」を含むmail.txtファイル 機密データなし :mail_normal.txtファイル   ステップ 4: Sensitive Data Discovery実行 Rubrik Sensitive Data Discovery は手動で実行する必要がありません。 ポリシーとアナライザーを設定するだけで、対象のオブジェクトがバックアップデータを取得するたびに自動的に実行されます。 Rubrik の公式説明によると、最大 24 時間以内にスキャンが完了するとされていますが、今回のシミュレーションでは バックアップ取得後、約 30 分で機密データの検知結果が反映 されました。 それでは、結果を一緒に確認してみましょう! ステップ 5: 結果確認 下図のように、 Data Security Posture ダッシュボードで簡単に確認可能です。 Sensitive Data Discovery が vSphere VM 内の機密データを適切に検出し、一つの中リスクのファイル (mail.txt) が存在することが判明しました。 なぜ中リスクなのかというと、設定したアナライザー「Japan Confidential」のリスク評価を中リスクに指定しているためです。 メニューの「 機密データ 」をクリックすると、下図に示すように、 どの VM のどのファイルに機密情報が含まれているのかを追跡でき、適切な対応 が可能になります。 さらに、下図のように、Sensitive Data Discovery はすべてのバックアップ世代をスキャンするため、 どの時点のバックアップデータから機密データが含まれるようになったのか特定 することも可能です。 最後に Rubrik Sensitive Data Discovery を使えば、機密データの管理がグッと楽になります。 ✔ 機密データを自動で検出し、可視化 ✔ バックアップデータを活用し、通常業務に影響を与えない ✔ ポリシー設定だけで継続的に監視可能 実際に試してみると、どこにどんな機密情報があるのか一目で分かるので、データ管理の負担を減らせます。 興味がある方がいらっしゃいましたら、ぜひぜひ 機密データの監視 | Rubrik をご覧ください。 また、Rubrik Sensitive Data Discovery は、今回のシミュレーションで使用したテキストファイルだけでなく、PDF、Excel、Word など多様なファイル形式に対応しています。詳しくは サポートされているファイル形式 をご確認ください。 ここまでご覧いただき、ありがとうございました。 今後も、Rubrik の便利な機能について紹介していく予定です。それでは、また次回!
もしも、映画史に残る感動的な場面を、最新のAI技術で蘇らせることができたら…? こんにちは、佐藤です。 皆さんは、 名作映画 といわれたら何を思い浮かべますか? 私は最近初めて映画 『タイタニック』 を見たのですが、やはり名作といわれるだけありますね…。 結末を知っていても楽しめるのはまさに不朽の名作といわれる所以だと感じました。 さて、タイタニックの中で最も印象的なシーンの一つが、ジャックとローズが船首で腕を広げるシーンですよね。 今回は、 Amazon BedrockでLuma AI の「Ray2」モデルを使い、この有名なワンシーンを再現できるのか―― というお話です。 Ray2モデルとは? 2025年1月23日、AWSは Luma AI の新しい動画生成 AI モデル「Ray2」 が Amazon Bedrock で利用できるようになった と発表しました(参考  https://aws.amazon.com/jp/about-aws/whats-new/2025/01/luma-ais-ray2-visual-ai-model-amazon-bedrock/ )。まずは簡単にLuma AIのRay2モデルについてご紹介しようと思います。 Ray2は、 Luma Labsが開発した最新の動画生成AIモデル です( https://lumalabs.ai/ray )。 前モデルであるRay1と比較して 処理能力が10倍に向上 しており、より滑らかで自然な動きを持つリアルな映像を生成できるのが大きな特徴です。また、従来のAI動画生成モデルであれば数分から数時間かかっていたレベルの動画生成を、 Ray2はわずか1分程度で作成可能 ということで大きな話題を呼びました。 現在はテキストプロンプトから動画生成をサポートしていますが、 今後は画像から動画生成や動画から動画への変換、また作成した動画の編集機能も実装予定 とのことで、これからの動向に目が離せないAIサービスですね。 テキストプロンプトから動画を生成 5秒または9秒のクリップを作成可能 高解像度(1080pのフルHD解像度もサポート)   BedrockでRay2を使ってみよう さて、さっそくBedrockでRay2モデルを使ってみましょう。 事前準備として行うセットアップもそこまで多くなく、この記事を見ながら簡単に設定することができると思います。 Ray2を使用するには、以下の準備が必要です。 Amazon Bedrockのアクセス権 AWSアカウント (無料枠で利用可能) 適切なIAMポリシー を持つユーザー Amazon S3バケット (生成された動画を保存するために必要)   BedrockでLuma AI Ray2を有効化する いきなりですがここで注意点! マネジメントコンソールにログインしたらとりあえずBedrockにアクセスして…と言いたいところですが、まずはリージョンを オレゴンリージョン(us-west-2) に切り替えましょう! 現在 Ray2はオレゴンリージョンのみのサポート となっているのでここで変更を忘れてしまうと、せっかくモチベがあるのにアクセスできない、なんてことも…。 リージョンを変更したらAmazon Bedrockにアクセスしてサイドバーをスクロールした一番下、 「モデルアクセス」からLuma AI – Ray2を有効化 していきましょう。 Luma AIのRay2のアクセスのステータスが 「リクエスト可能」 となっていると思いますので、その文字をクリック、アクセス権をリクエストしていきます。 数分待つと、このように 「アクセスが付与されました」 と表示されます。ここまでくれば準備はOK!  タイタニックの名シーンをAIで再現! テキストプロンプトを考えてみる 今回の検証で最も大切な部分、テキストプロンプトを作成します。 試しにこんなプロンプトを作ってみました。 A young man and woman stand at the bow of a large ship. The woman has her arms outstretched and the man is holding her from behind. The ocean and sunset behind them. Cinematic, high quality. このプロンプトには、 登場人物(young man and woman) 、 場所(bow of a large ship) 、 ポーズ(arms outstretched, holding her) 、 背景(ocean and sunset) などを記載してみました。 正直に言うと、 この手の有名なシーンの再現度を上げるには裏技があるんです。 その方法はとっても簡単。文の末尾に 「inspired by Titanic」 と記載するだけです。 AIが認識できるタイトルであれば、そこに寄せるようなプロンプトを作成することで再現度を上げることが可能なんですが… 今回はせっかくなので、あえてタイタニックの名前を一切出さずに寄せてみましょう…! Amazon Bedrockで動画を生成してみよう では早速動画を作成していきましょう。 まずはBedrockのホーム画面、 プレイグラウンドから「Image/Video」を選択 します。 続いてモデルの選択画面が表示されるので、カテゴリは 「Luma AI」 、モデルは 「Ray」 を選択して適用をクリックします。 (モデル名の表示はRayとなっていますが、v2と記載があれば今回取り上げているRay2モデルです!) また、この際に生成した動画を保存するためのS3バケットを作成しますが、以下のポップアップの「確認」をクリックすれば問題ないのでこのまま進めていきましょう。 動画の保存先であるS3バケットにも課金がされるので、長期間保存する必要がなければS3バケットは削除するようにしましょう。 ここまで完了したら、いよいよプロンプトの入力画面です。 設定画面からは 動画の画面比率や解像度(通常540pまたは720p)、長さ(5秒または9秒)など を指定することができます。 では、先ほど作成したプロンプトを入力して実行をクリックします。 あとは数分待つだけ。 生成が完了すると、動画が画面上に表示され、動画がS3バケットに保存されます。 4. AIの再現度はいかに…? では、生成された動画のクオリティを確認していきましょう。 document.createElement('video'); https://blog.usize-tech.com/contents/uploads/2025/02/DC708E58D9DB1F8ED0BF309B87475B691580B466.mp4 結果:なんかちがう!! 今回の結果をまとめるとこんな感じでしょうか… 船の上で男女がいる、ということは再現できている。 ジャックとローズらしき人物は表現されているが、服装があまりにラフすぎる… 背景の夕焼けと海の表現はかなりリアル!すごい! 手を広げるってことは伝わっているけど、そういうことじゃない… 全体として、AIは「船首で男女が会いを深めるシーン」というコンセプトを認識できたものの、さすがに細部のディテールは表現できていなかったですね。 プロンプトの工夫や追加のパラメータ設定によって、より精度を上げることができそうです。   プロンプトを変えて再度挑戦! さて、ここで終わってもいいのですがどうしても悔しいので、もう一度プロンプトを変えて挑戦してみました。 作成したプロンプト version2がこちら↓ A man wraps his arms around a woman from behind as she stands at the bow with her arms outstretched. The ocean and sunset behind them. Cinematic, high quality. 改善のポイント: より詳細なプロンプトを作成 (男性が後ろから女性を抱いている、女性が選手で手を広げているなど) 先ほどよかった「Cinematic, high quality」は継続 こうして作成されたリベンジ動画がこちら! https://blog.usize-tech.com/contents/uploads/2025/02/AFF0A35CD8BEE3AF53EE36A38481F03BADF1387A.mp4 うーん、これもなんか違うかもしれないですね…笑 やはり日常的にする行動ではないこともあり、AIの学習データの中に手を広げる女性を後ろから男性が抱擁するというニュアンスが伝わりづらいのかもしれないですね…   6. まとめ 今回はAmazon BedrockのRay2を使って、映画『タイタニック』の有名なワンシーンをAIで再現してみました。 結果として、全体の雰囲気はある程度再現できましたが、細部の再現度にはまだ改善の余地がありました…。 学び プロンプトを工夫することで、自分の想像に近い映像を作ることが可能! AIの学習データの中に少ないと思われるような動作は、なかなか再現しづらい…? 生成された動画を素材として編集することで、より良い映像作品が作れるのでは…?   Ray2は簡単に動画を生成できるため、他の映画の名シーン再現や、オリジナル映像の作成にも応用可能です。 ぜひ、皆さんも試してみてください!    
SCSKの畑です。 以前のエントリ の続き・・ではないのですが、データメンテナンス機能に関する言及という観点は同じなのでその2としました。今回は、データメンテナンス機能の対象となる Redshift の特性を踏まえた上で、アプリケーションの実装において考慮する必要があったポイント及び機能について記載します。Redshift そのものというよりは、DWH の特性とある程度言い換えて良いかもしれません。   アーキテクチャ図 今回主に言及するのは Redshift のみですが、前回エントリと関連した内容を含むため一応載せておきます。   ポイント1. テーブル定義/データの更新チェック機能 以前のエントリ で説明した通り、テーブル定義/データのバージョン管理の要件があること、テーブル定義変更(=DDL操作)についてはアプリケーション外部で実行されることの2点より、アプリケーション側からテーブル定義/データの更新をチェックできる必要がありました。 具体的には、S3 上に出力・配置される対象テーブルの定義/データファイルのハッシュ値を比較することで行っています。対象テーブルの定義/データのバージョン管理を S3 を使用して行っているため、最新のバージョンの定義/データと、チェック実施時の Redshift 上の定義/データを比較して、差異があれば Redshift 側に更新があったことが分かる仕組みです。 が、実はこれは苦肉の策でした。更新チェックを実施するために実質的に Redshift 上の対象テーブル定義/データの全量を取得しているに等しく、コストが大きいためです。通常、本アプリケーション上で対象テーブルを表示する際には、以下のようなロジックを実行しています。 対象テーブルの定義/データ更新をチェック Redshift 上のテーブルが更新されている場合は、更新チェックの際に S3 上に出力したファイルを最新バージョンとして更新 最新バージョンのファイルのテーブル定義/データをアプリケーション上で表示 このようなロジックとした理由はいくつかあるのですが、アプリケーションから対象テーブルを表示する際に毎回 Redshift から全量を取得せずに更新の有無だけをチェックし、更新がない場合はそのまま S3 からテーブル定義/データを取得するようにすることで、レスポンスの向上を狙いの一つとしていました。ところが、実際の挙動としては1.による更新チェックのタイミングで Redshift から毎回全量を取得しているに等しいため、その目論見が崩れてしまっています。逆に言うと、更新チェックはもっと少ないコストで実施できると考えていました。 1.による更新チェックを任意のタイミングで実行するようなロジック・画面とするというのが回避策の一つだと思うのですが、そうするとテーブル定義/データの整合性を担保する難易度が上がってしまうこともあり、現時点ではこのようなロジックとしています。 というところでようやく Redshift (DWH) の特性に関連した話になるのですが、、通常のデータベース (RDBMS) だと、このような情報はデータベース側の管理情報として管理されているものが多いです。例えば Oracle の場合は以下 URL の通り、テーブル定義やデータの更新日時についてもデータベース側の管理情報ビューとして管理されています。(後者は統計情報取得との兼ね合いもあるので単純な管理情報とは言い難い部分もありますが・・)後は同情報をアプリケーション側でも持っておいて、突き合わせれば簡単に更新チェックができます。 https://docs.oracle.com/cd/E82638_01/refrn/ALL_OBJECTS.html https://docs.oracle.com/cd/E82638_01/refrn/ALL_TAB_MODIFICATIONS.html 対して、Redshift のような DWH の場合、通常のデータベース (RDBMS) と比較してより大量のデータを扱う目的から、このような管理情報についてはオミットされているものも多いです。DWH におけるデータの保持方式や管理方式が RDBMS と異なること、より大量データを扱う以上管理情報を RDBMS の場合と同じように扱うコストが甚大になること、そもそもの DWH の用途を鑑みると想定されていない/必要とされないと製品・サービス側で判断されていること、などの理由が考えられますが、いずれにせよ Redshift ではこのような機能がなかったため、先述したような仕組みを実装する必要があったということです。唯一、以下 URL のビューが近しい情報を含んでいましたが、さすがにテーブル作成時刻のみだとちょっとどうしようもなかったですね・・ https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_SVV_TABLE_INFO.html Redshift は RDBMS である PostgreSQL をベースにしていることもあり、最初は PostgreSQL 側のビューなどから取得できるのでは?と淡い希望を抱いていたのですが、結論から言うとそもそも PostgreSQL 側でもそのような情報を取得するのには一工夫必要のようでした。Oracle は(良くも悪くも)高機能・多機能な RDBMS なので、それを基準に考えることの功罪があるかもしれません・・   ポイント2. データバリデーションチェック機能 データのメンテナンス・更新にあたり大事なポイントの1つがデータの整合性を保つことです。データの整合性と一口に言っても様々な観点があるかと思いますが、最も基本的な観点としては列定義や制約(NOT NULL/PK/UK/FK)などのテーブル定義に違反したデータが更新されないかどうかが挙げられると思います。もちろん、本案件事例でも要件に含まれていました。 通常のデータベース (RDBMS) であれば、基本的にデータベース側でバリデーションチェックが行われるため、これらのテーブル定義に違反したデータは更新できないようになっています。このため、ここで言及しているようなデータ整合性を担保するだけであればアプリケーション側での考慮は不要です。 では Redshift の場合はどうかという話ですが、以下 URL の通り NOT NULL 以外の制約は制約として機能しません。定義自体はできますがあくまでもクエリ実行時に Redshift 側で効率的にデータを処理するためのプラン(実行計画)を立てるための参考情報として扱われ、データ自体の制約としては機能しません。つまり、例えば PK 制約が定義されている列に対して重複した値を INSERT することが可能といったように、これらの制約に違反するようなデータを更新することができてしまいます。 テーブルの制約 - Amazon Redshift 一意性、プライマリキー、および外部キーの制約は情報提供のみを目的としており、Amazon Redshift によって強要されることはありません。ただし、プライマリキーと外部キーはプランニング時のヒントとして使用されます。アプリケーションの ... docs.aws.amazon.com 一意性、プライマリキー、および外部キーの制約は情報提供のみを目的としており、テーブルに値を入れるときに  Amazon Redshift によって強要されるわけではありません 。例えば、依存関係のあるテーブルにデータを挿入する場合、制約に違反していても挿入は成功します。ただし、プライマリキーと外部キーはプランニング時のヒントとして使用されます。アプリケーションの ETL プロセスまたは他の何らかのプロセスによってこれらのキーの整合性が強要される場合は、これらのキーを宣言する必要があります。 もちろん(さすがに)列定義に違反するデータは更新できません。以下 URL の通り暗黙の型変換により、意図していないデータ型に変換されて更新される可能性はあるかもしれませんが、このような挙動は(製品/サービスごとの差異はあるとしても) RDBMS でも考慮されるべき内容と思います。 データ型 - Amazon Redshift Amazon Redshift によってサポートされているデータベースデータ型を使用する際に従うべき規則について説明します。 docs.aws.amazon.com よって、これらの制約に対応するデータバリデーションチェック機能をアプリケーション側で実装する必要がありました。具体的には、バリデーションチェックに失敗した場合はデータの更新を許可せず、バリデーションに失敗した(制約に違反した)データを修正するように画面上で促すようなロジックを実装することで対応しました。 また、このような機能をアプリケーション側で実装する必要があったことから、Redshift 側でチェックしてくれる列定義や一部制約についても同様にアプリケーション側でチェックするようにしました。その方がデータ更新における一連のロジック/フローをシンプルにできることが理由です。Redshift 側でチェックするということは実際に Redshift に対して更新を試行する必要があり、更に試行後のエラー内容をアプリケーション側で解釈してデータバリデーションのエラー画面を出さないといけないことにもなります。データ更新時の承認フローなどとの兼ね合いも考えると、トータルでロジックがかなり複雑になってしまうと判断しました。 なお、このような機能をゼロから実装するとさすがに工数・コスト面で厳しくなることが想定されたので、テーブルのデータ表示や編集機能を司るライブラリ探しにおいてはデータバリデーションチェック機能についても気にしました。最終的には Tabulator というライブラリを使用したのですが、詳細(もとい紹介)はまた別のエントリのネタとさせて頂こうと思います。   まとめ 業務において Oracle を中心とした RDBMS を扱っている期間が長いこともあり、Redshift(もといおおよその DWH)と RDBMS の差異としてはある程度容易に思い浮かぶような内容ではありましたが、アプリケーション実装の観点からまとめておくことも大事と考えたので今回まとめてみました。実際、ポイント1については何となくできるだろう・・みたいにタカを括っていたところできずに、最終的に今の方式に辿り着くまであれこれ試行錯誤することになったりしたので。。このへんの感覚というか勘所はもう少し意識しないといけないかなと感じました。 本記事がどなたかの役に立てば幸いです。
AWS KMSの暗号化は、S3のデフォルト暗号化などで使われることが多いと思います。 オブジェクトをPutすると自動で暗号化されるため、**「実際にどんな処理が裏で動いているのか」**を意識していない方もいるのではないでしょうか?この記事ではS3を題材にしつつ、KMS暗号化の仕組みに焦点を当てて解説します。 「KMSで暗号化するから、Encryptの権限が必要です。」 これはありがちな誤解ですが、大体の場合は間違った理解です。なぜそうなのか?その理由を紐解いていきます。 CMKはどこにいる? まずは鍵を作成しなければ始まりません。ここではカスタマーマスターキー(以下CMK)を対象鍵で作成するものとします。 キー作成はKMSのAPIである” kms:CreateKey ” が発行され、AWS管理下のどこかに対象鍵(以下CMK)が作成されます。 ここでまず頭に入れておくべきことがあります。 作成されたCMKはKMSから出てくることはありません。 このことはKMSの動きを理解する上で重要です。 作成したCMKで何らかのデータを暗号化・復号化する際は、CMKをKMSから取り出すのではなく、対象データをKMSに送って暗号化・復号化を依頼し、結果を送り返してもらう、という流れになります。 ここで次の疑問が沸いた人は鋭いです。 「でかいデータだと全部KMSに送らないといけないのでわ・・・・RDSとかEBSとかどうするの? ^^;」 実際は暗号化したいデータをKMSに送ったりはしていません。「データを暗号化する鍵」をCMKで暗号化してやりとりすることでこの問題を回避しています。 KMS(CMK)が暗号化できる対象は4096Byteまでという制限があるため、そもそもでかいデータは暗号化できないのです。 GenerateDataKey 唐突ですが、KMSには” kms:GenerateDataKey “いうActionがあります。(この話題での最重要アクションです。) CMKを引数として実行し、以下の2つの文字列を返してきます。以下はAWS CLIで実行してみたものです。 $ aws kms generate-data-key --key-id arn:aws:kms:ap-northeast-1:999999999999:key/99999999-9999-9999-9999-999999999999 --key-spec AES_256 { "CiphertextBlob": "AQIDAHiF7qVe(略)", "Plaintext": "eS7mjjJQby2(略)", "KeyId": "arn:aws:kms:ap-northeast-1:999999999999:key/99999999-9999-9999-9999-999999999999" } “Plaintext”             単なるバイト列 “CiphertextBlob”    Plaintext を指定したCMKで暗号化したバイト列 + メタデータ KMSはGenerateDataKeyを受けると、内部でランダムな文字列を生成し(Plaintext)、それを指定されたCMKで暗号化し(CiphertextBlob)、その2つを返してくれます。 この”Plaintext” のことを データキー と言い、実際のデータの暗号化の鍵として使われます。(ファイルやらEBSやらRDSやら。。) ここでは重要な点が2つあります。 まず、データキーはKMSの外側に出てきているということ。 次にデータキーを用いた暗号化(Encrypt)は、 kmsのアクションではない 、ということ。(一般的な暗号化なのかな。AES?) また、CiphertextBlob のメタデータにはCMKの情報を含んでいます。つまり 暗号化されたデータキーは、 自分がどのCMKで暗号化されているのかを知っています 。このことはデータ復号化の時に大変重要になってきますので覚えておいてください。(また今度書くかも) データ暗号化の流れ 以上の内容をまとめまして、データ暗号化の流れは以下のようになります。例としてS3にPutする場合を示していますが、例えばEBSの暗号化の流れも同じようなものになります。       ユーザはKMSに対して、作成済みのCMKを指定してkms:GenerateDataKey を発行する。 CMKはデータキーとデータキーを暗号化したものを返す。 ここでCMKの役割は終わっています。       ユーザはデータキーを使ってデータを暗号化し、そのデータキーを廃棄 この暗号化はKMSの外側で行われています。       暗号化されたデータに暗号化されたデータキーを添えて、S3に保存 (エンベロープ暗号化、とか言ったりします。)         最後で データに暗号化されたデータキーを一緒にして保存している ことは覚えておきましょう。 「鍵とデータ一緒にして大丈夫なの?家のドアに鍵を貼り付けてるようなものでは?」とは思わないように。この場合、鍵自体が暗号化された状態ですので、このままでは使えません。CMKに復号化を依頼できる人だけがこのデータを復号できます。 以上のフローを見てわかるように、KMSに対してはkms:GenerateDataKeyだけしか実行していません。なのでデータ暗号化の際に必要な権限としては kms:GenerateDataKeyがあればよい 、ということになります。(kms:Encryptではなく!)   以上。データ暗号化の時の基本的な流れを説明してみました。 若干フローなどは単純化している個所もありますが、理解の助けになれば幸いです。
SCSKの畑です。 Amplify を使用したアプリケーション開発中に発生した事象の原因及び解決策について、Web 上にあまり情報がなかったことも含めて解決に少々手こずったので共有します。引き続き今回も小ネタです。   小ネタ本題 タイトルの繰り返しになるのですが、以下のようなスキーマを定義した際、Amplify codegen により生成された query にネストされた type が含まれなかったという事象が発生しました。ちなみに本スキーマは2つの Redshift テーブルの定義及びデータを差分比較結果を格納するためのもので、AddedRowsInfo/DeletedRowsInfo/UpdatedRowsInfo に差分のあった行情報がネストされて格納されます。 ちなみに、差分比較処理自体は素直に AppSync から Lambda リゾルバを使用して実現していますが、フロントエンド側での表示も含めてそこそこ苦労した部分なので、機会があれば別エントリとして書くかもしれません。 type DataDiffInfo { diff_summary: RSS3DiffStatus! added_rows_info: [AddedRowsInfo]! deleted_rows_info: [DeletedRowsInfo]! updated_rows_info: [UpdatedRowsInfo]! } type RSS3DiffStatus{ column: Boolean constraint: Boolean data: Boolean } type PKInfo { name: String! value: String! } type AddedRowsInfo { pk: [PKInfo!]! row_data: String! } type DeletedRowsInfo { pk: [PKInfo!]! row_data: String! } type UpdatedRowsInfo { pk: [PKInfo!]! cols: [String!]! row_data: String! } で、このスキーマ定義に対して、codegen で生成された typescript の query が以下になるのですが・・ export const GetTableDataDiffInfo = /* GraphQL */ `query GetTableDataDiffInfo($input: GetTableDataDiffInfoInput!) { GetTableDataDiffInfo(input: $input) {   diff_summary {     column     constraint     data     __typename   }   added_rows_info {     row_data     __typename   }   deleted_rows_info {     row_data     __typename   }   updated_rows_info {     cols     row_data     __typename   }   __typename } } ` as GeneratedQuery< APITypes.GetTableDataDiffInfoQueryVariables, APITypes.GetTableDataDiffInfoQuery >; 見てお分かりの通り、AddedRowsInfo/DeletedRowsInfo/UpdatedRowsInfo 配下の「PKInfo」type 部分が query 定義から抜け落ちてしまっています。ネストの深さとしては一番上の階層から数えると 「3」 になりますね。   暫定回避策 さてこれは困ったということで解決策を探したのですが、探し方が悪かったのかめぼしい情報が見当たらず。最初は AppSync のクエリの深さ制限設定を疑ったのですが、デフォルト値は無制限だったためこの可能性は除外。 そこで一旦暫定的な回避策として、自分で直接 GraphQL の query を書くことにしました。codegen で 型情報を生成して欲しかったので、以下サイト様の記事通り所定のパスに query が定義されたファイルを配置しました。 AmplifyでカスタムGraphQLクエリと型情報を生成する方法 - Qiita 本記事を対象とする人Web(React,Vueなど)でAmplify利用し、自動生成されるクエリでは足りなくなった結論graphqlconfig.ymlのincludesに指定しているディレク… qiita.com ただ、当然ながら query を自分で書いている以上スキーマ定義の変更があった場合も自動で追随してくれないため、開発が続くにつれて不便さ&イライラを感じてきました。そもそも、Amplify が自動生成しないような複雑なクエリを書きたいから自分で書く必要があるのであって、今回のような事象に対しては根本的な解決策でないことは明らかであったため、本腰を入れて解決策を調べたところ・・   解決策 結論としては以下 URL の通り、.graphqlconfig.yml の maxDepth 属性で、生成する query のネストの深さを明示的に指定することで解決しました。 ただ、以下 URL に記載のある –max-depth オプションは手元の環境だと機能しませんでした。また、「max d epth」のように大文字小文字を間違えてもダメですのでご注意ください。 最初間違えてしまったのですが、エラーも出ないのでこの設定方法も機能しないのではないかと疑心暗鬼になってしまいました・・ Nested types missing from queries in generated code - Require workaround · Issue #745 · aws-amplify/amplify-cli ** Which Category is your question related to? ** iOS side generated graphql queries ** What AWS Services are you utiliz... github.com 以下、maxDepth を 5 に設定した場合の実装例です。 projects: nuxt3app:   schemaPath: src/graphql/schema.json   includes:     - src/graphql/**/*.ts   excludes:     - ./amplify/**   extensions:     amplify:       codeGenTarget: typescript       generatedFileName: src/API.ts       docsFilePath: src/graphql       maxDepth: 5 extensions: amplify:   version: 3 こちらはオプション指定して codegen した query の内容です。PKInfo の type が追加されていることが確認できます。 export const GetTableDataDiffInfo = /* GraphQL */ `query GetTableDataDiffInfo($input: GetTableDataDiffInfoInput!) { GetTableDataDiffInfo(input: $input) {   diff_summary {     column     constraint     data     __typename   }   added_rows_info {     pk {       name       value       __typename     }     row_data     __typename   }   deleted_rows_info {     pk {       name       value       __typename     }     row_data     __typename   }   updated_rows_info {     pk {       name       value       __typename     }     cols     row_data     __typename   }   __typename } } ` as GeneratedQuery< APITypes.GetTableDataDiffInfoQueryVariables, APITypes.GetTableDataDiffInfoQuery >; また、同オプションのデフォルト値は 「2」 ということで、先般のスキーマ定義において PKInfo 以下の type が出力されなかった理由も辻褄が合ってスッキリしました。正直、デフォルト値はもう少し大きくても良いと思うんですけども・・   まとめ 以前の投稿にて Amplify.Configure に与える引数の定義が不明瞭で調査に苦労した旨書いていたのですが、本件も似たような文脈の話ではないかと思います。。 余談ですが、初めて本事象が発生した時は原因究明に結構な時間を要してしまいました。というのも、Amplify のデプロイや codegen 実行時はエラーが出ておらず、AppSync 側のスキーマ定義を確認しても問題なし。Lambda リゾルバの実装に問題がある可能性も考慮して、AWS マネジメントコンソールからクエリを直接実行してみるとちゃんと PKInfo 部分の情報も取れる。でもフロントエンド側から codegen で生成されたクエリを使用すると PKInfo 部分の情報が取れない。でもエラー自体は出ていない。という感じだったので・・ 開発当初は Amplify や AppSync、GraphQL などへの理解が十分でなかったこともありますが、Web 上の情報がもう少し多かったらもっと早く解決できた!はず!ということで小ネタではありますが、本記事がどなたかの役に立てば幸いです。
「~のサービスは次のうちどれでしょうか。」 クラウドの認定試験やIPAの午前試験などでよくある形式です。 こういう選択問題はなんとなくで解けてしまうことも多いですよね。 私も試験勉強中は 「よくわからないけど、これかな~?」 と曖昧な理解で正解した時期がありました。 大量の問題演習で何とかしのいでいましたが、こんな勉強法を脱却したいと日々悶々。 そんな思いがある中、実務で触れて理解が深まった Azureの「プライベートエンドポイント」 についてまとめます。 プライベートエンドポイントとは? AzureのPaaSサービスに接続するための手段のひとつです。 仮想ネットワーク内の プライベートIPアドレス を使用して PaaSリソース に接続するために使用します。 パブリックアクセスを無効化することで、インターネット経由のアクセスを防ぐことも可能です。 つまり セキュリティ向上の利点 があるわけです。                       試験勉強中はこの概念を流し読みしていましたが、そもそも「PaaSリソースとは何か?」をきちんと理解できていませんでした。 「なんとなく、インターネットを介さずに何かにアクセスできる仕組み」といった認識だったのです。それでも試験の問題には正解できてしまうので、深く考えることなく先に進んでしまっていました。 問題を解いてみる 例えば、次のような問題があるとします。 問1 仮想ネットワークのプライベートIPアドレスを使用してPaaSサービスに接続するためのサービスはどれ? a. Azure Bastion b. プライベートエンドポイント c. Azure Load Balancer d. Azure ExpressRoute この問題では、「プライベートIPアドレス」というキーワードだけに注目して”b”のプライベートエンドポイント選んでました。なぜかPaaSサービスに接続~のくだりを読み飛ばしていたのです。これで正解してしまいます。 問2 「」の内容が 正しい 場合は”変更は必要ありません” そうでない場合は正しい回答を選べ 「パブリックエンドポイント」を使用すると、Azure Cosmos DBなどのPaaSサービスに接続するためのパブリックアクセスを無効にできる。 a. プライベートエンドポイント b. 仮想ネットワークピアリング c. Azure ExpressRoute d. 変更は必要ありません パブリックアクセスを無効とくればプライベートエンドポイントで”a”を選択してました。こちらでもAzure Cosmos DBなどの記載を無視して解いていたのです。 問3 次のリソースがある。 名前 リソース種別 説明 VNET1 仮想ネットワーク ー VM1 仮想マシン VNET1に配置 Storage1 ストレージアカウント ー VM1がプライベートIPアドレスを使用してStorage1にアクセスできるように構成するにはどれを使うべきか? a. ユーザー割り当てマネージドID b. Azure Firewall c. プライベートエンドポイント d. Application Gateway 問1と同じようにプライベートIPアドレスとくればプライベートエンドポイント”c”を選べてしまいますが、 アクセス先がストレージであることに理由があったんだなぁ と今になって気づきました。 自分が何を理解していて、何を見落としていたのかがよく分かります。理解して解けるようになると問題設定も結構おもしろいです。 PaaSサービスの具体例 振り返ってみると、問題の意図がより明確に見えてきます。 そもそもPaaSサービスって具体的に何のことでしょうか? 公式ドキュメント見ると。プライベートエンドポイントの文脈で出てくるPaaSサービスとは以下のサービスのことです。 Azure Storage Azure Cosmos DB Azure SQL データベース Private Link サービスを使用する独自のサービス プライベート エンドポイントとは – Azure Private Link | Microsoft Learn 実務でストレージにプライベートIPを付与する場面を見たことで、やっとこの概念を理解できました。 文字情報だけでは気づけないことも多いと 痛感 しました。 デモ 自分でもストレージアカウントにプライベートIPアドレス付与してみようと思います。 1. ストレージアカウントの左ペインからセキュリティとネットワークを開き、ネットワークを選択。 プライベートエンドポイント接続、+プライベートエンドポイントを押下します。                     2.基本タブ入力。 名前を入力するとネットワークインターフェイス名が自動で作成された。               3.リソースタブでは対象サブリソースで、ストレージの種類選択。今回はblobになります。                 4. 仮想ネットワークタブではプライベートエンドポイントを作成するサブネットを指定。 このサブネット上にプライベートエンドポイント作成されプライベートIPアドレスが構成されます。                     5. DNSタブではプライベートDNSゾーンと統合するではいを選択。DNSレコードが自動で構成されます。             6.確認。 プライベートIPアドレス 10.0.156.4 が付与されました。                                                   7.プライベート経由のアクセス許可の確認 プライベートエンドポイントと同じ仮想ネットワーク上のVMへリモートデスクトップ接続してnslookup コマンド実施。 以下のようにプライベートIPアドレスが応答される。         自分のPCからnslookup実行するとパブリックIPアドレスが応答され、ストレージにアクセスできない。           さいごに 3月にAZ-305(Microsoft Certified: Azure Solutions Architect Expert)を受験します。 AZ-104よりも要件が複雑になっているので、理解しながら解けるようになろうと思います。 ふんわりした資格勉強から卒業し、実務で活かせる知識を身につけるために、しっかりとした学習を進めていきます。
こんにちは!SCSKの新人営業、栗山です。 皆さんの会社では、電話応対をどのように行っていますか? 顧客対応の質向上や効率化 は、多くの企業にとって重要な課題ですよね 近年、AI技術を活用した 電話応対のDX が注目されています。 例えば、音声認識技術を使えば、顧客との会話を自動でテキスト化し、分析したり、対応を効率化したりすることが可能になります! 今回は、Google Cloudが提供する音声認識サービス Google Cloud Speech-to-Text の検証を通して、AIによる電話応対DXの可能性を探ってみました! Google Cloud Speech-to-Tex(以降Speech-to-Text)は、高精度な音声認識を簡単に実現できるサービスです。 本記事では、Speech-to-Textを実際に使ってみた感想や検証結果を共有することで、 AI技術による電話応対DXに興味がある方 Speech-to-Textの導入を検討している方 文字起こしツールを活用したいけど何にしようか悩んでいる方 音声データを分析して業務に役立てたいと考えている方 にとって、少しでも役立つ情報になれば幸いです! 検証目的 コンタクトセンター業界 のお客様からは、音声データの文字起こしに対して、有用なサービスは無いかと質問を受けるケースが良くあります。 あるお客様は現状、オペレーターの対応時の録音データを分析に活用するため、 何度も聞き直しながら手作業で文字起こし を行っており、非常に時間と手間がかかっているとのことでした。。。 もし、この 文字起こし作業をAIで効率化 できれば、担当者はより創造的な業務に集中できます。 例えば、顧客対応の傾向分析や、サービス品質向上のための施策検討などに時間を有効活用できるでしょう。 そこで今回、限りなく実際の応対に近いテスト音声データを使い、Speech-to-Textによる音声認識精度の簡易検証を実施することで、 Speech-to-Textの導入により、お客様の文字起こし作業の効率化と負担軽減に貢献できる可能性 を明らかにしました!   なぜGoogle Cloud Speech-to-Textを選んだのか 導入の容易さ:  GUIが用意されており、初期設定が簡単で、すぐに検証を開始できる! コストパフォーマンス: 無料枠60分があり、コストを気にせず試しやすい! 高精度のリアルタイム文字起こし: 他クラウドと比較しても遜色ない性能! 他クラウドとの比較(文字起こしサービス編)       Google  Cloud      Speech-to-Text Amazon Transcribe    Microsoft Azure    Speech to Text AmiVoice Cloud Platform(Amivoice API) 対応言語 日本語を含む125以上の言語 日本語を含む複数言語 日本語を含む多数の言語 日本語、英語、中国語、韓国語 料金 約0.046円/秒 ※60分無料枠あり ※新規利用者は$300相当のクレジット ※ログ許可で割引あり 約0.046円/秒 ※利用量割引あり 約0.046円/秒 ※1か月あたり5音声時間は無料 0.044円/秒 ※毎月60分無料枠あり ※ログ許可で割引あり GUIでの利用 〇 〇 〇 × ※単語登録のみ可能 他サービスとの連携 〇 他Google Cloudサービスと容易に連携 〇 他AWSサービスと容易に連携 〇 他Azureサービスと容易に連携 〇 リアルタイム性 低遅延で字幕表示も可能 リアルタイム対応可能だが速度に制限あり 雑音環境での処理に強いが速度は平均的 リアルタイム性は他社と比較して平均 導入の容易さ デフォルトモデルで高精度・即利用可 即時利用可能 高精度だがカスタマイズ設定が必要 APIを利用したプログラミングが必要 あなたのユースケースに最適な音声文字起こしサービスはどれ?主要3社を比較してみた | ネットワンシステムズ ※あくまで公開されている情報や個人の見解に基づいており、モデルや設定によって結果が異なる場合があることにご注意ください。 Speech-to-Textで 期待できること Speech-to-Textは、音声データをリアルタイムまたはバッチ処理で文字起こしする機能を提供します。Speech-to-Textを活用・組み合わせて以下のような期待が持てます。 会議録音の文字起こしでの作業効率化 コールセンターでの問い合わせ分析 動画コンテンツの字幕生成               etc..   検証プロセス ① データ準備 検証に使用するデータは以下の2つです。 音声データ( MP3, FLAC, AMR, LINEAR16 など) 正解データ 音声データから一言一句書き起こしたテキストデータ(手動で作成) 評価を正確に行うため、改行やスペース、句読点(「、」「。」)も含まれていない ② 音声ファイル読み込み 今回はMP3の音声ファイルを読み込んでいます。(Cloud Storageのファイルも利用可能) チャンネルごとに別個の認識: 有効 音声データをアップロードすると自動的にサンプリングレートを割り当てくれます! ③ 音声文字変換のオプション APIバージョン:V1 使用する言語:Japanese 文字起こしモデル:Telephony リージョン:global 文字起こしモデル とは、音声データをテキストデータに変換するAIモデルのことです。Speech-to-Textでは、様々な種類の音声データに対応するために、複数のモデルが用意されています。 今回の検証では、通話録音データに最適化された Telephonyモデル を使用しました。Telephonyモデルは、電話会話特有のノイズや音声品質の変動に強く、通話内容の文字起こしに高い精度を発揮します。 その他モデルについては以下をご参照ください! 音声文字変換モデルを選択する  |  Cloud Speech-to-Text V2 documentation  |  Google Cloud cloud.google.com 詳細設定: 今回は全て無効にしましたが、下記の高度な詳細設定が可能です。 冒とく的な語句フィルタ 句読点入力の自動化 発話された句読点 発話された絵文字 話者ダイアライゼーション 単語の時間オフセット ※2024年12月時点 一部日本語対応していない機能ございます。 今回 カスタム音声モデル の適用はしませんでした。固有名詞や専門用語に対応する場合は、モデルを作成することで、認識精度をさらに向上させることが可能です。 ④ 正解データインポート 文字起こし精度を正しく評価するために、正解データ(音声データの内容を正確に書き起こしたテキストデータ)をインポートします。 今回は、自ら音声ファイルを手打ちで文字起こした正解データを用意しました。この正解データは、文字ベースでの認識制度を図るため、句読点や改行など、実際に話されていない文字は含めていません。 この正解データをSpeech-to-Textにインポートすることで、音声認識結果と正解データを比較し、認識精度を自動で算出することができます。   検証結果 成果 認識精度:約90%以上 文字レベルでの一致率を測定した結果です! 高い精度で文字起こしが可能であることが確認できました! 処理速度:音声データ1分あたり約60秒で処理 (同時実行可能) 非常に高速な処理を実現! 複数ファイル同時実行可能で、手作業に比べて大幅な時間短縮が可能! 観察事項 固有名詞誤認識が一部確認 一部音声ファイルの品質(背景ノイズや録音距離)に依存 今回の検証では、Speech-to-Textが 高い認識精度と処理速度 を持つことが確認できました。実際に私が1分あたりの音声データを一言一句文字起こしすると5分かかりましたので、 約80% の時間削減 が見込まれることになります (※1) 。これにより実際の担当者はより戦略的な業務に時間を活用できます。 今後は、削減された時間で、BigQueryなどのデータ分析基盤と連携し、文字起こしデータを様々な角度から分析することで、顧客対応の質向上や新たなビジネスチャンスの発掘が期待できます! ※1 あくまで一例であり、音声ファイルの品質や内容、オペレーターの習熟度などによって削減時間は変動します。 さらに精度を上げるには? カスタム音声モデルの作成 固有名詞や専門用語を学習させることで、精度を向上させます! 音声品質の改善 マイクの見直しやノイズ環境の調整により、音声データの品質を高め、音声認識の精度を改善します! APIバージョンのアップグレード(V1→V2) 最新バージョン(V2)を使用することで、性能の向上が期待されます!   なぜSCSK? SCSKは、Google Cloudのプレミアパートナーとして、お客様の課題解決に最適なクラウドサービスを選定し、導入から運用までをトータルでサポートします。お客様に寄り添い、長年の経験で培った技術力で、ビジネスの成長を力強く後押しします。 1. 幅広いクラウド技術の知見 Google Cloudはもちろん、AWS、Azureなど、マルチクラウドに対応したエンジニアが多数在籍しています。お客様のニーズやビジネスの特性に合わせて、最適なクラウド環境を構築し、柔軟なシステム基盤を提供いたします。 さらに、SCSK独自のプライベートクラウドサービス「USiZE」も提供しており、パブリッククラウドと組み合わせたハイブリッドクラウド環境の構築も可能です。 2.トータルサポート体制 40年以上にわたるシステム構築・運用実績で培った業界知識と、クラウドに関する高い技術力、そして 2,500名以上の認定技術者 を擁するSCSKだからこそ、お客様のビジネスに最適なクラウド環境を実現できます。 お客様の業界基準やコンプライアンスに準拠した、強固なセキュリティ体制を構築し、ISO 27001認証取得のデータセンターで運用することで、お客様のデータ資産を安全に保護します。 また、お客様のクラウド活用を支援する、幅広いサービスラインナップを取り揃えています。 クラウドサービス 時代の急激な変化に素早く柔軟に対応。キーワード「クラウドサービス」に関する製品・サービス一覧をご覧いただけます。 www.scsk.jp 3. AIの導入実績 AI技術を活用したシステムの導入実績も豊富です。AIチャットボット、需要予測AI、画像認識AIなど、様々な分野で実績があります。お客様のビジネス課題を解決に導く、最適なAIソリューションを提案します。 So-net 様 AI本番導入事例 : コンタクトセンターにてチャットボット、ボイスボットを導入し、オペレーターなしで回答を自動化。オペレーター応対件数を 35%削減 を実現 AI本番システム実装事例集|ダウンロード|クラウド移行だけでは描けない、理想のDXを実現する www.scsk.jp   おわりに いかがでしょうか。今回の検証では、Speech-to-Textが文字起こし作業の大幅な効率化に貢献できることが示されました。特に、 処理速度と認識精度は期待以上 であり、実務での活用に十分耐えうるレベルであると言えます。 Speech-to-Textの導入は、シンプルなUIで、配属1か月の営業担当の私でも たった2日 で使いこなすことができました。ただ、本格的な文字起こし作業を完了するには、APIやSDKを利用したプログラミングが必要になる場合があります。 今後も積極的に技術に触れ、お客様の課題に最適な提案ができる営業を目指します。 本記事をご覧いただき、詳細をご希望の方はお気軽にお問い合わせください!       ※本記事の内容は執筆者個人の見解であり、所属する組織の見解を代表するものではありません。
はじめに 検証でAzure環境とAWS環境をVPN接続した環境が必要となり、以下記事を参考に環境を構築しようとしました。 最低限のコストで、必要な時に作ったり消したりを気軽にできるよう、テンプレート化してみたという記事です。 チュートリアル - ポータルを使用して Azure と アマゾン ウェブ サービス (AWS) 間の BGP 対応接続を構成する - Azure VPN Gateway このチュートリアルでは、アクティブ/アクティブ VPN Gateway と AWS 上の 2 つのサイト間接続を使用して Azure と AWS を接続する方法について説明します。 learn.microsoft.com 上記記事の完全体はアクティブ-アクティブ構成かつ2つのトンネルで構成されていますが、今回はアクティブ-アクティブを無効にしてトンネルを1つだけ構成してます。段階的には成長期です。 一時的な検証用途なので、最低限の構成でつながればいいやという思想です。イメージはこんな感じ。 概要図 図としては、以下のような感じです。 テンプレート テンプレートは3つ用意しています。これはリソース構築後に払い出される値が必要なリソースがあるためです。 例えば、AWS側のカスタマーゲートウェイにAzureのパブリックIPが必要である、とか。 作成の大まかな流れは以下の通りです。 Step 作業項目 備考 Step1:【Azure】NW基盤作成 ①VNet・サブネットの作成 ②Virtual Network Gateway用パブリックIPの作成 対応テンプレート: azure_network_resource.json Step2:【AWS】VPNリソース作成 ①VPC作成 ②カスタマーゲートウェイ作成 ③仮想ネットワークゲートウェイ作成 ④VPN接続作成 ⑤ルート伝搬の有効化 対応テンプレート:aws_vpn_resource.yaml Step3:【Azure】VPNリソース作成 ①Local Network Gateway作成 ②Virtual Network Gateway作成 ③VPN接続作成 対応テンプレート:azure_vpn_resource.json Step1 :【Azure】NW基盤作成 指定しているパラメータ パラメータ名 デフォルト値 備考 vnetName VNet1 作成するVNetの名前 vnetAddressPrefix 10.1.0.0/16 作成するVNetのCIDR範囲 subnet1Prefix 10.1.0.0/24 GatewaySubnetのCIDR範囲 vpnpipName VNet1GWpip パブリックIPの名前 コード ファイル名:azure_network_resource.json {   "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",   "contentVersion": "1.0.0.0",   "metadata": {     "_generator": {       "name": "bicep",       "version": "0.6.18.56646",       "templateHash": "10806234693722113459"     }   },   "parameters": {     "vnetName": {       "type": "string",       "metadata": {           "description": "VNet Name"         },       "defaultValue": "VNet1"     },     "vnetAddressPrefix": {       "type": "string",       "metadata": {           "description": "VNet CIDR range"         },       "defaultValue": "10.1.0.0/16"     },     "subnet1Prefix": {       "type": "string",       "metadata": {           "description": "Gateway Subnet CIDR range"         },       "defaultValue": "10.1.0.0/24"     },      "vpnpipName": {       "type": "string",       "metadata": {           "description": "Public IP Name"         },       "defaultValue": "VNet1GWpip"     }   },   "resources": [     {       "type": "Microsoft.Network/virtualNetworks",       "apiVersion": "2024-05-01",       "name": "[parameters('vnetName')]",       "location": "[resourceGroup().location]",       "properties": {         "addressSpace": {           "addressPrefixes": [             "[parameters('vnetAddressPrefix')]"           ]         },         "subnets": [           {             "name": "GatewaySubnet",             "properties": {               "addressPrefix": "[parameters('subnet1Prefix')]"             }           }         ]       }     },     {       "type": "Microsoft.Network/publicIPAddresses",       "apiVersion": "2024-05-01",       "name": "[parameters('vpnpipName')]",       "location": "[resourceGroup().location]",       "sku": {         "name": "Standard",         "tier": "Regional"       },       "properties": {         "publicIPAllocationMethod": "Static",         "idleTimeoutInMinutes": 4       }     }   ]   } Step2:【AWS】VPNリソース作成 指定しているパラメータ パラメータ名 デフォルト値 備考 myVPCName VPC1 作成するVPCの名前 myVPCCIDR 10.2.0.0/16 作成するVPCのCIDR範囲 VGWName AzureGW 仮想ネットワークゲートウェイの名前 CGWName ToAzureInstance0 カスタマーゲートウェイの名前 VPNConnectionName ToAzureConnection VPN接続の名前 CustomBGPASN 65000 Azure側GatewayのASN azurepip なし Step1で作成したパブリックIPを指定 コード ファイル名:aws_vpn_resource.yaml AWSTemplateFormatVersion: '2010-09-09' Description: Create a Virtual Private Gateway and Customer Gateway Parameters: myVPCName:   Type: String   Default: "VPC1" # VPCの名前 myVPCCIDR:   Type: String   Default: "10.2.0.0/16" # VPCのCIDR範囲 VGWName:   Type: String   Default: "AzureGW" # 仮想ネットワークゲートウェイのリソース名 CGWName:   Type: String   Default: "ToAzureInstance0" # カスタムネットワークゲートウェイのリソース名 VPNConnectionName:   Type: String   Default: "ToAzureConnection" # VPN接続の名前 CustomBGPASN:   Type: Number   Default: 65000 # 任意のASNを入力 azurepip: # スタック作成時にAzure側のパブリックIPを入力する。     Type: String Resources: # VPCの作成 myVPC:   Type: AWS::EC2::VPC   Properties:     CidrBlock: !Ref myVPCCIDR     Tags:       - Key: Name         Value: !Ref myVPCName MyVpcDefaultRouteTable:   Type: AWS::EC2::RouteTable   Properties:     VpcId: !Ref myVPC # 仮想プライベートゲートウェイの作成 VirtualPrivateGateway:   Type: AWS::EC2::VPNGateway   Properties:     Type: ipsec.1     Tags:       - Key: Name           Value: !Ref VGWName   # 仮想プライベートゲートウェイをVPCにアタッチ VPCGatewayAttachment:   Type: AWS::EC2::VPCGatewayAttachment   Properties:     VpcId: !Ref myVPC       VpnGatewayId: !Ref VirtualPrivateGateway # カスタマーゲートウェイの作成 CustomerGateway:   Type: AWS::EC2::CustomerGateway   Properties:     BgpAsn: !Ref CustomBGPASN     IpAddress: !Ref azurepip  # カスタマーゲートウェイのパブリックIPアドレス     Type: ipsec.1     Tags:       - Key: Name         Value: !Ref CGWName   # VPN接続の作成 VPNConnection:   Type: AWS::EC2::VPNConnection   Properties:     Type: ipsec.1     CustomerGatewayId: !Ref CustomerGateway     VpnGatewayId: !Ref VirtualPrivateGateway     StaticRoutesOnly: false  # 動的ルーティングとする。     Tags:       - Key: Name         Value: !Ref VPNConnectionName     VpnTunnelOptionsSpecifications:       - TunnelInsideCidr: "169.254.21.0/30"  # トンネル1の内部IPv4 CIDR         - TunnelInsideCidr: "169.254.22.0/30"  # トンネル2の内部IPv4 CIDR   # ルート伝搬の有効化 EnableRoutePropagation:   Type: AWS::EC2::VPNGatewayRoutePropagation   Properties:     RouteTableIds:       - !Ref MyVpcDefaultRouteTable     VpnGatewayId: !Ref VirtualPrivateGateway     DependsOn: VPCGatewayAttachment Outputs: VirtualPrivateGatewayId:   Description: "The ID of the Virtual Private Gateway"   Value: !Ref VirtualPrivateGateway CustomerGatewayId:   Description: "The ID of the Customer Gateway"     Value: !Ref CustomerGateway VPNConnectionId:   Description: "The ID of the VPN Connection"     Value: !Ref VPNConnection Step3:【Azure】VPNリソース作成 指定しているパラメータ パラメータ名 デフォルト値 備考 myVNet VNet1 Step1で作成したVNetの名前 publicIpName VNet1GWpip Step1で作成したパブリックIPの名前 localNetworkGatewayName lngw_test Local Network Gatewayの名前 asn 64512 AWS側のASN bgpPeeringAddress 169.254.21.1 Local Network GatewayのピアIP customBgpIpAddress 169.254.21.2 Virtual Network GatewayのピアIP virtualNetworkGatewayName vngw_test Virtual Network Gatewayの名前 vngwasn 65000 Azure側のASN gatewaySku VpnGw1 VPN GatewayのSKUを指定 virtualNetworkConnectionName AWSTunnel1toAzureInstance0 VPN接続の名前 gatewayIpAddress なし Step2で作成したVPN接続(トンネル1)のパブリックIPを指定 PreSharedKey なし Step2で作成したVPN接続の事前共有鍵を指定 コード ファイル名:aws_vpn_resource.yaml {   "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",   "contentVersion": "1.0.0.0",   "parameters": {     "myVNet": {       "type": "string",       "metadata": {         "description": "VNet Name"       },       "defaultValue": "VNet1"     },     "publicIpName": {       "type": "string",       "metadata": {         "description": "PublicIPAddress Name"       },       "defaultValue": "VNet1GWpip"     },     "localNetworkGatewayName": {       "type": "string",       "metadata": {         "description": "LocalNetworkGateway Name"       },       "defaultValue": "lngw_test"     },     "asn": {       "type": "int",       "metadata": {         "description": "Autonomous System Number (ASN) for BGP"       },       "defaultValue": 64512     },     "bgpPeeringAddress": {       "type": "string",       "metadata": {         "description": "BGP peering address for LocalNetworkGateway"       },       "defaultValue": "169.254.21.1"     },     "customBgpIpAddress": {       "type": "string",       "metadata": {         "description": "BGP peering address for VirtualNetworkGateway"       },       "defaultValue": "169.254.21.2"     },     "virtualNetworkGatewayName": {       "type": "string",       "metadata": {         "description": "Name of the virtual network gateway"       },       "defaultValue": "vngw_test"     },     "vngwasn": {       "type": "int",       "metadata": {         "description": "Autonomous System Number (ASN) for BGP"       },       "defaultValue": 65000     },         "gatewaySku": {       "type": "string",       "metadata": {         "description": "SKU for the virtual network gateway"       },       "defaultValue": "VpnGw1",       "allowedValues": [         "Basic",         "VpnGw1",         "VpnGw2",         "VpnGw3",         "VpnGw4",         "VpnGw5"       ]     },     "virtualNetworkConnectionName": {       "type": "string",       "metadata": {         "description": "Name of the VPN Connection"       },       "defaultValue": "AWSTunnel1toAzureInstance0"     },     "gatewayIpAddress": {       "type": "string",       "metadata": {           "description": "AWS Public IP Address"         }     },     "PreSharedKey": {       "type": "string",       "metadata": {         "description": "Pre-SharedKey"       }     }   },   "resources": [     {       "type": "Microsoft.Network/localNetworkGateways",       "apiVersion": "2024-05-01",       "name": "[parameters('localNetworkGatewayName')]",       "location": "[resourceGroup().location]",       "properties": {         "gatewayIpAddress": "[parameters('gatewayIpAddress')]",         "bgpSettings": {           "asn": "[parameters('asn')]",           "bgpPeeringAddress": "[parameters('bgpPeeringAddress')]"         }       }     },     {       "type": "Microsoft.Network/virtualNetworkGateways",       "apiVersion": "2024-05-01",       "name": "[parameters('virtualNetworkGatewayName')]",       "location": "[resourceGroup().location]",       "properties": {         "ipConfigurations": [           {             "name": "vnetGatewayConfig",             "properties": {               "privateIPAllocationMethod": "Dynamic",               "subnet": {                 "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('myVNet'), 'GatewaySubnet')]"               },               "publicIPAddress": {                 "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIpName'))]"               }             }           }         ],         "gatewayType": "Vpn",         "vpnType": "RouteBased",         "enableBgp": true,         "activeActive": false,         "sku": {           "name": "[parameters('gatewaySku')]",           "tier": "[parameters('gatewaySku')]"         },         "bgpSettings": {           "asn": "[parameters('vngwasn')]",           "bgpPeeringAddresses": [             {               "ipconfigurationId": "[resourceId('Microsoft.Network/virtualNetworkGateways/ipConfigurations', parameters('virtualNetworkGatewayName'), 'vnetGatewayConfig')]",               "customBgpIpAddresses": [ "[parameters('customBgpIpAddress')]" ]             }           ]         }       }     },     {       "type": "Microsoft.Network/connections",       "apiVersion": "2024-05-01",       "name": "[parameters('virtualNetworkConnectionName')]",       "location": "[resourceGroup().location]",       "dependsOn": [         "[resourceId('Microsoft.Network/virtualNetworkGateways', parameters('virtualNetworkGatewayName'))]",         "[resourceId('Microsoft.Network/localNetworkGateways', parameters('localNetworkGatewayName'))]"       ],       "properties": {         "virtualNetworkGateway1": {           "id": "[resourceId('Microsoft.Network/virtualNetworkGateways', parameters('virtualNetworkGatewayName'))]"         },         "localNetworkGateway2": {           "id": "[resourceId('Microsoft.Network/localNetworkGateways', parameters('localNetworkGatewayName'))]"         },         "connectionType": "IPsec",         "sharedKey": "[parameters('PreSharedKey')]",         "enableBgp": true       }     }   ],   "outputs": {     "localNetworkGatewayId": {       "type": "string",       "value": "[resourceId('Microsoft.Network/localNetworkGateways', parameters('localNetworkGatewayName'))]"     },     "VirtualNetworkGatewayId": {       "type": "string",       "value": "[resourceId('Microsoft.Network/localNetworkGateways', parameters('localNetworkGatewayName'))]"     }   }   } 手順 ここからは上記テンプレートを用いた簡単な構築手順を記載します。なお、細かい画面遷移等は手順を省いていますのでご了承ください。 なお、Azure CLIがインストールされていることが前提となります。インストール手順は以下参照です。 Azure CLI をインストールする方法 Azure CLI は、Windows、macOS、および Linux 環境にインストールできます。 Docker コンテナーおよび Azure Cloud Shell でも実行できます。 learn.microsoft.com リソース構築手順 ①Azure CLIを使うため以下コマンドでAzureにログインします。 az login ②Azure側にリソースグループがない場合は以下コマンドでリソースグループを作成して下さい。 az group create --name <リソースグループ名> --location japaneast ③以下コマンドでAzureリソース(NW関連)をデプロイします。 az deployment group create --resource-group <リソースグループ名> --template-file azure_network_resource.json  デプロイ後、作成したパブリックIPのアドレスを控えます。 ④AWSコンソール画面のCloudFormationよりスタックを作成してください。   テンプレートファイルを読み込ませます。   パラメータとして③で確認したAzure側のパブリックIPアドレスを入力します。   その他はデフォ設定のままスタックを送信すればOKです。 ⑤CloudFormationが正常終了したら、VPN接続画面でトンネルのパブリックIPを確認します。 ⑥また、構成ファイルをダウンロードします。 ダウンロードしたファイル内に事前共有鍵が書かれてるので、後ほど使います。 ⑦最後に以下コマンドでAzureリソース(VPN関連)をデプロイします。 gatewayIpAddressで⑤で確認したパブリックIPを、PreSharedKeyで⑥で確認した事前共有鍵を指定します。 az deployment group create --resource-group <リソースグループ名> --template-file azure_vpn_resource.json --parameters gatewayIpAddress=<⑤で確認したパブリックIP> PreSharedKey=<⑥で確認した事前共有鍵> ➇以下のようになってれば、つながってるはずです。 ※Azure上で仮想VM、AWS上でEC2をたて、疎通できることを確認しました。 【Azure側】 【AWS側】 リソース削除手順 【Azure】 リソースグループを削除することで作成したリソースが全部消えます。以下コマンドを実行ください。 az group delete --name <リソースグループ名> 【AWS】 CloudFormationのスタックを削除することで作成したリソースが全部消えます。   おわりに 以上、AWSとAzureをVPN接続してみた、でした。本当に接続するとこだけしか作ってませんが。。 ちなみに構築全体流すので大体40分くらいかかります。※AzureのVPNリソース作成が30分超かかる。 コンセプトとしてはAzure、AWSに何もない状態で0から作るってことと手数をできるだけ少なくってことを意識しました。 とはいえ、AzureとAWSという異なるプラットフォームから値を引っ張ってくる必要があるので1つのテンプレートにおさめるのは難しく、手順も何ステップかに分かれてるのでもう少し工夫できないかなあと思っているところです。 余裕がでてくればそのうち冒頭のMicrosoft記事の完全体を作れるように…したいところです。
SCSK 岩井です。 前回はRaspberry Pi × 2台でWebサーバの冗長化を行いつつ、LED点灯を行いました。 今回はWebサーバの冗長化を踏襲しつつ、気温/気圧/湿度センサーを使って情報取得部分の冗長化をしてみたいと思います。   Raspberry PiでWebサーバ(冗長構成)を構築 Raspberry Piを2台使ってWebサーバの冗長化を行ってみたいと思います。 blog.usize-tech.com 2025.02.05   下準備 使用するRaspberry Piは前回同様に以下のものです。 【Raspberry Pi 5】 CPU: Broadcom BCM2712 quad-core Arm Cortex A76 processor @ 2.4GHz Memory: 8GB OS: Bookworm 【Raspberry Pi 3 Model B+】 CPU: Broadcom BCM2837B0, Cortex-A53 (ARMv8) 64-bit SoC @ 1.4GHz Memory: 1GB OS: Bookworm この2台にflaskを利用してWeb画面に測定結果を表示する構成を組んでみます。 【追加で用意するもの】 温湿度・気圧センサーモジュールキット(BME280使用) × 2 ジャンパーケーブル×8 ブレッドボード×1 Webサーバアクセス用PC   I2Cの有効化 Raspberry Piとセンサーの通信を行うために、Raspberry Pi側でI2C通信を有効化する必要があります。 コンソールで以下のコマンドを実行します。 ※以下はRaspberry Pi 5のものですが、Raspberry Pi 3も同様に設定します。 sudo raspi-config GUIが立ち上がるので、「3. Interface Options」を選択して[ENTER]キーを押します。 次の画面で「I5 I2C」を選択して[ENTER]キーを押します。 次に確認画面が表示されるので<はい>を選択し、[ENTER]キーを押します。 I2Cが有効化されたメッセージが表示されるので[ENTER]キーを押します。 Raspberry Piを再起動します。   ライブラリのインストール Raspberry PiでBME280センサーからデータを取得するために、前回分に smbus2 および bme280 ライブラリを追加します。 今回はGPIOまわりのライブラリは使用しないため、バージョン差異はありません。 Raspberry Pi 3/5共通で必要になるライブラリになります。また、I2C動作確認のためi2c-toolsライブラリも追加します。 sudo pip3 install smbus2 –break-system-packages sudo pip3 install bme280 –break-system-packages sudo sudo apt-get install i2c-tools sudo pip3 install RPi.bme280 –break-system-packages インストールオプションに「–break-system-packages」をつけないとインストール時にエラーになります。 OSがbookwormとなり、pipの扱いが厳しくなったことが原因のようです。 仮想環境を使用することが推奨されているようですが、今回は「–break-system-packages」で対処します。 また、「bme280」をインストールしているにもかかわらず、スクリプト実行時にライブラリが 見つからないというエラーが発生したため、「RPi.bme280」も併せてインストールしています。   温湿度・気圧センサーモジュールキットとRaspberry Piを接続する ブレッドボードに温湿度・気圧センサーモジュールキットを接続します。 今回もRaspberry Pi 5用とRaspberry Pi 3用に2セット回路を作ります。     次に回路とRaspberry Pi 5、Raspberry Pi 3を接続します。 センサ側 Raspberry Pi 3/5共通 BME280 VDD 3.3V:1ピン BME280 GND GND:9ピン BME280 SDI GPIO2(SDA):3ピン BME280 SCK GPIO3(SDL):5ピン 【Raspberry Pi 5のピン配置】 Raspberry Pi 5 Pinouts including GPIO for the 40 Pin Header – element14 Community 【Raspberry Pi 3のピン配置】 Raspberry Pi 3 Model B GPIO 40 Pin Block Pinout – element14 Community 接続が終わったら、以下のコマンドを実行します。 sudo i2cdetect -y 1 実行結果に「76」という表記があれば、正常に接続できています。   Pythonスクリプトの作成 前回同様にPythonでFlaskアプリケーションをRaspberry Pi 3/5でそれぞれ作成しますが、 内容は同じものとなります。画面に表示される「BME280 センサーデータ」の部分に Raspberry Pi 5は(Unit 1)、 Raspberry Pi 3は(Unit 2)と追記します。 ファイル名はtemp.pyにしてみました。  from flask import Flask, render_template_string  import smbus2  import bme280    app = Flask(__name__)  def read_bme280_data ():   port = 1 address = 0x76   bus = smbus2.SMBus(port)   bme280.load_calibration_params(bus, address)   data = bme280.sample(bus, address)     return {   'temperature' : round (data.temperature, 1 ),   'pressure' : round (data.pressure, 1 ),   'humidity' : round (data.humidity, 1 )   }    @app.route( '/' )  def index (): sensor_data = read_bme280_data()   html = '''   <!DOCTYPE html>   <html lang="ja">   <head>   <meta charset="UTF-8">   <title>センサーデータ</title>   </head>   <body>   <h1>BME280 センサーデータ</h1>   <ul>   <li>温度: {{ data.temperature }} °C</li>   <li>気圧: {{ data.pressure }} hPa</li>   <li>湿度: {{ data.humidity }} %</li>   </ul>   </body>   </html>   '''   return render_template_string(html, data=sensor_data)   if __name__ == '__main__' :   app.run(host= '0.0.0.0' , port= 5000 )   Webサーバの起動(Pythonスクリプトの実行) 各Raspberry Piのコンソールで、Webサーバを起動します。 まずはIPアドレス確認から。  # Raspberry Pi 5/Raspberry Pi 3共通  ip addr 次に各Raspberry PiでWebサーバを起動します。  # Raspberry Pi 5/Raspberry Pi 3共通  python3 temp.py   Webブラウザからアクセス Webサイトアクセス用PCでブラウザを2つ起動し、それぞれ以下のURLにアクセスします。 それぞれセンサーが稼働し、「温度」「気圧」「湿度」が表示されます。 http://Raspberry Pi 5のIPアドレス:5000 http://Raspberry Pi 3のIPアドレス:5000 湿度低め…。   冗長化確認 前回のnginxとkeepallived設定がそのまま残っているので、流用しました。 Webサイトアクセス用PC上のブラウザで仮想IPアドレスのURLにアクセスします。 http://192.168.11.110/ Unit 1の表記があり、Master側(Raspberry Pi 5)のWebサイトにアクセスしていることがわかります。 Raspberry Pi 5をシャットダウンします。 その後上記URLにアクセスするとUnit 2の表記があり、Backup側(Rapberry Pi 3)のWebサイトにアクセスしています。 センサーを稼働させながらシステムの冗長化を実現することができました。 これで片系のRaspberry Piに障害が発生しても測定を継続させることができるようになりました。
ServiceNowの生成AI機能であるNow Assist for IT Service Management(ITSM)を調べたので、学んだ内容を記事にします。 本記事は執筆時点(2025年2月)の情報です。最新の情報は製品ドキュメントを参考にしてください。   はじめに Now Assistは2023年に登場して以降、ITSMやCSM、FSM、HRSDなどなど、その対応領域はどんどん拡大されています。 今回はその中でも、ITSMの領域におけるNow Assistの機能について調べました。 仮想エージェント/ライブエージェントのチャットにおけるNow Assistの利用 仮想エージェント(Virtual Agent) ユーザーの質問や課題、要求に自動で応答し、24時間利用可能なセルフサービスを提供するチャットボット機能です。 ライブエージェント(Live Agent) ユーザーの課題が複雑で仮想エージェントによる解決ができなかった場合、ライブエージェントに接続することでオペレーター(エージェント)とチャット上で直接会話することができます。 チャット要約(Chat summarization) ユーザーが仮想エージェント、またはライブエージェントとチャット上で会話していた内容を要約する機能です。 ライブエージェントとしてユーザーからの問い合わせ対応をするオペレーターには以下のメリットがあると感じました。 ユーザーと仮想エージェント間のチャット要約を確認することで、ユーザーの問い合わせ内容・要件を素早く把握することができる ライブエージェントが異なるオペレーターにエスカレーションされた際、ユーザーと前担当者間でのやり取りを素早く把握し、スムーズに引継ぎを行うことができる 結果、ユーザーにとっても問合せの解決までにかかる時間の短縮が期待できます。 チャット返信内容のレコメンド(Chat reply recommendation) ライブエージェントとしてチャット上でユーザーと会話する際、返信内容を自動生成してレコメンドしてくれる機能です。 動作検証 まずは、エンドユーザーとして「ネットワークの調子が悪い」「ルーターが赤く点滅している」「ルーターを交換したい」など自身の抱えている課題を仮想エージェントに問い合わせます。 その後、仮想エージェントによる解決はできなかったという想定で、ライブエージェントへと接続します。 以降は、Service Operations Workspaceにおけるオペレータの操作画面となります。 エンドユーザーからのライブエージェント接続依頼がオペレーターに届いたので「オープン」をクリックしチャットを開始します。 チャットが開始されると、Now Assistによりそれまでにエンドユーザーと仮想エージェントの会話内容が要約されて表示されます。(赤枠) これによりオペレーターは、チャットを遡ることなしに、ユーザーの問い合わせ内容を素早くキャッチアップできます。 以下画像の赤枠部分は、Now Assistによるチャット返信のレコメンドになります。 エンドユーザーが入力したコメントを踏まえて、返信内容を自動生成しレコメンドしてくれます。 オペレーターは必要に応じて、文章を修正してエンドユーザーに返信することが可能です。 問合せ内容が自分自身の担当領域外で解決方法が分からない為、他のオペレーターへとエスカレーションすることにします。 /taというショートカットを使うことで、他のオペレーターへとチャットをエスカレーションできます。 別のオペレーターにエスカレーションの通知が届いたので、「承認」をクリックしてエンドユーザーとのチャットを開始します。 チャットが開始されると、エンドユーザーと仮想エージェント、及び、前担当者とのやり取り内容がNow Assistにより要約されて表示されます。(赤枠) エスカレーション先のオペレーターは、ユーザーの抱える課題、状況を素早くキャッチアップできます。 最終的に解決方法を提示して、チャットを終了します。   おわりに 本記事では、仮想エージェント、ライブエージェントにおけるNow Assistの機能を記載しました。 要約によりオペレーターの状況把握にかかる時間が短縮され、結果エンドユーザーの課題解決までの時間も短縮が期待できる機能だと思いました。 次回は、インシデント対応におけるNow Assistの機能をまとめていきたいと思います。
SCSKの畑です。 前回のエントリ で触れたアプリケーションにおいて、どのようにテーブルデータを保持していたかに関する補足的内容となります。小ネタです。   アーキテクチャ図 懲りずにいつものやつを。今回のメインは Amazon Redshift、Amazon DynamoDB、Amazon S3 あたりです。   テーブルデータメンテナンス機能要件のおさらい 最初に、改めてテーブルデータメンテナンスの要件を記載します。他、対象テーブルを所管する組織(= Cognito グループ)に属しているユーザのみデータ編集が可能となるような権限管理関連の要件もありましたが、本題にはあまり関係ないので割愛します。 メンテナンス対象テーブルデータの更新機能(≒DML操作) テーブル定義の変更(≒DDL操作)は対象外 テーブル定義の変更時は直接 Redshift に SQL を実行する想定 テーブルのバージョン管理機能  過去バージョンのデータ参照や、バージョン間のデータ比較が可能(テーブル定義が同一の場合のみ) テーブルデータ/定義どちらの変更があった場合でも、新しいバージョンと見なして管理 アプリケーション経由でテーブルデータを更新する際の簡易ワークフロー機能 別ユーザによる承認を以って、Redshift 側に編集したデータの更新が反映される 以上より、こちらも前回のエントリで記載した内容を含みますが、以下2点をアーキテクチャ設計で考慮する必要がありました。 1. より、テーブル定義の変更が行われてもシステム側で柔軟に対応できる必要がありました。また、テーブル定義の変更(≒DDL操作)についてはアプリケーションのスコープ外である以上、アプリケーション外での更新も取り込むことを考慮しておく必要がありました。 2. 及び 3. より、過去バージョンのデータや編集後の承認待ち一時データを保管しておく領域が必要になりました。また、1点目の内容より、アプリケーション外でのテーブル定義の変更に柔軟に対応できることが望ましかったです。 以上を踏まえて、どのようにこの領域を用意するかを検討していました。   第一候補:DynamoDB 当初は DynamoDB を使用する予定でした。 元々アプリケーションマスタとして DynamoDB を使用する予定だったため相乗りすればアーキテクチャとしてもシンプルですし、メンテナンス対象テーブルの編集ステータス管理なども担う都合上、合わせて実データも持てれば利便性もあるのではないかと考えました。また、実は DynamoDB って Redshift と COPY/UNLOAD 文によりテーブルと直接データの入出力ができることを知り、そういう意味でも親和性高いのではないかと。 下記 URL の通り、実は Redshift と COPY/UNLOAD 文で外部ファイル内のデータをやり取りをできるサービスは限定されており、DynamoDB はその一つです。一番ベーシックなのは S3 ですね。 COPY - Amazon Redshift データファイルまたは Amazon DynamoDB テーブルから、テーブルにデータをロードします。ファイルは Amazon Simple Storage Service (Amazon S3) バケット、Amazon EMR クラスターま... docs.aws.amazon.com UNLOAD - Amazon Redshift クエリの結果を、Amazon Simple Storage Service (Amazon S3) の 1 つ以上のファイルにアンロードします。 docs.aws.amazon.com ただ、DynamoDB 上でテーブル自体を保持するようにした場合、表定義の変更にどう対応するのかが課題となりました。実質的に Redshift との二重管理になってしまうため、Redshift 側での表定義変更時にどう対応するかが難しいと感じました。表定義変更自体はアプリケーション側のロジックで検知できるものの、そもそも KVS と RDBMS で根幹の仕組みも異なるため KVS 側で対応していない部分をどのように実装するかが悩ましく。例えば、DynamoDB におけるテーブルのパーティションキー/ソートキーの変更がある場合はテーブルの再作成が必要となりますが、特に UNLOAD の場合にそのようなケースに該当した場合の対応などです。 そもそも、お客さんの AWS 環境における DynamoDB のテーブルの作成/削除の権限がもらえていないというより根本的な問題もあったのですが、仮にこのアーキテクチャで行くと確定していた場合は交渉していたかと思います。それでも NG だった場合は対応を諦めざるを得なかったですが。 このため、対応の柔軟性を考えて DynamoDB のテーブルとしてデータを保持するのではなく、テーブル定義やデータ自体をテーブルの絡む(項目)内に持ってしまうような構成に変更しようとしたのですが、1項目の最大データサイズが 400KB であったため、データ自体を1項目に入れてしまうのは無理だと諦めました。当時はテーブルデータを圧縮する想定がなかったということもありますが、どちらにせよ足りなかったです。それ以前に設計としては無理矢理感があって良くなかったと思うので、結果的には断念することになって良かったと思っていますが・・   第二候補(決定):S3 ということで、DynamoDB 以外ということで丸い選択と考えると、ほぼ必然的に S3 を使用することになった感じです。S3 上に配置したファイル経由で COPY/UNLOAD 文により Redshift とデータ入出力が可能なこと、実質的にファイル単位で情報を保持することになる以上、DynamoDB の項目に記載したような問題が発生しない、の2点が主な理由です。 最も後者については、その分アプリケーション側での実装が必要になるとも言えるのですが、DynamoDB も KVS である以上 RDBMS との機能差異があるため、結果的にそこまでアプリケーションの実装をカバーできなかったのではないかと。 どのような実装がアプリケーション側になったかの詳細については、また別のエントリで書こうと思います。 また、一時テーブルデータや古いバージョンのテーブルデータを世代管理・ハウスキーピングするにあたり、S3 のライフサイクル機能や既存の S3 ハウスキーピング用 Lambda 関数を使い回せるという点もありました。最も、DynamoDB は TTL 設定ができるため、ある程度は代用できるところもあったとは思いますが。 最後に、どのようなファイル構成で Redshift のテーブルを扱っているかを簡単に説明して終わりたいと思います。現在は、下記3種類のファイルをテーブル単位でそれぞれ扱っており、これらの情報を組み合わせてアプリケーション上でテーブルデータを表示しています。 テーブル列定義ファイル 列名(論理名・物理名)やデータ型などの情報を扱っています。 論理名は別情報として定義されているコメントを結合して持ってくるようにしています。 テーブル制約定義ファイル 各制約(PK・UK・FKなど)の情報を扱っています。 SQL 文を含む内容の詳細は 5回目のエントリ を参照ください。 テーブルデータファイル 7回目のエントリ で記載した通り、Redshift と COPY/UNLOAD 文によりテーブルと直接データの入出力を行うため、同 SQL 文で直接扱える JSON Line 形式でファイルを保持するようにしています。 AppSync/Lambda とアプリケーション間でデータをやり取りする際には、AppSync の最大ペイロードサイズを考慮してデータを圧縮するようにしています。 上記のようなファイル構成として扱うことで、Redshift 上のテーブルの定義やデータが変更された場合もアプリケーション側の実装含めて柔軟に対応できるようにしています。また、テーブルのバージョン管理をするにあたり、実質的には Redshift 上のテーブルデータ/定義と、アプリケーションが認識している最新のテーブルデータ/定義(=S3上のテーブルデータ/定義)間の変更有無を検出できる必要がありますが、この仕組みにすることでファイルの内容を精緻に比較することなく、ファイルのハッシュ値のみで比較できるようになったというのも利点の一つでした。もちろん、そのように比較できるように SQL 文を書く必要はありましたが、実装面では幾分楽ができました。   まとめ 今回は正に前回エントリの補足というかそれに関連した小ネタでしたが、まだこのような内容はいくつかあるため、今後も既存のエントリの内容を補完する形で投稿していければと思います。 本記事がどなたかの役に立てば幸いです。
こんにちは。ひるたんぬです。 突然ですが、皆さんはシャツを着る時に後ろ前をどのように判断していますか? 一般的な判断基準としては首の部分の形状(Vネックやボタンが付いている場合は分かりやすいですよね)や、首の部分についているブランドのタグで判断される方もいらっしゃるのでは無いでしょうか。 ただ、この場合ですと、シャツの首周りを確認するために、わざわざシャツの向きを変えたり、整えたりする必要がありますよね(語彙力が乏しく…通じますかね?)。小さなことですが、大変な作業だよなぁ…と私は勝手に思っています。 私はシャツの裏側についている洗濯表示のタグの位置で判断しています。実は、洗濯表示のタグは必ずと言っていいほど左についているんです¹。 これにより、着る前にシャツの向きを変えることなく、下から裏の洗濯タグの位置を確認し、着ることができます。 少し時短することができました。嬉しいですね。 ¹ 私の人生経験上では左側にしかついていなかったのですが、明確にルールや取り決めなどは無いようです。右側の服が増えたらどうしよう… 参考: 洋服のタグ | さくら中央税理士法人 さて、今回は生成AIを利用するにあたって、ハルシネーションを起こしにくくする手法の一つであるRAGについて、個人的に気になったことがあったので検証してみました。 本記事はあくまで一個人が検証目的で行ったもので、後述する 結果の再現性を保証するものではありません 。 参考程度に捉えていただけますと幸いです。 気になったこと 先述した通り、RAGは生成AIのハルシネーションを起こしにくくするための手法の一つであり、昨今「ハルシネーションを防ぐにはRAGを導入しましょう!」と言ったことをよく耳にしていました。 そこで、私は「RAGの情報そのものがLLMにて学習していた事前知識と矛盾する場合や、RAGの情報内で矛盾していた場合どういう結果になるのだろうか…?」と思い、今回の検証を実施することにしました。 一個人の見解ですが、私は 厳密な事実を求める目的 に生成AIを利用するのは、現時点では否定的な立場です。LLMの性質上、確率に基づいて解を生成しているため、そこには多かれ少なかれ、誤りが発生してしまうことは構造上防げないと考えています。 ※ 今後大きなブレイクスルーが起こった場合はこの限りではありません。 ※ LLMの構造に興味がある方は、 こちら がとても参考になります。 テストケース 上記を整理すると、今回は以下のようなテストケースが考えられます。 今回は知りたいことを”A”, “B”とし、解を”V, W, X, Y, Z”で表しています。また”−”はその情報を持ち合わせていない・与えないことを表します。 パターン LLMの事前知識 RAGの情報① RAGの情報② ①-a A = Z − − ①-b A = Z A = Y − ①-c A = Z A = Y A = X ②-a − B = W − ②-b − B = W B = V パターン①は、LLMの事前知識がある場合、②はない場合です。 また、各パターンの”a”は、一般的な(正しい)使い方の結果を想定しています。 LLMの事前知識の有無は、LLMからの回答をもって判断するものとします。   事前準備 RAG環境の準備 今回の検証を実施するにあたり、RAGの構築が必須となります。今回は比較検証がメインとなるため、RAGの構築につきましては、下記記事を参考に実施しました。 AWSの生成AIで社内文書検索! Bedrockのナレッジベースで簡単にRAGアプリを作ってみよう - Qiita 生成AI、流行ってますね!今みんながやってる「社内文書検索」アプリ、いわゆるRAGアーキテクチャをAWSで簡単に作ってみましょう。1時間程度でサクッと試せるハンズオンです。2025/1/14更新… qiita.com …特に大きな懸念もなく構築することができました。 なお、今回は複数のケースで独立したRAG(ナレッジベース)を作成する必要があるため、バケット内のケースごとにフォルダを分割し、それぞれでナレッジベースを作成しました。 パターン①の題材決め パターン①では、Aというものに対して、既知の解Zと、矛盾する解X, Yを用意する必要があります。 今回はAをりんごとし、Zを果物と定義することにします。そして矛盾する解はそれぞれ「X = 魚類」「Y = 肉類」とします。 数学の定義上、「りんご = 果物」ではなく、「りんご ∈ 果物」と記載することが適切ですが、今回はその厳密性についてはご容赦ください。 パターン②の題材決め パターン②では、LLMがまだ知らない事象について確認する必要があります。 今回は架空の何か「えよぴんぷ」を作り出し、矛盾する解「V = 日本の郷土料理」「W = SCSKの社員」とします。 事前確認としてLLMに「えよぴんぷ」を知っているか確認も取ります。 知らないと答えてくれました。念の為、郷土料理やSCSKの社員か聞いても知らないか確認をします。 知らなかったですね。良かったです。 造語を作って聞いてみてもハルシネーションが多く、この返答を出してくれる単語を創作するのが実は一番大変でした。半濁音が多いのはなんとなく、です。 RAGに与える資料作り 今回は各要素について、「りんごは果物です。」等といった記述のみをした文書ファイルをそれぞれ作成し、与えることにします。 一例を以下に添付します。 これだけのPDFファイルも中々シュールです。   検証 準備も整ったので、一つずつ検証をしてみましょう。 パターン①-a まずは、既知の情報のみでの確認です。シンプルな質問で確認をします。 ▼ A = Z の確認 ▼ A ≠ X の確認 ▼ A ≠ Y の確認 ▼ Aが「X, Y, Z」のどれに該当するかの確認 …もちろん正しいです。 パターン①-b 続いて、矛盾する情報を一つ与えた場合について確認をしてみます。 ★ 「A = Z」と「A = Y」の情報を持っている場合です。 ▼ AとZの関係 ▼ AとXの関係 ▼ AとYの関係 ▼ Aが「X, Y, Z」のどれに該当するかの確認 …LLMは自身に「常識」を持っており、それと照らし合わせて判断していることが伺えました。 常識を基に、矛盾した情報に惑わされることなく「りんごは果物である」という事実を一貫して述べています。 パターン①-c 更に矛盾する情報を与えた場合の確認です。 ★ 「A = Z」と「A = Y」「A = Z」の情報を持っている場合です。 ▼ AとZの関係 ▼ AとXの関係 ▼ AとYの関係 ▼ Aが「X, Y, Z」のどれに該当するかの確認 パターン①-bと同じように、「りんごは果物である」というLLMの主張は変わりませんでした。 また、ナレッジベースの情報に矛盾があるということも指摘してきました。 パターン②-a ここからは、LLMに事前知識がない場合の検証です。 ★ 「B = W」の情報のみを持っている場合です。 ▼ BとWの関係 ▼ BとVの関係 ▼ Bが「V, W」のどれに該当するかの確認 きちんとRAGが動作し、えよぴんぷがSCSKの社員であることを答えてくれました。 料理にならなくて安心しました。 パターン②-b 更にLLMに矛盾した情報を与えてみましょう。 ★ 「B = W」と「B = V」の情報を持っている場合です。 ▼ BとWの関係 ▼ BとVの関係 ▼ Bが「V, W」のどれに該当するかの確認 ここで、BとWの関係について、一方のみの情報で解を出す事例がありました。 何回か聞いてみましたが、この状況は変わりませんでした。 そこで、BとVの関係についても何度か質問してみたところ、以下のような回答を出すことがありました。   まとめ 今回の検証の結果をまとめます。 パターン LLMの事前知識 RAGの情報① RAGの情報② 結果 ①-a A = Z − − A = Z のみ出力 ①-b A = Z A = Y − A = Z のみ出力 A = Y は誤った情報と回答 ①-c A = Z A = Y A = X A = Z のみ出力 A = X, Y は誤った情報・矛盾していると回答 ②-a − B = W − B = W のみ出力 ②-b − B = W B = V 結果が安定せず   考察・今後に向けて ここからは私個人の完全なる推測です。 今回は、ナレッジベースに与える情報として、「AはYです。」といった事実のみ与えました。 そのため、パターン①のように事前知識がある場合、情報量が少ないナレッジベースの内容は虚偽として捉えられた可能性が高いです。 一方、パターン②のようにLLMが事前確認として持ち合わせていない事象に対しては、情報量が(恐らく)等しい事象を与えたため、LLMが判断に迷い、様々な結果が出力されたと考えています。 今後はパターン①に対抗するため、事前知識に対抗しうる情報量をナレッジベースに与えた場合や、パターン②において情報量に偏りをもたせた場合の挙動について調査をすると、また面白い結果が出るのかなと感じた次第です。   おわりに この記事を執筆していると、ほんの少しですが学生時代の研究生活を思い出しました。(今回の検証は、厳密性・再現性の観点から見ると本当にお遊び程度ですが…) この内容についても学術的に研究されている論文もあります(アーカイブですが)ので、興味がある方は読んでみると面白いかもしれません。私も少しだけですが読みました。 ※ 今回の検証結果の一部は、下記論文の内容とも合致していました。 https://arxiv.org/pdf/2305.13300 arxiv.org
本記事は、以下記事の続編です。 Amazon Nova を触ってみた (テキスト生成編) 昨年のre:Invent 2024にて、Amazon Bedrockでのみ利用可能なモデルとしてAmazon Novaが発表されました。本記事では、Amazon Novaシリーズの中でテキスト生成が可能な3つのモデル(Micro、Lite、Pro)についてまとめました。Amazon BedrockマネジメントコンソールとConverse APIから実行する方法をご紹介します。 blog.usize-tech.com 2025.01.29 本記事では、画像生成モデルAmazon Nova Canvas、動画生成モデルAmazon Nova Reelについてまとめました。 Amazon Novaとは? Amazon Novaは、フルマネージドサービスであるAmazon Bedrockにて利用可能な、Amazonが開発したモデルです。 テキストや画像、動画をプロンプトとして与えることにより、テキスト生成だけでなく、画像生成や動画生成も可能です。 本記事投稿時点では、Canvas、Reelはバージニア北部でのみ利用可能です。 Amazon Nova Canvas テキストからの画像生成はもちろんのこと、既存の画像をもとに新たな画像を生成できるマルチモーダルなモデルです。 画像のある部分だけを別の画像へ置換、画像の特徴を維持したまま別のバリエーションで再生成、背景の削除など簡単な画像編集も可能です。 Amazon Novaユーザーガイドには、英語のみ対応と記載されていますが、実際には日本語にも対応しているようです。 入力形式 テキスト、画像 最大入力文字数 1024 最大入力画像サイズ 25MB サポートされている画像入力形式 PNG、JPEG 最大入力画像サイズ 25MB 画像1枚あたりの料金 (解像度1024×1024まで) USD 0.04 画像1枚あたりの料金 (解像度2048×2048まで) USD 0.06 Amazon Nova Reel テキストや画像から動画を生成できる動画生成モデルです。 本記事執筆時点では、最大6秒間の動画を生成できますが今後のアップデートにより、最大2分間の動画生成、高解像度への対応、ストーリボード機能による複数シーンの統合などがアナウンスされています。 また、Canvas同様にReelも日本語に対応しています。 入力形式 テキスト、画像 最大入力文字数 512 最大入力画像サイズ 25MB 解像度 1280×720 フレームレート 24fps 生成動画の長さ 最大6秒まで 生成された動画1秒あたりの料金 USD 0.08 実際に触ってみる モデルアクセス有効化 まずはモデルアクセスを有効化します。 リージョンをバージニア北部に変更し、Bedrockのメニューから「モデルアクセス」をクリックします。 以下のような画面が表示されたら「特定のモデルを有効にする」をクリックします。 「Nova Canvas」、「Nova Reel」にチェックを入れて「次へ」をクリックします。 「送信」をクリックします。 アクセスのステータスが「アクセスが付与されました」となっていればモデルアクセス有効化完了です。 Amazon Nova Canvasを使ってみる 「モデルを選択」をクリックします。 「Nova Canvas」を選択して「適用」をクリックします。   左側の設定では実行するアクションや生成する画像のサイズ、枚数、色の指定などが可能です。 「3匹の犬が公園で遊んでいる画像」をリクエストしてみます。 画像の一部を変更したい場合は、「バリエーションを生成」を選択して、プロンプトに変更内容を入力すると新たな画像が生成されます。生成された画像にばらつきはあるもののリクエスト通り毛並みが茶色になりました。 次は左側に写っている犬を画像から削除したいと思います。 「オブジェクトを削除」を選択すると青白い枠が表示されるので、削除したいオブジェクトを枠で囲みます。 リクエストどおりに左側に写っている犬が削除されました。 また、「背景を削除」を実行すると簡単にPNG透過された画像を生成できます。 Amazon Nova Reelを使ってみる 続いて動画生成をやってみます。まずはモデルを「Nova Reel」に変更します。 プロンプトを入力して実行すると生成が開始しました。 動画は5分ほどで生成され、左側に表示されているS3に保存されます。 可愛いわんちゃんが遊んでいる動画が生成されましたが、あまり動きがなく背景だけ動いている動画になってしまったのが少し残念です。。。 document.createElement('video'); https://blog.usize-tech.com/contents/uploads/2025/02/output.mp4 最後に先ほどCanvasで作成したこちらの画像をもとに動画を作成してみたいと思います。 散歩している動画をリクエストしたのですが、先頭の1匹だけが動いている動画が生成されました。。。 プロンプトを1文で記載していることも影響しているとは思いますが、精度が課題かもしれません。 https://blog.usize-tech.com/contents/uploads/2025/02/output-1.mp4 まとめ Amazon Novaシリーズの中で画像と動画生成が可能な2つのモデルについてまとめました。 画像は10秒程度、動画は5分程度で簡単に作成できる魅力的な生成モデルと感じました。 プロンプトやパラメータの調整、入力に画像を利用するなどの工夫で生成精度を上げることができれば、広告やプレゼンテーションなどに活用できる可能性もあると思います。 まだリリースされたばかりのモデルであり、今後のアップデートも発表されているので楽しみに待ちたいと思います。
Google Cloud環境では、多くの方がデータの保存や共有のためにCloud Storageサービスを利用していると思います。特に、データアーカイブやログ保管の用途でCloud Storageを使用する際には、データの世代管理など非機能要件の検討が重要だと思います。 今回は、先日Cloud Storageバケット使用時に、世代管理の設定を行った際の実装方法を振り返るとともに、CLIでの実装方法を整理してみたいと思います。 概要 まず、バケットの世代管理には、 バージョニング と ライフサイクル という機能が必要となります。 それぞれの機能について説明します。 バージョニングとは Cloud Storageバケット内でオブジェクトの異なるバージョンを保持する機能です。バージョニングを有効にすると、オブジェクトを上書きまたは削除した場合でも、過去のバージョンを非現行バージョンのオブジェクトとして保持し、必要に応じて復元することができます。バージョニングを使うことで、データの誤削除や意図しない変更から保護できます。 詳しくは、以下をご確認ください。 オブジェクトのバージョニング  |  Cloud Storage  |  Google Cloud cloud.google.com ライフサイクルとは Cloud Storageバケット内のオブジェクトについて自動管理するためのルールを設定する機能です。経過日数やオブジェクトのバージョン数など、特定の条件に応じてストレージクラスを変更したり、オブジェクトを削除したりできます。これにより、コストの最適化やストレージ管理の効率化が実現できます。 詳しくは、以下をご確認ください。 オブジェクトのライフサイクル管理  |  Cloud Storage  |  Google Cloud cloud.google.com よって世代管理の実現のためには、バージョニングの有効化と非現行バージョンの扱い方のルール設定を組み合わせることが重要です。   実装例 以下にて、CLIを使用した設定方法を示します。 バージョニングおよびライフサイクルの設定は、バケット単位で行います。 ①バージョニング有効化 以下のコマンドでバージョニングの有効化をします。 ※デフォルトではバージョニングの設定はオフになっています   gcloud storage buckets update gs://[バケット名] --versioning   例: $ gcloud storage buckets update gs://test-generation-management --versioning ⠼Updating gs://test-generation-management/... Completed 1   ②バージョニング有効化の確認 以下のコマンドでバージョニングの有効化を確認できます。   gcloud storage buckets describe gs://[バケット名] --format="default(versioning_enabled)"   例: $ gcloud storage buckets describe gs://test-generation-management --format="default(versioning_enabled)" versioning_enabled: true   ③ライフサイクルルールの作成 適用するライフサイクルルールを含むJSONファイルを作成します。 今回は、 「新しいバージョンを3つ保持しつつ、非現行バージョンとなってから1日経過したオブジェクトを削除する(削除対象は非現行バージョンのみ)」 という条件でルールを設定します。 (例)test-lifecycle.json { "lifecycle": { "rule": [ { "action": {"type": "Delete"}, "condition": { "daysSinceNoncurrentTime": 1, "isLive": false, "numNewerVersions": 3 } } ] } }   なお、設定したいライフサイクルルールのアクションやオブジェクトの条件についての詳細は以下のサイトをご確認ください。 オブジェクトのライフサイクル管理  |  Cloud Storage  |  Google Cloud cloud.google.com   注意点 条件の設定方法で、削除が行われるタイミングや対象が異なりますのでご注意ください。 { "lifecycle": { "rule": [ { "action": {"type": "Delete"}, "condition": { "numNewerVersions": 3, "isLive": false } }, { "action": {"type": "Delete"}, "condition": { "daysSinceNoncurrentTime": 1 } } ] } }   例として、先述した「test-lifecycle.json」では、記述しているすべての条件を満たした場合にのみルールが実行されますが、上記のようにルールを設定すると、各条件が独立しているため、どちらかの条件を満たすだけでルールが実行されます。つまり、保持したい新しいバージョンの数に限らず1日経過すると すべてのオブジェクトが削除対象 となってしまいます。   ④ライフサイクルルールの適用 以下のコマンドで、作成したJSONファイルを使用してライフサイクルルールを適用します。   gcloud storage buckets update gs://[バケット名] --lifecycle-file=[手順③で作成したJSONファイルのパス]   例: $ gcloud storage buckets update gs://test-generation-management --lifecycle-file=test-lifecycle.json ⠶Updating gs://test-generation-management/... Completed 1   ⑤ライフサイクルルール適用の確認 以下のコマンドでライフサイクルルールの適用を確認できます。   gcloud storage buckets describe gs://[バケット名] --format="default(lifecycle_config)"   例: $ gcloud storage buckets describe gs://test-generation-management --format="default(lifecycle_config)" lifecycle_config: rule: - action: type: Delete condition: daysSinceNoncurrentTime: 1 isLive: false numNewerVersions: 3   最後に バージョニングとライフサイクルの設定は、一見簡単に思えるかもしれませんが、実際に設定を行う際には詳細な条件設定が必要であり、意外と複雑です。適切な条件を設定することで、効果的なデータ管理と保護につなげることができると思います。 また、今回はGoogle CloudのCloud Storageバケットの世代管理について整理しましたが、AWSのストレージサービスであるS3バケットでも同様に、世代管理の設定が可能です。S3のライフサイクルルールでも JSONファイルを使用して設定を行い、CLIでルールを適用できます。 ただし、それぞれのアクションの選択肢や詳細な条件設定の方法には違いがあります。たとえば、S3ではオブジェクトタグを使って、特定のタグが付けられたオブジェクトに対してのみのライフサイクルルールの 適用が可能です 。一方、Cloud Storageでは現時点でタグを使用したフィルタリングオプションはありません。また、S3では非現行バージョンに対する制御がアクションの一部として設定できるのに対し、Cloud Storageでは非現行バージョンを条件の一部として設定するため、オブジェクトの制御方法が異なります。 このような違いを理解し、両方のクラウド環境でのストレージサービスの世代管理に柔軟に対応できるようにすることも重要だと思いました。 この記事が、Cloud Storageをストレージ先として選択する際や、非機能要件に基づくバケット管理方法の検討時の参考となり、 スムーズな設計と構築のお役に立てれば嬉しいです。