Stripe: 【3Dセキュア2.0対応】Stripe.jsのconfirmCardPayment()の内部動作を調べました
背景
- 2025/4/1より3Dセキュアが義務化されました
- Stripeが3DS対応を全てを吸収してくれる訳ではなく、一部、加盟店側で実装の修正が必要
- 加盟店
- アクワイアラー(中間業者=Stripe)を通じて、カードブランド(VISA、Mastercardなど)の決済ネットワークに加盟し、カード決済サービスを受ける事業者(サービス提供者)
- 加盟店
- 実装の際、
Stripe.jsのconfirmCardPayment()の内部動作を調べたのでメモ- 内部動作を調べた事で3DSの理解が深まりました!
ドキュメント、参考ブログ
- Stripeのドキュメント (※私は、以下のドキュメントが全く読解できず、非常に苦戦しました...(結局、コードを書いて理解した))
- 参考になったブログ
結論
- Stripe.js を通じて、Stripeがカード発行会社(イシュアー)のサーバと連携して認証をおこなっている
前提①: 3Dセキュア (英語: 3-D Secure) とは?
- ネットでクレジットカード決済するときの本人認証
- 3つのドメインで連携して本人認証を行う仕組み
要するに...
- クレジットカードに記載されている情報(カード番号、氏名、署名コード)だけで決済できてしまうと、カードを見られてしまったら不正利用されてしまうので、「クレジットカードに記載されていない情報(=TOTPなど)」での本人確認も行う事で、不正利用をブロックする、という仕組み
- 典型例
- ネットでクレジットカードで決済したときに、スマホに認証コードが飛んでくる
3つのドメイン
流れ
3DS 1.0vs3DS 2.01.0※旧方式- 予め登録したパスワードで、決済の度に毎回必ず認証
2.0- TOTP等に対応、リスクベースで認証
- リスクが低い場合は認証がスキップされる
- TOTP等に対応、リスクベースで認証
前提②: Stripe.jsのconfirmCardPayment()を利用して3DS認証画面を表示する方法
- 決済時に3DS認証が発生すると、
payment_intent.statusがrequires_actionになる- この際、Stirpeのeventとしては
payment_intent.requires_actioneventが発生する (※1) payment_intent.client_secretでクライアントシークレットが返される
- この際、Stirpeのeventとしては
1.のクライアントシークレットを、Stripe.jsのconfirmCardPayment()の第一引数に渡すconfirmCardPayment()から Promise で3DS認証後の paymentIntentが返される- paymentIntent.status等を参照すれば、3DS認証に成功したがどうかを識別できる
※1 payment_intent.requires_action イベントのイベントデータ
{
"object": {
"id": "pi_***",
"object": "payment_intent",
//...
"client_secret": "pi_***_secret_***",
//...
"status": "requires_action",
//...
}
}
実装イメージ
import { loadStripe } from '@stripe/stripe-js'
// ...
// 3Dセキュア認証が必要な場合
if (currentPaymentIntent?.status === 'requires_action') {
const clientSecret = currentPaymentIntent.client_secret
const stripeApiPublicKey = process.env.NEXT_PUBLIC_STRIPE_API_PUBLIC_KEY
const stripe = await loadStripe(stripeApiPublicKey)
// モーダルで3DS認証画面を表示
const { error: stripeError, paymentIntent } = await stripe.confirmCardPayment(clientSecret)
// 3DS認証が成功した場合
if (paymentIntent?.status === 'succeeded') {
//...
} else {
// 3DS認証に失敗した場合
//...
}
Stripe.jsのconfirmCardPayment()の内部動作の調査方法
- ドキュメントから把握
- https://docs.stripe.com/js/payment_intents/confirm_card_payment
- 内部的な動作に関しては記述がなさそう
- https://docs.stripe.com/js/payment_intents/confirm_card_payment
- コードから把握
- https://js.stripe.com/v3 の
confirmCardPaymentメソッドを分析- ※@stripe/stripe-jsを利用すると
<header></header>内に以下のscriptが読み込まれる<script src="https://js.stripe.com/v3"></script>
- => 理屈的にはソースコードから分析可能そうだが、minify されてるので現実的にはツラそう
- ※@stripe/stripe-jsを利用すると
- https://js.stripe.com/v3 の
- Stripe.jsによるリクエスト内容から把握
- => この方法で推論する事にした
Stripe.jsによる3DS認証関連のリクエスト内容
POST https://api.stripe.com/v1/payment_intents/:id/confirmPOST https://api.stripe.com/v1/3ds2/authenticateStripe.jsがiframe内にacsURLを読み込み事で、ifreme内に「3DS認証用の画面」を表示- この画面で、ユーザーが TOTP などを入力し、認証を通す
iframe内にacsURLが読み込みこまれている様子
Stripe.jsがiframe内にacsURLを読み込んでいる様子
POST https://api.stripe.com/v1/3ds2/challenge_complete- このリクエストで、イシュアーの認証結果(=この場合は認証OK)を、Stripeのサーバー側に送信 (してるんだと思う)
GET https://api.stripe.com/v1/payment_intents/:id?is_stripe_sdk=false&client_secret=:シークレット- 3DS認証完了後のStripe PaymentIntens オブジェクトを取得
- これが
Stripe.jsのconfirmCardPayment()のPromiseとして返される
- これが
- 3DS認証完了後のStripe PaymentIntens オブジェクトを取得
読書メモ: うまくてダメな写真とヘタだけどいい写真
所感
- 写真の話としてより、アーティストとして自分を揺さぶられる内容が多かった
- 本質は写真も音楽も一緒ですね
MEMO
- ヘタだけど良いもの、を目指したほうが圧倒的によい
- うまい写真 ≠ いい写真
- 感動していないならシャッターを押す意味がない
- 普段目にする景色がつまらなく見えるのは、自分がつまらないから
- 写真以外から写真を学ぶ
- 写真がうまくなる前に「いい写真とはなにか?」を考える
- 写真を映画など(=写真以外)から学んだほうがよい
- 露出、構図 -> 勉強すればわかるし、大変な勉強でもない -> うまくなった気になるだけ
- 写真がうまくなる前に「いい写真とはなにか?」を考える
- 家族写真
- 子どもの楽しさを邪魔しない
- 写真をとるときは絶対に声をかけない
- 子どもの楽しさを邪魔しない
- AIで生成できるものを作っている人は淘汰される
- 逆にAIで作れないものを作れれば価値が上がる
- AIにできることはAIに任せて別の道を進むこと
- 同じ話を何度もする人は経験が乏しい
- 打ち上げで写真以外の話をすること
- 面白い話 = 相手が知らない話
- つまらない話 = すでに知っている話
- 趣味の話は道具の話になりがち
- 道具を使って「どんな経験をしたか」を会話するように心がけましょう
- 道具の話は補足程度
- カメラをやるんじゃなくて写真をやる
- カメラなんかなんでもよい
- 言葉で伝える
- 「写真を見た人が自由に感じてほしい」だと見る人は困る
- 良い作品 = 感情が伝わる作品
- 説明文がないと感情を伝えることができない
- 言葉
- 感情をわかりやすく説明
- ポエムではなく、小学生でも理解できる言葉で
- 写真に写っているものの説明ではない
- OK: 家族で行った遊園地。小学生になった息子はお父さんの前をいくようになった
- NG: 子どもとブランコ
- 感情をわかりやすく説明
- 「自分の好き」を積み重ねる
- 自分の好きがわからない人は、みんなが好きなもの(=バズる、バエる、エモい)をマネる
- マグレを分析する
- 300枚とればマグレあたりが1枚はある
- その写真をよく見る
- 太陽がどこにあったか思い出す
- そうしたらもう一度、同じ条件で撮る。マグレだった写真をもう一度狙う
読書メモ: コード×AIーソフトウェア開発者のための生成AI実践入門
コード×AIーソフトウェア開発者のための生成AI実践入門(amazon)
所感
- TODO
1 章
AIの仕組みを理解する事がAI活用の第一歩
プロンプトエンジニアリング- AIとの対話を最適化するためのテクニック
- 安定性、精度の追求
- ※テクニックは銀の弾丸ではない、AIへの理解がより重要
-
- 10分目を通せば、一通りのテクニックを把握できる
AIによりエンジニアがいらなくなるのでは?
- NO。むしろ役割は拡大
- 例: クラウド -> インフラエンジニアは不要にならず、役割が拡大
- NO。むしろ役割は拡大
ハルシネーション- 生成AIが事実と異なる内容をもっともらしく出力すること
- AIの使用者のレビューが不可欠
- 生成AIが事実と異なる内容をもっともらしく出力すること
トークンコードレビュー
- AI活用にあたり、人間が可能なレビュー数の限界 の考慮が必要
- 自分の限界を理解し、適切な量のレビューを行う事が鍵
- 1時間あたり、500 行以内
- 適量を、ゆっくと、限られた時間内で行うと効果的
- AI活用にあたり、人間が可能なレビュー数の限界 の考慮が必要
AIとの会話を通じて早く答えにたどり着く
- 3 回程度の迅速な試行で見極める
- なんども試行を繰り返す事は時間の無駄
- 3 回程度の迅速な試行で見極める
開発支援AIツールの特性と限界を理解し、状況に応じて使い分ける
開発支援AIのタイプ
- 自動補完型
GitHub Copilot
- 対話型
ChatGPT
- エージェント型
GitHub Copilot Workspace
- 自動補完型
今後
- 「みんなができないこと」をAIで実現する事が重要
- みんなが使ってるAIツールを導入する事は差別化にはならない
- how
- AIが使うためのデータを用意し、企業として育てる
- 「みんなができないこと」をAIで実現する事が重要
「コストカット」や「生産性向上」に目を奪われて、「価値創造」の機会を見逃さない
- 「コストカット」「生産性向上」は取り組みやすいが、既存の範囲内での改善にとどまる
2 章
- TODO
3 章
- TODO
4 章
- TODO
5 章
- TODO
6 章
- TODO
7 章
- TODO
8 章
- TODO
9 章
- TODO
AWS Certified Solutions Architect (SAA-C03) 認定試験向けのメモ
サービス
分析
Amazon Athena
- S3 上のデータに対して 標準SQL を実行できるデータ分析サービス (サーバレス)
Amazon Redshift
- DWH (ペタバイト級のストレージに対応)
AWS Data Exchange
AWS Data Pipeline
AWS Glue
-
- ストリーミングデータのリアルタイム処理
- Data Streams
- 外部から送信されるストリーミングデータを収集
- 大量のリアルタイム性の高いデータ処理
- ストリーミングデータを直接読み取り、カスタムアプリケーション(Kinesis Data Analytics や Lambda)でリアルタイム処理
- データの保存や検索はできない
- Data Firehose
- リアルタイムのストリーミングデータを取り込み、Amazon S3、Amazon Redshift、Amazon OpenSearch Serviceなどへ配信
AWS Managed Service for Apache Flink (旧 Kinesis Data Analitics)
AWS Lake Formation
Amazon OpenSearch Service (Amazon Elasticsearch Service)
Amazon QuickSight
- 様々なデータソースを基にダッシュボードやレポート、グラフを作成してデータを可視化するサービス
アプリケーション統合
Amazon EventBridge (Amazon CloudWatch Events)
- AWSアカウント内で発生したイベントを検知し、アクションを自動実行
Amazon MQ
AWS Step Functions
- ワークフローを作成して実行
Amazon AppFlow
- 様々なSaaSアプリケーション(例:Salesforce、ServiceNow、Slackなど)と、AWSサービス(例:Amazon S3、Redshift、DynamoDBなど)間でデータを安全に転送できるフルマネージドサービス
- デフォルトでAWSのKey Management Service(KMS)が有効になっており、データは保存時および転送中に暗号化される
- 様々なSaaSアプリケーション(例:Salesforce、ServiceNow、Slackなど)と、AWSサービス(例:Amazon S3、Redshift、DynamoDBなど)間でデータを安全に転送できるフルマネージドサービス
AWS AppSync
AWS コスト管理
コンピューティング
AWS Batch
- バッチ処理を実行する為の使い捨ての実行環境
Amazon EC2 Auto Scaling
AWS Elactic Beanstalk
- WEBアプリケーションを簡単にAWSに構築
- アプリケーションが動作する定番の構成を提供
- CloudFormation と似ているが、テンプレートの作成の必要がない
- WEBアプリケーションを簡単にAWSに構築
AWS Outposts
AWS Serverless Application Repository
AWS Wavelength
コンテナ
Amazon ECR (Amazon Elastic Container Registry)
- コンテナレジストリ (マネージド)
Amazon ECS (Amazon Elastic Container Service)
- コンテナタスクの起動場所として、EC2 を使用
- 必要な設定が全て入った EC2 を使用
- 要素
- クラスター
- タスク
- ECSで管理するコンテナの実行単位
- サービス
- コンテナタスクの起動場所として、EC2 を使用
Amazon ECS Anywhere
Amazon EKS (Amazon Elastic Kubernetes Service)
- k8s
- コンテナオーケストレーションプラットフォーム
- k8s
Amazon EKS Anywhere
AWS Fargate
- memo
- コンテナタスクの起動場所として、EC2を使わない
- memo
データベース
Amazon RDS
- 自動バックアップ
- 最大 35 日
- それ以上は AWS Backup で
- 最大 35 日
- RDS for SQL Server
- Microsoft SQL Serverの一部機能(データベースのログ配布やネイティブスナップショット)はサポートしていない
- SQL Serverのすべての機能を利用した場合は、EC2インスタンスにMicrosoft SQL Serverをインストールする必要がある
- Microsoft SQL Serverの一部機能(データベースのログ配布やネイティブスナップショット)はサポートしていない
- 備考
- オンプレからのインポート
- オンプレの PostgreSQL から、RDS for PostgreSQL へ直接インポートはできない
- => 一旦、S3にダンプファイルをおいて、インポート
- オンプレからのインポート
- 自動バックアップ
-
- データベースクラスタ
Amazon Aurora Serverless
- 自動でスケール
-
- KVS
- グローバルテーブル
- 複数のリージョンにまたがって運用できる
- DynamoDB Streams
- テーブルに対して行われた直近の24時間の変更(追加や更新、削除)をログに保存する機能
- 非同期で動作するため、ストリームを有効にしても元のテーブルのパフォーマンスには影響を与えない
- テーブルに対して行われた直近の24時間の変更(追加や更新、削除)をログに保存する機能
Amazon ElastiCache
Amazon Redshift
- DWH (ペタバイト級のストレージに対応)
Amazon DocumentDB (with MongoDB compatibility)
Amazon Keyspaces (for Apache Cassandra)
Amazon Neptune
- グラフデータサービス (マネージメントサービス)
- 関係性、相関情報を扱う (SNS、レコメンデーションエンジン)
- グラフデータサービス (マネージメントサービス)
Amazon Timestream
マネジメント と ガバナンス
AWS CloudWatch
AWS Auto Scaling
AWS CloudFormation
AWS CloudTail
AWS Config
- AWSリソースの設定情報を記録
AWS Management Console
AWS Organizations
AWS Systems Manager
AWS Trusted Advisor
- ユーザーのAWSアカウント環境の状態を自動チェック
- コスト削減やパフォーマンス向上の推奨事項を提供
AWS Compute Optimizer
- コンピューティングリソースの設定と使用状況を分析し、コスト最適化とパフォーマンス向上のための推奨事項を提供
AWS Managed Grafana
AWS Managed Service for Prometheus
AWS Service Catalog
- 主にCloudFormationテンプレートを製品として登録し、他のAWSユーザーへ共有できるサービス
- 製品の管理者は、製品のバージョンや、製品がいつ・誰に使用されたかを一元的に管理できる
- 主にCloudFormationテンプレートを製品として登録し、他のAWSユーザーへ共有できるサービス
AWS Proton
- マイクロサービスやコンテナ化されたアプリケーションのインフラ管理を自動化
- 開発チームが標準化されたテンプレートを使って、インフラのプロビジョニングやデプロイを効率的に行えるようにする
- マイクロサービスやコンテナ化されたアプリケーションのインフラ管理を自動化
AWS Well-Arhcitected Tool
フロントエンドの WEB と Mobile
デベロッパーツール
メディアサービス
機械学習
Amazon Comprehend
Amazon Forecast
- 時系列予測 (フルマネージドサービス)
- memo
- 機械学習の知識がなくても容易に利用できる
Amazon Fraud Detector
Amazon Kendra
Amazon Lex
Amazon Polly
Amazon Rekognition
Amazon SageMaker
Amazon Textract
- ドキュメント(PDFなど)からテキストを抽出
Amazon Transcribe
- 音声データをテキストに変換
Amazon Translate
移行 と 転送
AWS Snow Family
AWS Application Discovery Service
AWS Applicatiion Migration Service (CloudEndure Migration)
AWS DMS (AWS Database Migration Service)
- memo DBスナップショットからの移行は行えない
AWS DataSync
AWS Migration Hub
AWS Transfer Family
セキュリティ、アイデンティティ、コンプライアンス
AWS KMS (AWS Key Management Service)
- データを暗号化するための鍵を作成・管理
AWS Secrets Manager
AWS WAF
AWS Shield
- DDoS 保護
Amazon GuardDuty
Amazon Inspector
- 脆弱性を検出
AWS CloudHSM
Amazon Cognito
- Webアプリケーション、モバイルアプリケーションのエンドユーザーを管理
- 機能
- Cognito ユーザープール
- SingUp, SignIn
- Cognito ID プール
- Cognito ユーザープール、または Goolge,Fackbook など他の IDP で SignIn したユーザーに、IAMロールを連携させることで、AWSサービスへのアクセス権限を付与
- Cognito ユーザープール
AWS Artifact
AWS Audit Manager
- 監査業務の為のエビデンスを自動収集
Amazon Detective
AWS Directory Service
- Active Directory (マネージドサービス)
Amazon Macie
- S3バケット内のデータ保護
- 個人情報(PII)や秘匿技術などの機密データを識別・分類
AWS Security Hub
- Macie, GuardDuty, Inspector などのイベントを集約し、ダッシュボードで管理
ネットワーク と コンテンツ配信
AWS Route 53
- フェイルオーバールーティングポリシー
- ヘルスチェック
- ホストゾーン
- パブリックホストゾーン
- 公開インターネット向け
- プライベートホストゾーン
- 内部ネットワーク専用
- パブリックホストゾーン
ELB (Elastic Load Balancing)
AWS Global Accelerator
-
- 複数のVPCやオンプレミスネットワークを一元的に接続・管理するためのハブ型ネットワーキングサービス
- 大規模なネットワーク構成をシンプルにし、管理を効率化
- 複数のVPCやオンプレミスネットワークを一元的に接続・管理するためのハブ型ネットワーキングサービス
AWS Direct Connect
AWS PrivateLink
サーバレス
ストレージ
Amazon S3 Glacier
- ストレージクラス
- Interlligent - Tiering
- アクセスパターンが変化、不明
- xxx IA (Infrequent Access)
- 頻繁にはアクセスされないが、必要なときに迅速にアクセスできる必要があるデータの保存に最適化
- Flexible Retrieval
- IA より低価格
- Deep Archive
- データの取り出しに長時間がかかる
- 標準取り出し
- 最大 12 時間
- 大容量取り出し
- 最大 48 時間
- 標準取り出し
- データの取り出しに長時間がかかる
- Interlligent - Tiering
- ストレージクラス
Amazon FSx (すべてのタイプに対応)
AWS Backup
- ストレージやデータベース等のバックアップを一元管理 (フルマネージド サービス)
- 以前はサービスごとに行っていたバックアップ作業を統合できる
- memo
- 全体のシステムやアーキテクチャのバックアップ・リストアの目的では利用できません
- ストレージやデータベース等のバックアップを一元管理 (フルマネージド サービス)
その他
用語
ベアメタル環境
- 仮想化技術を使用せず、物理的なコンピューターハードウェア上に直接インストールされたオペレーティングシステム(OS)やアプリケーション
ワークロード
- ビジネス価値をもたらすリソースとコード (顧客向けアプリケーションやバックエンドプロセスなど) の集合のこと
ETL
- Extract(抽出)、Transform(変換)、Load(ロード)の頭文字をとった略語
- さまざまなソースからデータを抽出し、取り扱いやすい形にデータを変換し、DWH などのデータシステムに書き出すプロセス
フェデレーション
- 複数の異なるドメインや組織間で、ユーザーの認証情報を共有・統合する仕組み
- => 「SSO」を「異なる組織間」で可能にするための技術や枠組み
- 複数の異なるドメインや組織間で、ユーザーの認証情報を共有・統合する仕組み
ACL vs セキュリティーグループ
DataSync vs Storage Gateway
転送時間
暗記しておくとよいこと
- 1TB のデータを 1Gbps で転送すると、約 2.2 H かかる
- 600TB を 600 Mbps で転送 の計算
- 2.2 × 600 / 0.6 = 2,200 H
600TB を 600 Mbps で転送
- 94 日
- 計算式
- 600TB を bit に変換
- 600,000(T),000(G),000(M),000(k) * 8
- = 4,800,000(T),000(G),000(M),000(k)
- 4,800,000(T),000(G),000(M),000(k) / 600,000(M),000(k)
- 4,800,000,000 / 600
- 48,000,000 / 6
- 8,000,000 s
- 8,000,000 s
- = 8,000,000 / 3,600
- 2,222 H
- 92 日
- 600TB を bit に変換
8TB を 300 Mbps で転送
- 2.2 H * 8 / 0.3
- 58 H
- 2.4 日
- 2.2 H * 8 / 0.3
MUIのスタイリング方法
MUI v5
- スタイリングは
Emotionorstyled componentsを利用できる
CSS-in-JSライブラリ
JSS (JavaScript Style Sheets)
- MUI v4 では makeStyles と JSS を組み合わせてスタイリング
- MUI v5 で makeStyles が非推奨になった
- MUI v4 では makeStyles と JSS を組み合わせてスタイリング
styled components
- CSS-in-JS(JavaScript内でCSSを記述すること)のためのライブラリ
- JavaScriptのテンプレートリテラルを使用してスタイルを定義できる
- MUI v5 で利用可能
Emotion
- CSS-in-JS(JavaScript内でCSSを記述すること)のためのライブラリ
- JavaScriptのオブジェクトやCSS構文を使用してスタイルを定義できる
- MUI v5 で利用可能
MUI v5 でのスタイリング方法
(MUIの) sx prop
- https://mui.com/system/getting-started/the-sx-prop/
- スタイルの指定方法
- オブジェクトとしてスタイルを指定
(MUIの) css prop
- 以下のいずれかで生成したスタイルオブジェクトを渡すことが可能
- MUIのデフォルトのスタイリングエンジン(
@mui/styled-engine)- https://mui.com/system/styled/
- 内部で Emotion を使用
- https://mui.com/system/styled/
- Emotiom(
@emotion/react)- https://emotion.sh/docs/css-prop#string-styles
- スタイルの指定方法
- 文字列としてCSSを指定
- styled-components(
@mui/styled-engine-sc)
- MUIのデフォルトのスタイリングエンジン(
- 以下のいずれかで生成したスタイルオブジェクトを渡すことが可能
sx propvscss prop- スタイルを別ファイルに分ける必要が無いような軽微なスタイリングは sx prop を使用すると良さそう
Laravel: Facade vs Contract
自分の言葉で言語化してメモ
Facade vs Contract
- Facade と Contract はどちらも Laravel のコア機能を使う為の方法である
Facade
- what
- Laravelのコア機能をサービスコンテナを介さずに利用できる静的なインターフェース
- メリット
- サービスコンテナを意識することなくサービスに簡単にアクセスできる
- デメリット
- インジェクション(コンストラクタインジェクションまたはメソッドインジェクション)なしで利用できてしまう為、依存性の管理が難しくなり、テストが困難になる
※とはいえ、Facade も Laravel の内部でサービスコンテナに登録されてる
See: \Illuminate\Foundation\Application::registerCoreContainerAliases
Contract
- what
- Laravelのコア機能のインターフェース
- 開発者は、ServiceProviderでContract(Interface)と実装クラスを明示的にbindする事で、サービスコンテナ経由でコア機能を利用する事ができる
- メリット
- 依存性の注入ができる為、疎結合になる
- テストがしやすくなる
- デメリット
- サービスコンテナでのbindが必要
用語
Contract vs Interface
Laravelにおいて Contract(契約) という用語は、サービスコンテナに登録するために使用される Interface を指す
- Contract (契約)
- Laravelのコア機能のInterface
- 言い換えると、サービスコンテナに登録するサービスのInterface
Azure Application Insights への特定のログ出力を Azure Monitor で監視し、Slack 通知する方法
先日、Azure Function の異常終了を検知し、Slack に通知する仕組みを構築しました。
今回は、Azure Application Insights に特定のログが出力されたら Slack に通知する仕組みを構築する手順を書きます。
使用するもの
- Slack
- 通知を受けるチャンネル
- Incoming Webhook
- Azure
- Azure Application Insights ※エラーログの出力先
- Azure Monitor ※エラーログを監視する
- アクショングループ
- アラートルール
- Logic App ※エラーログ発生時に、Azure Monitor からトリガーし、Slack Incoming Webhook にメッセージを送信
概要
- Azure Function が異常終了すると Azure Function に severityLevel が 3 のログ(※1)が出力される
- Azure Monitor の アラートルール で上記のログの出力を監視
- ログを検知したら、アラートルール の アクショングループ から Locig App をトリガーする
- アラートルールから直接、Slack の Incoming Webhook にメッセージを送信できない為、Locic Apps 経由で送信します
- Logic Apps で Slack の Incoming Webhook に対応した payload を生成して送信する必要がある
- アラートルールから直接、Slack の Incoming Webhook にメッセージを送信できない為、Locic Apps 経由で送信します
- Logic Apps から Slack の Incoming Webhook にメッセージを送信
※1 のログを検索する KQL
traces | where operation_Name contains "対象Function名" and message contains "Executed 'Functions.対象Function名'" and severityLevel != 1
構築手順
- Incoming Webhook の URL を取得
- (Azure Monitor から Logic App に送信されるペイロードを取得しておく)
- Logic App を作成
- Azure Monitor の アクショングループ を作成
- Azure Monitor の アラートルール を作成
0. 監視対象の Azure Function を作成
- 今回はログ監視の構築が主旨の為、Azure Portal 上でTimer Trigger の Function を作成し、5分毎に実行結果のログが Application Insights に出力されるようにしておきます

1. Incoming Webhook の URL を取得

- 後ほど Logic App からの送信先に指定しますので、Webhook URL をコピーしておきます。

2. Azure Monitor から Logic App に送信されるペイロードを取得
※後ほど、Logic Appのワークフローで送信するSlack通知メッセージに、アラート内容等を含める為に、
要求本文のJSONスキーマの作成が必要になります-
要求本文のJSONスキーマの作成に、実際のペイロードが必要な為、予め取得しておきます
-
公式ドキュメントにペイロードのサンプルがあるので、どのサンプルが利用できれるかを予め把握できている場合は
手順 2.はスキップしてok です。- 今回は結果的に アラートのペイロードのサンプル - テスト アクション ログ アラート V2 を利用できる事がわかりました。
取得方法としては、Logic Appを仮設定で作成し、アクショングループの作成(手順 4.)、及び、アラートルールの作成(手順 5.)を行い、一度、実際にペイロードを受信します
トリガーを
HTTP要求の受信時とし、要求本文のJSONスキーマを{}で作成します- (ここではペイロードが取得しただけなので) 以降のアクション(=
HTTPの部分)は未設定でもok
- (ここではペイロードが取得しただけなので) 以降のアクション(=
(アラートルールからLogic Appがトリガーされるのを待つ)
Logic Appsの実行履歴より、ペイロードを取得します
HTTP要求の受信時の出力の本文がペイロード
採取したペイロード
- 公式ドキュメントの アラートのペイロードのサンプル - テスト アクション ログ アラート V2 の内容になっている模様
{
"schemaId": "azureMonitorCommonAlertSchema",
"data": {
"essentials": {
"alertId": "/subscriptions/c86f8ad8-7f32-4f84-8cf5-9ba182bd2a40/providers/Microsoft.AlertsManagement/alerts/ddc294f2-8510-62be-114c-4fd9e3300027",
"alertRule": "TimerTrigger1関数のエラー終了",
"severity": "Sev2",
"signalType": "Log",
"monitorCondition": "Fired",
"monitoringService": "Log Alerts V2",
"alertTargetIDs": [
"/subscriptions/c86f8ad8-7f32-4f84-8cf5-9ba182bd2a40/resourcegroups/blog20231223/providers/microsoft.insights/components/sampleapptimertrigger"
],
"configurationItems": [
"/subscriptions/c86f8ad8-7f32-4f84-8cf5-9ba182bd2a40/resourceGroups/blog20231223/providers/microsoft.insights/components/SampleAppTimerTrigger"
],
"originAlertId": "bef8427b-d266-440e-84be-4cbe66cd588e",
"firedDateTime": "2023-12-23T03:23:02.1147771Z",
"description": "TimerTrigger1関数がエラー終了しました",
"essentialsVersion": "1.0",
"alertContextVersion": "1.0"
},
"alertContext": {
"properties": {},
"conditionType": "LogQueryCriteria",
"condition": {
"windowSize": "PT1H",
"allOf": [
{
"searchQuery": "traces | where operation_Name contains \"TimerTrigger1\" \nand message contains \"Executed 'Functions.TimerTrigger1'\"\nand severityLevel == 1",
"metricMeasureColumn": null,
"targetResourceTypes": "['microsoft.insights/components']",
"operator": "GreaterThan",
"threshold": "1",
"timeAggregation": "Count",
"dimensions": [],
"metricValue": 8,
"failingPeriods": {
"numberOfEvaluationPeriods": 1,
"minFailingPeriodsToAlert": 1
},
"linkToSearchResultsUI": "https://portal.azure.com#@6a02fd2f-7f98-4f16-9639-951b0994621f/blade/Microsoft_Azure_Monitoring_Logs/LogsBlade/source/Alerts.EmailLinks/scope/%7B%22resources%22%3A%5B%7B%22resourceId%22%3A%22%2Fsubscriptions%2Fc86f8ad8-7f32-4f84-8cf5-9ba182bd2a40%2FresourceGroups%2Fblog20231223%2Fproviders%2Fmicrosoft.insights%2Fcomponents%2FSampleAppTimerTrigger%22%7D%5D%7D/q/eJxVjDsOwkAMBXtOYW2TDikHSAkVokqPrM3TxhLrRbYDQeLwfKpQTTMzYZzh9KLHDAO1G4xDml7OXEG5abCoUxqlwkaTUmB9oh3rRBXuXLbWYUVeAhN1x0Xz9%2BP7v7JLv9Jxh0k8Tx9eaRiofwM%3D/prettify/1/timespan/2023-12-23T02%3a22%3a25.0000000Z%2f2023-12-23T03%3a22%3a25.0000000Z",
"linkToFilteredSearchResultsUI": "https://portal.azure.com#@6a02fd2f-7f98-4f16-9639-951b0994621f/blade/Microsoft_Azure_Monitoring_Logs/LogsBlade/source/Alerts.EmailLinks/scope/%7B%22resources%22%3A%5B%7B%22resourceId%22%3A%22%2Fsubscriptions%2Fc86f8ad8-7f32-4f84-8cf5-9ba182bd2a40%2FresourceGroups%2Fblog20231223%2Fproviders%2Fmicrosoft.insights%2Fcomponents%2FSampleAppTimerTrigger%22%7D%5D%7D/q/eJxVjDsOwkAMBXtOYW2TDikHSAkVokqPrM3TxhLrRbYDQeLwfKpQTTMzYZzh9KLHDAO1G4xDml7OXEG5abCoUxqlwkaTUmB9oh3rRBXuXLbWYUVeAhN1x0Xz9%2BP7v7JLv9Jxh0k8Tx9eaRiofwM%3D/prettify/1/timespan/2023-12-23T02%3a22%3a25.0000000Z%2f2023-12-23T03%3a22%3a25.0000000Z",
"linkToSearchResultsAPI": "https://api.applicationinsights.io/v1/apps/ec3b3196-ebf9-49af-814c-585faba48434/query?query=traces%20%7C%20where%20operation_Name%20contains%20%22TimerTrigger1%22%20%0Aand%20message%20contains%20%22Executed%20%27Functions.TimerTrigger1%27%22%0Aand%20severityLevel%20%3D%3D%201×pan=2023-12-23T02%3a22%3a25.0000000Z%2f2023-12-23T03%3a22%3a25.0000000Z",
"linkToFilteredSearchResultsAPI": "https://api.applicationinsights.io/v1/apps/ec3b3196-ebf9-49af-814c-585faba48434/query?query=traces%20%7C%20where%20operation_Name%20contains%20%22TimerTrigger1%22%20%0Aand%20message%20contains%20%22Executed%20%27Functions.TimerTrigger1%27%22%0Aand%20severityLevel%20%3D%3D%201×pan=2023-12-23T02%3a22%3a25.0000000Z%2f2023-12-23T03%3a22%3a25.0000000Z"
}
],
"windowStartTime": "2023-12-23T02:22:25Z",
"windowEndTime": "2023-12-23T03:22:25Z"
}
},
"customProperties": {}
}
}
3. Logic App を作成

プランの種類=消費で作成します
ロジック アプリ デザイナーでワークフローを作成します
アラートルール からの HTTPリクエストをトリガーとする想定の為、
HTTP 要求の受診時を選択します
+新しいステップを押下し、HTTPアクションを追加しますURIに Slack の Incoming Webhook のエンドポイントを指定本文に、Slack Incoming Webhook のメッセージの送り方 (※2)に準拠したJSONを登録- メッセージに
動的なコンテンツの追加よりdescriptionとlinkToSearchResultsUIを含める事で、アラート概要と、当該KQLへのリンクをメッセージに含める事ができます
- メッセージに
※2 Slack Incoming Webhook のメッセージの送り方

保存します

4. Azure Monitor の アクショングループ を作成

アクションタブより、上記で設定した Logic Apps をアラート発生時のアクションとして設定します
テストを実行し、Logic App 経由で Slack 通知が届く事を確認しておきます

5. Azure Monitor の アラートルール を作成
監視対象の Function の
監視 > ログより、Application Insights の画面に移動します
監視対象となるログを検索し、
+新しいアラートルールを押下します
※今回は severityLevel が 3 のログは出力されないので 1 を監視対象にしています
traces | where operation_Name contains "TimerTrigger1" and message contains "Executed 'Functions.TimerTrigger1'" and severityLevel == 1
以下の内容でアラートルールを作成します
留意点
- 以下の意味になります
集計の粒度= 過去何分間で出力されたログをアラート対象にするか評価の頻度= 何分起きにログをチェックするか
- 今回は、
集計の粒度= 1時間、評価の頻度= 5分 とし、過去1時間以内のログを、5分おきに監視します
- 以下の意味になります
アラートタブより、アラート検知時のアクションを、上記で作成したアクショングループに設定します
詳細タブより、アラートルール名アラートルールの説明を設定します- ※
アラートルールの説明は手順 3.の動的なコンテンツとして取得できるので、 Slack 通知メッセージで利用します
- ※
Slack通知内容
- エラーログを検知すると以下のSlack通知が飛ぶようになりました!
- リンクから対象のエラーログに飛べます

- リンクから対象のエラーログに飛べます

