TECH PLAY

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

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

1230

こんにちは。SCSKの山口です。 今回は、Cloud Functions とData Fusionを組み合わせて、下記のパイプラインを構築してみたいと思います。 Cloud Functions のEventarc トリガーでGCSバケットへのファイル配置・更新を検知する Cloud Functions からDataFusionパイプラインを起動し、データ加工とBigQuery へのデータ格納を行う 特定のバケットにファイルが置かれた際に、それを検知してData Fusion起動→BigQuery テーブルへデータ格納。といった流れです。 Data Fusion パイプライン作成 今回は、下記のブログで作成したパイプラインを再利用します。 【GCP】Cloud Data Fusion で Wrangler を柔軟に使い倒す Google CloudのData Fusionでパイプラインを構築する機会が多くあり、その中でも「Wrangler」のプライグインを多く使用したので、その際に便利だった機能をご紹介します。 blog.usize-tech.com 2024.08.06 CSVファイル内の ハイフン付きの電話番号 から ハイフンを取り除き 、BigQuery テーブルへ格納するパイプラインです。 Wranglerプラグインを直感的に操作する方法を紹介しています。本ブログのメインではないので詳細は省きます。気になる方はぜひご覧ください。   Cloud Functions ファンクション作成 次にファンクションを作成し、デプロイします。 構成 下記構成で作成します。 基本 環境:第2世代 関数名:yamaguchi-test-datafusionkick リージョン:asia-northeast1(東京) トリガー トリガーのタイプ: Cloud Storage イベントタイプ: google.cloud.storage.object.v1.finalized バケット: yamaguchi_test_20240806 イベントタイプの「google.cloud.storage.object.v1.finalized」については、下記ブログの「Cloud Storageトリガーとは?」で紹介してあるのでこちらをご覧ください。 Cloud FunctionsのCloud Storageトリガーをフォルダレベルで指定したい!! 先日、Dialogflow CXのAgentからのテストケース作成を自動化していて、「あるフォルダにファイルがアップロードされたら起動するCloud Functionsを作りたい」とふと思いました。そこで今回はバケットレベルで指定するCloud Storageトリガーをどうにかしてフォルダレベルで指定できないか調べてみました。 blog.usize-tech.com 2024.08.05 今回は、「yamaguchi_test_20240806」バケットを対象とし、バケットレベルで更新を検知する設定とします。 コード 今回作成したコードは下記のとおりです。 main.py import functions_framework import os import requests from google.cloud import data_fusion_v1 from google.auth import compute_engine from google.auth.transport.requests import Request @functions_framework.cloud_event def call_datafusion(cloud_event):   # Data Fusionクライアント生成     DataFusion_client = data_fusion_v1.DataFusionClient()   # アクセストークン取得 →{access_token}   credentials = compute_engine.Credentials()   credentials.refresh(Request())     access_token = credentials.token   # Data Fusionパイプライン呼び出し用の認証ヘッダ設定 →{auth_header_fusion}     auth_header_fusion = {'Authorization': f'Bearer {access_token}'}   #パラメータ設定   namespace = 'default'   app_name = 'yamaguchi_test_20240805'   workflow_name = 'DataPipelineWorkflow'   #CDAPのエンドポイントを取得(gcloudコマンド無し) →{cdap_endpoint}   set_request = data_fusion_v1.GetInstanceRequest(       name="projects/scsksdv-dev-XXXXXXXXX/locations/asia-northeast1/instances/test-df-02",   )   get_prm = DataFusion_client.get_instance(request=set_request)     cdap_endpoint = get_prm.api_endpoint   # CDAP APIにリクエストを送信   url = f'{cdap_endpoint}/v3/namespaces/{namespace}/apps/{app_name}/workflows/{workflow_name}/start'     response = requests.post(url, headers=auth_header_fusion)   # レスポンスを確認   if response.ok:       print(f'パイプライン呼び出しは正常に処理されました。ステータスコード: {response.content.decode()}')       print(f'IDトークン: {ID_token}')       print(f'アクセストークン: {access_token}')   else:       print(f'パイプライン呼び出しでエラーが発生しました。ステータスコード: {response.content.decode()}')     return ("END") requirements.txt functions-framework==3.* google-cloud-storage google-auth google-cloud-data-fusion pandas requests 以上でファンクションは完成です。   ファンクションのコードに関しての備忘(※読み飛ばしても問題ないです) コードを作成するにあたっていくつかの壁に当たったので備忘として残しておきます。 今回パイプラインを起動するコードの作成にあたって、下記の方法(コマンド実行)でパイプラインが起動できることをはじめに確認しました。 POST -H "Authorization: Bearer ${AUTH_TOKEN}" "${CDAP_ENDPOINT}/v3/namespaces/namespace-id/apps/pipeline-name/workflows/DataPipelineWorkflow/start" 上記コマンドでは、認証とパイプライン起動のために「AUTH_TOKEN」、「CDAP_ENDPOINT」を必要とします。 この「2つのトークンの取得 → CDAP APIへリクエスト送信」のコードをCloud Functions で実行したところ、下記のエラーにあたりました。 errorとなる部分 error内容 500 Internal Server Error: The server encountered an initial error and was unable to complete your request. 詳細を調べたところ、Cloud Functions内で 「gcloud」のコマンドが実行できず 、 「CDAP_ENDPOINT」が正常に取得できていないこと が原因でした。 対応策 上記の対応策として、 「gcloudコマンドを使わないコードに置き換える」 手段を取りました。 下記ライブラリリファレンスから代替ライブラリを探し、 「CDAP_ENDPOINT」を正しい形で取得できるよう コードを修正しました。 API と Python ライブラリ  |  Google Cloud cloud.google.com →CDAP_ENDPOINTの欲しい形は「https://…」 →怪しいライブラリを発見 →コピペして実行してみると、欲しい形「https://…」でCDAP_ENDPOINTが取得できた   実践 ファンクションとパイプラインが準備できたので、ここから実践に入ります。 まず、今回やりたいことをおさらいします。   Cloud Storageバケットの変更、更新をCloud FunctionsのCloud Storageトリガー出検知 Cloud FunctionsからData Fusionのパイプラインをキック Cloud Storage上のファイルをBigQueryテーブルに取り込む 仰々しく図式化しましたが、やりたいことはシンプルです。   今回使用する、データ取り込み先のテーブルは下記です。 また、GSCに配置する(テーブルに取り込む)CSVファイルの中身はこんな感じになっています。   それではファイルをバケットに配置してみます。  バケットにファイルを配置すると、 パイプラインが起動されました。(Provisioning状態) しばらく待つと、 パイプライン処理が完了し、BigQueryテーブルにレコードが追加されました。大成功です。   最後に 今回はCloud FunctionsのCloud Storageトリガーでバケットの変更を検知し、Data Fusionパイプラインを起動してみました。 バケット単位での変更検知ができるとなると、次にやりたいのは 「フォルダ・ファイル単位」の変更検知 ですよね。 実は、 フォルダ・ファイル単位の検知トリガーはまだ実装されていません 。(なんてことだ・・・) しかし、Cloud Functions内のコードに処理を寄せることで、 疑似的に実現することは可能 です。 こちらについては下記ブログで詳細な方法が紹介されているのでぜひご覧ください。(先を越されてた・・・) Cloud FunctionsのCloud Storageトリガーをフォルダレベルで指定したい!! 先日、Dialogflow CXのAgentからのテストケース作成を自動化していて、「あるフォルダにファイルがアップロードされたら起動するCloud Functionsを作りたい」とふと思いました。そこで今回はバケットレベルで指定するCloud Storageトリガーをどうにかしてフォルダレベルで指定できないか調べてみました。 blog.usize-tech.com 2024.08.05
本記事は 夏休みクラウド自由研究 8/9付の記事です 。 はじめに Cato クラウドのネットワークに AWS や Azure などのパブリッククラウドを接続する場合、vSocket という仮想マシンイメージ形式で提供されるアプライアンスを利用するのが一般的ですが、IPsec やインターコネクト (AWS Direct Connect など) で接続することもできます。 vSocket は機能面や管理の手間という点で断然メリットが多いものの、アプライアンスの中身のソフトウェアがブラックボックスであるという点は、エンジニアとして少しだけ不安な要素でもあります。やはり通信は標準化されたプロトコルで行い、実際に見える形にして安心したいという思いがあります。 そこで、アプライアンスやルータ機器などを用いず、Linux サーバから IPsec で Cato クラウドに接続してみたいと思います。今回のブログは「 夏休みクラウド自由研究 」の一環ですので、自身の探求心に従い自由気ままにやっていきましょう。 今回試した構成 今回はシンプルに次のようなネットワーク構成で試しました。 Linux サーバはオフィスやパブリッククラウド上のネットワークの中にある想定で、次の前提・想定を置いています。 Linux サーバからインターネットに任意にアクセスできる Linux サーバは NAT (IPマスカレード) を行うルータの内側に存在し、グローバルIPアドレスを持たない ゲートウェイのグローバルIPアドレスは固定ではない 要するにこの Linux サーバは一般的なネットワーク環境にある1端末という位置づけです。このサーバと Cato PoP との間で IPsec 接続を試しました。 実際は AWS 環境上で環境を構築しており、Linux サーバをプライベートサブネットに配置し、NAT Gateway 経由でインターネットにアクセスするような構成としています。 Cato 側の設定 まずは CMA 上で IPsec 接続用の検証用 Site を作成します。 IPsec 接続に関する設計ポイントや具体的な設定方法は、 弊社の別記事 や Cato クラウドのドキュメント に詳しく記載されています。 【Catoクラウド】YAMAHAルータでIPsec接続 YAMAHAルータをCatoへIPsec接続する際の、Config例や注意点をご紹介します。 blog.usize-tech.com 2024.02.02 今回は次の設定で Site を作成しました。 Site Name : Linux IPsec Test Site Type : Branch Connection Type : IPsec IKEv2 Country : Japan Timezone : Tokyo City : Tokyo License Type, License : 適切なもの Native Range : 192.168.200.0/24 (Linux サーバの LAN のレンジ) 作成した Site の IPsec の設定は次のようにしました。 Connection Mode : Responder Only Authentication Identifier : FQDN Primary Destination Type : FQDN Cato FQDN : 自動で割り当てられる PoP Location : 空欄 Public Site Identifier : 自動で割り当てられる Private IPs : Cato, Site ともに空欄 (今回はBGPを利用しないため) Last-mile Bandwidth : License と同じ帯域幅 Primary PSK : 事前共有鍵 (64文字以下の任意の英数字) Secondary : 設定しない Init Message Parameters : 変更しない (Responder Mode では設定できない) Auth Message Parameters : 変更しない (全てデフォルトのまま) Routing : 設定しない 上記設定のポイントは3か所あります。 今回のネットワーク構成では NAT のせいで Cato PoP から Linux サーバに対して IPsec 接続を開始できないため、 Connection Mode を “Responder Only” とすることで Cato PoP から IPsec 接続を行わないようにしています。 Destination Type についてですが、”IPv4″ にすると IP Allocation 機能で確保した特定 PoP に紐づくIPアドレスを指定する必要があり、その PoP で大きな障害が起きてサービスダウンが発生すると IPsec 接続が行えなくなってしまいます。そうなっても困らないようにするために、通常は Secondary も指定して2本目の IPsec 接続を行って冗長化する必要があります。しかし、 Destination Type を “FQDN” を選択して PoP Location を空欄 にしておけば、PoP でサービスダウンが発生しても別の正常な PoP に接続するよう名前解決が自動で切り替わり、数分間の通信断を許容できるのであれば IPsec 接続を冗長化しなくても済むという特徴があるので、今回採用してみました。 Authentication Identifier は “IPv4″ (プライベートIPアドレスを指定する) としても問題はないのですが、Cato 側にピアのIPアドレスを意識させたくなかったため、”FQDN” としました。 Linux サーバの設定 OS・ネットワークの確認 今回は Linux サーバのOSとして、Red Hat Enterprise Linux 9 と互換性の高い AlmaLinux OS 9 を採用しました。 $ cat /etc/redhat-release AlmaLinux release 9.4 (Seafoam Ocelot) $ uname -a Linux alma 5.14.0-427.26.1.el9_4.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Jul 17 15:51:13 EDT 2024 x86_64 x86_64 x86_64 GNU/Linux ネットワークインターフェースやルートテーブルなど、関連する設定は次のようになっていました。 $ ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000 link/ether 06:0c:19:8a:6a:b5 brd ff:ff:ff:ff:ff:ff altname enp0s5 altname ens5 inet 192.168.200.132/28 brd 192.168.200.143 scope global dynamic noprefixroute eth0 valid_lft 2102sec preferred_lft 2102sec inet6 fe80::40c:19ff:fe8a:6ab5/64 scope link valid_lft forever preferred_lft forever $ ip route default via 192.168.200.129 dev eth0 proto dhcp src 192.168.200.132 metric 100 192.168.200.128/28 dev eth0 proto kernel scope link src 192.168.200.132 metric 100 $ ip rule 0: from all lookup local 32766: from all lookup main 32767: from all lookup default ネットワーク的にはインターフェースを1つだけ持つシンプルなマシンです。 Libreswan のインストール・設定 Linux サーバで IPsec 接続を行う場合、OSS ですと Libreswan, strongSwan, Openswan といったソフトウェアを使うことになりますが、今回は RHEL で採用されている Libreswan を使っていきます。 インストールは libreswan パッケージを dnf でインストールするだけです。 $ sudo dnf install libreswan $ ipsec --version Libreswan 4.12 次に Libreswan の設定ですが、 ipsec.conf(5) や ipsec.secrets(5) のマニュアルを参考に次の内容で作成し、/etc/ipsec.d/ ディレクトリに配置しました。 $ sudo vim /etc/ipsec.d/cato.conf $ sudo cat /etc/ipsec.d/cato.conf conn cato left=192.168.200.132 leftid=@XXXXXXXXXX.YYYY.catonetworks.com leftnexthop=192.168.200.129 right=ZZZZZZZZZZ.ipsec.catonetworks.net rightid=@ZZZZZZZZZZ.ipsec.catonetworks.net leftsubnet=0.0.0.0/0 rightsubnet=0.0.0.0/0 ipsec-interface=yes encapsulation=yes authby=secret ikev2=insist auto=start $ sudo vim /etc/ipsec.d/cato.secrets $ sudo cat /etc/ipsec.d/cato.secrets @XXXXXXXXXX.YYYY.catonetworks.com @ZZZZZZZZZZ.ipsec.catonetworks.net : PSK "事前共有鍵" $ sudo chmod 600 /etc/ipsec.d/cato.secrets left は Linux サーバ側、right は Cato PoP 側を表す設定項目です。また、”XXXXXXXXXX.YYYY.catonetworks.com” と “ZZZZZZZZZZ.ipsec.catonetworks.net” は、Cato 側の IPsec の設定で自動で割り当てられた Public Site Identifier および Cato FQDN の値です。 left や leftnexthop には Linux サーバのプライベートIPアドレスやゲートウェイのIPアドレスを指定しています。 今回は IPsec 接続の認証IDとして FQDN を利用しますので、FQDN の先頭に “@” を付けた文字列を leftid や rightid に指定する必要がありました。 IPsec にはポリシーベースとルートベースの2種類がありますが、ルートベースのほうが扱いやすいため、そうするため leftsubnet, rightsubnet, ipsec-interface を上記のように指定しています。また、Linux サーバは NAT (IPマスカレード) を行うルータの内側に存在するので、NAT トラバーサルを有効にするため “encapsulation=yes” としています。 今回の検証において、ちゃんと動作する Libreswan の設定を作るのが一番大変でした…。 IPsec 接続 Libreswan の設定を配置したら、IPsec 接続をして確認していきます。 その前に、Cato PoP の接続先の FQDN を名前解決してみると次のような結果となりました。 $ dig +noall +answer A ZZZZZZZZZZ.ipsec.catonetworks.net ZZZZZZZZZZ.ipsec.catonetworks.net. 30 IN A 150.195.218.109 150.195.218.109 というIPアドレスは東京にあるいずれかの PoP のものですね。Socket や Cato Client による PoP 接続とは異なり、いくつかの接続先の候補が提示されて近いものを選択するという仕組みではないようです。Site の設定で場所を東京としていましたので、その設定をもとに近い PoP が自動で選択されたものと思います。 DNS レコードの TTL は30秒となっており、IPsec の接続先が切り替わったときに素早く反映されるようになっていますね。 それでは IPsec 接続を開始してみます。systemctl で ipsec サービスを起動すれば接続が行われます。 $ sudo systemctl start ipsec 無事にうまく接続されれば、ipsec1 というインターフェースが作成されているはずです。 $ ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000 link/ether 06:0c:19:8a:6a:b5 brd ff:ff:ff:ff:ff:ff altname enp0s5 altname ens5 inet 192.168.200.132/28 brd 192.168.200.143 scope global dynamic noprefixroute eth0 valid_lft 2987sec preferred_lft 2987sec inet6 fe80::40c:19ff:fe8a:6ab5/64 scope link valid_lft forever preferred_lft forever 3: ip_vti0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 5: ipsec1@eth0: <NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000 link/none inet6 fe80::4e73:f3e6:521e:1678/64 scope link stable-privacy valid_lft forever preferred_lft forever journalctl で接続時のログも見てみましたが、Child SA も確立して問題なく接続できているようです。 Jul 29 17:19:34 alma pluto[1480]: "cato": added IKEv2 connection Jul 29 17:19:34 alma pluto[1480]: listening for IKE messages Jul 29 17:19:34 alma pluto[1480]: Kernel supports NIC esp-hw-offload Jul 29 17:19:34 alma pluto[1480]: adding UDP interface eth0 192.168.200.132:500 Jul 29 17:19:34 alma pluto[1480]: adding UDP interface eth0 192.168.200.132:4500 Jul 29 17:19:34 alma pluto[1480]: adding UDP interface lo 127.0.0.1:500 Jul 29 17:19:34 alma pluto[1480]: adding UDP interface lo 127.0.0.1:4500 Jul 29 17:19:34 alma pluto[1480]: adding UDP interface lo [::1]:500 Jul 29 17:19:34 alma pluto[1480]: adding UDP interface lo [::1]:4500 Jul 29 17:19:34 alma pluto[1480]: loading secrets from "/etc/ipsec.secrets" Jul 29 17:19:34 alma pluto[1480]: loading secrets from "/etc/ipsec.d/cato.secrets" Jul 29 17:19:34 alma pluto[1480]: "cato" #1: initiating IKEv2 connection Jul 29 17:19:34 alma pluto[1480]: "cato" #1: sent IKE_SA_INIT request to 150.195.218.109:500 Jul 29 17:19:34 alma pluto[1480]: "cato" #1: received anti-DDOS COOKIE response, resending IKE_SA_INIT request with COOKIE payload Jul 29 17:19:34 alma pluto[1480]: "cato" #1: sent IKE_SA_INIT request to 150.195.218.109:500 Jul 29 17:19:34 alma pluto[1480]: "cato" #1: sent IKE_AUTH request {cipher=AES_GCM_16_256 integ=n/a prf=HMAC_SHA2_256 group=DH19} Jul 29 17:19:34 alma pluto[1480]: "cato" #1: initiator established IKE SA; authenticated peer using authby=secret and ID_FQDN '@ZZZZZZZZZZ.ipsec.catonetworks.net' Jul 29 17:19:34 alma pluto[1480]: "cato" #2: route-client output: leftsubnet == rightsubnet = 0.0.0.0/0 cannot add route Jul 29 17:19:34 alma pluto[1480]: "cato" #2: initiator established Child SA using #1; IPsec tunnel [0.0.0.0-255.255.255.255:0-65535 0] -> [0.0.0.0-255.255.255.255:0-65535 0] {ESPinUDP=>0x42a73e98 <0x32b41687 xfrm=AES_GCM_16_256-NONE NATD=150.195.218.109:4500 DPD=passive} Jul 29 17:19:34 alma pluto[1480]: netlink_expire got message with length 116 < 232 bytes; ignore message Jul 29 17:19:34 alma pluto[1480]: netlink_expire got message with length 116 < 232 bytes; ignore message Jul 29 17:19:34 alma pluto[1480]: netlink_expire got message with length 116 < 232 bytes; ignore message Jul 29 17:19:34 alma pluto[1480]: netlink_expire got message with length 60 < 232 bytes; ignore message ネットワーク関連の設定も見てみると、ポリシーベースルーティングにより IPsec の通信は50番のルーティングテーブルを参照し、Cato PoP 宛の通信は Linux サーバがあるネットーワークのゲートウェイ経由で行われるようになっていました。 $ ip route default via 192.168.200.129 dev eth0 proto dhcp src 192.168.200.132 metric 100 192.168.200.128/28 dev eth0 proto kernel scope link src 192.168.200.132 metric 100 $ ip rule 0: from all lookup local 100: from all fwmark 0x1 lookup 50 32766: from all lookup main 32767: from all lookup default $ ip route show table 50 150.195.218.109 via 192.168.200.129 dev eth0 もしも ipsec1 というインターフェースが作られていなかった場合、設定の不備や不整合により IPsec 接続に失敗しています。この場合、設定を変更して再接続を試してみるわけですが、CMA 上の設定変更が反映されるまで5分程度時間がかかったり、接続失敗を何度も繰り返していると一定期間は接続拒否されたりするため、試行錯誤が大変でした…。 ルーティング変更 IPsec 接続に成功したら、次はルーティングを変更して Cato 側にトラフィックが流れていくようにします。 デフォルトルートを IPsec のインターフェースに向けつつ、Linux サーバがある LAN やリンクローカルのネットワーク宛のトラフィックは Cato 側に流れないようにしました。 $ sudo ip route add 192.168.200.0/24 via 192.168.200.129 dev eth0 # LAN $ sudo ip route add 169.254.0.0/16 via 192.168.200.129 dev eth0 # リンクローカル $ sudo ip route add default dev ipsec1 $ ip route default dev ipsec1 scope link default via 192.168.200.129 dev eth0 proto dhcp src 192.168.200.132 metric 100 169.254.0.0/16 via 192.168.200.129 dev eth0 192.168.200.0/24 via 192.168.200.129 dev eth0 192.168.200.128/28 dev eth0 proto kernel scope link src 192.168.200.132 metric 100 これでOKと言いたいところですが、これではまだ Cato 経由でのインターネットとの通信が期待通り動作しませんでした。また、この状態では Cato PoP 側からの IPsec 接続の生存確認も失敗するため、すぐに接続が切れて再接続が必要となってしまいます。 rp_filter 変更 前項のルーティング変更後、インターネット上のサーバ (Google Public DNS) に対して ping を打っても成功せず、tcpdump でパケットキャプチャを眺めてみると次の結果となりました。 17:22:25.383815 ipsec1 Out IP 192.168.200.132 > 8.8.8.8: ICMP echo request, id 1, seq 1, length 64 17:22:25.383858 eth0 Out IP 192.168.200.132.4500 > 150.195.218.109.4500: UDP-encap: ESP(spi=0x42a73e98,seq=0x2), length 120 17:22:25.388051 eth0 In IP 150.195.218.109.4500 > 192.168.200.132.4500: UDP-encap: ESP(spi=0x32b41687,seq=0x2), length 120 17:22:26.442569 ipsec1 Out IP 192.168.200.132 > 8.8.8.8: ICMP echo request, id 1, seq 2, length 64 17:22:26.442606 eth0 Out IP 192.168.200.132.4500 > 150.195.218.109.4500: UDP-encap: ESP(spi=0x42a73e98,seq=0x3), length 120 17:22:26.445991 eth0 In IP 150.195.218.109.4500 > 192.168.200.132.4500: UDP-encap: ESP(spi=0x32b41687,seq=0x3), length 120 ICMP パケットは ipsec1 インターフェースに向けて送信 (1,4行目) され、eth0 インターフェースで IPsec のパケット (UDP でカプセル化された ESP パケット) が Cato PoP に向けて送信 (2,5行目) されています。また、おそらく ping の戻りの ICMP パケットをカプセル化した IPsec のパケットを Cato PoP から受信 (3,6行目) しているようですが、ICMP echo reply は受信できていません。 eth0 インターフェースで IPsec パケットを受信しているのに、ipsec1 インターフェースからカプセル化を解除したパケットが出てきていないということは、受信した IPsec パケットが Linux カーネルで破棄され、Libreswan のプロセスに渡っていないということです。思い当たる心当たりとしては rp_filter ですね。 rp_filter - INTEGER 0 - No source validation. 1 - Strict mode as defined in RFC3704 Strict Reverse Path Each incoming packet is tested against the FIB and if the interface is not the best reverse path the packet check will fail. By default failed packets are discarded. 2 - Loose mode as defined in RFC3704 Loose Reverse Path Each incoming packet's source address is also tested against the FIB and if the source address is not reachable via any interface the packet check will fail. Current recommended practice in RFC3704 is to enable strict mode to prevent IP spoofing from DDos attacks. If using asymmetric routing or other complicated routing, then loose mode is recommended. The max value from conf/{all,interface}/rp_filter is used when doing source validation on the {interface}. Default value is 0. Note that some distributions enable it in startup scripts. ※ https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt より引用 端的に説明すると、rp_filter というカーネルパラメータが1の場合、FIB (どのIPアドレス宛のパケットをどのインターフェースから送信するかを示すテーブル) によって選択されるインターフェースと、パケットを受信したインターフェースが異なると、パケットを破棄するというものです。 実際、eth0 インターフェースの rp_filter の値は1でした。 $ sudo sysctl -a | grep "\.rp_filter" net.ipv4.conf.all.rp_filter = 0 net.ipv4.conf.default.rp_filter = 1 net.ipv4.conf.eth0.rp_filter = 1 net.ipv4.conf.ip_vti0.rp_filter = 1 net.ipv4.conf.ipsec1.rp_filter = 1 net.ipv4.conf.lo.rp_filter = 1 FIB を参照すると Cato PoP (150.195.218.109) から来るパケットはデフォルト経路により ipsec1 インターフェースで受信されるべきですが、eth0 インターフェースで受信しているため破棄されているのですね。 このような場合、Cato PoP のIPアドレス宛の通信を eth0 インターフェースから送信する経路をデフォルトのルーティングテーブルに追加 ( “sudo ip route add 150.195.218.109/32 via 192.168.200.129 dev eth0” ) すれば解決できますが、Cato PoP のIPアドレスを明確に意識しなければならなくなるため、この方法は避けたいです。 そこで、rp_filter を緩めることにしました。 $ sudo sysctl net.ipv4.conf.eth0.rp_filter=2 これで ping も正常に通るようになりました。 $ ping 8.8.8.8 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=122 time=3.63 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=122 time=3.55 ms 64 bytes from 8.8.8.8: icmp_seq=3 ttl=122 time=3.41 ms ^C --- 8.8.8.8 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2004ms rtt min/avg/max/mdev = 3.411/3.531/3.634/0.091 ms 17:23:07.224050 ipsec1 Out IP 192.168.200.132 > 8.8.8.8: ICMP echo request, id 2, seq 1, length 64 17:23:07.224087 eth0 Out IP 192.168.200.132.4500 > 150.195.218.109.4500: UDP-encap: ESP(spi=0x42a73e98,seq=0x5), length 120 17:23:07.227627 eth0 In IP 150.195.218.109.4500 > 192.168.200.132.4500: UDP-encap: ESP(spi=0x32b41687,seq=0x5), length 120 17:23:07.227664 ipsec1 In IP 8.8.8.8 > 192.168.200.132: ICMP echo reply, id 2, seq 1, length 64 17:23:08.225956 ipsec1 Out IP 192.168.200.132 > 8.8.8.8: ICMP echo request, id 2, seq 2, length 64 17:23:08.225994 eth0 Out IP 192.168.200.132.4500 > 150.195.218.109.4500: UDP-encap: ESP(spi=0x42a73e98,seq=0x6), length 120 17:23:08.229374 eth0 In IP 150.195.218.109.4500 > 192.168.200.132.4500: UDP-encap: ESP(spi=0x32b41687,seq=0x6), length 120 17:23:08.229454 ipsec1 In IP 8.8.8.8 > 192.168.200.132: ICMP echo reply, id 2, seq 2, length 64 17:23:09.227701 ipsec1 Out IP 192.168.200.132 > 8.8.8.8: ICMP echo request, id 2, seq 3, length 64 17:23:09.227736 eth0 Out IP 192.168.200.132.4500 > 150.195.218.109.4500: UDP-encap: ESP(spi=0x42a73e98,seq=0x7), length 120 17:23:09.231011 eth0 In IP 150.195.218.109.4500 > 192.168.200.132.4500: UDP-encap: ESP(spi=0x32b41687,seq=0x7), length 120 17:23:09.231065 ipsec1 In IP 8.8.8.8 > 192.168.200.132: ICMP echo reply, id 2, seq 3, length 64 良い感じです。 MTU 変更 IPsec 接続による作られた ipsec1 インターフェースの MTU は 1500 となっていました。 IPsec 接続時のログを見ると “AES_GCM_16_256” アルゴリズムで接続されており、今回のインターネット回線の MTU は 1500 ですので、IPsec のインナーパケットの最大長は 1438 バイトのはずです。 ※計算式 : rounddown((1500 – 20 – 8 – 8 – 8 – 16) / 4, 0) * 4 – 2 回線MTU : 1500 IPヘッダ長 : 20 (IPv4) UDPヘッダ長 : 8 (NATトラバーサル用) ESPヘッダ長 : 8 ESP初期化ベクトル : 8 (AES-GCM) ESP認証データ : 16 (AES-GCM) ESPトレーラ : 2 ブロックサイズ : 4 実際、1438 バイトのパケット (ペイロードが 1410 バイトの ping) は送信でき、1439 バイトのパケットは送信できませんでした。 17:26:54.130174 ipsec1 Out IP 192.168.200.132 > XXX.XXX.XXX.XXX: ICMP echo request, id 13, seq 1, length 1418 17:26:54.130210 eth0 Out IP 192.168.200.132.4500 > 150.195.218.109.4500: UDP-encap: ESP(spi=0x57179fd4,seq=0x1f), length 1472 17:26:54.138973 eth0 In IP 150.195.218.109.4500 > 192.168.200.132.4500: UDP-encap: ESP(spi=0xb3a32ad4,seq=0x22), length 1416 17:26:54.138973 eth0 In IP 150.195.218.109.4500 > 192.168.200.132.4500: UDP-encap: ESP(spi=0xb3a32ad4,seq=0x23), length 112 17:26:54.139047 ipsec1 In IP XXX.XXX.XXX.XXX > 192.168.200.132: ICMP echo reply, id 13, seq 1, length 1360 17:26:54.139047 ipsec1 In IP XXX.XXX.XXX.XXX > 192.168.200.132: ip-proto-1 17:26:58.465889 ipsec1 Out IP 192.168.200.132 > XXX.XXX.XXX.XXX: ICMP echo request, id 14, seq 1, length 1419 17:26:58.465922 eth0 Out IP 192.168.200.132.4500 > 150.195.218.109.4500: UDP-encap: ESP(spi=0x57179fd4,seq=0x21), length 1476 17:26:58.466157 eth0 In IP 192.168.200.1 > 192.168.200.132: ICMP 150.195.218.109 unreachable - need to frag (mtu 1500), length 36 そのため、ipsec1 インターフェースの MTU を 1438 に変更しておきましょう。 $ sudo ip link set dev ipsec1 mtu 1438 なお、1438 バイトのパケットは送信できているものの、戻りの 1438 バイトのパケットはIPフラグメント化されて受信しています。これは過去の検証の通り、Cato PoP 経由でのインターネットとの通信の MTU が 1383 であることと一致していました。 Cato Client を用いた通信における MTU の調査 Cato クラウドの PoP 経由で通信する場合の MTU の値を調査・検証してみました。 blog.usize-tech.com 2023.11.30 接続確認 CMA 上での接続確認 CMA 上では、Site 画面で今回の IPsec 接続用の Site の状態を確認できますが、無事に Connected となっており、Tokyo PoP に接続されていました。新しい Tokyo_DC2 や Tokyo_DC3 PoP に接続されるとは限らないようです。 また、Site の IPsec の設定画面で「Connection Status」ボタンを押せば IPsec 接続の状態を確認できます。 この内容に特に見どころはありませんが、IPsec 接続で利用されている暗号スイートぐらいは確認しておくと良いですね。 さらに、Events 画面を見てみると、IPsec 接続が成功したときのログや、接続確認時の ICMP (ping) のログもちゃんとイベントとして記録されていました。(接続確認より前に NTP の通信も行われていました。) CMA で見れる内容としては問題なさそうです。 Linux サーバ側の接続確認 Linux サーバからインターネットに通信してみて、ちゃんと Cato PoP を通っているのか確認してみます。 今回は「確認くん」の Web サイトにアクセスし、インターネット側から見えるグローバルIPアドレスを確認してみました。 $ curl https://www.ugtop.com/spill.shtml <!DOCTYPE html> <html lang="ja"> (中略) <th>あなたのIPアドレス(IPv4)</th> <td><font size=+2 color=blue>150.195.218.108</font></td> <tr> <th>ゲートウェイの名前</th> <td><font size=+1 color=red>(none)</font></td><tr> (後略) 自マシンのIPアドレスは 150.195.218.108 として見えているようであり、これは Cato の東京の PoP のものですので、問題なさそうですね。 その後 CMA で Events を見てみると、もちろん上記のアクセスも記録されていました。 まとめ Linux サーバから Cato クラウドに問題なく IPsec 接続を行えることが確認できました。IPsec は標準化されたプロトコルですし、流れるパケットも手軽に見れるので良い感じです。 vSocket を用意したりクラウドの IPsec サービスを利用したりしなくても、軽いノリで Cato クラウドに接続できるのも良い点です。Cato クラウドを Pooled ライセンスで利用しているのであれば、今回のように気軽に Site を立てて利用するといったこともできますので、ライセンスは余剰分を確保しておきたいですね。 ただし、今回はあくまでも IPsec 接続できるかを検証したものであり、本番環境用途で利用するためには次のようなことも追加で検証・構築する必要があります。 同じネットワーク上の他のマシンから今回の Linux サーバを介して Cato クラウドに接続する IPsec 接続時に手動で行っている内容 (ルーティングや MTU の変更) を自動で行う Linux サーバ側からも IPsec 接続の生存確認を行い、生存が確認できなければ自動で再接続する 高い可用性が必要なら、IPsec 接続を冗長化 (Secondary 接続や Linux サーバを複数用意) する この中でも4つ目は検証も構築も大変なので、本番環境用途を考えるなら間違いなく vSocket やパブリックラウドが提供する IPsec サービスなどを利用することを推奨します。vSocket や IPsec サービスなどを利用できないような環境で Cato クラウドに接続する手段の1つとして本記事を参考にしていただければと思います。
本記事は 夏休みクラウド自由研究 8/8付の記事です 。 AWS/Azure等のパブリッククラウドをCatoクラウドへ接続する方法には、以下の3つがありますが、このうち最も手軽で多く利用されている方法がvSocketです。   接続方法 対象環境 主な利用シーン 1 vSocket AWS/Azure/VMware ESXi 通常の場合 2 Cloud Interconnect (旧名称:Cross Connect) AWS/Azure/GCP/Oracle Cloud 高スループット・低遅延な通信を必要とする場合 3 IPSec すべての環境 1および2が利用できない・用途にマッチしない場合 vSocketは、VPC/VNET内に仮想マシンを構築しSocketとして動作させるもので、物理Socketと同等の機能が利用できます。AWS/Azure環境を物理的な拠点と同等にCatoクラウドへ接続でき、とても便利です。 実際のご利用環境では、複数のAWS VPC や Azure VNetが存在することがほとんどかと思います。このような場合のCatoクラウドへの接続構成について、よくご質問をいただくため、本記事にて構成例をご紹介します。 AWS 複数VPCを接続する際の構成 AWSで複数VPCを接続する方法としては、以下2つの構成パターンがあります。 パターン1 VPCごとにvSocketを構築する 各VPCにvSocketを作成し、それぞれCatoクラウドに接続する構成です。 メリット 各VPCが完全に独立してCatoクラウドへ接続します。Catoクラウド上でも、それぞれのVPCが独立したSiteとして表示されますので、通信量・通信内容の確認や、管理がSiteごと(=VPCごと)に可能です。 デメリット 接続するVPCごとに、Catoクラウドライセンスが必要です。図の例ですと、3つのVPCに対し合計3つのSiteライセンス契約が必要です。また、VPCごとにvSocketの構築が必要です。 パターン2 複数VPCをTransit Gatewayで接続し、1つのVPCからCatoへ接続する Transit Gatewayを構築してVPCを相互接続し、1つのVPCのみCatoクラウドへ接続する構成です。 なお、VPC同士をVPC Peeringで接続する構成は利用できません。AWSのVPC Peeringは、接続先のVPCより先のNWには通信できないという制約(2hop制限)があるためです。 メリット Catoクラウドのライセンス契約は1Site分のみ必要となります。またvSocketの構築も1セットのみです。 デメリット Catoクラウドへのすべての通信が、Transit Gateway および vSocketのVPCを経由することとなります。各VPCのセキュリティ要件上問題ないか、ご検討が必要な場合があるかもしれません。 また、この構成では、Catoクラウド上ではすべてのVPCがあわせて1つのSiteとして扱われますので、VPCごとの通信量を確認するなどができません。Siteご契約帯域も、すべてのVPCを合算した通信量にてご契約頂く必要がございます。 もしvSocketや、そのVPC内に障害が発生した場合、すべてのVPCでCatoクラウドへの通信が不可となります。 パターン2の構成の詳細 Transit Gatewayを使用する場合、各SubnetとTransit Gatewayのルートテーブルで、もれなくルートの設定が必要です。設定のポイントを上記の図にまとめましたので、ご参照ください。 構築後、通信が通らない場合、よくある原因に以下の2つがあります。うまく行かない場合は見直してみてください。 上記図内の①~③のルートテーブルに、ルートが足りていない。※特にCatoモバイルユーザのルートを設定し忘れがちです 通信先のAWSリソース(EC2等)で、セキュリティグループやOSのFirewallが設定されていて、CatoのSiteやモバイルユーザのIPアドレスレンジからの通信が許可されていない。 Transit Gatewayを使用した構成については、Cato Networksのナレッジベースにも解説がありますので、合わせてご参照ください。 How to Implement Cato vSocket in AWS Multiple VPCs Environment | Cato Knowledge Base Azure 複数VNetを接続する際の構成 Azureで複数のVNetをCatoへ接続したい場合、同様に2つのパターンがあります。 パターン1 VNetごとにvSocketを構築する AWSの例と同様です。VNetごとに個別に管理できますが、SiteライセンスがVNetの数だけ必要です。 パターン2 複数VNetをVNet Peeringで接続し、1つのVNetからCatoへ接続する Azureの場合は、VNet PeeringでVNet間を接続します。 メリット・デメリットはAWSと同様です。 パターン2の詳細 複数VNetを接続する場合、Peeringを作成の上で、各Subnetのルートテーブルでルートの設定が必要です。設定のポイントを上記の図にまとめましたので、ご参照ください。 構築後、通信が通らない場合、よくある原因はAWSと同様です。サーバが所属するルートテーブルや、セキュリティグループを確認します。また、Peeringのオプション「Allow forwarded traffic」が有効になっているかも合わせて確認します。 Peeringを使用した構成については、Cato Networksのナレッジベースにも解説がありますので、合わせてご参照ください。 How to Use a vSocket in Azure Multiple VNets Environment | Cato Knowledge Base まとめ AWS、Azureともに、複数環境を個別にCatoクラウドへ接続する方法と、まとめて接続する方法があります。メリット・デメリットを確認の上、接続方法をご選択ください。 もちろん、環境分離したいVPC/VNetは個別に接続し、その他はまとめて接続するといった構成も可能です。 SCSKでは、Catoクラウドとパブリッククラウドの両方に精通したエンジニアが多数在籍しており、最適な構成のご提案が可能です。お悩みの点などありましたら、ぜひご相談ください。
Prisma Cloudは、クラウド環境のセキュリティとコンプライアンスを一元管理するツールで、リアルタイムの脅威検出やリソースのチェックが可能です。 今回は、クラウドアカウントをアカウントグループに追加し、重要度の高いポリシー違反を通知するためのアラートルールを設定する手順を紹介します。また、他の運用例についても簡単に触れます。 用語の説明 設定手順の説明の前に、アカウントグループとアラートルールの簡単な説明をします。 アカウントグループとは アカウントグループ は、複数のクラウドアカウントをまとめて管理するための論理的なグループです。これにより、複数の部門や事業単位、開発や本番などの環境単位でのアカウント管理を行うことができます。 アラートルールとは? アラートルール は、特定の条件が満たされた場合に通知を送信するための設定です。これにより、異常な活動や特定のポリシーやコンプライアンス違反を監視することができます。条件の設定では、特定のポリシーセットを選択する方法のほか、リソースタグによって識別された特定のクラウドリソースにルールを絞り込むことも可能です。 アカウントグループとアラートルールの関係 クラウドアカウントとアカウントグループ、アラートルールの関係は以下のようになります。 ・同じクラウドアカウントを複数のアカウントグループに含めることができます。 ・複数のアラートルールをアカウントグループに適用できます。 ・複数のアカウントグループに同じアラートルールを適用できます。 PrismaCloudでの設定方法 アラートルールをアカウントグループに適用することで、選択したアカウントグループで発生した特定のポリシールール違反の通知だけを受け取るような運用をすることができます。 以下に、例としてクラウドアカウントをアカウントグループに追加し、重要度の高いポリシー違反を通知するためのアラートルールを設定し、作成したアカウントグループに適用する手順を紹介します。 アカウントグループの作成とクラウドアカウントのアタッチ 1). Prisma Cloudアカウントにログインし、「Settings」を押下します。 2). 左ペインの「Account Groups」を選び、「新しいアカウントグループを作成」を押下します。 3). 以下項目を入力し、「Save」を押下します。 Name:アカウントグループ名 Cloud Account:アタッチするクラウドアカウント 4). 一覧にアカウントグループが追加されたことを確認したら完了です。 アラートルールの作成とアカウントグループへの適用 1). Alertsページの「View Alert Rules」を押下します。 2). 「Add Alert Rule」を押下します。 3). 以下項目を入力し、「Next」を押下します。 Name:アラートルール名 AUTOMATIONS (OPTIONAL):今回はメール通知させるので、「Alert Notifications」を選択します 4). 以下項目を入力し、「Next」を押下します。 Select the account ~ this alert rule:「Account Groups」を選択します Account Groups:先ほど作成したアカウントグループを選択します 5). 監視するポリシーを選択します。今回は重要度がHighまたはCriticalのポリシーをすべて選択するためにフィルター機能を使います。 「Add filter」でPolicy Severityを選択します。 6). Policy Severity横の「Select」を押下し、Highを選択します、同様にCriticalを選択します。 7). 「Include all ~ filter criteria」にチェックして、フィルター条件に合致するすべてのポリシーを選択し、「Next」を押下します。 8).  以下項目を入力し、「Next」を押下します。 Emails:通知先のメールアドス Enable:チェックします 9). アラートルール名やアカウントグループ名、フィルターしたポリシー、「Configured Channels」にメールのマークが表示されているかなどの設定値を確認し、「Save」を押下します。 10). アラートルールの作成が成功したメッセージを確認したら、PrismaCloudの設定は完了となります。 PrismaClodでアラートの確認をしてみる 実際に確認してみましょう。 1). アラートルールの設定後、該当ポリシーの違反が検知されると設定した連絡先に以下のようなメッセージが送信されます。 検知アラート数や対応状況、ポリシー名やポリシー違反したリソースなどがこのメッセージからわかりますが、赤枠の検知数を押下することでPrisma Cloud に飛び、詳細を確認できます。 2). このようにPrisma Cloud コンソールのAlertsページに遷移し、該当アラートが表示されますので、Alert IDを押下することでアラートの概要や推奨される対応などを参照できます。 他の運用例の紹介 例1: 環境ごとのアカウントグループとアラートルール 開発、テスト、本番環境に応じたアカウントグループを作成し、それぞれに適したアラートルールを設定します。 開発環境 : 緩やかなポリシー設定。 本番環境 : 厳格なポリシー設定。 例2: 地域ごとのセキュリティ管理 異なる地域のクラウドアカウントをグループ分けし、地域の規制に応じたセキュリティポリシーとアラートルールを適用します。 EUリージョン : GDPRに準拠したアラートルールを設定。 まとめ 今回は、Prisma Cloudにおいてアカウントグループとアラートルールを使用して、セキュリティ監視を強化する基本的な設定方法を紹介しました。これにより、効率的かつ一貫したセキュリティ運用が可能になります。 この記事でPrisma Cloudの導入イメージや使用感などが少しでも伝われば嬉しいです。 Prisma Cloudにはアラートの可視化など他にもクラウド環境設定のセキュリティチェックに便利な機能がありますので、他の記事でまたご紹介できればと思っています。 また、当社では、複数クラウド環境の設定状況を自動でチェックし、設定ミスやコンプライアンス違反、異常行動などのリスクを診断するCSPMソリューションを販売しております。ご興味のある方はお気軽にお問い合わせください。リンクはこちら↓ マルチクラウド設定診断サービス with CSPM| SCSK株式会社 マルチクラウド環境のセキュリティ設定リスクを手軽に確認可能なスポット診断サービスです。独自の診断レポートが、運用上の設定ミスや設計不備、クラウド環境の仕様変更などで発生し得る問題を可視化し、セキュリティインシデントの早期発見に役立ちます。 www.scsk.jp
こんにちは。SCSKの山口です。 今回は、BigQueryで ウィンドウ関数(分析関数) を使ってデータを集約してみたいと思います。 テーブル全体ではなく、 特定の実行範囲(パーティション)での処理 が実行できる便利な機能です。ぜひご覧ください。   ウィンドウ関数とは(イメージ) ウィンドウ関数とは、一言で言うと「行のグループ単位で計算を行い、 行ごとに一つの結果を返してくれる 」ものです。 似た言葉で、「集約関数」がありますが、ウィンドウ関数の有無で違う挙動を示します。 おそらくこの説明では???な方が多いと思うので、集約関数を使用する際、ウィンドウ関数がある場合とない場合に分けて図で説明します。   以下、 テスト結果のクラスごとの平均点数を算出する例 で説明します。 集約関数のみ 集約関数(avg)のみを使用した場合は上図のようになります。 テーブル全体に対して、「クラス」カラムでGroup byし、「クラス」ごとに平均点を算出して結果を返します。 上図を見てわかる通り、「グループ(クラス)ごとの出力」となり、「氏名」の情報は欠落します。 ウィンドウ関数+集約関数 ウィンドウ関数と集約関数を組み合わせた場合は上図のようになります。 集約関数のみの場合と異なり、 行ごとの出力 となっています。 また、 元テーブルの情報を欠落させることなく出力 することも可能です。 実践:ウィンドウ関数を使った集計 ここから実際にウィンドウ関数を使用してデータを分析してみます。 利用データ 今回は、下記情報を持つテーブルデータを使用してウィンドウ関数を使ってみます。 ユーザID ユーザ名 アクション タイムスタンプ やりたいこと 今回は上記テーブルから、 各ユーザが実行した最終アクション を、 元テーブル情報(カラム)を維持したまま 抽出します。 集約関数を使用する場合と、使用しない場合の2パターンで抽出してみます。 せっかくなので 「Geminiを使用してSQLを生成」 してみます。 下記の鉛筆のようなマークをクリックし、実現したい内容を書くとSQLを生成してくれます。 Gemini in BigQuery の Gemini の概要  |  Gemini for Google Cloud Gemini in BigQuery で利用できる機能の概要。 cloud.google.com ①集約関数のみ Geminiが生成したSQLは下記です。 -- 分析関数を使わずに、user_action_allテーブルから、各userIDの最新のデータを全カラムSELECT SELECT user_action_all.* FROM `evocative-entry-277709.yamaguchi_test.user_action_all` AS user_action_all INNER JOIN ( SELECT   userID,   MAX(timestamp) AS max_timestamp FROM   `evocative-entry-277709.yamaguchi_test.user_action_all` GROUP BY   1 ) AS latest_user_action ON user_action_all.userID = latest_user_action.userID   AND user_action_all.timestamp = latest_user_action.max_timestamp; 下記2データをINNER JOINすることで実現しています。 テーブル全量 userIDでGroup byし、MAX関数でtimestampを集約したデータ 上記SQLでも、抽出したいデータを得ることはできました。(ちょっとメンドクサイSQLですが。) ②ウィンドウ関数+集約関数 Geminiが生成したSQLは下記です。 -- 分析関数を使って、user_action_allテーブルから、各userIDの最新のデータを全カラムSELECT SELECT   * FROM   (     SELECT         *,         ROW_NUMBER() OVER(PARTITION BY userID ORDER BY timestamp DESC) AS rn       FROM         `evocative-entry-277709.yamaguchi_test.user_action_all`   ) AS t   WHERE t.rn = 1; 先ほどよりスッキリしたSQLですが、 実はさらにスッキリさせることができます(詳細は後述) 。 SELECT *, ROW_NUMBER() OVER(PARTITION BY userID ORDER BY timestamp DESC) AS rn FROM `evocative-entry-277709.yamaguchi_test.user_action_all` QUALIFY   rn=1 実行するとこちらも抽出したいデータを得ることができました。 よく見ると、SQLに見慣れない一文があります。 ROW_NUMBER() OVER(PARTITION BY userID ORDER BY timestamp DESC) AS rn この部分です。 ここがウィンドウ関数の正体 です。 ここからは章を分けて、ウィンドウ関数について詳細を見ていきます。   ウィンドウ関数とは(詳細) 先ほどはウィンドウ関数について、図を使ってイメージを把握していただきましたが、ここからもう少し詳しく見ていきます。 ウィンドウ関数の「ウィンドウ」は、 結果セットの中の特定の一部分 のことを指します。 下図のような、 「窓越しに風景の一部を見る」 絵を想像していただけるとわかりやすいかと思います。 またまたイメージの話になってしまいましたが、本題に移ります。 ウィンドウ関数を使用するには、 「OVER句」 が必要になります。このOVER句内の 3要素 によって、ウィンドウを細かくコントロールすることができます。 パーティション:データを分割 オーダー:パーティション内の結果に順序付け フレーム:現在の行に対して相対的に移動するスライディングウィンドウフレームを指定可能(※今回は省略) 今回、実践で使用したデータに当てはめてみます。 ROW_NUMBER() OVER(PARTITION BY userID ORDER BY timestamp DESC) AS rn PARTITION BY userID:userIDごとにデータを分割 ORDER BY timestamp DESC:userIDごとのデータをtimestampで降順にソート ここまでで、下記のデータが取得されます。 上記結果を見ると、一番右の「rn」列でタイムスタンプをもとにランク付けがされていることがわかります。 今回のケースでは、ウィンドウ関数で取得したそれぞれのユーザのデータから、ランク(rn)が「1」のものを取得することで各ユーザの最新のデータを取得することができます。 ウィンドウ関数の結果を絞り込みは、 QUALIFY を使用して実現することができます。 QUALIFY   rn=1   先ほど実践にて「 実はさらにスッキリさせることができます(詳細は後述) 」と、せっかくGeminiが生成したSQLに少しケチをつけてしまいましたが、ウィンドウ関数の結果を絞り込む際は QUALIFY を使用することをオススメします。 QUALIFYを使用することで、今回のケースのように 「サブクエリが削減できる」 等のメリットがあります。 WHEREで絞り込み QUALIFYで絞り込み SELECT     *   FROM     (       SELECT           *,           ROW_NUMBER() OVER(PARTITION BY userID ORDER BY timestamp DESC) AS rn         FROM           `evocative-entry-277709.yamaguchi_test.user_action_all`     ) AS t   WHERE t.rn = 1; SELECT   *,   ROW_NUMBER() OVER(PARTITION BY userID ORDER BY timestamp DESC) AS rn FROM   `evocative-entry-277709.yamaguchi_test.user_action_all` QUALIFY   rn=1   レガシー SQL 関数と演算子  |  BigQuery  |  Google Cloud cloud.google.com Query syntax  |  BigQuery  |  Google Cloud cloud.google.com Window function calls  |  BigQuery  |  Google Cloud cloud.google.com   まとめ 今回は、ウィンドウ関数を使ってデータを分析してみました。 ウィンドウ関数を使用することで少ない文量のSQLで、元テーブルのデータを欠落させることなくデータが取得できました。 調べていく中で「スライディングウィンドウ」が気になったので、機会があれば詳しく調べてみたいと思います。 最後に、 やっぱりGeminiって便利ですね、、、
本記事は 夏休みクラウド自由研究 8/7付の記事です 。 こんにちは!SCSKの中山です。   少し前のアップデートにて、Cato Clientのセッション強制切断(Revoke Session)機能が実装されました。 こちらの機能は名前の通り、Cato Clientで接続しているSDPユーザをCMA上から切断することができる機能になります。 今回はこの機能を使い方や検証した内容を書きつつ、実際に運用における利用シーンを考えてみようと思います。 本記事は2024/7/31時点で作成した記事になります。 機能アップデート等で仕様や画面が変わる可能性がございますので、予めご了承ください。   Revoke Session機能について まず「Revoke Session」機能について、最初にお伝えしておくと、本機能のメインはあくまで 再認証を強制する機能 になります。 こちらのCatoのナレッジにも記載がありますが、「Revoke Session」はクライアント側に再認証を求め、ユーザ側で10分以内に認証しない場合に接続を切断する仕様になっております。 そのため、”切断”という観点では対象のユーザをCatoから切断するために10分程度時間がかかるという仕様になってます。 Cato KnowledgeBase(Revoking a Remote User’s Session) 実施手順 ①CMAにより、「Access」>「Users」>「User Directory」より切断したいユーザを選択します。 ②右上の「Actions」>「Revoke sessions」をクリックすると確認画面が出てくるので、「Confirm」を押します。   画面上部に「Sessions revoke successfuly」とポップアップが出てきたら、セッションの切断が成功しております。   実際にセッション切断をやってみた まずは、セッション切断時にClient利用者側の画面・表示はどのようになるかを試してみました。 今回はWindows のCato Clientのセッション切断を実施しました。   ▼セッション切断後のCato Clientの画面 「Revoke Sessions」押下後、2,3分後にCato Clientでは上記のログイン画面が再度表示されておりました。 今回は検証にあたりClientの確認を続けていたので気づきましたが、何か作業中に切断された場合には、気づかないかもです。。   ログイン画面が表示された時点でCMAの「Topology」を確認すると「Revoke Session」を実施したユーザが表示されており、Eventsを見てもまだSDPユーザで接続されているログが残っておりました。 ▼Cato Client側がログアウト画面になった時のCMAの「Topology」画面   その後、「Topology」から表示が消え、セッションの切断が確認できたのは「Revoke Sessions」押下後、約10分後ぐらいでした。 ⇒Catoの仕様通りではありますが、個人的にはセッション切断というと即時で切断できる機能かと思ったので、ここら辺感覚と違う人も多いのでは?と思います。なので運用にあたっては注意が必要かもです。   ちなみに、Cato Clientではログアウト画面、「Topology」上には表示がある状態で再度接続を試してみました。   接続時間が継続していたため、Cato Clientでログイン画面が表示された状態は、あくまで再認証が求められている状態なだけでセッション自体は続いていることがClient側でも確認できました。   ユースケースを考えてみた まずは端末を紛失した場合ですかね。 こちらはCatoのナレッジの使用例にもあったケースでCato Clientのセッションが残ってしまっている状態で端末を紛失してしまった場合、その端末からは社内NWに入ることができてしまいます。 それをセッション切断を行うことで、正規の利用者以外はログインできないため第三者が社内NWに侵入することを防ぐことができ、情報漏洩のリスクを削減することができます。こちらは端末紛失時の運用に組み込めば、実運用でも使えそうです。 ナレッジの使用例だと「Stories Workbench」で大量アップロードしているユーザを特定し、そのユーザのセッションを切断するケースが紹介されておりました。正当な利用者であるか否かを選別できるのはメリットですが、業務で短期的に大量データをやり取りする場合と区別が難しいと思いますので、実運用に組み込む際には注意が必要かなと思います。 他にも何かを検知してセッションを切断するというケースがあるかと思ったのですが、現状の機能だと向いてない気がします。 あくまで再認証を求める機能で、検証した通りセッションが切断されるまでに約10分ほどかかっておりましたので、ウイルスやマルウェアを検知した時に運用側で対応するのでは対応が遅くなってしまうかと思います。 また、ユーザ制御の観点でセッションを切断する場面があるかもと考えましたが、現状では利用者本人であればセッションを切断しても再ログインできてしまうので、正当な利用者の行動を制限することは難しそうです。 上記の例にも書いた通り、Clientの正当な利用者か否かを選別したいという場面では、一応使えそうではあります。   まとめ 今回はCato Client接続のセッション切断機能について記事を書いてみました。 ユースケースでも運用と絡めて記載をしておりますが、セッション切断機能は実際の運用に関わる機能なので、使用にあたってはしっかりと運用ルールを決める必要があります。運用ルールを決めて使えばとても有用な機能になりますので、本機能のリリースと合わせて運用ルールも見直してみては如何でしょうか。
こんにちは。SCSKの江木です。 Google Cloud Next Tokyo ’24に参加してきたので、インベントの様子や感想を投稿します。 Google Cloud Next Tokyo ’24とは? Google Cloud Next Tokyo ’24は2024年8月1日・2日にパシフィコ横浜ノースで開催されたGoogle Cloudのカンファレンスイベントです。 本イベントは主に以下の内容で構成されています。 基調講演 セッション Innovators Hive Expo スポンサーブース 基調講演と各セッションではGoogle Cloudの最新情報や技術動向、国内外の企業での活用事例が紹介されます。Innovators Hiveではデベロッパーやエンジニア向けに、Google Cloudのデモ体験や認定資格のクイズチャレンジなどができます。ExpoではGoogle Cloudの最新サービス・ソリューションのデモを体験できます。スポンサーブースではGoogle Cloud パートナー企業によるソリューション展示やデモを体験することができます。(弊社も出展しておりました!!) 昨年同様、Google Cloudの最新情報を知れるだけでなく、パートナーや資格取得者同士の交流を深められるイベントになっております。 昨年のNext Tokyoについて知りたい方は以下を参照ください。 Google Cloud Next Tokyo '23に参加してみた Google Cloud Next Tokyo '23に参加したので、イベントの内容と感想を投稿します。 Google Cloud Next Tokyo '23は2023年11月15日・16日に東京ビッグサイトで開催されたGoogle Cloudのカンファレンスイベントです。 blog.usize-tech.com 2023.12.02 会場の様子および全体的な印象 基調講演開始の1時間ほど前の会場入り口の様子。空いているのかなと思いきや、建物内にはすでにたくさんの方がいらっしゃいました。 かなりの方が参加しており、大盛況でした!!   Google Cloud Next ’24の印象をまとめると、以下の通りです。 出展内容の7割ほどが生成AI絡み 昨年よりも生成AIの出展が増えている気がします… イベント参加者が昨年より多いように感じた 会場の広さが影響しているのかもしれません… グッズをもらいやすくなった 今年はスタンプラリーがあった(私が参加しようと思った頃には売り切れでした…) 参加レポート 今回はDay1基調講演を聞いた後、Innovators Hive、Expoを生成AI周りを中心に見学してきました。それぞれの内容を紹介してきます。 Day1基調講演 生成AIの活用事例紹介、AIの新サービスの発表が行われました。新サービスにはGeminiの新しいモデルやGemini for Google Cloud Service Level Agreement(SLA)などがありました。 基調講演の詳しい内容は以下のブログを参照ください。(弊社の出展についても掲載しているので、ぜひご覧ください!!) 【現地速報】Google Cloud Next ’24 Tokyo Keynoteまとめ。/スポンサーブースにも出展中!!!!!! Google Cloud Next '24 Tokyo「Day 1 開幕速報」として、Day 1 Keynoteまとめ、弊社SCSKの展示ブース、現地の最新情報を共有します。 blog.usize-tech.com 2024.08.01 Innovators Hive 体験型デモ Google Cloudのサービスを面白いデモを使って、遊び感覚で学べるエリアになります。体験型デモでは「Instant Web with Gemini」と「Beat Google at Load Balancing」を体験してきました。 Instant Web with Gemini Webサイトのインターフェースを自分で描き、描いたものを画像認識で読みこみ、HTMLなどのプログラムを出力するといったデモでした。 自分が描いたインターフェースをそこそこの精度でプログラムにしてくれました。 ※左が読み込んだWebサイトのインターフェース、右がHTMLのプログラム Beat Google at Load Balancing Load Balancingと負荷分散能力を競うというデモでした。デモ内容としては、迫りくるパケットを4つのボタンを押して、バケットを分散させるというものです。 惜しくも負けてしまいました… Quiz Challenge Google Cloudのクイズに挑戦できるエリアになります。ジャンルとしては、AI、データ、クラウドアーキテクチャ、アプリ開発、DevOps、セキュリティの6分野ありました。 私の所属がAI専門部隊ということで、AIの試験を受けてみました! すると、70点/ 100点! うーん…、微妙ですね…。 ですが、70点以上だったので、以下のアクリルスタンドをもらいました。 Vertex AIと書いてますね!かっこいい!! 認定者ラウンジ   Google Cloud認定資格を取得している人だけが入れる認定資格者ラウンジに行ってきました。 ラウンジに行くと、以下のボールペンをもらえました!また、エンジニア性格診断を受けると、可愛いバッチをもらうことができました! また、私はGoogle Cloud認定資格を全冠しているので、オリジナルのSWAGをもらうことが決まりました!(後日もらえるとのことなので、楽しみです!!) 全冠について知りたい方は以下のサイトをご参照ください。 Google Cloud 認定資格を全冠したので軌跡をまとめてみる Google Cloud認定資格を全冠しました。私が実際にどのように学習を進めてきたのか、具体的な勉強法や感想をお伝えしていきます。 blog.usize-tech.com 2024.06.11 Expo Google Cloudの最新技術に触れることができるブースになっています。今回は生成AIに関連が深い、「AI Innnovation」と「Google Workspace」の2つのエリアを見学してきました。 AI Innovation   AI Innovationという名前の通り、AIに関するデモを紹介していました。その中でも特に興味深いと感じたデモを2つ紹介します。 画像編集の新体験 Imagen 3.0× Flutter × Gemini Imagen3.0による画像編集能力とGeminiのマルチモーダル対応能力を利用したデモでした。具体的な内容としては、Imagen 3.0で画像を生成・編集し、その画像に対してGeminiでタイトルを生成するというものでした。ついにAIだけで画像を自由にカスタマイズできる時代が来ましたね! Geminiによる生成的推薦とRAG ある画像を検索すると、その画像に近い画像を推薦するといったデモでした。検索対象画像をエンベディング(ベクトル化)し、画像のデータベースに対して、ベクトル検索をかけることで実現しているそうです。ベクトル検索は文章にも画像にも使えるので、かなり便利だということを再認識しました!! Google Workspace   Google Workspaceについて紹介するエリアで、主にGeminiとのコラボレーションを紹介するといった内容でした。 見学してきたGemini機能の中でとても面白い機能があったので、1つ紹介します。 AIで動画制作をスマートに Geminiを使って、動画制作をする機能になります。この機能のどこがすごいのかといいますと、「 docxやpptxの資料から動画制作できる 」という点です。つまり、人間の思考・手を介さずに、プレゼン動画を作成できるということになります。(そうは言っても、もちろん人の思考・手による修正は必要です。) 現在は英語版のみ対応とのことですが、2024年末までに日本語対応するそうです。日本語化が楽しみですね!!! 感想 いかがだったでしょうか。Google Cloud Next Tokyoの現地の様子をお届けしました。 昨年に引き続き、Google Cloud Next Tokyoに参加してみて、「AIを試す時代から使う時代になった」と改めて感じました。また、本イベントの参加が生成AI活用について考えるヒントになったとも思っています。 今後もGoogle Cloudの最新情報を常にキャッチアップし、より深く学んでいきたいと考えています。 最後まで読んでいただき、ありがとうございました。
本記事は 夏休みクラウド自由研究 8/6付の記事です 。 こんにちは。SCSKの山口です。 最近、Google CloudのData Fusionでパイプラインを構築する機会が多くあり、その中でも「Wrangler」のプライグインを多く使用したので、その際に便利だった機能をご紹介します。 ※本ブログではData Fusionパイプラインの基本的な構築方法については言及していませんので、構築方法等については下記をご参照ください。 Cloud Data Fusion のドキュメント  |  Cloud Data Fusion Documentation  |  Google Cloud Google Cloud Platform でデータ パイプラインのビルドと管理を行うための、CDAP を基に構築されたフルマネージド サービス。 cloud.google.com Cloud Data Fusion 概要 まずData Fusionについて簡単にご説明します。 Data Fusionは、 データパイプラインを素早く構築、管理できる、クラウドネイティブのフルマネージドサービス です。 フルマネージドサービスなので、インフラの管理なしでパイプラインを構築することが可能です。 そして、何より マウスだけで視覚的にパイプラインを構築すること が可能なため、直感的な操作で、コードを意識することなくETLパイプラインをデプロイすることができる点が長所です。 Cloud Data Fusion | Google Cloud Cloud Data Fusion は、ETL および ELT のデータ パイプラインを効率的に構築して管理できる、フルマネージドでコードを意識させないデータ統合サービスです。 cloud.google.com 利用できるプライグイン プラグインとは、Data Fusionの機能を拡張するために使用できるカスタマイズ可能なモジュールのことです。 下記の種別のプラグインが用意されています。 ソース 変換 集計 シンク エラーコレクタ アラートパブリッシャー アクション かなり数があり、一つひとつ説明すると膨大な文量になるので詳細は下記ドキュメントをご覧ください。 Cloud Data Fusion のプラグイン リファレンス | Google Cloud お客様がデジタル トランスフォーメーションに乗り出したばかりでも、あるいはすでに進めている場合でも、Google Cloud は困難な課題の解決を支援します。 cloud.google.com   実践:WrangerプラグインでGCSのファイルを加工してBigQueryテーブルに取り込む 実現したいこと 今回実現したいことは以下の内容です。 下記「member」テーブルに、氏名と電話番号( ハイフンなし )のデータをロードします。 データのインポート元はGCSファイルに置いているCSVファイルです。 「member」テーブルの電話番号カラムには ハイフンなしの番号(最大長:11) をロードしたいですが、GCS内のCSVファイルにはハイフンが含まれています。 GCSからCSVファイルをBigQueryテーブルにインポートする際に、 「電話番号」カラムのハイフンを取り除きたい です。 これを、Data Fusion(Wrangerプラグイン)で実現します。 パイプライン構築 では早速パイプラインを構築していきます。 Source 今回はデータソースとして「GCS」プラグインを選択します。 左ペインから「GCS」を選択し、パイプライン構築画面に表示されたGCSアイコンから「Properties」を設定します。 今回は、インポート対象のCSVファイルを「BROWSE」より検索し、選択します。 Transform 今回は変換のプラグインとして「Wrangler」プラグインを使用します。(本ブログのメイン) propertyを開き「Directives」の「WRANGLE」ボタンを押下します。 今回のソースファイルを選択します。 インポートしたいファイルが表示されたら準備OKです。   さて、今回やりたいことをおさらいします。 やりたいことは、「telephone_number」カラム内のハイフンを取り除くことです。 この作業を実際にWRANGLE画面でやってみます。 対象カラム「telephone_number」の横のプルダウンを開き。「Find and replace」を選択します。 下記を入力します。 Find:-(ハイフン) Replace with:(何も入力しない) Replace Allを押下すると、ハイフンが削除されていることがわかります。 ここまでは何の驚きもないかもしれませんが、画面右ペインの「Transformation steps」をクリックすると、先ほどやった作業のレシピを記述してくれています。 さらに、右上の「Apply」ボタンを押下すると、 「Directives」の「Recipe」に先ほどの内容を記述してくれています。 つまり、 実際のデータを見ながら手で作業した内容を自動的にレシピに反映してくれている。 というわけです。 レシピに直接コードを入力することなく、やりたい変換処理を実際に行うだけで自動的に記述してくれる 大変便利な機能です。 Sink さあ仕上げです。データの最終的な出力先(sink)に「BigQuery」プラグインを選択し、宛先テーブルを指定します。 以上でパイプライン構築は完了です。 豆知識 プラグインをつなげていくと、矢印がジグザグになったりと画面が煩雑になることがあります。 このような場合は、プラグインを全選択し、画面右ペインの「Align」をクリックすると、プラグインを綺麗に整列してくれます。 以上、A型の筆者からの豆知識でした。 パイプライン デプロイ・起動 パイプラインをデプロイし、起動(Run)します。 パイプラインは無事成功しました。最後に出力先のテーブルを確認します。 電話番号のカラムにハイフンなしのデータが取り込まれています。大成功です。   まとめ 今回はData FusionでWranglerプラグインを活用してパイプラインを構築しました。 最初にも述べた通り、Data Fusionを使用するメリットの一つは、 視覚的・直感的な操作でパイプラインが構築できる点 です。 今回紹介したWranglerプラグインの使い方は、そのメリットを最大限活用したものだと思います。 また、Wranglerプラグインでは正規表現を使用した変換等も可能なので、柔軟なデータ加工が可能です。 皆さんも是非ご活用ください。
こんにちは!SCSKの江木です。 先日、Dialogflow CXのAgentからのテストケース作成を自動化していて、「あるフォルダにファイルがアップロードされたら起動するCloud Functionsを作りたい」とふと思いました。(テストケース作成自動化について知りたい方は以下のブログを参照ください。) Dialogflow CX Agentからの単体テストケース作成を自動化してみる 今回はテストケース作成の時間を削減すべく、グラフ理論を使って、単体テストケース作成を自動化する方法を実装してみました。このグラフ理論の考え方は他にも使えると思うので、ぜひご覧ください。 blog.usize-tech.com 2024.08.02 そこで今回はバケットレベルで指定するCloud Storageトリガーをどうにかしてフォルダレベルで指定できないか調べてみました。 Cloud FunctionsとCloud Storage まずはCloud FunctionsとCloud Storageについて簡単に紹介します。 Cloud Functionsとは? Cloud Functionsは、サーバーレスコンピューティングプラットフォームであり、コードを記述してデプロイすることで、イベントに応じて自動的に実行される関数を作成することができます。サーバーの準備や管理を行う必要がなく、コードを記述してデプロイするだけで、スケーラブルかつ高可用性のインフラストラクチャ上でコードを実行することができます。 バージョンは第1世代と第2世代があります。第2世代はCloud RunとEventarcに構築されており、処理速度の向上や多くのイベントへの対応を図っています。(第2世代のCloud Functionsを作成すると、Cloud Runのリソースも作成されます。) 今回は性能がよい第2世代のCloud Functionsを扱います。 より詳しい内容は公式ドキュメントを参照ください。 Cloud Functions の概要  |  Cloud Functions Documentation  |  Google Cloud cloud.google.com Cloud Storageとは? Cloud Storageはオブジェクトストレージサービスで、容量無制限で非構造化データを安全に保存し、世界中どこからでも高速アクセスできるサービスです。データのアーカイブ、バックアップ、コンテンツ配信、ビッグデータ分析、機械学習など、幅広いユースケースに対応できます。また、従量課金制でコストを抑え、ニーズに合わせて柔軟に拡張できます。 より詳しい内容は公式ドキュメントを参照ください。 Cloud Storage のプロダクト概要  |  Google Cloud cloud.google.com Cloud Functions(第2世代)のCloud Storageトリガーとは? Cloud Functionsのトリガーとは? Cloud Functionsではトリガーを指定することで、イベントに応じて自動実行できるようになります。 このトリガーにはどのような種類があるのか、公式ドキュメントでは以下のように記述されています。 トリガーは次の 2 つのカテゴリに分類されます。 HTTP トリガー 。HTTP(S) リクエストに応答し、 HTTP 関数 に対応します。 イベント トリガー 。Google Cloud プロジェクト内のイベントに応答し、 イベント ドリブン関数 に対応します。 Cloud Functions(第 2 世代)では、次のタイプのトリガーがサポートされています。 HTTP トリガー イベント トリガー: Pub/Sub トリガー Cloud Storage トリガー Firestore トリガー 汎用の Eventarc トリガー Eventarc でサポートされているすべてのイベントタイプをサポート(Cloud Audit Logs を介した 90 以上のイベントソースを含む) 様々なトリガーがありますね!今回はこの中でもCloud Storageトリガーに着目します。 Cloud Storageトリガーとは? 公式ドキュメントによると、Cloud Functions(第2世代)のCloud Storageトリガーは以下のイベントタイプがサポートされています。 イベント イベントタイプ 説明 オブジェクトのファイナライズ google.cloud.storage.object.v1.finalized (Eventarc 経由) 新しいオブジェクトが作成されるか、既存のオブジェクトが上書きされ、そのオブジェクトの新しい世代が作成されると送信されます。 オブジェクトの削除 google.cloud.storage.object.v1.deleted (Eventarc 経由) オブジェクトが完全に削除された場合に発生します。 オブジェクトのアーカイブ google.cloud.storage.object.v1.archived (Eventarc 経由) オブジェクトのライブ バージョンが非現行バージョンになると送信されます。詳細については、オブジェクトのバージョニングをご覧ください。 オブジェクト メタデータの更新 google.cloud.storage.object.v1.metadataUpdated (Eventarc 経由) 既存オブジェクトのメタデータが変更された場合に送信されます。 「あるフォルダにファイルがアップロードされたら起動するCloud Functionsを作りたい」という用途ですと、「 google.cloud.storage.object.v1.finalized 」が最適ですね。 Cloud Storageトリガーの仕様(2024年7月現在) Cloud Storageトリガーの説明は公式ドキュメントでは以下のように記載されています。 Cloud Functions では、Cloud Storage トリガーによって、Cloud Storage の変更に応じて関数を呼び出すことができます。関数に Cloud Storage トリガーを指定するときに、イベントタイプを選択して Cloud Storage バケットを指定します。この関数は、 指定されたバケット内のオブジェクト(ファイル) が変更されるたびに呼び出されます。 赤字箇所にありますように、Cloud Storageトリガーは バケットレベルでのファイルの変更にのみ 対応しています。 つまり、「以下のようなバケットの構造を考えたとき、フォルダAにファイルがアップロードされたときのみ関数が実行されるトリガーを作ることができない」ということになります。困りました… フォルダレベルでのCloud Storageトリガーを実装してみる 先ほど、フォルダレベルでのファイル変更に対応したCloud Storageトリガーはないことがわかりました。そこで、Cloud Functionでの処理を工夫することで、フォルダレベルでのCloud Storageトリガーを使っているかのように見せたいと思います。 今回実装するのは、hogehogeフォルダとfugafugaフォルダをバケットに作り、hogehogeフォルダにファイルがアップロードされたときのみ、ログにメッセージを出力する簡易的なシステムです。 バケットの作成 まず、バケットを作成します。以下のような設定でバケットを作成します。 次にフォルダを作成していきます。hogehogeフォルダとfugafugaフォルダを作成します。 これでバケットの作成は完了です。 Cloud Functionsの作成 それではCloud Functionsを作っていきます。以下のような第2世代の関数を作ります。 Cloud Storageトリガーのイベントタイプは google.cloud.storage.object.v1.finalized 」を設定します。 コーディングをしていきます。言語はPython3.12を使います。 hogehogeフォルダにファイルが格納されたときのみ、ログにメッセージを出力するようにします。 import functions_framework # Triggered by a change in a storage bucket @functions_framework.cloud_event def hello_gcs(cloud_event):   data = cloud_event.data   bucket = data["bucket"]     name = data["name"]   folder_name = data["name"].split("/")[-2]     file_name = data["name"].split("/")[-1]   print("これから処理を行います")   if folder_name == "fugafuga":       return   elif folder_name == "hogehoge":         print(file_name+"が格納されました!") コーディングが行いましたら、デプロイし、実装完了です。 実装結果 それでは実際にフォルダにファイルを格納して、動作確認をしていきます。 まず、hogehogeフォルダにtest.txtというファイルをアップロードします。 すると、以下のように「test.txtが格納されました!」というメッセージがログに出力されました。 一方で、fugafugaフォルダにtest.txtをアップロードしてみるとどうなるでしょうか? メッセージが出力されませんでした。 うまく実装することができました! しかし、トリガーで関数が実行されてしまっているので、あくまで疑似的なフォルダレベルのトリガーです。 おわりに 今回はフォルダレベルでのCloud Storageトリガーはないということがわかったので、疑似的なフォルダレベルのCloud Storageのトリガーを実装してみました。 フォルダレベルでのCloud Storageトリガーがない理由ですが、オブジェクトストレージであるがゆえにフラットな階層になっていることが原因であると私は考えています。 しかし!最近、Google Cloudより以下のブログが出ました! 階層名前空間によって Cloud Storage にファイル システム最適化をもたらす | Google Cloud 公式ブログ 新しい階層名前空間機能は、Cloud Storage バケットにファイル システム最適化をもたらします。 cloud.google.com このブログによると、Cloud Storageが階層名前空間(HNS)に対応するになるようです! ということはフォルダレベルでのCloud Storageトリガーが実装される日が近いのかもしれません… 以上、Cloud Storageトリガーのお話でした!! 最後まで読んでいただき、ありがとうございました。
本記事は 夏休みクラウド自由研究 8/5付の記事です 。 こんにちは。ひるたんぬです。 先日この暑さに身体がやられてしまい、休みのほとんどを寝て過ごしました… 何もせずにただひたすら横になることに最初は罪悪感を感じておりましたが、休みの過ごし方は人それぞれ。たまには(なんならいつも?)こんな休日があってもいいですね。休むことも大切です(自戒)。皆さんは休日どのように過ごされていますか? [新連載]ファストリ柳井氏の改心 猛烈一転「休みを取らないのは罪悪」 かつて、無休で猛烈に働いていた経営者も、年3回の長期休暇を欠かさなくなった。「休みを取らないことは罪悪」「日本人はもっと長期の休みを取るべきだ」――。ファーストリテイリング柳井正会長兼社長に休みとの向き合い方を聞いた。 business.nikkei.com さて、今回の企画名が「夏休みクラウド自由研究」でしたので、プレビュー版としてリリースされたばかりのAWS App Studioを使ってカンバンボードのプロジェクト管理ツールを作ってみようと思います。 AWS App Studioとは? 約一ヶ月ほど前の7月10日にパブリックプレビューとなった新しいサービスです。 AWS App Studio is a generative AI-powered service that uses natural language to build enterprise-grade applications, empowering a new set of builders to create applications in minutes . With App Studio, technical professionals without deep software development skills, such as IT project managers, data engineers, and enterprise architects, can quickly develop business applications tailored to their organization’s needs . 引用:AWS 「 AWS App Studio 」 要約すると、「生成AIを活用することで、ソフトウェア開発などの専門的な知識がなくとも自身の組織の要望に沿ったアプリケーションを短時間で生成できるサービス」と言ったところでしょうか。 開発領域においても生成AIを利用したサービスが次々とリリースされていますね! 料金につきましては、開発やテストなどをする分には無料で利用できますが、作成したアプリケーションを公開した場合、その時間に応じて料金が発生するようです。¹ ¹ アプリケーションによって動作するサービスの利用料金が別途発生します。 Generative AI–powered, low-code application builder – AWS App Studio Pricing – AWS View the pricing information for AWS App Studio—a generative AI–powered, low-code application building service. Start bu... aws.amazon.com   使い方 インスタンスの作成 マネジメントコンソールにて「AWS App Studio」と検索すると出てきます。 現在はオレゴンリージョンでのみ提供されているため、下記画面が表示された場合は、リージョンを切り替えてください。 App Studioの画面が表示されるので、セットアップの「開始」を押下します。 App Studioのインスタンス作成画面に移るので、表示に従って次のものを用意します。 IAM Identity Center Account Amazon CodeCatalystスペース CodeCatalystについては私は以前スペースを作成していたため、そちらを流用しました。 スペースの作成方法や利用方法につきましては、以下の記事をご参照ください。 Amazon CodeCatalyst で AWS Lambda の CI/CD 環境を構築する 2023年4月にGAとなった「CodeCatalyst」を触ってみたので、それについてお話ししようと思います。 blog.usize-tech.com 2024.05.24 また、IAM Identity Center Accountについては作成していなかったため、この画面で作成します。 IAM Identity Center Accountをこの画面で作成すると、オレゴンリージョンで有効化・作成されます。他の任意のリージョンで作成したい場合は、あらかじめ作成したうえで、この画面で選択することも可能です。 管理者グループ・ビルダーグループの名前を設定し、管理者グループユーザーに最低1人のユーザーを追加します。今回は、私一人のみの寂しい開発ですので、管理者グループユーザーにのみユーザー情報を記載しました。 最終的に確認事項にチェックを入れ、「設定」を押下します。 …と思ったのですが、「設定」ボタンがグレーアウトしたまま押すことができませんでした。 改めて見てみたところ、権限上何かが読み取れていなかった(何が読み取れていなかったのかは見落としました…)ので、それが原因かもしれません。 そのため、あらかじめIAM Identity Center Accountを作成し、割り当てをしたうえで「設定」を押下します。 するとセットアップが始まります…が、なんとこれ、最大で30分かかると書いてありますね。 アイスでも食べながら大人しく待つことにします。この季節のアイスはたまらないですよねぇ…冬にこたつに入りながら食べるアイスもまた良いのですが。 別画面に遷移しても問題はありません。進捗はApp Studioトップ画面の「設定に戻る」から確認できます。 私の環境では、15分ほどで設定が完了したという画面に切り替わりました。 そうしましたら、「App Studio に移動」を押下します。 App Studioにサインイン 最初に以下のような画面が表示されます。なんというか…CodeCatalystに似ていますね。 ここから「Sign in」を押下します。 ここでは先程のIAM Identity Center Accountで登録したユーザー名やパスワードを入力し、サインインします。 サインイン後にMFAの追加が求められる場合がありますので、必要に応じて追加してください。 サインインが完了するとApp Studioのトップページが開きます。ここからは英語ですね… アプリを作る 管理者グループでサインインをしている場合、最初に「Admin hub」が表示されているので、左側ペインより「Builder hub」を押下して移動します。 移動後に「CREATE A NEW APP」を押下します。 アプリ名は適当に設定し、アプリの作成方法を選択します。今回は一人ぼっちの開発なので、せめてもの思いでAIを仲間に入れようと思います。(「Generate an app with AI」を選択します。) 次にアプリに含めるデータソースの有無を尋ねられます。ここはオプションの選択項目であり、あとでも設定できるため、今は「Skip」を選択します。 するとセッションの準備が始まり… 1分もしないうちに作成画面が表示されました。 ここでは 自分で一からプロンプトを入力 サンプルのプロンプトを使用(カスタマイズもできる) のどちらかで、AIに命令を与えます。今回は以下の要件を完結に英語で表現して入力を与えてみました。 プロジェクト管理ツールを作りたい カンバンボード形式の見た目 「Backlog」「In progress」「Done」の3つの項目からなる ユーザーはタスクの作成と移動が簡単にできる この情報からAIがアプリケーションの概要を作成してくれるので、内容を確認します。 自身の要件を確認するには「Your requirements」を、実際に作成されるアプリケーションの要件を確認するには「App overview」を確認すると良いと思います。 …すごいですね。拙い文章だったのですが、やりたいことが概ね記載されているように思えます。 ここで、私はタスクに重要度を付与できる機能を与えることを忘れていることに気づいたので、それも追加してみます。 そして、更新後の要件をもう一度確認してみると…きちんと重要度に関する要件が追加されていますね! 今回はこれで要件を充足していると思うので、「Generate app」を押下しアプリケーションを作成します。しばらくするとアプリケーションが作成された、と表示されるので、「Preview app」もしくは「Edit app」のどちらかを押下します。 今回は「Preview app」を押下し、実際のアプリケーションを見てみようと思います。 アプリケーションの出来栄えは…? 完成したアプリケーションはこちらです。 カンバンボード形式でタスク一覧を見れる機能と、タスクを新たに追加する機能、タスクを移動させる機能(Backlog→In progress, In progress→Done)が実装されていました。 もちろん既存サービスなどの理想形とはまだまだ差がありますが、たった数文を与えただけでこれだけのアプリケーションができることは驚きました。事前のAIとの対話でもっと要件を具体化する、もしくは編集画面にて自分の思うように画面や処理を変更することができるので、ここは工夫の余地があるなと思いました。 ▼実際の編集画面   おわりに 今回は「自由研究」がテーマでしたので、自分が全く触れていない新しいサービスを体験し、その所感を記事にしました。生成AIとの対話を通して簡単にアプリケーションが作れる一方で、細かいところなどにはまだまだ人間の工夫が必要なのかなというのが正直な感想です。 これからも自身の技術力向上のための取り組みは続けつつ、生成AIと上手に付き合うためのスキルも磨いていきたいなと思った次第です。
本記事は 夏休みクラウド自由研究 8/4付の記事です 。 みなさんこんにちは。 本ブログでは、Prisma Cloudを用いたサービス開発や運営の中で得た知見や、使いこなし方を共有することで、クラウドセキュリティの重要性の認知度を高め、対策レベルを向上させることを目指しています。ただの情報発信ではなく、実際の使用例や失敗から学んだ教訓など、実務に役立つ具体的な内容も提供していきます。 今回は、CWPPについての2つ目の記事として、PrismaCloudのCWPP機能の中核を成すDefender(エージェント)について詳しく解説していきたいと思います。   Prisma CloudのDefenderの機能 Prisma CloudのDefenderは、クラウド環境のセキュリティを強化するためのエージェントです。Defenderはホスト、コンテナ、サーバーレス環境を包括的に保護し、リアルタイムの監視と脅威の防御を提供します。以下にDefenderの具体的な機能を解説します。 1. ランタイム防御 プロセス監視 Defenderは実行中のプロセスをリアルタイムで監視し、不審なプロセスの起動や異常な挙動を検出します。これにより、マルウェアや不正な活動を早期に発見し対応することができます。 ファイルシステム監視 ファイルシステムの変更をリアルタイムで監視し、不審な変更を検出します。例えば、重要なファイルの改ざんや不正なファイルの追加を検知し、アラートを発することが可能です。 ネットワークトラフィック監視 ワークロード間のネットワークトラフィックを監視し、不審な通信や異常なトラフィックパターンを検出します。これにより、例えば情報漏洩に繋がる外部の悪意あるIPアドレスへの通信をブロックすることができます。 2. 脆弱性管理 脆弱性スキャン DefenderはCI/CDパイプラインと連携し、コンテナイメージやホストの脆弱性を詳細にスキャンします。デプロイ前に脆弱性を検出し修正でき、脆弱なイメージからコンテナを起動しないように制御することが可能です。 脆弱性の優先順位付け 公開リスクやリスクスコアに基づいて、最も優先順位の高い脆弱性を特定します。これにより、重要な脆弱性に迅速に対応することができます。 3. 自動応答 自動応答 脅威を検出した際に自動的に対応策を講じます。例えば、感染したコンテナを自動的にターミネートし再作成することで、被害の拡大をリアルタイムに防ぐことができます。 4. コンプライアンス管理 コンプライアンスチェック Defenderは業界標準や内部ポリシーに基づいたコンプライアンスチェックを実行します。コンプライアンス違反を早期に検出し修正することができます。 5. サーバーレスセキュリティ サーバーレス関数の保護 DefenderはAWS Lambda、Azure Functions、Google Cloud Functionsなどのサーバーレス関数を保護します。関数の脆弱性をスキャンし、継続的に監視します。 ランタイム保護 サーバーレス関数の実行中に脆弱性や不審な活動を検出し、リアルタイムで対応します。これにより、サーバーレス環境のセキュリティを強化します。   まとめ Prisma CloudのDefenderは、ランタイム防御、脆弱性管理、自動応答、コンプライアンス管理、サーバーレスセキュリティなど、多岐にわたる機能を備えており、クラウド環境のワークロードに対する包括的なセキュリティ対策を提供します。クラウド環境のセキュリティ対策として、Defenderはもはや必須と言えるでしょう。ただし、エージェントの導入は運用上のデメリットもありますので、その辺りがイメージできるように、次回以降、Defenderのホスト上での動作原理や、エージェントレスとの違いについても詳しく解説していきます。   最後に、当社ではPrismaCloudを用いたマネージドサービスを提供しているので紹介させてもらいます。 === 【CSPMマネージドサービス SmartOneCloudSecurity】 SmartOneCloudSecurityは、Prisma Cloud を用いたCSPMマネージドサービスです。Prisma Cloud の導入から設定変更まで、弊社技術担当者がお客様のCSPM対策をサポートします。CSPMの導入を検討中の方はもちろん、Prisma Cloud を利用中だけど機能や運用面でもっと上手に活用したい、というような課題をお持ちな方は、お気軽に下記URLからお問い合わせください。Prisma Cloud のPoCの相談も受けています。 New!! CWPPの導入サポートも始めました! Smart One Cloud Security® パブリッククラウドのセキュリティ設定を診断/監視するマネージドCSPMサービスです。Palo Alto Networks社Prisma Cloud(CSPM機能)を使い易く、簡単に導入いただけます。 www.scsk.jp
本記事は 夏休みクラウド自由研究 8/3付の記事です 。 こんにちは、SCSK齋藤です。 今回は、SQSキューポリシーに明示的な拒否を設定しましたが、考えが甘かったせいで、SQSにアクセスできなくなったお話を書いていきます。 そして、その教訓からIAMのポリシー定義について、再び学びを深めてみたいと思います。 何が起こったか? SQS→Lambdaへと連携するようなサーバレスアーキテクチャを開発している時に、SQSに次の2点のアクセス制御を実施したいと考えました。 SQSへメッセージを送受信するリソースを、特定のLambdaのみにしたい 人手による運用が入るのを考慮し、マネジメントコンソール経由で全IAMユーザーからのアクセスは許可したい。 そのため、実際に定義したキューポリシーは下記の通りです。 # # ------------------------------------------------------------# # # SQSQueuePolicy # # ------------------------------------------------------------#   SQSPolicy:     Type: AWS::SQS::QueuePolicy     Properties:       Queues:         - !Ref SQS       PolicyDocument:         Version: "2012-10-17"         Statement:           #IAMユーザと必要リソース以外のアクセスを拒否           - Effect: Deny             Principal: "*"             Action: "sqs:*"             Resource: !GetAtt SampleSQS.Arn             Condition:               StringNotEquals:                 aws:UserAgent:                   - aws-internal-console               ArnNotLike:                 aws:SourceArn:                   - !Sub "arn:aws:lambda:*:${AWS::AccountId}:function:sample-lambda-*" 上記ポリシーを設定し、SQSをSAMテンプレートから作成してみましたが、管理者権限を持ったIAMユーザーからでは、マネジメントコンソール上に作成したSQSが表示されません。 なお、CloudShellを開き、SQSのリストをAWS CLIで表示してみたら、リストの一覧には出てきました。 AWS CLI上だけ見えるのも変だと思いながらも、そのままAWS CLIで削除コマンドを実施しましたが、Access Deniedになり、削除できませんでした。 まさしく、八方塞がりな状態でした。。。   暫定対処 上記の状態に陥ったので、ひとまずキューを削除する方法を考えました。 ① 特定のLambdaのみからアクセスできるようにする意図で、キューポリシーを書いていたので、そのLambdaからキューを削除することができないか? →実際に試してみましたが、こちらもAccess Deniedされてしまいました。。なぜだ。。。。 ② ルートユーザーから削除できないか? →こちらは成功いたしました。やはり最後の頼みの綱は、ルートユーザーなんだなと感じました。   キューポリシーを振り返る 一旦削除はできたので、改めて定義したキューポリシーの何がいけなかったのかを考察していきます。 ポイントは、2つです。 IAMユーザーからマネジメントコンソールで閲覧させる権限の記述の誤り ポリシーの中の、下記が問題でした。 StringNotEquals:    aws:UserAgent:       - aws-internal-console こちらを書いた意図としては、IAMユーザーがマネジメントコンソール経由でSQSの操作ができるようにするために記載しました。 元々は、PrincipalをNotPrincipalにする下記の記載方式を検討していましたが、NotPrincipal内ではuserに*は使えないとのことで作成ができませんでした。 NotPrincipal: arn:aws:iam::111122223333:user/*   また、事後調査でわかりましたが、下記のようなドキュメントも見つけたので、NotPrincipalとDenyはそもそも相性が悪いんだということもわかりました。 AWS JSON ポリシーの要素: NotPrincipal - AWS Identity and Access Management AWS JSON ポリシー言語の NotPrincipal 要素を定義します。 docs.aws.amazon.com   そのため、チャット式の生成AIに聞いたら、aws:UserAgentを用いた書き方を提案されたので、今回のような書き方をしました。。。 しかし、インターネットで調べてもこのような書き方は出てこないので、嘘情報だったのではと思います。 実際、今回記載した内容は「aws-internal-console」というアプリケーションからのHTTPリクエストという意味になるそうです。 マネジメントコンソール上でHTTPヘッダーを確認しましたが、aws-internal-consoleという情報は出てこなかったです。 これでは、マネジメントコンソールからアクセスできませんね。。。 Denyステートメント内でのLambdaへの権限の記述誤り Lambdaについては、下記のように記載していました。 ArnNotLike:  aws:SourceArn:  - !Sub "arn:aws:lambda:*:${AWS::AccountId}:function:sample-lambda-*" これは、LambdaのARNを指定して、Denyから回避しようとしてました。 しかし、正しくはLambdaにアタッチされている IAMロール をNotとして回避させてあげないといけません。 あくまでLambdaからSQSへ操作する実行主体は、IAMロールなので、それに対する権限の記載をしないといけなかったという訳です。   正しい記載は何か? いろいろ調査した結果、正しい記載は下記ではないかと考えられます。 {   “Version”: “2012-10-17",   “Statement”: [     {       “Effect”: “Deny”,       “Principal”: “*”,       “Action”: “sqs:*“,       “Resource”: “arn:aws:sqs:ap-northeast-1:${AWS::AccountId}:SampleQueue”,       “Condition”: {         “ArnNotEquals”: {           “aws:PrincipalArn”: [             “arn:aws:iam::${AWS::AccountId}:user/*“,             “arn:aws:iam::${AWS::AccountId}:role/service-role/example-role”           ]         }       }     }   ] } ArnNotEqualsの中身は、aws:PrincipalArnで統一をします。 その中で、下記2つを記載して、それぞれのことを実現します。 “arn:aws:iam::${AWS::AccountId}:user/*“ ・・・そのアカウント内の全IAMユーザーへのアクセス制御を実現。 “arn:aws:iam::${AWS::AccountId}:role/service-role/example-role” ・・・Lambdaに付与しているIAMロールへのアクセス制御を実現。   今回の教訓 今回アクセス拒否されてしまった事象の教訓としては、下記がございます。  Lambdaへのアクセス制御は、付与しているIAMロールへのアクセス制御が必要。 ・実行権限を付与する主体が何なのかは、今後権限付与する際にしっかり調査する必要があると感じました。 NotPrincipalとDenyはそもそも相性が悪い。 ・AWS側も非推奨としているので、DenyをするならConditionの中にaws:PrincipalArnを書く方法を採用すべきですね。 ポリシー作成後に検証して動作確認するとはいえ、安易に生成AIのいうことを聞いてはいけない。 ・今回は明示的な拒否のため、アクセスできなくなるリスクが孕んでおり、そういう場合には慎重に調査をすべきと感じました。   まとめ 今回は、SQSへのアクセスができなくなった事象についてまとめました。 IAMの記述方式は複雑であり、非常に奥が深いことを再実感しました。 正しい仕様を理解することはやはり重要ですね。
本記事は 夏休みクラウド自由研究 8/2付の記事です 。 こんにちは。SCSKの江木です。 夏休みクラウド自由研究2024の2日目の記事になります。 みなさん、単体テストケース作成に時間がかかりすぎていませんか? 先日Dialogflow CXの単体テストケースを作成していて、抜け漏れチェックに追われて、かなり時間がかかってしまいました。 今回はテストケース作成の時間を削減すべく、グラフ理論を使って、単体テストケース作成を自動化する方法を実装してみました。 このグラフ理論の考え方は他にも使えると思うので、ぜひご覧ください。 Dialogflow CXにおける単体テストケースについて 単体テストの方法 Dialogflow CX(以下、Dialogflow)は他のサービスと連携して使用されることが多いのが現状です。したがって、本記事におけるDialogflowの単体テストはDialogflow単体で動作するかという意味で使用していますので、ご了承ください。 これを踏まえて、Dialogflowの単体テストは以下の方法で行うことを想定しております。 基本的にはページレベルでテスト ループのテストはフローレベルで テストは正常系、異常系、ループに分ける それぞれの観点について詳しく説明していきます。 基本的にはページレベルでテスト 一般的にプログラムの単体テストは関数/メソッドといった単位で行いますが、このプログラムにおける関数/メソッドをDialogflowで置き換えるとページと捉えることができます。 従って、ページレベル単位でテストを行います。 ※一般的な単体テストと捉えていただけるとわかりやすいと思います。 ループのテストはフローレベルで 聞き返し機能をチャット/ボイスボットに備えるため、DialogflowのAgentにはループが存在することがあります。 ループのテストはページレベルで行うとテストケースが複雑になるため、フローレベルで行います。 テストは正常系、異常系、ループに分ける テストは正常系、異常系、ループの3つに分けて行います。 正常系ではパラメータ入力およびイベント発生における動作確認を行います。異常系では無効な入力に対する動作確認を行います。 また、正常系・異常系は以下の観点でテストを行います。 正しく遷移するか 画面が仕様通りに表示されているか 取得情報に誤りがないか 一方で、ループは以下の観点でテストを行います。 ループがフローに影響がないか ループは正常系に入れてもよいのですが、テスト観点が異なるためテストジャンルを分けました。 作成するテストケースについて 上記のテスト観点を踏まえて、テストケースを作成していきます。作成したテストケースは以下のようなエクセルシートで出力したいと思います。また、出力されるエクセルシートは全部埋められているわけではなく、抜け漏れチェックのためにエクセルシートの一部をテスターが埋めるようにしています。 ※横に長いため、分割しています。 実装 アーキテクチャ アーキテクチャは以下の図を想定しています。 Cloud StorageのバケットにAgentのファイルをアップロードすると、テストケースが同じバケットに出力されるように設計しています。 実装方針 テストケース作成にはページの遷移先、ループの検出が不可欠です。そこで、グラフ理論の考え方でDialogflowのフローは有向グラフであることに着目し、Pythonのグラフ系ライブラリであるNetworkXを使って、実装しました。NetworkXを使うことで、ループ検出、ルート検索が容易になります。 有向グラフとは? 有向グラフとは、下図のように頂点と、それらを結ぶ辺が向きを持つグラフです。辺の向きは矢印で表され、矢印の先端が頂点の終点、矢印の根元が始点となります。 いざ実装! それでは実際に実装していきます。Dialogflowのフローを有向グラフに置き換える箇所を中心にプログラムを抜粋して紹介していきます。 トリガーの設定 Cloud Storageのトリガーを設定していきます。Cloud StorageのバケットにAgentのファイルが格納された際にCloud Functionsが起動するようにしたいので、以下のように「google.cloud.storage.object.v1.finalized」で設定します。   Agentファイルの読み込み CloudEvent関数を使用して、Cloud Storageにアップロードされたファイル名の取得を行います。その後、ファイル名からAgentをjson形式でCloud Storageから読み込みます。以下は、アップロードされたAgentのファイルから辞書形式でAgentの詳細を取得するプログラムです。 @functions_framework.cloud_event def main(cloud_event):   #GCSバケットの名前   bucket_name = cloud_event.data['bucket']   #zipファイルの名前   blob_name = cloud_event.data['name'] #Agentファイル以外がアップロードされた場合は終了   if blob_name.split(".")[1] != "zip":         return   #flowごとのjsonが格納された辞書を取得   Agent_dict = get_dict(bucket_name,blob_name) また、辞書形式でAgentを取得するget_json関数の詳細は以下の通りです。 def get_dict(bucket_name: str,blob_name: str) -> dict:   storage_client = storage.Client()   bucket = storage_client.bucket(bucket_name)   blobs = storage_client.list_blobs(bucket_name)   blob = bucket.blob(blob_name)     content = blob.download_as_string()   # zipファイルを読み込む     zip_f = zipfile.ZipFile(BytesIO(content))   # zipファイルの中身のファイル名を取得     lst = zip_f.namelist()     selected_items = [item for item in lst if 'flows' in item]   Agent_dict = {}   for item in selected_items:       flow_name = item.split('/')[1]       tag = item.split('/')[-1].split('.')[0]       if flow_name not in Agent_dict:           Agent_dict[flow_name] = {}       with zip_f.open(item) as myfile: # openを利用してファイルにアクセス           json_detail = json.load(myfile)         Agent_dict[flow_name][tag] = json_detail return Agent_dict 有向グラフの作成 それでは、辞書型のAgentからグラフを作成していきます。以下は辞書型のAgentから、page名をkey、そのpageからの遷移先の配列をvalueとした辞書を作成し、その辞書からグラフを作成していくプログラムになります。また、page_dictはflowごとのpage一覧が格納された辞書を表しています。 def make_graph(page_dict: dict,flow_name: str,Agent_dict: dict) -> Graph:       #page名が入った配列を作成。End Sessionページが入っていないので追加する page_list = page_dict[flow_name]         page_list.append("End Session")       #page名をkey,遷移先の配列をvalueとした辞書を作成       dict_flow = {} #page名からflowを探索して、遷移先の配列を作成       for page in page_list           if page == "Start Page":                  dict_flow[page] = search(Agent_dict[flow_name][flow_name])           elif page == "End Session":                dict_flow[page] = []           else:               dict_flow[page] = search(Agent_dict[flow_name][page])     #グラフ作成       g = nx.DiGraph(dict_flow) return g   テストケースの作成 正常系、異常系、ループの3つのジャンルで作成していきます。 正常系テストケースの作成 正常系のテストケースを作成するプログラムは以下の通りです。イベントを確認するテストケースとパラメータを確認するテストケースに分けて作成してします。rowは操作するエクセルシートの行、wsはエクセルシート、flow_dictはflowの辞書を表しています。 def make_normal(row: int,page: str,ws: sheet,flow_dict: dict) -> Tuple[int,sheet]:     test_category = "正常系"   #イベントテストケース作成 #イベント一覧の取得   event_list,event_json = get_event(page,flow_dict) #異常系のイベントを除去   event_list_remove_abnormal = [event for event in event_list if 'sys.no-match' not in event and 'sys.no-input' not in event and 'long-utterance' not in event]   if len(event_list_remove_abnormal) != 0:       for event in event_list_remove_abnormal:           category_sentence = "イベント(" + event + ")"           transition = "遷移しない"           for event_detail in event_json["page_event"]:               if event_detail["event"] == event and "targetPage" in event_detail.keys():                     transition = event_detail["targetPage"] #テストケースをエクセルへ書き込み             row,ws = add_page_testcase(row,page,test_category,category_sentence,transition,ws)   #パラメータテストケース作成 #パラメータ一覧の取得   parameter_list = get_parameter(page,flow_dict) #遷移先一覧の取得   transitionRoute_list,transitionRoute_json = get_transitionRoutes(page,flow_dict)   if len(parameter_list) != 0:       param_all = ','.join(parameter_list)       category_sentence = "パラメータ(" + param_all + ")"       for route in transitionRoute_json:           for param in parameter_list:               transition = "遷移しない"               if "$page.params.status" in route["condition"] or param in route["condition"]:#page.paramsかパラメータ名が条件に入っていれば、そのルートをテストケースとする                   if "targetPage" in route.keys():                       transition = route["targetPage"]            #テストケースをエクセルへ書き込み                     row,ws = add_page_testcase(row,page,test_category,category_sentence,transition,ws)   return row,ws 異常系テストケースの作成 異常系のテストケースを作成するプログラムは以下の通りです。no-match、no-inputイベントとlong-utteranceイベントに分けてテストケース作成を行います。no-match、no-inputイベントは設定された回数分テストケースを作成します。long-utteranceイベントはループ回数の指定があれば、指定の回数分テストケースを作成しますが、指定がない際はテストケースを1つのみ作成します。 def make_abnormal(row: int,page: str,ws: sheet,flow_dict: dict) -> Tuple[int,sheet]:     test_category = "異常系" #イベント一覧の取得   event_list,event_json = get_event(page,flow_dict)   event_list_abnormal = [event for event in event_list if "sys.no-match" in event or "sys.no-input" in event or "long-utterance" in event]     event_list_abnormal_not_longutterance = [event for event in event_list if "sys.no-match" in event or "sys.no-input" in event]   if len(event_list_abnormal_not_longutterance) != 0:       for event in event_list_abnormal_not_longutterance:           category_sentence = event + "イベント"           #pageのほうにある場合もある           transition = "遷移しない"           if "param_event" in event_json.keys():               for event_detail in event_json["param_event"]:                   if event_detail["event"] == event and "targetPage" in event_detail.keys():                     transition = event_detail["targetPage"]           elif "page_event" in event_json.keys():               for event_detail in event_json["page_event"]:                   if event_detail["event"] == event and "targetPage" in event_detail.keys():                       transition = event_detail["targetPage"] #テストケースをエクセルへ書き込み           row,ws = add_page_testcase(row,page,test_category,category_sentence,transition,ws)   #long-utteranceの時の処理   parameter_list = get_parameter(page,flow_dict)   transitionRoute_list,transitionRoute_json = get_transitionRoutes(page,flow_dict)   for event in event_list_abnormal:       if "long-utterance" in event:           #loop-countのパラメータがなければ(not-added)、テストケースは1つだけ作成する           flag = "not-added"           for route in transitionRoute_json: #long-utteranceのループ回数をカウントするパラメータを探索して、存在すればそのループカウント分だけテストケースを作成。               if "loop" in route["condition"] and "count" in route["condition"] and "$session.params" in route["condition"]:                   split_condition = route["condition"].split("=")                   loop_count_max = int(split_condition[1].strip())                   for i in range(loop_count_max):                       category_sentence = event + "-" + str(i+1) +"イベント"                       if i+1 != loop_count_max:                           transition = "遷移しない"                       else:                           transition = route["targetPage"] #テストケースをエクセルへ書き込み                       row,ws = add_page_testcase(row,page,test_category,category_sentence,transition,ws)                   flag = "added"           if flag == "not-added":               category_sentence = event + "イベント"               transition = "遷移しない" #テストケースをエクセルへ書き込み                 row,ws = add_page_testcase(row,page,test_category,category_sentence,transition,ws)     return row,ws ループテストケースの作成 ループのテストケースを作成するプログラムは以下の通りです。NetworkXの閉路を検知する関数を使って、ループ検知を行います。 def make_loop_test(row: int,pages: str,ws: sheet,g: Graph) -> Tuple[int,sheet]:   #有向グラフからサイクル検知でloopを検知     loop_list = list(nx.simple_cycles(g))   if len(loop_list) != 0:       for loop in loop_list:           loop.append(loop[0])           page_sentence = "⇒".join(loop)           test_category = "-"           category_sentence = "、".join(loop)             category_sentence = category_sentence + "におけるloopをカウントするパラメータの確認" #テストケースをエクセルへ書き込み             row,ws = add_loop_testcase(row,page_sentence,test_category,category_sentence,ws)         return row,ws ファイルの出力・保存 エクセルファイルをCloud Storageのバケットへ出力するプログラムは以下の通りです。エクセルファイルを一時ファイル的に保存するためにtmpフォルダを使用しています。(地味に苦労したポイントです!!)tmpフォルダへ格納した後、Cloud Storageのバケットへアップロードします。 def repository(wb: book,bucket_name: str,file_name: str) -> None: #エクセルの一時ファイルを保存 wb.save("/tmp/"+excel_filename)    storage_client = storage.Client() bucket = storage_client.bucket(bucket_name)     blob = bucket.blob(file_name)   # エクセルの一時ファイルをCloud Storageのバケットへアップロード   blob.upload_from_filename("/tmp/" + file_name)     os.remove("/tmp/" + file_name) 出力結果 以下のAgentのテストケースを出力してみます。 以下のようにうまく出力することができました!(テストケースが多いので、抜粋しています) また、ループの検知がうまくできていることも以下のように見て取れます。 おわりに 今回はグラフ理論を使って、Dialogflow CXのテストケース作成の自動化を実装してみました。 本記事で実装しているのはループの検出のみですが、ルートの検出ももちろんできます。 ループ、ルートの検出が出来ると何がうれしいかといいますと、テストケースの抜け漏れを防げるということです! Dialogflowの他にも、世の中にはグラフに置き換えることができるサービスで溢れていますので、それらのサービスをグラフに置き換えることができれば、今回のように何らかの自動化ができるかもしれませんね… 最後まで読んでいただき、ありがとうございました。
こんにちは。SCSKの島村です。 今年もGoogle Cloud のカンファレンスイベント Google Cloud Next Tokyo ’24 が パシフィコ横浜 にて開催されております。 8月1日(木)-2日(金) の二日間にわたり、 生成 AI やセキュリティをはじめ、ビジネスに欠かせないテーマを元に、基調講演、ライブ セッションやハンズオンなど 様々なプログラムがご用意されているGoogle Cloudのビッグイベントとなります。 ☟☟☟イベント詳細については、こちらの記事よりご確認ください。☟☟☟ まだ登録されていない方は、下記リンクよりご一読いただけますと幸いです。 Google Cloud Next Tokyo ’24 へ出展のお知らせ – TechHarmony (usize-tech.com) 本記事では、Google Cloud Next Tokyo’24「 Day1開幕速報 」として、 ・ Day 1 Keynoteまとめ ・ 弊社SCSKの展示ブースについて ・ (おまけ)現地の最新情報    を共有できればと思います。 ご登録がお済でない方は、まずはこちらからご登録ください↓↓ 【招待コード  : FY24nx_pt030】 申し込み時にご入力ください!! [速報] Keynote(10:00-11:30 D1-KEYNOTE 基調講演会場) 概要 Google Cloud Next 24 Tokyoの開幕イベント共に本日10時よりKeynoteセッションが行われました。 現地速報として、リリースされた新サービスの情報並びに会場の雰囲気をいち早くお伝えします。 (*各サービスの詳細については、後日追って共有いたします。) Keynoteアーカイブは以下,Google Cloud 公式Youtubeから確認可能です。 Watch – DAY 1 基調講演 (cloudonair.withgoogle.com) 本Keynoteでは、 「話題の生成 AI を筆頭に多様なプロダクト アップデートや最新のソリューションの紹介」 「Google Cloud を導入しビジネスに革新をもたらすの企業のリーダーから、そのビジョンと取り組みについて」共有されました。 —本Keynoteにてご登壇された方々— ●東日本旅客鉄道 代表取締役副社長イノベーション戦略本部長 CTO・CDO・CIO 伊勢 勝巳 氏 ● LINEヤフー 上級執行役員 生成AI統括本部長 宮澤 弦 氏 ● 星野リゾート 代表 星野 佳路 氏 ● Google Cloud 日本代表 平手 智行氏 ● Google DeepMind プロダクト & エンジニアリング シニア ディレクター セシュ アジャラプ氏 ● Google Cloud AI ディレクター プロダクト マネージメント アーワン メナード氏 ● Google Cloud Google Workspace 事業本部 コラボレーション アプリ プロダクト マネージメント バイス プレジデント クリスティナ ベア氏 ● Google Cloud Retail & CPG Cluster カスタマー エンジニア 諏訪 悠紀氏 ● Google Cloud Google Workspace 事業本部 ソリューション エンジニアリング リード 白川 遼氏 Keynoteにて発表されたサービス 新たに発表されたサービス一覧 *各サービスの詳細については、後日追って共有いたします。次回のブログをお楽しみにしていただければと思います。 NEW ML Processing in Japan Geminiモデル in Japan Geminiに関する処理のすべてが日本国内で完結 NEW Gemini for Google Cloud Service Level Agreement(SLA) 高度に規則された業界でも安心してGeminiを利用可能 NEW Gemma 2 軽量かつ最先端のオープンモデルファミリー NEW MaaS(Model as a Service) Llama:405B(プレビュー) 8B/70B(Coming Soon) Mistral:Codestral(一般提供)Large 2(一般提供)NeMo(一般提供) NEW Gemini 1.5 Pro | Gemini 1.5 Flash コンテキストキャッシング 大規模なコンテンツキャッシュと新しいプロンプト入力を組み合わせGeminiでコンテンツ生成が可能 入力コストを最大で75%削減 NEW Grounding on Vertex AI ● サードパーティデータセットによるグラウンディング ● 高忠実度モードによるグラウンディング ●Dynamic Retrieval Keynoteでは、Geminiを利用したプロトタイプでのデモが紹介されたました。 日本語でのマルチモーダルな問い合わせをスマホから実施しており、インパクトのあるデモで会場でも拍手が起こっていました。また、本KeynoteではGoogle Cloudを活用されていリーダ企業様の事例を複数共有いただきました。   弊社SCSKの展示ブース(スポンサーブース@Expo)について 今回、弊社SCSKは Platinumスポンサー として ブレイクアウトセッション &Ask the Speaker に登壇し 、 Expo 会場へのブースを出展 しております。 >>展示ブースのコンセプト<< 弊社は今年の4月にLas Vegasで開催されたGoogle Cloud Next ’24 Partner Summit において 『 Google Cloud ソーシャルインパクト パートナー オブ ザ イヤー 』を受賞しております。 AIの導入実績を評価いただいているのは国内では当社のみ。 AIを導入・活用した実績や受賞に関わるAI技術のデモ、事例集を用意。イケイケでいきます。   —プレスリリースの詳細はこちらから— 国内企業で初受賞「Google Cloud ソーシャルインパクト パートナー オブ ザ イヤー」を受賞 (scsk.jp) Enterprise向けに画像(外観検査AI)や音声(コンタクトセンターAI)とマルチモーダルなデータを活用し、お客様課題解決、社会に新たな価値創出したことが認められ受賞に至りました。 展示ブースでは以下のデモをご用意しております。是非お立ち寄りください。 出展デモ概要 ■「電話基盤⇒音声認識⇒自動要約オプション⇒VOC分析」 (PrimeTiaas+Voiceek 紹介・デモ) ■ ボイスボットオプション(DialogflowCXを利用したPrimeTiaasオプションサービス 紹介・デモ) ■ PrimeAgentGAI(Google CloudのDialogflowCX+Agent Builderのデモ) ■ 生成AIによる問い合わせ業務アシスタントツール(Agent Builder Search、Geminiなどを使った文書検索デモ) ■ Security Operations(SecOps・運用サービス紹介)   出展デモ詳細:(生成AIによる問い合わせ業務アシスタントツール) 弊社にて展示させていただいているデモの中から一部をご紹介させていただきます。 詳細気になった方は是非、会場SCSKブースまでお越しください!!!!!!   生成AIによる問い合わせ業務アシスタントツール とは? 問い合わせ業務を対応されているオペレーター向けの生成AIアシスタントツールです。 流行りのRAG(Retrieval-Augmented Generation)による検索やマルチモーダル(画像)での回答生成で、 『 オペレーターの回答支援を実施するプラットフォーム 』です。 以下、簡単に機能を紹介いたします。 【機能一覧】 ■ 問い合わせ機能 ① Geminiへの問い合わせ:複数のGeminiモデルから選択可能で、オペレーターが作成した回答文の添削などを支援します。 ② ドキュメント検索:クラウド上に保存したナレッジから候補となる回答を検索し回答文作成を支援します。 ③ 過去問合せ検索:過去とのお客様とのやり取りを集約し、類似の問い合わせから回答文作成を支援します。 ④ Geminiへの問い合わせ(マルチモーダル):お客様から受領した添付画像を元に回答文作成を支援します。 ■ 問い合わせ履歴確認機能 ■ サンプルプロンプト管理機能 ■ ダッシュボード機能   利用イメージ [問い合わせ機能] 実際のデモ画面①☟☟☟☟ [ダッシュボード機能] 実際のデモ画面②☟☟☟☟   おまけ:現地会場(パシフィコ横浜)の様子 [現地写真]D1-KEYNOTE 基調講演会場 Keynote開始前には会場は満員近くになり、開始と同時に会場には拍手が響き渡りました。 会場MAP Next仕様のバス 横浜駅西口からパシフィコ横浜ノースまでの連絡バスが運行しておりました。 [パシフィコ横浜ノース] ノース | 施設ガイド | パシフィコ横浜 (pacifico.co.jp)   最後に 今回はGoogle Cloudのカンファレンスイベントである Google Cloud Next ’24 Tokyoについて現地速報をお届けしました。 本日から2日に渡るイベントをGoogle Cloud のPartnerとして一緒に盛り上げていければと思います。 弊社SCSKも Platinumスポンサーとして出展させていただいております! 現地では、会場の雰囲気も味わうことができ、Google Cloud の熱気も感じることができおります。 是非、皆様と会場にてお会いできることを楽しみにしています。 また、弊社出展サービスに関してのお問い合わせは以下のフォームからお願い致します。 お問い合わせ製品・サービス名に「Google Cloud」を選択してください。 お問い合わせ|クラウド移行だけでは描けない、理想のDXを実現する www.scsk.jp 新サービスの発表もありより詳しい内容については調査・整理し、本ブログにて情報発信できればと思います。 今後とも、AIMLに関する情報やGoogle CloudのAIMLサービスのアップデート情報を掲載していきたいと思います。 最後まで読んでいただき、ありがとうございました!!!
本記事は 夏休みクラウド自由研究 8/1付の記事です 。 こんにちは、広野です。 以前、以下の記事で Amazon Bedrock や Agents for Amazon Bedrock を使用した最小構成 RAG 環境構築を紹介しておりました。当時はAmazon Bedrock 関連のリソースを一部 AWS CloudFormation ではデプロイできなかったのですが、今はサポートされたためにできるようになりました。 React アプリに Agents for Amazon Bedrock への問い合わせ画面を組み込む [RAG・レスポンスストリーミング対応] Agents for Amazon Bedrock を使用して簡単な RAG をつくってみましたので、問い合わせ画面コードの一部を紹介します。 blog.usize-tech.com 2024.02.15 当時の構成を現在は変更しており、Knowledge Base に使用するデータベースを Amazon OpenSearch Serverless から Aurora Serverless v2 Postgresql に変更しています。 本シリーズ記事では、環境構築用の AWS CloudFormation のサンプルテンプレートを 3 記事に分けて紹介します。説明を分割するため、テンプレートを3つに分けていますのでご了承ください。 初回は VPC 編です。 本記事で取り扱う構成 RAG 環境全体の構成 以下のアーキテクチャで、RAG アプリケーションを構築しています。このうち、赤枠の部分が本シリーズ記事で取り扱う箇所です。series 1 VPC 編では、Amazon Aurora Serverless v2 Postgresql を構築する際に必要な VPC について説明します。 VPC の構成 Amazon Aurora Serverless v2 をデプロイするためには VPC が必要になります。サーバーレスなんですが、VPC リソースからアクセス可能にするためにそのような仕様にしているのだと思います。以下の VPC を用意します。 Aurora Serverless はプライベートサブネットに配置します。リーダーインスタンスやレプリカは設定していません。 Aurora Serverless を配置するときに、RDS サブネットグループが必要になります。任意の 2 つ以上のサブネットをグループに登録します。これが Aurora Serverless の設定で必要になるため、マルチ AZ 構成が必須になります。 データベースなので、プライベートサブネットに配置します。選択したサブネットに、VPC 内からアクセスするためのエンドポイントが作成されます。ただし Agents for Amazon Bedrock からは Data API 経由で接続するため、VPC は通りません。 エンドポイントにはセキュリティグループを関連付けます。ここでは、サブネットの CIDR から Postgresql に接続するためのデフォルトポート番号を開けておきます。 Agents for Amazon Bedrock が Aurora Serverless に接続するときのクレデンシャルは、Secrets Manager から取得します。これについては次回の記事で紹介します。 NAT ゲートウェイは本記事では省略しました。 AWS CloudFormation テンプレート 図に掲載している、Amazon Aurora Serverless、Agents for Amazon Bedrock、Secrets Manager は次回記事のテンプレートに含まれます。 Aurora Serverless で使用する RDS サブネットグループとセキュリティグループはここで作成し、次回のテンプレートで使用するためリソース情報をエクスポートしておきます。 AZ は仕様上、使用可能な 2 つの AZ をアルファベット順に前から選定します。東京リージョンだと b が使用できないため a と c が選定されますが、多くのリージョンでは a と b が選定されます。ここでは、東京リージョンでの使用を想定して a と c がリソースの名前に使用されています。ご注意ください。 AWSTemplateFormatVersion: 2010-09-09 Description: The CloudFormation template that creates A VPC, Subnets, an Internet Gateway and Routings. Additionally, a RDS subnet group and a security group for Aurora serverless. # ------------------------------------------------------------# # Input Parameters # ------------------------------------------------------------# Parameters: SubName: Type: String Description: System sub name of sample. (e.g. test) Default: test MaxLength: 10 MinLength: 1 VPCCIDR: Type: String Description: IP Address range for your VPC (16 bit mask) Default: 192.168.0.0/16 MaxLength: 14 MinLength: 10 AllowedPattern: ^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){2}0\.0/16$ PublicSubnetACIDR: Type: String Description: IP Address range for your public subnet A (24 bit mask) Default: 192.168.1.0/24 MaxLength: 16 MinLength: 10 AllowedPattern: ^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}0/24$ PublicSubnetCCIDR: Type: String Description: IP Address range for your public subnet C (24 bit mask) Default: 192.168.2.0/24 MaxLength: 16 MinLength: 10 AllowedPattern: ^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}0/24$ PrivateSubnetACIDR: Type: String Description: IP Address range for your private subnet A (24 bit mask) Default: 192.168.101.0/24 MaxLength: 16 MinLength: 10 AllowedPattern: ^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}0/24$ PrivateSubnetCCIDR: Type: String Description: IP Address range for your private subnet C (24 bit mask) Default: 192.168.102.0/24 MaxLength: 16 MinLength: 10 AllowedPattern: ^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}0/24$ Resources: # ------------------------------------------------------------# # VPC # ------------------------------------------------------------# VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VPCCIDR EnableDnsSupport: true EnableDnsHostnames: true InstanceTenancy: default Tags: - Key: Name Value: !Sub sample-VPC-${SubName} - Key: Cost Value: !Sub sample-${SubName} InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Sub sample-IGW-${SubName} - Key: Cost Value: !Sub sample-${SubName} InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC # ------------------------------------------------------------# # Subnet # ------------------------------------------------------------# PublicSubnetA: Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select - 0 - Fn::GetAZs: !Ref AWS::Region CidrBlock: !Ref PublicSubnetACIDR MapPublicIpOnLaunch: true VpcId: !Ref VPC Tags: - Key: Name Value: !Sub sample-Public-a-${SubName} - Key: Cost Value: !Sub sample-${SubName} PublicSubnetC: Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select - 1 - Fn::GetAZs: !Ref AWS::Region CidrBlock: !Ref PublicSubnetCCIDR MapPublicIpOnLaunch: true VpcId: !Ref VPC Tags: - Key: Name Value: !Sub sample-Public-c-${SubName} - Key: Cost Value: !Sub sample-${SubName} PrivateSubnetA: Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select - 0 - Fn::GetAZs: !Ref AWS::Region CidrBlock: !Ref PrivateSubnetACIDR VpcId: !Ref VPC Tags: - Key: Name Value: !Sub sample-Private-a-${SubName} - Key: Cost Value: !Sub sample-${SubName} PrivateSubnetC: Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select - 1 - Fn::GetAZs: !Ref AWS::Region CidrBlock: !Ref PrivateSubnetCCIDR VpcId: !Ref VPC Tags: - Key: Name Value: !Sub sample-Private-c-${SubName} - Key: Cost Value: !Sub sample-${SubName} # ------------------------------------------------------------# # Subnet Group for RDS # ------------------------------------------------------------# PrivateSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupName: !Sub sample-${SubName} DBSubnetGroupDescription: !Sub Subnet Group for KB database for sample-${SubName} SubnetIds: - !Ref PrivateSubnetA - !Ref PrivateSubnetC Tags: - Key: Cost Value: !Sub sample-${SubName} # ------------------------------------------------------------# # Security Group for RDS # ------------------------------------------------------------# AuroraSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Sub bedrock-rag-kb-sample-${SubName} GroupDescription: !Sub Allow Aurora PostgreSQL for sample-${SubName} VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 5432 ToPort: 5432 CidrIp: !Ref PrivateSubnetACIDR - IpProtocol: tcp FromPort: 5432 ToPort: 5432 CidrIp: !Ref PrivateSubnetCCIDR Tags: - Key: Cost Value: !Sub sample-${SubName} - Key: Name Value: !Sub sg-bedrock-rag-kb-sample-${SubName} # ------------------------------------------------------------# # RouteTable # ------------------------------------------------------------# PublicRouteTableA: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC PublicRouteTableC: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC PrivateRouteTableA: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC PrivateRouteTableC: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC # ------------------------------------------------------------# # Routing to Internet # ------------------------------------------------------------# PublicRouteA: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PublicRouteTableA DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicRouteC: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PublicRouteTableC DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway # ------------------------------------------------------------# # RouteTable Associate # ------------------------------------------------------------# PublicSubnetARouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetA RouteTableId: !Ref PublicRouteTableA PublicSubnetCRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetC RouteTableId: !Ref PublicRouteTableC PrivateSubnetARouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnetA RouteTableId: !Ref PrivateRouteTableA PrivateSubnetCRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnetC RouteTableId: !Ref PrivateRouteTableC # ------------------------------------------------------------# # Output Parameters # ------------------------------------------------------------# Outputs: # Subnet PrivateSubnetGroupName: Value: !Ref PrivateSubnetGroup Export: Name: !Sub sample-${SubName}-PrivateSubnetGroupName # Security Group AuroraSecurityGroupId: Value: !Ref AuroraSecurityGroup Export: Name: !Sub sample-${SubName}-AuroraSecurityGroupId まとめ いかがでしたでしょうか? VPC 作成テンプレートはどこにでもある情報だと思いますし、マネジメントコンソールでも以前より簡単に作れるようになっているので必要性は低いかもしれませんが、私は普段からこのテンプレートを活用して VPC をデプロイしています。 次回は Knowledge Base 用 Aurora Serverless のデプロイがテーマです。 本記事が皆様のお役に立てれば幸いです。
はじめに 今回はPythonで作成したAWS Lambda関数を保護するサーバーレスディフェンダーの導入方法を解説していきます。 サーバーレスディフェンダーには関数組み込み型とレイヤー型の2つの種類があり、今回は両方導入方法を解説していきたいと思います。 サーバーレスディフェンダーとは CWPP(Cloud Workload Protection Platform)の中の機能の一つでAWS LambdaとAzure Functionを保護するための機能です。 ※ARM64 アーキテクチャはサポートされていません 他のディフェンダー種類については こちら から確認できます。 何から保護してくれるのか Prisma Cloud のサーバーレスディフェンダーは、以下のリスクから AWS Lambda 関数を保護します。 プロセスアクティビティ ポリシーに対して、起動されたサブプロセスを検証することを可能にします。 ネットワーク接続 インバウンドとアウトバウンドの接続を検証し、明示的に許可されたドメインへのアウトバウンド接続を許可します。 ファイルシステムアクティビティ 関数がアクセスできるファイルシステムの部分を制御します。 サーバーレスディフェンダーに必要な通信経路 Lambda が Prisma Cloud の特定IP/ドメインと通信できる必要があります。 IPは日本リージョンの場合以下の通りになります。 詳細は こちら です。 通信方向 IPアドレス Egress 35.194.113.255 Ingress 35.200.123.236 関数組み込み型とレイヤー型の設定作業の違い 関数組み込み型とレイヤー型のそれぞれの作業概要を説明します。 関数組み込み型 Prisma Cloud コンソールからサーバーレスディフェンダー用ライブラリをダウンロードする Lambda関数のフォルダにサーバーレスディフェンダーのライブラリを配置する Lambda関数がサーバーレスディフェンダーを利用できるようにソースコードを追記する 環境変数を設定する レイヤー型 Prisma Cloud コンソールからサーバーレスディフェンダー用ライブラリをダウンロードする サーバーレスディフェンダー用のLambdaレイヤーを作成する すべての Lambda 関数にレイヤーを適用する 環境変数、ハンドラー設定を行う どちらが導入が簡単か レイヤー型の方が導入が簡単 です。一度レイヤーを作成すれば、Lambda関数ごとにライブラリを配置することや、コードを修正する必要が無くなります。 対応バージョンと対応言語 サーバーレスディフェンダー(AWS Lambda)の対応言語とバージョンは以下の通りです。 詳しくは こちら を参照ください。 言語 バージョン C#(.NET Core) 6.0 Java 8, 11 Node.js 14.x, 16.x, 18.x Python 3.6, 3.7, 3.8, 3.9 Ruby 2.7 サーバーレスディフェンダーの導入(関数組み込み型) 環境変数用の値を取得 左上の選択が「ランタイムセキュリティ」になっていることを確認します。 「ホーム」→ 左ペイン「MANAGE」→ 「Defenders」に行きます。 「Manual deploy」を押下します。 押下すると設定画面に遷移します。 変更した設定値は以下の通りです。 Method: Single Defender Defender Type: Serverless Defender – AWS 次に「Manual Deploy」に行き設定をします。 Runtime: Python Deployment type: Embedded Function name: defender-test Region: Tokyo            Runtimeは今回はLambdaでPythonを使用するのでPythonを指定しています。 同様に関数組み込み型を使用する場合は、Embeddedを指定します。 FunctionNameはLambdaの関数名と同じにします。 RegionはTokyoを指定しています。 ディフェンダーライブラリのダウンロード 「1. Download file」の「Command」か「Download file directly」どちらかでライブラリのダウンロードを行ってください。       ダウンロードしたライブラリを事前に解凍しておきます。           「3. Handler」の部分はのちに使用する部分ですが、今は使用しないのでスキップします。 TW_POLICYの生成 Lambdaの環境変数に使うTW_POLICYの生成を行っていきます。 「Generate」ボタンを押して、KeyとValueを保存しておきます。 サーバーレスディフェンダーの導入 以下サーバーレスディフェンダー導入前のLambdaのコードになります。 コード自体は本編に関係ないので深くは解説しませんが、S3内の特定ファイルにログを書き込むコードになっています。 import boto3 import json def lambda_handler(event, context): s3_bucket_name = 's3-lambda-log-test' s3 = boto3.client('s3') data = event['awslogs']['data'] if 'test' in data: print(f"Found 'test' in log data.") s3_key = f"log-data.json" s3.put_object(Body=json.dumps(data), Bucket=s3_bucket_name, Key=s3_key) return { 'statusCode': 200, 'body': json.dumps('Successfully processed log data.') } 1. Lambda関数の環境変数の設定 先ほどの「7.TW_POLICYの生成」で生成したKeyと値をLambdaの環境変数に入力します。 2. Lambda関数の修正 ライブラリの追加 最初に先ほど「6.ディフェンダーライブラリのダウンロード」にてダウンロードしたライブラリをLambdaに追加します。 先ほどダウンロードした「twistlock_serverless_defender.zip」を解凍します。 解凍し、中に入り「twistlock」というフォルダの中に入ります。 そうすると以下画像の3つのファイルがあることを確認します。 Lambda関数のファイルのダウンロードを行います。 「ファンクションコード .zip をダウンロード」を押下し、zipファイルをダウンロードし、解凍します。 解凍したファイルの末尾がランダムな英数字になっているので、元のLambda関数の名前に変更します。 1で解凍した「twistlock_serverless_defender」のディレクトリの中にある「twistlock」を今回ダウンロードしたLambda関数名のフォルダに入れます。 以下画像のようになれば大丈夫です。 lambda_function.pyとtwistlockを選択し、zip化します。 lambdaに先ほどzip化したzipファイルをアップロードします。 「コード」→ 画像右上の「アップロード元」→「.zipファイル」から先ほどのzipファイルを選択します。 以下画像のようになればライブラリの追加は完了です。 コードの修正 次にコードの修正をしていきます。 修正したコードは赤アンダーライン部分です。 先ほどLambdaにファイル追加した「twistlock.serverless」をimportして、「lambda_handler」関数をラップするとサーバーレスディフェンダーを関数に埋め込むことができます。 import boto3 import json import twistlock.serverless @twistlock.serverless.handler def lambda_handler(event, context): s3_bucket_name = 's3-lambda-log-test' s3 = boto3.client('s3') data = event['awslogs']['data'] if 'test' in data: print(f"Found 'test' in log data.") s3_key = f"log-data.json" s3.put_object(Body=json.dumps(data), Bucket=s3_bucket_name, Key=s3_key) return { 'statusCode': 200, 'body': json.dumps('Successfully processed log data.') } 3. 正常に Prisma Cloud と接続されているか確認 これで関数組み込み型のサーバーレスディフェンダーの導入が完了しました。 Lambda関数が1回動作しないとPrismaCloudコンソールに表示されないので1回動作させます。 Prisma Cloud コンソールで「ホーム」→「Defenders」に行くとLambda関数名が「Host」のところに出ているのが確認できます。   サーバーレスディフェンダーの導入(レイヤー型) 次はレイヤー型のサーバーレスディフェンダーの導入を行っていきます。 レイヤー用のzipファイルのダウンロード 左上の選択が「ランタイムセキュリティ」になっていることを確認します。 「ホーム」→ 左ペイン「MANAGE」→ 「Defenders」に行きます。 「Manual deploy」を押下します。 押下すると設定画面に遷移します。 変更した設定値は関数組み込み型と同じ以下の通りです。 Method: Single Defender Defender Type: Serverless Defender – AWS                   次に「Manual Deploy」に行き設定をします。 ManualDeployに行ったら以下を設定します。 Runtime: Python Deployment type: Layer Function name: defender-test Region: Tokyo 関数組み込み型とほとんど同様ですが、 Runtimeは今回はPythonを使用するのでPythonを指定しています。 Deployment typeはレイヤー型を使用する場合は、Layerを指定します。 Function nameはLambda関数名と同じにします。 RegionはTokyoを指定しています。 ディフェンダーライブラリのダウンロード Download fileのCommandかDownload file directlyどちらかでレイヤー追加用のzipファイルのダウンロードを行ってください。 TW_POLICYの生成 Lambdaの環境変数に使うTW_POLICYの生成を行っていきます。 「Generate」ボタンを押して、KeyとValueを保存しておきます。 レイヤーの追加 次はLambda関数にレイヤーを追加しますが、その前にレイヤーの作成を行います。 レイヤーの作成 「Lambda」→「レイヤー」→「レイヤーの作成」を押下していきます。 名前: twistlock .zipをアップロード: twistlock_defender_layer.zip 互換性のあるランタイム – オプション: python3.8 他はオプションなどは自由に選択などをしてください。 入力出来たら、「作成」を押下します。 名前はtwistlockを指定してください。 .zipをアップロードは先ほど「レイヤー用のzipファイルのダウンロード」の「5. ディフェンダーライブラリのダウンロード」でダウンロードしたzipファイルを選択してください。 互換性のあるランタイム – オプションはlambdaで使うランタイムを選択してください。 今回はpython3.8でLambda関数を作成したのでpython3.8を指定しています。 Lambda関数にレイヤーを追加する 「Lambda」→「(関数名)」→「コード」→ 一番下にある「レイヤー」→「レイヤーを追加」を押下します。 「レイヤーを選択」→「カスタムレイヤー」→先ほど作成した「twistlock」→ バージョンは最新のものを選択します 選択したら「追加」を押下します。 Lambda関数の環境変数の設定 関数組み込み型と同様に環境変数に設定するものがあるので設定します。 先ほど「6. TW_POLICY」で生成したKeyと値を環境変数に入力します。 次にORIGINAL_HANDLERを環境変数に追加する必要があるので追加します。 値には現在のハンドラ名を入力します。 「コード」→「ランタイム設定」→「ハンドラ」で現在のハンドラ名を確認できます。 デフォルトだと「lambda_function.lambda_handler」になっています。 ハンドラー設定の変更 次にLambda関数のハンドラー設定を変更します。 「コード」→「ランタイム設定」→「ハンドラ」に行きます。 ハンドラ: twistlock.handler ハンドラ名を変更したら「保存」を押下して保存します。 正常に Prisma Cloud と接続されているか確認 これでレイヤー型のサーバーレスディフェンダーを導入することができました。 関数組み込み型と同様でLambda関数を1回動作させないと Prisma Cloud コンソール上に現れないのでLambda関数を1回動作させます。 Prisma Cloud コンソールで「ホーム」→「Defenders」に行くとLambda関数名が「Host」のところに出ているのが確認できます。 おわりに 当社では、複数クラウド環境の設定状況を自動でチェックし、設定ミスやコンプライアンス違反、異常行動などのリスクを診断するCSPMソリューションを販売しております。 マルチクラウド設定診断サービス with CSPM| SCSK株式会社 CSPM | Smart One Cloud Security® Powered by Prisma Cloud from Palo Alto Networks | SCSK株式会社 ご興味のある方は是非、お気軽にお問い合わせください。
こんにちは、皆さん。 LifeKeeperの記事ではこれまで、製品に関する機能や利用用途についてご紹介してきました。 今回はそんなLifeKeeperとミドルウェアを組み合わせて、ミドルウェアにおけるニーズの高まりと 運用における可用性向上の方法についてご紹介していきたいと思います!   ミドルウェアにおける可用性ニーズについて 皆様は現在のパブリッククラウド環境において可用性の仕組みをどのように導入しており、 また、どんなミドルウェアの可用性を高めたいと考えておりますか。 先日、システム運用の関係者へWebアンケート(ITmedia)を実施した際、 このような結果がでました。 パブリッククラウド環境で可用性向上の仕組みを導入しているか? という質問に対して、70%近くのお客様が可用性を導入している、と回答がございました。 システムの稼働が止まってしまっては大変ですから、大半のお客様は可用性を高めているといった結果でした。   続いて、可用性を更に高めるためには具体的なミドルウェアの選定も重要となってきます。 そこで、特に可用性を高めたいと考えているミドルウェアは何でしょうか?と質問したところ、 Microsoft SQL Server、Oracle Database、MySQL といった重要なデータ基盤である データベース関連の可用性向上のニーズが高いことが判りました。   一方で、ここ5年くらいの傾向として ・JP1/AJS ・Zabbix ・HULFT ・SVF などの共通基盤系といったミドルウェアの可用性向上ニーズの広がりを感じています。 このような傾向があるミドルウェアの中でも、 今回は 「HULFT」 について 「LifeKeeper」で可用性を高める方法をご紹介していきます!   HULFTについて まず、HULFTについてご紹介いたします。 HULFTとは、主に企業間やシステム間でのデータ転送やファイル転送を行うためのミドルウェア製品です。 特徴としては5つあります。 1. 高い信頼性 データ転送の確実性が高く、エラーが発生した場合のリトライ機能や転送状況の確認機能を備える 2. セキュリティ データ暗号化や認証機能により、安全なデータ転送を実現 3. 多様なプラットフォーム対応 Windows、Linux、Unixなど、さまざまなOSに対応 4. 簡単な操作性 GUIを利用して簡単に設定や管理が可能であり、利用が簡易 5. 高いパフォーマンス 大容量データの転送や高速なデータ処理が可能   このような特徴を持つHULFTは、金融機関や製造業をはじめとする多くの業界で利用されており、 企業内外でのデータ連携を効率化するための強力なツールとして評価されています。   HULFT × LifeKeeper データ連携ツールであるHULFTはシステム全体において重要な役割を担っており、 運用において高い可用性が求められます。   運用中はサーバーの障害やソフトウェアの障害など、24時間x365日起こりうる障害への対策が必要となります。 そのため、障害対策として自動で検知し自動で復旧する事が望ましいです。   HULFTとLifeKeeperを組み合わせた構成イメージとしては以下のようになります。 このように、LifeKeeperを用いた高可用性ソリューションを組み合わせることで、 基幹系システムに求められるレベルの可用性の実現が可能となります。   製品ページ SCSKでは、上記で紹介したHULFT、そしてLifeKeeperの製品ページをご用意しております。   HULFT www.scsk.jp   「LifeKeeper」で安定稼働を実現 | SCSK株式会社 「LifeKeeper」は、システム障害時にあなたのビジネスを守るHAクラスターソフトウェアです。オンプレ環境だけでなく、パブリッククラウド環境での安定稼働の実現にも最適です。長年培ったSCSK独自のノウハウでお客様の課題解決に向け最適なご... www.scsk.jp   ご参考までに、HULFT8のライセンス価格と技術サポート一年パックの価格表(サポート種別ごと)の定価について掲載いたします。 待機系のライセンス価格につきましては、稼働系ライセンス価格の 半額 となっております。 ■ライセンス価格 対象OS 稼働系 待機系 Linux \650,000 \325,000 Windows \400,000 \200,000   ■通常技術サポート 対象OS 稼働系 待機系 Linux \98,000 \49,000 Windows \60,000 \30,000 ※通常技術サポート窓口の対応時間として、 月曜日~金曜日9:30~17:00(祝祭日及び年末年始を除く)   ■24/365技術サポート 対象OS 稼働系 待機系 Linux \196,000 \98,000 Windows \120,000 \60,000 ※24/365技術サポートサービスとして、24時間365日をサポート   最後に 今回は、ミドルウェアの可用性ニーズが高まってきていること そして、そのミドルウェアの中の「HULFT」という製品をご紹介させていただきました。 HULFTにLifeKeeperを用いることで高可用性が実現でき、業務の安定稼働に向けて一役買うことができたらと思います。
こんにちは。磯野です。 Cloud RunでPythonプログラムを実行する際、ログレベルをCloud Loggingへ反映させる方法をご紹介します。 はじめに Cloud Runのログは自動的にCloud Loggingへ反映される Cloud Runのログは、print文やloggingライブラリを使用して標準出力に文字列を出力すると 自動的に Cloud Logging に記録  されます。 しかし、このままだとすべてログレベルがデフォルトとなってしまいます。(下記画像参照) ↑WARNINGやERRORレベルのログも、デフォルトとして表示されている このままではエラー調査やフィルタの活用が難しくなってしまう、ということで、本記事ではログレベルの反映方法をご紹介します。 方法1:公式ドキュメントの記載方法を利用 下記を参考に設定します。 Python 用 Cloud Logging の設定  |  Google Cloud cloud.google.com コードの記載方法 ログの設定方法 import google.cloud.logging client = google.cloud.logging.Client() # 実行中の環境に基づいて Cloud Logging ハンドラを取得し、 # このハンドラを Python のログモジュールと統合します。 # デフォルトでは INFO レベル以上のすべてのログをキャプチャします。 client.setup_logging() ログの出力 import logging text = "Hello, world!" logging.warning(text) Cloud Loggingへの出力結果 無事にログレベルが反映されました。 ところが… 該当のCloud Runジョブ画面 >ログ という画面遷移であればログが表示されたのですが 該当のCloud Runジョブ画面 > 該当の実行ID > ログという画面遷移だと、ログが表示されませんでした。 labelsに”run.googleapis.com/execution_name”が付与されておらず、ジョブ単位にログをフィルタすることができなかったのが原因のようです。ジョブ単位にログをフィルタする必要がある場合は、方法2を推奨します。 ※こちらGoogleの不具合のようで、googleapiのgithub上で本件 issue になっていました。 追って解消されるかもしれません。 方法2: StructuredLogHandler ()を使用する コードの記載方法 ログの設定方法 import logging import google.cloud.logging from google.cloud.logging_v2.handlers import StructuredLogHandler logger = logging.getLogger() handler = StructuredLogHandler() logger.setLevel(logging.INFO) logger.addHandler(handler)   ログの出力 出力方法は方法1と同じため、割愛します Cloud Loggingへの出力結果 ログレベルの反映・labelsの付与ができました。   まとめ ログレベルの反映に苦労したので、記事にしました。 参考になれば幸いです。
こんにちは。SCSK株式会社の上田です。 今回は、Zabbixの監視で利用できる”正規表現”という機能の使い方を紹介します。正規表現を使うことで、複雑な条件にマッチするログの監視をすることが可能です。 正規表現とは 正規表現 とは、 文字列のパターンを表現するための記法 です。特定の文字列を検索したり、置換したりする際に使われます。 例えば、電話番号やメールアドレスのフォーマットに一致する文字列を抽出したり、 Sysログ等の大量の文字列の中から特定のキーワードを含む行を検索したりするときに、正規表現が使われます。 Zabbixにおける正規表現 Zabbixでは、 Perl互換の正規表現(PCRE、PCRE2) がサポートされています。これにより、柔軟なパターンマッチングが可能になっています。 Zabbixで主に使用される正規表現をいくつか紹介します。 正規表現 意味 . 任意の一文字 * 直前の文字の0回以上の繰り返し + 直前の文字の1回以上の繰り返し ? 直前の文字の0回または1回の出現 ^ 行の先頭 $ 行の末尾 [abc] a,b,cのいずれか一文字 [^abc] a,b,c以外 | いずれかの文字列に一致 \ エスケープ文字(直後の文字を、正規表現ではなく普通の文字列とする) これらを組み合わせることによって、文字列のパターンを表現します。 とはいえ、この表だけではピンとこないと思いますので、いくつか例を挙げてみます。 【 .* 】は、 任意の一文字 + それの0回以上の繰り返し ということで、 任意の0文字以上の文字列 を表します。 【 ^ zabbix .* test $ 】という正規表現は、 “ zabbix”で始まり”test”で終わる行 を表します。 【 \ [hoge \ ] 】という正規表現は、 “[hoge]”という文字列 を表します。ここで、 “[]” はそのままだと正規表現文字のため、 “[]” という文字自体にマッチさせたい場合はエスケープ文字の” \ “を使います。もしエスケープ文字が無ければ、 h,o,g,eのいずれか一文字 とマッチしてしまいます。 Zabbixでの正規表現の設定方法 ここまで正規表現とは何かについて説明してきました。続いてZabbixで正規表現を使う方法について説明します。 Zabbixでは、 アイテムキーに直接正規表現を書き込んだり 、 ユーザーマクロで正規表現を使ったり 、いろいろな場所で正規表現を使えます。 今回は、その中から グローバル正規表現 の使い方を説明します。グローバル正規表現の設定画面では、 ある文字列が作成した条件式にマッチするかのテストが実施できる ので、正しく正規表現が書けているかチェックできて便利です。 グローバル正規表現の設定方法 グローバル正規表現設定画面を開くには、ZabbixのWEBコンソールから 【管理 >一般設定 >正規表現】 と選択します。 正規表現の設定画面 デフォルトでいくつか正規表現が作成されています。 新しく正規表現を作成するために、右上のボタンをクリックします。 正規表現の作成画面 このような設定画面が開きます。 「文字列が含まれる」「いずれかの文字列が含まれる」「文字列が含まれない」 は、その名の通り入力した文字列が含まれるか含まれないかの条件を追記できます。 「結果が真」「結果が偽」 を選択すると、正規表現を使うことができます。 ここで、先ほど例示した正規表現を条件式に書いてみましょう。 条件式作成後の画面 これで、 【^zabbix.*test$】にマッチ し、かつ 【\[hoge\]】にマッチしない  という条件の正規表現が作成できました。 想定通りの条件になっているかテストしてみましょう。 以下の3つの文字列を考えます。  1:zabbixにおける正規表現のtest  2:zabbixにおける正規表現のtestです。  3:zabbixにおける[hoge]のtest これらは、作成した正規表現にマッチするでしょうか? 1は、 【^zabbix.*test$】にマッチ し、かつ 【\[hoge\]】にマッチしない ので、 マッチします。 ※最終結果が真ならマッチしている、偽ならマッチしていないことを表します。 テスト①   2は、 【^zabbix.*test$】にマッチしない ので、 マッチしません。 テスト②   3は、 【^zabbix.*test$】にマッチ しますが、 【\[hoge\]】にもマッチする ので、 マッチしません。 (hogeのテストって何だろう。。。) テスト③ トリガー条件式への正規表現の適用 これで正規表現が作成できたので、これをトリガー条件式に適用してみましょう。 正規表現を使いたいトリガーの設定画面を開きます。条件式に、以下のように記入します。 find (/host/key,,"regexp","@正規表現名") find関数は、アイテムから一致する値を見つける関数です。 通常では、第1パラメーターにホスト名とアイテムキーを指定し、第4パラメータに一致させたい値を入力しますが、第3パラメータに “regexp” を指定することで、第4パラメータで正規表現が使用できます。 正規表現を指定ときは、頭に “@” を付けます。 今回は、ホスト「Zabbix server」の/var/log/messagesを監視するアイテムに対してトリガーを設定してみます。 トリガーの設定画面 これで、作成した正規表現に一致するログが出力されたら障害を検知するトリガーが作成できました。 障害検知テスト 実際にログを出力させてみて、障害検知するか確認してみましょう。 監視対象ログに、正規表現に一致するログを出力させてみます。 # echo zabbixにおける正規表現のtest >> /var/log/messages 出力したログが、アイテムとして取得されると。。。 ログアイテムの取得状況 想定通り、障害検知しました! 障害検知結果 まとめ 今回は、Zabbixにおける正規表現の使い方と、ログ監視への適用方法をまとめました。今回は簡単な正規表現を作ってテストしましたが、うまく活用すればより複雑な条件で検知したいログを絞ることが可能です。 実際のログ監視への活用方法については、また別の記事でまとめようと思っています。 最後まで読んでいただき、ありがとうございました。   弊社ではZabbix関連サービスを展開しています。以下ページもご参照ください。 ★SCSK Plus サポート for Zabbix★ SCSK Plus サポート for Zabbix 世界で最も人気のあるオープンソース統合監視ツール「Zabbix」の導入構築から運用保守までSCSKが強力にサポートします www.scsk.jp ★YouTubeに、SCSK Zabbixチャンネルを開設しました!★ SCSK Zabbixチャンネル 本チャンネルでは、SCSK株式会社でのZabbixに関するトレンド/事例紹介などを動画にまとめて取り上げております。 最新のトピックについては、以下の弊社HPもしくはツイッターアカウントをぜひ参照ください。 ツイッターアカウント: www.youtube.com ★X(旧Twitter)に、SCSK Zabbixアカウントを開設しました!★ x.com X.com
こんにちは、ひるたんぬです。 最近は耐え難い暑さが続いておりますね… 私はとても暑さに弱い生物なので、ひと月ほど前からエアコンの恩恵にあずかっているのですが、エアコンの設定温度ってとても難しいなと思っています。 というのも期待した温度にならないのです。28℃に設定してるのに25℃近くになったり、逆に30℃くらいになったり… エアコンも暑さでおかしくなってしまったのでしょうか…?今夏を乗り越えてくれるよう切に願っています。 さて、今回は業務でSDK(boto3)に触れている中で、ふと気になった点について調査をしました。 気になったこと Secrets Managerからシークレットを取得したい!と思った際、マネジメントコンソールでは各言語でのサンプルコードを示してくれています。(とても親切!!)例えば、Python3(boto3)の場合は以下のようになっています。 # Use this code snippet in your app. # If you need more information about configurations # or implementing the sample code, visit the AWS docs: # https://aws.amazon.com/developer/language/python/ import boto3 from botocore.exceptions import ClientError def get_secret(): secret_name = "SECRET_NAME" region_name = "REGION_NAME" # Create a Secrets Manager client session = boto3.session.Session() client = session.client( service_name='secretsmanager', region_name=region_name ) try: get_secret_value_response = client.get_secret_value( SecretId=secret_name ) except ClientError as e: # For a list of exceptions thrown, see # https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html raise e secret = get_secret_value_response['SecretString'] # Your code goes here. このコードを見て、私は「 boto3.session.Session()ってなんぞや? 」と思いました。 そう、この記述とはここで会ったのが初めてだったのです。 boto3のSessionとは こういうときに役に立つのは、やはり公式ドキュメントですね。 Boto3の公式ドキュメントには次のように記載があります。 A session stores configuration state and allows you to create service clients and resources. 引用:AWS 「 Boto3 1.34.146 documentation -Session reference- 」 つまり、アクセスキーやシークレットキーなどの認証情報を一つのオブジェクトとしてまとめて生成し、それをクライアントやリソースオブジェクトの生成時に引数として指定することで使い回すことができる、という仕組みのようです。複数のクライアントやリソースオブジェクトを生成する際に、いちいち認証情報を入力しなくて済むので、これは便利な機能ですね。 さらなる疑問 Sessionについて調べる中で、公式ドキュメント内でSessionを以下のように使っている場合もありました。 # Explicitly create a new Session for this thread session = boto3.Session() dynamodb = session.resource('dynamodb')   Python と Boto3 による Amazon DynamoDB のプログラミング - Amazon DynamoDB Python で DynamoDB をプログラミングする方法に関するさまざまな概念について説明します。 docs.aws.amazon.com そうです、”session”が一つ欠けているのです。こういうのすごく気になってしまうんですよね… こちらについては、結論から言いますと同じオブジェクトを指しておりました。 せっかくなので、boto3のソースコードを見て確認してみましょう。 今回は執筆時点での最新バージョンである「1.34.146」のコードで確認しています。 GitHub - boto/boto3 at 1.34.146 AWS SDK for Python. Contribute to boto/boto3 development by creating an account on GitHub. github.com boto3.session.Session()と記載する場合 この場合は、boto3フォルダにある”session.py”を参照し、Sessionクラスを呼び出しています。 boto3.Session()と記載する場合 この場合は、boto3フォルダにある”__init__.py”を参照します。 するとこのファイルの17行目に from boto3.session import Session と記載があります。これによって、boto3フォルダにある”session.py”を参照し、Sessionクラスを呼び出していることが分かりましたね。 おわりに 細かいところが気になってしまう性分なのでしっかり調べました。 こういうことを一つずつ知るたびに成長しているなぁ…と実感できて嬉しいです。 余談ですが、botoの名前の由来は「アマゾン川に自生する淡水イルカ(アマゾンカワイルカ)」だそうです。 アマゾンカワイルカ|海棲哺乳類データベース www.kahaku.go.jp また、Boto 3 の数字はライブラリのメジャーバージョン(3番目)を示しているようです。 下記サイトに載っていたのですが、なぜDynamoDB上のドキュメントにBotoの由来などが記載されているのでしょうか…謎は深まるばかりですね。 Python と Boto3 による Amazon DynamoDB のプログラミング - Amazon DynamoDB Python で DynamoDB をプログラミングする方法に関するさまざまな概念について説明します。 docs.aws.amazon.com