通知を設定する
Shisho Cloud では、リアルタイム通知 と プロジェクトレポート通知 という二つの通知機能が利用できます。
- リアルタイム通知: 検出事項の発見・トリアージなど、状態が変化したタイミングで通知されます。
- プロジェクトレポート通知: プロジェクト単位で、定期的に現在のセキュリティ状況をまとめて通知します。
本ページでは、それぞれの通知の設定方法を説明します。
通知機能の比較
以下の表は、それぞれの通知機能の特徴をまとめ たものです。用途に応じて使い分けてください。
| 機能 | リアルタイム通知 | プロジェクトレポート通知 |
|---|---|---|
| 主な用途 | 検出事項の発見・トリアージ時の通知 | 定期的なセキュリティ状況の把握・報告 |
| 通知トリガー | 検出事項の発見・トリアージ時 | 定期的 |
| 通知内容 | 個別の検出事項 | プロジェクト全体のサマリーと内訳 |
| 設定方法 | ワークフローによる制御 | プロジェクト設定画面による設定 |
| カスタマイズ性 | 高い(ワークフローで柔軟に制御可能) | 中程度(設定項目で制御可能) |
使い分けの例:
- リアルタイム通知: Critical / High の検出事項が見つかった際に Slack で通知する、またはチケット管理システムに起票する。
- プロジェクトレポート通知: 毎日、プロジェクト全体のセキュリティ状況をメールで受信し、定例会で確認する。
リアルタイム通知を設定する
リアルタイム通知は、検出事項の発見やトリアージなど、状態が変化したタイミングで通知される機能です。
Shisho Cloud では、通知のタイミングや内容を ワークフロー として柔軟に制御できます。複雑な設定をせずとも利用できるよう、標準で 通知ワークフロー が用意されており、検出事項の 深刻度 (Severity) に応じて通知されます。
Slack 通知の例

メール通知の例

