为Confluence添加HTTPS加密通信功能

在公司内网搭建Confluence、JIRA、GitLab、Jenkins、SonarQube等团队协作和CI/CD工具之后,如果想要通过VPN将这些工具提供给其他办公场所的人员使用,只通过Nginx反向代理是无法确保数据安全性的,因为数据传输都是HTTP明文,仍然存在数据被监听或篡改的风险。使用HTTPS(Hyper Text Transfer Protocol over Secure Socket Layer)可以最大程度地避免此类安全问题,它是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。

本文所述的配置会达到如下的效果:

  • 外部客户端通过SSL和Nginx建立安全连接,而Nginx和Confluence之间的连接是不安全的。
  • Confluence和Nginx在同一个网段内运行,不需要使用HTTPS互访。

网络拓扑图,如下所示:

网络拓扑图

一、环境配置

  1. 操作系统
    版本: Deepin GNU/Linux 15.11
  2. Docker
    版本: Docker version 19.03.5, build 633a0ea838
    安装方式: 《Get Docker Engine – Community for Debian
  3. Confluence
    版本:7.2.1
    安装方式:《容器化部署和破解Confluence知识库
  4. Nginx
    版本:1.17.9
    安装方式:《为Confluence添加Nginx反向代理
  5. mkcert
    版本:mkcert-v1.4.1-linux-amd64

二、安装mkcert

HTTPS 是 Web 发展的趋势,用于提高网站的安全性。使用 HTTPS 需要配置 TLS 证书,得益于 ACME 协议和 Let’s Encrypt 证书,远程环境可以很容易部署。但是对于本地环境,还没有普遍有效的证书。

这是一个问题,因为越来越多的浏览器特性要求必须以 HTTPS 的方式访问,混合 HTTP 和 HTTPS 内容可能导致网站不可访问。本地环境使用 HTTPS 开发应该要像远程环境部署 HTTPS 一样简单。这就是本文推荐的工具 mkcert 的用途。

mkcert 被设计的足够简单,隐藏了几乎所有生成 TLS 证书所必须的知识。它适用于任何主机名或者 IP,包括 localhost ,因为它只在用户的本地环境使用。证书是由用户的私有 CA 签发,因此,当浏览器访问时,就会显示安全标识。目前支持 MacOS、Linux 和 Windows,以及 Firefox、Chrome 和 Java,甚至支持一些手机设备。

首先,从GitHub下载mkcert的预编译文件:

cd  ~/Downloads
wget -O mkcert  https://github.com/FiloSottile/mkcert/releases/download/v1.4.1/mkcert-v1.4.1-linux-amd64

然后,修改访问权限,并且将其拷贝至/usr/local/bin目录:

chmod +x mkcert
sudo mv mkcert /usr/local/bin

三、生成自签名SSL证书

首先,获取和查看本地CA证书的根目录:

mkcert -CAROOT

可以看到,mkcert会将本地CA证书放在~/.local/share/mkcert目录中。

然后,安装本地CA证书:

mkcert -install

上述命令的输出信息,如下图所示:

安装本地CA根证书

可以看到:

  • 本地CA证书存储在~/.local/share/mkcert目录中;
  • 本地CA证书已安装至系统信任存储库中;
  • 本地CA证书已安装至Firefox和Chrome/Chromium的信任存储库中(需要重启浏览器);
  • 本地CA证书已安装至Java的信任存储库中。

此时,在Nginx宿主机上的浏览器、Java程序等,访问经过mkcert自签名证书保护的本地网站时,都会信任其SSL证书!

最后,生成自签名的SSL证书:

mkcert <domain-name>

注意,请用实际域名替换,SSL证书的公钥和私钥会存放在当前目录中。此时,得到两个密钥文件:

  • SSL证书公钥:.pem
  • SSL证书私钥:-key.pem

查看SSL证书公钥的内容:

cat <domain-name>.pem

SSL证书公钥的内容,如下图所示:

SSL公钥

四、配置Confluence

Confluence服务是在Tomcat容器中运行的,而Tomcat的HTTP连接器必须经过配置才能支持前置Nginx的HTTPS协议。

首先,进入confluence容器的bash:

docker exec -it confluence /bin/bash

然后,在confluence容器的bash中,修改配置模板文件:

vi /opt/atlassian/etc/server.xml.j2

