HTTPS是指HTTP over TLS,主要是为了提升HTTP协议栈的安全性。众所周知,HTTP本身是基于TCP/IP,从浏览器到网站之间的数据都是通过明文传输。明文传输就可能存在数据被篡改以及隐私泄漏的风险。TLS通过证书认证,通信加密以及摘要算法保证了端到端之间的安全性。HTTPS已经被广泛的应用到了因特网上,如果访问的哪个网站没有启用HTTPS那么主流的浏览器就会给予用户提示潜在的风险。随着越来越多的智能设备接入到局域网中,局域网的网络安全往往是大家容易忽视的地方。

家庭网络分析

局域网中只要有任意设备上运行着不安全程序,那么直接访问局域网中部署的HTTP网站就可能被监听账号密码和隐私数据。在我的家庭网络中,很多服务都是需要通过Web来进行设置,那么启用全网站的HTTPS就上刻不容缓了。

在上篇文章中已经介绍了我目前的网络配置,有这些服务是需要启用HTTPS的。

  1. Proxmox VE
  2. pfSense
  3. OpenWRT
  4. NAS
  5. Docker
  6. Web server Caddy
  7. Portainer
  8. Gitea
  9. Home Assistant

启用HTTPS主要是需要申请以及部署服务器证书。对于这么多个站点,如果需要定时的手工申请和部署那肯定是不现实的。Docker里的几个服务器上可以通过Caddy进行方向代理。因为数据不会离开Docker环境,所以方向代理过程中发送的明文数据不会被局域网中其它设备监听到。所以最终就剩下5个服务器需要进行操作。目前最常见的自动化部署方案当属通过ACME申请和部署Let’s encrypt的证书。这个方案在我的大部分服务中都有支持,但是我没有选择这个完整的方案,原因如下,

  1. 这个方案需要拥有一个自己的域名。虽然我自己有不少域名,但是在局域网中还是希望能使用一个简短的域名(比如.lan)来方便内部访问。
  2. 证书的有效期比较短,通常为三个月。之前尝试过使用正式运命,由于在部分服务上出现过没成功续签导致网站无法访问,所以还是希望能够有个至少一年的证书有效期。
  3. 内部网站只能通过DNS挑战来签发证书,我并不希望所有的服务都能够有直接操作域名的权限。

寻找方案

既然使用了私有域名,那么就需要有自己的证书管理体系了。我最开始使用的是pfSense自带的证书管理软件,相比于网上那些直接使用openssl命令行来创建CA和签发证书要方便不少。自签证书为了减少证书到期后的部署问题,也是直接使用了10年有效期。然而随着苹果对证书的要求升级,超过一年的证书仍然会被提示证书日期问题,于是不得不再继续寻找其它方案。在网上搜索ACME服务器的时候发现了step ca,支持acme.shCaddy自动部署,完全符合我的需求。

部署

step ca

首先是在docker中部署step ca, 参考这里的内容。默认情况下CA证书是由step ca产生,但是为了方便管理,我还是在pfSense中产生了一个CA并且导入到step ca中来使用。step ca的初始化分以下几步操作。

  1. 初始化。这里我将证书ca.crtca.key放在了*/root/docker/step*目录下,根据提示输入并记下密码。
1
docker run -it -v step:/home/step -v /root/docker/step:/step smallstep/step-ca step ca init --root=/step/ca.crt --key=/step/ca.key
  1. 保存密码已经更新配置。
1
docker run -it -v step:/home/step smallstep/step-ca sh

在容器中,将密码保存到指定位置。

1
echo -n "<your password here>" > /home/step/secrets/password

在容器中,更新配置。

1
vi /home/step/config/ca.json

