TECH PLAY

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

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

1268

本記事は 夏休みクラウド自由研究 8/29付の記事です 。 こんにちは あるいは こんばんは SCSKの猿橋です。 パリオリンピックの興奮冷めやらぬ2024年現在、AIといえば生成AIが全盛ですが、特定のユースケースではMLのカスタムモデルを活用するケースもあるかと思います。 カスタムモデルを構築するには機械学習の知識やノウハウ、実装スキルが必要になりますが、Amazon SageMaker Canvasを活用すれば、ノーコードでモデル構築が可能となります。 今回はAWSのハンズオンを通じてAmazon SageMaker Canvasを試してみました。 ノーコード機械学習 — Amazon SageMaker Canvas — AWS Amazon SageMaker Canvas は、ビジネスアナリストが ML の経験がなくても、非常に正確な機械学習モデルを作成できるように、コーディング不要の ML インターフェイスを提供しています。 aws.amazon.com AWS Hands-on for Beginners Amazon SageMaker Canvas 〜 ノーコードで機械学習を始めよう 〜 | AWS Webinar AWS Hands-on for Beginners Amazon SageMaker Canvas 〜 ノーコードで機械学習を始めよう 〜 | AWS Webinar pages.awscloud.com はじめる前に Amazon SageMaker Canvasは使用時間課金になります。 左下にLogoutボタンがあり、使用しないときはLogoutをすることで課金を止めることができるようですので、 忘れずLogout しておきましょう。 ワークスペースインスタンス (セッション-時間) の料金 1.9 USD/時間 ノーコード機械学習 - Amazon SageMaker Canvas の料金 - AWS ビジネスアナリストが機械学習 (ML) モデルを構築し、予測を生成するためのノーコードサービス、Amazon SageMaker Canvas の料金をご覧ください。 aws.amazon.com Amazon SageMaker Canvasのセッションはブラウザを閉じたりAWSコンソールからログアウトするセッションとは独立しているようで、それでは課金が止まらないようです。ブラウザを閉じる前に確実にLogoutしましょう。 定期的に意図しない課金が発生していないか、コンソールのホームに表示される「コストと使用状況」でチェックしておくのもよいでしょう。   機械学習におけるAmazon SageMaker Canvasの活用シーン 機械学習を活用するにあたり、以下の課題があるとハンズオンの中で挙げられています。 機械学習の実用化には時間がかかり、コーディングと知識が必要 機械学習のニーズは増える一方で、データサイエンスチームはフル稼働 ビジネスアナリストは、機械学習の知識不足で短時間での習得は困難 ステークホルダー間でのコラボレーションは機械学習モデルの信頼性を高めるが、一般的なツールは単一ワークスペースで、機械学習テクニカル知識を求める単一ワークスペース環境 機械学習を活用するには専門的な知識が求められますが、そういった人材を育てたり確保したりすることが簡単ではない、ということも背景にありそうです。 そのような状況の中でも、ビジネス課題に対して機械学習でのソリューションを試してみたい、という場合に、ノーコードで機械学習を活用できるAmazon SageMaker Canvasがビジネスの現場で活用シーンがでてくるわけですね。   Amazon SageMaker Canvas環境作成 それではハンズオンを始めてみます。 まずは「SageMakerドメインを作成」ボタンでドメイン作成を開始します。 今回はクイックセットアップを活用することで、ドメインとユーザープロファイルの作成ができました。 作成されたプロファイルの横にある起動ボタンでCanvasを起動します。 Canvasが起動できました ハンズオン動画ではドメイン作成時にドメインとユーザープロファイルの入力ができますが、2024/6現在のクイックセットアップではそれぞれ自動設定されるようです 後続のデータセットインポートでトラブルになるのですが、ハンズオンではドメイン作成時にIAMロールにAmazon S3へのアップロード権限を付与していました。現在クイックセットアップを選んでしまうとその手順ができなさそうなので、後で権限を付与するか、その他の方法でデータセットをアップロードする必要がありそうです(手順は後述)   データの投入 環境構築が完了してCanvasが起動できたら、次はデータの投入です。 今回のハンズオンのユースケースとしては、以下のようなテーマ設定になっていました。 ■ユースケース 私たちは、携帯電話通信事業者のマーケティングアナリストです。 データを活用して、顧客離反の要素を判明し、お客さんの解約傾向を予測したいです。 ハンズオンのWebページに今回のユースケース用のデータダウンロードリンクがついているので、そこからデータをダウンロードしました。 このデータをCanvasに投入してみます。 左のメニューからDatasetsを選びます。 DLしたデータセットをインポートする為、右上のImport Data>Tabularを押下 表示されたダイアログにデータセット名を入力 データセットをドラッグ&ドロップでインポート、、、 と、拡張子がtxtのままだとエラーになってしまいました。 気を取り直してcsvに拡張子を変更し、アップロードしたところS3へのアップロードエラー 振り返ると、最初のドメイン作成時に自動で生成してくれたのは便利だったのですが、ハンズオン動画を見直すとドメイン作成時にIAMロールでAmazon S3への権限設定をしていました。 アップロードのエラー対策として、IAMロールにAmazon S3権限を追加することも考えられますが、今回はデータソースがAmazon S3を選べるので、手動でAmazon S3にアップロードし、Amazon S3からインポートすることとしました。 S3へのアップロードが完了したら、Data SourceでAmazon S3を選択し、データセットのインポートを実行 データセットを指定すると、プレビューができました 右上のCreate datasetボタンでデータセットの登録を実行 これで無事データセットのインポートが完了しました。   モデルの構築:データの探索 データセットのインポートが完了したら、次はデータの探索です。 機械学習で予測精度を上げるにはデータセットへの理解が欠かせません。 データセット内のパターンや特徴を把握し、クレンジングが必要な箇所を特定し、仮説を立ててデータ項目の相関性を分析します。 まずは左メニューのMy Modelsを選択し、モデル画面を表示します。 New modelボタンよりモデルの構築を開始します。 モデル名にハンズオンに倣って「CustomerChurn」と付けました。 「Churn」は解約を表す言葉でサブスクリプション型ビジネスモデルではチャーン率が重要な指標となります。 使用するデータセットを選択して「Select dataset」ボタン押下 Buildタブに移動し、選択したデータセットのカラム情報が表示されています。 データセットに対し予測対象のカラムを指定します。 今回は「Churn」を選択します。 予測カラムを選択すると、お勧めのモデルがModel type欄に表示されます。 「2 category prediction」がお勧めされました。 予測列を選択したプルダウンの下にValue distributionとして予測対象カラムの値分布が表示されていますが、False/True半々のようです。 ということで、「2 category prediction」でよさそうです。 モデルを変更したい場合は以下のようにConfigure modelで変更ができます。 Grid viewを選択すると、各カラムの分布図がワンクリックで表示されます。 最初のカラム毎の情報を掴むのに便利な機能ですね! さらに高度な探索をするために、「Data visualizer」を使ってみます。 「Day_Mins」(日中の通話時間)を横軸に、「Day_Charge」(日中の課金額)を縦軸に散布図を作成してみます。 各点の色にChurnを割り当てていて、赤色が解約したユーザーになります。 傾向として、長時間電話して課金額が高いユーザーであるほど解約傾向が高そうなことが分かりました。 次は「State」(州)を横軸に、「CustServ_Call」(カスタマーサービスへのCall数)を縦軸に積み上げ棒グラフを作成してみます。 ChurnのTrue/Falseの割合が州毎に可視化できました。 もしかしたらChurn率が高い州はカスタマーサービスの改善の余地があるかもしれませんね。   モデルの構築:モデルのプレビューと特徴量エンジニアリング カラムの相関関係や特徴などが掴めてきたら、特徴量エンジニアリングとモデルのプレビューに進みます。 特徴量エンジニアリングとは簡単にいうと予測に有用な説明変数を作り上げることですが、単純に1カラム、2カラムのデータを取り上げて予測を説明する変数だ、と言えるほど単純なものではありません。予測精度を上げるために複数のカラムの情報を組み合わせることになり、ドメイン知識なども活用して算出式を作ってみて、Try&Errorで精度を上げていく作業になります。実際には簡単に精度が上げられるわけではなく、多くの作業時間を費やしても思ったような結果がでにくい難易度が高い作業になりがちです。(PoC死が発生するわけですね それでは「Preview model」をクリックし、モデルのプレビューを開始してみます。 ベースライン精度が95.6%と分かります。(95.6%の確率で正しく予測できる、という指標 ハンズオンでは最初にデータセットに問題ないかを確認する「Validation」という機能を実施していますが、2024/08現在そのようなメニューが見当たりません。 現在ではPreview modelなど、モデル構築時に同時にValidation処理が実行されているようです。(Preview modelの上部にValidation結果の「No issues have been found in your datase」が表示されているのが確認できます。 Previewが完了しました。 Column impactとして特徴量の重要度が一覧表示されるのが便利ですね。 ※もし、重要度があまりにも高すぎる、予測ターゲットと同意のカラムがある場合は除去するなどの注意が必要になるようです。 続いてデータセットのクリーニングを実施します。 今回のユースケースを考慮し、例えば「Phone」は電話番号を表すカラムですが、解約には無関係と思われるので、ノイズとなりうるカラムは除去しておきます。カラムのチェックボックスを外すことで簡単に除去できます。 データ探索でお客様への請求額が高いほど解約傾向が高そうだという気づきがありましたので、合計の請求額を表す算出カラムを追加してみます。 Manage columns>Custom fomula で計算式とカラム名を設定し、Addボタンで追加します。 操作履歴は「Model recipe」に記録されるようです。 ハンズオンでは「Functions」メニューでカラムを追加していますが、2024/06現在、「Manage columns」メニューとして整理されたようです。 カラムを追加したら再度Preview modelを実行してみます。 Updateするかを聞いてくるんのでUpdateをクリックして更新処理を進めます。 結果、ベースライン精度が96.3%(+0.7%)に上がりました。カラムの編集が効果があったようです。     モデルの学習と評価 データの探索を終えたらモデルの学習と評価の進みます。 モデルのビルド方法として2種類用意されています。 QuickBuild 構築時間2~20分程度 精度より速度重視 最大5万行まで Standard Build 構築時間2~4時間程度 速度より精度重視 今回のようなPoCレベルであれば、まずはQuickBuildがお勧めのようですので、QuickBuildを進めてみます。 StandardBuildのような数時間レベルの作業の場合は、忘れずLogoutをしてセッション課金を止めておきましょう。 QuickBuildを開始すると最初にDataValidation処理が実行されています。 今回は数分でモデルが出来上がりました。 予測精度は約94.3%でPreview時より予測精度が下がってしまったようです。 今回のモデルでは「Eve_Mins」のImpcatが高いようです。     ハンズオン動画ではQuickBuild後に予測精度が上がっていたので、Case by caseのようです Scoringタブを確認してみます。 このViewに視覚的に予測がどれだけ正しかったかクロス集計として確認することができます。 Advanced Metricsタブでは3種類のメトリクスが確認できます メトリクステーブル 混合行列 Precision recall curve(PR曲線) これらのメトリクスやグラフをみながらパラメータチューニングを実施していくことになります。   生成したモデルでの予測 それでは生成したカスタムモデルで予測を実施してみます。 予測には2種類用意されています。 バッチ予測 データセット全体を予測する場合に使用 シングル予測 一つのデータに対して予測する。各パラメータを変更可能なので、仮説を立ててパラメータを変更しながら予測の変化を確認できる まずはバッチ予測を選択して進めてみます。 Manualボタンを押下すると予測したいデータセットを選択できます。 データセットを選択し、Generate predictionsボタンでバッチ予測を進めます。 ハンズオンではSelect datasetボタンでデータセットを選択していましたが、2024/08現在、Manual/Automaticボタンに整理されたようです 予測処理が終わるとStatusがReadyになります。 Status列の3点メニューにより予測結果をPreviewできるので確認してみます。 予測結果と予測確率が確認できます。 結果はDownloadボタンでcsvダウンロード可能。 次にシングル予測を実施してみます。 各特徴量を変更したら予測がどう変わるかをリアルタイムに確認できます。 仮説:夕方の通話時間が増えたら解約予測はどう変化するか? Eve_Minsの値を増やしてみます。 予測を更新するにはUpdate predictionsボタンを押下します。 更新前の解約予測は0.154% 予測更新の結果、解約予測は3.127%にわずかに上がりました。 このような形でWaht-If分析を進めることができます。     おわりに 作業が終わったら忘れずにLogoutしておきましょう。 今回ノーコードで機械学習カスタムモデルを構築することができました。 また、データ探索がGUIで進められたり特徴量の重要度の一覧が自動で表示されるなど、コーディングをしなくともモデル構築を進められることを実感できました。今後、ML活用のPoCがより手軽に精度高く(PoC死しないように)進むように願っています。   あとがき:やってしまいました 冒頭に課金について記載しましたが、このハンズオンを実施する中でやらかしてしまったようで、気づいたらSageMakerの課金が続いてしまっていました。。。 ※関係者の方々申し訳ありませんでしたm(_ _)m Logoutを忘れないように気を付けていたつもりですが、他の調べものなどをしている間にブラウザに埋もれてLogoutを忘れてしまったままブラウザを閉じてしまった日があったようです。 タイミング悪く、ハンズオンを中断してしばらく作業をしていなかったうちに課金が膨らんでしまいました。 Logoutは確実に忘れないこと、また、ハンズオンも集中して1~2日で終わらせられれば無用な課金も抑えられたかと思います。 ※Cloud9のように未使用30分でセッション終了する仕組みがあると助かりますね。 同じようなご経験の方のブログを参考として置いておきます。 SageMakerを触っていたらいつの間にか10万円請求された話 - Qiita 類似のやらかし記事が見当たらなかったので書いてみました。ちなみに執筆時点でまだ請求額が確定してないので円安に震えてます。。本記事は経緯や調査の流れを細かく書いているので「止め方が知りたいんだ!」… qiita.com
こんにちは。SCSKの山口です。 今回はBigQuery利用の料金を抑える一つの方法として、 「オンデマンドクエリの上限値設定」 をやってみます。 プロジェクト/クエリごとの上限値を設定し利用料金の増加を抑えるほか、意図しない大規模クエリによる利用料金の急増を抑える効果もあります。ぜひご覧ください。 BigQueryの料金体系 ここについては詳細に説明されている 公式ドキュメント 等があるため、要点を抑えて簡単に説明します。 BigQueryの料金は下記二つの要素で構成されています。 コンピューティング料金 :クエリを実行するためのコンピューティング料金 ストレージ料金 :BigQueryに読み込むデータを保存する料金 今回紹介する方法は「コンピューティング料金」を抑える方法です。 コンピューティング料金は、下記二つの課金体系から選択することができます。 オンデマンド料金 (TiB 単位):クエリごとに処理されるバイト数に応じて課金 容量料金 (スロット時間単位): BigQueryエディション から料金モデルを選択 今回アプローチするのは 「オンデマンド料金」 です。 BigQueryエディションに関しての詳細はリンクの公式ドキュメントをご覧ください。   割り当てを設定する 割り当て値とシステムの上限について  |  Cloud Quotas  |  Google Cloud 既存の割り当て使用量のモニタリングや、特定のプロジェクト内での API 割り当ての更新に役立つ Google Cloud の割り当てシステムについて紹介します。 cloud.google.com 割り当てとは、 「使用できるカウント可能な共有リソースの量」 を指します。いわゆる 「上限値」 です。 割り当てが不足すると、実行しようとしているタスクが 割り当てエラー によって失敗します。 ユーザ・プロジェクト・組織単位での設定が可能です。 設定方法 下記のどちらかで「割り当てとシステム上限」のページへアクセスします。 IAMと管理 – 割り当てシステムと上限 – フィルタで「BigQuery API」で検索 APIとサービス – 有効なAPIとサービス – フィルタで「BigQuery API」で検索   以下、IAM画面からアクセスする方法で説明します。 「BigQuery API」の 「Query usage per day」 を選択した状態で右端の点三つ「その他の操作」をクリック 「割り当てを編集」をクリック 「新しい値」に設定したい上限値(単位はTiBのみ)を入力しリクエストを送信 ここまでで設定は完了です。 一日のクエリ量上限を超える見積のクエリを実行しようとすると、下記エラーが出ます。 Custom quota exceeded: Your usage exceeded the custom quota for QueryUsagePerDay, which is set by your administrator. For more information, see   今回は「Query usage per day」を選択し、プロジェクト全体で使用できる一日の上限値を設定しましたが、似た名称の 「Query usage per day per user」 を使用すると 各ユーザが使用できる一日の上限値 を設定することができます。   課金されるバイト数を制限する 費用の見積もりと管理  |  BigQuery  |  Google Cloud cloud.google.com 今度は クエリ単位 で 課金される最大バイト数 の上限値を設定する方法です。 クエリ費用の抑制方法として、 BigQueryのドライラン機能 を活用してクエリ量を見積もる方法も有効な手段です。詳細はリンク先のブログをご覧ください。 課金される最大バイト数を設定したことによってクエリが失敗した場合は、下記エラーが返されます。 Error: Query exceeded limit for bytes billed: 1000000. 10485760 or higher required.   設定方法 BigQueryで「展開」タブから「クエリ設定」をクリック 「詳細オプション」を展開し、「課金される最大バイト数」に上限として設定したいバイト数を入力   上限を超えるクエリ(401 B)を実行すると、エラーが返されました。   まとめ 今回はBigQueryで各種上限値を設定してみました。 割り当ての設定では、 管理者目線で 一日あたりのクエリバイト数を制限することができます。 それに対して、クエリ単位でのバイト数制限では、 利用者それぞれが 意図しない利用量増加を防ぐために設定をすることができます。 私自身、BigQueryを触り始めて2年ほどになりますが、クエリを実行する前にどのくらいの処理バイトが発生するかを必ず確認するようにしています。 今回紹介した割り当ての設定で組織・プロジェクト単位での上限値設定は可能ですが、 だれか一人が容量を食いつぶしてしまってやむを得ず上限解放する 。といった事態になりかねないです。このような事態が多発すると上限値設定の意味も薄れてしまいます。 様々な上限値設定は用意されていますが、ひとり一人が意識する・対応策を打つことが重要ですね。 そのうえで、組織・プロジェクト単位での上限値を敷いておくのもかなり有効な手だと思います。 みなさんも今回紹介した内容をぜひご活用ください。
本記事は 夏休みクラウド自由研究 8/28付の記事です 。 こんにちは、SCSK株式会社の小寺崇仁です。 以前投稿した ZabbixとChatGPTを連携してみた(メディアタイプ編) をカスタマイズしてAmazon Bedrockと連携したいと思います。 事前準備 Zabbix 6.x 6系以上のZabbixが必要です。 AWS アクセスキー yyyyyyyy   AWS アクセスキー zzzzzzzzz     Amazon Bedrockの設定 Amazon Bedrockで使用できるAIモデルはデフォルトで無効になっており、アクセス許可設定が必要です。 AWSマネジメントコンソールから「Amazon Bedrock」->「Bedrock configurations」->「モデルアクセス」を開き使用したいモデルの「アクセスをリクエスト」します。 今回は「Titan Text G1 – Express」を使用します。   スクリプトの作成 メディアタイプのタブ 項目 値 補足 名前 任意   範囲 手動イベント処理   タイプ スクリプト   次で実行 Zabbixサーバー   コマンド 次に記載   ホストグループ すべて   ユーザーグループ すべて   必要なホストへのアクセス権 表示のみ   スクリプト export aws_access_key_id=YYYYYYYYYYYYY export aws_secret_access_key=ZZZZZZZZZZ export region=ap-northeast-1 export service=bedrock export model_id=amazon.titan-text-express-v1 curl -s "https://bedrock-runtime.${region}.amazonaws.com/model/${model_id}/invoke" \ --aws-sigv4 "aws:amz:${region}:${service}" \ --user "${aws_access_key_id}:${aws_secret_access_key}" \ -H "Content-Type: application/json" \ -X POST \   --data '{   "inputText": "次のログの対応方法を教えてください。\n{ITEM.VALUE}" }'| jq '.results[0].outputText' | sed 's/\\n/\'$'\n/g'   実行イメージ ログを受信する 障害画面からスクリプトを実行する Amazon Bedrockからの回答が表示される   最後に 弊社ではZabbix関連サービスを展開しています。以下ページもご参照ください。 SCSK Plus サポート for Zabbix SCSK Plus サポート for Zabbix 世界で最も人気のあるオープンソース統合監視ツール「Zabbix」の導入構築から運用保守までSCSKが強力にサポートします www.scsk.jp ★YouTubeに、SCSK Zabbixチャンネルを開設しました!★ SCSK Zabbixチャンネル 本チャンネルでは、SCSK株式会社でのZabbixに関するトレンド/事例紹介などを動画にまとめて取り上げております。 最新のトピックについては、以下の弊社HPもしくはツイッターアカウントをぜひ参照ください。 ツイッターアカウント: www.youtube.com ★X(旧Twitter)に、SCSK Zabbixアカウントを開設しました!★ x.com x.com
今回は、Prisma Cloudでのカスタムポリシー作成について詳しく解説します。セキュリティやコンプライアンスのニーズに合わせたポリシーを作成する方法を知っておくと、より効果的なクラウドリソースの管理が可能になります。この記事では、カスタムポリシーの基本から具体的な手順までをわかりやすく説明します。 カスタムポリシーとは? カスタムポリシーは、組織の特定の要件やニーズに応じて利用者側で作成するセキュリティルールです。Prisma Cloudでは予め用意されているポリシーが存在しますが、カスタムポリシーを作成することでよりニーズに合ったクラウドリソースの監視やコンプライアンスの確保が容易になります。Prisma Cloudでは、RQL(Resource Query Language)を使ってクエリを作成するか、保存済み検索を利用してクラウドリソースを照合することができます。   カスタムポリシーの種類 Prisma Cloudで作成できるカスタムポリシーには、以下のような種類があります。 Attack Path(攻撃経路)ポリシー このポリシーは、高リスクの攻撃経路を監視します。侵害の可能性がある経路を特定し、適切な対応を促します。 Attack Pathポリシーの詳細については こちら の記事でも説明しています。 Audit Event(監査イベント)ポリシー 監査データを調査し、特権アクティビティや疑わしいアクティビティまたは類似したアクティビティを監視します。 Prisma CloudがAWS、Azure、およびGCPクラウドサービスから取り込んだ、各種サービスおよび関連するユーザー/イベントデータから、クラウド環境内のコンソールおよびAPIアクセスの調査、特権アクティビティの監視とアカウント不正利用や不審なユーザー行動の検出などを行うことができます。 Config(設定)ポリシー リソース設定を監視し、ポリシー違反の可能性をチェックします。BuildとRunの2種類のサブタイプがあり、BuildポリシーはIaCテンプレート内のセキュリティの設定誤りをチェックして、それらの問題がプロダクション環境に持ち込まれないようにします。Runポリシーはデプロイされたクラウドリソースを監視し、潜在的な問題をチェックします。 IAMポリシー クラウド環境のID(認証情報)を監視し、過剰または未使用の権限を確認します。 Network(ネットワーク)ポリシー ネットワーク活動を監視し、リスクを検出します。 取り込まれたネットワークトラフィックデータの異常を機械学習で特定し、インターネットに公開されているサービス、疑わしい IP との通信などを検出します。   カスタムポリシーの作成手順 では、実際にカスタムポリシーを作成する手順を見ていきます。 今回はConfigポリシーを作成します。 ガバナンスを選択 Prisma Cloud の管理コンソールで、まず[ガバナンス]を選択します。   ポリシーを追加 次に、[Add Policy(ポリシーを追加)] > [設定]を順に選択します。 ポリシー名と説明を入力 ポリシー名を入力し、必要に応じて説明やラベルを追加します。 サブタイプの選択 サブタイプで[実行]を選択します。 ※サブタイプ[実行]はデプロイ済みのリソースのスキャンを、サブタイプ[ビルド]はコードリポジトリやIaCテンプレートのスキャンを行います。 重大度の選択 ポリシーの重大度を選択し、[Next(次へ)]をクリックします。 クエリの作成 RQLを使ってポリシーのクエリを作成します。保存済み検索を使用する場合、事前定義オプションを選択してクエリを自動記入できます。 今回は、インスタンスタイプに「large」を含むEC2インスタンスを検出するRQLを入力しました。 [検索]を押下し、検索欄左のマークが緑色であることを確認して[次へ]をクリックします。 コンプライアンス基準の追加 必要に応じて、ポリシーにコンプライアンス基準を追加します。 今回は特に要件がないので、何も選択せずに[Next(次へ)]をクリックします。 修正セクションの入力 ポリシー違反のアラートを自動的に修正する場合、修正用のコマンドラインコマンドを入力します。CLI修復はサブタイプがRun(実行)のポリシーでのみ利用可能です。 今回はアラート検知だけで自動修正は行わないので、何も設定せず[サブミット]をクリックします。 これでカスタムポリシーの作成は完了です。 作成後の確認 ガバナンスの画面で、画面右側にある検索欄に作成したカスタムポリシー名を入力し、ポリシーが表示されることを確認します。 作成したカスタムポリシーが表示されたので、以上で作業完了です。   まとめ カスタムポリシーは、Prisma Cloud を活用したクラウドリソースの効果的な管理に役立つ機能です。この記事で紹介した手順を参考に、組織の特定のニーズに合ったポリシーを作成し、セキュリティとコンプライアンスの強化を図りましょう。 今後も、Prisma Cloud の活用方法について実用的な情報をお届けできればと思います。 また、当社では、複数クラウド環境の設定状況を自動でチェックし、設定ミスやコンプライアンス違反、異常行動などのリスクを診断するCSPMソリューションを販売しております。 マルチクラウド設定診断サービス with CSPM| SCSK株式会社 マルチクラウド環境のセキュリティ設定リスクを手軽に確認可能なスポット診断サービスです。独自の診断レポートが、運用上の設定ミスや設計不備、クラウド環境の仕様変更などで発生し得る問題を可視化し、セキュリティインシデントの早期発見に役立ちます。 www.scsk.jp ご興味のある方は是非、お気軽にお問い合わせください。
こんにちは、SCSK株式会社の谷川です。 今回はZabbixの脆弱性管理、脆弱性情報の確認方法についてご紹介したいと思います。   脆弱性管理運用について 脆弱性とはソフトウェア、ハードウェアなどに存在するセキュリティ上の弱点や欠陥のことを指します。 この弱点が存在することにより、攻撃者は不正にシステムにアクセスしたり、データを盗んだり、システムを破壊 したりすることが可能になります。このためシステム管理者は稼働するシステムのソフトウェアや、ハードウェアの 脆弱性情報をタイムリーに情報収集し、その対策を講じる必要があります。 直近では下記記事のとおり、8月にZabbixでもCVSSスコア 「 9.9 」 と重大な脆弱性情報の公開がありました。 【緊急】Zabbix の脆弱性情報 CVE-2024-22116 (CVSS 9.9) 2024年8月9日(現地時間)にZabbix社は、監視ソリューション「Zabbix」に深刻な脆弱性があると公表いたしました。 この脆弱性が悪用された場合は、システム全体が危険にさらされる可能性があるため、緊急のアップデートが推奨されております。 blog.usize-tech.com 2024.08.21 Zabbixの脆弱性情報の公開頻度について Zabbixの脆弱性情報は下記URLにて公開されています。 Security Policy www.zabbix.com 公開頻度は、新バージョンがリリースされた後やZabbixを構成しているソフトウェアやミドルウェアに依存する 脆弱性情報が見つかったタイミング等で、傾向はなく不定期に公開される特性のものと認識しています。 一方で上記脆弱性情報の概要や自身の環境に影響があるかは、英語表記ということもあり、 英語が苦手な自分は少し判断がしづらいかなと感じております。 脆弱性情報の概要・影響の確認方法について そこで本日は、生成AIを利用して脆弱性情報の概要・影響が少しだけ分かりやすく 確認できる方法の一例についてご紹介したいと思います。 生成AIのモデルはGPT-4を利用し、以下のプロンプト例では脆弱性情報とZabbixのバージョンを変数としています。 脆弱性情報の概要・影響把握のためのプロンプト例 #命令書: あなたはZabbixサーバーの管理者です。 以下の{{脆弱性情報}}より要約のうえ影響と回避方法について回答してください。 なお{{利用バージョン}}に該当しなければその旨、回答してください。 #脆弱性情報 ・{{脆弱性情報}}:ZBV-2023-09-20-1 #対象者 ・Zabbixに詳しくない人 #制約条件 ・バージョンは明確に ・{{利用バージョン}}:Zabbix Agent 5.0.10 #内容構成 1.概要要約 2.対象コンポーネント 3.対象バージョン 4.影響 5.回避方法 回答例 以下に、指定された脆弱性情報「ZBV-2023-09-20-1」について要約し、影響と回避方法について回答します。 {{脆弱性情報}}: ZBV-2023-09-20-1 1. 概要要約 脆弱性「ZBV-2023-09-20-1」は、特定の条件下でZabbixサーバーやエージェントに影響を与える セキュリティ上の問題です。この脆弱性により、攻撃者がシステムに不正アクセスしたり、 サービスを停止させたりする可能性があります。 2. 対象コンポーネント この脆弱性は主にZabbixエージェントに関連しています。 3. 対象バージョン 対象バージョンは以下の通りです: Zabbix Agent 6.0.0 ~ 6.0.15 Zabbix Agent 7.0.0 ~ 7.0.9 4. 影響 この脆弱性が悪用されると、攻撃者は以下の影響を与える可能性があります: エージェントを通じてシステムに不正アクセス。 エージェントのサービスを停止させる。 機密データの漏洩。 5. 回避方法 アップデート: 対象バージョンのZabbixを最新バージョンにアップデートする。 設定変更: エージェントの設定を見直し、不要なサービスやポートを無効にする。 ファイアウォール設定: エージェントが通信するポートに対して適切なファイアウォールルールを設定。 {{利用バージョン}}: Zabbix Agent 5.0.10 該当しない : この脆弱性情報「ZBV-2023-09-20-1」はZabbix Agent 5.0.10には該当しないため、 特別な対応は不要です 。 質問や詳細な情報が必要であれば、お知らせください。 まとめ 上記のとおり、一部回避方法部分で怪しい箇所はあるものの、人の調査レポートに近しい品質の回答が得られました。 プロンプトに条件や前提を付与することで翻訳だけでなく、 脆弱性の概要や影響把握のための調査工数が少しだけ軽減されるように感じております。 なお今回は脆弱性情報の概要・影響の確認方法にフォーカスしましたが、 次回は重大な脆弱性が公開されたタイミングでタイムリーに検知する方法について記事にしたいと思います。 さいごに もし上記のようなZabbixに関連した脆弱性影響有無の判断が難しい場合や、 セキュリティ面に考慮した構築・運用のサポートが必要でしたら、 本件に関わらず以下ページよりお気軽にお問合せください。 お問い合わせ 製品・サービスについて 入力 | SCSK株式会社 SCSK株式会社 製品・サービスについてご意見・ご質問をお受けしております。 www.scsk.jp また直近で以下のZabbixに関連したセミナーへ参加予定です。 ご質問をお受けする時間もございますので、ご興味がございましたら是非ご参加ください。   ■Zabbix五都市キャラバン 2024.9.13 (金) 大阪 2024.9.20 (金) 博多 2024.9.27 (金) 札幌 Zabbix5都市キャラバン2024 www.zabbix.com   ■SCSK Zabbixプライベートセミナー 2024.10.02(水)オンライン https://www.scsk.jp/event/2024/20241002_2.html
こんにちは、SCSKの吉田です。 本記事では、タイトルにあるようにServiceNowの生成AI機能であるNow Assistを活用した、カタログアイテム(申請フォーム)とフローの作成を実践してみたので、そのプロセスを紹介します。 本記事は執筆時点(2024年8月)の情報です。最新の情報は製品ドキュメントを参考にしてください。 シナリオ ServiceNowへのアカウント登録を依頼する申請書を作成します。 申請フォーム 以下の質問項目を含めます。 First Name, Last Name, Email, Department(部署) フロー 以下のフローを作成します。 申請フォームに入力されたDepartment(部署)の部長に承認を求める。 部長が承認したらServiceNow上にアカウントを自動登録し、登録完了を申請者と登録されたユーザーに通知する。 部長が却下した場合、申請者に通知する。 使用する機能 Now Assist for Creatorに含まれる2つの機能を使います。 Catalog item generation 完成イメージを文字で入力すると、Now Assistがカタログアイテム(申請フォーム)の説明文や質問項目を自動で作成してくれる機能になります。GUIベースでカタログアイテムを作成できるCatalog Builderの中にNow Assistが追加されました。 Flow generation ServiceNowのフローを作成する機能であるFlow Designerの中で使用することができます。 作成したいフローの説明を文字で入力することで、Now Assistがフローのアウトラインを自動で作成してくれる機能になります。  実践 申請フォームの作成 Catalog Builderのカタログアイテムを作成するプロセスで「Now Assist」というステップが追加されています。 以下のように作成したいカタログアイテムの説明を入力して「Generate with Now Assist」をクリックします ※カタログアイテムのアクセス制限やフローとの紐づけなどその他設定が必用ですが、本記事では割愛します。 Create a user registration request form. It must include String type fields: First Name, Last Name, Email. Add a drop down menu offering department records stored within cmn_department table. All fields must be mandatory. Now Assistが作成したカタログアイテムは以下画像の通りです。 フォームの説明文、各質問項目は全てNow Assistにより自動生成されています。 こちらの内容で問題ない為、カタログアイテムの作成はこれで完了です。 フローの作成 Flow Designerで作成したいフローの説明を以下の通り入力します。 Flow DesignerにはActionやFlow Logicといったコンポーネントが用意されており、入力した説明に基づきNow Assistがこれらのコンポーネントを配置してフローを組んでくれます。 Create a flow that would be triggered upon the submission of a request. First, get cataalog variable and look up a record. Next, ask for approbal. If approvals are approved, create a record and send a email. If not, send a email.   以下画像がNow Assistにより生成されたフローのアウトラインとなります。 フローのトリガーや、コンポーネントの配置、If分岐など全て想定通りのフローを作成してもらえました。 誰に承認を求めるか、誰に通知を送るかなど細かい設定をマニュアルで実施すればフローの作成は完了となります。 最後に、作成したカタログアイテムとフローを紐づけます。 動作確認 以下の情報でユーザー登録を申請します。 ※IT Departmentの部長は、「Taro Test」を設定しています 申請するとIT Departmentの部長であるTaro Testに承認依頼が作成されます。 部長が承認すると、ユーザーテーブル上にアカウントが自動で登録されました。 また、申請者と新規作成されたユーザー宛てにメールが通知されています。 (申請が却下された場合は、ユーザー登録されず、却下メールが通知されていることも確認できました)   以上で、Now Assistに作成を支援してもらったカタログアイテム(申請フォーム)とフローの動作確認が完了しました。   最後に Now Assistを活用してカタログアイテム(申請フォーム)、フローを作成してみました。 一部はマニュアルでの設定が必要ですが、完成イメージを文字で説明するだけで、大枠部分を自動生成してくれるので、単純作業にかける時間を省くことができると感じました。 今回は簡単なシナリオでしたが、より複雑なシナリオに対しNow Assistによりどれだけ作業を効率化できるか、今後試していきたいと思います。   以下、弊社HPです。 併せてご参照ください。 ServiceNow ServiceNowは、企業の生産性向上や業務プロセス改善を支えるサービスマネジメントクラウドソリューションです。従業員満足度・顧客満足度の向上、業務効率化を強力に支援します。 www.scsk.jp
こんにちは。SCSKの山口です。 今回は、BigQuery で機密データを扱う際に欠かせない「データマスキング」について書きます。 実装する中で、権限周りでかなり悩んだ部分もあったので記載しておきます。お役に立てると嬉しいです。 BigQuery のデータマスキング 概要 データ マスキングの概要  |  BigQuery  |  Google Cloud BigQuery での列レベルのデータ マスキングと、そのメリット、要件、制限事項について説明します。いくつかのサンプル ユースケースで、マスキング ルールがさまざまなユーザー グループに適用される仕組みを示します。 cloud.google.com BigQuery では、「列レベルでのデータマスキング」をサポートしています。 この機能は「列レベルのアクセス制御」のベースの上に構築されているものなので、列レベルのアクセス制御を把握しておく必要があります。詳細は下記ブログをご参照ください。 【GCP】BigQuery のアクセス制御まとめ その② 本ブログはBigQuery のアクセス制御まとめ その①の続編です。今回は、BigQueryの「列と行のアクセス制御」について書きます。 blog.usize-tech.com 2024.08.22 下記手順で実装します。 分類と1つ以上のポリシータグを設定する ポリシータグのデータポリシーを構成する ポリシータグをBigQuery テーブルの列に割り当て、データポリシーを適用する マスクされたデータにアクセスできるユーザを、BigQuery のマスクされた読み取りロールに割り当てる マスキングを実装すると、 ユーザのロールに基づいて クエリの実行時にマスキングルールが自動的に適用されます。これは クエリに関する他のすべてのオペレーションよりも優先 されます。 マスキングのルールに関しては、事前に用意された下記のルールから選択することができます。 使用可能なマスキングルール 使用可能なマスキングルールは以下の通りです。 カスタムマスキングルーティン 年月日マスク デフォルトのマスキング値 メールマスク 先頭/末尾の4文字 Null化 カスタムマスキングルーティン ユーザー定義関数  |  BigQuery  |  Google Cloud cloud.google.com カスタムマスキングルーティンとは、 「ユーザ定義関数(UDF)」 を適用することにより、 ユーザ独自のマスキングルール を実装する方法です。 カスタムマスキングルーティンでは、各種文字列関数の他、ハッシュ関数、日時関数など多くの関数が使用可能となっています。(詳細は こちら ) 例)ユーザの社会保障番号を「XXX-XX-XXXX」に置き換えるマスキングルーティン   CREATE OR REPLACE FUNCTION SSN_Mask ( ssn STRING ) RETURNS STRING   OPTIONS ( data_governance_type = "DATA_MASKING" ) AS (   SAFE . REGEXP_REPLACE ( ssn , '[0-9]' , 'X' ) # 123-45-6789 -> XXX-XX-XXXX   );   年月日マスク データ内の 年以降の情報を切り捨てる マスキングルールです。 DATE,DATETIME,TIMESTAMP型 のデータに対してのみ使用できます。 種類 元の値 マスク後の値 DATE 2030-07-17 2030-01-01 DATETIME 2030-07-17T01:45:06 2030-01-01T00:00:00 TIMESTAMP 2030-07-17 01:45:06 2030-01-01 00:00:00   デフォルトのマスキング値 対象の列のデータ型に基づいて、あらかじめ定められている デフォルトのマスキング値 を返します。 データ型 デフォルトのマスキング値 STRING “” BYTES b” INTEGER 0 FLOAT 0.0 NUMERIC 0 BOOLEAN FALSE TIMESTAMP 1970-01-01 00:00:00 UTC DATE 1970-01-01 TIME 00:00:00 DATETIME 1970-01-01T00:00:00 GEOGRAPHY POINT(0 0) BIGNUMERIC 0 ARRAY [] STRUCT NOT_APPLICABLE ポリシータグは、 STRUCT  データ型を使用する列には適用できませんが、そのような列のリーフ フィールドに関連付けることができます。 JSON null   メールマスク 有効なメールアドレスのアカウント部分(@より前)を「XXXXX」に置き換えます。 有効なメールアドレスでない場合は、SHA-256ハッシュ関数を使用してハッシュ化された値に置き換えます。 STRING型のデータ にのみ使用できます。 元の値 マスク後の値 abc123@gmail.com XXXXX@gmail.com randomtext jQHDyQuj7vJcveEe59ygb3Zcvj0B5FJINBzgM6Bypgw= test@gmail@gmail.com Qdje6MO+GLwI0u+KyRyAICDjHbLF1ImxRqaW08tY52k=   先頭/末尾の4文字 先頭(末尾)を返し、文字列の残りの部分を「XXXXX」に置き換えます。 文字列の長さが4文字以下の場合は、SHA-256ハッシュ関数を使用してハッシュ化された値に置き換えます。 STRING型のデータ にのみ使用できます。 元の値 先頭の4文字 末尾の4文字 example XXXXple exaXXXX rei 80a23528c754a504894e9747d7df4fde20e937d3e9e63a86c001eecb0908b46 80a23528c754a504894e9747d7df4fde20e937d3e9e63a86c001eecb0908b46   Null化 列の値の代わりに「NULL」を返します。 列の値に加えて、 データ型も非表示にしたい場合 に有効です。   実践:データマスキング ここからは実際にデータをマスキングしていきます。 下記テーブルを使用します。 今回は、「クレジットカード番号」と「メールアドレス」をマスキングします。 また、事前にAdminユーザとMemberユーザの2つを用意し、それぞれの作業で分けて説明します。 Admin:分類の作成 列データをマスキングする  |  BigQuery  |  Google Cloud Google Cloud コンソールまたは BigQuery Data Policy API を使用してデータポリシーを追加、表示、更新、削除する方法を説明します。 cloud.google.com まず分類を作成する必要があります。 今回は、 BigQuery のアクセス制御のブログ で作成した下記分類を再利用します。 文類の作成方法については こちらのブログ をご参照ください。   Admin:カスタムマスキングルーティンを作成する 次に、クレジットカード番号をマスキングするためのカスタムマスキングルーティンを作成します。 下記クエリを実行し、UDFを作成します。 CREATE OR REPLACE FUNCTION yamaguchi_test_acctrl.SSN_Mask(ssn STRING) RETURNS STRING OPTIONS (data_governance_type="DATA_MASKING") AS ( SAFE.REGEXP_REPLACE(ssn, '[0-9]', 'X') # 123-45-6789 -> XXX-XX-XXXX );   Admin:データポリシーを作成する 列データをマスキングする  |  BigQuery  |  Google Cloud Google Cloud コンソールまたは BigQuery Data Policy API を使用してデータポリシーを追加、表示、更新、削除する方法を説明します。 cloud.google.com 分類が準備できたら、次にデータポリシーを作成します。 BigQuery画面の左ペインから「管理」-「ポリシータグ」を選択し、対象のポリシータグを選択した状態で「データポリシーを管理」をクリック [クレジットカード番号:カスタムマスキングルーティン] 先ほど作成したルールを選択 「プリンシパル」にマスキングルールを適用させたいユーザアカウントを入力 [メールアドレス:メールマスク]   ここまででデータポリシーの作成は完了です。   Admin:ポリシータグを列に設定する 列データをマスキングする  |  BigQuery  |  Google Cloud Google Cloud コンソールまたは BigQuery Data Policy API を使用してデータポリシーを追加、表示、更新、削除する方法を説明します。 cloud.google.com この作業は、 BigQuery のアクセス制御のブログ で作成した設定を再利用します。 設定方法の詳細については こちらのブログ をご参照ください。 BigQueryの対象テーブルの「スキーマ」ペインで「スキーマの編集」をクリック 対象スキーマを選択した状態で「ADD POLICY TAG」をクリック 対象スキーマに設定するポリシータグを選択する 設定完了するとこんな感じになります。 ここまででAdmin側での設定作業は完了です。   Member:テーブルデータ確認 Memberユーザでテーブルのプレビューを見てみます。 今回マスキングを設定したスキーマのデータが表示されなくなりました。 クエリを投げてデータを見てみます。 対象スキーマのデータがマスキングされた状態 で表示されました。大成功です。   悩んだ点 冒頭にも書きましたが、マスキングがうまくいかず、半日くらい悩まされました。 結果として、権限の設定が原因でした。 今回登場する権限(ロール)は下記の二つです。 ・マスクされた読み取りロール ・きめ細かい読み取りロール 公式ドキュメント を参考に下記の手順を実行しました。 結論として、 2の「きめ細かい読み取り」ロールを、マスキングしたデータを見せたいMemberのアカウントに付与していたこと が原因で、マスキングが適用されていませんでした。 各ロールの仕組みのドキュメント を見ると、下記記載があります。 図にすると以下の通りです。 マスキングされたデータを見せたいユーザに対しては、 マスクされた読み取りロールのみを付与する か、 マスクされた読み取りロールが優位に働くようにする 必要があります。 今回は、 二つのロールを同じポリシータグ内で付与してしまってい たため、マスキングされたデータが表示されませんでした。 ちなみに、「マスクされた読み取りロール」はマスキングルールとプリンシパルを紐づける操作の際に自動的に付与されます。 公式ドキュメントに記載のあるベストプラクティスは、「データポリシー レベルでBigQuery のマスクされた読み取りロールを割り当てること」です。プロジェクトレベル以上でロールを割り当てると、プロジェクト内のすべてのデータポリシーに対する権限がユーザーに付与され、過剰な権限による問題の原因となります。 列データをマスキングする  |  BigQuery  |  Google Cloud Google Cloud コンソールまたは BigQuery Data Policy API を使用してデータポリシーを追加、表示、更新、削除する方法を説明します。 cloud.google.com   まとめ 今回はBigQueryのデータマスキングについて書きました。 今回はあらかじめ用意しておいたデータに対してマスキングを行いましたが、設定以降に入ってきたデータに対してももちろんマスキングが実行されます。都度設定する必要がないので大変便利ですね。 今回紹介したマスキングや前回のブログで紹介したアクセス制御に関しては、 「分類やポリシーの設計」 がとても重要になると思います。 また、データマスキングを列レベルのアクセス制御と組み合わせて使用することで、さまざまなユーザーグループのニーズに基づいたアクセス範囲を構成できます。 BigQueryの列レベルのアクセス制御に関しては、 こちらのブログ をご覧ください。
本記事は 夏休みクラウド自由研究 8/27付の記事です 。 こんにちは。SCSKの島村です。 Googleが提供するオープンAIモデル Gemma についてご存じでしょうか??? Gemma は、 Googleが公開した商用利用可能なオープンモデル で、「軽量かつ高性能なLLM」という特徴があります。 本記事では、 『 Gemma 』について色々調査いたしましたので、それらを整理してみたいと思います。 また、実際にGoogle Cloud上でGemmaを展開し、利用してみました。その魅力について少しだけご紹介させていただければと思います。 Google Gemmaとは?? Gemma は、「アプリケーション内、ハードウェア、モバイル デバイス、ホスト型サービス」で実行できる 軽量型の生成 AIオープンモデルセット です。 ( Gemini モデルの作成に使用されたのと同じ研究とテクノロジーから構築された、軽量で最先端のオープンモデルです。) Gemma モデルは、ノートパソコン、ワークステーション、または Google Cloud で実行できます。 また、Colab や Kaggle ノートブック、JAX、PyTorch、Keras 3.0、Hugging Face Transformers などのフレームワークなどでもサポートをしています。 詳細については、以下、Google Blog公式からご確認ください。 Gemmaについて- Google Blog 大規模言語モデル(LLM)の性能を評価するためのベンチマークの一つであるMMLUでも 他のモデルと比較して性能が高いとのことです。(2024-06-27時点) MMLU(Massive Multitask Language Understanding) は、 様々な分野、多岐にわたるタスクを網羅した膨大な量の質問と回答のペアで構成されており、LLMが幅広い知識と理解能力を持っているかを測るために用いられます。                      横軸: 評価されたLLMのモデル名と、そのモデルのパラメータ数(数十億単位) 縦軸: MMLUベンチマークにおける正解率(%)   Gemma モデル ファミリー Gemmaは「様々なサイズや用途に合わせて、複数のモデルが提供」されています。 それらを表で整理してみました。 Gemma 2 200 億、900 億、270 億のパラメータ サイズで利用可能です。 3 つの新しい パワフルで効率的なモデル を提供し、すべてセーフティ機能を備えています。 Gemma 1 軽量でテキストからテキストを生成する、 デコーダのみの 大規模言語モデルです。 テキスト、コード、数学コンテンツの膨大なデータセットでトレーニングされます。 RecurrentGemma 再帰型ニューラル ネットワークとローカル アテンションを活用してメモリ効率を向上させる、技術的に異なるモデルです。 PaliGemma PaLI-3 に着想を得たオープンなビジョン言語モデル SigLIP と Gemma を活用しており、幅広い視覚言語タスクに転送するための汎用モデルとして設計されています。 CodeGemma CodeGemma は、オリジナルの事前トレーニング済み Gemma モデルの基盤を利用して、ローカル コンピュータに適したサイズの強力なコード補完と生成機能を提供します。   Google AI Studio上でGemmaを試してみた。 ここからは実施にGemmaモデルを利用してみたを共有できればと思います。 まずは簡単に試してみるということで、『 Google AI Studio 』からモデルを選択して、そのレスポンスを見てみます。 Google AI Studioとは?? Googleが提供 する、生成AIモデルであるGeminiを使って、様々なタスクを実行できるプラットフォームです。 ユーザーフレンドリーなインターフェースによって 開発の経験がないユーザーでも簡単に利用可能なことが特徴です。 Google AI Studioへのログインはこちら Gemini appとの違いは、 「APIキーの発行」や「モデルの選択」、「パラメータの調整」などのその他開発者向けの機能が充実しております。 Google AI StudioでモデルGemmaを選択してみる。 Gemmaは3つのサイズから選択可能です。 実際にpromptを入力して実行してみました。☟☟☟ 複数プロンプト実行してみた結果、 Gemini1.5 Flashに比べると出力までの時間は多少要しましたが、精度は申し分ないかと思います。   Google Cloud上でGemmaを動かしてみた。 Vertex AI で Gemma モデルを使用すると、 開発者はモデルの調整、管理、監視をシンプルかつ直感的に行えるエンドツーエンドのMLプラットフォームを活用できます。 Google CloudからGemmaを利用するには??? Gemma は、Vertex AI Model Garden からノートブックを起動して利用開始することができます。 また、Google Kubernetes Engine や Dataflow などのGoogle Cloud プロダクトでも利用可能です。 Google Cloud から利用できるGemma モデルのサイズと機能 https://ai.google.dev/gemma?hl=ja GCE(ローカル環境)上にGemamモデルをデプロイして使ってみる!!!! 今回、Gemmaの実行環境として Ollama を利用しました。 *『Ollam』はローカル環境でLLMモデルを動かすことができる無料でツールあり、使いやすいインターフェースが特徴です。 GCEインスタンを作成する。今回はGPUとしてNVIDIA T4を利用しました。 作成したインスタンスにSSHして DokcerとOllamaをインストールする。 Ollamaは公式ドキュメントの手順通りにインストールをします。 Download Ollama on Linux Download Ollama on Linux ollama.com                curl -fsSL https://ollama.com/install.sh | sh Ollama Open WebUIを起動する。 インストールできたら以下のコマンドでDockerを起動します。                 sudo docker run -d --network=host -v open-webui:/app/backend/data -e OLLAMA_BASE_URL=http://127.0.0.1:11434 --name open-webui --restart always ghcr.io/open-webui/open-webui:main ブラウザからOllama Open WebUIにアクセスする。 正しく起動でき、アクセスできると以下の画面が現れます。 *起動したOpenWebUI(GCE)へのアクセスは適切なネットワークとファイアウォールの設定を実施して接続してください。 モデル(Gemma)を選択し、プロンプトを送信してみる。 今回は「Gemma:7b」を利用してみした。 Gemmaをローカル環境でも利用することができました!!!!!!                 初回利用時は、Gemmaモデルをインストールする必要があります。 [設定]-[モデル]から[Ollama.comからモデルをプル]にてモデル名(例:gemma:7b)と入力しダウンロードしてください。   ローカル環境のリソースということもあり、出力には数十秒の時間を要しました。 ですが、実際の精度は申し分ないかと思います。 Gemma以外の他のオープンモデルについても試してみてそれらの使いやすさをい整理していこうと思います。   最後に 今回は Google のオープンAIモデル『Gemma』 についてご紹介させていただきました。 また、実際にローカル環境で実行してみてその手軽さを少しでもお伝え出来たかなと思います。 より詳細な機能については、追って公開させていただきます。引き続き本ブログをお楽しみください!!!!!! 今後とも、AIMLに関する情報やGoogle CloudのAIMLサービスのアップデート情報を掲載していきたいと思います。 最後まで読んでいただき、ありがとうございました!!!
こんにちは。SCSKの上田です。 今回は Zabbixで複雑な条件のログ監視を行う方法 をご紹介します。 ログ監視は、例えば「”ERROR”という文字列が含まれる」「イベントIDが”777″」などシンプルな条件なら簡単に作成できるのですが、 “Error”という文字列と”CPU”という文字列をともにを含む 深刻度が”警告”以上、但しイベントIDが”777″の場合は除外する といった 複合条件 や 除外条件 が加わると、作成が難しくなります。 そこで今回は、ログ監視の作成方法と、複雑な条件のログ監視を設定する方法について紹介していきます。 Linuxのテキストログ監視とWindowsのイベントログ監視でやり方が異なるので、それぞれについて書いていきます。 Linuxのログ監視 まずは、 Linuxのログ監視 についてです。 ログ監視のやり方 Linuxのログは、以下のアイテムキーで取得できます。 アイテムキー: log[監視するファイル名] 以下は、実際に取得されたアイテムの情報です。 Linuxログのアイテム取得画面 このように、出力されたログが プレーンテキスト として取得できます。 このログから特定の文字列を検知するには、以下のトリガー関数を使います。 トリガー関数: find(/ホスト名/log[監視するファイル名],,,”検知したい文字列”) このfind関数は、 アイテムの最新の値に検知したい文字列が 含まれている場合1 を、 含まれていない場合0 を返します。 例えば、/var/log/messagesで “ERROR” が含まれるログを検知したい場合、アイテムキーが “log[/var/log/messages]” のアイテムを作成し、トリガー条件式が “find(ホスト名/log[/var/log/messages],,,”ERROR”)=1″ となるトリガーを作成します。 複雑なログ監視のやり方 Linuxでは、 複合条件 も 除外条件 も、 グローバル正規表現 を使うのが有効です。 別の記事 “正規表現の使い方” にて正規表現の使い方とログ監視への応用方法を紹介しておりますので、そちらをご参照ください。 ログ監視に役立つZabbix正規表現の使い方 Zabbixにおける正規表現の使い方を説明します。正規表現を使うことで、複雑な条件にマッチするログの検知を行うことができます。 blog.usize-tech.com 2024.07.24   Windowsのログ監視 続いて、 Windowsのログ監視 についてです。こちらはLinuxと比べて少々複雑です。(理由は後述) ログ監視のやり方 まずログ取得のアイテムですが、 アイテムキー: eventlog[イベントログ名](または eventlog[イベントログ名称,,,,,,skip]) で取得します。パラメータに「 skip 」を指定しないと、 ホストに蓄積された過去のログも全て取得されてしまいます ので、アイテム登録した時点からのログだけ取得したい場合はskip付きののアイテムキーを使ってください。(本記事ではskip無しのアイテムキーを使用しています。) 以下は、実際に取得されたアイテムの情報です。 Windowsイベントログのアイテム取得画面 Linuxのログとは異なり、1つのプレーンテキストではなく 「ソース」 、 「深刻度」 、 「イベントID」 、 「値(ログの内容)」 と分かれて値が取得され、要素ごとにトリガー関数も分かれています。 (これがWindowsのイベントログ監視が複雑になる理由です) ソース: logsource (/ホスト名/eventlog[イベントログ名],,”検知したいソース”) 深刻度: logseverity(/ホスト名/eventlog[イベントログ名]) イベントID: logeventid (/ホスト名/eventlog[イベントログ名],,”検知したいイベントID”) 値: find(ホスト名/log[/var/log/messages],,,”検知したい文字列”) ソース、イベントID、値の関数は、 最新のイベントログに検知したい要素が 含まれている場合1 を、 含まれていない場合0 を返します。 深刻度の関数は、深刻度が “情報”なら1、”警告”なら2、,”エラー”なら4、”クリティカル”なら9 を返します。 例えば、システムログでイベントの 深刻度がエラー のログを検知したい場合、” logseverity(/ホスト名/eventlog[System]) =4″、 イベントIDが777 のログを検知したいときは” logeventid (/ホスト名/eventlog[System],,”777″)=1″ という風に、適切な関数を選んでトリガーを設定します。 複雑なログ監視のやり方 それでは、複雑な条件のログ監視を設定してみましょう。 ①複合条件 まず、「ソースが●● かつ 深刻度が●● かつ ・・・」という 複合条件 を考えてみます。 トリガー条件式は、 論理演算子”and” や “or” が使えるので、それを使って条件式を組み立ててみます。 例として、以下のすべての条件を満たす条件式を作ってみましょう。 ソースがtest 深刻度が警告以上 イベントIDが777 この場合、以下のような条件式になります。 logsource(/ホスト名/eventlog[System],,”test”)=1 and logseverity(/ホスト名/eventlog[System])>=2 and logeventid(/ホスト名/eventlog[System],,”777″)=1 イベントログ監視トリガー① これで実際に該当のイベントログを検知できるか試してみましょう。イベントログを生成するには、 “EVENTCREATE” コマンドを使います。 監視対象機器のコマンドプロンプトで、以下のコマンドを実行してみましょう。 EVENTCREATE /ID 777 /L system /SO test /T ERROR /D "イベントテスト" すると、想定通り障害として検知しました。 障害検知 ②除外条件 続いて、 除外条件 も考えてみましょう。例えば、「深刻度がエラー以上 但しソースが●●のモノは除く」といった条件です。 トリガー条件式では、 否定演算子”not” も使えるので、これを使って条件を組み立てます。 以下の条件を考えてみましょう。 深刻度が警告以上 但し、イベントIDが”777″のログは除く この場合、以下のような条件式になります。 logseverity(/ホスト名/eventlog[System])>=2 and not logeventid(/ホスト名/eventlog[System],,”777″)=1 イベントログ監視トリガー② その後、EVENTCREATEで以下のイベントを生成します。 EVENTCREATE /ID 888 /L system /SO test /T ERROR /D "イベントテスト" これは、 深刻度が警告以上 で イベントIDは”777″ではない ので、条件にマッチして障害として検知されます。 障害検知② その後、今度は除外条件にマッチする以下のイベントを生成します。 EVENTCREATE /ID 777 /L system /SO test /T ERROR /D "イベントテスト" こちらは除外条件にマッチするので、想定通り 障害が発生しません。 ③複合条件と除外条件のMIX 最後に、さらに複雑な、 複合条件 と 除外条件 の 合わせ技 をやってみます。 例えば、以下のような条件を考えます。 深刻度が警告以上 但し、以下の条件のいずれかを満たすものは除外する:  1:「ソースが”test”」かつ「イベントIDが”777″」  2:「ソースが”hoge”」かつ「イベントIDが”888″」かつ「内容に”テスト”という文字列が含まれる」 複雑なので、一つ一つ紐解いていきます。 まず、”深刻度が警告以上”という条件は、今まで出てきている通り、 logseverity(/ホスト名/eventlog[System])>=2 となります。 続いて1と2の条件式は、複合条件なので以下のように書けます。 1: logsource (/ホスト名/eventlog[System],,”test”)=1 and logeventid(/ホスト名/eventlog[System],,”777″)=1 2:logsource(/ホスト名/eventlog[System],,”hoge”)=1 and logeventid(/ホスト名/eventlog[System],,”888″)=1 and find(/ホスト名/eventlog[System],,,”テスト”)=1 これらの条件を満たす場合は検知しないので、この条件をnotで否定し、最初の条件と結合します。複数条件に演算子を適用する場合は、()で括ります。 logseverity(/ホスト名/eventlog[System])>=2 and not (logsource(/ホスト名/eventlog[System],,”test”)=1 and logeventid(/ホスト名/eventlog[System],,”777″)=1) and not (logsource(/ホスト名/eventlog[System],,”hoge”)=1 and logeventid(/ホスト名/eventlog[System],,”888″)=1 and find(/ホスト名/eventlog[System],,,”テスト”)=1) イベントログ監視トリガー③ それでは、これが正しい動作をするかテストしてみましょう。 まずは除外条件に当てはまらないログを生成し、障害検知するかテストします。 EVENTCREATE /ID 888 /L system /SO test /T ERROR /D "イベントテスト" これは除外条件1,2ともにすり抜けているので、障害として検知されます。 障害検知③ 続いて、以下のログを生成します。 EVENTCREATE /ID 777 /L system /SO test /T ERROR /D "イベントテスト" これは除外条件1にマッチしているので、障害として検知されません。 以下のログでも試してみましょう。 EVENTCREATE /ID 888 /L system /SO hoge /T ERROR /D "イベントテスト" これは除外条件2にマッチしているので、こちらも障害としては検知されません。 以上のテストより、想定通り 除外条件にマッチするログは検知しない ことが分かります。   まとめ 今回は、LinuxとWindowsのログ監視について紹介しました。 Linuxは正規表現を使えば複合条件も除外条件も簡単に作成できますが、Windowsはイベントログの要素によって関数が分かれているため、どうしても複雑なトリガー条件式になってしまいます。しかし、論理演算子 “and” “or” “not” をうまく組み合わせれば柔軟な条件式が作成できるので、この記事を参考にぜひ試してみてください。 最後に、弊社が参加するイベントについて宣伝させてください。 ① Zabbix全国5都市キャラバン2024 Zabbix社主催の、 全国5都市を回るセミナーイベント です。東京・名古屋は終了しましたが 2024年9月に大阪・九州・北海道でも開催 しますので、是非お近くの会場に足を運んでみてください! Zabbix5都市キャラバン2024 www.zabbix.com ② Zabbix7.0セミナー こちらは 2024年10月2日(水) に開催される、 SCSK主催のWEBセミナー です。Zabbix7.0の新機能やバージョンアップの勘所についてご紹介します。 本記事の筆者が講師として登壇します ので、是非ご視聴ください! Zabbix7.0セミナー~新機能とバージョンアップの要点~ 本セミナーでは、Zabbix 7.0の新機能と改善点について詳しくご紹介させていただきます。実際のアップグレード手順についてもご説明し、皆様のZabbix 7.0への移行をスムーズに進めるためのヒントもお伝えいたします。 www.scsk.jp 最後まで読んでいただき、ありがとうございました。 弊社ではZabbix関連サービスを展開しています。以下ページもご参照ください。 ★SCSK Plus サポート for Zabbix★ SCSK Plus サポート for Zabbix 世界で最も人気のあるオープンソース統合監視ツール「Zabbix」の導入構築から運用保守までSCSKが強力にサポートします www.scsk.jp ★YouTubeに、SCSK Zabbixチャンネルを開設しました!★ SCSK Zabbixチャンネル 本チャンネルでは、SCSK株式会社でのZabbixに関するトレンド/事例紹介などを動画にまとめて取り上げております。 最新のトピックについては、以下の弊社HPもしくはツイッターアカウントをぜひ参照ください。 ツイッターアカウント: www.youtube.com ★X(旧Twitter)に、SCSK Zabbixアカウントを開設しました!★ x.com x.com
本記事は 夏休みクラウド自由研究 8/26付の記事です 。 「夏休みクラウド自由研究」ということで、Microsoft Azure の Azure AI サービスの TTS (Text to speech) / SST (Speech to text) を使って LLM (gpt-4o-mini) と音声で会話してみようと思います。 準備 まずはいろいろ試せるように、Azure AI Studio をセットアップします。 Azure AI Studio は Azure AI 関連サービス (Azure ML や Azure OpenAI なども含む) を一元的にエンドツーエンドで管理できるようにしてくれます。すべてを集めてきてくれており、簡単に使えていろいろ捗るので、目的からは必須ではありませんが使ってみます。 Azure AI Studio ハブの作成 Azure AI Studio ハブは、次の 2 つの方法で作成できます。 Azure AI Studio (ai.azure.com) から作成する Azure Portal (portal.azure.com) から作成する 1 は必要最低限のパラメーターで作成できるため簡単ですが、ネットワーク設定などのエンタープライズ利用においては必須の設定ができなかったりしますので、まじめに使うときは 2 で作成いただくのがよろしいかと思います。 ※ 今回は特にカスタマイズしたいこともないのですが、どんな設定があるか見たいので、 2 で設定内容などを眺めながら作成します。 ※ なお、Azure OpenAI 利用申請は終わっている前提です。 作成手順 (クリック) Azure Portal の検索バーで Azure AI Studio を検索してアクセスします。 「新しい Azure AI ハブ」をクリックします。 基本設定を行い、「次へ」をクリックします。 サブスクリプション: デプロイ先のサブスクリプションを指定 リソースグループ: デプロイ先の RG を指定 リージョン: デプロイ先のリージョンを指定 ※ 利用可能なモデルは下の「Azure AI サービスのベース モデル」で接続するリソースのリージョン依存 名前: リソースの名前を指定 フレンドリ名: Azure AI Studio 上で利用される表示名 既定のプロジェクトリソースグループ: 別途、Azure AI Studio プロジェクトを作成する際のデフォルトの RG を指定 OpenAI を含む AI サービスに接続する: Azure AI Studio と接続する Azure AI サービスのリソースを指定 ※ 今回は新規作成で Azure お任せ ストレージ設定を行い、「次へ」をクリックします。 ストレージアカウント: Azure AI Studio 上で扱うファイルや設定などを格納するストレージアカウントを指定 ※ 今回は新規作成で Azure お任せ キーコンテナー: Azure AI Studio 上で扱うシークレットなどを格納する Key Vault を指定 ※ 今回は新規作成で Azure お任せ Application Insights: 分析情報などを取得するために使う Application Insights を指定 ※ 今回は必要ないのでなし コンテナーレジストリ: Azure AI Studio 上で扱う Docker イメージなどを格納するレジストリを指定 ※ 今回は必要ないのでなし ネットワーク設定を行い、「次へ」をクリックします。 ※ 今回はデフォルトのまま 暗号化設定を行い、「次へ」をクリックします。 ※ 今回はデフォルトのまま ID 設定を行い、「確認および作成」をクリックします。 ※ 今回はデフォルトのまま ※ タグ設定はすっとばします   Azure AI Studio と 付帯リソースが作成されました。 ※ リソースグループには指定したストレージアカウントやKey Vaultも作成されています。 モデルのデプロイ Azure AI Studio ハブが作成できたら、 Azure AI Studio にアクセスして、利用するモデルをデプロイします。 Azure Speech (Text to speech, Speech to text) Azure OpenAI (gpt-4o-mini) Azure Speech の方は、先ほど作成した AzureAI リソースに含まれており個別にモデルをデプロイする必要はないため、gpt-4o-mini だけ追加でデプロイします。 作成手順 (クリック) Azure AI Studio のホーム画面で「すべてのハブ」をクリックします。 ※ 「管理」カテゴリが見えていない場合はログインできていない可能性がありますので右上の方を見てみてください。 モデルをデプロイするハブをクリックします。 「デプロイ」メニューに移動して、「モデルのデプロイ」をクリックします。 デプロイするモデルを選択して「確認」をクリックします。 デプロイ名やその他のパラメーターを指定して、「デプロイ」をクリックします。 ※ モデルのデプロイ単位で固有の API パスを持つことになります ※ 今回は、デプロイの種類を Global standard から Standard に変更しています モデルがデプロイされました。   gpt-4o-mini と音声で会話してみる MS 公式サンプルを参考に会話する Microsoft がサンプルコードを公開してくれているので、今回はそちらを参考に試してみたいと思います。 Azure OpenAI 音声読み上げチャット - Speech サービス - Azure AI services この攻略ガイドでは、Speech を使用して Azure OpenAI と会話します。 Speech ではオーディオを認識し、それを Azure OpenAI に送信し、音声応答を合成します。 learn.microsoft.com ソースコード (クリック) 自分のために少し手直ししています。 コメントを日本語に変更 環境変数を .env ファイルから取得するように変更 認識する言語を日本語 (ja-jp) に変更 import os import azure.cognitiveservices.speech as speechsdk from openai import AzureOpenAI from dotenv import load_dotenv # .envファイルから環境変数を読み込みます load_dotenv() # この例では、"OPEN_AI_KEY"、"OPEN_AI_ENDPOINT"、および "OPEN_AI_DEPLOYMENT_NAME" という名前の環境変数が必要です # エンドポイントは次のような形式である必要があります https://YOUR_OPEN_AI_RESOURCE_NAME.openai.azure.com/ client = AzureOpenAI( azure_endpoint=os.environ.get('OPEN_AI_ENDPOINT'), api_key=os.environ.get('OPEN_AI_KEY'), api_version="2023-05-15" ) # これは、モデルをデプロイしたときに選択したカスタム名に対応します。 deployment_id=os.environ.get('OPEN_AI_DEPLOYMENT_NAME') # この例では、"SPEECH_KEY" と "SPEECH_REGION" という名前の環境変数が必要です speech_config = speechsdk.SpeechConfig(subscription=os.environ.get('SPEECH_KEY'), region=os.environ.get('SPEECH_REGION')) audio_output_config = speechsdk.audio.AudioOutputConfig(use_default_speaker=True) audio_config = speechsdk.audio.AudioConfig(use_default_microphone=True) # スピーカーの言語に合わせたロケールを設定する必要があります speech_config.speech_recognition_language="ja-JP" speech_recognizer = speechsdk.SpeechRecognizer(speech_config=speech_config, audio_config=audio_config) # Azure OpenAIが代わりに応答する音声の言語にします speech_config.speech_synthesis_voice_name='en-US-JennyMultilingualNeural' speech_synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=audio_output_config) # tts sentence end mark tts_sentence_end = [ ".", "!", "?", ";", "。", "!", "?", ";", "\n" ] # Azure OpenAIにリクエストを送信し、応答を合成します。 def ask_openai(prompt): # Azure OpenAIにストリーミングでリクエストを送信する response = client.chat.completions.create(model=deployment_id, max_tokens=200, stream=True, messages=[ {"role": "user", "content": prompt} ]) collected_messages = [] last_tts_request = None # ストリームレスポンスをイテレートする for chunk in response: if len(chunk.choices) > 0: chunk_message = chunk.choices[0].delta.content # extract the message if chunk_message is not None: collected_messages.append(chunk_message) # save the message if chunk_message in tts_sentence_end: # sentence end found text = ''.join(collected_messages).strip() # join the recieved message together to build a sentence if text != '': # if sentence only have \n or space, we could skip print(f"Speech synthesized to speaker for: {text}") last_tts_request = speech_synthesizer.speak_text_async(text) collected_messages.clear() if last_tts_request: last_tts_request.get() # 継続的に音声入力をリッスンし、認識してテキストとしてAzure OpenAIに送信する def chat_with_open_ai(): while True: print("Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation.") try: # マイクから音声を取得し、それをTTSサービスに送信します。 speech_recognition_result = speech_recognizer.recognize_once_async().get() # 音声が認識された場合、それをAzure OpenAIに送信して応答を待ちます。 if speech_recognition_result.reason == speechsdk.ResultReason.RecognizedSpeech: if speech_recognition_result.text == "Stop.": print("Conversation ended.") break print("Recognized speech: {}".format(speech_recognition_result.text)) ask_openai(speech_recognition_result.text) elif speech_recognition_result.reason == speechsdk.ResultReason.NoMatch: print("No speech could be recognized: {}".format(speech_recognition_result.no_match_details)) break elif speech_recognition_result.reason == speechsdk.ResultReason.Canceled: cancellation_details = speech_recognition_result.cancellation_details print("Speech Recognition canceled: {}".format(cancellation_details.reason)) if cancellation_details.reason == speechsdk.CancellationReason.Error: print("Error details: {}".format(cancellation_details.error_details)) except EOFError: break # Main try: chat_with_open_ai() except Exception as err: print("Encountered exception. {}".format(err)) 環境変数の確認方法 (クリック) いろいろ導線はありますが、一例を示します。 項目 確認方法 OPEN_AI_KEY 種類が Azure OpenAI の行のキー値 ※ 右側にコピーボタンがあります OPEN_AI_ENDPOINT 種類が Azure OpenAI の行のターゲット値 ※ マウスオーバーでコピーできます OPEN_AI_DEPLOYMENT_NAME 先の手順で指定したモデルのデプロイ名 SPEECH_KEY 種類が Azure OpenAI の行のキー値 ※ 右側にコピーボタンがあります SPEECH_REGION 先の手順で指定した Azure AI サービスのデプロイ先リージョン では、さっそく Python スクリプトを実行して会話してみましょう。 Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. Recognized speech: こんにちは最近どうですか? Speech synthesized to speaker for: こんにちは! Speech synthesized to speaker for: 私は元気です。 Speech synthesized to speaker for: あなたはどうですか? Speech synthesized to speaker for: 最近何か面白いことがありましたか? Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. document.createElement('video'); https://blog.usize-tech.com/contents/uploads/2024/08/azure-ai-tts-sst_audio1.mp4 うまく日本語を認識して会話できているようです。 男性の声は、ローカル PC のテキスト読み上げ機能で発声させており、女性の声が gpt-4o-mini の応答を TTS で読み上げたものです。 ざっくり、こんな動きをしています。 処理の流れイメージ カスタマイズしてみる 音声合成のレートを変更する 話し方がゆっくりしているので、音声合成のレートを変更してみます。 54行目を次のように (無理やり) 変更して、SSML で音声合成をカスタマイズします。 # last_tts_request = speech_synthesizer.speak_text_async(text) ssml = f"<speak version='1.0' xmlns='http://www.w3.org/2001/10/synthesis' xml:lang='ja-JP'><voice name='en-US-JennyMultilingualNeural'><prosody rate='1.3'>{text}</prosody></voice></speak>" last_tts_request = speech_synthesizer.speak_ssml_async(ssml) collected_messages.clear() 音声合成マークアップ言語 (SSML) の概要 - 音声サービス - Azure AI services 音声合成マークアップ言語を使用して、テキスト読み上げの発音と韻律を制御する方法を説明します。 learn.microsoft.com それでは実行して会話してみましょう。 Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. Recognized speech: こんにちは最近どうですか? Speech synthesized to speaker for: こんにちは! Speech synthesized to speaker for: 私は元気です。 Speech synthesized to speaker for: あなたはいかがですか? Speech synthesized to speaker for: 最近何か楽しいことがありましたか? Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. https://blog.usize-tech.com/contents/uploads/2024/08/azure-ai-tts-sst_audio2.mp4 先ほどより早めに話すようになりました。   音声モデルを変更してみる 音声モデルを日本人男性の声  ja-JP-DaichiNeural に変更してみます。 言語サポート - 音声サービス - Azure AI services 音声サービスでは、音声翻訳に加え、音声テキスト変換とテキスト読み上げ変換のためのさまざまな言語がサポートされています。 この記事では、サービス機能によってサポートされている言語の包括的な一覧を示します。 learn.microsoft.com 30行目を次のように変更します。 # speech_config.speech_synthesis_voice_name='en-US-JennyMultilingualNeural' speech_config.speech_synthesis_voice_name='ja-JP-DaichiNeural' ※ 音声合成のレート変更 (SSML) はロールバックしています。   それでは実行して会話してみましょう。   Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. Recognized speech: こんにちは最近どうですか? Speech synthesized to speaker for: こんにちは! Speech synthesized to speaker for: 私は元気です。 Speech synthesized to speaker for: あなたはいかがですか? Speech synthesized to speaker for: 最近のことについて教えてください。 Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. https://blog.usize-tech.com/contents/uploads/2024/08/azure-ai-tts-sst_audio3.mp4 男性の声に変りました。   システムロールをカスタマイズする システムロールのカスタマイズは TTS / SST というよりは、LLM の方の制御ですが、一応やっておきます。 39 行目に role が system のプロンプトを追加します。       {"role": "system", "content": "織田信長になりきってください。性格や語気もトレースします。"},         {"role": "user", "content": prompt} それでは実行して会話してみましょう。 Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. Recognized speech: あなたのことを教えてください。 Speech synthesized to speaker for: 我は織田信長。 Speech synthesized to speaker for: 尾張の大名として、天下統一を目指す者なり。 Speech synthesized to speaker for: かつては小さな領地を治めていたが、今やその力を壮大に広げつつある。 Speech synthesized to speaker for: 強さや革新を重んじ、古きものを打破することに執念を燃やしておる。 Speech synthesized to speaker for: 敵には容赦せず、味方には厚く接するが、今は戦国の混乱を収め、安定した世を築くことが我が使命よ。 Speech synthesized to speaker for: 何か聞きたいことがあれば、問うてみよ! Azure OpenAI is listening. Say 'Stop' or press Ctrl-Z to end the conversation. https://blog.usize-tech.com/contents/uploads/2024/08/azure-ai-tts-sst_audio4.mp4 織田信長のようなことを言う何かに変りました。   まとめ 今回の夏休みクラウド自由研究では、Microsoft Azure の Azure AI サービスの TTS (Text to Speech) / SST (Speech to Text) 機能を活用し、LLM(gpt-4o-mini)と音声で対話する方法を試してみました。 Azure AI Studio を使ってみたい気持ちと、Azure の音声サービスに入門したい気持ちから今回はこういった内容にしてみましたが、実用を考えると、Azure OpenAI の Function Calling や Assistants API といったプラグイン機能や、LangChain や Semantic Kernel などのフレームワークを利用したほうが、より効率よく高度な処理を実現できる気がします。また、gpt-4o / mini の音声対応版や、Azure OpenAI の TTS / SST も一部プレビューが始まっています。 その辺りも追って挑戦しながら、AI ともっと自然に高度な会話ができないかもくもく試していきたいと思います。
本記事は 夏休みクラウド自由研究 8/25付の記事です 。 こんにちは、Terraform学習中のSCSK稲葉です。 Terraformを使用してAWS上にWordpressの環境を構築する方法を学習したのでご紹介いたします。  Terraformとは インフラの構成をソースコードとして管理できるIaCツールです。   AWSやAzure、GCPなどの様々なクラウドサービスに対応しています。 Terraform | HashiCorp Developer Explore Terraform product documentation, tutorials, and examples. developer.hashicorp.com   作成するWordpress環境の構成 Terraformで以下のような環境を構築します。 ALBの後ろに配置するEC2インスタンスは、オートスケーリングによって可用性を持たせています。 複数のEC2インスタンスがWordpressのファイルにアクセスできるように、WordpressのファイルをEFSに配置しています。 RDSもマルチAZによって可用性を持たせています。   Terraformの構成 下記のようなディレクトリ構成を作成しました。 実際の開発では開発環境と本番環境のように複数の環境を作成することになると思います。 環境ごとに分ける必要がある内容をenvironmentsディレクトリの配下に配置しました。 . ├── environments # 環境管理ディレクトリ │   ├── dev # 開発環境用ディレクトリ │   │   ├── dev.tfbackend # tfstateの管理場所を指定するファイル │   │   └── dev.tfvars # 変数に指定するパラメータを定義するファイル │   └── prd # 本番環境用ディレクトリ │   ├── prd.tfbackend # tfstateの管理場所を指定するファイル │   └── prd.tfvars # 変数に指定するパラメータを定義するファイル ├── main.tf # リソースを定義するファイル ├── variables.tf # 変数を定義するファイル ├── output.tf # 実行結果として出力する値を指定するファイル ├── provider.tf # 指定したプロバイダの設定をするファイル └── user_data_script.tpl # ユーザーデータ ダウンロードはこちらからどうぞ WordPressの環境構築IaCコード Download Now! 6 Downloads 各ファイルのコードは本稿の最後に載せています。 main.tf main.tfファイルでは作成するリソースを定義します。 下記コードはVPCを定義しています。 他のリソースもこのコードと同じようにresource ブロックで定義できます。 リソースごとの書き方は Terraformのドキュメント でその都度調べながら書くことになります。 resource aws_vpc vpc { cidr_block = "10.0.0.0/16" instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "dev-vpc" } } また、main.tfの1番初めにあるTerraformブロックは、Terrafrom自体の設定を定義する箇所です。 下記コードでは、バージョンが5.57.Xの”hashicorp/aws”プロバイダーを使用すると記載されています。 terraform { backend s3 {} required_providers { aws = { source = "hashicorp/aws" version = "~> 5.57.0" } } } variable.tf variable.tfファイルでは変数を定義します。 下記コードのようにvariableブロックで変数を指定することで、 varable vpc_cidr_block {} variable vp_instance_tenancy {} variable enable_dns_support {} variable enable_dns_hostnames {} variable vpc_name_tag {} main.tfファイルで変数を使用できるようになります。 変数を使用する場合、”var.<変数名>”と書きます。 resource aws_vpc vpc { cidr_block = var.vpc_cidr_block instance_tenancy = var.vpc_instance_tenancy enable_dns_support = var.enable_dns_support enable_dns_hostnames = var.enable_dns_hostnames tags = { Name = var.vpc_name_tag } } output.tf output.tfファイルではTerraformの実行結果に出力する内容を定義します。 下記コードはVPCのIDをTerraformの実行結果に出力すると記載されていて、 output vpc_id { value = aws_vpc.vpc.id } 下記のように出力されます。 Apply complete! Resources: xx added, 0 changed, 0 destroyed. Outputs: vpc_id = "vpc-xxxxxxxxxxxxxxxxxx" provider.tf provider.tfファイルではmain.tfで指定したプロバイダーの設定を定義します。 本稿ではawsプロバイダーが指定されているので、awsの設定を記載します。 特にdefault_tagの機能は、Terraformで作成するリソースに対して一括でタグ付けできるので便利だなと思っています。 provider aws { region = "ap-northeast-1" profile = "inaba-poc" default_tags { tags = { Project = "wordpress" Terraform = "true" } } } environmentsディレクトリ 開発環境と本番環境で分けるファイルを配置します。 tfbackendファイルについて Terraformではリソースの管理をjson形式でtfstateというファイルにまとめます。 Terraformは後述するTerraformのリソース作成コマンド(terraform apply)を実行するたびに、このファイルを作成、参照、更新して現在のリソースの状態とコマンド実行後のリソースの状態の差を取得します。 リソースの状態に差があるとリソースを変更し、無い場合変更しません。 この仕組みでTerraformは冪等性を実現しています。 tfbackendファイルではtfstateファイルを管理する場所を定義します。 下記コードではS3のバケットを指定しているので、s3バケットにtfstateが作成されます。 S3で管理することで他者も同じtfstateファイルにアクセスできます。 S3バケットを指定しない場合、Terraformのディレクトリにtfstateが作成されます。 bucket = "s3-inaba" key = "terraform/techharmony/tfstate" region = "ap-northeast-1" profile = "inaba-poc" tfvarsファイルについて tfvarsファイルでは変数に指定するパラメータを定義します。 variable.tfファイルが下記コードの場合 variable vpc_cidr_block {} variable vpc_instance_tenancy {} variable enable_dns_support {} variable enable_dns_hostnames {} variable vpc_name_tag {} tfvarsファイルで、variable.tfファイルで定義されている変数とパラメータの組を記載することで、変数にパラメータが代入されます。 vpc_cidr_block = "10.0.0.0/16" vpc_instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true vpc_name_tag = "vpc" また、変数はmap形式で管理することもできます。 variable.tfファイルで変数を下記のように1つにまとめて variable vpc_args {} tfvarsファイルでは下記のようにmap形式でパラメータを記載します。 vpc_args = { cidr_block = "10.0.0.0/16" instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true name_tag = "vpc" } main.tfファイルでは下記のようにlookup(変数名、キー)で変数を使用することができます。 resource aws_vpc vpc { cidr_block = lookup(var.vpc_args, "cidr_block") instance_tenancy = lookup(var.vpc_args, "instance_tenancy") enable_dns_support = lookup(var.vpc_args, "enable_dns_support") enable_dns_hostnames = lookup(var.vpc_args, "enable_dns_hostnames") tags = { Name = lookup(var.vpc_args, "name_tag") } } user_data_script.tplファイル user_data_script.tplファイルではEC2の起動時に実行するスクリプトを定義しています。 本稿では詳細を省きますが、EFSのマウント、nginxのインストールと設定、phpとphp-fpmのインストールと設定、wordpressのインストールを行っています。 取り上げたいところとして、EFSをマウントする際に設定しているウェイトタイムですが、 これはEFS作成後、DNSの伝播が終わるまで90秒かかるためウェイトタイムを入れています。 私はEFSがマウントされず1日以上悩むことになりました。 Troubleshooting mount issues - Amazon Elastic File System Find information about troubleshooting EFS file system mounting issues. docs.aws.amazon.com # EFSマウント設定 yum install -y amazon-efs-utils efs_id="${efs_id}" mkdir /efs echo "$efs_id:/ /efs/ efs _netdev,nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport 0 0" >> /etc/fstab sleep 150 mount -a mkdir /efs/document_root   Terraformのセットアップと実行、Wordpressのセットアップ Terraformのセットアップ Terraformはtfenvを使用してインストールします。 tfenvを使用することで簡単にバージョン管理できます。 Cloud9上でセットアップする想定で、プロファイルは設定済みであることとします。 tfenvのインストール $ git clone https://github.com/tfutils/tfenv.git ~/.tfenv $ sudo ln -s ~/.tfenv/bin/* /usr/local/bin $ tfenv -v terraformのバージョン指定ファイルを作成 $ touch .terraform-version $ vi .terraform-version 1.8.5 terraformのインストールとバージョン指定する $ tfenv install $ tfenv use ※ M1 macの場合 $ TFENV_ARCH=amd64 tfenv install $ tfenv use Terraformの実行方法 コマンドを実行したディレクトリをTerraformで使用するために、下記コードで初期化します。 $ terraform init -backend-config="environments/dev/dev.tfbackend" 下記コードでDry Runの結果を確認します。 $ terraform plan -var-file="environments/dev/dev.tfvars" 下記コードでリソースを作成します。 $ terraform apply -var-file="environments/dev/dev.tfvars" 下記コードでリソースの削除ができます。 $ terraform destroy -var-file="environments/dev/dev.tfvars" WordPressのセットアップ Terraform実行後、outputに下記4つの変数が出力されるので、セットアップで使用します。 Outputs: alb_dns_name = "tf-lb-xxxxxxxxxxxxxxxxxx-xxxxxxxxx.ap-northeast-1.elb.amazonaws.com" # albへのアクセス先 rds_database_name = "xxxxxxxxxx" # データベース名 rds_endpoint = "xxxxxxxxx.xxxxxxxx.ap-northeast-1.rds.amazonaws.com:3306" # データベースのエンドポイント rds_password = "xxxxxxxxxxx" # データベースのパスワード 1. albへのアクセス先にブラウザでアクセスします。 2. 言語選択画面に遷移するので、日本語を指定してください。 3. その後データベースについての情報を入力することが求められます。 terraformのoutputに出力されたデータベース名、データベースのエンドポイント(データベースのホスト名)、データベースのパスワードを入力してください。 4. その後サイト名やWordpressユーザーの設定画面に遷移します。 サイト名やWordpressユーザー名を考え、入力してください。 先ほど作成したWordpressユーザーでログインできるようになります!   課題 本稿で作成したWordpressのサイトは非常に不安定でした(頻繁にタイムアウトします)。 EFSのメトリクスをみると、頻繁にメタデータへのアクセスがある状態です。 EFSのパフォーマンスチューニングが今後の課題です。   最後に WordPressの設定簡単だろうと思っていたら痛い目に会いました。。 相談に乗っていただいた方々( 木澤さん 、 広野さん 、 兒玉さん )には、本当に感謝しています。 非常に簡単にIaCできるのでTerraformはおすすめです!ぜひ触ってみてください!   コード main.tf terraform { backend s3 {} required_providers { aws = { source = "hashicorp/aws" version = "~> 5.57.0" } } } # ネットワーク ############################################################################################################## # VPC resource aws_vpc vpc { cidr_block = lookup(var.vpc_args, "cidr_block") instance_tenancy = lookup(var.vpc_args, "instance_tenancy") enable_dns_support = lookup(var.vpc_args, "enable_dns_support") enable_dns_hostnames = lookup(var.vpc_args, "enable_dns_hostnames") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.vpc_args, "name_tag")) } } # サブネット resource aws_subnet public_subnet_1a { vpc_id = aws_vpc.vpc.id cidr_block = lookup(var.public_subnet_1a_args, "cidr_block") map_public_ip_on_launch = true availability_zone = lookup(var.public_subnet_1a_args, "availability_zone") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.public_subnet_1a_args, "name_tag")) } } resource aws_subnet private_subnet_1a { vpc_id = aws_vpc.vpc.id cidr_block = lookup(var.private_subnet_1a_args, "cidr_block") availability_zone = lookup(var.private_subnet_1a_args, "availability_zone") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.private_subnet_1a_args, "name_tag")) } } resource aws_subnet public_subnet_1c { vpc_id = aws_vpc.vpc.id cidr_block = lookup(var.public_subnet_1c_args, "cidr_block") map_public_ip_on_launch = true availability_zone = lookup(var.public_subnet_1c_args, "availability_zone") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.public_subnet_1c_args, "name_tag")) } } resource aws_subnet private_subnet_1c { vpc_id = aws_vpc.vpc.id cidr_block = lookup(var.private_subnet_1c_args, "cidr_block") availability_zone = lookup(var.private_subnet_1c_args, "availability_zone") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.private_subnet_1c_args, "name_tag")) } } # インターネットゲートウェイ resource aws_internet_gateway internet_gateway { vpc_id = aws_vpc.vpc.id tags = { Name = format("%s-%s", var.name_prefix, var.internet_gateway_name_tag) } } # ルートテーブル resource aws_route_table route_table_to_internet { vpc_id = aws_vpc.vpc.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.internet_gateway.id } tags = { Name = format("%s-%s", var.name_prefix, var.route_table_to_internet_name_tag) } } # ルートテーブル 関連付け resource aws_route_table_association route_association_public_subnet_1a { subnet_id = aws_subnet.public_subnet_1a.id route_table_id = aws_route_table.route_table_to_internet.id } resource aws_route_table_association route_association_public_subnet_1c { subnet_id = aws_subnet.public_subnet_1c.id route_table_id = aws_route_table.route_table_to_internet.id } # EFS ################################################################################################################### resource "aws_efs_file_system" "efs" { performance_mode = lookup(var.efs_args, "performance_mode") throughput_mode = lookup(var.efs_args, "throughput_mode") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.efs_args, "name_tag")) } } # マウントターゲット resource "aws_efs_mount_target" "mount_target_1a" { file_system_id = aws_efs_file_system.efs.id subnet_id = aws_subnet.public_subnet_1a.id security_groups = [aws_security_group.security_group_for_efs.id] } resource "aws_efs_mount_target" "mount_target_1c" { file_system_id = aws_efs_file_system.efs.id subnet_id = aws_subnet.public_subnet_1c.id security_groups = [aws_security_group.security_group_for_efs.id] } # セキュリティグループ resource aws_security_group security_group_for_efs { description = lookup(var.security_group_for_efs_args, "description") vpc_id = aws_vpc.vpc.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_for_efs_args, "name_tag")) } } resource aws_vpc_security_group_ingress_rule ingress_rule_for_efs { from_port = lookup(var.security_group_ingress_for_efs_args, "ingress_from_port") to_port = lookup(var.security_group_ingress_for_efs_args, "ingress_to_port") ip_protocol = lookup(var.security_group_ingress_for_efs_args, "ingress_protocol") cidr_ipv4 = lookup(var.security_group_ingress_for_efs_args, "ingress_cidr_ipv4") referenced_security_group_id = aws_security_group.security_group_for_ec2.id security_group_id = aws_security_group.security_group_for_efs.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_for_efs_args, "name_tag")) } } resource aws_vpc_security_group_egress_rule egress_rule_for_efs { from_port = lookup(var.security_group_egress_for_efs_args, "egress_from_port") to_port = lookup(var.security_group_egress_for_efs_args, "egress_to_port") ip_protocol = lookup(var.security_group_egress_for_efs_args, "egress_protocol") cidr_ipv4 = lookup(var.security_group_egress_for_efs_args, "egress_cidr_ipv4") referenced_security_group_id = null security_group_id = aws_security_group.security_group_for_efs.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_egress_for_efs_args, "name_tag")) } } # EC2 #################################################################################################################### # ec2 launch template resource aws_launch_template ec2_launch_template { image_id = lookup(var.ec2_launch_template_args, "ami_id") instance_type = lookup(var.ec2_launch_template_args, "instance_type") user_data = base64encode(templatefile("user_data_script.tpl", { efs_id = aws_efs_file_system.efs.id #efs_id = aws_efs_file_system.efs.dns_name })) block_device_mappings { device_name = lookup(var.ec2_launch_template_args, "block_device_name") ebs { volume_size = lookup(var.ec2_launch_template_args, "ebs_volume_size") volume_type = lookup(var.ec2_launch_template_args, "ebs_volume_type") delete_on_termination = lookup(var.ec2_launch_template_args, "ebs_delete_on_termination") } } tag_specifications { resource_type = "instance" tags = { Name = format(lookup(var.ec2_launch_template_args, "instance_name_tag")) } } iam_instance_profile { name = aws_iam_instance_profile.instance_profile.name } network_interfaces { associate_public_ip_address = true security_groups = [aws_security_group.security_group_for_ec2.id] } tags = { Name = format(lookup(var.ec2_launch_template_args, "launch_template_name_tag")) } # efsのマウントをするため、マウントポイントが作成後EC2を作成する depends_on = [ aws_efs_file_system.efs ] } # EC2用セキュリティグループ resource aws_security_group security_group_for_ec2 { description = lookup(var.security_group_for_ec2_args, "description") vpc_id = aws_vpc.vpc.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_for_ec2_args, "name_tag")) } } resource aws_vpc_security_group_ingress_rule ingress_rule_from_alb_for_ec2 { from_port = lookup(var.security_group_ingress_from_alb_for_ec2_args, "ingress_from_port") to_port = lookup(var.security_group_ingress_from_alb_for_ec2_args, "ingress_to_port") ip_protocol = lookup(var.security_group_ingress_from_alb_for_ec2_args, "ingress_protocol") cidr_ipv4 = lookup(var.security_group_ingress_from_alb_for_ec2_args, "ingress_cidr_ipv4") referenced_security_group_id = aws_security_group.security_group_for_alb.id security_group_id = aws_security_group.security_group_for_ec2.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_from_alb_for_ec2_args, "name_tag")) } } resource aws_vpc_security_group_ingress_rule ingress_rule_from_internet_for_ec2 { from_port = lookup(var.security_group_ingress_from_internet_for_ec2_args, "ingress_from_port") to_port = lookup(var.security_group_ingress_from_internet_for_ec2_args, "ingress_to_port") ip_protocol = lookup(var.security_group_ingress_from_internet_for_ec2_args, "ingress_protocol") cidr_ipv4 = lookup(var.security_group_ingress_from_internet_for_ec2_args, "ingress_cidr_ipv4") referenced_security_group_id = null security_group_id = aws_security_group.security_group_for_ec2.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_from_internet_for_ec2_args, "name_tag")) } } resource aws_vpc_security_group_egress_rule egress_rule_for_ec2 { from_port = lookup(var.security_group_egress_for_ec2_args, "egress_from_port") to_port = lookup(var.security_group_egress_for_ec2_args, "egress_to_port") ip_protocol = lookup(var.security_group_egress_for_ec2_args, "egress_protocol") cidr_ipv4 = lookup(var.security_group_egress_for_ec2_args, "egress_cidr_ipv4") referenced_security_group_id = null security_group_id = aws_security_group.security_group_for_ec2.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_egress_for_ec2_args, "name_tag")) } } # インスタンスプロファイル(インスタンスとIAM Roleの関連付け) resource aws_iam_instance_profile instance_profile { tags = { Name = format("%s-%s", var.name_prefix, lookup(var.ec2_role_settings_args , "instance_profile_name_tag")) } role = aws_iam_role.instance_role.name } # IAM ロール resource aws_iam_role instance_role { tags = { Name = format("%s-%s", var.name_prefix, lookup(var.ec2_role_settings_args , "iam_role_name_tag")) } assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json } data aws_iam_policy_document assume_role_policy { statement { actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["ec2.amazonaws.com"] } } } # SSM用ポリシー resource aws_iam_role_policy_attachment attachment_ssm { role = aws_iam_role.instance_role.name policy_arn = data.aws_iam_policy.ssm_policy.arn } data aws_iam_policy ssm_policy { name = "AmazonSSMManagedInstanceCore" } # cloudwatchエージェント用ポリシー resource aws_iam_role_policy_attachment attachment_cloudwatch_agent { role = aws_iam_role.instance_role.name policy_arn = data.aws_iam_policy.cloudwatch_agent_policy.arn } data aws_iam_policy cloudwatch_agent_policy { name = "CloudWatchAgentServerPolicy" } # ALB #################################################################################### # alb resource aws_lb alb { internal = false load_balancer_type = "application" security_groups = [aws_security_group.security_group_for_alb.id] subnets = [aws_subnet.public_subnet_1a.id, aws_subnet.private_subnet_1c.id] tags = { Name = format("%s-%s", var.name_prefix, lookup(var.alb_args, "name_tag")) } } # ターゲットグループ resource aws_lb_target_group target_group { port = 80 protocol = "HTTP" vpc_id = aws_vpc.vpc.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.target_group_args, "name_tag")) } health_check { interval = lookup(var.target_group_args, "health_check_interval") path = lookup(var.target_group_args, "health_check_path") port = "traffic-port" protocol = "HTTP" timeout = lookup(var.target_group_args, "health_check_timeout") healthy_threshold = lookup(var.target_group_args, "healthy_threshold") unhealthy_threshold = lookup(var.target_group_args, "unhealthy_threshold") } stickiness { cookie_duration = lookup(var.target_group_args, "stickiness_cookie_duration") enabled = lookup(var.target_group_args, "stickiness_enables") type = lookup(var.target_group_args, "stickiness_type") } } # リスナー resource aws_lb_listener listener { load_balancer_arn = aws_lb.alb.arn port = "80" protocol = "HTTP" default_action { target_group_arn = aws_lb_target_group.target_group.arn type = "forward" } tags = { Name = format("%s-%s", var.name_prefix, var.listener_name_tag) } } # Auto Scaling Group resource aws_autoscaling_group auto_scaling_group { name = format("%s-%s", var.name_prefix, lookup(var.auto_scaling_args, "name")) max_size = lookup(var.auto_scaling_args, "max_size") min_size = lookup(var.auto_scaling_args, "min_size") health_check_grace_period = lookup(var.auto_scaling_args, "health_check_grace_period") health_check_type = lookup(var.auto_scaling_args, "health_check_type") desired_capacity = lookup(var.auto_scaling_args, "desired_capacity") vpc_zone_identifier = [aws_subnet.public_subnet_1a.id, aws_subnet.public_subnet_1c.id] target_group_arns = [aws_lb_target_group.target_group.arn] launch_template { id = aws_launch_template.ec2_launch_template.id version = aws_launch_template.ec2_launch_template.latest_version } } # セキュリティグループ resource aws_security_group security_group_for_alb { description = lookup(var.security_group_for_alb_args, "description") vpc_id = aws_vpc.vpc.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_for_alb_args, "name_tag")) } } resource aws_vpc_security_group_ingress_rule ingress_rule_for_alb { from_port = lookup(var.security_group_ingress_for_alb_args, "ingress_from_port") to_port = lookup(var.security_group_ingress_for_alb_args, "ingress_to_port") ip_protocol = lookup(var.security_group_ingress_for_alb_args, "ingress_protocol") cidr_ipv4 = lookup(var.security_group_ingress_for_alb_args, "ingress_cidr_ipv4") referenced_security_group_id = null security_group_id = aws_security_group.security_group_for_alb.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_for_alb_args, "name_tag")) } } resource aws_vpc_security_group_egress_rule egress_rule_for_alb { from_port = lookup(var.security_group_egress_for_alb_args, "egress_from_port") to_port = lookup(var.security_group_egress_for_alb_args, "egress_to_port") ip_protocol = lookup(var.security_group_egress_for_alb_args, "egress_protocol") cidr_ipv4 = lookup(var.security_group_egress_for_alb_args, "egress_cidr_ipv4") referenced_security_group_id = null security_group_id = aws_security_group.security_group_for_alb.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_egress_for_alb_args, "name_tag")) } } # RDS ########################################################################################################### # RDS DB インスタンス resource aws_db_instance rds { allocated_storage = lookup(var.rds_args, "allocated_storage") max_allocated_storage = lookup(var.rds_args, "max_allocated_storage") storage_type = lookup(var.rds_args, "storage_type") engine = lookup(var.rds_args, "engine") engine_version = lookup(var.rds_args, "engine_version") instance_class = lookup(var.rds_args, "instance_class") multi_az = lookup(var.rds_args, "multi_az") skip_final_snapshot = lookup(var.rds_args, "skip_final_snapshot") identifier = lookup(var.rds_args, "identifier") db_name = lookup(var.rds_args, "db_name") username = lookup(var.rds_args, "username") password = lookup(var.rds_args, "password") vpc_security_group_ids = [aws_security_group.security_group_for_rds.id] parameter_group_name = aws_db_parameter_group.parameter_group.name option_group_name = aws_db_option_group.option_group.name db_subnet_group_name = aws_db_subnet_group.subnet_group.name tags = { Name = format("%s-%s", var.name_prefix, lookup(var.rds_args, "name_tag")) } } # パラメータグループ resource aws_db_parameter_group parameter_group { family = lookup(var.parameter_group_args, "family") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.parameter_group_args, "name_tag")) } } # オプショングループ resource aws_db_option_group option_group { engine_name = lookup(var.option_group_args, "engine_name") major_engine_version = lookup(var.option_group_args, "major_engine_version") tags = { Name = format("%s-%s", var.name_prefix, lookup(var.option_group_args, "name_tag")) } } # サブネットグループ resource aws_db_subnet_group subnet_group { subnet_ids = [aws_subnet.private_subnet_1a.id, aws_subnet.private_subnet_1c.id] tags = { Name = format("%s-%s", var.name_prefix, var.subnet_group_name_tag) } } # セキュリティグループ resource aws_security_group security_group_for_rds { description = lookup(var.security_group_for_rds_args, "description") vpc_id = aws_vpc.vpc.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_for_rds_args, "name_tag")) } } resource aws_vpc_security_group_ingress_rule ingress_rule_for_rds { from_port = lookup(var.security_group_ingress_for_rds_args, "ingress_from_port") to_port = lookup(var.security_group_ingress_for_rds_args, "ingress_to_port") ip_protocol = lookup(var.security_group_ingress_for_rds_args, "ingress_protocol") cidr_ipv4 = lookup(var.security_group_ingress_for_rds_args, "ingress_cidr_ipv4") referenced_security_group_id = aws_security_group.security_group_for_ec2.id security_group_id = aws_security_group.security_group_for_rds.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_for_rds_args, "name_tag")) } } resource aws_vpc_security_group_egress_rule egress_rule_for_rds { from_port = lookup(var.security_group_egress_for_rds_args, "egress_from_port") to_port = lookup(var.security_group_egress_for_rds_args, "egress_to_port") ip_protocol = lookup(var.security_group_egress_for_rds_args, "egress_protocol") cidr_ipv4 = lookup(var.security_group_egress_for_rds_args, "egress_cidr_ipv4") referenced_security_group_id = null security_group_id = aws_security_group.security_group_for_rds.id tags = { Name = format("%s-%s", var.name_prefix, lookup(var.security_group_ingress_for_rds_args, "name_tag")) } } variable.tf variable name_prefix {} # ネットワーク variable vpc_args {} variable public_subnet_1a_args {} variable private_subnet_1a_args {} variable public_subnet_1c_args {} variable private_subnet_1c_args {} variable internet_gateway_name_tag {} variable route_table_to_internet_name_tag {} # efs variable efs_args {} variable security_group_for_efs_args {} variable security_group_ingress_for_efs_args {} variable security_group_egress_for_efs_args {} # wordpress ec2 variable ec2_launch_template_args {} variable security_group_for_ec2_args {} variable security_group_ingress_from_alb_for_ec2_args {} variable security_group_ingress_from_internet_for_ec2_args {} variable security_group_egress_for_ec2_args {} variable ec2_role_settings_args {} # alb variable alb_args {} variable target_group_args {} variable listener_name_tag {} variable auto_scaling_args {} variable security_group_for_alb_args {} variable security_group_ingress_for_alb_args {} variable security_group_egress_for_alb_args {} # rds variable rds_args {} variable option_group_args {} variable parameter_group_args {} variable subnet_group_name_tag {} variable security_group_for_rds_args {} variable security_group_ingress_for_rds_args {} variable security_group_egress_for_rds_args {} output.tf output vpc_id { value = aws_vpc.vpc.id } output alb_dns_name { value = aws_lb.alb.dns_name } output rds_endpoint { value = aws_db_instance.rds.endpoint } output rds_user { value = lookup(var.rds_args, "username") } output rds_password { value = lookup(var.rds_args, "password") } output rds_database_name { value = lookup(var.rds_args, "db_name") } provider.tf provider aws { region = "ap-northeast-1" profile = "inaba-poc" default_tags { tags = { Project = "wordpress" Terraform = "true" } } } user_data_script.tpl #!./bin/bash # yumアップデート yum update -y # EFSマウント設定 yum install -y amazon-efs-utils efs_id="${efs_id}" mkdir /efs echo "$efs_id:/ /efs/ efs _netdev,nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport 0 0" >> /etc/fstab sleep 150 mount -a mkdir /efs/document_root # RDS接続用のsqlクライアントのインストール yum install -y mariadb # nginxのインストール yum install -y nginx systemctl start nginx systemctl enable nginx # phpのインストール yum install -y php php-fpm php-mysqlnd systemctl start php-fpm mv /etc/php-fpm.d/www.conf /etc/php-fpm.d/bk-www.conf # php-fpmの設定 cat < /etc/php-fpm.d/www.conf [www] user = nginx group = nginx listen = /run/php-fpm/www.sock listen.owner = nginx listen.group = nginx listen.acl_users = apache,nginx listen.allowed_clients = 127.0.0.1 pm = dynamic pm.max_children = 50 pm.start_servers = 5 pm.min_spare_servers = 5 pm.max_spare_servers = 35 slowlog = /var/log/php-fpm/www-slow.log php_admin_value[error_log] = /var/log/php-fpm/www-error.log php_admin_flag[log_errors] = on php_value[session.save_handler] = files php_value[session.save_path] = /var/lib/php/session php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache EOF systemctl restart php-fpm systemctl enable php-fpm # wordpressのインストール wget https://wordpress.org/latest.tar.gz -P /tmp tar -xzf /tmp/latest.tar.gz -C /tmp/ mv /tmp/wordpress/* /efs/document_root chown -R nginx:nginx /efs/* # nginx の設定 cat < /etc/nginx/conf.d/wordpress.conf server { listen 80; server_name _; root /efs/document_root/; index index.php index.html index.htm; location / { try_files \$uri \$uri/ /index.php?\$args; } location ~ \.php$ { include /etc/nginx/fastcgi_params; fastcgi_pass unix:/run/php-fpm/www.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; } } EOF # ヘルスチェック用ファイルの作成 mkdir /efs/document_root/health_check touch /efs/document_root/health_check/health_check_file systemctl restart nginx environments/dev/dev.tfvars ※セキュリティグループのインバウンドルールに指定するIPアドレスは、コピペ後埋めてください。 name_prefix = "inaba-wp-dev" # ネットワーク ############################################################################## vpc_args = { cidr_block = "10.0.0.0/16" instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true name_tag = "vpc" } public_subnet_1a_args = { cidr_block = "10.0.0.0/24" availability_zone = "ap-northeast-1a" name_tag = "public-subnet-1a" } private_subnet_1a_args = { cidr_block = "10.0.2.0/24" availability_zone = "ap-northeast-1a" name_tag = "private-subnet-1a" } public_subnet_1c_args = { cidr_block = "10.0.1.0/24" availability_zone = "ap-northeast-1c" name_tag = "public-subnet-1c" } private_subnet_1c_args = { cidr_block = "10.0.3.0/24" availability_zone = "ap-northeast-1c" name_tag = "private-subnet-1c" } internet_gateway_name_tag = "igw" route_table_to_internet_name_tag = "route_table_to_internet" # EFS ########################################################################################### efs_args = { name_tag = "efs" performance_mode = "generalPurpose" throughput_mode = "elastic" } security_group_for_efs_args = { name_tag = "security-group-for-efs" description = "for efs" } security_group_ingress_for_efs_args = { name_tag = "ingress-rule-for-efs" ingress_from_port = 2049 ingress_to_port = 2049 ingress_protocol = "tcp" ingress_cidr_ipv4 = null } security_group_egress_for_efs_args = { name_tag = "egress-rule-for-efs" egress_from_port = 0 egress_to_port = 0 egress_protocol = "-1" egress_cidr_ipv4 = "0.0.0.0/0" } # EC2 #################################################################################### ec2_launch_template_args = { ami_id = "ami-03350e4f182961c7f" # Amazon Linux 2023 AMI instance_type = "t3.medium" block_device_name = "/dev/xvde" #ebsよくわからない 調べる ebs_volume_size = "30" ebs_volume_type = "gp3" ebs_delete_on_termination = true instance_name_tag = "wordpress-ec2" launch_template_name_tag = "launch-template-for-wordpress-ec2" } security_group_for_ec2_args = { name_tag = "security-group-for-ec2" description = "for ec2" } security_group_ingress_from_alb_for_ec2_args = { name_tag = "ingress-rule-from-alb-for-ec2" ingress_from_port = 80 ingress_to_port = 80 ingress_protocol = "tcp" ingress_cidr_ipv4 = null } security_group_ingress_from_internet_for_ec2_args = { name_tag = "ingress-rule-from-internet-for-ec2" ingress_from_port = 80 ingress_to_port = 80 ingress_protocol = "tcp" ingress_cidr_ipv4 = "xxx.xxx.xxx.xxx/32"# マイIP } security_group_egress_for_ec2_args = { name_tag = "egress-rule-for-ec2" egress_from_port = 0 egress_to_port = 0 egress_protocol = "-1" egress_cidr_ipv4 = "0.0.0.0/0" } ec2_role_settings_args = { instance_profile_name_tag = "instance-profile-for-wordpress-ec2" iam_role_name_tag = "iam-role-for-wordpress-ec2" } # alb ############################################################################################ alb_args = { name_tag = "alb" } target_group_args = { name_tag = "target-group" health_check_interval = 10 health_check_path = "/health_check/health_check_file" health_check_timeout = 5 healthy_threshold = 3 unhealthy_threshold = 3 stickiness_cookie_duration = 1800 stickiness_enables = true stickiness_type = "lb_cookie" } listener_name_tag = "linstener" auto_scaling_args = { name = "auto-scaling" max_size = 2 min_size = 1 health_check_grace_period = 300 health_check_type = "EC2" desired_capacity = 2 } security_group_for_alb_args = { name_tag = "security-group-for-alb" description = "for alb" } security_group_ingress_for_alb_args = { name_tag = "ingress-rule-for-alb" ingress_from_port = 80 ingress_to_port = 80 ingress_protocol = "tcp" ingress_cidr_ipv4 = "xxx.xxx.xxx.xxx/32"# マイIP } security_group_egress_for_alb_args = { name_tag = "egress-rule-for-alb" egress_from_port = 0 egress_to_port = 0 egress_protocol = "-1" egress_cidr_ipv4 = "0.0.0.0/0" } # RDS ################################################################################################ rds_args = { allocated_storage = 20 max_allocated_storage = 200 storage_type = "gp3" engine = "mariadb" engine_version = "10.11" instance_class = "db.t3.micro" multi_az = true skip_final_snapshot = true identifier = "wordpressdb" db_name = "wordpressdb" username = "root" password = "password" name_tag = "db" } option_group_args = { engine_name = "mariadb" major_engine_version = "10.11" name_tag = "option-group" } parameter_group_args = { family = "mariadb10.11" name_tag = "parameter-group" } subnet_group_name_tag = "subnet_group" security_group_for_rds_args = { name_tag = "security-group-for-eds" description = "for rds" } security_group_ingress_for_rds_args = { name_tag = "egress-rule-for-rds" ingress_from_port = 3306 ingress_to_port = 3306 ingress_protocol = "tcp" ingress_cidr_ipv4 = null } security_group_egress_for_rds_args = { name_tag = "egress-rule-for-rds" egress_from_port = 0 egress_to_port = 0 egress_protocol = "-1" egress_cidr_ipv4 = "0.0.0.0/0" } environments/dev/dev.tfbackend bucket = "s3-inaba" key = "terraform/techharmony/tfstate" region = "ap-northeast-1" profile = "inaba-poc"
本記事は 夏休みクラウド自由研究 8/24付の記事です 。 皆さんこんにちは。UGです。 自分が書いた字を見て、ふと子供の頃は大人になったら自然と字って綺麗になっていくものだと思っていたなーと。 もちろん自然と綺麗になることなどなく、何なら昔の方が綺麗だったんじゃないか??と思った今日この頃。。。 さて本題ですが、以前AWS情報で見かけて気になっていながら触れられていなかった、Amazon CloudWatchでAIを活用した自然言語クエリ生成を試してみました。 CloudWatch Logs InsightsとCloudWatch Metrics Insightsにて自然言語でクエリ生成ができるとのことです。 Amazon CloudWatch announces AI-Powered natural language query generation - AWS Discover more about what's new at AWS with Amazon CloudWatch announces AI-Powered natural language query generation aws.amazon.com 現時点(2024/8/25時点)では、米国東部 (バージニア北部)、米国西部 (オレゴン)、アジアパシフィック (東京) でのみ使用できるようです。 はてさてどれほど便利なものなのか。 やってみる CloudWatch Logs Insights まずはCloudWatch Logs Insightsの自然言語クエリ生成から試してみます。 [CloudWatch] → [ログのインサイト]を開くと 「Query generator」 なるものが画面に表示されています。 「Query generator」 をクリックして展開します。 プロンプトの横の 「情報」 をクリックすると、画面右側にQuery generatorの説明が表示されます。(以下に説明文からプロンプトの例のみを抜粋) 良いプロンプトの例 このプロンプトでは、選択したロググループ内のさまざまなクライアントの例外を一覧表示するクエリを生成できます。 What types of client exceptions are in my logs? このプロンプトでは、最新の 5 つのログパターンを一覧表示するクエリを生成できます。 List the 5 most frequent patterns in my exception logs このプロンプトでは、請求額が最も高い Lambda 呼び出しの上位 100 件を検索するクエリを生成できます。 Return the top 100 highest billed lambda invocations このプロンプトでは、IAM ロールまたはポリシーが変更された最新の CloudTrail イベントを検索するクエリを生成できます。 Return the most recent events with changes to IAM role or policy events このプロンプトでは、仮想プライベートクラウドログ内の最新の 20 件の TCP リクエストを返すクエリを生成できます。 What are the 20 most recent TCP requests? 上記の例のように、自然言語には 英語のみ が利用できます。 では実際に試してみます。 ロググループを選択し、 「Show the oldest 3 logs(最も古いログを3件表示)」 をプロンプトに入力して、「新しいクエリを生成」をクリックします。 そうすると画像のようなクエリ文が自動で生成されました。 「クエリを更新」はクエリ文が記載済みの場合に、新しいプロンプトの内容からクエリを生成し更新を行います。 「クエリを更新」はクエリ文が記載されていない場合は選択ができません。 「新しいクエリを生成」はクエリ文が記載済みであろうとなかろうと選択できるので、「クエリを更新」は使わず、常に「新しいクエリを生成」を選択で良いと思います。 「クエリの実行」をクリックし、クエリを実行すると、最も古いログが3件表示されていました。 CloudWatch Metrics Insights 次にCloudWatch Metrics Insightsの自然言語クエリ生成を試してみます。 [CloudWatch] → [すべてのメトリクス]から[マルチソースクエリ]タブを開くと、今回も 「Query generator」 なるものが画面に表示されています。 プロンプトの横の 「情報」 をクリックすると、画面右側にQuery generatorの説明が表示されます。(以下に説明文からプロンプトの例のみを抜粋) 適切なプロンプトの例 このプロンプトは、消費された読み取りキャパシティユニットごとにソートされた 10 個の DynamoDB テーブルのリストを返すクエリを生成できます。 消費された読み取りキャパシティユニットの順に上位 10 個の DynamoDB テーブルを検索する このプロンプトは、エラー数が最も多い 10 個の DynamoDB テーブルのリストを返すクエリを生成できます。 トランザクション競合エラーの数が最も多い上位 10 個の DynamoDB テーブルを検索する このプロンプトは、書き込み数でランク付けされた 10 個の RDS クラスターのリストを返すクエリを生成できます。 書き込み順で上位 10 個の RDS クラスターを検索する このプロンプトは、ダウンロードされたバイト数の順に整理された上位 10 個の S3 バケットのリストを返すクエリを生成できます。 ダウンロードされたバイト数の順で上位 10 個の S3 バケットを検索する このプロンプトは、どの AWS サービスの使用率が最も高いかを示すクエリを生成できます。 自分のアカウントで最も多く使用されている AWS サービスを検索する あれ?今回は日本語で表示されているぞ? つまりは日本語でできるのか?と思いダメ元でチャレンジ。 怒られました…やはり日本語は対応していないようです。例文はミスかと。 では丁度良いので上の日本語例文をGoogle翻訳で英文にして自動生成を行ってみます。 翻訳:「自分のアカウントで最も多く使用されている AWS サービスを検索する」⇒「Find the most used AWS services in your account」 上記翻訳結果をプロンプトに入力して、「新しいクエリを生成」をクリックします。 そうすると画像のようなクエリ文が自動で生成されました。 「Editor」画面ではクエリ文が以下のようになります。 んん?自動生成されたクエリが明らかにおかしいなと。。。見るからにAPIのリクエスト数を調べるクエリですね… どうやら失敗のようです。。。 100%の精度があるわけではもちろんないので仕方がないですね。 まとめ ということでAIを活用した自然言語クエリ生成を試してみました。 クエリ言語に関する知識が少ないという方には、一からコードを書く必要がないため良い手助けになるなと思いました。 しかしその半面、少ないからこそ今回の失敗例のようなときに気づくことができない恐れもあるため、頼り切った利用は危険とも思いました。 他のAI利用でも同じですが、あくまで参考であって自分で調べて確かめることが大事だなと。 最後までお読みいただきありがとうございました!!
本記事は 夏休みクラウド自由研究 8/23付の記事です 。 こんにちは。AWS の作業を日々少しでも楽にしようと取り組んでいる兒玉です。 皆さん、AWS CloudFormation を使ってテンプレートを作成する際に、実行時エラーの修正を何度も行う際に、AWS Management Console を使って CloudFormation スタックへのパラメータの入力を何度も繰り返して行わないといけなくて、うんざりした経験はありませんか? 今回は、そんな際に CloudFormation のスタックを AWS CLI のコマンドを使って楽に何度も同じパラメータ入力をしなくても良いようにしよう、というちょっとした小技の紹介です。 なぜAWS CLI? CloudFormation スタックの実行時は様々なパラメータを毎回 4 ステップ分入力する必要があります。 テンプレートファイルを選択して、ローカルからアップロード スタック名を入力して、スタックのパラメータをパラメータ数分だけ入力 タグを必要な数だけ入力、その他詳細オプション等あれば入力 入力した値を確認して送信 という手順になります。1回や2回くらいなら、「まぁ、手打ちでもいいか…」 となるのですが、テンプレートを作成中などで、テンプレートに不具合があってうまくスタックが作成完了しなかった場合には、ロールバックして、再度スタックを作成するために上記の4手順を行って… と繰り返していくと、テンプレート内の不具合がなかなか解消しなかった場合には段々とイライラしてきます… 何度も同じパラメータも同じで何度も実行するので、1回ちょっと手間をかけたら、あとはサッとスムーズに実行して、テンプレートの不具合修正に集中したいところです。 そこで、 CLI の出番です。 CLI なら、テキストエディタでコマンドを一回編集して貼り付ければ、あとは何度も同じ操作を実行する場合にはコマンド履歴からキーボード数回打鍵するだけで実行可能です! やってみよう 早速、やってみましょう。 今回利用するのは以下の CloudFormationテンプレートです。VPCと、インターネットゲートウェイ、S3ゲートウェイエンドポイントを作るだけなのですが、パラメータの入力(4つ)を使ってタグ付けをしていて、しかも CreateDate は今日の日付を入れようという、スタック作成時に面倒なテンプレートです。 --- AWSTemplateFormatVersion: "2010-09-09" Description: Create VPC*1, Subnet*2, InternetGateway*1, RouteTable*1 NACL*1 S3 GatewayEndpoint * 1 Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Common Settings Parameters: - ProjectName - Environment - CostTagValue - CreateDate - Label: default: VPC Settings Parameters: - VPCCidr - PublicSubnetCidr1 - PublicSubnetCidr2 - PrivateSubnetCidr1 - PrivateSubnetCidr2 Parameters: ProjectName: Description: Project Name Type: String Default: unnamed Environment: Description: Environment Type: String Default: sbx AllowedValues: - prd - dev - stg - sbx VPCCidr: Description: VPC IP Range Type: String Default: 10.0.0.0/16 AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$' PublicSubnetCidr1: Description: Public Subnet 1 IP Range Type: String Default: 10.0.1.0/24 AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$' PublicSubnetCidr2: Description: Public Subnet 2 IP Range Type: String Default: 10.0.2.0/24 AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$' PrivateSubnetCidr1: Description: Private Subnet 1 IP Range Type: String Default: 10.0.17.0/24 AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$' PrivateSubnetCidr2: Description: Private Subnet 2 IP Range Type: String Default: 10.0.18.0/24 AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$' CostTagValue: Description: Tag Value for Cost allocation tag. Type: String Default: nanashi CreateDate: Description: Create Date Type: String Default: 2023/09/15 Resources: # Create VPC VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VPCCidr EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-vpc - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} # Create InternetGateway & VPC Attach InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-igw - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway # Create Public RouteTable & Setting Routing PublicRouteTable1: Type: AWS::EC2::RouteTable DependsOn: AttachGateway Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-public-rtb1 - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PublicRoute1: Type: AWS::EC2::Route DependsOn: AttachGateway Properties: RouteTableId: !Ref PublicRouteTable1 DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway # Create Public Subnet *2 # Public 1 PublicSubnet1: Type: AWS::EC2::Subnet DependsOn: AttachGateway Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ""] CidrBlock: !Ref PublicSubnetCidr1 MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-public-subnet1 - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PublicSubnetRouteTableAssociation1: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet1 RouteTableId: !Ref PublicRouteTable1 # Public 2 PublicSubnet2: Type: AWS::EC2::Subnet DependsOn: AttachGateway Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ""] CidrBlock: !Ref PublicSubnetCidr2 MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-public-subnet2 - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PublicSubnetRouteTableAssociation2: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet2 RouteTableId: !Ref PublicRouteTable1 # Create Private Subnet *2 # Private 1 PrivateSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ""] CidrBlock: !Ref PrivateSubnetCidr1 Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-private-subnet1 - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PrivateRouteTable1: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-private-rtb1 - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PrivateSubnetRouteTableAssociation1: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnet1 RouteTableId: !Ref PrivateRouteTable1 # Private 2 PrivateSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ""] CidrBlock: !Ref PrivateSubnetCidr2 Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-private-subnet2 - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PrivateRouteTable2: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-private-rtb2 - Key: Environment Value: !Sub ${Environment} - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} PrivateSubnetRouteTableAssociation2: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnet2 RouteTableId: !Ref PrivateRouteTable2 # Create Network ACL # Public NACL PublicNetworkACL1: Type: AWS::EC2::NetworkAcl Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-public-nacl1 - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} NetworkACLEntryPublicIngress1: Type: AWS::EC2::NetworkAclEntry Properties: CidrBlock: "0.0.0.0/0" Egress: false NetworkAclId: !Ref PublicNetworkACL1 Protocol: -1 RuleAction: "allow" RuleNumber: 100 NetworkACLEntryPublicEgress1: Type: "AWS::EC2::NetworkAclEntry" Properties: CidrBlock: "0.0.0.0/0" Egress: true NetworkAclId: !Ref PublicNetworkACL1 Protocol: -1 RuleAction: "allow" RuleNumber: 100 # Private NACL PrivateNetworkACL1: Type: AWS::EC2::NetworkAcl Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${ProjectName}-${Environment}-Private-nacl1 - Key: Cost Value: !Sub ${CostTagValue} - Key: CreateDate Value: !Sub ${CreateDate} NetworkACLEntryPrivateIngress1: Type: AWS::EC2::NetworkAclEntry Properties: CidrBlock: "0.0.0.0/0" Egress: false NetworkAclId: !Ref PrivateNetworkACL1 Protocol: -1 RuleAction: "allow" RuleNumber: 100 NetworkACLEntryPrivateEgress1: Type: "AWS::EC2::NetworkAclEntry" Properties: CidrBlock: "0.0.0.0/0" Egress: true NetworkAclId: !Ref PrivateNetworkACL1 Protocol: -1 RuleAction: "allow" RuleNumber: 100 # VPC Endpoint for S3 gateway Endpoint # prod-region-starport-layer-bucket is ECR used S3 bucket for Docker image download from ECR. # https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/vpc-endpoints.html#ecr-minimum-s3-perms S3Endpoint: Type: AWS::EC2::VPCEndpoint Properties: PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: '*' Action: - s3:* Resource: - !Sub arn:aws:s3:::*${AWS::Region}.amazon.com/* - !Sub arn:aws:s3:::*${AWS::Region}.amazon.com/ - Effect: Allow Principal: '*' Action: - s3:GetObject Resource: - !Sub arn:aws:s3:::prod-${AWS::Region}-starport-layer-bucket/* RouteTableIds: - !Ref PublicRouteTable1 - !Ref PrivateRouteTable1 - !Ref PrivateRouteTable2 ServiceName: !Sub com.amazonaws.${AWS::Region}.s3 VpcId: !Ref VPC VpcEndpointType: Gateway # NetworkACL Association PublicNetworkACLAssocation1: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: SubnetId: !Ref PublicSubnet1 NetworkAclId: !Ref PublicNetworkACL1 PublicNetworkACLAssocation2: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: SubnetId: !Ref PublicSubnet2 NetworkAclId: !Ref PublicNetworkACL1 PrivateNetworkACLAssocation1: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: SubnetId: !Ref PrivateSubnet1 NetworkAclId: !Ref PrivateNetworkACL1 PrivateNetworkACLAssocation2: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: SubnetId: !Ref PrivateSubnet2 NetworkAclId: !Ref PrivateNetworkACL1 Outputs: ExportVPC: Value: !Ref VPC Export: Name: !Sub ${ProjectName}-${Environment}-VPC ExportVPCCidr: Value: !Ref VPCCidr Export: Name: !Sub ${ProjectName}-${Environment}-VPCCidr ExportPublicSubnet1: Value: !Ref PublicSubnet1 Export: Name: !Sub ${ProjectName}-${Environment}-PublicSubnet1 ExportPublicSubnet2: Value: !Ref PublicSubnet2 Export: Name: !Sub ${ProjectName}-${Environment}-PublicSubnet2 ExportPrivateSubnet1: Value: !Ref PrivateSubnet1 Export: Name: !Sub ${ProjectName}-${Environment}-PrivateSubnet1 ExportPrivateSubnet2: Value: !Ref PrivateSubnet2 Export: Name: !Sub ${ProjectName}-${Environment}-PrivateSubnet2 ExportPrivateRouteTable1: Value: !Ref PrivateRouteTable1 Export: Name: !Sub ${ProjectName}-${Environment}-PrivateRouteTable1 ExportPrivateRouteTable2: Value: !Ref PrivateRouteTable2 Export: Name: !Sub ${ProjectName}-${Environment}-PrivateRouteTable2 ExportS3GatewayEndpoint: Value: !Ref S3Endpoint Export: Name: !Sub ${ProjectName}-${Environment}-S3GatewayEndpoint 今回は AWS のアクセスキー設定等が不要で便利な AWS CloudShell 環境(Amazon linux 2023でした)から実行します。 [cloudshell-user@ip-10-130-56-54 kodama-th-cloundformation-cli]$ cat /etc/os-release | grep PRETTY_NAME PRETTY_NAME="Amazon Linux 2023.5.20240708" 上記のCloudFormationテンプレートを、vpc.yaml として保存して、カレントディレクトリに配置しておきます。 [cloudshell-user@ip-10-130-56-54 kodama-th-cloundformation-cli]$ [cloudshell-user@ip-10-130-56-54 kodama-th-cloundformation-cli]$ ls -la total 20 drwxr-xr-x. 2 cloudshell-user cloudshell-user 4096 Aug 21 14:51 . drwxr-xr-x. 21 cloudshell-user cloudshell-user 4096 Aug 21 14:51 .. -rw-r--r--. 1 cloudshell-user cloudshell-user 11885 Aug 21 14:51 vpc.yaml この状態で、以下コマンドをのCLIをテキストエディタなどで編集したあと、コマンドラインにはりつけて実行します。 STACK_NAME= <作成する CloudFormationスタックの名前 kodama-th-sample-stackname> TEMPLATE_FILE= <CloudFormation テンプレートファイルの名前> TIMEOUT_IN_MINUTES= <スタックのタイムアウト時間(分)> PROJECT_NAME= <作成するリソースに付与する Project タグ名> COST= <作成するリソースに付与する Cost タグ名> Environment= <デプロイするリソースの環境, prd, dev, stg, sbx のいずれか> aws cloudformation create-stack \ --stack-name ${STACK_NAME} \ --template-body "file://${TEMPLATE_FILE}" \ --parameters \ ParameterKey="ProjectName",ParameterValue="${PROJECT_NAME}" \ ParameterKey="Environment",ParameterValue="${Environment}" \ ParameterKey="CostTagValue",ParameterValue="${COST}" \ --tags \ Key=Cost,Value="${COST}" \ Key=Project,Value="${PROJECT_NAME}" \ Key=Environment,Value="${Environment}" \ Key=Name,Value=${STACK_NAME} \ Key=CreateDate,Value=$(date '+%Y/%m/%d') \ --timeout-in-minutes="${TIMEOUT_IN_MINUTES}" \ --capabilities CAPABILITY_NAMED_IAM 今日の日付を CreateDate タグにつけているのですが、これを Linux の date コマンドを利用して自動的にちゃんと実行した日付になるようにしています。 赤字の部分は、必要に応じて書き直すのですが、今回は、 STACK_NAME= kodama-th-sample-stackname TEMPLATE_FILE= vpc.yaml TIMEOUT_IN_MINUTES= 10 PROJECT_NAME= kodama-th-cloudformation-cli COST ="j.kodama" Environment= sbx としました。 実際に貼り付けて実行すると、以下のようになりました。 “StackID”: “arn:aws:cloudformation:~” の応答が返ってくればスタックが作成されて実行が開始されています。 Managemend Console の CloudFormation スタックの画面を見ると、無事作成されています! 削除したい場合 スタックでAWSリソースの作成に失敗したりして、削除したい場合は、簡単です。 すでにスタックは環境変数STACK_NAMEとして登録済みなので、以下を貼り付けるだけで実行できます。 aws cloudformation delete-stack \ --stack-name "${STACK_NAME}" Management Consoleでスタック名を「削除済み」で検索すると、削除されていることがわかります。 あとは、これを理想のCloudFormation テンプレートに仕上がるまで繰り返していきます。 GUIでは 4ページ分必要だったパラメータ入力が、Linux Shell のコマンド履歴から矢印キーを数回 + Enter キーで実行できるようになります! 終わりに いかがでしょうか? これで CloudFormation テンプレートを作ろうとしているけど、デバッグ時の入力作業の繰り返しがうんざりしてやめてしまった方でも「もう一度トライしてみよう!」と思えませんか? 皆様の良き CloudFormation テンプレート作成ライフをお祈りしています!
こんにちは。SCSKの山口です。 本ブログは BigQuery のアクセス制御まとめ その① の続編です。 今回は、BigQueryの「列と行のアクセス制御」について書きます。 BigQuery のアクセス制御 概要については下記ブログをご参照ください。 【GCP】BigQuery のアクセス制御まとめ その① BigQuery の様々なレベルでのアクセス制御についてまとめます。今回のブログ(その①)では、リソースレベルでのアクセス制御について詳しく見ていきます。 blog.usize-tech.com 2024.08.22 データレベルのアクセス制御 本ブログでは、列と行のアクセス制御を「データレベル」のアクセス制御と位置付けます。 列レベルのアクセス制御 列レベルのアクセス制御の概要  |  BigQuery  |  Google Cloud BigQuery の列レベルのアクセス制御、ワークフロー、制限事項について説明します。サンプル ユースケースを使用して、列レベルのアクセス制御が設定されたテーブルとビューにクエリを実行する方法を示します。 cloud.google.com 列レベルのアクセス制御では、文字通り列に対するアクセスを制御することができます。 列レベルのアクセス制御を実現するには、以下の手順を踏む必要があります。 分類階層とポリシータグを定義する BigQuery 列にポリシータグを割り当てる 分類階層にアクセス制御を適用する ポリシータグへのアクセス権を管理する 聞きなれない 「ポリシータグ」 という単語が出てきました。ポリシータグについて説明します。 ポリシータグ BigQuery でポリシータグを使用する際のベスト プラクティス  |  Google Cloud ポリシータグの階層(テーブル列に適用して列レベルのアクセス制御を行う)を設計し、モニタリング専用モードを使用してアクセスをテストするためのガイダンスです。 cloud.google.com ポリシータグとは、 カラム単位のアクセス制限 や、 動的データマスキング を行うために、BigQuery の 列にタグを付与する 機能です。 ※動的データマスキングについてはまた別のブログで触れようと思います。 ポリシータグを使用する際に重要になるのが、 「データクラス階層の構築」 です。 取り扱うデータの種類を検討し、データ特性や重要度、機密性等を加味してデータクラスを決定します。 上記、公式ドキュメント内の図で説明します。 最上段の黄色四角形が 最上位ポリシータグ です。すべてのデータタイプが高、中、低で分類されています。 最上位ポリシータグにぶら下がっている青色四角形が リーフポリシータグ です。 このように、ポリシータグは ツリー状にまとめること が可能です。 これらのポリシータグをBigQuery の列に付与し、アクセス制御や動的データマスキングを実現します。   行レベルのアクセス制御 BigQuery の行レベルのセキュリティの概要  |  Google Cloud 行レベルのアクセス ポリシー、そのパフォーマンスおよびセキュリティの制限について説明し、他のアクセス制御方法(承認済みビューおよびテーブルレベルのアクセス制御)と比較します。 cloud.google.com こちらも文字通り、行に対するアクセスを制御できます。 行レベルのアクセス制御は、 「アクセスポリシー」 を使用して実現します。データに対するアクションがされた際に、 ユーザまたはグループが許可リストに含まれているかどうか に応じて 特定のデータ行を表示または非表示 します。 1つのテーブルに対して、複数の行レベルアクセスポリシーを設定することも可能です。   実践1:列レベルのアクセス制御 実際に列レベルのアクセス制御をやってみます。 今回も前ブログ(その①)同様、AdminとMemberに分けて実装していきます。 まずは「分類階層の定義」と「ポリシータグの定義」でしたね。 Admin:分類階層の定義 今回は公式ドキュメントに記載のある分類階層のテーブルをそのまま使用します。 テスト用に、最上位ポリシータグの高、中、低のカラム含むテーブルを用意します。 Admin:ポリシータグの定義 次にポリシータグを定義します。 BigQuery 画面の左ペインから「管理」-「ポリシータグ」を選択 「分類を作成」をクリック ポリシータグの分類を作成 Admin:BigQuery 列にポリシータグを割り当てる 作成したポリシータグを割り当てます。 今回のテーブルのカラムとポリシータグの対応は以下の通りです。 カラム名 最上位ポリシータグ リーフポリシータグ ユーザID – – クレジットカード番号 High Credit card 住所_都道府県 Medium Location 氏名 Low Name メールアドレス Low Email 上記の対応に基づいてポリシータグを割り当てます。 対象テーブルの「スキーマ」タブの「スキーマの編集」をクリック 割り当て対象のスキーマを選択した状態で「ADD POLICY TAG」をクリック 対応付けたいポリシータグを選択 該当するすべてのスキーマにタグを割り当てる →「氏名」スキーマを見てわかる通り、あえて上位ポリシータグの「Low」を割り当てることも可能です。 Admin:分類階層にアクセス制御を適用する 次にアクセス制御を適用します。 今回はMemberユーザに対して、MediumとLowのデータのみアクセスを許可(Highのデータはアクセス禁止)する制御とします。 BigQuery の「ポリシータグの分類」画面から、 「Medium」「Low」配下のすべてのポリシータグを選択 した状態で、「プリンシパルを追加」をクリック ※最上位のポリシータグを選択しても、リーフポリシータグは選択されていない状態になるので注意が必要です。 「新しいプリンシパル」にMemberユーザのアカウントを入力し、「ロール」で「プロダクトまたはサービス」-「データカタログ」-「きめ細かい読み取り」を選択 ここまででAdmin側の作業は完了です。 Member:テーブル確認 Admin側で、アクセス制御の適用を行っていない状態でMemberのアカウントからテーブルを見てみます。 ポリシータグを付与していないスキーマはデータがみれていますが、 ポリシータグを付与したスキーマ関してはデータが閲覧不可 になっています。 Admin側でのアクセス制御の適用が完了した後に再度確認すると。 Admin側でアクセスを許可したMedium,Lowのスキーマがアクセス可能になりました。   実践2:行レベルのアクセス制御 次に行レベルのアクセス制御をやってみます。 あらかじめ、Memberユーザからテーブル内のすべてのデータがみれるようにしておきます。 Admin:行データのフィルタリングをクエリ Admin側から下記クエリを発行します。 CREATE ROW ACCESS POLICY location_filter ON `evocative-entry-277709.yamaguchi_test_acctrl.user` GRANTTO ("user:shXXXX@XXXX.com") FILTER USING (`住所_都道府県`="Tokyo") これで、Memberユーザに対して` 住所_都道府県`=”Tokyo”のデータのみにしかアクセスできない制限 がかかりました。 Member:クエリ結果確認 Memberユーザ側でデータを全件SELECTしてみます。 ` 住所_都道府県`=”Tokyo”のデータのみが表示 されました。 Memberユーザがアクセスできる行を絞り込むことができました。   まとめ BigQuery の様々なレベルのアクセス制御について、二本にわたって書きました。 今回紹介した各レベルの制御方法は組み合わせることができます。各方法のベストプラクティスを確認し、 要件に適した組み合わせ、実装方法を検討すること が重要だと思います。 どんなデータがあって、だれに見せたくないのか(見せたいのか)を確認すること最初のステップが重要です。 その次の実装のステップでこのブログが皆さんのお役に立てると幸いです。   BigQuery の行レベルのセキュリティに関するベスト プラクティス  |  Google Cloud サイドチャネル攻撃の軽減、更新中のアクセス ウィンドウの防止、フィルタ済みデータ閲覧者のロールの慎重な使用、パーティション分割テーブルのパフォーマンスへの影響など、BigQuery の行レベルのセキュリティの使用に関する考慮事項について説明... cloud.google.com BigQuery でポリシータグを使用する際のベスト プラクティス  |  Google Cloud ポリシータグの階層(テーブル列に適用して列レベルのアクセス制御を行う)を設計し、モニタリング専用モードを使用してアクセスをテストするためのガイダンスです。 cloud.google.com
こんにちは。SCSKの山口です。 今回は、BigQuery の、様々なレベルでのアクセス制御についてまとめます。 BigQuery のアクセス制御 BigQuery の IAM ロールと権限  |  Google Cloud 事前定義ロールとカスタムロールを含む、BigQuery 向け Identity and Access Management(IAM)によるアクセス制御のロールと権限について説明します。 cloud.google.com BigQuery では、下記のレベルでのアクセス制御が可能です。 リソースレベル データセット テーブル データレベル 列 行 公式ドキュメントには「データレベル」というワードありませんが、わかりやすくするために使用しています。 図式化すると以下の通りです。 アクセス制御が実装されているBigQuery では、ユーザは目的のデータ(宝石)を入手するために 各レベルに設定されたアクセス制御を潜り抜ける 必要があります。 もちろん、アクセス制御がされていない場合もあります。 今回のブログ(その①)では、 リソースレベルでのアクセス制御 について詳しく見ていきます。 リソースレベルのアクセス制御 前述しましたが、ここでいう「リソース」は データセット/テーブル を指します。 下記方法で設定することが可能です。 IAMを使用したアクセス制御 承認によるアクセス制御 VPC Service Controlsを使用する タグを使用する IAM Conditionsを使用する IAMを使用したアクセス制御 IAM を使用してリソースへのアクセスを制御する  |  BigQuery  |  Google Cloud cloud.google.com IAMを使用してBigQuery のアクセス制御を実装する場合は、下記のロールが必要です。 BigQuery データオーナー(roles/bigquery.dataOwner) 既に実装されているアクセス制御については、下記手順で、コンソール上で確認することができます。 データセット名の横の点三つをクリックし「アクションを表示」 「共有-権限の管理」をクリック 新たにアクセス権を付与する場合もコンソール上での操作が可能です。 (上記と同様の手順) (上記と同様の手順) 「プリンシパルを追加」をクリック 「新しいプリンシパル」欄にプリンシパルを入力 「ロールを選択」リストで付与するロールを選択 「保存」をクリック   承認によるアクセス制御 VPC Service Controlsを使用する BigQuery の VPC Service Controls  |  Google Cloud cloud.google.com VPC Service Controls の詳細については下記ドキュメントをご参照ください。 VPC Service Controls の概要  |  Google Cloud cloud.google.com BigQuery で VPC Service Controls を使用することで、データアクセスとデータの引き出しを制限することができます。   タグを使用する テーブルとデータセットにタグを付ける  |  BigQuery  |  Google Cloud cloud.google.com 事前に作成したタグを使用し、 リソースにタグが付いているかどうかに基づいて条件付きでポリシーを適用する 方法です。 タグはKey-Value ペアとして構成されるリソースで、組織リソースまたはプロジェクトリソース配下に作成することができます。詳細は下記をご参照ください。 タグの概要  |  Resource Manager Documentation  |  Google Cloud cloud.google.com タグを使用することで、例えば下記のような運用・制御が可能です。 [前提] 組織を管理している 組織内のデータアナリストはすべてグループ「 analysts@example.com  」のメンバ アナリストはプロジェクト「 userData 」に対して「 BigQuery データ閲覧者IAMロール 」を持つ アナリストの インターンの学生 が一名入ってきた [やりたいこと] インターンの学生にはuserData プロジェクトの 「anonymousData」 データセットを表示する権限のみ を付与したい [実現方式] 「anonymousData」 データセットにタグを付与 する インターン生のIAM(もしくはサービスアカウント)の「 BigQuery データ閲覧者IAMロール 」に対して タグの条件を追加する (公式ドキュメント内の例を参考にしています。) テーブルとデータセットにタグを付ける  |  BigQuery  |  Google Cloud cloud.google.com この方法に関しては、後ほど実践したいと思います。   IAM Conditionsを使用する IAM Conditions によるアクセス制御  |  BigQuery  |  Google Cloud cloud.google.com この方法では、指定された条件が満たされた場合のみBigQuery リソースへのアクセスを認可できます。 IAM Conditions は、プロジェクト、フォルダ、組織レベルでサポートされ、BigQuery データセット、テーブル、ルーティン、モデルに適用できます。 次の属性に基づいた設定が可能です。 属性 概要 値 request.time ユーザがBigQuery リソースへアクセスした時刻 – resource.name BigQuery リソースのパス projects/ PROJECT_ID /datasets/ DATASET_ID projects/ PROJECT_ID /datasets/ DATASET_ID /tables/ TABLE_ID resource.type BigQuery リソースのタイプ bigquery.googleapis.com/Dataset(Table) resource.service BigQuery リソースが使用するGoogle Cloud サービス bigquery.googleapis.com resource.tags BigQuery リソースに付加されたタグ –   具体的な実践は今回は省きますが、タグの使用でも説明した「IAMの条件を追加」から設定することが可能です。 [例:request.time]   実践1:IAMを使用したアクセス制御 IAMを使ってアクセス制御してみます。 以降はAdminとMemberでアカウントを分けて進めます。 Admin:データセット+テーブル作成 下記データセットとテーブルを作成します。 データセット:yamaguchi_test_acctrl テーブル:test1,test2 次に、AdminのBigQueryで、 test1テーブル の権限の共有で下記を設定します。 プリンシパル:shXXXXX@XXXX(MemberのGoogleアカウントのアドレス) ロール:BigQuery データ閲覧者 Member:テーブル確認 Admin側で共有設定をする前は、test1.test2テーブルともに閲覧ができない状態でした。 Adminでtest1テーブルの共有設定を行うと、 test1テーブルのみ閲覧することができるようになりました。   実践2:タグを使用したアクセス制御 次に、同じことをタグを使って実現してみます。 今度はtest2テーブルに対する閲覧許可を実装します。 Admin:タグ作成+付与 まず、タグを作成します。 次に、test2テーブルに作成したタグを付与します。 「詳細」タブから「詳細を編集」 タグの「スコープの選択」でプロジェクトを選択し、作成したタグ情報を入力 Admin:IAMの条件を追加 権限付与対象のプリンシパルの「BigQuery データ閲覧者」ロールに、下記IAMの条件を追加します。 条件タイプ:タグ 演算子:値IDがある キーID:tagKeys/281476642126196(タグ値詳細画面の「親キー」) 値ID:tagValues/281483470283076(タグ値詳細画面の「タグ値ID」) Member:テーブル確認 Admin側でタグ設定をする前は、test2テーブルが閲覧できない状態でした。 タグとIAMの設定完了後にtest2テーブルを再度確認すると、 test2テーブルも閲覧可能になりました。   まとめ 今回はBigQuery のアクセス制御 その①ということで、リソースレベルのアクセス制御を実践してみました。 本ブログで実践した通り、IAMによる制御と承認(タグ)による制御は共存させることができます。便利ではあるのですが、闇雲に設定してしまうと 意図しない認可が発生してしまう 恐れもあります。 IAMの設定に関しては下記ドキュメント等のプラクティスに準拠することをお勧めします。 IAM を安全に使用する  |  IAM のドキュメント  |  Google Cloud cloud.google.com まとめ②では、BigQueryテーブル内の行・列単位のアクセス制御について取り扱います。
本記事は 夏休みクラウド自由研究 8/22付の記事です 。 こんにちは。SCSKの吉田です。 本記事は、ServiceNowの開発者向け生成AI機能であるNow Assist for Creatorに関する記事となります。 Now Assist for Creatorには、いくつかの機能がありますが、今回は Code generation を紹介させていただきます。 本記事は執筆時点(2024年8月)の情報です。最新の情報は製品ドキュメントを参考にしてください。 Code generationとは Code generationは、自然言語で記載したいコードの説明を入力すると、その内容をもとにAIがコードをサジェスト、生成してくれる機能となります。 Code generationの使用には以下のようなメリットがあると個人的に感じており、ServiceNowの開発業務を大幅に効率化することができます。 開発経験の有無に関係なく、ServiceNowスクリプトの文法に沿ったコードを簡単に作成できる 過去作成したコードを見返したり、ドキュメントを読んだりなど、調査の時間を短縮できる 普段、ロード・ノーコード開発に慣れていると、久しぶりにコーディングする際に「どういう構文だったっけ?」となることがあります。 そんなとき、Code generationを使用すれば、ドキュメントを調べる必要もなくなるので非常に便利なツールです。 使い方 Now Assist for Creatorをインストールした後、Code generationをアクティベートとすることで、Business rule、Script Includeなどのスクリプトエディターや、Flow Designerで利用可能になります。 Now Assistのセットアップ方法は、以下の記事で簡単にご紹介していますので併せてご覧ください。 【ServiceNow×生成AI】Now Assistをセットアップしてみる ServiceNowの生成AI機能であるNow Assistをセットアップしてみましたので、その手順を簡単にご紹介します。 blog.usize-tech.com 2024.08.15 ここではシステムで一般的な要件として存在する、以下のシナリオを想定してコードを作成してみます。 セキュリティの観点から、一定期間ログインが無いユーザーを無効化したい 自動生成したコードは、非本番環境でレビュー・動作確認の上、本番利用してください。 コードのサジェスト まず始めにコードのサジェスト機能のご紹介です。 画像のようにCode with Now Assistダイアログボックスに、作成したいコードの説明を記載します。 「ユーザーテーブルを検索し、最終ログイン日が180日以上前のアカウントを非アクティブ化する」 次に記載した内容をSubmitすると、Now Assistが入力された内容をもとにコードをサジェストしてくれます。(ハイライト部分) サジェストされた内容で問題なければ、Acceptを選択することで自動生成されたコードが反映されます。 最後に、変数名やログ出力処理など、各開発チームが持つ開発標準に合わせて微修正して保存すれば作成完了となります。 実際に自動生成された処理を実行したところ正しく動作することが確認できました。   コードの補完 続いて、コードの補完機能のご紹介です。 ここではあえてコードを途中まで記載した状態からスタートします。 コメントで作成したいコードの説明を記載のうえ、右クリック→Auto-generate code completionを選択します。 すると画像のように残りのコードを補完してくれます。(グレーアウト部分) 補完された内容は、先ほどのサジェストされたコードと同じ内容であることが確認できます。   生成AIが考えたお題にチャレンジ シナリオ 弊社内で利用できる生成AIにシナリオを考えてもらい、Code generationでコードを作成してみようと思います。 (吉田) ServiceNowのスクリプティングを勉強しています。複数のテーブルからデータを取得して特定の条件でクエリするような、複雑なスクリプトのお題をください。 (生成AI) ServiceNowのスクリプティングを学ぶためのスクリプトの課題をご紹介します。 シナリオ:ユーザーのアクティビティを監視し、特定の条件に基づいて一覧を表示するスクリプトを作成します。 要件: 1.ユーザーテーブルからアクティブなユーザーを取得します。 2.ログイン履歴テーブルから、過去1週間以内のログイン履歴を取得します。 3.各ユーザーのログイン回数を集計し、1回以上ログインしているユーザーのリストを表示します。 実践 まず始めにアクティブなユーザーをクエリするコードを作成します。 次に各ユーザーのログイン履歴を取得し、ログへ出力するコードを作成します。 最後に変数名などを分かりやすく修正した上で完成した処理がこちらになります。 実際にこの処理を動かしてみます。 過去1週間のうちにログインしているユーザーは、私自身のアカウントとテスト用ユーザーの2アカウントとなります。 なおテスト用ユーザーは非アクティブな状態に更新したため、ログは1件のみ出力されるのが想定している動作となります。 ログを確認すると、1件のみ出力されており、正しくコードを作成できていることが確認できました。   まとめ 今回は、Now Assist for Creatorの各機能のうち、コードを自動生成してくれるCode generationを使ってみました。 Code generationを使用すれば、ServiceNowの文法に沿った高品質のコードを簡単に作成することができ、また、手動でコードを書く時間を短縮できるので、開発者の業務効率を向上させることが可能な強力なツールと感じました。 Now Assist for Creatorにはその他の機能も用意されているので、今後ご紹介していきます。   最後に・・・ 弊社では、ITSMやCSM、ESGなど様々なServiceNow製品を扱っています。 以下から問合せ可能ですので、是非ご参照ください。 ServiceNow ServiceNowは、企業の生産性向上や業務プロセス改善を支えるサービスマネジメントクラウドソリューションです。従業員満足度・顧客満足度の向上、業務効率化を強力に支援します。 www.scsk.jp
こんにちは!Zabbixを担当している曽我です。 今回、Zabbixの 新しい構築サービス をリリースしましたので紹介いたします。 本サービスは、お客様からの導入時の以下の悩み事を解決できる内容になっています。 ・Zabbixの導入を依頼するといくら必要なの? ・要件を満たすには、どんな構成でZabbixを構築する必要があるの? ・導入後のサポートは何があるの? Quick Start Package for Zabbixのサービス概要 本サービスは、弊社にて2017年よりZabbix構築サービスを提供してきた中で、よくある構築作業をパッケージ化したサービスです。 お客様のご要望に応じて、複数の選択肢を用意しており、それらを組み合わせることで、構築から、構築後のサポートまで提供します。 お客様は、以下の①~④のZabbix環境を構築する上で必要なコンポーネントより、要件にあったメニューを選択頂くことで、ご希望の 監視環境を得ることができます。 Quick Start Package for Zabbixの全体メニュー 以降で、①~④のコンポーネントについて説明します。 ①サーバ環境 Zabbixサーバの環境として、大きく3つの選択肢があります。 選択1)Zabbix Enteprise アプライアンス(監視対象数の目安:~1000台) Zabbix Enterprise アプライアンスは、ZS-5000シリーズ(監視対象数の目安:200台)と ZS-7000シリーズ(監視対象数の目安:1000台)の2種類があります。 機器の詳細については、こちらの リンク より確認してください。 ZS-5000 / ZS-7000シリーズ 選択2)仮想アプライアンス Zabbix Enteprise サポート契約者さま向けに仮想アプライアンスが提供されています。 対応している仮想基盤は、以下です。(2024/8/21時点) VMware 5.5/6.0/6.5/7.0/8.0 VirtualBox 必要なサーバスペックについては、 ご相談 ください。 選択3)物理サーバ/仮想マシン/クラウド 本サービス上は、お客様にてご用意頂いた物理サーバ/仮想マシン/クラウドにOS環境を ご用意頂き、Zabbixを導入させて頂く内容となっております。 ※もし環境の準備をご希望される場合は、別途ご相談ください。   ②構築サービス 構築サービスは、構築する環境に応じて3種類ご用意しております。 構築サービスメニュー 環境によっては、Zabbixプロキシが必要になり、上記の構築メニューでは不十分なケースが御座います。 その場合は、個別見積で対応させて頂きますので、ご相談ください。   ③オプション 構築オプションメニュー 構築サービスの内容に以下のオプションを追加で加えることが可能です。 構築オプションメニュー 運用支援オプションメニュー 構築後、Zabbixのサポートはあるけど、お客様自身だけでは不安な場合、導入後の支援をご依頼頂けます。 構築後支援メニュー ④Zabbixサポート 当社のサポートは全部で、5種類あり、一番お勧めは、問合せ無制限の「ゴールド」です。 以下、サービスメニューです。 赤い★マーク がついているところは、当社のオリジナルメニューです。 Zabbix Enterprise サポート ※ 1 平日営業時間内は日本時間月曜~金曜日(祝祭日、弊社規定休日を除く)9時~17時30分となります。 ※ 2 ご契約のZabbixサーバに接続されているZabbixプロキシの台数分プロキシオプションの契約が必要となります。サーバとプロキシのサポートレベルは同一であることが必須となります。 ※ 3 18時~翌9時まで、対応言語は英語のみとなります。 ※ 4 VALinux社提供のVAQuestサービスを利用しています。 ※ 5 本サポートをご契約頂けるお客様は、新規でサポートをご契約頂くお客様または他社様のZabbixサポートから乗り換えのお客様に限ります。 Zabbixアプライアンスのサポートには利用できません。   構築例 ①Zabbix Enteprise アプライアンス ZS-5000シリーズ+②構築サービス エントリー+③ Zabbix Enteprise サポート シルバーの場合 No 製品名 数量 価格 1 Zabbixアプライアンス ZS-5000シリーズ 1 \298,000 2 構築サービス エントリー 1 \100,000 3 Zabbix Enteprise サポート シルバー 1年 1 \1,600,000 合計 \1,998,000 (税込\2,197,800)   まとめ 「Quick Start Package for Zabbix」は、監視システムを導入されようとしているお客様にとっての メリットは、「スピーディーな導入」「分かりやすい料金体系」「安心のサポート」が御座いますので、 是非、ご興味がございましたら、 こちら よりご連絡ください。 また、オプションメニューについては、拡充することを予定しておりますので、 ご期待ください!   参考 弊社ではZabbix関連サービスを展開しています。以下ページもご参照ください。 ★SCSK Plus サポート for Zabbix★ SCSK Plus サポート for Zabbix 世界で最も人気のあるオープンソース統合監視ツール「Zabbix」の導入構築から運用保守までSCSKが強力にサポートします www.scsk.jp ★YouTubeに、SCSK Zabbixチャンネルを開設しました!★ SCSK Zabbixチャンネル 本チャンネルでは、SCSK株式会社でのZabbixに関するトレンド/事例紹介などを動画にまとめて取り上げております。 最新のトピックについては、以下の弊社HPもしくはツイッターアカウントをぜひ参照ください。 ツイッターアカウント: www.youtube.com ★X(旧Twitter)に、SCSK Zabbixアカウントを開設しました!★ x.com X.com  
こんにちは、SCSK株式会社の中野です。 Zabbixの脆弱性に関して、深刻な脆弱性が発表されましたので、本記事にて共有いたします。 Zabbixをご利用の方は一度ご覧いただき、対象の場合はアップデート等のご検討お願い致します。 Zabbix脆弱性情報 2024年8月9日(現地時間)にZabbix社は、監視ソリューション「Zabbix」に深刻な脆弱性があると以下URLにて公表しております。 ———————— CVE/Advisory number: CVE-2024-22116 Synopsis: Remote code execution within ping script Zabbix Security Advisories and CVE database ———————— この脆弱性が悪用された場合は、リモートコード実行の攻撃を受け、システム全体が危険にさらされる可能性がございます。 例えスクリプト実行を制限された権限を持つ管理者であっても、監視しているホストでスクリプト実行機能を悪用できる可能性があり、 scriptのパラメータはデフォルトでエスケープされていないため、攻撃者はping scriptを介して任意のコードを実行し、インフラ全体を侵害することが可能となります。 影響を受けるとされるZabbixのバージョンは以下となります。 ・Zabbix 6.4.0 ~ 6.4.15  ・Zabbix 7.0.0alpha1 ~ 7.0.0rc2  脆弱性を修正するためには、修正されたZabbixのバージョンへアップデートする必要がございますので 以下バージョンへのアップデートのご検討をお願い致します。 ・Zabbix 6.4.16rc1 ・Zabbix 7.0.0rc3 最後に 弊社では本件に関してのお問い合わせもお受けしております。 ご相談事項がございましたら、以下ページよりお問い合わせいただければと思います。 お問い合わせ 製品・サービスについて 入力 | SCSK株式会社 また、以下Zabbixのイベントが直近で開催されます。 本件に限らずご質問をお受けする時間もございますので、ご興味がございましたら是非ご参加ください。 2024.8.23 (金) Zabbix全国5都市キャラバン2024 名古屋 2024.10.02(水) Zabbix7.0セミナー ~新機能とバージョンアップの要点~ 以上、最後までご覧いただきありがとうございました。
こんにちは。SCSKの吉田です。 今年リリースされたWashington DCバージョンから「Customized Metadata Detail」というテーブルが追加されていることを最近発見しました。 このテーブルを使用することで、インスタンスに加えたカスタマイズを簡単にトレースすることができるようになりました。 公式ドキュメントにはおそらく記載はなく(見逃していたらすいません)、あくまでも個人で調べた内容となりますが、共有させていただきます。 はじめに ServiceNowを導入する際は、OOTB(Out of the Box)と呼ばれる標準機能を利用して、カスタマイズを最小限に抑えることが推奨されています。標準機能を利用することで初期構築期間の短縮、システム稼働後のメンテナンスコスト削減などのメリットがあります。 その一方で、業務要件のためにカスタマイズが必要となる場面もあります。その際は以下の点を考慮する必要があります。 メンテナンス工数の増大 カスタマイズは自身でメンテナンスを行っていく必要があります。カスタマイズの程度にもよりますが、発生した問題の原因がカスタマイズの場合、サポート対象外となることがあります。 また、ServiceNowでは1年に1回はインスタンスのアップグレードを実施する必要があり、カスタマイズが多いほどリグレッションテストにかかる工数は増大します。 カスタマイズ箇所のブラックボックス化 もちろんですがカスタマイズで実装した内容は、公式ドキュメントに記載されていません。そのため、設計書に残していない場合、カスタマイズを実施した特定の開発者に属人化してしまいます。 また、きちんと引継ぎがなされないまま開発者が離任した場合、カスタマイズ箇所の特定が困難になります。 上記のことから、不要なカスタマイズを避けることが求められ、またカスタマイズを実施する場合は、設計書等にドキュメント化しておく必要があります。 しかし、ドキュメント化のルールを整備しないまま開発を進めてしまい、後からカスタマイズをトレースするのに苦労しているという方も多いのではないでしょうか。   カスタマイズをトレースする 以前までは、例えば以下のようにカスタマイズをトレースしていました。 テーブルに追加したカスタムフィールドを探す場合:sys_dictionaryテーブル上で名前が「u_」から始まるレコードを検索する カスタマイズしたBusiness ruleを探す場合:sys_scriptテーブル上で、作成/更新者、作成/更新日時、スクリプトの中身を確認してカスタマイズか否かを確認する このように、各テーブル上で、それぞれの探し方でトレースする必要がありました。 しかし、Washington DCからは、カスタマイズのトレースを簡単にする以下テーブルが追加されました。 Customized Metadata Detail[sys_metadata_customization] どのテーブル上のレコードを変更したかに関係なく、カスタマイズと分類される変更は、Customized Metadata Detailテーブル上にレコードとして格納されるようになったようです。 各テーブル毎に探す手間が省け、かつカスタマイズのみが格納されるテーブルの為、OOTBかカスタマイズかの判別も不要となりました。 また、Author Typeの値を使用することで、以下のように更に詳細な分類ができます。 「ServiceNow」の場合:OOTBのレコードに対して、変更を加えカスタマイズしている 「Custom」の場合:レコードを新規作成してカスタマイズしている 他にもAuthor Typeが「Unknown」や「ToBeDetermined」となっているレコードがありましたが、カスタマイズを特定する上では上記2つを確認するだけで問題なさそうです。   注意点として、Customized Metadata Detailに格納されるのは、 更新セットにキャプチャされる変更のみ のようです。 試しにScheduled Jobを作成しましたが、Customized Metadata Detailにはレコードが作成されませんでした。   最後に 今回は、Washington DCで追加されたテーブルを使用し、カスタマイズをトレースする方法をご紹介しました。 カスタマイズのトレースにお困りの方にとって、本記事が参考になれば幸いです。 また、弊社では豊富な構築・運用ノウハウにより、ServiceNow導入のご支援が可能です。 以下HPも併せてご参照ください。 ServiceNow ServiceNowは、企業の生産性向上や業務プロセス改善を支えるサービスマネジメントクラウドソリューションです。従業員満足度・顧客満足度の向上、業務効率化を強力に支援します。 www.scsk.jp
本記事は 夏休みクラウド自由研究 8/21付の記事です 。 クラウドサービスのオブジェクトストレージの利便性 便利なストレージサービス AWSのS3(Simple Storage Service)や、Google CloudのCloud Storage、Microsoft AzureのAzure Blob Storageなど、パブリッククラウド各社には代表的なオブジェクトストレージサービスが存在しています。これらは非常にシンプルで便利なストレージサービスです。とりあえずデータを入れておけば、連携するサービスや対応するソフトウェアが豊富にあり様々な活用ができます。さらに、ストレージ料金も非常に安価で、クラウド利用時のデータレイクとして最適です。 思わぬ課金項目に注意! クラウド上のオブジェクトストレージは確かに便利ですが、その活用方法によっては想定に反して思わぬ請求が来てびっくりしてしまうケースが存在します。見落としがちな課金項目として挙げられるのが、クラウド外へのデータ転送課金です。 クラウド外へのデータ転送課金(ダウンロード課金)とは? 主要なパブリッククラウドにはデータをクラウド外に送信する際に 従量 課金が発生します。一般的には Egress課金 やダウンロード課金と呼ばれます。 クラウド内や他のリージョンでのデータ送受信はゼロ円もしくは極めて安価でほとんど気にする必要はありませんが、他のクラウドやオンプレミス環境、またはクライアントへデータをダウンロードする際にはGBごとに課金が発生します。 この課金は単価が安いため見過ごしがちですが、使用量が増えるとコストがじわじわと上昇していきます。以下はあるオブジェクトストレージサービスにデータを保存してクラウド外に読み出しを行った場合の課金額シミュレーションです。読み出し量が多いと保存料金以上にダウンロード料金がかかることがわかります。   注意すべきユースケース 特に以下のようなユースケースでは、思いもよらなかった高額な課金になることがあります。 クライアント向けに頻繁にもしくは大量にデータ送信するケース ファイル配布、モジュール配信、ファイルサーバ利用など、様々なユースケースが考えられますが、データ量が大量になったり、データの送付先・配布先が大量になるケースは場合によって注意が必要です。 マルチクラウド環境でのデータ活用 パブリッククラウドの大手各社はデータ活用領域でも様々な魅力的なサービスを提供しています。各社の強味や特性を活かすために様々なクラウドサービスへデータを連携させていると、結果としてデータレイクやデータベースの存在するクラウドからのEgressトラフィックが増加します。 ハイブリッド環境でのデータ連携が多いケース 様々な理由があってパブリッククラウドとオンプレミスもしくはパブリッククラウド以外のクラウドサービスとの組合せ構成をとる場合。ある程度のEgress発生は想定内のはずですが、ハイブリッド構成をとるシステムが増えてくると意図せずEgressが多くなるケースが発生しえます。   解決策 この課金問題を回避するための方法をいくつか記載します。 解決策1:データ連携の多いシステムやサーバは同じクラウドに配置する 外に送るのにお金がかかるのなら送り先を中にしてしまおうという発想です。 クライアントなどもクラウド内に置いておけば追加のダウンロード料金が発生しません。 複数のクラウドを利用する必要がない場合は、これが最もシンプルな解決策です。 解決策2:ダウンロード課金がかからないサービスを活用する 複数のクラウドを使い分ける必要がある場合や、どうしても外部へ大量のデータを送らなければならない場合には、こちらの方法が適しています。Egress従量料金の代わりに固定の回線費用が発生する場合もありますので、扱うデータ量によって最適な構成の見極めが必要です。   まとめ ダウンロード課金による予想外のコスト増加を避けるためには、データの取り扱い方をあらかじめ計画し、最適な配置を行うことが重要です。 1つのクラウドですべてが完結する場合は問題ありませんが、複数のクラウドを利用する場合は特に注意が必要です。 オンプレ回帰は最適解か? 最近「オンプレ回帰」というワードを良く耳にします。クラウド利用したは良いけど、様々な理由で効果が出ずクラウドの利用をやめてオンプレミスのシステムに戻るという動きです。オンプレ回帰の理由の1つにコストの最適化があげられます。課金の仕組みをただしく理解して最適なデータ配置をすれば、コスト上昇を抑えてパブリッククラウドを利用し続ける事も可能と考えます。先進的なサービスが次々と実装されるパブリッククラウドの利用をあきらめるのはDXを推し進める上でもデメリットと考えています。今回の記事が読者の皆様のDX推進の一助になればうれしいです。 最後に宣伝 SCSKではUSiZE(ユーサイズ)というプライベートクラウドを提供中です。 USiZEには今回の記事でテーマにしたダウンロード課金はありません。 またSCNXというパブリッククラウドとの優れた接続性を有するサービスとも直結しており、 これによりパブリッククラウドとの連携も低コスト、低遅延で行うことができます。 直近でデータの蓄積場所として活用いただけるクラウドストレージというサービスもリリースをしております。 今回の記事に該当するようなお悩みをもっている方は、是非選択肢の一つとして「USiZE」をご検討頂ければと思います。   関連情報 データ主権を担保したソブリンクラウド ユーサイズ│SCSK株式会社|サービス|クラウド移行だけでは描けない、理想のDXを実現する プライベートクラウド「USiZE」でクラウドストレージサービスを提供開始 ~データ転送料金不要の純国産サービスでコストダウン、海外法影響排除を実現~ SCSK Cloud netXchange マルチクラウド接続サービス|SCSK株式会社