需要对该文件进行如下修改:

  • 找到“protocol”参数,将其默认值改为“org.apache.coyote.http11.Http11NioProtocol”;
  • 找到“secure”参数,将其默认值改为“true”;
  • 找到“scheme”参数,将其默认值改为“https”;
  • 找到“proxyName”参数,将其默认值改为“”;
  • 找到“proxyPort”参数,将其默认值改为“443”。

注意,请用实际的域名来替换。注意,不要直接修改/opt/atlassian/confluence/conf/server.xml配置文件,因为每当confluence容器重启时,都会根据上述的配置模板文件自动还原配置文件,因此修改的配置永远不会生效!

修改后的配置模板文件,如下图所示:

配置模板文件

最后,退出容器,重启confluence容器:

docker restart confluence

此时,Confluence便可以支持启用HTTPS的Nginx反向代理服务器了!

五、配置Nginx

Nginx服务器不仅仅承载反向代理的功能,还承载HTTPS协议。

首先,复制SSL证书至Nginx配置目录:

sudo cp <domain-name>* /var/lib/nginx/conf/

注意,请用实际的域名来替换。

然后,修改confluence.conf配置文件:

sudo vi /var/lib/nginx/conf/conf.d/confluence.conf

这个配置文件的内容,如下所示:

server {
    listen       80;
    server_name  <domain-name>;
    if ($http_x_forwarded_proto = 'http') {
        return 301 https://<domain-name>;
    }

    listen 443 default ssl;
    ssl_certificate     /etc/nginx/<domain-name>.pem;
    ssl_certificate_key /etc/nginx/<domain-name>-key.pem;

    ssl_session_timeout  5m;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_prefer_server_ciphers   on;

    location / {
            try_files $uri @confluence;
    }

    location /synchrony {
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Server $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://<container-ip-address>:8091/synchrony;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
    }

    location @confluence {
            internal;
            proxy_pass http://<container-ip-address>:8090;
            proxy_connect_timeout 30s;
            proxy_send_timeout 120;
            proxy_read_timeout 120;
            proxy_buffer_size 32k;
            proxy_buffers 4 32k;
            proxy_busy_buffers_size 64k;
            proxy_redirect off;
            proxy_hide_header Vary;
            proxy_set_header Accept-Encoding '';
            proxy_set_header Host $host;
            proxy_set_header Referer $http_referer;
            proxy_set_header Cookie $http_cookie;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            client_max_body_size 100m;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Server $host;
    }

    client_max_body_size 100m;
}

上述配置,有几点需要注意:

  • 请用实际的域名来替换;
  • 请用confluence容器的IP地址来替换;
  • client_max_body_size参数的值必须等于Confluence支持的上传附件的大小,否则上传附件时,可能会出现HTTP 413错误;
  • 必须包含synchrony的配置,否则协同编辑可能会出错;
  • 支持强制HTTPS访问。

最后,重启Nginx容器:

docker restart nginx

此时,为Confluence添加HTTPS加密通信功能就基本完成了!

六、为客户端导入SSL证书

虽然Confluence服务端的配置都已经完成了,但是客户端的浏览器在访问Confluence时,会收到“您的连接不是私密连接”的警告信息,这是因为本地CA证书尚未导入客户端的浏览器,客户端不信任本地自签名的SSL证书所导致的,如下图所示:

HTTPS警告信息

此时,需要登录Confluence和Nginx的服务器,将本地CA根证书拷贝出来,上传到网盘或其他共享方式,客户端下载后导入浏览器。上传共享本地CA根证书的过程不再赘述,本文将详述如何将本地CA根证书导入客户端浏览器。

公司内大多数客户端安装的是Windows 10系统,可以使用certmgr.exe工具来导入本地CA根证书。

首先,下载导入工具和CA根证书,这个步骤按实际情况进行操作。

然后,打开CMD命令行,进入导入工具所在的目录,然后运行以下命令:

certmgr.exe /c /add rootCA.pem /s root

此时,会弹出一个确认对话框,点击“是”按钮即可,如下图所示:

导入本地CA根证书

最后,通过certmgr.msc来查看本地CA根证书是否导入成功,检查“证书 – 当前用户 → 受信任的根证书颁发机构 → 证书”,若导入成功,则如下图所示:

检查本地CA根证书导入结果

七、测试验证

在已经导入本地CA根证书的客户端上,使用浏览器访问Confluence,可以看到原先的警告已经消除,证书状态正确,如下图所示:

通过HTTPS访问Confluence

至此,为Confluence添加HTTPS加密通信功能已经全部完成了!