diff --git a/README.MD b/README.MD
index f0bb2c20..09fe5abe 100644
--- a/README.MD
+++ b/README.MD
@@ -53,7 +53,7 @@ make docker/docker-push/docker-test
# 本地测试运行
make clean && make build
copy conf/app-example.conf conf/app.conf
-build/bin/PrometheusAlert
+./PrometheusAlert
# 测试应用健康
curl http://localhost:8080/health
@@ -136,6 +136,7 @@ feiyu563/prometheus-alert:latest
- 增加支持飞书机器人应用。
- 增加告警组,可以将通知媒介写到告警组里面,便于配置和修改。
- 增加热加载配置接口
+ - 增加钉钉加签
-------------------------------------
diff --git a/conf/app-example.conf b/conf/app-example.conf
index fe8307a3..a7265ef5 100644
--- a/conf/app-example.conf
+++ b/conf/app-example.conf
@@ -69,6 +69,9 @@ open-dingding=1
ddurl=https://oapi.dingtalk.com/robot/send?access_token=xxxxx
#是否开启 @所有人(0为关闭,1为开启)
dd_isatall=1
+#是否开启钉钉机器人加签,0为关闭,1为开启
+# 使用方法:https://oapi.dingtalk.com/robot/send?access_token=XXXXXX&secret=mysecret
+open-dingding-secret=0
#是否开启微信告警通道,可同时开始多个通道0为关闭,1为开启
open-weixin=1
diff --git a/controllers/dingding.go b/controllers/dingding.go
index ebb00239..04db30c8 100644
--- a/controllers/dingding.go
+++ b/controllers/dingding.go
@@ -3,14 +3,20 @@ package controllers
import (
"PrometheusAlert/models"
"bytes"
+ "crypto/hmac"
+ "crypto/sha256"
"crypto/tls"
+ "encoding/base64"
"encoding/json"
- "github.com/astaxie/beego"
- "github.com/astaxie/beego/logs"
- "io/ioutil"
+ "io"
"net/http"
"net/url"
+ "strconv"
"strings"
+ "time"
+
+ "github.com/astaxie/beego"
+ "github.com/astaxie/beego/logs"
)
type DDMessage struct {
@@ -31,6 +37,11 @@ func PostToDingDing(title, text, Ddurl, AtSomeOne, logsign string) string {
logs.Info(logsign, "[dingding]", "钉钉接口未配置未开启状态,请先配置open-dingding为1")
return "钉钉接口未配置未开启状态,请先配置open-dingding为1"
}
+ // dingding sign
+ if openSecret := beego.AppConfig.String("open-dingding-secret"); openSecret == "1" {
+ Ddurl = dingdingSign(Ddurl)
+ }
+
Isatall, _ := beego.AppConfig.Int("dd_isatall")
Atall := true
if Isatall == 0 {
@@ -82,7 +93,7 @@ func PostToDingDing(title, text, Ddurl, AtSomeOne, logsign string) string {
logs.Error(logsign, "[dingding]", err.Error())
}
defer res.Body.Close()
- result, err := ioutil.ReadAll(res.Body)
+ result, err := io.ReadAll(res.Body)
if err != nil {
logs.Error(logsign, "[dingding]", err.Error())
}
@@ -91,3 +102,41 @@ func PostToDingDing(title, text, Ddurl, AtSomeOne, logsign string) string {
logs.Info(logsign, "[dingding]", string(result))
return string(result)
}
+
+// dingdingSign adds sign and timestamp parms to dingding webhook url
+// docs: https://open.dingtalk.com/document/orgapp/custom-bot-creation-and-installation
+func dingdingSign(ddurl string) string {
+ timestamp := time.Now()
+ timestampMs := timestamp.UnixNano() / int64(time.Millisecond)
+ tsMsStr := strconv.FormatInt(timestampMs, 10)
+ // parse ddurl parms
+ u, err := url.Parse(ddurl)
+ if err != nil {
+ logs.Info("[dingdingSign]", "配置文件已开启钉钉加签,钉钉机器人地址解析加签参数 secret 失败,将使用不加签的地址!")
+ return ddurl
+ }
+ // get parm secret
+ queryParams := u.Query()
+ secret := queryParams.Get("secret")
+ if len(secret) == 0 {
+ logs.Info("[dingdingSign]", "配置文件已开启钉钉加签,钉钉机器人地址解析加签参数 secret 为空,将使用不加签的地址!")
+ return ddurl
+ }
+ // sign string
+ signStr := tsMsStr + "\n" + secret
+ // HmacSHA256
+ key := []byte(secret)
+ h := hmac.New(sha256.New, key)
+ h.Write([]byte(signStr))
+ signature := h.Sum(nil)
+ // Base64
+ sign := base64.StdEncoding.EncodeToString(signature)
+ // splice url
+ delete(queryParams, "secret")
+ queryParams.Add("timestamp", tsMsStr)
+ queryParams.Add("sign", sign)
+ u.RawQuery = queryParams.Encode()
+ signURL := u.String()
+
+ return signURL
+}
diff --git a/controllers/dingding_test.go b/controllers/dingding_test.go
new file mode 100644
index 00000000..f07f297b
--- /dev/null
+++ b/controllers/dingding_test.go
@@ -0,0 +1,42 @@
+package controllers
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestDDMesage(t *testing.T) {
+ // A sample dingding message json payload
+ payload := `
+ {
+ "msgtype": "markdown",
+ "markdown": {
+ "title": "AlertPrometheus告警测试",
+ "text": "**测试告警信息**\n"
+ },
+ "at": {
+ "atMobiles": ["139xxxxxxxx", "159xxxxxxxx"],
+ "isAtAll": false
+ }
+ }`
+ message := DDMessage{}
+ err := json.Unmarshal([]byte(payload), &message)
+ assert.Nil(t, err)
+}
+
+func TestDingdingSign(t *testing.T) {
+ var want, result string
+
+ // url without parm secret
+ withoutURL := "https://oapi.dingtalk.com/robot/send?access_token=XXX"
+ want = withoutURL
+ result = dingdingSign(withoutURL)
+ assert.Equal(t, want, result)
+
+ // url with parm secret
+ withURL := "https://oapi.dingtalk.com/robot/send?access_token=XXX&secret=mysecret"
+ result = dingdingSign(withURL)
+ t.Logf("一个示例的加签的地址:%s", result)
+}
diff --git a/doc/readme/conf-dingding.md b/doc/readme/conf-dingding.md
index 72cb2f11..b8870143 100644
--- a/doc/readme/conf-dingding.md
+++ b/doc/readme/conf-dingding.md
@@ -1,8 +1,6 @@
# PrometheusAlert全家桶钉钉配置说明
------------------
-
- **开启钉钉机器人**
+## 开启钉钉机器人
打开钉钉,进入钉钉群中,选择群设置-->智能群助手-->添加机器人-->自定义,可参下图:
@@ -10,6 +8,8 @@
![ding2](../images/dingding2.png)
+
+
新版本的钉钉加了安全设置,只需选择安全设置中的 自定义关键词 即可,并将关键词设置为 Prometheus或者app.conf中设置的title值均可,参考下图
![ding3](../images/dingding3.png)
@@ -18,12 +18,15 @@
复制图中的Webhook地址,并填入PrometheusAlert配置文件app.conf中对应配置项即可。
+
+
**PS: 钉钉机器人目前已经支持 `@某人` ,使用该功能需要取得对应用户的钉钉关联手机号码,如下图:**
+
![ding4](../images/dingding5.png)
钉钉目前支持只支持markdown语法的子集,具体支持的元素如下:
-```
+```md
标题
# 一级标题
## 二级标题
@@ -54,9 +57,38 @@
2. item2
```
-钉钉相关配置:
+
+
+
+## 钉钉加签配置
+
+增加钉钉加签的配置。创建自定义机器人的时候,选择加签,并复制加签内容组装到到机器人地址参数(webhook url parm secret)。程序会获取这个 `secret` 参数,进行加签处理之后生成对应的加签地址。
+
+如果配置文件中启用了钉钉加签认证,但 webhook url 并没有传递 parm secret,那么程序将返回不加签的地址。也就是说,PrometheusAlert 配置中启用钉钉加签并不会影响不加签的机器人。
+
+示例如下:
+```conf
+# 默认的钉钉机器人地址 webhook url 格式
+https://oapi.dingtalk.com/robot/send?access_token=XXX
+
+# 假如机器人加签内容为:mysecret
+# 带上加签参数: secret=mysecret
+https://oapi.dingtalk.com/robot/send?access_token=XXX&secret=mysecret
+
+# 程序加签处理后生成的加签地址
+https://oapi.dingtalk.com/robot/send?access_token=XXXXXX×tamp=XXX&sign=XXX
+
+# 如果配置文件中启用了钉钉加签认证,但 webhook url 并没有传递 parm secret,那么程序将返回不加签的地址
+https://oapi.dingtalk.com/robot/send?access_token=XXX
```
+
+
+
+
+## 钉钉相关配置
+
+```ini
#---------------------↓全局配置-----------------------
#告警消息标题
title=PrometheusAlert
@@ -72,15 +104,21 @@ open-dingding=1
ddurl=https://oapi.dingtalk.com/robot/send?access_token=xxxxx
#是否开启 @所有人(0为关闭,1为开启)
dd_isatall=1
+#是否开启钉钉机器人加签,0为关闭,1为开启
+# 使用方法:https://oapi.dingtalk.com/robot/send?access_token=XXXXXX&secret=mysecret
+open-dingding-secret=0
```
-**如何使用**
+
+
+
+## 如何使用
以Prometheus配合自定义模板为例:
Prometheus配置参考:
-```
+```yml
global:
resolve_timeout: 5m
route:
@@ -93,4 +131,4 @@ receivers:
- name: 'web.hook.prometheusalert'
webhook_configs:
- url: 'http://[prometheusalert_url]:8080/prometheusalert?type=dd&tpl=prometheus-dd&ddurl=钉钉机器人地址,钉钉机器人地址2&at=18888888888,18888888889'
-```
\ No newline at end of file
+```