介绍
GoCD 是一个强大的持续集成和交付平台,旨在自动化测试和发布过程。 GoCD 具有许多高级功能,例如比较构建、可视化复杂工作流程和自动化构建版本跟踪的能力,是一种灵活的工具,可以帮助团队将经过良好测试的软件交付到生产环境。
在上一篇文章中,我们安装了GoCD服务器,设置了代理,并配置了身份验证。 在本指南中,我们将配置 GoCD 以使用受信任的 Let's Encrypt SSL 证书,以防止在访问 Web 界面时出现浏览器警告。 我们将为两种不同的可能配置提供说明。
第一种方法将安装 Nginx Web 服务器作为反向代理,将连接转发到 GoCD 的 HTTP 端点。 这种选择提供了更无缝的 Let's Encrypt 体验,并且可能是大多数人的最佳选择。
我们将讨论的第二种方法将从 Let's Encrypt 获取证书,然后切换 GoCD 的 HTTPS 端点使用的证书。 虽然这消除了对单独 Web 服务器的要求,可能会节省资源,但 GoCD 使用 Java 密钥库 SSL 证书存储库,它与 Let's Encrypt 提供的证书格式不直接兼容。 我们需要创建一个脚本,以便在每次续订时自动将证书转换为预期的格式。 如果您的服务器资源最少并且您希望将所有可用的资源分配给 GoCD 本身,则此选项是最佳选择。
先决条件
如果您尚未在 Ubuntu 16.04 上配置 GoCD 服务器,则需要在开始本指南之前配置一个。 基础服务器需要 至少 2G 的 RAM 和 2 个 CPU 内核 。 GoCD 还需要一个专用的分区或磁盘来存储工件。 您可以使用以下两个指南之一来了解如何配置此额外空间:
- 如果您使用 DigitalOcean 作为服务器主机,则可以使用块存储卷作为工件存储位置。 按照本指南了解 如何配置、格式化和安装 DigitalOcean 块存储卷 。
- 如果您 不是 使用 DigitalOcean,请按照本指南学习 如何在通用主机 上分区、格式化和挂载设备。
设置服务器后,您可以使用以下指南执行一些初始配置并安装 GoCD:
- 使用 Ubuntu 16.04 进行初始服务器设置:本指南将向您展示如何创建
sudo
用户并设置基本防火墙。 - 如何在 Ubuntu 16.04 上安装和配置 GoCD:本指南将指导您安装软件、配置工件挂载点和设置用户身份验证。
要从 Let's Encrypt 获取 SSL 证书,您的服务器需要有一个 域名。
进一步的要求取决于您要采用的方法,并将在相应的部分中进行说明。 当您准备好继续时,选择您要使用的方法并按照相关说明进行操作。
选项 1:将 Nginx 配置为 GoCD 的反向代理
如果您想将 Nginx 设置为 GoCD 的 SSL 终止反向代理,请按照本节操作。 在此配置中,Nginx 将被配置为使用 Let's Encrypt 证书服务 HTTPS 流量。 它将解密客户端连接,然后使用常规 HTTP 将流量转发到 GoCD 的 Web 界面。 这需要 Nginx 前端的一些额外开销,但这是一种更直接的方法。
其他要求
如果您想使用 Nginx 作为 GoCD 的反向代理,您首先需要安装 Nginx 和 Let's Encrypt 客户端,然后为您的域申请证书。 这些教程提供了获取证书和配置 Web 服务器所需的步骤:
完成上述指南后,仍然可以通过访问 https://your_domain:8154
使用自签名证书访问 GoCD,并且当您删除端口规范时,应该使用 Let's Encrypt 证书显示默认 Nginx 页面。
现在,我们可以将 Nginx 配置为将请求代理到 GoCD 后端,以便客户端连接使用 Let's Encrypt 证书进行加密。
将 Nginx 配置为代理到 GoCD 的 HTTP Web 界面
我们从 Let's Encrypt 下载了 SSL 证书,并配置 Nginx 在默认 SSL 端口上处理请求时使用该证书。 我们的下一步是配置 Nginx 以将这些请求代理到 GoCD 的常规 HTTP Web 界面,该界面可在端口 8153 上使用。
首先,打开配置为使用 Let's Encrypt 证书的默认 Nginx 服务器块文件:
sudo nano /etc/nginx/sites-available/default
在文件顶部,在 server
块之外,打开一个新的 upsteam
部分。 我们将此块称为 gocd
以便我们以后可以轻松识别它。 在里面,指定 Nginx 可以用来联系 GoCD 的 HTTP 接口的地址。 在我们的例子中,这将使用本地环回设备,因此完整地址应该是 127.0.0.1:8153
:
/etc/nginx/sites-available/default
upstream gocd { server 127.0.0.1:8153; } server { . . .
接下来,在 server
块中,找到 location /
块。 在里面,注释掉 try_files
指令,以便我们可以指定我们的代理配置。 代替 try_files
行,使用 http://
协议向我们定义的上游 gocd
添加代理传递。 包含 proxy_params
文件以设置我们的位置块所需的其他代理设置:
/etc/nginx/sites-available/default
. . . server . . . location / { #try_files $uri $uri/ =404; proxy_pass http://gocd; include proxy_params; } . . .
完成后保存并关闭文件。
回到命令行后,通过键入以下命令检查 Nginx 配置中的语法错误:
sudo nginx -t
如果没有发现错误,请键入以下命令重新启动 Nginx 服务:
sudo systemctl restart nginx
您的 GoCD Web UI 现在应该可以使用 https://
协议通过您的常规域名访问。
注意: 虽然我们通过 Nginx 代理端口 80 和 443 上的请求,但我们仍然需要 在我们的防火墙中保持 8154 HTTPS 端口打开。 GoCD 代理需要能够直接联系 GoCD 服务器(无需代理),以便服务器可以直接验证客户端的 SSL 证书。 保持端口 8154 开放将允许外部代理正确联系服务器,而通过浏览器的常规 Web 请求可以通过代理。
我们需要调整的最后一项是 GoCD 的 Web UI 中的站点 URL 设置。
更新 GoCD 站点 URL 以使用新地址
重新启动 Nginx 后,剩下的唯一任务是修改 GoCD 在内部使用的站点 URL 设置以构建适当的链接。
在 Web 浏览器中访问您的 GoCD 服务器域并在必要时登录:
https://example.com
接下来,单击顶部菜单栏中的 ADMIN,然后从下拉菜单中选择 Server Configuration:
在 Server Management 部分,修改 Site URL 以从末尾删除 :8154
端口规范。 如果您之前使用的是 IP 地址而不是域名,请将 URL 更改为也使用您的域名:
向下滚动到页面底部,然后单击 SAVE 立即实施更改。 您的站点现在已设置为通过 Nginx 将您的域的所有请求代理到 GoCD Web UI。
选项 2:配置 GoCD 的本机 SSL 以使用 Let's Encrypt 证书
如果您想配置 GoCD 自己的 Web 服务器以使用 Let's Encrypt 证书,请按照本节操作。 在此配置中,我们将使用 Let's Encrypt 提供的可信证书替换 GoCD 服务器已经使用的自签名证书。 不过,要做到这一点,我们需要将证书文件转换为新格式并将它们导入到 Java 密钥库文件中。 我们将创建一个脚本,以便每次更新证书文件时都可以重复该过程。
其他要求
如果您希望从 GoCD 本身处理所有 SSL 操作,则需要从 Let's Encrypt 下载证书,而无需执行 Web 服务器配置过程。 按照本指南下载适当的客户端并为您的域获取证书:
- 如何使用 Certbot 独立模式检索 Let's Encrypt SSL 证书:您可以跳过设置自动续订的步骤,因为我们将在此过程中创建一个特定的脚本来运行。
完成上述指南后,GoCD 应该仍然可以通过访问 https://your_domain:8154
使用自签名证书访问,并且 Let's Encrypt 提供的证书文件应该在 /etc/letsencrypt/live/your_domain
目录中可用。
创建证书转换脚本
GoCD 使用 Java 密钥库 来处理 SSL 证书。 不幸的是,这与 Let's Encrypt 使用的格式不同。 要将我们的 Let's Encrypt 证书与 GoCD 一起使用,我们必须使用非常特定的过程来转换它们。
由于该过程的复杂性以及我们每次更新证书时都需要转换证书,我们将创建一个脚本来自动化该过程。 在 /usr/local/bin
目录中,创建并在文本编辑器中打开一个名为 convert_certs_for_gocd.sh
的脚本:
sudo nano /usr/local/bin/convert_certs_for_gocd.sh
在里面,粘贴以下脚本。 您需要更新的唯一设置是 base_domain
变量的值。 将其设置为您的 GoCD 服务器的域名(这应该与 /etc/letsencrypt/live/
中目录的值匹配):
/usr/local/bin/convert_certs_for_gocd.sh
#!/bin/bash base_domain="example.com" le_directory="/etc/letsencrypt/live/${base_domain}" working_dir="$(mktemp -d)" gocd_pass="serverKeystorepa55w0rd" clean_up () { rm -rf "${working_dir}" } # Use this to echo to standard error error () { printf "%s: %s\n" "$(basename "${BASH_SOURCE}")" "${1}" >&2 clean_up exit 1 } trap 'error "An unexpected error occurred."' ERR copy_cert_files () { cp "${le_directory}/fullchain.pem" "${working_dir}" cp "${le_directory}/privkey.pem" "${working_dir}" } convert_to_pkcs12 () { openssl_pkcs12_args=( "pkcs12" "-inkey" "${working_dir}/privkey.pem" "-in" "${working_dir}/fullchain.pem" "-export" "-out" "${working_dir}/${base_domain}.crt.pkcs12" "-passout" "pass:${gocd_pass}" ) openssl "${openssl_pkcs12_args[@]}" } import_to_keytool () { keytool_args=( "-importkeystore" "-srckeystore" "${working_dir}/${base_domain}.crt.pkcs12" "-srcstoretype" "PKCS12" "-srcstorepass" "${gocd_pass}" "-destkeystore" "${working_dir}/keystore" "-srcalias" "1" "-destalias" "cruise" "-deststorepass" "${gocd_pass}" "-destkeypass" "${gocd_pass}" ) keytool "${keytool_args[@]}" } install_new_keystore () { cp /etc/go/keystore /etc/go/keystore.bak mv "${working_dir}/keystore" "/etc/go/keystore" chown go:go /etc/go/keystore systemctl restart go-server } if (( EUID != 0 )); then error "This script requires root privileges" fi copy_cert_files && convert_to_pkcs12 && import_to_keytool && install_new_keystore && clean_up
让我们来看看这个脚本在做什么。
一开始,我们设置了一些变量来帮助我们的脚本更易于使用。 我们为要转换的证书设置域名和一个扩展为 Let's Encrypt 证书目录的变量。 我们使用 mktemp
命令创建一个临时工作目录,并将值分配给另一个变量。 GoCD 要求其所有 Java 密钥库密码 为 serverKeystorepa55w0rd
,我们设置另一个变量来保存该值。
接下来,我们定义一个在调用时删除临时目录的函数。 我们在脚本末尾使用它来清理自己以及发生任何意外错误时。 为了实现第二种可能性,我们创建了另一个函数来显示错误消息并在退出前进行清理。 我们使用 trap
命令在出现错误时自动调用此函数。
之后,我们创建进行实际转换的函数。 第一个函数通过将私钥和完整链证书复制到工作目录来设置我们的工作区。 convert_to_pkcs12
函数使用openssl
将全链证书文件和私钥文件加入keytool使用的组合PKCS 12文件中。 此过程需要导出密码,因此我们使用 GoCD 密码变量。
下一个函数将新的 PKCS 12 文件导入 Java 密钥库文件。 我们导入文件并提供导出密码。 然后,我们为密钥库文件的各种密码提供相同的密码。 最后最后一个函数将新的keystore
文件复制到/etc/go
目录下(备份旧的keystore
后),调整文件归属,重启GoCD服务器。
在脚本结束时,我们通过检查有效用户 ID 是否为“0”来检查脚本是否以适当的权限被调用,这意味着“与 root 具有相同的权限”。 然后以适当的顺序调用函数以正确转换证书并安装新的 keystore
文件。
完成后,保存并关闭文件以继续。
执行初始转换
现在我们有了一个转换脚本,我们应该使用它来执行初始证书转换。
首先,将脚本标记为可执行,这样它就可以直接执行而无需调用解释器:
sudo chmod +x /usr/local/bin/convert_certs_for_gocd.sh
现在,使用 sudo
调用脚本进行初始转换,安装生成的 keystore
文件,并重新启动 GoCD 进程
sudo /usr/local/bin/convert_certs_for_gocd.sh
由于 GoCD 服务器必须重新启动,因此该过程可能需要一些时间。 脚本完成后,服务器可能需要一两分钟才能准备好监听连接。 您可以通过键入以下内容来查看应用程序当前使用的端口:
sudo watch netstat -plnt
此视图将以两秒的刷新率显示应用程序当前正在侦听的 TCP 端口。 当 GoCD 开始监听端口 8153 和 8154 时,屏幕应如下所示:
OutputEvery 2.0s: netstat -plnt Thu Jul 27 20:16:20 2017 Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1736/sshd tcp6 0 0 :::22 :::* LISTEN 1736/sshd tcp6 0 0 :::8153 :::* LISTEN 8942/java tcp6 0 0 :::8154 :::* LISTEN 8942/java
一旦端口 8153 和 8154 出现,点击 CTRL-C 退出显示。
应用程序开始侦听连接后,通过使用 HTTPS 在端口 8154 上访问您的 GoCD 域来检查 Web 界面:
https://example.com:8154
以前,当访问此页面时,地址栏中的图标表示证书不可信(请注意,您的浏览器的视觉指示器可能不同):
第一次访问时,您可能不得不点击浏览器中的警告屏幕:
现在我们已经用 Let's Encrypt 提供的受信任证书替换了自签名证书,浏览器将指示该证书是受信任的,用户无需绕过浏览器警告即可访问该站点。 请注意,在您关闭当前选项卡、窗口或会话之前,您的浏览器可能会缓存以前的证书:
这意味着 GoCD 能够使用我们转换的 Let's Encrypt 证书。
设置自动续订挂钩
现在我们已经验证了我们的脚本正确地转换了证书资产,我们可以确保每次更新证书时 certbot
都会调用我们的脚本。
通过键入以下内容在 /etc/letsencrypt/renewal
目录中打开您的域的续订配置文件:
sudo nano /etc/letsencrypt/renewal/example.com.conf
在里面,在文件的 [renewalparams]
部分,将行设置 renew_hook
添加到脚本的位置:
/etc/letsencrypt/renewal/example.com.conf
. . . [renewalparams] . . . renew_hook = /usr/local/bin/convert_certs_for_gocd.sh
certbot
软件安装一个 cron
作业,检查是否有任何证书应每天更新两次。 更新证书后,将运行renew_hook
指定的脚本。 这样,我们可以确保 GoCD 始终使用从 Let's Encrypt 获得的最新有效证书。
完成后保存并关闭文件。
您可以通过试运行更新过程来测试您没有向文件引入任何语法错误。 请注意,这不会运行我们的证书转换脚本,但会打印出一条关于它被跳过的通知:
sudo certbot renew --dry-run
OutputSaving debug log to /var/log/letsencrypt/letsencrypt.log ------------------------------------------------------------------------------- Processing /etc/letsencrypt/renewal/example.com.conf ------------------------------------------------------------------------------- Cert not due for renewal, but simulating renewal for dry run Renewing an existing certificate Performing the following challenges: http-01 challenge for example.com Waiting for verification... Cleaning up challenges Dry run: skipping renewal hook command: /usr/local/bin/convert_certs_for_gocd.sh ------------------------------------------------------------------------------- new certificate deployed without reload, fullchain is /etc/letsencrypt/live/example.com/fullchain.pem ------------------------------------------------------------------------------- ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates below have not been saved.) Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/example.com/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates above have not been saved.)
上面的输出验证了我们所做的更改并没有阻止证书更新。 输出还表明更新挂钩指向正确的脚本位置。
结论
在本指南中,我们介绍了使用 Let's Encrypt 的受信任 SSL 证书保护 GoCD 安装的两种不同方法。 第一种方法使用 Nginx 设置证书,然后将流量代理到 GoCD 的 Web 界面。 第二个选项将 Let's Encrypt 证书文件转换为 PKCS 12 格式,并将它们导入到 Java 密钥库文件中,供 GoCD 本地使用。 这两个选项都使用受信任的证书保护 GoCD 的 Web 界面,但它们使用不同的策略和独特的权衡来实现这一点。 适合您的方法在很大程度上取决于您团队的要求和目标。