Alerting: Support storing sensitive notifier settings securely/encrypted (#25114)

Support storing sensitive notification settings securely/encrypted.
Move slack notifier url and api token to secure settings.
Migrating slack notifier to store token and url encrypted is currently 
a manual process by saving an existing slack alert notification channel.
saving an existing slack alert notification channel will reset the stored 
non-secure url and token.

Closes #25113
Ref #25967

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
This commit is contained in:
Mitsuhiro Tanda
2020-07-08 10:17:05 +02:00
committed by GitHub
co-authored by Marcus Efraimsson
parent b26ef1db25
commit 292c985b76
9 changed files with 295 additions and 67 deletions
+84 -5
View File
@@ -281,6 +281,11 @@ func CreateAlertNotification(c *models.ReqContext, cmd models.CreateAlertNotific
func UpdateAlertNotification(c *models.ReqContext, cmd models.UpdateAlertNotificationCommand) Response {
cmd.OrgId = c.OrgId
err := fillWithSecureSettingsData(&cmd)
if err != nil {
return Error(500, "Failed to update alert notification", err)
}
if err := bus.Dispatch(&cmd); err != nil {
return Error(500, "Failed to update alert notification", err)
}
@@ -289,13 +294,27 @@ func UpdateAlertNotification(c *models.ReqContext, cmd models.UpdateAlertNotific
return Error(404, "Alert notification not found", nil)
}
return JSON(200, dtos.NewAlertNotification(cmd.Result))
query := models.GetAlertNotificationsQuery{
OrgId: c.OrgId,
Id: cmd.Id,
}
if err := bus.Dispatch(&query); err != nil {
return Error(500, "Failed to get alert notification", err)
}
return JSON(200, dtos.NewAlertNotification(query.Result))
}
func UpdateAlertNotificationByUID(c *models.ReqContext, cmd models.UpdateAlertNotificationWithUidCommand) Response {
cmd.OrgId = c.OrgId
cmd.Uid = c.Params("uid")
err := fillWithSecureSettingsDataByUID(&cmd)
if err != nil {
return Error(500, "Failed to update alert notification", err)
}
if err := bus.Dispatch(&cmd); err != nil {
return Error(500, "Failed to update alert notification", err)
}
@@ -304,7 +323,64 @@ func UpdateAlertNotificationByUID(c *models.ReqContext, cmd models.UpdateAlertNo
return Error(404, "Alert notification not found", nil)
}
return JSON(200, dtos.NewAlertNotification(cmd.Result))
query := models.GetAlertNotificationsWithUidQuery{
OrgId: cmd.OrgId,
Uid: cmd.Uid,
}
if err := bus.Dispatch(&query); err != nil {
return Error(500, "Failed to get alert notification", err)
}
return JSON(200, dtos.NewAlertNotification(query.Result))
}
func fillWithSecureSettingsData(cmd *models.UpdateAlertNotificationCommand) error {
if len(cmd.SecureSettings) == 0 {
return nil
}
query := &models.GetAlertNotificationsQuery{
OrgId: cmd.OrgId,
Id: cmd.Id,
}
if err := bus.Dispatch(query); err != nil {
return err
}
secureSettings := query.Result.SecureSettings.Decrypt()
for k, v := range secureSettings {
if _, ok := cmd.SecureSettings[k]; !ok {
cmd.SecureSettings[k] = v
}
}
return nil
}
func fillWithSecureSettingsDataByUID(cmd *models.UpdateAlertNotificationWithUidCommand) error {
if len(cmd.SecureSettings) == 0 {
return nil
}
query := &models.GetAlertNotificationsWithUidQuery{
OrgId: cmd.OrgId,
Uid: cmd.Uid,
}
if err := bus.Dispatch(query); err != nil {
return err
}
secureSettings := query.Result.SecureSettings.Decrypt()
for k, v := range secureSettings {
if _, ok := cmd.SecureSettings[k]; !ok {
cmd.SecureSettings[k] = v
}
}
return nil
}
func DeleteAlertNotification(c *models.ReqContext) Response {
@@ -336,9 +412,12 @@ func DeleteAlertNotificationByUID(c *models.ReqContext) Response {
//POST /api/alert-notifications/test
func NotificationTest(c *models.ReqContext, dto dtos.NotificationTestCommand) Response {
cmd := &alerting.NotificationTestCommand{
Name: dto.Name,
Type: dto.Type,
Settings: dto.Settings,
OrgID: c.OrgId,
ID: dto.ID,
Name: dto.Name,
Type: dto.Type,
Settings: dto.Settings,
SecureSettings: dto.SecureSettings,
}
if err := bus.Dispatch(cmd); err != nil {
+19 -7
View File
@@ -48,7 +48,7 @@ func formatShort(interval time.Duration) string {
}
func NewAlertNotification(notification *models.AlertNotification) *AlertNotification {
return &AlertNotification{
dto := &AlertNotification{
Id: notification.Id,
Uid: notification.Uid,
Name: notification.Name,
@@ -60,7 +60,16 @@ func NewAlertNotification(notification *models.AlertNotification) *AlertNotifica
SendReminder: notification.SendReminder,
DisableResolveMessage: notification.DisableResolveMessage,
Settings: notification.Settings,
SecureFields: map[string]bool{},
}
if notification.SecureSettings != nil {
for k := range notification.SecureSettings {
dto.SecureFields[k] = true
}
}
return dto
}
type AlertNotification struct {
@@ -75,6 +84,7 @@ type AlertNotification struct {
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Settings *simplejson.Json `json:"settings"`
SecureFields map[string]bool `json:"secureFields"`
}
func NewAlertNotificationLookup(notification *models.AlertNotification) *AlertNotificationLookup {
@@ -122,12 +132,14 @@ type EvalMatch struct {
}
type NotificationTestCommand struct {
Name string `json:"name"`
Type string `json:"type"`
SendReminder bool `json:"sendReminder"`
DisableResolveMessage bool `json:"disableResolveMessage"`
Frequency string `json:"frequency"`
Settings *simplejson.Json `json:"settings"`
ID int64 `json:"id,omitempty"`
Name string `json:"name"`
Type string `json:"type"`
SendReminder bool `json:"sendReminder"`
DisableResolveMessage bool `json:"disableResolveMessage"`
Frequency string `json:"frequency"`
Settings *simplejson.Json `json:"settings"`
SecureSettings map[string]string `json:"secureSettings"`
}
type PauseAlertCommand struct {