快速实现一个企业级域名 SSL 证书有效期监控巡检系统

Why

现在对于企业来说,HTTPS 已经不是可选项,已经成为一个必选项。HTTPS 协议采用 SSL 协议,采用公开密钥的技术,提供了一套 TCP/IP 传输层数据加密的机制。SSL 证书是一种遵守 SSL 协议的服务器数字证书,一般是由权威机构颁发给网站的可信凭证。SSL 证书是有过期时间的限制的,从 2020 年的 9 月以后,权威机构颁发的 SSL 证书的最长有效期被限制在 398 天以内,也就是说,基本上每个网站都需要每年更新或者替换一次 SSL 证书,不然证书过期会导致网站无法访问、数据被暴露等各种风险。

根据互联网公开的信息,2018 年 12 月,日本运营商软银数字证书过期导致 3060 万用户通信故障长达 4 个多小时;2020 年 2 月,微软协同办公软件 Team 因证书过期在全球范围内处于宕机瘫痪状态;2020 年 5 月 13 日,特斯拉因证书过期导致 APP 出现大面积宕机,导致大部分车主被锁在车外。据《企业数字证书管理安全调查》统计报告,74% 的组织都经历过证书过期的停机故障,每个组织的平均损失超过 1100 万美元。

证书有效期的缩短,增加了证书更新的频率,导致使用加密证书的网站所有者和企业的管理周期变得更加复杂,对许多依赖数字证书保护系统的公司来说,带来很大的证书管理成本,对于 SSL 证书的管理者来说,建设一套 SSL 证书有效期的监控巡检系统非常有必要。

How

本文实现的 SSL 证书有效期监控巡检系统原理比较简单,大致流程如下图所示。本质上就是通过 Python 脚本获取域名的 SSL 证书文件,一般来说证书文件内容会包括颁发机构、证书序列号、有效期起始时间、有效期结束时间等信息,获取证书的有效期结束时间后,判断证书是否即将过期,将过期事件推送至观测云(www.guance.com),巡检系统配置对应的告警策略,发生事件告警后推送至钉钉群或企微群。

What

下面将会详细介绍如何利用观测云(www.guance.com)的智能巡检能力帮助企业快速构建一个 SSL 证书有效期监控巡检系统。

前提条件:注册观测云

登录观测云官网(www.guance.com)注册观测云。

步骤一:安装或开通 DataFlux Func

DataFlux Func (func.guance.com)是一个基于 Python 的脚本开发、管理、执行平台,可以非常快速方便的帮助我们执行 Python 脚本。

执行以下命令安装 DataFlux Func 平台。

复制代码
/bin/bash -c "$(curl -fsSL func.guance.com/portable-download)" -- --for=GSE

或者登录到在观测云控制台「集成」-「扩展」,开通「DataFlux Func 托管版」。

步骤二:获取 API Key

在观测云控制台「管理」 -「API Key 管理」-「新建 Key」,保留生成的 Key ID 和 Key 。

步骤三:运行 SSL 证书有效期巡检脚本

1.进入步骤一搭建的 Func 平台,进入「管理」-「实验室」功能,「开启 PIP 工具模块」。

2.进入「管理」-「PIP 工具」,输入 pyopenssl,点击「安装」。

3.进入「脚本市场」-「官方脚本市场」,搜索并安装「观测云自建巡检 Core 核心包」。

4.进入「开发」-「新建脚本集」,填写 ID 和标题(此处可按需求随意填写),点击「保存」。

5.进入「开发」-「SSL证书有效期监控巡检」-「新建脚本」,填写脚本 ID。

6.复制以下代码到「SSL 证书有效期监控巡检」-「main」脚本中,修改 133 行和 134 行的 API_KEY_ID 和 API_KEY 为步骤二创建的 Key ID 和 Key ,修改 12 行的 domain_list,添加需要巡检的域名,点击右上角「发布」,若需脚本功能,可在编辑状态点击运行。

复制代码
import arrow
from urllib3.contrib import pyopenssl
from dateutil import parser
from socket import socket

