使用 Node.js 的 Let's Encrypt 证书最安全的方法是什么?

What is the most secure way to use Let's Encrypt certificates with Node.js?

我正在 node.js 上开发一个安全的网络服务器,我正在使用 Let's Encrypt 证书和 https 模块。 我希望它在 Ubuntu/Debian 机器上 运行。 默认情况下,证书和私钥存储在:

/etc/letsencrypt/live/domain.name.example/fullchain.pem
/etc/letsencrypt/live/domain.name.example/privkey.pem

这些文件权限只允许root用户读取它们,所以问题是node.js服务器无法正常加载它们使用:

const cert = fs.readFileSync("/etc/letsencrypt/live/domain.name.example/fullchain.pem");
const privKey = fs.readFileSync("/etc/letsencrypt/live/domain.name.example/privkey.pem");

(会抛出权限错误)

我知道的唯一解决方案是:

  1. 运行将节点服务器设置为 root,以便它具有对文件的权限(不推荐用于节点)。
  2. 将带有sudo cp的文件复制到本地目录并使用sudo chmod +r申请权限,以便在每次更新证书后服务器可以访问它们(let's encrypt 不建议复制这些文件,这是我目前的解决方案)。
  3. 运行ning节点为root,加载证书和私钥,然后用process.setgid()process.setuid()将uid改为非root用户,这样会掉root特权。

我的问题是是否有更好的解决方案来实现这一点,或者这些方法中的一种可能就可以了?

使用setgid.

将目录的组所有权设置为您正在使用 运行 nodejs 的组。例如,如果您的用户和组是 itay:staff,请这样说

chgrp -R staff /etc/letsencrypt/live/domain.name.example

然后像这样设置目录权限的setgid位。

chmod 02755 staff /etc/letsencrypt/live/domain.name.example

此后,写入该目录的任何文件都将归该组所有,在此示例中为 staff。因此,您的 nodejs 程序将能够毫不费力地读取它们。

根据 O. Jones 的评论,我通过使用 nginx 作为我的 nodejs 服务器的 reverse-proxy 解决了这个问题。这样 nginx 就可以在没有权限问题的情况下处理 SSL,而 nodejs 只需要 运行 一个 http 服务器。

按照 letsencrypt 文档(引用 B)的第二个建议解决了这个问题,该文档不需要我创建任何脚本来在证书自动更新时移动或复制文件(我安装了 - -apache 插件,作为旁注,如果您在虚拟主机中从 http 重定向到 https,当您第一次 运行 certbot 使用 --no-redirect 以避免在安装期间报告错误证书)。

尽管我发现没有必要移动或复制 pem 文件。在 certbot 文档 here 中,我没有发现 letsencrypt 不建议移动证书,在他们的文档中,到目前为止,他们甚至告诉你如何正确地做:

引用 A:

If you would like the live certificate files whose symlink location Certbot updates on each run to reside in a different location, first move them to that location, then specify the full path of each of the four files in the renewal configuration file. Since the symlinks are relative links, you must follow this with an invocation of certbot update_symlinks.

For example, say that a certificate’s renewal configuration file previously contained the following directives:

archive_dir = /etc/letsencrypt/archive/example.com
cert = /etc/letsencrypt/live/example.com/cert.pem
privkey = /etc/letsencrypt/live/example.com/privkey.pem
chain = /etc/letsencrypt/live/example.com/chain.pem
fullchain = /etc/letsencrypt/live/example.com/fullchain.pem

The following commands could be used to specify where these files are located:

mv /etc/letsencrypt/archive/example.com /home/user/me/certbot/example_archive
sed -i 's,/etc/letsencrypt/archive/example.com,/home/user/me/certbot/example_archive,' /etc/letsencrypt/renewal/example.com.conf
mv /etc/letsencrypt/live/example.com/*.pem /home/user/me/certbot/
sed -i 's,/etc/letsencrypt/live/example.com,/home/user/me/certbot,g' /etc/letsencrypt/renewal/example.com.conf
certbot update_symlinks

引用B (我的解决方案,只是因为它是简单的-KISS原理)

关于权限和组所有权,他们说如下:

For historical reasons, the containing directories are created with permissions of 0700 meaning that certificates are accessible only to servers that run as the root user. If you will never downgrade to an older version of Certbot, then you can safely fix this using chmod 0755 /etc/letsencrypt/{live,archive}.

For servers that drop root privileges before attempting to read the private key file, you will also need to use chgrp and chmod 0640 to allow the server to read /etc/letsencrypt/live/$domain/privkey.pem.

这很有趣,它们是 700 只是出于历史原因。他们没有澄清的是 /etc/letsencrypt/live 和 keys 文件夹是 700,在 20.04 Ubuntu 你甚至看不到文件夹存在,除非你成为 root,是的 sudo 不起作用,找不到文件夹错误。 -d 或域文件夹为 755 (/etc/letsencrypt/live.domain.com),.pem 文件的符号链接本身为 777.

Letsencrypt 文档说:

the pem files in the directory mentioned above, are only symlinks: /etc/letsencrypt/archive and /etc/letsencrypt/keys contain all previous keys and certificates, while /etc/letsencrypt/live symlinks to the latest version

密钥本身拥有权限:600 在我的带有 cerbot --apache 证书和安装的 Ubuntu 20.04 系统中,我发现 keys 文件夹有 000x_key-certbot.pem 权限为 600 的文件,存档目录有实际的 cert1.pem、chain1.pem、完整chain1.pem 和 privkey1.pem 文件,权限分别为:644、644、644 和 600。

/etc/letsencrypt/archive/domain.com# 文件夹的权限为 755,/etc/letsencrypt/archive 文件夹的权限为 700。 因此,通过隐藏目录并阻止密钥本身来阻止访问。