authority下添加如下内容将默认的证书有效期从一天改为一年。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
              "claims":{                                                                                                                                                         
                    "minTLSCertDuration": "5m",                                                                                                                                 
                    "maxTLSCertDuration": "8760h",                                                                                                                              
                    "defaultTLSCertDuration": "8760h",                                                                                                                          
                    "disableRenewal": false,                                                                                                                                    
                    "minHostSSHCertDuration": "5m",                                                                                                                             
                    "maxHostSSHCertDuration": "1680h",                                                                                                                          
                    "defaultHostSSHCertDuration": "720h",                                                                                                                       
                    "minUserSSHCertDuration": "5m",   
                    "maxUserSSHCertDuration": "24h",     
                    "defaultUserSSHCertDuration": "16h"  
              }
  1. 启动容器,以端口9000为例。
1
docker run -d -p 9000:9000 -v step:/home/step smallstep/step-ca
  1. 将ca.crt安装到所有需要访问局域网内网站的设备上。
  2. 这里以ca.lan做为域名,访问https://ca.lan:9000/health,安装正常的情况下可以在浏览器中看到如下内容,并且浏览器也不再报证书不可信问题了。
1
{"status":"ok"}

step ca服务启动后,那么接下来就可以在各个网页服务器上启用ACME了。这里需要做两方面设置,

  1. 让服务器信任ca.crt。
  2. 设置ACME的directory为https://ca.lan:9000/acme/acme/directory

Proxmox VE (pve)

  1. 让pve信任ca.crt。打开shell,创建目录'/usr/local/share/ca-certificates/my-custom-ca’将证书放进去,执行update-ca-certificates即可。
  2. 添加ACME账号。pve的网页上只能添加Let’s Encrypt的ACME账号,可以通过pvenode acme指令来设置。打开shell,执行pvenode acme account register default user@email.lan --directory https://ca.lan:9000/acme/acme/directory
  3. 申请证书。打开shell,执行
1
2
pvenode config set --acme domains=pve.lan
pvenode acme cert order

看到如下输出就代表证书部署完成了,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Loading ACME account details
Placing ACME order
...
Status is 'valid'!

All domains validated!
...
Downloading certificate
Setting pveproxy certificate and key
Restarting pveproxy
Task OK

pfSense

  1. 让pfSense信任ca.crt。打开shell,创建目录'/usr/local/etc/ssl/certs’将证书放进去,执行certctl rehash 即可。
  2. 通过网页安装软件包acme。
  3. 在shell里编辑'/usr/local/pkg/acme/acme.inc',大概在172行左右,添加如下代码,根据pfSense版本不同,代码略微有点差异。
    1
    2
    3
    4
    
    $a_acmeserver['local'] = [
        'name' => "acme.local",
        'url' => 'https://ca.lan:9000/acme/acme/directory'
    ];
    
  4. 在shell里选11重启网页:11) Restart webConfigurator
  5. 在网页打开’Service' -> ‘Acme Certificates’,选择’Account Keys',‘Add’。‘ACME Server’选’acme.local’。
  6. 在网页打开’Service' -> ‘Acme Certificates’,选择’Certificates',‘Add’。完成后点’Issue/Renew',就可以看到签发的证书啦。

群晖

  1. 安装acme.shcurl https://get.acme.sh | sh -s email=my@example.com --force
  2. 将ca.crt证书放置到'$HOME/.acme.sh/'。
  3. 进入'$HOME/.acme.sh', 签发证书。./acme.sh --issue -d nas.lan --ca-bundle ./ca.crt --server https://ca.lan:9000/acme/acme/directory --webroot /var/lib/letsencrypt --force
  4. 设置本地部署。
1
2
export SYNO_USE_TEMP_ADMIN=1
./acme.sh --deploy --deploy-hook synology_dsm -d nas.lan
  1. 在网页中创建定时任务,执行/root/.acme.sh/acme.sh --cron --home /root/.acme.sh/

Caddy

  1. 将ca.crt放到Caddyfile配置所在目录。
  2. 在Caddyfile最前面增加如下配置
1
2
3
4
5
{
  email my@example.com
  acme_ca https://ca.lan:9000/acme/acme/directory
  acme_ca_root /ca.crt
}
  1. 反向代理本地HTTP服务
1
2
3
home.lan {
  reverse_proxy <Host>:<Port>
}