nginx upstream server主动健康监测模块添加https检测功能【上】

1 缘起

前面的《nginx upstream server主动健康检测模块ngx_http_upstream_check_module 使用和源码分析》系列已经分析了ngx_http_upstream_check_module的实现原理,并且在借助这个模块的框架实现了一个udp健康检测的新功能。

但是ngx_http_upstream_check_module还缺乏基于https监测上游服务器健康状况的能力,始终是一个缺憾,因此,本文基于《nginx upstream server主动健康检测模块ngx_http_upstream_check_module 使用和源码分析》《nginx stream proxy 模块的ssl连接源码分析》两篇博文的分析成果,来实现一个基于https的上游服务器健康检测的能力。

1.1 功能定义

本次支持的功能:

  • 支持向上游服务器发起https请求功能
  • 请求的报文复用原有的http检测的请求报文定义
  • 响应的状态码检测复用原有的http检测的响应码的定义
  • 支持ssl握手过程中添加sni扩展信息
  • 支持ssl握手协议类型的配置
  • 支持ssl握手协议加密套件的配置

暂时不支持的功能:

  • 不支持ssl会话复用(会话复用可以降低上游服务器的ssl握手压力)
  • 不支持ssl证书双向验证
  • 不支持服务器端证书有效性验证

&ems;  由于本次主要是检验https的链接握手流程,对一些不是特别关键的ssl握手特性暂时不支持主要是为了简化代码逻辑,但是不影响业务流程,这样也便于在本文中将整个实现流程进行阐述。后续可以参照ngx_stream_proxy_module中的实现,继续将这些特性进行完善,以臻于完美。

2. 实现后的效果

首先来看一下实现后的效果,有一些感性的认识。

2.1 配置文件

Bash 复制代码
#user  nobody;
worker_processes  1;
daemon off;
master_process off;

error_log  logs/error.log;
pid        logs/nginx.pid;

