Support default SMTP TLS config

Fixes: #3709

Signed-off-by: Mathieu Parent <math.parent@gmail.com>
This commit is contained in:
Mathieu Parent 2024-02-22 15:29:05 +01:00
parent efa801faf7
commit ef5e903418
6 changed files with 61 additions and 47 deletions

View File

@ -365,6 +365,9 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
}
}
for _, ec := range rcv.EmailConfigs {
if ec.TLSConfig == nil {
ec.TLSConfig = c.Global.SMTPTLSConfig
}
if ec.Smarthost.String() == "" {
if c.Global.SMTPSmarthost.String() == "" {
return fmt.Errorf("no global SMTP smarthost set")
@ -629,12 +632,14 @@ func checkTimeInterval(r *Route, timeIntervals map[string]struct{}) error {
// DefaultGlobalConfig returns GlobalConfig with default values.
func DefaultGlobalConfig() GlobalConfig {
defaultHTTPConfig := commoncfg.DefaultHTTPClientConfig
return GlobalConfig{
ResolveTimeout: model.Duration(5 * time.Minute),
HTTPConfig: &defaultHTTPConfig,
defaultSMTPTLSConfig := commoncfg.TLSConfig{}
return GlobalConfig{
ResolveTimeout: model.Duration(5 * time.Minute),
HTTPConfig: &defaultHTTPConfig,
SMTPHello: "localhost",
SMTPRequireTLS: true,
SMTPTLSConfig: &defaultSMTPTLSConfig,
PagerdutyURL: mustParseURL("https://events.pagerduty.com/v2/enqueue"),
OpsGenieAPIURL: mustParseURL("https://api.opsgenie.com/"),
WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"),
@ -742,29 +747,30 @@ type GlobalConfig struct {
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
SMTPFrom string `yaml:"smtp_from,omitempty" json:"smtp_from,omitempty"`
SMTPHello string `yaml:"smtp_hello,omitempty" json:"smtp_hello,omitempty"`
SMTPSmarthost HostPort `yaml:"smtp_smarthost,omitempty" json:"smtp_smarthost,omitempty"`
SMTPAuthUsername string `yaml:"smtp_auth_username,omitempty" json:"smtp_auth_username,omitempty"`
SMTPAuthPassword Secret `yaml:"smtp_auth_password,omitempty" json:"smtp_auth_password,omitempty"`
SMTPAuthPasswordFile string `yaml:"smtp_auth_password_file,omitempty" json:"smtp_auth_password_file,omitempty"`
SMTPAuthSecret Secret `yaml:"smtp_auth_secret,omitempty" json:"smtp_auth_secret,omitempty"`
SMTPAuthIdentity string `yaml:"smtp_auth_identity,omitempty" json:"smtp_auth_identity,omitempty"`
SMTPRequireTLS bool `yaml:"smtp_require_tls" json:"smtp_require_tls,omitempty"`
SlackAPIURL *SecretURL `yaml:"slack_api_url,omitempty" json:"slack_api_url,omitempty"`
SlackAPIURLFile string `yaml:"slack_api_url_file,omitempty" json:"slack_api_url_file,omitempty"`
PagerdutyURL *URL `yaml:"pagerduty_url,omitempty" json:"pagerduty_url,omitempty"`
OpsGenieAPIURL *URL `yaml:"opsgenie_api_url,omitempty" json:"opsgenie_api_url,omitempty"`
OpsGenieAPIKey Secret `yaml:"opsgenie_api_key,omitempty" json:"opsgenie_api_key,omitempty"`
OpsGenieAPIKeyFile string `yaml:"opsgenie_api_key_file,omitempty" json:"opsgenie_api_key_file,omitempty"`
WeChatAPIURL *URL `yaml:"wechat_api_url,omitempty" json:"wechat_api_url,omitempty"`
WeChatAPISecret Secret `yaml:"wechat_api_secret,omitempty" json:"wechat_api_secret,omitempty"`
WeChatAPICorpID string `yaml:"wechat_api_corp_id,omitempty" json:"wechat_api_corp_id,omitempty"`
VictorOpsAPIURL *URL `yaml:"victorops_api_url,omitempty" json:"victorops_api_url,omitempty"`
VictorOpsAPIKey Secret `yaml:"victorops_api_key,omitempty" json:"victorops_api_key,omitempty"`
VictorOpsAPIKeyFile string `yaml:"victorops_api_key_file,omitempty" json:"victorops_api_key_file,omitempty"`
TelegramAPIUrl *URL `yaml:"telegram_api_url,omitempty" json:"telegram_api_url,omitempty"`
WebexAPIURL *URL `yaml:"webex_api_url,omitempty" json:"webex_api_url,omitempty"`
SMTPFrom string `yaml:"smtp_from,omitempty" json:"smtp_from,omitempty"`
SMTPHello string `yaml:"smtp_hello,omitempty" json:"smtp_hello,omitempty"`
SMTPSmarthost HostPort `yaml:"smtp_smarthost,omitempty" json:"smtp_smarthost,omitempty"`
SMTPAuthUsername string `yaml:"smtp_auth_username,omitempty" json:"smtp_auth_username,omitempty"`
SMTPAuthPassword Secret `yaml:"smtp_auth_password,omitempty" json:"smtp_auth_password,omitempty"`
SMTPAuthPasswordFile string `yaml:"smtp_auth_password_file,omitempty" json:"smtp_auth_password_file,omitempty"`
SMTPAuthSecret Secret `yaml:"smtp_auth_secret,omitempty" json:"smtp_auth_secret,omitempty"`
SMTPAuthIdentity string `yaml:"smtp_auth_identity,omitempty" json:"smtp_auth_identity,omitempty"`
SMTPRequireTLS bool `yaml:"smtp_require_tls" json:"smtp_require_tls,omitempty"`
SMTPTLSConfig *commoncfg.TLSConfig `yaml:"smtp_tls_config,omitempty" json:"smtp_tls_config,omitempty"`
SlackAPIURL *SecretURL `yaml:"slack_api_url,omitempty" json:"slack_api_url,omitempty"`
SlackAPIURLFile string `yaml:"slack_api_url_file,omitempty" json:"slack_api_url_file,omitempty"`
PagerdutyURL *URL `yaml:"pagerduty_url,omitempty" json:"pagerduty_url,omitempty"`
OpsGenieAPIURL *URL `yaml:"opsgenie_api_url,omitempty" json:"opsgenie_api_url,omitempty"`
OpsGenieAPIKey Secret `yaml:"opsgenie_api_key,omitempty" json:"opsgenie_api_key,omitempty"`
OpsGenieAPIKeyFile string `yaml:"opsgenie_api_key_file,omitempty" json:"opsgenie_api_key_file,omitempty"`
WeChatAPIURL *URL `yaml:"wechat_api_url,omitempty" json:"wechat_api_url,omitempty"`
WeChatAPISecret Secret `yaml:"wechat_api_secret,omitempty" json:"wechat_api_secret,omitempty"`
WeChatAPICorpID string `yaml:"wechat_api_corp_id,omitempty" json:"wechat_api_corp_id,omitempty"`
VictorOpsAPIURL *URL `yaml:"victorops_api_url,omitempty" json:"victorops_api_url,omitempty"`
VictorOpsAPIKey Secret `yaml:"victorops_api_key,omitempty" json:"victorops_api_key,omitempty"`
VictorOpsAPIKeyFile string `yaml:"victorops_api_key_file,omitempty" json:"victorops_api_key_file,omitempty"`
TelegramAPIUrl *URL `yaml:"telegram_api_url,omitempty" json:"telegram_api_url,omitempty"`
WebexAPIURL *URL `yaml:"webex_api_url,omitempty" json:"webex_api_url,omitempty"`
}
// UnmarshalYAML implements the yaml.Unmarshaler interface for GlobalConfig.

View File

@ -857,9 +857,12 @@ func TestEmptyFieldsAndRegex(t *testing.T) {
FollowRedirects: true,
EnableHTTP2: true,
},
ResolveTimeout: model.Duration(5 * time.Minute),
SMTPSmarthost: HostPort{Host: "localhost", Port: "25"},
SMTPFrom: "alertmanager@example.org",
ResolveTimeout: model.Duration(5 * time.Minute),
SMTPSmarthost: HostPort{Host: "localhost", Port: "25"},
SMTPFrom: "alertmanager@example.org",
SMTPTLSConfig: &commoncfg.TLSConfig{
InsecureSkipVerify: false,
},
SlackAPIURL: (*SecretURL)(mustParseURL("http://slack.example.com/")),
SMTPRequireTLS: true,
PagerdutyURL: mustParseURL("https://events.pagerduty.com/v2/enqueue"),
@ -905,6 +908,9 @@ func TestEmptyFieldsAndRegex(t *testing.T) {
Smarthost: HostPort{Host: "localhost", Port: "25"},
HTML: "{{ template \"email.default.html\" . }}",
RequireTLS: &boolFoo,
TLSConfig: &commoncfg.TLSConfig{
InsecureSkipVerify: false,
},
},
},
},

View File

@ -248,20 +248,20 @@ type EmailConfig struct {
NotifierConfig `yaml:",inline" json:",inline"`
// Email address to notify.
To string `yaml:"to,omitempty" json:"to,omitempty"`
From string `yaml:"from,omitempty" json:"from,omitempty"`
Hello string `yaml:"hello,omitempty" json:"hello,omitempty"`
Smarthost HostPort `yaml:"smarthost,omitempty" json:"smarthost,omitempty"`
AuthUsername string `yaml:"auth_username,omitempty" json:"auth_username,omitempty"`
AuthPassword Secret `yaml:"auth_password,omitempty" json:"auth_password,omitempty"`
AuthPasswordFile string `yaml:"auth_password_file,omitempty" json:"auth_password_file,omitempty"`
AuthSecret Secret `yaml:"auth_secret,omitempty" json:"auth_secret,omitempty"`
AuthIdentity string `yaml:"auth_identity,omitempty" json:"auth_identity,omitempty"`
Headers map[string]string `yaml:"headers,omitempty" json:"headers,omitempty"`
HTML string `yaml:"html,omitempty" json:"html,omitempty"`
Text string `yaml:"text,omitempty" json:"text,omitempty"`
RequireTLS *bool `yaml:"require_tls,omitempty" json:"require_tls,omitempty"`
TLSConfig commoncfg.TLSConfig `yaml:"tls_config,omitempty" json:"tls_config,omitempty"`
To string `yaml:"to,omitempty" json:"to,omitempty"`
From string `yaml:"from,omitempty" json:"from,omitempty"`
Hello string `yaml:"hello,omitempty" json:"hello,omitempty"`
Smarthost HostPort `yaml:"smarthost,omitempty" json:"smarthost,omitempty"`
AuthUsername string `yaml:"auth_username,omitempty" json:"auth_username,omitempty"`
AuthPassword Secret `yaml:"auth_password,omitempty" json:"auth_password,omitempty"`
AuthPasswordFile string `yaml:"auth_password_file,omitempty" json:"auth_password_file,omitempty"`
AuthSecret Secret `yaml:"auth_secret,omitempty" json:"auth_secret,omitempty"`
AuthIdentity string `yaml:"auth_identity,omitempty" json:"auth_identity,omitempty"`
Headers map[string]string `yaml:"headers,omitempty" json:"headers,omitempty"`
HTML string `yaml:"html,omitempty" json:"html,omitempty"`
Text string `yaml:"text,omitempty" json:"text,omitempty"`
RequireTLS *bool `yaml:"require_tls,omitempty" json:"require_tls,omitempty"`
TLSConfig *commoncfg.TLSConfig `yaml:"tls_config,omitempty" json:"tls_config,omitempty"`
}
// UnmarshalYAML implements the yaml.Unmarshaler interface.

View File

@ -83,6 +83,8 @@ global:
# The default SMTP TLS requirement.
# Note that Go does not support unencrypted connections to remote SMTP endpoints.
[ smtp_require_tls: <bool> | default = true ]
# The default TLS configuration for SMTP receivers
[ smtp_tls_config: <tls_config> ]
# The API URL to use for Slack notifications.
[ slack_api_url: <secret> ]
@ -884,7 +886,7 @@ to: <tmpl_string>
# TLS configuration.
tls_config:
[ <tls_config> ]
[ <tls_config> | default = global.smtp_tls_config ]
# The HTML body of the email notification.
[ html: <tmpl_string> | default = '{{ template "email.default.html" . }}' ]

View File

@ -131,7 +131,7 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) {
success = false
)
if n.conf.Smarthost.Port == "465" {
tlsConfig, err := commoncfg.NewTLSConfig(&n.conf.TLSConfig)
tlsConfig, err := commoncfg.NewTLSConfig(n.conf.TLSConfig)
if err != nil {
return false, fmt.Errorf("parse TLS configuration: %w", err)
}
@ -178,7 +178,7 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) {
return true, fmt.Errorf("'require_tls' is true (default) but %q does not advertise the STARTTLS extension", n.conf.Smarthost)
}
tlsConf, err := commoncfg.NewTLSConfig(&n.conf.TLSConfig)
tlsConf, err := commoncfg.NewTLSConfig(n.conf.TLSConfig)
if err != nil {
return false, fmt.Errorf("parse TLS configuration: %w", err)
}

View File

@ -407,7 +407,7 @@ func TestEmailNotifyWithSTARTTLS(t *testing.T) {
Text: "Text body",
RequireTLS: &trueVar,
// MailDev embeds a self-signed certificate which can't be retrieved.
TLSConfig: commoncfg.TLSConfig{InsecureSkipVerify: true},
TLSConfig: &commoncfg.TLSConfig{InsecureSkipVerify: true},
},
c.Server,
)