Security: apply patch 428 (#106710)
* declare dingding url as secret patch raw settings before parsing because DingDing's config parser does not know about secrets * fix integration test --------- Co-authored-by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>
This commit is contained in:
co-authored by
Yuri Tseretyan
parent
5f3c04f537
commit
910eb1dd9e
@@ -53,6 +53,7 @@ type alertmanager struct {
|
||||
Store AlertingStore
|
||||
stateStore stateStore
|
||||
DefaultConfiguration string
|
||||
decryptFn alertingNotify.GetDecryptedValueFn
|
||||
}
|
||||
|
||||
// maintenanceOptions represent the options for components that need maintenance on a frequency within the Alertmanager.
|
||||
@@ -149,6 +150,7 @@ func NewAlertmanager(ctx context.Context, orgID int64, cfg *setting.Cfg, store A
|
||||
Store: store,
|
||||
stateStore: stateStore,
|
||||
logger: l.New("component", "alertmanager", opts.TenantKey, opts.TenantID), // similar to what the base does
|
||||
decryptFn: decryptFn,
|
||||
}
|
||||
|
||||
return am, nil
|
||||
@@ -335,6 +337,14 @@ func (am *alertmanager) applyConfig(ctx context.Context, cfg *apimodels.Postable
|
||||
return false, nil
|
||||
}
|
||||
|
||||
receivers := PostableApiAlertingConfigToApiReceivers(cfg.AlertmanagerConfig)
|
||||
for _, recv := range receivers {
|
||||
err = patchNewSecureFields(ctx, recv, alertingNotify.DecodeSecretsFromBase64, am.decryptFn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
am.logger.Info("Applying new configuration to Alertmanager", "configHash", fmt.Sprintf("%x", configHash))
|
||||
err = am.Base.ApplyConfig(alertingNotify.NotificationsConfiguration{
|
||||
RoutingTree: cfg.AlertmanagerConfig.Route.AsAMRoute(),
|
||||
@@ -342,7 +352,7 @@ func (am *alertmanager) applyConfig(ctx context.Context, cfg *apimodels.Postable
|
||||
MuteTimeIntervals: cfg.AlertmanagerConfig.MuteTimeIntervals,
|
||||
TimeIntervals: cfg.AlertmanagerConfig.TimeIntervals,
|
||||
Templates: ToTemplateDefinitions(cfg),
|
||||
Receivers: PostableApiAlertingConfigToApiReceivers(cfg.AlertmanagerConfig),
|
||||
Receivers: receivers,
|
||||
DispatcherLimits: &nilLimits{},
|
||||
Raw: rawConfig,
|
||||
Hash: configHash,
|
||||
@@ -355,6 +365,50 @@ func (am *alertmanager) applyConfig(ctx context.Context, cfg *apimodels.Postable
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func patchNewSecureFields(ctx context.Context, api *alertingNotify.APIReceiver, decode alertingNotify.DecodeSecretsFn, decrypt alertingNotify.GetDecryptedValueFn) error {
|
||||
for _, integration := range api.Integrations {
|
||||
switch integration.Type {
|
||||
case "dingding":
|
||||
err := patchSettingsFromSecureSettings(ctx, integration, "url", decode, decrypt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func patchSettingsFromSecureSettings(ctx context.Context, integration *alertingNotify.GrafanaIntegrationConfig, key string, decode alertingNotify.DecodeSecretsFn, decrypt alertingNotify.GetDecryptedValueFn) error {
|
||||
if _, ok := integration.SecureSettings[key]; !ok {
|
||||
return nil
|
||||
}
|
||||
decoded, err := decode(integration.SecureSettings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
settings := map[string]any{}
|
||||
err = json.Unmarshal(integration.Settings, &settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentValue, ok := settings[key]
|
||||
currentString := ""
|
||||
if ok {
|
||||
currentString, _ = currentValue.(string)
|
||||
}
|
||||
secretValue := decrypt(ctx, decoded, key, currentString)
|
||||
if secretValue == currentString {
|
||||
return nil
|
||||
}
|
||||
settings[key] = secretValue
|
||||
data, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
integration.Settings = data
|
||||
return nil
|
||||
}
|
||||
|
||||
// PutAlerts receives the alerts and then sends them through the corresponding route based on whenever the alert has a receiver embedded or not
|
||||
func (am *alertmanager) PutAlerts(_ context.Context, postableAlerts apimodels.PostableAlerts) error {
|
||||
alerts := make(alertingNotify.PostableAlerts, 0, len(postableAlerts.PostableAlerts))
|
||||
|
||||
@@ -284,6 +284,7 @@ func GetAvailableNotifiers() []*NotifierPlugin {
|
||||
Placeholder: "https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxx",
|
||||
PropertyName: "url",
|
||||
Required: true,
|
||||
Secure: true,
|
||||
},
|
||||
{
|
||||
Label: "Message Type",
|
||||
|
||||
@@ -11,7 +11,7 @@ func TestGetSecretKeysForContactPointType(t *testing.T) {
|
||||
receiverType string
|
||||
expectedSecretFields []string
|
||||
}{
|
||||
{receiverType: "dingding", expectedSecretFields: []string{}},
|
||||
{receiverType: "dingding", expectedSecretFields: []string{"url"}},
|
||||
{receiverType: "kafka", expectedSecretFields: []string{"password"}},
|
||||
{receiverType: "email", expectedSecretFields: []string{}},
|
||||
{receiverType: "pagerduty", expectedSecretFields: []string{"integrationKey"}},
|
||||
|
||||
@@ -24,12 +24,17 @@ func (am *alertmanager) TestReceivers(ctx context.Context, c apimodels.TestRecei
|
||||
SecureSettings: gr.SecureSettings,
|
||||
})
|
||||
}
|
||||
receivers = append(receivers, &alertingNotify.APIReceiver{
|
||||
recv := &alertingNotify.APIReceiver{
|
||||
ConfigReceiver: r.Receiver,
|
||||
GrafanaIntegrations: alertingNotify.GrafanaIntegrations{
|
||||
Integrations: integrations,
|
||||
},
|
||||
})
|
||||
}
|
||||
err := patchNewSecureFields(ctx, recv, alertingNotify.DecodeSecretsFromBase64, am.decryptFn)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
receivers = append(receivers, recv)
|
||||
}
|
||||
a := &alertingNotify.PostableAlert{}
|
||||
if c.Alert != nil {
|
||||
|
||||
@@ -2088,10 +2088,8 @@ var expAlertmanagerConfigFromAPI = `
|
||||
"name": "dingding_test",
|
||||
"type": "dingding",
|
||||
"disableResolveMessage": false,
|
||||
"settings": {
|
||||
"url": "http://CHANNEL_ADDR/dingding_recv/dingding_test"
|
||||
},
|
||||
"secureFields": {}
|
||||
"settings": {},
|
||||
"secureFields": {"url": true}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user