From 7581d974ffd80db1361b824a094f4f358708abdb Mon Sep 17 00:00:00 2001 From: Fabian Reinartz Date: Thu, 3 Dec 2015 12:40:50 +0100 Subject: [PATCH] Hide secret configuration data --- config/config.go | 55 ++++++++++++++++++++++++++++----------------- config/notifiers.go | 22 +++++++++--------- notify/impl.go | 6 ++--- ui/bindata.go | 2 +- 4 files changed, 49 insertions(+), 36 deletions(-) diff --git a/config/config.go b/config/config.go index 87c7aa4f..a741f613 100644 --- a/config/config.go +++ b/config/config.go @@ -26,6 +26,16 @@ import ( "gopkg.in/yaml.v2" ) +var patAuthLine = regexp.MustCompile(`((?:api_token|api_key|service_key|api_url):\s+)(".+"|'.+'|[^\s]+)`) + +// Secret is a string that must not be revealed on marshaling. +type Secret string + +// MarshalYAML implements the yaml.Marshaler interface. +func (s Secret) MarshalYAML() (interface{}, error) { + return "", nil +} + // Load parses the YAML input s into a Config. func Load(s string) (*Config, error) { cfg := &Config{} @@ -101,14 +111,17 @@ func checkOverflow(m map[string]interface{}, ctx string) error { } func (c Config) String() string { + var s string if c.original != "" { - return c.original + s = c.original + } else { + b, err := yaml.Marshal(c) + if err != nil { + return fmt.Sprintf("", err) + } + s = string(b) } - b, err := yaml.Marshal(c) - if err != nil { - return fmt.Sprintf("", err) - } - return string(b) + return patAuthLine.ReplaceAllString(s, "${1}") } // UnmarshalYAML implements the yaml.Unmarshaler interface. @@ -149,11 +162,11 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error { } } for _, sc := range rcv.SlackConfigs { - if sc.URL == "" { - if c.Global.SlackURL == "" { - return fmt.Errorf("no global Slack URL set") + if sc.APIURL == "" { + if c.Global.SlackAPIURL == "" { + return fmt.Errorf("no global Slack API URL set") } - sc.URL = c.Global.SlackURL + sc.APIURL = c.Global.SlackAPIURL } } for _, pdc := range rcv.PagerdutyConfigs { @@ -197,7 +210,7 @@ type GlobalConfig struct { SMTPFrom string `yaml:"smtp_from"` SMTPSmarthost string `yaml:"smtp_smarthost"` - SlackURL string `yaml:"slack_url"` + SlackAPIURL Secret `yaml:"slack_api_url"` PagerdutyURL string `yaml:"pagerduty_url"` OpsGenieAPIHost string `yaml:"opsgenie_api_host"` } @@ -221,8 +234,8 @@ type Route struct { GroupWait *model.Duration `yaml:"group_wait,omitempty"` GroupInterval *model.Duration `yaml:"group_interval,omitempty"` - RepeatInterval *model.Duration `yaml:"repeat_interval"` - SendResolved *bool `yaml:"send_resolved"` + RepeatInterval *model.Duration `yaml:"repeat_interval,omitempty"` + SendResolved *bool `yaml:"send_resolved,omitempty"` // Catches all undefined fields and must be empty after parsing. XXX map[string]interface{} `yaml:",inline"` @@ -322,14 +335,14 @@ type Receiver struct { // A unique identifier for this receiver. Name string `yaml:"name"` - EmailConfigs []*EmailConfig `yaml:"email_configs"` - FlowdockConfigs []*FlowdockConfig `yaml:"flowdock_configs"` - HipchatConfigs []*HipchatConfig `yaml:"hipchat_configs"` - PagerdutyConfigs []*PagerdutyConfig `yaml:"pagerduty_configs"` - PushoverConfigs []*PushoverConfig `yaml:"pushover_configs"` - SlackConfigs []*SlackConfig `yaml:"slack_configs"` - WebhookConfigs []*WebhookConfig `yaml:"webhook_configs"` - OpsGenieConfigs []*OpsGenieConfig `yaml:"opsgenie_configs"` + EmailConfigs []*EmailConfig `yaml:"email_configs,omitempty"` + FlowdockConfigs []*FlowdockConfig `yaml:"flowdock_configs,omitempty"` + HipchatConfigs []*HipchatConfig `yaml:"hipchat_configs,omitempty"` + PagerdutyConfigs []*PagerdutyConfig `yaml:"pagerduty_configs,omitempty"` + PushoverConfigs []*PushoverConfig `yaml:"pushover_configs,omitempty"` + SlackConfigs []*SlackConfig `yaml:"slack_configs,omitempty"` + WebhookConfigs []*WebhookConfig `yaml:"webhook_configs,omitempty"` + OpsGenieConfigs []*OpsGenieConfig `yaml:"opsgenie_configs,omitempty"` // Catches all undefined fields and must be empty after parsing. XXX map[string]interface{} `yaml:",inline"` diff --git a/config/notifiers.go b/config/notifiers.go index eb3983b5..c98bb30c 100644 --- a/config/notifiers.go +++ b/config/notifiers.go @@ -39,10 +39,10 @@ var ( Client: `{{ template "pagerduty.default.client" . }}`, ClientURL: `{{ template "pagerduty.default.clientURL" . }}`, Details: map[string]string{ - "firing": `{{ template "pagerduty.default.instances" (.Alerts | firing) }}`, - "resolved": `{{ template "pagerduty.default.instances" (.Alerts | resolved) }}`, - "num_firing": `{{ .Alerts | firing | len }}`, - "num_resolved": `{{ .Alerts | resolved | len }}`, + "firing": `{{ template "pagerduty.default.instances" .Alerts.Firing }}`, + "resolved": `{{ template "pagerduty.default.instances" .Alerts.Resolved }}`, + "num_firing": `{{ .Alerts.Firing | len }}`, + "num_resolved": `{{ .Alerts.Resolved | len }}`, }, } @@ -68,7 +68,7 @@ var ( // FlowdockConfig configures notifications via Flowdock. type FlowdockConfig struct { // Flowdock flow API token. - APIToken string `yaml:"api_token"` + APIToken Secret `yaml:"api_token"` // Flowdock from_address. FromAddress string `yaml:"from_address"` @@ -155,7 +155,7 @@ const ( // https://www.hipchat.com/docs/apiv2/method/send_room_notification type HipchatConfig struct { // HipChat auth token, (https://www.hipchat.com/docs/api/auth). - AuthToken string `yaml:"auth_token"` + APIToken Secret `yaml:"api_token"` // HipChat room id, (https://www.hipchat.com/rooms/ids). RoomID int `yaml:"room_id"` @@ -183,8 +183,8 @@ func (c *HipchatConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { if err := unmarshal((*plain)(c)); err != nil { return err } - if c.AuthToken == "" { - return fmt.Errorf("missing auth token in HipChat config") + if c.APIToken == "" { + return fmt.Errorf("missing API token in HipChat config") } if c.MessageFormat != HipchatFormatHTML && c.MessageFormat != HipchatFormatText { return fmt.Errorf("invalid message format %q", c.MessageFormat) @@ -194,7 +194,7 @@ func (c *HipchatConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { // PagerdutyConfig configures notifications via PagerDuty. type PagerdutyConfig struct { - ServiceKey string `yaml:"service_key"` + ServiceKey Secret `yaml:"service_key"` URL string `yaml:"url"` Client string `yaml:"client"` ClientURL string `yaml:"client_url"` @@ -247,7 +247,7 @@ func (c *PushoverConfig) UnmarshalYAML(unmarshal func(interface{}) error) error // SlackConfig configures notifications via Slack. type SlackConfig struct { - URL string `yaml:"url"` + APIURL Secret `yaml:"api_url"` // Slack channel override, (like #other-channel or @username). Channel string `yaml:"channel"` @@ -300,7 +300,7 @@ func (c *WebhookConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { // OpsGenieConfig configures notifications via OpsGenie. type OpsGenieConfig struct { - APIKey string `yaml:"api_key"` + APIKey Secret `yaml:"api_key"` APIHost string `yaml:"api_host"` Description string `yaml:"description"` Source string `yaml:"source"` diff --git a/notify/impl.go b/notify/impl.go index a5fee92d..6d487d9d 100644 --- a/notify/impl.go +++ b/notify/impl.go @@ -308,7 +308,7 @@ func (n *PagerDuty) Notify(ctx context.Context, as ...*types.Alert) error { } msg := &pagerDutyMessage{ - ServiceKey: tmpl(n.conf.ServiceKey), + ServiceKey: tmpl(string(n.conf.ServiceKey)), EventType: eventType, IncidentKey: key, Description: tmpl(n.conf.Description), @@ -411,7 +411,7 @@ func (n *Slack) Notify(ctx context.Context, as ...*types.Alert) error { return err } - resp, err := ctxhttp.Post(ctx, http.DefaultClient, n.conf.URL, contentTypeJSON, &buf) + resp, err := ctxhttp.Post(ctx, http.DefaultClient, string(n.conf.APIURL), contentTypeJSON, &buf) if err != nil { return err } @@ -474,7 +474,7 @@ func (n *OpsGenie) Notify(ctx context.Context, as ...*types.Alert) error { apiURL string apiMsg = opsGenieMessage{ - APIKey: n.conf.APIKey, + APIKey: string(n.conf.APIKey), Alias: key, } alerts = types.Alerts(as...) diff --git a/ui/bindata.go b/ui/bindata.go index 434f5f01..5a774040 100644 --- a/ui/bindata.go +++ b/ui/bindata.go @@ -301,7 +301,7 @@ func uiBindataGo() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "ui/bindata.go", size: 77824, mode: os.FileMode(420), modTime: time.Unix(1448991327, 0)} + info := bindataFileInfo{name: "ui/bindata.go", size: 77824, mode: os.FileMode(420), modTime: time.Unix(1449127936, 0)} a := &asset{bytes: bytes, info: info} return a, nil }