from guance_monitor__cloud_checker import BaseCloudChecker
import guance_monitor__utils as utils
import guance_monitor__event_detail as event_detail
from guance_monitor__register import self_hosted_monitor
from guance_monitor__runner import Runner

domain_list = [
    'www.guance.com',
    'func.guance.com'
]

class SSLChecker(BaseCloudChecker):
    def _get_domain_list(self):
        '''
        可对接内部域名管理系统
        '''
        return domain_list

    def _get_ssl_detail_data(self, domain, port=443):
        try:
            connection = pyopenssl.ssl.create_connection((domain, 443))
            socket = pyopenssl.ssl.SSLContext(pyopenssl.ssl.PROTOCOL_SSLv23).wrap_socket(connection, server_hostname=domain)
            certificate = pyopenssl.ssl.DER_cert_to_PEM_cert(socket.getpeercert(True))
            connection.close()
            cert_obj = pyopenssl.OpenSSL.crypto.load_certificate(pyopenssl.OpenSSL.crypto.FILETYPE_PEM, certificate)
            cert_issue = cert_obj.get_issuer()
            return {
                'version': cert_obj.get_version() + 1,
                'serial_number': cert_obj.get_serial_number(),
                'issue': cert_issue.commonName,
                'start_date': parser.parse(cert_obj.get_notBefore().decode("UTF-8")),
                'expire_date': parser.parse(cert_obj.get_notAfter().decode("UTF-8"))
            }
        except Exception as e:
            print(f'get certificate failed, domain: {domain}, err: {e}')
            return None

    def _build_event_detail(self, ssl_data, advice, title, content):
        event_details = event_detail.Detail()
        event_tab = event_detail.Tab(name="事件详情", index=0)

        # md section
        md_section = event_detail.Section('事件概览', index=0)
        md = event_detail.Markdown("")
        text_list = [
            f'**检测对象**:{ssl_data["域名"]}',
            f'**异常描述**:{content}',
            f'**操作建议**:{advice}'
        ]
        md.set_text(*text_list)
        md_section.add(md)

        # 详情section
        instance_detail_section = event_detail.Section('异常详情', index=1)
        detail_table = event_detail.Table('该域名 SSL 证书的详细信息如下')
        detail_table.set_header('属性', '值')
        for key, value in ssl_data.items():
            detail_table.add_row(key, value)
        instance_detail_section.add(detail_table)

        event_tab.add(md_section, instance_detail_section)
        event_details.add(event_tab)

        return event_details

    def _check_impl(self, dataway, configs):
        events = []
        for domain in self._get_domain_list():
            ssl_data = self._get_ssl_detail_data(domain)
            if ssl_data is None:
                continue
            start_date = ssl_data['start_date']
            expire_date = ssl_data['expire_date']
            # 若需测试脚本功能,可修改以下过期时间
            # expire_date = '2022-12-06 15:27:00+08:00'
            expire_day = (arrow.get(expire_date).to('Asia/Shanghai') - arrow.now()).days
            print(expire_day)
            show_day = arrow.get(expire_date).to('Asia/Shanghai').humanize(arrow.utcnow(), locale='zh')

            if expire_day > 14:
                continue
            elif 7 < expire_day <= 14:
                lever = 'warning'
                expired_time = f'预计到期{show_day}'
                content = f'发现您有一个域名 SSL 证书还有 {show_day} 过期。'
            elif 0 <= expire_day <= 7:
                lever = 'critical'
                expired_time = f'预计到期{show_day}'
                content = f'发现您有一个域名 SSL 证书还有 {show_day} 过期。'
            else:
                lever = 'critical'
                expired_time = f'过期时间{show_day}'
                content = f'发现您有一个域名 SSL 证书已经过期。'

            expire_advice = '请及时对 SSL 证书进行续费,否则证书过期后会导致您的业务受到影响。'
            complete_title = f'{domain} 的 SSL 证书{"即将过期" if expire_day >= 0 else "已经到期"}'
            ssl_detail_data = {
                '域名': domain,
                '证书版本号': ssl_data['version'],
                '证书序列号': ssl_data['serial_number'],
                '颁发机构': ssl_data['issue'],
                '起始时间': arrow.get(start_date).to('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss'),
                '截止时间': arrow.get(expire_date).to('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss')
            }

            event_details = self._build_event_detail(ssl_detail_data, expire_advice, domain, content)

            events.append({
                'title': complete_title,
                'message': f'''
                    {content}
                    该域名 SSL 证书的详细信息如下:
                        &emsp;&emsp;域名:{ssl_detail_data['域名']}
                        &emsp;&emsp;证书版本号:{ssl_detail_data['证书版本号']}
                        &emsp;&emsp;证书序列号: {ssl_detail_data['证书序列号']}
                        &emsp;&emsp;颁发机构:{ssl_detail_data['颁发机构']}
                        &emsp;&emsp;起始时间:{ssl_detail_data['起始时间']}
                        &emsp;&emsp;截止时间:{ssl_detail_data['截止时间']}
                    建议:
                        &emsp;&emsp;{expire_advice}
                ''',
                'status': lever,
                'event_detail': event_details.to_json()
            })
        return events


