内部服务的TLS证书管理得当
标题有点像点击诱饵——你的体验可能不同,但让我解释一下为什么我认为“这就是正确的方法”。我们从一个简单的例子开始——我们有一台服务器,它托管了一些HTTP服务。其中一些服务是外部的,其他的是内部的。为了访问内部服务,您需要连接到VPN。为了简单起见,我们考虑两个选择:我们使用ICANN限制的顶级域作为私有用途——例如.internal,或者我们使用我们拥有的公共顶级域——例如.tuxnet.dev。Grafana将是我们内部应用的例子。假设它可通过10.0.1.10内部IP地址访问,并且我们的VPN具有DNS解析功能。那么,.internal有什么问题呢?我们可以简单地创建一个类型为“A”的DNS记录,解析10.0.1.10内部IP地址——例如grafana.tuxnet.internal。但如果我们不想让它成为明文HTTP服务,我们需要创建一个自签名证书。好的一面是有足够的教程教您如何做到这一点(例如这个)。丑陋的一面是,突然间,每个HTTP客户端应该被配置为信任这个自签名证书。或者我们可以告诉用户忽略TLS证书错误¯\_(ツ)_/¯。怎样才能做到“正确的方法”?这就是“分裂视野DNS”配置。对于公共DNS解析器,我们的grafana.tuxnet.dev域解析到公共IP,而对于连接到VPN的客户端,这个域解析到内部IP。好的一面是,由于它解析到公共IP,我们可以使用像Let’s Encrypt或ZeroSSL这样的公共CA。丑陋的一面是,我们仍然需要某种Web应用防火墙来拒绝非来自VPN的流量。考虑到这两种解决方案的利弊,我认为在一个地方(我们的服务器上)设置WAF比在加入我们内部网络的每台机器上安装自签名证书(或者建议用户忽略TLS错误)要简单得多。“空谈无用,给我代码”。我们现在有理论了,是时候动手实践了。我们需要:一个带有DNS解析功能的VPN——我选择NetBird。用于颁发证书的ACME客户端——我选择acme.sh。一个带有WAF功能的反向代理在我们的grafana前面——我选择nginx。如果您读过我的其他博文,您可能注意到我是NetBird的粉丝(抱歉Tailscale)。得益于自定义区域功能,NetBird为我们完成了“分裂视野DNS”所需的所有繁重工作。通过使用用户组或对等组,我们可以选择性地应用自定义区域,以便服务器对grafana.tuxnet.dev使用公共DNS解析器。为什么要将服务器排除在该自定义区域之外?除非我们想使用http-01挑战,否则这不是必需的。使用其他方法也是可能的,但为了这篇博文的缘故我选择http-01。好的,现在让我们获取证书:acme.sh --issue -d grafana.tuxnet.dev --server letsencrypt --standalone。acme.sh非常灵活,有很多模式。关于独立模式(通过--standalone标志启用)的酷炫之处在于我们的nginx根本不需要监听80端口。这个端口只有在acme.sh获得证书时才“激活”。好吧,现在我们可以投入nginx行动了。这是我们的配置:upstream grafana { server localhost:3000; } map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen our-server.netbird.cloud:443 ssl; server_name grafana.tuxnet.dev; http2 on; ssl_certificate /etc/ssl/certs/grafana.tuxnet.dev.crt; ssl_certificate_key /etc/ssl/private/grafana.tuxnet.dev.key; access_log /var/log/nginx/grafana.tuxnet.dev.access.log main; error_log /var/log/nginx/grafana.tuxnet.dev.error.log warn; location / { proxy_pass http://grafana; proxy_set_header Host $host; } # 代理Grafana实时WebSocket连接。 location /api/live/ { proxy_pass http://grafana; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; } } 在这个配置中有一个值得解释的关键设置——listen our-server.netbird.cloud:443 ssl;。我们绑定到服务器的VPN网络接口。代替our-server.netbird.cloud的可以是一个VPN IP地址。在实践中,这将拒绝来源于公共互联网的任何对grafana.tuxnet.dev的流量——这就是我们的Web访问防火墙。安全性是关于层次(就像洋葱和巨魔)。我们的第一层是分裂视野DNS,但如果由于某种原因它失败或被巧妙绕过,我们有第二层——WAF——应该保持防线。最后但同样重要的是——证书自动续期。acme.sh有一个开箱即用的--cron标志。现在我们需要一个每天运行的cron作业,调用acme.sh --cron。acme.sh会自动选择应该续期的证书。我们要做的就是确保cron作业将新证书复制到nginx的ssl_certificate和ssl_certificate_key中定义的位置。Nginx也需要重新加载以使用新证书。我们的cron作业可能看起来像这样:main () { refresh_certs sync_api_tuxnet_dev
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