博客 | NGINX

NGINX 开源版无需重启即可进行 SSL/TLS 证书轮换

Maxim Ivanitskiy 缩略图
马克西姆·伊万尼茨基
2023 年 9 月 26 日发布

在高性能 Web 服务器领域, NGINX是一个受欢迎的选择,因为其轻量级、高效的架构使其能够处理大量流量。 随着NGINX JavaScript 模块(njs)共享字典功能的引入,NGINX 的性能能力达到了一个新的水平。

在这篇博文中,我们探讨了 njs 共享字典的功能和优势,并展示了如何设置 NGINX 开源,而无需在轮换 SSL/TLS 证书时重新启动。

共享词典基础知识和优点

新的js_shared_dict_zone指令允许 NGINX 开源用户启用共享内存区域,以便在工作进程之间实现高效的数据交换。 这些共享内存区域充当键值字典,存储可实时访问和修改的动态配置设置。

共享词典的主要优点包括:

  • 最小开销且易于使用 -直接内置于 njs,通过直观的 API 和简单的实现即可轻松配置和使用。 它还可以帮助您简化工作进程之间管理和共享数据的过程。
  • 轻量高效——与 NGINX 无缝集成,利用其事件驱动、非阻塞 I/O 模型。 这种方法减少了内存使用量,提高了并发性,使 NGINX 能够有效地处理许多并发连接。
  • 可扩展性——利用 NGINX 跨多个工作进程水平扩展的能力,以便您可以在这些进程之间共享和同步数据,而无需复杂的进程间通信机制。 生存时间 (TTL) 设置允许您通过从区域中删除因不活动而导致的共享词典条目中的记录来管理它们。 evict参数删除最旧的键值对,为新条目腾出空间。

使用共享字典进行 SSL 轮换

共享字典最有影响力的用例之一是 SSL/TLS 轮换。 使用js_shared_dict_zone时,如果发生 SSL/TLS 证书或密钥更新,则无需重新启动 NGINX。 此外,它还为您提供了类似 REST 的 API 来管理 NGINX 上的证书。

下面是 NGINX 配置文件的示例,它使用js_setssl_certificate指令设置 HTTPS 服务器。 JavaScript 处理程序使用js_set从文件中读取 SSL/TLS 证书或密钥。

此配置片段使用共享字典将证书和密钥存储在共享内存中作为缓存。 如果密钥不存在,那么它会从磁盘读取证书或密钥并将其放入缓存中。

您还可以显示清除缓存的位置。 一旦磁盘上的文件更新(例如,证书和密钥被更新),共享字典就会强制从磁盘读取。 此调整允许轮换证书/密钥,而无需重新启动 NGINX 进程。

http {     ...
    js_shared_dict_zone zone=kv:1m;
   
  server {   …    # Sets an njs function for the variable. Returns a value of cert/key     js_set $dynamic_ssl_cert main.js_cert;     js_set $dynamic_ssl_key main.js_key;  
    # use variable's data     ssl_certificate data:$dynamic_ssl_cert;     ssl_certificate_key data:$dynamic_ssl_key;    
   # a location to clear cache  location = /clear {     js_content main.clear_cache;     # allow 127.0.0.1;     # deny all;   }
  ... }

以下是使用js_shared_dict_zone轮换 SSL/TLS 证书和密钥的 JavaScript 实现:

function js_cert(r) {  if (r.variables['ssl_server_name']) {
    return read_cert_or_key(r, '.cert.pem');
  } else {
    return '';
  }
}

function js_key(r) {
  if (r.variables['ssl_server_name']) {
    return read_cert_or_key(r, '.key.pem');
  } else {
    return '';
  }
}
/** 
   * Retrieves the key/cert value from Shared memory or fallback to disk
   */
  function read_cert_or_key(r, fileExtension) {
    let data = '';
    let path = '';
    const zone = 'kv';
    let certName = r.variables.ssl_server_name;
    let prefix =  '/etc/nginx/certs/';
    path = prefix + certName + fileExtension;
    r.log('Resolving ${path}');
    const key = ['certs', path].join(':');
    const cache = zone && ngx.shared && ngx.shared[zone];
   
  if (cache) { data = cache.get(key) || ''; if (data) { r.log(`Read ${key} from cache`); return data; } } try { data = fs.readFileSync(path, 'utf8'); r.log('Read from cache'); } catch (e) { data = ''; r.log(`Error reading from file:${path}. Error=${e}`); } if (cache && data) { try { cache.set(key, data); r.log('Persisted in cache'); } catch (e) { const errMsg = `Error writing to shared dict zone: ${zone}. Error=${e}`; r.log(errMsg); } } return data }

通过发送/clear请求,缓存将失效,并且 NGINX 将在下一次 SSL/TLS 握手时从磁盘加载 SSL/TLS 证书或密钥。 此外,您可以实现一个js_content ,它从请求中获取 SSL/TLS 证书或密钥,同时持久保存并更新缓存。

此示例的完整代码可以在njs GitHub repo中找到。

立即开始

共享字典功能是您的应用程序可编程性的强大工具,在精简和可扩展性方面带来了显著的优势。 通过利用js_shared_dict_zone的功能,您可以释放新的增长机会并有效处理不断增长的流量需求。

准备好使用js_shared_dict_zone增强你的 NGINX 部署了吗? 您可以使用js_shared_dict_zone升级您的 NGINX 部署以解锁新的用例,并在我们的文档中了解有关此功能的更多信息。 此外,您还可以在最近推出的njs-acme 项目中看到共享字典功能的完整示例,这使得 njs 模块运行时能够与 ACME 提供程序一起工作。

如果您有兴趣开始使用 NGINX 开源并且有疑问,请加入 NGINX 社区 Slack – 介绍自己并了解这个 NGINX 用户社区!


“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”