load_module  objs/ngx_http_upstream_check_module.so;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  logs/access.log  main;
    sendfile        on;
    keepalive_timeout  65;

	upstream backend {
		check type=https interval=3000 rise=2 fall=5 timeout=1000 port=443;
		check_http_send "GET / HTTP/1.1\r\nHost: www.test.com\r\n\r\n";
		check_http_expect_alive http_2xx http_3xx;
        check_ssl_server_name www.test.com;
		server 192.168.0.1:443;
	}

    server {
        listen       9080;
        server_name  localhost;

        # 开启本模块的状态查询接口	
		location /status {
			check_status html;
		}

        location / {
			proxy_pass http://backend;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }
}

以上配置文件中的upstream块中定义了一个https的健康检测类型, check_http_send复用了http的定义,而check_ssl_server_name是新增的指令,用来配置ssl握手设置sni扩展主机host信息。

2.2 运行效果

查看nginx的error.log日志, 可以看到如下信息:

复制代码
2024/02/16 09:31:33 [error] 23638#0: https check failed with return code: 403
2024/02/16 09:31:33 [error] 23638#0: check protocol https error with peer: 192.168.0.1:443
2024/02/16 09:31:45 [info] 23663#0: enable check peer: 192.168.0.1:443

error.log中的前面两条因为服务器响应403报了错误,对应在配置了"check_http_expect_alive http_2xx http_3xx;"的情况。如果配置改成"check_http_expect_alive http_2xx http_3xx http_4xx;" 则报后面那条上游服务器enable的信息。证明https的检测功能已经可用了。

3. 代码实现

3.1 配置指令

3.1.1 配置指令定义:

支持的配置指令如下:

  • check_ssl_ciphers:
        配置加密套件,格式参考proxy_ssl_ciphers
  • check_ssl_protocols:
        和服务器交互采用的ssl协议版本,如TLSv1.1 TLSv1.2等,格式参考proxy_ssl_protocols。
  • check_ssl_server_name:
        和服务器进行ssl握手时候采用的sni扩展host名字,如果不设置并且upstream块中的server是用域名设置的,那么默认就采用设置的服务器名字。
  • check_ssl_verify:[on/off]
        是否校验服务器的证书有效性。(待后续实现)
  • check_ssl_session_reuse: [on/off]
        和上游服务器进行ssl握手的时候是否复用ssl会话信息。

3.1.2 配置指令结构体:

c 复制代码
struct ngx_http_upstream_check_srv_conf_s {
    ngx_uint_t                               port;
    ngx_uint_t                               fall_count;
    ngx_uint_t                               rise_count;
    ngx_msec_t                               check_interval;
    ngx_msec_t                               check_timeout;
    ngx_uint_t                               check_keepalive_requests;

    ngx_check_conf_t                        *check_type_conf;
    ngx_str_t                                send;

    union {
        ngx_uint_t                           return_code;
        ngx_uint_t                           status_alive;
    } code;

    ngx_array_t                             *fastcgi_params;

    ngx_uint_t                               default_down;
    ngx_uint_t                               unique;
    ngx_uint_t                               udp : 1;                       /* 是否udp socket */
    ngx_int_t                                match_part : 1;                /* 是否只要部分匹配就可以了 */
    ngx_int_t                                match_offset;                  /* udp响应期望的内容从哪个字节开始匹配 */
    ngx_str_t                                expect;                        /* udp响应的期望内容 */

#if (NGX_HTTP_SSL)
    ngx_ssl_t                               *ssl;                            /* ssl 配置上下文 */
    ngx_str_t                                ssl_ciphers;                    /* ssl 加密套件 */
    ngx_uint_t                               ssl_protocols;                  /* 采用的ssl协议 */
    ngx_str_t                                ssl_server_name;                /* ssl握手的sni扩展hostname */
#endif
};

以上添加的ssl_protocols参数在ngx_http_upstream_check_create_srv_conf函数中需要将其设置为NGX_CONF_UNSET_UINT,避免nginx在解析配置文件的时候出现参数重复的报错。

3.1.3 配置指令源码定义:

c 复制代码
#if (NGX_HTTP_SSL)
    { ngx_string("check_ssl_ciphers"),
      NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_str_slot,
      NGX_HTTP_SRV_CONF_OFFSET,
      offsetof(ngx_http_upstream_check_srv_conf_t, ssl_ciphers),
      NULL },

    { ngx_string("check_ssl_protocols"),
      NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
      ngx_conf_set_bitmask_slot,
      NGX_HTTP_SRV_CONF_OFFSET,
      offsetof(ngx_http_upstream_check_srv_conf_t, ssl_protocols),
      &ngx_upstream_check_ssl_protocols },

    { ngx_string("check_ssl_server_name"),
      NGX_HTTP_UPS_CONF|NGX_CONF_FLAG,
      ngx_conf_set_str_slot,
      NGX_HTTP_SRV_CONF_OFFSET,
      offsetof(ngx_http_upstream_check_srv_conf_t, ssl_server_name),
      NULL },
#endif

通过以上配置指令,可以将解析到的参数设置到ngx_http_upstream_check_srv_conf_s结构体对应的字段中。其中ngx_upstream_check_ssl_protocols是一个可选协议的列表,定义如下:

c 复制代码
#if (NGX_HTTP_SSL)

static ngx_conf_bitmask_t  ngx_upstream_check_ssl_protocols[] = {
    { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
    { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
    { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
    { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
    { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
    { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
    { ngx_null_string, 0 }
};

#endif

nginx upstream server主动健康监测模块添加https检测功能【完整版】

相关推荐
IT成长日记7 分钟前
【Linux基础】Linux系统管理:GPT分区实践详细操作指南
linux·运维·服务器·gpt·parted·磁盘分区·fdisk
爱喝水的鱼丶28 分钟前
SAP-ABAP: ABAP ASSIGN COMPONENT 语句详解:动态字段符号的利器作用用法示例详解
运维·开发语言·sap·abap·开发经验·动态字段符号
清寒敲代码39 分钟前
k8s核心技术-Helm
运维·容器·kubernetes
quqi9940 分钟前
Enable FIPS in ubuntu (by quqi99)
linux·运维·ubuntu
人工智能训练师1 小时前
在Ubuntu中如何使用PM2来运行一个编译好的Vue项目
linux·运维·服务器·vue.js·ubuntu·容器
程序媛Dev1 小时前
50.4k Star!我用这个神器,在五分钟内搭建了一个私有 Git 服务器!
运维·服务器·git
杏花春雨江南1 小时前
腾讯云 CLB (Cloud Load Balancer) 为例,详细讲解如何配置 Nginx 集群
nginx·云计算·腾讯云
Lynnxiaowen2 小时前
今天继续学习shell脚本
linux·运维·学习·云计算·bash
Mysticbinary2 小时前
BurpSuite 代理原理 和 证书钉扎检测技术
http·https·网络代理·代理·网络流量·websockets·证书钉扎
hmcjn(小何同学)2 小时前
轻松Linux-9.进程间通信
linux·运维·服务器·c++·bash