Openresty之动态更新https证书

       如果是第一次看这个文章,可以先看下这篇openresty介绍性的文章:Openresty宏观介绍

         没用过openresty的人可能不知道这个是干啥的,但是用过的人大概就明白这个到底是个啥。在此简单说一下,openresty功能和Nginx功能一样,在用户如果需要做https访问的时候,需要在Nginx的配置文件nginx.conf文件里面配置证书和对应的KEY秘钥,这样Nginx才能提供https的访问请求。那么此时可能有这么一个需求,证书过期或者其他什么原因需要在不停止服务的情况下更改证书和秘钥,实现动态更改证书和秘钥的功能。实现如下功能需要下面几步

  • 编写lua脚本文件,在脚本文件里面去修改证书和密钥
  • 拷贝lua文件到openresty的安装路径
  • 修改nginx.conf文件,引入lua脚本,实现动态更新证书

一般证书/私钥的格式分两种,一种是文本格式的 PEM,另一种是二进制格式的 DER

1、编写lua脚本

命名脚本文件为ssl.lua,如果证书是PEM格式的话,通过如下方法更新证书和私钥:

local ssl = require "ngx.ssl"

-- 清除之前设置的证书和私钥
local ok, err = ssl.clear_certs()
if not ok then
    ngx.log(ngx.ERR, "failed to clear existing (fallback) certificates")
    return ngx.exit(ngx.ERROR)
end

-- 获取证书内容,比如 io.open("my.crt"):read("*a")
local cert_data, err = get_my_pem_cert_data()
if not cert_data then
    ngx.log(ngx.ERR, "failed to get PEM cert: ", err)
    return
end

-- 解析出 cdata 类型的证书值,你可以用 lua-resty-lrucache 缓存解析结果
local cert, err = ssl.parse_pem_cert(cert_data)
if not cert then
    ngx.log(ngx.ERR, "failed to parse PEM cert: ", err)
    return
end

local ok, err = ssl.set_cert(cert)
if not ok then
    ngx.log(ngx.ERR, "failed to set cert: ", err)
    return
end

local pkey_data, err = get_my_pem_priv_key_data()
if not pkey_data then
    ngx.log(ngx.ERR, "failed to get DER private key: ", err)
    return
end

local pkey, err = ssl.parse_pem_priv_key(pkey_data)
if not pkey then
    ngx.log(ngx.ERR, "failed to parse pem key: ", err)
    return
end

local ok, err = ssl.set_priv_key(pkey)
if not ok then
    ngx.log(ngx.ERR, "failed to set private key: ", err)
    return
end

备注:里面的get_my_pem_cert_data函数是获取证书函数,此处没有原函数,用户根据自己情况获取,有些是文件直接读取,有些是网络请求获取,有些是字符串直接使用。

如果证书格式是DER的话,使用如下代码进行动态更新

local ssl = require "ngx.ssl"

-- 清除之前设置的证书和私钥
local ok, err = ssl.clear_certs()
if not ok then
    ngx.log(ngx.ERR, "failed to clear existing (fallback) certificates")
    return ngx.exit(ngx.ERROR)
end

-- 获取证书内容,比如 io.open("my.crt.der"):read("*a")
local cert_data, err = get_my_der_cert_data()
-- 你也可以把 pem 格式的证书直接转换成 der 格式的,像这样:
-- local cert_pem_data = get_my_pem_cert_data()
-- local cert_data, err = ssl.cert_pem_to_der(cert_pem_data)
if not cert_data then
    ngx.log(ngx.ERR, "failed to get DER cert: ", err)
    return
end

-- 这里的 cert_data 是 string 类型的,所以可以直接缓存到 lua_shared_dict 当中
local ok, err = ssl.set_der_cert(cert_data)
if not ok then
    ngx.log(ngx.ERR, "failed to set DER cert: ", err)
    return
end

local pkey_data, err = get_my_der_priv_key_data()
-- 你也可以把 pem 格式的私钥直接转换成 der 格式的,像这样:
-- local pkey_pem_data = get_my_pem_priv_key_data()
-- local pkey_data, err = ssl.priv_key_pem_to_der(pkey_pem_data)
if not pkey_data then
    ngx.log(ngx.ERR, "failed to get DER private key: ", err)
    return
end

local ok, err = ssl.set_der_priv_key(pkey_data)
if not ok then
    ngx.log(ngx.ERR, "failed to set DER private key: ", err)
    return
end

2、拷贝lua文件到openresty安装目录

拷贝编辑的ssl.lua文件到目录/usr/local/openresty/nginx/lua/下面,如果没有,新建一个这个路径

3、修改nginx.conf文件

修改路径/usr/local/openresty/nginx/nginx.conf文件的内容如下:

#user  nobody;
worker_processes  1;

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

events {
    worker_connections  1024;
}

env SERVER_ADDR;
env SERVER_ADDR_TOKEN;


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;
    # error_log   logs/error.log error; 

    lua_package_path "/usr/local/openresty/lualib/?.lua;/usr/local/openresty/nginx/lua/?.lua;";
    lua_package_cpath "/usr/local/openresty/lualib/?.so;;";


    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;
    proxy_connect_timeout 3s;

    #gzip  on;

   
    # HTTPS server
    server {
       listen       443 ssl;
       server_name  localhost;

       ssl_certificate      server.crt;
       ssl_certificate_key  server.key;
       ssl_certificate_by_lua_file lua/ssl.lua;

       ssl_session_cache    shared:SSL:1m;
       ssl_session_timeout  5m;

       ssl_ciphers  HIGH:!aNULL:!MD5;
       ssl_prefer_server_ciphers  on;

       location / {
            #设置代理目的url变量
            proxy_pass https://127.0.0.1;
       }
 
    }

}

最重要的两句代码就是上面的

lua_package_path "/usr/local/openresty/lualib/?.lua;/usr/local/openresty/nginx/lua/?.lua;";

扫描二维码关注公众号,回复: 16975622 查看本文章

ssl_certificate_by_lua_file lua/ssl.lua;

第一句是添加lua代码的路径,第二句代码是指定ssl请求的lua文件,意思就是所有的ssl访问请求都会经过ssl.lua代码文件的代码操作,在里面去动态修改证书。

猜你喜欢

转载自blog.csdn.net/u013896064/article/details/128705381
今日推荐