TECH PLAY

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

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

1235

こんにちは。SCSKのふくちーぬです。 AWS Systems Managerのフリートマネージャーを利用して、Windowsサーバにブラウザベースでのリモート接続している方多いかと思います。その際に、PowerShellでキーボード入力が機能しなかった事象が発生しましたので対処策をお話します。 アーキテクチャー Systems Managerの管理下にするために、EC2はマネージドインスタンスとする。また、OSはWindows Server 2022を利用します。 運用者は、フリートマネージャーを利用してEC2に接続します。 完成したCloudFormationテンプレート 以下のテンプレートをデプロイしてください。 AWSTemplateFormatVersion: 2010-09-09 Description: CFN template EC2 Parameters: ResourceName: Type: String AMIId: Type: String Resources: # ------------------------------------------------------------# # VPC # ------------------------------------------------------------# VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Sub ${ResourceName}-VPC # ------------------------------------------------------------# # Internet Gateway # ------------------------------------------------------------# InternetGateway: Type: AWS::EC2::InternetGateway AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway # ------------------------------------------------------------# # Public Subnet # ------------------------------------------------------------# PublicSubnet1a: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: 10.0.1.0/24 AvailabilityZone: ap-northeast-1a MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${ResourceName}-subnet-1a # ------------------------------------------------------------# # Route Table and Routes # ------------------------------------------------------------# PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: PublicRouteTable PublicRoute: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnet1aAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet1a RouteTableId: !Ref PublicRouteTable # ------------------------------------------------------------# # Security Group # ------------------------------------------------------------# SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: For EC2 VpcId: !Ref VPC # ------------------------------------------------------------# # IAM Role and Instance Profile # ------------------------------------------------------------# SSMRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${ResourceName}-ec2-role AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ec2.amazonaws.com Action: sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref SSMRole # ------------------------------------------------------------# # EC2 Key Pair # ------------------------------------------------------------# KeyPair: Type: AWS::EC2::KeyPair Properties: KeyName: !Sub ${ResourceName}-key # ------------------------------------------------------------# # EC2 Instance # ------------------------------------------------------------# EC2Instance: Type: AWS::EC2::Instance Properties: InstanceType: t2.micro ImageId: !Ref AMIId SubnetId: !Ref PublicSubnet1a IamInstanceProfile: !Ref InstanceProfile SecurityGroupIds: - !Ref SecurityGroup KeyName: !Ref KeyPair Tags: - Key: Name Value: !Sub ${ResourceName}-ec2   本事象の確認 キーペアの値を確認し、EC2に接続 Systems Manager パラメータストアにアクセスし、キーペアの値をメモしておく。 上記の値を利用して管理者パスワードを復号します。 フリートマネージャーを利用し管理者パスワードを入力し、EC2に接続します。 PowerShellでキーボード入力が機能しないことを確認 PowerShellを開き、キーボードで文字の入力を試みますが動作しません。 ※メモ帳内の文字をコピー&ペーストで、PowerShellに貼り付けることはできます。   解決策 PowerShellにて、PSReadlineモジュールをインストールすることで解決できます。 モジュールのインストール PSReadLineモジュールは、コマンド ラインを編集させるためのモジュールとなります。このモジュールのおかげで、コマンド履歴を追ったりすることができます。 PSReadLineのバージョン2.2.2以上をインストールします。 キーボード入力機能は利用できないため、コピー&ペーストを使って下記コマンドを実行します。 Install-Module -Name PSReadLine -Repository PSGallery -MinimumVersion 2.2.2 -Force  Yes/Noの確認プロンプトが表示されたら、”Y”を入力します。この際も、コピー&ペーストを使って入力することに注意してください。 PowerShellでキーボード入力が機能することを確認 再度、PowerShellを開きます。キーボードから任意の文字を入力してみます。 無事にキーボード入力が機能しましたね。   まとめ Windows Server 2022では、PowerShell でキーボードが正常に機能するためにはPSReadLine のバージョン 2.2.2 以上が必要です。 本制約は、フリートマネージャー利用時特有のものとなります。 キーボード機能用 PSReadLine モジュールバージョン PowerShell でキーボードが正しく機能することを確認するには、Windows Server 2022 を実行しているノードに PSReadLine モジュールバージョン 2.2.2 以降がインストールされていることを確認してください。古いバージョンを使用している場合は、以下のコマンドを使用して、必要なバージョンをインストールできます。 Remote Desktop を使用して Windows Server マネージドインスタンスに接続する - AWS Systems Manager Fleet Manager を使用して RDP 経由で Windows Server マネージド EC2 インスタンスに接続します。 docs.aws.amazon.com Install-Module -Name PSReadLine -Repository PSGallery -MinimumVersion 2.2.2 -Force  代替策として、以下の方法もございますので併せてご検討いただければと思います。 プライベートなRDP接続 EC2 Instance Connect Endpoint経由でのRDP接続   最後に いかがだったでしょうか。 フリートマネージャー利用時には、WindowsサーバのモジュールをアップデートすることでPowerShellを正常に機能させることができます。 本記事が皆様のお役にたてば幸いです。 ではサウナラ~🔥
こんにちは。SCSKの山口です。 本ブログでは、前回のブログで作成したBigQuery MLの線形回帰モデルの性能を評価してみたいと思います。 [前回ブログ]モデル作成・予測結果 【GCP】BigQuery MLを触りたいときに読むブログ 今回はBigQuery MLを使って機械学習モデルの作成、テストをやってみます。 AI/MLの知識はあまりないがとにかくBigQuery MLを触ってみたい方、BigQuery MLでモデルを作成して推論してみたい方にぜひ読んでいただきたいブログです。 blog.usize-tech.com 2024.09.06 前回のブログで線形回帰モデルの作成・予測をした結果、下記の出力を得ました。 従業員数 モデル予測結果(原材料費) 正解値(原材料費) 476 1344.5283231034557 1564 この結果は果たしてどうなのでしょうか、、?モデルの予測精度はどうなのでしょうか、、? これを今回は計測したいと思います。   モデル評価 BigQuery ML モデルの評価の概要  |  Google Cloud cloud.google.com 作成したモデルの評価は、 「ML.EVALUATE関数」 を用いることで可能です。 選択したモデルタイプによって、他の評価関数を使用することで様々な評価指標を得ることができます。詳細は 公式ドキュメント をご覧ください。 今回はモデルタイプとして線形回帰を選択したので、ML.EVALUATE関数で評価してみます。 下記SQLを実行します。 SELECT * FROM ML.EVALUATE(MODEL `yamaguchi_test_bqml.test_model_liner_reg`,   (   SELECT     IFNULL(cost_manufacturing, 0) AS cost_mf,     IFNULL(cost_material, 0) AS label,     IFNULL(cost_employees, 0) AS cost_emp,     IFNULL(manufacturing_line, 0) AS manu_line,     IFNULL(manufacturing_efficiency, 0) AS manu_eff,     IFNULL(employees, 0) AS emp   FROM     `scsksdv-dev-dais.yamaguchi_test_bqml.test` )); 実行結果 公式ドキュメントを見ると、線形回帰のモデルでは、ML.EVALUATE関数を実行することで下記の指標が得られます。 mean_absolute_error:平均絶対誤差 mean_squared_error:平均二乗誤差 mean_squared_log_error:平均二乗対数誤差 median_absolute_error:絶対誤差の中央値 r2_score:R2スコア explained_variance:説明分散   回帰モデルの評価指標 平均絶対誤差:MAE SCSK AI AutoML 「誰でも」「簡単に」AIを利用できるようにするために、SCSKでは、H2O Driverless AIやLearning Center Forecastなど、データサイエンティストによる機械学習モデル作成を自動化・高速化するソリューションを... www.scsk.jp 平均絶対誤差(MAE)は、各行で[予測値 – 正解値]の絶対値(=絶対誤差)を取り、その平均を出したものです。 以下の式で表されます。 MAEの代表的な特性は下記のとおりです。 0以上の値 小さいほど良い結果となる 外れ値に対して脆弱 今回の結果で言うと、MAE=190くらいなので、 「予測値と正解値が平均して190くらい離れている」 ということになります。 評価で使用したtestテーブルに外れ値を加えてMAEの値を見てみましょう。 21行目に原材料費が外れ値となるようなデータを追加しました。 この状態で再度モデルを評価してみると、 MAEの値がかなり大きくなりました。 このようにたった一つでも 外れ値のデータが入ってしまうと値が大きくなってしまう のがMAEの弱点です。 平均二乗誤差:MSE SCSK AI AutoML 「誰でも」「簡単に」AIを利用できるようにするために、SCSKでは、H2O Driverless AIやLearning Center Forecastなど、データサイエンティストによる機械学習モデル作成を自動化・高速化するソリューションを... www.scsk.jp 平均二乗誤差(MSE)は下記の式で表されます。 先ほどのMAEとかなり似た式ですが、予測値と正解値の差を二乗している点が違いです。 誤差を二乗しているため、より大きな誤差が発生していると値が大きくなります。すなわち、 間違いをより重要視した指標 ということになります。 この指標も 値が小さいほど良い結果 となります。 お気づきの方も多いかもしれないですが、MSEは MAEよりも外れ値に対して脆弱 です。 誤差を二乗しているため、その分外れ値に対しても弱くなってしまうわけですね。 平均二乗対数誤差:MSLE [損失関数/評価関数]平均二乗対数誤差(MSLE:Mean Squared Logarithmic Error)/RMSLE(MSLEの平方根)とは? 用語「平均二乗対数誤差」について説明。損失関数/評価関数の一つで、各データに対して「予測値の対数と正解値の対数との差(=対数誤差)」の二乗値を計算し、その総和をデータ数で割った値(=平均値)を表す。 atmarkit.itmedia.co.jp 平均二乗対数誤差(MSLE)は、各行で 予測値の対数と正解値の対数の差(=対数誤差)の二乗 を計算し、その平均を出したものです。 0に近いほど良い結果 となります。 下記の式で表されます。 数学では、底が同じ対数の引き算は割り算に変換することができます。これに着目すると、上記の式は 「予測値/正解値」 の形に変換することができます。 すなわちMSLEは、 予測値/正解値の比率に着目した指標 であるということが言えます。 比率に着目することで、 誤差が大きくなっても過大に評価しないこと が可能です。 そのため、MAE,MSEの弱点であった、 外れ値への脆弱性をある程度克服した指標 と言えます。 絶対誤差中央値:MedAE [評価関数]中央絶対誤差(MedAE:Median Absolute Error)とは? 用語「中央絶対誤差」について説明。評価関数の一つで、各データに対して「予測値と正解値の差(=誤差)」の絶対値を計算していき、それら全ての計算結果における中央値を表す。 atmarkit.itmedia.co.jp そのまま略すと「MAE」となり平均絶対誤差と混同してしまうので「MedAE」と略すのが一般的のようです。 MedAEは、各行で[予測値 – 正解値]の絶対値(=絶対誤差)を計算し、 小さい順に並べた際の中央値 を出したものです。 下記の式で表されます。 この値も、 0に近いほど良い結果 となります。 決定計数:R2スコア SCSK AI AutoML 「誰でも」「簡単に」AIを利用できるようにするために、SCSKでは、H2O Driverless AIやLearning Center Forecastなど、データサイエンティストによる機械学習モデル作成を自動化・高速化するソリューションを... www.scsk.jp R2スコアは、回帰モデルを評価する際に 「最も直感的な基準」 だと言われています・ これまで説明した指標はすべて誤差を見るものでしたが、ここでやっと モデルの性能(良し悪し) を測ることのできる指標が登場します。 複数のモデルの性能を比較する際にもよく使われる指標で、 モデルがどれだけデータをうまく説明できているか を表現してくれる値です。 テストの点数に置き換えると理解しやすいです。 数学のテストの点数が高い:数学についてよく理解できており、説明できる。 英語のテストの点数が悪い:英語についてよく英買いできておらず、説明できない。 下記の式で表されます。 SSEとSSTについてみていきます。 残差平方和:SSE 各行に対して、 観測値(正解値)と予測値の差 を二乗した値を総和したもの MSE の平均を求めないバージョン 正解値と予測値がどれくらい離れているかを示す 二乗平均:SST 各行に対して、 観測値(正解値)と全観測値の平均との差 を二乗した値を総和したもの 分散 の平均を求めないバージョン 正解データ自体の平均からのばらつき具合を示す これを抑えたうえでr2スコアの公式をもう一度見ると、 予測値に正解データの平均値を用いた ” 単純なモデル ” と ” 作成したモデル ” を比較(前者で後者を割る)する という作りになっていることがわかります。このことから、 r2スコアは非常に単純なモデルと比較した際のパフォーマンスを示している と言えいます。 R2スコアは、 1に近づくほど良い結果 となります。 説明分散:EV [評価関数]分散説明率(Explained variance score)とは? 用語「分散説明率」について説明。線形回帰モデルなどの評価関数の一つで、回帰式のモデルが「観測データの分散」のうちどれくらいの割合を説明するかを表す。決定係数R2の代わりに用いられることがある。 atmarkit.itmedia.co.jp 説明分散(ここではEVと略します。)は、R2スコアと同様にモデルの性能を測ることができる指標です。 正解データの散らばり(分散)のうち、モデルがどのくらいの割合を説明できるか を表現する指標です。 下記の式で表されます。 式のつくりを見ていきますが、視覚的に把握するために図式化します。 オレンジ色:モデル予測できた割合 紺色:モデル予測できなかった(誤差)割合 です。 EV値では上図のオレンジ色の部分を以下の流れで表現します。 EV値は、 1に近づくほど良い結果 となります。   作成したモデルの性能はどうなの? 必要な知識が揃ったところで、今回作成した線形回帰モデルの性能を見てみたいと思います。 R2スコアとEV値を見てみると、 R2スコア:0.568692977058064 EV値:0.58093681298823574 という結果でした。だいたい60点くらいの性能のモデルですね。   まとめ 今回は線形回帰モデルを評価してみました。 複数の指標を組み合わせて評価することが非常に重要だと感じました。 ほとんど指標の説明に費やしてしまいましたが、今後はモデルの性能を向上させるための方法を調べてみたいなと思っています。
こんにちは。SCSKの山口です。 今回はBigQuery MLを使って機械学習モデルの作成、テストをやってみます。 こんな方にオススメの記事です。 ・とにかくBigQuery MLを触ってみたい ・BigQuery MLでモデルを作成してみたい ・BigQuery MLでモデルを使って推論してみたい 筆者はこんな人です。 ・Google Cloud歴:約2年 ・BigQueryのコンソール操作には慣れている ・ SQLが少し書ける ・AI/MLの知識はあまりない 今回のブログでは、BigQuey MLを試すために最低限必要な事項にフォーカスして書きます。 より詳細な概念、知識に関しては後続のブログをお待ちください。 BigQuery ML BigQuery ML とは  |  Google Cloud cloud.google.com まずはBigQuery MLについて紹介します。 BigQuey MLでは、 GoogleSQLクエリ を使用して、 MLモデルの作成と実行 を行うことができます。 BigQuey MLを使用する最大のメリットは、 AI/MLのプログラミング経験が少ないデータアナリストでも、SQLの知識とツールでモデルの構築・評価ができる点 にあるといえます。 大規模なデータセットでAI/MLタスクを実行するには、各フレームワークに対する高度なプログラミング技術と知識が必要になります。 そのため データをよく理解しているアナリスト が、プログラミング経験が少ないばかりにソリューション開発から除外されてきましたが、BigQuey MLはそれを解決してくれます。 BigQuey MLは、下記の方法で使用できます。 Google Cloudコンソール bqコマンドラインツール BigQuery REST API BigQueryに統合されたColab Enterpriseノートブック Jupyter ノートブックやビジネス インテリジェンス プラットフォームなどの外部ツール 今回は、Google Cloudコンソール(BigQuery画面)でBigQuey MLを触ってみます。 また、BigQuery MLでは 下記のモデル が内部でトレーニング済みで、BigQuery MLに組み込まれています。 線形回帰 ロジスティック回帰 K平均法クラスタリング 行列分解 主成分分析(PCA) 時系列 上記以外にも様々なモデルが使用可能です。詳細は こちら の公式ドキュメントをご参照ください。 今回は、 線形回帰 のモデルを使用して予測を行います。   BigQuey ML使ってみた では、さっそく触ってみます。 事前準備 今回は、モデルのトレーニング用とテスト用で二つのテーブルを用意しました。(※同一データは含んでいない) スキーマ情報(2テーブル共通) training:80行 test:20行 モデルを作成し推論するにあたって、下記を決めておきます。 目的変数:予測したいデータ 説明変数:予測するために使用するデータ 今回は 目的変数を「cost_material:原材料費」 とし、 説明変数をその他のカラム とします。 モデル作成・トレーニング 下記SQLを実行して、モデルを作成します。 CREATE OR REPLACE MODEL `yamaguchi_test_bqml.test_model_liner_reg` OPTIONS(model_type='linear_reg') AS SELECT IFNULL(cost_manufacturing, 0) AS cost_mf, IFNULL(cost_material, 0) AS label, --目的変数 IFNULL(cost_employees, 0) AS cost_emp, IFNULL(manufacturing_line, 0) AS manu_line, IFNULL(manufacturing_efficiency, 0) AS manu_eff, IFNULL(employees, 0) AS emp FROM   `yamaguchi_test_bqml.training` ; CREATE MODEL文で簡単にモデルを作成することが可能です。OPTIONS句内で今回使用する線形回帰(linear_reg)を指定しています。 その後のSELECT文によって指定されたデータを使用してモデルをtrainingします。 また、 「cost_material」 に対して、 「label」 というエイリアスを作成することで、 cost_materialが目的変数であること を示しています。CREATE句でinput_label_cols=オプションを使用して目的変数を設定することも可能です。 最後のFROM句でトレーニング用のテーブル「training」を指定しています。 モデル作成が完了すると、エクスプローラ画面の「モデル」配下に作成したモデルが表示されます。 以上でモデルの作成・トレーニングは完了です。 モデルテスト 作成したモデルを使って予測をしてみます。 下記SQLを実行します。 SELECT predicted_label AS predicted_costs FROM ML.PREDICT(MODEL `yamaguchi_test_bqml.test_model_liner_reg`,   (   SELECT     IFNULL(cost_manufacturing, 0) AS cost_mf,     IFNULL(cost_employees, 0) AS cost_emp,     IFNULL(manufacturing_line, 0) AS manu_line,     IFNULL(manufacturing_efficiency, 0) AS manu_eff,     IFNULL(employees, 0) AS emp   FROM     `yamaguchi_test_bqml.test`   WHERE     employees=476 )) ML.PREDICT関数 を使って予測を行います。モデルの出力列名は predicted_<label_column_name> としています。 SELECT句で指定しているpredicted_labelは labelの推定値 になります。 ネストされたSELECT句は、モデル作成のCREATE MODEL句と同じにしていますが、FROM句にはtestテーブルを指定しています。 trainingのデータでモデルを学習させ、testのデータを使って予測の挙動を見る。といった狙いです。今回は、 「従業員数が476人の場合の原材料費」 を予測しています。 予測結果を見てみましょう。 1344.5283 …という予測が得られました。testテーブルの実際のデータを比較してみると、 、、、、何とも言えない結果ですね。。 とはいえ、そこまでかけ離れている数値ではないです。 予測の精度が良くない原因として、そもそも学習に使用するデータ量が少ない点がまず考えられます。 それ以外にもモデルを学習させる際に、CREATE句のOPTION内で様々な設定をし、予測精度を上げることも可能です。ここについては後続のブログで書きたいと思います。   まとめ 今回は、BigQuery MLを使ってモデルを作成し、実際に予測をしてみました。 今回は 公式ドキュメント に沿って実践を進めたのですが、「モデルの評価」については本ブログでは触れませんでした。(長くなりそうだったので。) 今回作成したモデルの評価結果を先出しておきます。 こんな感じです。初めて見る評価指標がズラリと並んでいたので、この辺りは別のブログで深堀していきます。
こんにちは。SCSK 中山です。 少し前に発表のあったDevice Postureのアップデートでプロファイルでレジストリキーの値や稼働しているプロセスを条件として設定できるようになりました。 弊社アカウントにもアップデートが適用されましたので、今回は設定・動作検証をしてみたいと思います。 と、その前に、、 Device Postureという機能を軽く説明しておきます。 Device Postureとは Device Postureとは、端末の状態をチェックし属性を付与する機能です。付与した属性に対してポリシーを設定することで、要件を満たさない端末をネットワークへ接続させないといったコントロールが可能になります。 詳細については、別途記事を書いておりますので、こちらをご覧ください。 CatoクラウドでDevice Postureを利用したい Device Postureの簡単な設定例と動作検証結果をご紹介します。 blog.usize-tech.com 2024.05.17 Device Postureは設定できる条件がいくつかあり、よく使われるところだとクライアントのセキュリティソフトのインストール有無、セキュリティソフトのバージョンのチェックがありますが、今回のアップデートでは条件として端末のレジストリキーの値や指定したプロセスが稼働しているかが指定できるようになったという感じです。 合わせてこの記事では触れてませんが、MacOS向けに「Property List」での指定も追加されております。 詳しくはCatoのナレッジをご確認ください。対応OS/Cato Clientのバージョンも記載されております。 Creating Device Posture Profiles and Device Checks   それでは早速設定・検証をしていきたいと思います。 実施手順 レジストリキーの設定 ① CMAから、「Access」 >「 Device Posture」>「Device Checks」の「New」から新規のポリシーを作成します。 ②「General」>「Device Test Type」で「Registry Key」を選択します。 ③ 「Criteria」にポリシーの内容を記載します。 OS:Windows Registry Key Path:<設定したいレジストリーのパス> Key Value Name:<設定したいレジストリキーの名前> Key Value Data:<設定したいレジストリキーの値> イメージとしては、「Registry Key Path」と「Key Value Name」でレジストリキーのフルパスを作る感じです。 例えば、以下画像のレジストリキー(HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU\NoAutoUpdate)の値で条件を作成したい場合、CMA側の設定はこんな感じになります。 ◆レジストリエディターの画面 ◆CMAの設定画面 レジストリキーに何かしら値が入っていたら、、、という条件の場合は「Key Value Data」で「Any Value」を選択してください。   ④ ポリシーを作成できたら、「Device Posture Profiles」より、新規でプロファイルを作成し、③で作成したポリシーを紐づけます。   プロセスの設定 ① レジストリキーの設定と同様に新規ポリシーを作成します。 ②「General」>「Device Test Type」で「Running Process」を選択します。   ③「Criteria」にポリシーの内容を記載します。(以下設定はWindowsの場合) OS:Windows Process Name or path:<設定したいプロセスのフルパス or プロセス名> Signer Certificate Thumbprint:<証明書の拇印> 以下は検証の際にAWSのssm-agentで設定した際のCMAの画面です。 プロセス名、拇印の確認方法 ・ プロセス名 「タスクマネージャー」よりプロセスの「プロパティ」を開くことで確認できます。 フルパスで指定したい場合には、同じようにプロパティ画面から確認できます。 CMAには 場所+プロセス名+ファイルの種類で記載すれば設定できます。 上記の場合、「C:\Program Files\Amazon\SSM\amazon-ssm-agent.exe」と指定する感じです。 サービスとして稼働している場合には、各サービスのプロパティ画面から直接フルパスを確認できます。   ・ 証明書の拇印の確認方法 ① プロセス名の確認手順と同様にタスクマネージャからプロセスのプロパティを開きます。 ② 「デジタル署名」タブを開き、署名を選択し、詳細を開きます。 ③「証明書の表示」し、証明書の「詳細タブ」を開きます。 詳細の中に「拇印」という項目があるので、その値をCMAの「Signer Certificate Thumbprint」に記載します。 Device Postureの設定自体はこれで完了です。 「Client Connectivity Policy」や「 Internet Firewall」、「WAN Firewall」で 作成したプロファイルを指定することで、対象のデバイスをコントロールすることができます。   実際にやってみた レジストリキーを指定する場合、プロセスを指定する場合、どちらも検証してみました。 レジストリキーはWindows Updateを無効化しているデバイスをCatoに接続できなくするような設定で検証してみました。 CMAの各設定はこんな感じです。 ◆ Device Checks 「Default」はレジストリエディター上で(規定)となっている箇所の時に使用します。 ◆ Device Posture Profile ◆ Client Connectivity Policy 今回設定しているレジストリキーはWindows Updateの自動更新を有効にする場合は「0」、自動更新を無効にする場合は「1」を設定するような項目になっていて、このポリシーでは自動更新が有効の場合、ポリシー1が適用されCatoに接続できますが、自動更新が無効の場合はポリシー2が適用され、接続できなくするような設定になってます。 クライアント側のレジストリキーはこんな感じで設定しました。 値を1にして自動更新を無効にしてます。 これでいざCato Clientの接続を試みると、、 エラーが出て接続できませんでした。 こんな感じでWindows Updateを無効化している端末をCatoに接続できないようにできました。 次にプロセスを指定する場合を検証しました。 操作ログ取得系のアプリがバックグラウンドで動いているイメージで、そのアプリを停止させるとCatoに接続できなくするような想定で検証しようと思いましたが、操作ログ取得系のアプリが検証環境になかったので、適当にバックグラウンドで動いているアプリを指定して検証しました。 CMAの各設定はこんな感じです。 ◆ Device Checks ◆ Client Connectivity Policy ◆ Client Connectivity Policy 基本的にはレジストリと同様でプロセスが稼働中はポリシー1が適用され、プロセスが停止中の場合はポリシー2が適用され接続できないような設定になってます。   クライアント側のプロセス稼働状況はこんな感じです。 設定した「amazon-ssm-agent」が稼働しております。 この状態で接続をすると、、 プロセス稼働中はもちろん接続はできます。   Catoに接続した状態のまま、「amazon-ssm-agent」のプロセスを停止して放置します。 ~5分後~ 接続が切れてしまい、再接続もできなくなりました。 本環境では、Device Postureのチェック間隔を5分にしていたため、検証では再チェックのタイミングで接続が切れました。 このように定期的にチェックが入るため、接続時のみプロセス稼働させておき、接続後にプロセスを落とすということはできないようになってます。 また、上記含めて「Client Connectivity Policy」でCatoに接続させるか否かを制御しておりますが、 Internet Firewall、WAN Firewallで もDevice Postureの設定を使った制御も可能です。 一応こんな感じです。 ◆ インターネットFW 「Action」部分を載せてませんが、「BLOCK」に設定していて、「Device Posture Profiles」の条件に該当する通信は全拒否するようにしてます。Profileは先程のプロセスで検証したものと同様。 ◆Cato Client 「Client Connectivity Policy」で制御していないので、Cato自体への接続はできてます。 Catoに接続 かつ 「amazon-ssm-agent」のプロセスが稼働している状態でインターネットにアクセスしようとすると、、 今回は条件該当する場合に通信をBLOCKするので、アクセスができないようになってます。   もちろんプロセスを止めると、条件に当てはまらないので、通常通りインターネットにアクセスすることができました。   余談ですが、ふと思いつきで複数ユーザでログインした状態でプロセスの判定を検証したところ、片方のユーザがプロセス起動している状態であれば、もう一方のユーザはプロセスを立ち上げてなくても、Catoに繋げてしまったので、”Device Posture”というだけあって、Catoに接続しようとしているユーザのプロセスだけではなく、端末全体のプロセスを見ているっぽいです。 誰かしらプロセスを立ち上げていればすり抜けられちゃうみたいなので、ユーザ単位で起動しているプロセスを条件に指定する場合には、注意が必要そうです。   ユースケースを考えてみた レジストリ/プロセスを指定して制御するユースケースを考えてみたいと思います。   まず、レジストリから。 レジストリは設定できる内容が多いため、できることはたくさんあると思います。 私が知っているレジストリの知識の範囲で例を挙げてみたいと思います。 まずは検証のようにWindows Updateを無効にしている端末の接続を不可にする場合ですかね。 パッチ管理ソフトでの制御をしている場合は不要かと思いますが、パッチ管理ソフトを導入していない場合、ルールは決めていてもなかなか強制はできず、セキュリティ基準を満たしていないPCが接続してしまう可能性があります。このような端末をレジストリで条件指定することによって、社内NWに接続できないようにできるのかなと思います。 パッチ回りだと適用されているセキュリティパッチを指すレジストリキーがありそうなので、そのキーを条件指定することで、セキュリティパッチを適用していないをCatoに接続させないということができそうかなと思ったのですが、毎回KB○○に新規で作成されるみたいで、毎月条件を変更するといった運用が必要そうなので、やろうと思えばできそうですが、運用を踏まえると現実的ではなさそうです。 他だと会社から支給されたPCに何かしらのフラグが設定されていたりしたら、会社PC or 個人PCとで識別できますかね。Cato Clientは正規のユーザであればログインできてしまうので、個人のPCにClientを入れてCatoから社内NWに接続できてしまいます。これに対し、フラグにあたるレジストリキーを条件にすることで、会社PCのみCatoに接続でき、個人PCは接続させないとかができそうです。   次にプロセス。 こちらも検証でやろうとしていた管理系のアプリ/プロセスを条件にして操作ログの取得できない端末は社内NWに接続させないとかは結構有用な気がします。 あとは、アンチウイルスソフトのプロセスを指定するとかもありな気がします。従来の設定でもアンチウイルスソフトを設定する方法がありましたが、あくまでインストールされているか、バージョンはポリシーを満たしているかをチェックしているだけで、実際に起動しているかを条件にしているものではないです。なので、社内ルールに則りインストールはしていても、実際にはアプリを止めているとかもできてしますので、プロセスの方で条件するのも良いかもです。 ただ、プロセス全般に言えることかもですが、バージョンアップ等でプロセス名が変わってしまうと設定変更が必要なので、注意が必要かもです。アップデートごとに検証をするという運用もセットかもですね。   まとめ 今回はアップデートで追加されたDevice Postureのレジストリキー/プロセスの指定での制御を検証してみました。 レジストリキー/プロセスを条件を指定できることになり、設定にあたりOSの知識も必要になってきましたが、今までの条件より比較的柔軟にデバイス制御ができるようになったかと思います。これまでにデバイス制御を断念したことがある方も今回のアップデートを機に再検討してみては如何でしょうか。  
本記事は 夏休みクラウド自由研究 8/31付の記事です 。 こんにちは、SCSK木澤です。 8/1から始まった夏休みクラウド自由研究も今回で最終回となりました。 今回の企画は幅広いクラウドやソリューションを担当する31名の執筆者にご協力いただき、無事完走することが出来ました。 TechHarmonyは 今春に500記事を超え 、その後も順調に記事数を増やしています。 今後も色々な企画を考えていきたいと思いますので、どうぞ引き続きご愛顧の程よろしくお願いします。 さて今回は自由研究らしく、普段とは違う話題としてAWS Lambdaのファイルシステムについて調査してみました。 きっかけ 私が本件に興味を持ったのは、5年前に携わった案件に遡ります。 管理しているEC2インスタンスに配布する設定ファイル一式についてユーザー毎/インスタンス毎にカスタマイズする必要があり、調査の上、 Lambdaのファイルシステム上で処理してS3に出力することが適切 と判断して実装しました。 S3バケットからzipファイルをダウンロードしてzip解凍 設定ファイルを書き換え 再度zip圧縮して、S3バケットに書き込み サーバレスコンピューティングとはいえ、実態としてはサーバーがあるんだなと興味深く当時は思った次第です。 そのあたりをもう少し詳細にお話していきます。   動作仕様 Lambdaの動作原理 理解を深めるためにも、Lambdaの動作原理についてから触れたいと思います。 とはいえJAWS DAYS 2022でのAWS(当時)の亀田さんの講演がとても解りやすく私の印象に強く残っているので、こちらから紹介します。 AWS Lambdaは2014年のre:Inventで発表されたものとなりますが、当時はユーザー毎に内部にEC2インスタンスを持つ構成でした。 その後Lambdaの実行に特化した構成としてNitroシステムとFirecrackerが導入され、より強固なアイソレーション(環境分離)と高速・多数の起動環境を実現しています。 実は私はAWSを担当する前に自社クラウドに携わっていたため強く思うのですが、AWS Lambdaのリリース当初はEC2ベース+コンテナの技術レベルであったにも関わらず、お客様(ディベロッパー)にとってあるべき姿を定義し、あるべき価格で(赤字でも?)提供する、そしてその後改善・解決していくという姿はThink BigでありCustomer Obesessionでもあるので感銘を受けたのを覚えています。 話が長くなったので戻しますが、現在AWS LambdaはNitroシステム+Firecrackerで提供されています。 つまり Lambdaも小さい仮想サーバー(microVM) という訳です。 よって、当然ながらファイルシステムもあります。 クオータ(制限)についてはこちらをご覧下さい。 Lambda クォータ - AWS Lambda Lambda 関数および API リクエストに関する最大サイズ、制限、およびクォータです。 docs.aws.amazon.com ユーザーがLambdaにアタッチできるローカルファイルシステムは、 /tmp にマウントされ512MB~10240MBの間で設定可能 です。 ウォームスタートとコールドスタート Lambdaのローカルファイルシステムについて触れる際に、この話は避けて通れません。 Lambdaを起動した際にmicroVMを作成される訳ですが、どうしてもこの 初期化作業には一定の時間が掛かります(コールドスタート) 。そのため、 もし再利用できるmicroVMがあれば再利用 してスピードアップするよう動作します (ウォームスタート) 参考:AWS Blackbelt AWS Lambda(p60あたりから) https://pages.awscloud.com/rs/112-TZM-766/images/20190402_AWSBlackbelt_AWSLambda%20Part1&2.pdf この 再利用(ウォームスタート)が発生した際は、前の実行時のファイルがユーザーファイルシステムに残ったまま になっています。 ファイル処理を行った際にファイル重複でエラーになる可能性があるのでご注意ください。 実行開始時に一旦すべて削除するか、例外処理を入れる必要があるでしょう。   調査 さて、ファイルシステムの詳細を調べてみたいと思います。 容量・パーミッションの確認 デフォルトの設定でLambdaを作成し、以下のコードで実行してみます。 PythonのOSライブラリでOSコマンドを実行しています。 import json import os def lambda_handler(event, context): # 実行ユーザーを確認 print("--user") print(os.system("whoami")) # ディスク容量を確認 print("--disk capacity") print(os.system("df -h")) # マウント状態を確認 print("--mount") print(os.system("cat /etc/fstab")) # パーミッションの確認 print("--permisson /") print(os.system("ls -al /")) print("--permisson /tmp") print(os.system("ls -al /tmp")) # 書き込み print("--write /") print(os.system("touch /test1.txt")) print(os.system("ls -al /")) print("--write /tmp") print(os.system("touch /tmp/test2.txt")) print(os.system("ls -al /tmp")) return { 'statusCode': 200, 'body': '' } 実行結果を確認します 実行ユーザー --user sbx_user1051 当然ながら一般ユーザー権限でユーザープロセスは実行されています ディスク容量、マウント状態 --disk capacity Filesystem Size Used Avail Use% Mounted on /dev/vde 144G 143G 0 100% / /dev/vdb 1.5G 18M 1.4G 2% /etc/hosts tmpfs 64M 0 64M 0% /dev /dev/vdd 525M 8.0K 514M 1% /tmp /dev/root 9.7G 386M 9.3G 4% /etc/passwd /dev/vdc 128K 128K 0 100% /var/task --mount # LABEL=/ / auto defaults,noatime 1 1 /tmpはユーザー設定により容量が変わるので、別ディスクとしてマウントされています 。 ルートディスクはリードオンリーではないですが、書き込み不可となっています。 パーミッション --permisson / total 116 drwxr-xr-x 18 root root 4096 Jul 31 08:47 . drwxr-xr-x 18 root root 4096 Jul 31 08:47 .. -rw-r--r-- 1 root root 48222 Jul 31 22:38 THIRD-PARTY-LICENSES.txt lrwxrwxrwx 1 root root 7 Jan 30 2023 bin -> usr/bin dr-xr-xr-x 2 root root 4096 Jan 30 2023 boot drwxr-xr-x 2 root root 200 Aug 30 00:50 dev drwxr-xr-x 34 root root 4096 May 10 11:16 etc drwxr-xr-x 2 root root 4096 Jan 30 2023 home -rwxr-xr-x 1 root root 397 Jul 31 15:59 lambda-entrypoint.sh lrwxrwxrwx 1 root root 7 Jan 30 2023 lib -> usr/lib lrwxrwxrwx 1 root root 9 Jan 30 2023 lib64 -> usr/lib64 drwxr-xr-x 2 root root 4096 Apr 25 19:25 local drwxr-xr-x 2 root root 4096 Jan 30 2023 media drwxr-xr-x 2 root root 4096 Jan 30 2023 mnt drwxr-xr-x 2 root root 4096 Jan 30 2023 opt dr-xr-xr-x 123 root root 0 Aug 30 01:40 proc dr-xr-x--- 2 root root 4096 Jan 30 2023 root drwxr-xr-x 5 root root 4096 Apr 25 19:25 run lrwxrwxrwx 1 root root 8 Jan 30 2023 sbin -> usr/sbin drwxr-xr-x 2 root root 4096 Jan 30 2023 srv drwxr-xr-x 2 root root 4096 Apr 25 19:25 sys drwxrwxrwx 2 root root 4096 Aug 5 15:36 tmp drwxr-xr-x 12 root root 4096 Jul 31 08:47 usr drwxr-xr-x 24 root root 4096 May 9 21:46 var /tmpは権限777のため、一般ユーザーでも書き込み可能です。 ファイル書き込みの確認 --write / touch: cannot touch '/test1.txt': Read-only file system 当然ながらルートディスクは書き込み不可です。 --write /tmp total 8 drwxrwxrwx 2 root root 4096 Aug 30 01:40 . drwxr-xr-x 18 root root 4096 Jul 31 08:47 .. -rw-r--r-- 1 sbx_user1051 990 0 Aug 30 01:40 test2.txt /tmpには書き込み可能です。 ファイル入出力速度の調査 さて、ローカルファイルシステム(/tmp)には何も保存されていない訳ですし、データは永続化できません。 よって、 S3バケットなどからダウンロードしてきてから処理を行う必要があります 。 ファイルの入出力時間が気になるので、確認してみます。 S3バケットを作成して、CloudShellから1GBのファイルを作成して保存します。 $ dd if=/dev/zero of=1gb.dat bs=1024k count=1024 $ aws s3 cp 1gb.dat s3://S3バケット名/ 以下のようなコードでLambda関数を作成します。 import json import boto3 import os bucketname = "S3バケット名" def lambda_handler(event, context): s3r = boto3.resource('s3') # /tmp削除 print("--delete") print(os.system("rm -rf /tmp/*")) # コピー data_bucket = s3r.Bucket(bucketname) print("--copy from S3 Bucket Start") data_bucket.download_file('1gb.dat','/tmp/1gb.dat') print("--copy from S3 Bucket End") return { 'statusCode': 200, 'body': '' } S3にアクセスできるLambda用IAMロールを作成し、本関数に適用します。 ディスク容量は増やしておきます。 EC2インスタンスと同様、Lambdaにおいてもメモリ容量とCPUスペックは比例するように設計されています。 そこで、メモリ容量≒CPU割り当てとS3からの読み取り速度を調べたところ、以下の通りになりました。(3回平均、CloudWatch Logsに出力されたログのタイムスタンプから算定) Lambdaメモリ割当量 ダウンロード時間 速度 128MB 74.2秒 110Mbps 256MB 40.4秒 203Mbps 512MB 19.4秒 422Mbps 1024MB 10.7秒 768Mbps 2048MB 10.4秒 785Mbps メモリ割り当てに比例してネットワークI/O帯域も拡張されること、但し(S3バケットからのダウンロードにおいては)800Mbps弱で頭打ちになる ことを確認しました。 つまり、/tmpの最大容量10GBのダウンロードもしくはアップロードを行うには、最低100秒程度の時間が掛かることになります。 この辺りがローカルディスクを用いた処理の限界であるであろうことが解りました。 要件満たさない場合はEFS利用 10GBを超える 大容量ファイルを扱いたい場合、あるいは永続ファイルをマウントしたい場合はAmazon EFSの利用が可能 です。 なお、Amazon EFSはVPC上のサービスですので、LambdaもVPCアタッチが必要となります。   まとめ 実に地味な内容でしたが、Lambdaのファイルシステムについて解説・確認しました。 ネットワーク帯域にも変動があることなど、新たな発見があり楽しかったですね。 Lambdaのローカルファイルシステム(/tmp)は非永続ということもあり、ディスク容量は課金には影響しません。 色々使いこなすと楽しいので、皆様もご活用下さい!
本記事は 夏休みクラウド自由研究 8/30付の記事です 。 こんにちは、SCSKの松岡です。 今回は、Snowflakeをこれから利用する方向けに、環境構築で最低限抑えておきたいポイントをぎゅっと絞ってご紹介します。Snowflakeのアカウントは作ったけど何から始めよう…とお悩みの方はぜひご参考ください! Snowflakeとは Snowflake (Snowflake Cloud Data Platform)は、Snowflake社が提供するSaaS型のクラウドデータプラットフォームです。 データ管理、セキュリティ、ガバナンス、可用性、データレジリエンスをサポートしたフルマネージド型のサービスであり、ウェアハウスのスケーリング/ポリシー制御/データ共有の柔軟性などから、デジタルデータの一元管理に優れたプラットフォームとして注目を集めています。 プラットフォームの概要 Snowflakeのクラウドデータプラットフォームが世界的に、あらゆる規模、あらゆる業界において、をほぼ無制限の同時実行ワークロードで強化した方法をご紹介します。 www.snowflake.com   利用する前に…… エディション Snowflakeでは、4つのエディションが用意されており、利用するアカウントがどのエディションかによって、一部できることが異なります。 (例)Time Travelによるデータの保管期間の90日延長はEnterprise以上のエディションのみ (例)PrivateLinkを使用したプライベート接続のサポートはBusiness Critical以上のエディションのみ Snowflakeは従量課金制ですが、上位のエディションほど利用あたりの単価が高い点にも注意が必要です。 Snowflake Edition | Snowflake Documentation docs.snowflake.com 言語設定 Snowsight(Snowflakeを操作するウェブ画面)のデフォルト表示は英語ですが、アイコンから「My profile」を選択し、Languageで「日本語」を選択することで日本語表示に切り替わります。 システムロール Snowflakeでは、「ロール」と呼ばれる単位でアクセス制御や権限管理を行います。 ユーザーには複数のロールを割り当てることができ、操作を行う際は、その操作ごとにロールを切り替えて(適切なアクティブロールを選択して)から実行を行います。 あらかじめ定義されたロールとして、以下のようなシステムロールが存在しています。 ACCOUNTADMIN アカウント内で最上位のロール。 アカウント管理者に限定して付与し、アカウント全体に関わる設定等をする際に使用します。 SECURITYADMIN セキュリティ管理用のロール。 ユーザーとロールの作成や、ロールの割り当て等が可能です。 USERADMIN ユーザーとロールの管理専用のロール。 SECURITYADMINと同じくユーザーとロールの作成が可能ですが、限定的です。 SYSADMIN ウェアハウスやデータベース、スキーマのようなオブジェクトを作成する権限を持つロール。 PUBLIC アカウント内のすべてのユーザー、ロールにデフォルトで付与されるロール セキュリティや誤操作防止の観点から、付与するロール、指定するロールはなるべく最小権限のものが望ましいです。 最初の時点では、アカウント全体の設定はACCOUNTADMIN、ユーザーの作成はUSERADMIN、ロールの作成・割り当てはUSERADMINかSECURITYADMIN、オブジェクト(データベース・スキーマ・ウェアハウス)の作成はSYSADMINと覚えておくと良いでしょう。 アクセス制御の概要 | Snowflake Documentation docs.snowflake.com Snowsightでは、以下の箇所でロールの切替を行えます。 (GUIで操作する場合) アイコンから「ロールを切り替え」を選択 (クエリを実行する場合) ワークシートの画面右上からロールを選択 Snowsightでは[プロジェクト]>[ワークシート]からワークシートを開くことで、ブラウザ上でSQLクエリの実行が可能です。   環境構築最初にやること集 最低限のパラメータ設定で作成する手順を紹介します。 ユーザー作成 利用者ごとにユーザーを作成しましょう。 GUIで作成 [管理者]>[ユーザーとロール]>[ユーザー]画面から、[+ ユーザー]を選択し、必要情報を入力して作成します。 クエリで作成 (サンプル) --user_001という名前でユーザー作成 CREATE USER user_001   PASSWORD = '[パスワード]'    EMAIL = "[メールアドレス]"    MUST_CHANGE_PASSWORD = TRUE    DISPLAY_NAME = "[表示名]" ; [MUST_CHANGE_PASSWORD]をTRUEにすることで、初回ログイン時にパスワード変更を強制させることができます。 CREATE USER | Snowflake Documentation docs.snowflake.com ユーザーを作成したら、アイコンの[自分のプロファイル]から多要素認証(MFA)を登録してもらいましょう。 特に管理者(ACCOUNTADMIN)ロールを持つユーザーについては設定が強く推奨されています。 多要素認証(MFA) | Snowflake Documentation docs.snowflake.com ウェアハウス作成 ウェアハウスは、クエリの処理時に使用されるコンピューティングリソースです。 データベース・スキーマのようなストレージ領域がコンピューティングリソースと分離しているのがSnowflakeの大きな特徴の一つです。 仮想ウェアハウス | Snowflake Documentation docs.snowflake.com GUIで作成 [管理者]>[ウェアハウス] 画面から、[+ ウェアハウス]を選択し、ウェアハウス名を入力して作成します。 Snowflakeではウェアハウスの稼働時間が長いほど多くの費用が発生するので、ウェアハウスの自動一時停止を有効にしておくことでコスト削減につながります。 クエリで作成 (サンプル) --wh_001という名前でウェアハウス作成 CREATE WAREHOUSE wh_001 WAREHOUSE_SIZE = XSMALL AUTO_SUSPEND = 60 ; 作成時に[WAREHOUSE_SIZE]でウェアハウスのサイズを指定します。お試し用途であれば、一番小さいXSMALLサイズで問題ないでしょう。 [AUTO_SUSPEND]の値が自動一時停止されるまでの秒数を表しますが、デフォルトの600より短い60に変更することで、利用していない場合はより素早く一時停止されます。(※60未満の値は非推奨) CREATE WAREHOUSE | Snowflake Documentation docs.snowflake.com   データベース・スキーマ作成 Snowflakeでは、データを格納するためにテーブルが必要ですが、そのテーブルの格納先としてデータベース、スキーマが必要です。 GUIで作成 [データ]>[データベース] 画面から、[+ データベース]を選択し、データベース名を入力して作成します。 スキーマは作成したデータベースの画面から、[+ スキーマ]を選択して作成します。 クエリで作成 (サンプル) --db_001という名前でデータベース作成 CREATE DATABASE db_001; --schema_001という名前で、db_001にスキーマ作成 CREATE SCHEMA db_001.schema_001; データベース、スキーマともに、通常利用であれば特別なパラメータの指定は必要なく簡単に作成ができます。 CREATE DATABASE | Snowflake Documentation docs.snowflake.com CREATE SCHEMA | Snowflake Documentation docs.snowflake.com   ロール作成・付与 序盤にシステムロールを紹介しましたが、独自のロールを作成してユーザーに権限付与することも可能です。 例として、特定のDB、特定のウェアハウスのみに対して一般的な操作限定で行えるロールを作成してみます。 クエリで作成 (サンプル) --sample_role_001という名前でロールの作成 CREATE ROLE sample_role_001; --sample_role_001ロールにUSAGE権限付与 GRANT USAGE ON DATABASE db_001 TO ROLE sample_role_001; GRANT USAGE ON SCHEMA db_001.schema_001 TO ROLE sample_role_001; GRANT USAGE ON WAREHOUSE wh_001 TO ROLE sample_role_001; --sample_role_001ロールにテーブル、ビューのCREATE権限付与 GRANT CREATE TABLE, CREATE VIEW ON SCHEMA db_001.schema_001 TO ROLE sample_role_001; --sample_role_001ロールにテーブル、ビューの操作権限付与 GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE ON ALL TABLES IN SCHEMA db_001.schema_001 TO ROLE sample_role_001; GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE ON FUTURE TABLES IN SCHEMA db_001.schema_001 TO ROLE sample_role_001; GRANT SELECT ON ALL VIEWS IN SCHEMA db_001.schema_001 TO ROLE sample_role_001; GRANT SELECT ON FUTURE VIEWS IN SCHEMA db_001.schema_001 TO ROLE sample_role_001; --user_001ユーザーにample_role_001ロールを付与 GRANT ROLE sample_role_001 TO USER user_001; sample_role_001という名前のロールを作成し、ロールに対して権限を付与し、そのロールを特定のユーザーuser_001に付与してみました。 ロールに付与している権限の中で、「USAGE」は使用権になります。使用できるようにしたいデータベース、スキーマ、ウェアハウスに対して、このUSAGE権限をそれぞれ付与する必要があります。 続けて、ロールに対し、スキーマschema_001に限定してテーブル・ビューのcreate権限や操作権限を付与しています。 テーブルやビューを指定する際に、「ALL TABLES」や「ALL VIEWS」のような指定は、既存のテーブルやビューすべてを対象に権限を付与することを意味します。一方で「FUTURE TABLES」や「FUTURE VIEWS」のような指定は、これから作成されるテーブルやビューに対して権限を付与することを意味します。 「ALL TABLES」で指定しただけでは、新規で作成したテーブルに対して権限が付与されないことに注意が必要です。 最後に、GRANT ROLE でユーザーに対して作成したロールを付与することで、付与した特定のユーザーに対してカスタマイズした権限のみを付与することが可能です。 GRANT <権限> | Snowflake Documentation docs.snowflake.com   ネットワークポリシー設定 Snowflakeでは、ネットワークポリシーを設定し、Snowflakeに接続できるIPアドレスを制限することが推奨されています。例として、IPアドレス範囲を指定して、許可したIPアドレスのみ接続できるようにする設定を示します。 クエリで設定 (サンプル) USE ROLE SYSADMIN; --Network Rules設定用のデータベース・スキーマを作成 CREATE DATABASE securitydb; CREATE SCHEMA securitydb.networkrules; USE ROLE ACCOUNTADMIN; --network_rule_sampleという名前でネットワークルールを作成 CREATE NETWORK RULE network_rule_sample MODE = INGRESS TYPE = IPV4 VALUE_LIST = ('47.88.25.32/27') ; --network_policy_sampleという名前でネットワークポリシーを作成し、network_rule_sampleを許可 CREATE NETWORK POLICY network_policy_sample ALLOWED_NETWORK_RULE_LIST = ('network_rule_sample') ; --作成したネットワークポリシーをアカウント全体に適用 ALTER ACCOUNT SET NETWORK_POLICY = network_policy_sample; ネットワークルールはスキーマオブジェクトなので、作成時にデータベース、スキーマを指定する必要があります。 上記を実行することにより、Snowflakeアカウント全体が、 47.88.25.32/27 のIPアドレス範囲からの接続しか許可されなくなります。 ネットワークルールを複数作成することで、許可する条件をOR条件で複数設定することや、ネットワークポリシーをアカウント全体でなくユーザーごとに別々に適用することも可能です。 アカウント全体に適用する際は、設定誤りに注意しましょう。 適用後、サインアウトする前に別ブラウザを立ち上げる等して接続できるかどうかの動作を確認しておくと安心です。設定誤りがある場合は、  ALTER ACCOUNT UNSET NETWORK_POLICY; を実行することでネットワークポリシーを無効化できます。   ネットワークポリシーを使用したネットワークトラフィックの制御 | Snowflake Documentation docs.snowflake.com   タイムゾーンの変更 Snowflakeでは、デフォルトのタイムゾーンがAmerica/Los_Angelesに設定されています。 アカウント全体でデフォルトのタイムゾーンを日本標準時に変更する場合は、以下のようにアカウントパラメータの値を変更します。 --タイムゾーンを日本標準時に変更 ALTER ACCOUNT SET TIMEZONE = 'Asia/Tokyo';   パラメーター管理 | Snowflake Documentation docs.snowflake.com   リソースモニター リソースモニターを利用することで、Snowflakeアカウント内でのクレジット(リソース使用量)の状況を監視することができます。 リソースモニターによる設定は、新規の場合は[管理者]>[コスト管理]>リソースモニター 画面から、[+ リソースモニター]を選択します。 リソースモニターによる監視は、[モニタータイプ]から、アカウント全体の監視か、ウェアハウス個別の監視かを指定できます。 [クレジットクォータ]で、指定した期間で許可するクレジットの上限を設定します。そして、指定したクレジットクォータに対して実際の使用が何%に達したかに応じて、[アクション]で、通知や即時一時停止といった内容を設定することが可能です。 作成したリソースモニターの通知を受け取りたい場合は、ACCOUNTADMIN権限を持つユーザーのアイコンの[自分のプロファイル]を選択し、「リソースモニターからのメール通知」にチェックが入っていることを確認しましょう。 リソースモニターの操作 | Snowflake Documentation docs.snowflake.com   最後に Snowflakeでは公式のガイドやブログ記事が充実しており、構築に関するヒントやベストプラクティスの記載をたくさん見つけられるので要チェックです。 環境が用意できたら、どんどんデータを投入して活用してみましょう! ガイド - Snowflakeドキュメント docs.snowflake.com Inside the AI Data Cloud From technical articles about AI and application strategies to real-world success stories, the Snowflake Blog explores w... www.snowflake.com
Prisma Cloudにおけるアラートとは、Prisma Cloudがクラウド環境内で検知したセキュリティリスクや脆弱性等を通知するための機能です。アラートが発生した後、適切な対応を取りシステムのセキュリティを維持することが重要です。 Prisma Cloudで検知されたアラートに対して取ることができるアクションにはアラートの解除や一時停止等があります。アラートに対して取ることができる主なアクションについて解説していきたいと思います。 アラートの解決 クラウド側で設定を修正した場合やアラートが発生した対象のリソースが削除された場合等、これらの変更がなされると該当のアラートは自動的に「resolved」(解決済)というステータスに更新されます。   アラートの一時停止 アラートの一時停止は、アラート対応を一時的に保留したい場合や特定の期間中にアラートを無視したい場合等に使用します。この機能により、特定の時間枠内でのアラート通知を抑制することが可能です。 ユースケース メンテナンス期間中: メンテナンス作業中に一時的に発生するアラートを抑制したい場合 テスト中: テスト中に特定のアラートを抑制したい場合 等 設定方法 1.PrismaCloudコンソールにログインします。 2.「アラート」セクションに移動し、対象のアラートを選択します。   3.「一時停止」をクリック → 一時停止の期間や理由を入力し、「Snooze」をクリックします。今回は「まで」を選択し「2024年7月25日木曜日 18:10」までアラートを一時停止することにします。 アラートの最低一時停止時間は1時間です。1時間より短い時間を指定することはできません。 ↓   4.画面右上に「アラートは正常にスヌーズされました。」ポップアップが表示され、対象のアラートは表示されなくなりました。   5.フィルタの「アラートステータス」で「スヌーズ中」を選択してみると対象アラートの「アラートステータス」がsnoozedになっていることが確認できました。   6.「2024年7月25日木曜日 18:10」以降に確認すると、対象アラートの「アラートステータス」がopenに戻っていることを確認できました。(ちなみに、同日18:12時点ではまだ「アラートステータス」がsnoozedでしたが、18:30頃には「アラートステータス」がopenに戻っていました。)   アラートの解除 アラートの解除は、アラートの原因となった設定は意図した設定であり問題なしと判断した場合等に行います。この操作によりアラートは消え、再び同じインシデントが発生しない限り表示されなくなります。 ユースケース テスト環境のアラート解除: テスト環境で発生したアラートであるため解除したい場合 等 設定方法 1.Prisma Cloud コンソールにログインします。 2.「アラート」セクションに移動し、対象のアラートを選択します。   3.「解除」をクリック → 理由を記載して「Dismiss」をクリックします。 ↓     4.画面右上に「アラートは正常に解除されました。」ポップアップが表示され、対象のアラートは表示されなくなりました。   5.フィルタの「アラートステータス」で「解除済」を選択してみると対象アラートの「アラートステータス」がdismissedになっていることが確認できました。   アラートの再オープン アラートの再オープンは、一度解決されたアラートが再び問題となる場合や新たな関連リスクが確認された場合等に使用します。この機能は、アラートのライフサイクルを追跡しやすくし、継続的なセキュリティ監視を可能にします。 ユースケース 問題が再発した場合: 過去に解決したセキュリティ問題が再び発生した場合 等 設定方法 1.Prisma Cloud コンソールにログインします。 2.「アラート」セクションに移動し、再オープンしたいアラートを選択します。   3.「再オープン」をクリックし、「確認する」をクリックします。 ↓   4.画面右上に「アラートは正常に再オープンされました。」ポップアップが表示され、対象のアラートは表示されなくなりました。   5.フィルタの「アラートステータス」で「未解決」を選択してみると対象アラートの「アラートステータス」がopenになっていることが確認できました。   まとめ Prisma Cloudで検知されたアラートに対する対応には、アラートの解除、一時停止等多くの選択肢があります。ユースケースに合わせて活用することで、安全で効率的なクラウド環境を維持することができます。クラウドのセキュリティ管理には迅速かつ正確な対応が求められるため、Prisma Cloudのアラート機能をしっかりと活用することが重要です。このブログが、Prisma Cloudのアラート管理についての理解を深める一助となれば幸いです。 また、当社では、複数クラウド環境の設定状況を自動でチェックし、設定ミスやコンプライアンス違反、異常行動などのリスクを診断するCSPMソリューションを販売しております。   ■マルチクラウド設定診断サービス with CSPM マルチクラウド設定診断サービス with CSPM| SCSK株式会社 ■Smart One Cloud Security CSPM | Smart One Cloud Security® Powered by Prisma Cloud from Palo Alto Networks | SCSK株式会社 ご興味のある方はお気軽にお問い合わせください。
本記事は 夏休みクラウド自由研究 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 テンプレート作成ライフをお祈りしています!