WeChat Public Number: Operations and Maintenance Development Story, Author: wanger
demand
For people who often maintain the website, they need to deal with https certificates frequently. Generally, the validity period of https certificates is one year. Once the certificates expire, the loss to the company is enormous. Last year NetEase mailbox because https certificates forgot to renew, resulting in a large number of users unable to use the mailbox normally is a good example. It's not realistic to check manually when we think about it. The best way to do this is to monitor expiration times and send notifications automatically at a certain time. You can use ZABBIX or ssl_from Prometheus Exporter to monitor, at zabbix4. Before version 4, zabbix-agent2 appeared after version 4.4 using custom scripts. In addition to the official plug-ins, they can also be customized to meet our monitoring needs. Then, we will show you how to use the zabbix-agent2 custom plug-ins to achieve the requirements of obtaining https certificate expiration time.
zabbix-agent2 custom https_expire plug-in
Previous questions have described how to use custom plugins to monitor mqtt, the original address https://mp.weixin.qq.com/s/4e6WnFyjXZYnXphx2erkGw However, the Watcher interface was used to actively push the new data to the server side. This time, the data will be collected by implementing the Exporter interface. Here is the official document again https://www.zabbix.com/documentation/current/manual/config/items/plugins Translate official posts with Zabbix Certified Expert Mihong https://mp.weixin.qq.com/s/7JLuVdZYX719pgGSP3xc9w
Here I'll recap some of the standard specifications for custom plug-ins
1. Plugins must import zabbix.com/pkg/plugin package.
import "zabbix.com/pkg/plugin"
1. A plug-in must define a structure and embed the plugin.Base structure.
type Plugin struct { plugin.Base } var impl Plugin
1. A plug-in must implement one or more plug-in interfaces.
func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error) { if len(params) > 0 { p.Debugf("received %d parameters while expected none", len(params)) return nil, errors.New("Too many parameters") } return time.Now().Format(time.RFC3339) }
1. The plug-in must register itself during initialization.
func init() { plugin.RegisterMetrics(&impl, "Time", "system.time", "Returns time string in RFC 3999 format.") }
Ssl_ Not many expire codes. Plugin written by Nicola Tulakesky Wang Er. Complete code can go github See
func (p *Plugin) Configure(global *plugin.GlobalOptions, options interface{}) { if err = conf.Unmarshal(options, &p.options); err != nil { p.Errf("cannot unmarshal configuration options: %s", err) } if p.options.Timeout == 0 { p.options.Timeout = global.Timeout } p.client = newClient(p.options.Timeout) } func (p *Plugin) Validate(options interface{}) error { return conf.Unmarshal(options, &opts) } func checkParamnums(params []string) error { if len(params) > paramnums { err:=errors.New("Too many parameters.") return zbxerr.ErrorTooFewParameters.Wrap(err) } else if len(params) ==0 { err:=errors.New("Missing URL parameters.") return zbxerr.ErrorTooFewParameters.Wrap(err) } return nil } func checkParams(params []string) (string, error) { if strings.HasPrefix(params[0], "http://") { errorsting:=fmt.Sprintf("Target is using http scheme: %s", params[0]) err:=errors.New(errorsting) return "",zbxerr.ErrorInvalidParams.Wrap(err) } if !strings.HasPrefix(params[0], "https://") { params[0] = "https://" + params[0] } return string(params[0]),nil } func (cli *client) Query(url string) (int64, error) { resp, err := cli.client.Get(url) if err != nil { impl.Debugf("cannot fetch data: %s", err) err:=errors.New("cannot fetch data") return 0, zbxerr.ErrorCannotFetchData.Wrap(err) } defer resp.Body.Close() certInfo:=resp.TLS.PeerCertificates[0] expiredays:=(certInfo.NotAfter.Unix()-time.Now().Unix())/60/60/24 return expiredays,nil } // Export implements the Exporter interface. func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (interface{}, error) { if err = checkParamnums(params); err != nil { return nil, err } urls,err:= checkParams(params) if err!= nil { return nil,err } body, err := p.client.Query(urls) if err!=nil{ return nil, err } return body,nil } func init() { plugin.RegisterMetrics(&impl, pluginName, "https_expire", "Returns the number of days between the HTTPS certificate expiration time and the current date.") }
Download the zabbix agent2 source and compile the custom plug-in
yum install golang git clone https://git.zabbix.com/scm/zbx/zabbix.git --depth 1 zabbix-agent2 cd zabbix-agent2 git submodule add https://github.com/cxf210/ssl_expire.git src/go/plugins/https_expire
Import https_expire plug-in
vi src/go/plugins/plugins_linux.go
Add last line
_ "zabbix.com/plugins/ceph" _ "zabbix.com/plugins/docker" _ "zabbix.com/plugins/kernel" _ "zabbix.com/plugins/log" _ "zabbix.com/plugins/memcached" _ "zabbix.com/plugins/modbus" _ "zabbix.com/plugins/mqtt" _ "zabbix.com/plugins/mysql" _ "zabbix.com/plugins/net/netif" _ "zabbix.com/plugins/net/tcp" ... _ "zabbix.com/plugins/https_expire"
Compile and install zabbix agent2
yum install automake autoconf pcre* -y ./bootstrap.sh pushd . cd src/go/ go mod vendor popd ./configure --enable-agent2 --enable-static make install
Edit Profile
Here I have adjusted the log level to facilitate foreground debugging
Optional parameters
Plugins.Https_expire.Timeout = 5
egrep -v "^$|^#" conf/zabbix_agent2.conf LogType=console LogFile=/tmp/zabbix_agent2.log DebugLevel=4 Server=172.17.0.5 Plugins.Https_expire.Timeout=5 Hostname=node2 ControlSocket=/tmp/agent.sock
Start Zabbix_agent2
cd /root/zabbix_agent/src/go/bin zabbix_agent2 -c conf/zabbix_agent2.conf
![image.png](https://img-blog.csdnimg.cn/img_convert/01e581803e6800e564773504acd5a50d.png#align=left&display=inline&height=81&margin=[object Object]&name=image.png&originHeight=161&originWidth=1060&size=30987&status=done&style=none&width=530)
Zabbix Create Monitoring Items
Examples of key values are as follows
https_expire["www.xyzabbix.cn"]
or
https_expire["https://www.xyzabbix.cn"]
![image.png](https://img-blog.csdnimg.cn/img_convert/d1fe529aa9654569c15a7e152c271045.png#align=left&display=inline&height=336&margin=[object Object]&name=image.png&originHeight=672&originWidth=930&size=46093&status=done&style=none&width=465)
Look at the latest data. This certificate has forty days to expire
![image.png](https://img-blog.csdnimg.cn/img_convert/532389a54e779e6c31ee9a228b2d950a.png#align=left&display=inline&height=80&margin=[object Object]&name=image.png&originHeight=159&originWidth=1625&size=15012&status=done&style=none&width=812.5)
I'm using the Ali Cloud ssl certificate and I can see that there are actually forty days before the expiration date. Today is 2021.3.7
![image.png](https://img-blog.csdnimg.cn/img_convert/a9e0059914c661a2288c57a573f193b2.png#align=left&display=inline&height=118&margin=[object Object]&name=image.png&originHeight=236&originWidth=1497&size=21620&status=done&style=none&width=748.5)
You can create a trigger to send an alert when there is still a month to go
![image.png](https://img-blog.csdnimg.cn/img_convert/7921a39a29c3807bfbde3372e13b2f02.png#align=left&display=inline&height=302&margin=[object Object]&name=image.png&originHeight=603&originWidth=949&size=40242&status=done&style=none&width=474.5)