Configure Notifications
The English user guide is currently in beta preview. Most of the documents have been automatically translated from the Japanese version. Should you find any inaccuracies, please reach out to Flatt Security.
Notifications in Shisho Cloud are entirely managed through workflows, controlling both timing and content. You can define multiple default notification destinations for each project. For ease of use, a default notification workflow is readily available, enabling notifications based on the severity of detected issues.
Example Slack Notification
Example Email Notification
- Notification Workflow
- Per-Project Notification Workflow
The notification workflow is a standard workflow included in Shisho Cloud. It sends notifications when issues are detected or triaged for all resources within the organization, using the following delivery methods:
- Notifications to Slack channels
- Emails to designated addresses
- Notifications to destinations associated with notification groups
Some users may have a workflow distributed that only supports Slack notifications. In that case, please open the standard notification workflow page, copy and paste the following new workflow to replace the existing one. After replacing the workflow, you will need to specify the notification destinations again. Please specify them in the parameter settings on the standard notification workflow page.
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("", ["トリアージ者: ", target.triageInitiator.displayName, "\n"]),
concat("", ["コメント: ", target.triageComment, "\n"]),
] {
target.triageInitiator.displayName != ""
target.triageComment != ""
} else := [
concat("", ["トリアージ者: ", target.triageInitiator.displayName, "\n"]),
] {
target.triageInitiator.displayName != ""
target.triageComment == ""
} else := []
# send notifications by email
notifications[n] {
# send notification only if the email address is specified
data.params.email_address != ""
email = data.params.email_address
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_email(
email,
concat("", [
headline(event.type, event.status),
"\n\n",
"違反が見られた観点: ",
concat("", [title(event.target.explanation, event.target.apiVersion, event.target.kind), " (", event.target.viewer, ")", "\n"]),
"対象リソース: ",
concat("", [event.target.subject.displayName, " (", event.target.subject.viewer, ")", "\n"]),
"深刻度: ",
severity_string(target_severity),
"\n",
"対応状況: ",
concat("", [triage_status(event.status), "に変化しました", "\n"]),
"\n",
concat("", triage_information(event.target)),
"\n",
concat("", ["Powered by \"", event.target.createdBy.name, " (", event.target.createdBy.viewer, ")", "\" on Shisho Cloud"]),
]),
)
}
# send notifications with a notification group
notifications[n] {
# send notification only if the notification group ID is specified
data.params.notification_group != ""
group_id = data.params.notification_group
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_group(
group_id,
concat("", [
headline(event.type, event.status),
"\n\n",
"違反が見られた観点: ",
concat("", [title(event.target.explanation, event.target.apiVersion, event.target.kind), " (", event.target.viewer, ")", "\n"]),
"対象リソース: ",
concat("", [event.target.subject.displayName, " (", event.target.subject.viewer, ")", "\n"]),
"深刻度: ",
severity_string(target_severity),
"\n",
"対応状況: ",
concat("", [triage_status(event.status), "に変化しました", "\n"]),
"\n",
concat("", triage_information(event.target)),
"\n",
concat("", ["Powered by \"", event.target.createdBy.name, " (", event.target.createdBy.viewer, ")", "\" on Shisho Cloud"]),
]),
)
}
input:
schema: |
query {
shisho {
event {
__typename
... on ShishoTriageStatusEvent {
type
status
target {
apiVersion
kind
subject {
displayName
parentDisplayName
viewer
}
severity
viewer
explanation(locale: JA_JP) {
title
description
}
createdBy {
name
viewer
}
triageComment
triageInitiator {
id
type
displayName
}
}
}
}
}
}
with:
slack_channel:
type: slack_channel
descrition: The Slack channel to send notifications.
value: ""
email_address:
type: string
descrition: The email channel to send notifications.
value: ""
notification_group:
type: notification_target
descrition: The notification group to send notifications.
value: ""
minimum_severity:
type: string
description: The minimum severity to notify.
value: HIGH
oneof:
- INFO
- LOW
- MEDIUM
- HIGH
- CRITICAL
The per-project notification workflow sends notifications to various destinations when issues are detected or triaged within the scope (resources) of a project. This workflow is not included by default. If necessary, please copy and create a new workflow using the following YAML:
version: 0.1.0
id: "notification-project-security"
name: "Prebundle: Notify Shisho Cloud project's important security events"
triggers:
triage:
# send notifications when...
- event: [updated]
status_changed_to:
# the issue is calling your review.
- awaiting_review
# the issue is acknowledged, and no further action is not expected.
- acknowledged
# the issue is marked to need your fix.
- action_required
# the issue was fixed :tada:
- secure
# the resource with security issue(s) gets deleted.
- deleted
# send notifications on a finding needs your action
- event: [created]
status_changed_to:
- awaiting_review
jobs:
- id: triage
name: Notify triage status updation
notify:
rego: |
package notification.project_security.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] {
event := input.query.shisho.event
event.__typename == "ShishoTriageStatusEvent"
input.running_state == shisho.job.running_state_preprocessing
# send a 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
# send a notification to the default project notification channels
project := event.target.subject.projectsBelongingTo[_]
channel := project.defaultNotificationChannels[_]
channel.__typename == "ShishoNotificationChannelSlack"
n := shisho.notification.to_slack_channel(
channel.workspaceId,
channel.channelId,
{"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("", ["トリアージ者: ", target.triageInitiator.displayName, "\n"]),
concat("", ["コメント: ", target.triageComment, "\n"]),
] {
target.triageInitiator.displayName != ""
target.triageComment != ""
} else := [
concat("", ["トリアージ者: ", target.triageInitiator.displayName, "\n"]),
] {
target.triageInitiator.displayName != ""
target.triageComment == ""
} else := []
# send notifications by email
notifications[n] {
event := input.query.shisho.event
event.__typename == "ShishoTriageStatusEvent"
input.running_state == shisho.job.running_state_preprocessing
# send a 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
# send a notification to the default project notification channels
project := event.target.subject.projectsBelongingTo[_]
channel := project.defaultNotificationChannels[_]
channel.__typename == "ShishoNotificationChannelEmail"
n := shisho.notification.to_email(
channel.email,
concat("", [
headline(event.type, event.status),
"\n\n",
"違反が見られた観点: ",
concat("", [title(event.target.explanation, event.target.apiVersion, event.target.kind), " (", event.target.viewer, ")", "\n"]),
"対象リソース: ",
concat("", [event.target.subject.displayName, " (", event.target.subject.viewer, ")", "\n"]),
"深刻度: ",
severity_string(target_severity),
"\n",
"対応状況: ",
concat("", [triage_status(event.status), "に変化しました", "\n"]),
"\n",
concat("", triage_information(event.target)),
"\n",
concat("", ["Powered by \"", event.target.createdBy.name, " (", event.target.createdBy.viewer, ")", "\" on Shisho Cloud"]),
]),
)
}
# send notifications with a notification group
notifications[n] {
event := input.query.shisho.event
event.__typename == "ShishoTriageStatusEvent"
input.running_state == shisho.job.running_state_preprocessing
# send a 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
# send a notification to the default project notification channels
project := event.target.subject.projectsBelongingTo[_]
channel := project.defaultNotificationChannels[_]
channel.__typename == "ShishoNotificationChannelGroup"
n := shisho.notification.to_group(
channel.id,
concat("", [
headline(event.type, event.status),
"\n\n",
"違反が見られた観点: ",
concat("", [title(event.target.explanation, event.target.apiVersion, event.target.kind), " (", event.target.viewer, ")", "\n"]),
"対象リソース: ",
concat("", [event.target.subject.displayName, " (", event.target.subject.viewer, ")", "\n"]),
"深刻度: ",
severity_string(target_severity),
"\n",
"対応状況: ",
concat("", [triage_status(event.status), "に変化しました", "\n"]),
"\n",
concat("", triage_information(event.target)),
"\n",
concat("", ["Powered by \"", event.target.createdBy.name, " (", event.target.createdBy.viewer, ")", "\" on Shisho Cloud"]),
]),
)
}
input:
schema: |
query {
shisho {
event {
__typename
... on ShishoTriageStatusEvent {
type
status
target {
apiVersion
kind
subject {
displayName
parentDisplayName
viewer
projectsBelongingTo {
id
name
defaultNotificationChannels {
__typename
... on ShishoNotificationChannelSlack {
workspaceId
channelId
name
}
... on ShishoNotificationChannelGroup {
id
name
}
... on ShishoNotificationChannelEmail {
email
}
}
}
}
severity
viewer
explanation(locale: JA_JP) {
title
description
}
createdBy {
name
viewer
}
triageComment
triageInitiator {
id
type
displayName
}
}
}
}
}
}
with:
minimum_severity:
type: string
description: The minimum severity to notify.
value: HIGH
oneof:
- INFO
- LOW
- MEDIUM
- HIGH
- CRITICAL
Let's take a look at how to configure notifications.
Configuring the Notification Workflow
This section explains how to modify the notification workflow settings and configure notifications for when issues are detected and triaged.
Accessing the Notification Workflow Settings Page
Go to the notification workflow editing page. You should see the following screen:
Editing Parameters
In the upper right corner of the screen, you'll find settings for various notification destinations and the severity levels of detected issues that trigger notifications. Configure each item and click Save.
To configure notifications, you need to configure various notification targets beforehand. For details, see here.
Testing Slack Notifications
To use Slack channel notifications, you can send a test notification by clicking the Send Test Notification button. If you see a message like the one below, your notification settings are complete.
Configuring Per-Project Notification Workflows
In some cases, you may want to send notifications to the same destination, while in other cases, you may want to send notifications to different destinations for each project. In such cases, use the per-project notification workflow described above.
Accessing the Settings Page of the Target Project
First, from the project list screen, select the project you want to configure notifications for and go to the settings page.
Configuring Notification Destinations
On the settings page, select the desired notification destination and add or update it.
The following can currently be added as project notification destinations. Each of these needs to be configured in advance, so if your desired notification destination is not displayed as an option, please check the configuration.
- Slack channels: See "Setting Up Slack Notifications" in Notification Targets.
- Notification groups: See Configuring Notification Groups.
- Email: See "Setting Up Email Notifications" in Notification Targets.
Accessing the Per-Project Notification Workflow Settings Page
Since you have already configured the notification destinations on the project settings page, you do not need to configure them again using parameters. If you want to change the severity of detected issues that trigger notifications, go to the per-project notification workflow edit page and edit the parameters.