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

2024-02-17 07:44

本文主要是介绍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 配置文件


#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 配置指令结构体:


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 配置指令源码定义:

#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是一个可选协议的列表,定义如下:

#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

3.2 模块的初始化

static ngx_http_module_t  ngx_http_upstream_check_module_ctx = {NULL,                                    /* preconfiguration */ngx_http_upstream_check_init,            /* postconfiguration */ngx_http_upstream_check_create_main_conf,/* create main configuration */ngx_http_upstream_check_init_main_conf,  /* init main configuration */ngx_http_upstream_check_create_srv_conf, /* create server configuration */NULL,                                    /* merge server configuration */ngx_http_upstream_check_create_loc_conf, /* create location configuration */ngx_http_upstream_check_merge_loc_conf   /* merge location configuration */
};

  在以上代码中ngx_http_upstream_check_module_ctx结构体的初始化定义中,ngx_http_upstream_check_init_main_conf函数将在配置文件的http块解析完成后进行初始化,因此,我们通过修改这个函数来实现ssl上下文的初始化,即ngx_http_upstream_check_srv_conf_s的ssl指针的初始化。ssl是一个指向ngx_ssl_t的指针,用来对ssl协议的相关参数进行设定并初始化ssl上下文。
  以下是ngx_http_upstream_check_init_main_conf函数的代码:

static char *
ngx_http_upstream_check_init_main_conf(ngx_conf_t *cf, void *conf)
{ngx_buf_t                      *b;ngx_uint_t                      i;ngx_http_upstream_srv_conf_t  **uscfp;ngx_http_upstream_main_conf_t  *umcf;umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);b = ngx_http_upstream_check_create_fastcgi_request(cf->pool,fastcgi_default_params,sizeof(fastcgi_default_params) / sizeof(ngx_str_t) / 2);if (b == NULL) {return NGX_CONF_ERROR;}fastcgi_default_request.data = b->pos;fastcgi_default_request.len = b->last - b->pos;uscfp = umcf->upstreams.elts;for (i = 0; i < umcf->upstreams.nelts; i++) {if (ngx_http_upstream_check_init_srv_conf(cf, uscfp[i]) != NGX_OK) {return NGX_CONF_ERROR;}}return ngx_http_upstream_check_init_shm(cf, conf);
}

  在以上代码中,

    for (i = 0; i < umcf->upstreams.nelts; i++) {if (ngx_http_upstream_check_init_srv_conf(cf, uscfp[i]) != NGX_OK) {return NGX_CONF_ERROR;}}

  这段代码是对所有配置的http upstream进行遍历,然后对它进行初始化,因为我们的ssl上下文信息每个upstream对应一个,因此,正好在ngx_http_upstream_check_init_srv_conf函数里面可以进行初始化。
  在函数ngx_http_upstream_check_init_srv_conf的最后返回前,我们添加ssl的初始化代码,如下:

static char *
ngx_http_upstream_check_init_srv_conf(ngx_conf_t *cf, void *conf)
{
......
#if (NGX_HTTP_SSL)/* 如果当前的监测类型是https才需要进行ssl的初始化设置 */if (check->type == NGX_HTTP_CHECK_HTTPS) {/* 如果ssl_protocols没有设置,那么默认开启NGX_SSL_TLSv1,NGX_SSL_TLSv1_1和NGX_SSL_TLSv1_2 */if (ucscf->ssl_protocols == NGX_CONF_UNSET_UINT) {ucscf->ssl_protocols = NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1|NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2;}/* 如果没有设置ssl_ciphers,那么设置默认值为DEFAULT */if (ucscf->ssl_ciphers.len == 0) {ngx_str_set(&ucscf->ssl_ciphers,"DEFAULT");}/* 为ssl分配内存 */ucscf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));if (ucscf->ssl == NULL) {return NGX_CONF_ERROR;}ucscf->ssl->log = cf->log;/* 创建ssl上下文 */if (ngx_ssl_create(ucscf->ssl, ucscf->ssl_protocols, NULL) != NGX_OK) {return NGX_CONF_ERROR;}/* 设置ssl上下文回收回调函数 */cln = ngx_pool_cleanup_add(cf->pool, 0);if (cln == NULL) {return NGX_CONF_ERROR;}cln->handler = ngx_ssl_cleanup_ctx;cln->data = ucscf->ssl;/* 设置可以支持的加密套件 */if (ngx_ssl_ciphers(cf, ucscf->ssl, &ucscf->ssl_ciphers, 0) != NGX_OK) {return NGX_CONF_ERROR;}}#endifreturn NGX_CONF_OK;
}

【未完待续】

这篇关于nginx upstream server主动健康监测模块添加https检测功能的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/717120

相关文章

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Android使用ImageView.ScaleType实现图片的缩放与裁剪功能

《Android使用ImageView.ScaleType实现图片的缩放与裁剪功能》ImageView是最常用的控件之一,它用于展示各种类型的图片,为了能够根据需求调整图片的显示效果,Android提... 目录什么是 ImageView.ScaleType?FIT_XYFIT_STARTFIT_CENTE

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Spring Boot 整合 SSE的高级实践(Server-Sent Events)

《SpringBoot整合SSE的高级实践(Server-SentEvents)》SSE(Server-SentEvents)是一种基于HTTP协议的单向通信机制,允许服务器向浏览器持续发送实... 目录1、简述2、Spring Boot 中的SSE实现2.1 添加依赖2.2 实现后端接口2.3 配置超时时

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

Python中的getopt模块用法小结

《Python中的getopt模块用法小结》getopt.getopt()函数是Python中用于解析命令行参数的标准库函数,该函数可以从命令行中提取选项和参数,并对它们进行处理,本文详细介绍了Pyt... 目录getopt模块介绍getopt.getopt函数的介绍getopt模块的常用用法getopt模

Nginx location匹配模式与规则详解

《Nginxlocation匹配模式与规则详解》:本文主要介绍Nginxlocation匹配模式与规则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、环境二、匹配模式1. 精准模式2. 前缀模式(不继续匹配正则)3. 前缀模式(继续匹配正则)4. 正则模式(大

springboot项目如何开启https服务

《springboot项目如何开启https服务》:本文主要介绍springboot项目如何开启https服务方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录springboot项目开启https服务1. 生成SSL证书密钥库使用keytool生成自签名证书将

Android实现两台手机屏幕共享和远程控制功能

《Android实现两台手机屏幕共享和远程控制功能》在远程协助、在线教学、技术支持等多种场景下,实时获得另一部移动设备的屏幕画面,并对其进行操作,具有极高的应用价值,本项目旨在实现两台Android手... 目录一、项目概述二、相关知识2.1 MediaProjection API2.2 Socket 网络

Redis消息队列实现异步秒杀功能

《Redis消息队列实现异步秒杀功能》在高并发场景下,为了提高秒杀业务的性能,可将部分工作交给Redis处理,并通过异步方式执行,Redis提供了多种数据结构来实现消息队列,总结三种,本文详细介绍Re... 目录1 Redis消息队列1.1 List 结构1.2 Pub/Sub 模式1.3 Stream 结