通知ワークフロー
通知ワークフローには、組織全体のリソースを対象にした通知と、特定のプロジェクト内のリソースを対象にした通知の2種類があります。どちらも、問題の発見やトリアージ時に通知されます。
- 通知ワークフロー
- プロジェクトごとの通知ワークフロー
通知ワークフローは標準で含まれているワークフローの一つで、組織内の全リソースを対象とした問題の発見・トリアージ時に下記の方法で通知します。
- Slack チャンネルへ通知
- 指定のメールアドレスへ送信
- 通知グループに紐付けられた送信先へ通知
警告
id: notification-security
name: "Prebundle: Notify important security events in a variety of ways"
version: 0.1.0
triggers:
triage:
- event:
- updated
status_changed_to:
- awaiting_review
- acknowledged
- action_required
- secure
- deleted
- event:
- created
status_changed_to:
- awaiting_review
jobs:
- id: triage
name: Notify triage status updation
notify:
rego: |
package notification.triage
import data.shisho
import data.shisho.notification.slack
import data.shisho.notification.group
minimum_severity := severity_intl(data.params.minimum_severity) {
data.params
data.params.minimum_severity != ""
} else := shisho.decision.severity_critical
severity_intl(x) := shisho.decision.severity_info {
x == "INFO"
} else := shisho.decision.severity_low {
x == "LOW"
} else := shisho.decision.severity_medium {
x == "MEDIUM"
} else := shisho.decision.severity_high {
x == "HIGH"
} else := shisho.decision.severity_critical {
x == "CRITICAL"
} else := shisho.decision.severity_low
severity_string(x) := "参考情報(info)" {
x == shisho.decision.severity_info
} else := "低(low)" {
x == shisho.decision.severity_low
} else := "中(medium)" {
x == shisho.decision.severity_medium
} else := "高(high)" {
x == shisho.decision.severity_high
} else := "緊急(critical)" {
x == shisho.decision.severity_critical
} else := x
severity_emoji(x) := ":information_source:" {
x == shisho.decision.severity_info
} else := ":eyes:" {
x == shisho.decision.severity_low
} else := ":warning:" {
x == shisho.decision.severity_medium
} else := ":rotating_light:" {
x == shisho.decision.severity_high
} else := ":sos:" {
x == shisho.decision.severity_critical
} else := ":memo:"
triage_status(x) := "要レビュー" {
x == "AWAITING_REVIEW"
} else := "要対応" {
x == "ACTION_REQUIRED"
} else := "リスク受容中" {
x == "ACKNOWLEDGED"
} else := "セキュア" {
x == "SECURE"
} else := "削除済" {
x == "DELETED"
} else := x
triage_status_emoji(x) := ":eyes:" {
x == "AWAITING_REVIEW"
} else := ":heavy_exclamation_mark:" {
x == "ACTION_REQUIRED"
} else := ":arrow_right:" {
x == "ACKNOWLEDGED"
} else := ":large_green_circle:" {
x == "SECURE"
} else := ":wastebasket:" {
x == "DELETED"
} else := ":memo:"
title(explanation, api_version, kind) := explanation.title {
explanation
} else := "" {
concat(":", [api_version, kind])
}
slack_headline(type, status) := "*新たなポリシー違反が検出されました。*\n対応を検討しましょう。" {
type == "CREATED"
} else := "*ポリシー違反が解決されました* :tada:" {
type == "UPDATED"
status == "SECURE"
} else := "*ポリシーに違反した設定の対応状況が変化しました。*\n引き続き対応を進めましょう。"
slack_triage_information(target) := [
slack.divider_block,
slack.context_block([slack.text_element(concat("", [":mega: トリアージ者: ", target.triageInitiator.displayName]))]),
slack.context_block([slack.text_element(concat("", [":memo: コメント: ", target.triageComment]))]),
] {
target.triageInitiator.displayName != ""
target.triageComment != ""
} else := [
slack.divider_block,
slack.context_block([slack.text_element(concat("", [":mega: トリアージ者: ", target.triageInitiator.displayName]))]),
] {
target.triageInitiator.displayName != ""
target.triageComment == ""
} else := []
# send notifications by Slack
notifications[n] {
# send notification only if the channel is specified
data.params.slack_channel != ""
workspace_id := split(data.params.slack_channel, ":")[0]
channel_id := split(data.params.slack_channel, ":")[1]
event := input.query.shisho.event
event.__typename == "ShishoTriageStatusEvent"
input.running_state == shisho.job.running_state_preprocessing
# send notification only if the severity of the target decision is higher than the minimum severity
target_severity := severity_intl(event.target.severity)
minimum_severity <= target_severity
n := shisho.notification.to_slack_channel(
workspace_id,
channel_id,
{"blocks": array.concat(
[slack.text_section(
slack_headline(event.type, event.status),
{"fields": [
# The first row
slack.text_element("*:memo: 違反が見られた観点*"),
slack.text_element("*:dart: 対象リソース*"),
slack.text_element(concat("", ["<", event.target.viewer, "|", title(event.target.explanation, event.target.apiVersion, event.target.kind), ">"])),
slack.text_element(concat("", ["<", event.target.subject.viewer, "|", event.target.subject.displayName, ">"])),
# The second row
slack.text_element(concat("", [severity_emoji(target_severity), " *重大度*"])),
slack.text_element(concat("", [triage_status_emoji(event.status), " *対応状況*"])),
slack.text_element(severity_string(target_severity)),
slack.text_element(concat("", ["*", triage_status(event.status), "* に変化しました"])),
]},
)],
# The footer
array.concat(slack_triage_information(event.target), [
slack.divider_block,
slack.context_block([slack.text_element(concat("", [":shield: *Powered by \"<", event.target.createdBy.viewer, "|", event.target.createdBy.name, ">\" on Shisho Cloud*"]))]),
slack.divider_block,
]),
)},
)
}
headline(type, status) := "新たなポリシー違反が検出されました。対応を検討しましょう。" {
type == "CREATED"
} else := "ポリシー違反が解決されました" {
type == "UPDATED"
status == "SECURE"
} else := "ポリシーに違反した設定の対応状況が変化しました。引き続き対応を進めましょう。"
triage_information(target) := [
concat("", ["