API_KEY_ID = 'wsak_69ea3***cee'
API_KEY = 'jaZu***I0'

@self_hosted_monitor(API_KEY_ID, API_KEY)
@DFF.API('SSL证书过期时间巡检')
def checker(name=''):
    checkers = [
        # 配置检测项(目前已支持的检测项见下文)
        SSLChecker(),
    ]
    Runner(checkers, debug=False).run()

Tips:

  • 若需测试脚本过期时间提示功能,可打开 80 行注释,可自定义证书过期时间,点击「执行」可测试脚本查看结果
  • 若需对接内部域名管理系统,可修改 _get_domain_list 函数

7.进入「管理」-「自动触发配置」-「新建」,选择「执行函数」,按照实际要求来设置脚本执行频率,以下设置为每天 08:00 定时触发脚本

步骤四:配置智能巡检告警策略

1.进入观测云控制台(console.guance.com),选择「监控」-「通知对象管理」-「新建通知对象」,按照实际要求添加通知对象,具体步骤可参考添加页面「更多帮助」。

2.进入「监控」-「告警策略管理」-「新建告警策略」,输入「名称」,告警通知对象选择第一步创建的通知对象。

3.进入「监控」-「智能巡检」,点击修改「SSL 证书过期时间巡检」,「告警策略」选择第二步创建的告警策略。

Tips:步骤三的脚本至少要运行一次才会有 SSL 证书过期时间巡检这个选项

效果展示

  • 通过观测云「事件」,可以对 SSL 证书过期事件进行管理
  • 告警推送效果

总结

这篇文章重点介绍如何利用现有平台的能力快速帮助构建企业级的 SSL 证书有效期监控巡检系统。除此之外,观测云本身也可以支持接入指标、链路和日志等可观测性数据,并且可以对这些数据进行统一的标签处理,控制台可实现可观测性数据的互相关联打通,方便运维、研发和测试团队从一个平面理解系统运行情况,可大大提升软件开发交付的效率。

相关推荐
张飞的猪6 天前
通过Certbot自动申请更新HTTPS网站的SSL证书
ssl证书·certbot
SRETalk7 天前
为 Prometheus 告警规则增加 UI 管理能力
prometheus·监控告警·夜莺监控·运维监控
�FENG10 天前
Prometheus 监控平台部署 (云原生环境)
云原生·kubernetes·prometheus·监控告警
SRETalk24 天前
底层的告警,上层业务应该收吗?
监控告警·告警订阅
SRETalk25 天前
CPU 负载高,到底应不应该告警?
监控告警·运维监控
SRETalk2 个月前
夜莺监控V8发版,内置支持 DeepSeek 对接
aiops·监控告警·夜莺监控·运维监控·deepseek
醉殇姒若梦遗年5 个月前
给网站配置https访问
网络协议·https·解决方案·ssl证书
智驱力人工智能5 个月前
智能飞鸟监测 守护高压线安全
人工智能·计算机视觉·视觉检测·智能巡检·视觉算法·飞鸟检测·视觉分析
智驱力人工智能5 个月前
安全守护:反光衣检测技术的革新之路
人工智能·安全·计算机视觉·智慧城市·智慧工地·智能巡检·智慧监控