lua-resty-peter_sslers
OpenResty SSL 证书例程,用于 peter_sslers SSL 证书管理器
$ opm get aptise/lua-resty-peter_sslers
lua-resty-peter_sslers
Lua 支持 https://github.com/aptise/peter_sslers 证书管理器在 OpenResty 中使用
状态
此包已在生产环境中使用,自 2016 年起。
0.5.0
版本需要 peter_sslers >= 0.5.0
0.4.0
版本需要 peter_sslers >= 0.4.0, <0.5.0
早期版本需要 peter_sslers < 0.4.0
安装
一行代码…
sudo opm install aptise/lua-resty-peter_sslers
升级?
sudo opm upgrade aptise/lua-resty-peter_sslers
概述
lua-resty-peter_sslers
是一个可以在 OpenResty/Nginx 环境中使用的库,用于为给定域名动态提供正确的 SSL 证书。
与 https://github.com/aptise/peter_sslers 协同工作,此包将加载现有证书或执行“autocert”以配置新的证书。
它支持 peter_sslers
的两种主要缓存类型 1 和 2。
它支持 peter_sslers
的“autocert”功能。
它作为库实现,并附带一些示例脚本以调用它。
核心库
peter_sslers.lua
示例可以在 examples
目录中找到,以及广泛的单元测试。
示例
ssl_certhandler-lookup.lua
ssl_certhandler-expire.lua
ssl_certhandler-status.lua
-lookup.lua
、-expire.lua
、-status.lua
脚本可以复制到 nginx/openresty 服务器块中。作为参考,请查看测试套件。
库默认使用以下信息连接 Redis
local redis_server = '127.0.0.1' local redis_port = '6379' local redis_db_number = 9
这可以通过“redis_update_defaults”修改。
redis_update_defaults(_redis_server, _redis_port, _redis_db_number)
Redis 不是必需的,但建议使用。相反,您可以回退到直接查询 peter_sslers pyramid 实例。
禁用 Redis
使用 nil
而不是 1
或 2
调用 ssl_certhandler_set
并设置 redis_strategy
。很简单!
Pyramid 回退
要使用 Peter SSlers Pyramid 回退来查询域名或 autocert 功能,请使用以下库
lua-resty-http https://github.com/pintsized/lua-resty-http
回退 API 的命中和未命中将缓存在共享缓存字典中。如果需要删除值,则需要重新启动服务器或使用 Nginx/lua 示例之一清除缓存。回退 API 请求将通知 Pyramid 应用程序请求应具有直通缓存行为。
调试语句发送到 nginx 服务器日志,因此最终用户可以调试回退和 autocert 功能。
缓存说明
为了最大限度地提高性能,Nginx/OpenResty 中有两个缓存层
证书缓存在给定工作进程中的 LRU 缓存中,使用
peter_sslers.lru_cache_duration
秒(默认为 60 秒)的原生 CDATA 格式。证书以 PEM 格式缓存在所有工作进程中,使用
peter_sslers.cert_cache_duration
秒(默认为 600 秒)。
这些值可以调整。
为什么?
Nginx 共享字典可以轻松查询、刷新/过期/覆盖值,但它只能存储 PEM 证书(而不是 cdata 指针),因此需要重复解析证书。
LRU 缓存可以保存 cdata 指针,但 Nginx/OpenResty 的实现细节不允许轻松查询和操作缓存。在所有工作进程之间发送覆盖/过期消息也将是一项艰巨的任务。
处理部署问题的一种简单方法是在 LRU 缓存上使用超时,该超时足够长以在负载下执行良好,但足够短以允许共享字典中的更改传播。
用法
确保您的 Nginx 包含
`` server { # 初始化 cert_cache 到一个大小 # 它将通过
nginx.shared.cert_cache
访问 lua_shared_dict cert_cache 100k; lua_code_cache on; init_by_lua_block { require "resty.core" local ssl_certhandler = require "resty.peter_sslers" ssl_certhandler.initialize() } init_worker_by_lua_block { require "resty.core" local ssl_certhandler = require "resty.peter_sslers" -- cert_cache_duration, lru_cache_duration, lru_maxitems ssl_certhandler.initialize_worker(90, 30, 200) } } ``
initialize
目前什么也不做。initialize_worker
接受三个参数cert_cache_duration
ngx.shared.DICT 中 PEM 缓存的秒数lru_cache_duration
工作进程中 cdata 指针的 LRU 缓存的秒数lru_maxitems
工作进程中 cdata 指针的 LRU 缓存的最大项目数
然后实现示例路由
由于 lua/luajit 的实现细节,以下示例必须在块/文件中实现,不能“require(/path/to/example)”。这是因为 Redis 连接的实例化方式。
参见
https://github.com/openresty/lua-resty-redis/issues/33
https://github.com/openresty/lua-nginx-module/issues/376
resty/peter_sslers.lua
核心库。公开多个函数。
examples/ssl_certhandler-lookup.lua
这非常简单,它仅仅指定了缓存、持续时间和 redis_strategy
在 Nginx 中调用…
server {
listen 443 default_server;
...
// nginx must have a default configured
ssl_certificate /path/to/default/fullchain.pem;
ssl_certificate_key /path/to/default/privkey.pem;
ssl_certificate_by_lua_block {
}
examples/ssl_certhandler-expire.lua
Nginx 共享内存缓存在配置重新加载后仍然存在。服务器必须完全重启才能清除内存。
解决方法?API 端点“刷新”缓存或使某些键(域名)过期。
examples/ssl_certhandler-expire
提供了一个简单的示例,可以很容易地在 Nginx 中调用它。
`` server { listen 443 default_server; ... location /.peter_sslers { auth_basic "peter_sslers-nginx"; auth_basic_user_file /path/to/peter_sslers-nginx.htpasswd; location /.peter_sslers/nginx/shared_cache/expire { content_by_lua_block { -- requirements local ssl_certhandler = require "resty.peter_sslers"
-- alias functions
local ssl_certhandler_expire = ssl_certhandler.expire_ssl_certs
ssl_certhandler_expire()
}
}
}
}
C<>``
此过期工具创建以下路由
/peter_sslers/nginx/shared_cache/expire/all
刷新整个 Nginx 证书缓存/peter_sslers/nginx/shared_cache/expire/domain/{DOMAIN}
刷新证书缓存中域名的 pkey 和 chain 条目
成功时,这些路由将在 HTTP-200-OK 文档中返回 JSON。
{"result": "success", "expired": "all"}
{"result": "success", "expired": "domain", "domain": "{DOMAIN}"}
{"result": "error", "expired": "None", "reason": "Unknown URI"}
出错时,这些路由应生成错误状态代码。
Pyramid 组件可以自动为您查询这些端点。
examples/ssl_certhandler-status.lua
状态路由显示有关系统的一些信息
`` server { listen 443 default_server; ... location /.peter_sslers/nginx { auth_basic "peter_sslers-nginx"; auth_basic_user_file /path/to/peter_sslers-nginx.htpasswd; location /.peter_sslers/nginx/shared_cache/status { content_by_lua_block { -- requirements local ssl_certhandler = require "resty.peter_sslers"
-- alias functions
local ssl_certhandler_status = ssl_certhandler.status_ssl_certs
ssl_certhandler_status()
}
}
}
}
C<>``
examples/ssl_certhandler-lookup.lua
这是核心工作
`` ssl_certificate_by_lua_block { -- requirements local ssl_certhandler = require "resty.peter_sslers"
-- alias functions
local ssl_certhandler_set = ssl_certhandler.set_ssl_certificate
local redis_strategy = 1
local fallback_server = 'http://0.0.0.0:6543/.well-known/admin'
local enable_autocert = 1
ssl_certhandler_set(redis_strategy, fallback_server, enable_autocert)
}
C<>``
完全配置的示例
在主 peter_sslers 仓库中提供了完全配置的示例
https://github.com/aptise/peter_sslers/blob/master/tools/nginx_conf/enabled.conf
详情
此方法积极利用 Nginx 工作进程(通过工作进程 lru 和共享字典)和 Redis 中的缓存;缓存命中和未命中。
Nginx 工作进程字典在重新加载后共享(kill -HUP {PID}
);因此,如果出现错误的值,则必须重新启动或等待超时。
伪代码中的逻辑
`` cert_cdata = lru_cache.get(domain) # 检查工作进程缓存 if hit(cert_cdata): if invalid(cert_cdata): return else: cert_pem = cert_cache.get(domain) # 检查共享缓存 if hit(cert_pem): if invalid(cert_pem): lru_cache.set(domain, invalid) return else: cert_pem = redis.get(domain) if hit(cert_pem): if invalid(cert_pem): lru_cache.set(domain, invalid) cert_cache.set(domain, invalid) return else: if autocert_enabled: cert_pem = upstream_https.get(domain) # autocert else: cert_pem = upstream_https.get(domain) # 查询 if hit(cert_pem): if invalid(cert_pem): lru_cache.set(domain, invalid) cert_cache.set(domain, invalid) return if valid(cert_pem) lru_cache.set(domain, cert_cdata) cert_cache.set(domain, cert_pem) cert_cdata = parse(cert_pem) if valid(cert_cdata): set_ssl_certificate(cert_cdata)
``
集成/调试方法
各种级别的信息发送到以下 Nginx 的调试级别。更改 Nginx 调试级别将显示更多数据
ERR
NOTICE
DEBUG
注意工作进程是如何初始化的
-- cert_cache_duration, lru_cache_duration, lru_maxitems ssl_certhandler.initialize_worker(90, 30, 100)
为了调试,您可能希望将这些值降低以将 LRU 缓存缩短到可以忽略不计的数字
ssl_certhandler.initialize_worker(5, 1, 100)
“/status”和“/expire”路由仅显示共享缓存中的信息 - 信息缓存在每个工作进程自己的 LRU 缓存中,并且这些路由无法访问。如果使用“/expire”,则域名将从共享缓存中删除,并且“/status”路由… 但可能仍存在于工作进程的 LRU 中。
检查状态
curl -k https://peter:sslers@127.0.0.1/.peter_sslers/nginx/shared_cache/status
过期
curl -k https://peter:sslers@127.0.0.1/.peter_sslers/nginx/shared_cache/expire
测试
Luacheck
test.yml
中的测试禁用未使用的变量
run: luacheck lib --no-unused
执行本地测试
luarocks install luacheck luacheck lib
Test::Nginx
升级 CPAN
cpan upgrade
安装 cpanm
cpan App::cpanminus
安装测试工具
cpanm -q -n Test::Nginx
您的 openresty 在哪里?确保它在路径中
export PATH=/usr/local/openresty/nginx/sbin:$PATH export PATH=/usr/local/bin/:$PATH
运行测试
/usr/bin/prove -I../test-nginx/lib -r t/
已知问题
没有!
版本控制
此项目使用主版本号.次版本号.修订版本号 语义版本控制。
主版本号.次版本号 版本发布与 lua-resty-peter__slers
的相同主版本号.次版本号 版本发布挂钩。
例如
| peter_sslers | lua-resty-peter_sslers | 兼容? | | --- | --- | --- | | 0.5.1 | 0.5.1 | 是 | | 0.5.1 | 0.5.0 | 是。修订版本号不匹配是可以的! | | 0.5.1 | 0.4.2 | 否。次版本号不匹配。 |
作者
Jonathan Vanasco <jonathan@findmeon.com>
最初在 https://github.com/aptise/peter_sslers 中启动
测试和 github actions 复制或借鉴了优秀的 lua-resty-http 模块 https://github.com/ledgetech/lua-resty-http(由 James Hurst 创建)和 openresty 测试套件。
许可证
此模块根据 MIT 许可证授权。请参阅 LICENSE.txt
作者
Jonathan Vanasco (github.com/jvanasco)
许可证
mit
依赖项
ledgetech/lua-resty-http,openresty
版本
-
OpenResty SSL 证书例程,用于 peter_sslers SSL 证书管理器 2021-03-19 20:07:50
-
openresty ssl 证书例程,用于 peter_sslers SSL 证书管理器 2020-11-25 01:49:01
-
openresty ssl 证书例程,用于 peter_sslers SSL 证书管理器 2020-11-25 00:36:01
-
openresty ssl 证书例程,用于 peter_sslers SSL 证书管理器 2020-11-24 23:35:05
-
openresty ssl 证书例程,用于 peter_sslers SSL 证书管理器 2018-06-28 19:15:34