为极狐GitLab Linux 包配置 SSL

极狐GitLab Linux 包 (Omnibus GitLab) 支持 SSL 配置的几种常见用例。

默认情况下,HTTPS 未启用。要启用 HTTPS,您可以:

  • 使用 Let’s Encrypt 免费的自动 HTTPS。
  • 使用您自己的证书手动配置 HTTPS。
note如果您使用代理、负载均衡器或其他一些外部设备,来终止极狐GitLab 主机名的 SSL,请参阅外部、代理和负载均衡器 SSL 终止

下表显示了每个极狐GitLab 服务支持的方法。

服务 手动 SSL Let’s Encrypt
GitLab Instance Domain Yes Yes
Container Registry Yes Yes
Mattermost Yes Yes
GitLab Pages Yes No

启用 Let’s Encrypt 集成

如果 external_url 设置为 HTTPS 协议且未配置其他证书,则默认启用 Let’s Encrypt

先决条件:

  • 运行验证检查的公共 Let’s Encrypt 服务器必须可以访问端口 80443。验证不适用于非标准端口。如果环境是私有的或隔离的,certbot(Let’s Encrypt 使用的工具)提供了安装 Let’s Encrypt 证书的手动方法

要启用 Let’s Encrypt:

  1. 编辑/etc/gitlab/gitlab.rb并添加或更改以下条目:

    ## GitLab instance
    external_url "https://gitlab.example.com"         # Must use https protocol
    letsencrypt['contact_emails'] = ['foo@email.com'] # Optional
    
    ## Container Registry (optional), must use https protocol
    registry_external_url "https://registry.example.com"
    #registry_nginx['ssl_certificate'] = "path/to/cert"      # Must be absent or commented out
    
    ## Mattermost (optional), must use https protocol
    mattermost_external_url "https://mattermost.example.com"
    
    • 证书每 90 天到期一次。当到期日期临近时,您为 contact_emails 指定的电子邮件地址会收到警报。
    • 极狐GitLab 实例是证书上的主域名。Container Registry 等其他服务作为备用域名添加到同一个证书中。在上面的示例中,主域名是 gitlab.example.com,Container Registry 域名是 registry.example.com。您不需要设置通配符证书。
  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

自动更新证书

默认安装会在每月第 4 天的午夜后安排更新。 在哪一分钟更新由 external_url 中的值确定,帮助在上游 Let’s Encrypt 服务器上分配负载。

要明确设置更新时间:

  1. 编辑 /etc/gitlab/gitlab.rb

    # Renew every 7th day of the month at 12:30
    letsencrypt['auto_renew_hour'] = "12"
    letsencrypt['auto_renew_minute'] = "30"
    letsencrypt['auto_renew_day_of_month'] = "*/7"
    
  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    
note仅当证书在 30 天内到期时才会更新。例如,如果您将其设置为每月 1 日 00:00 更新,并且证书在 31 日到期,则证书将在更新之前到期。

要禁用自动更新:

  1. 编辑 /etc/gitlab/gitlab.rb

    letsencrypt['auto_renew'] = false
    
  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

手动更新证书

使用以下任一命令手动更新 Let’s Encrypt 证书:

sudo gitlab-ctl reconfigure
sudo gitlab-ctl renew-le-certs

仅当证书即将到期时,前面的命令才会生成更新。 如果在更新期间遇到错误,考虑上行速率限制

使用 Let’s Encrypt 以外的 ACME 服务器

您可以使用 Let’s Encrypt 以外的 ACME 服务器,并将极狐GitLab 配置为使用它来获取证书。提供自己的 ACME 服务器的服务有:

要将极狐GitLab 配置为使用自定义 ACME 服务器:

  1. 编辑 /etc/gitlab/gitlab.rb 并设置 ACME 端点:

    external_url 'https://example.com'
    letsencrypt['acme_staging_endpoint'] = 'https://ca.internal/acme/acme/directory'
    letsencrypt['acme_production_endpoint'] = 'https://ca.internal/acme/acme/directory'
    

    如果自定义 ACME 服务器提供了它,那么也可以使用暂存端点。在将请求提交给 ACME 生产之前,首先检查暂存端点确保 ACME 配置正确。这样做是为了在处理配置时避免 ACME 速率限制。

    默认值:

    https://acme-staging-v02.api.letsencrypt.org/directory
    https://acme-v02.api.letsencrypt.org/directory
    
  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

手动配置 HTTPS

cautionNGINX 配置告诉浏览器和客户端在接下来的 365 天内使用 HSTS,仅通过安全连接与您的极狐GitLab 实例通信。 有关更多配置选项,请参阅配置 HTTP 严格传输安全性。如果启用 HTTPS,您必须至少在接下来的 24 个月内为您的实例提供安全连接。

要启用 HTTPS:

  1. 编辑 /etc/gitlab/gitlab.rb
    1. external_url 设置为您的域名。请注意 URL 中的 https

      external_url "https://gitlab.example.com"
      
    2. 禁用 Let’s Encrypt 集成:

      letsencrypt['enable'] = false
      

      极狐GitLab 尝试在每次重新配置时更新任何 Let’s Encrypt 证书。如果您打算使用自己手动创建的证书,则必须禁用 Let’s Encrypt 集成,否则证书可能会由于自动更新而被覆盖。

  2. 创建 /etc/gitlab/ssl 目录并在那里复制您的密钥和证书:

    sudo mkdir -p /etc/gitlab/ssl
    sudo chmod 755 /etc/gitlab/ssl
    sudo cp gitlab.example.com.key gitlab.example.com.crt /etc/gitlab/ssl/
    

    在示例中,主机名是 gitlab.example.com,因此 Omnibus GitLab 会查找私钥和公共证书文件,分别名为 /etc/gitlab/ssl/gitlab.example.com.key/etc/gitlab/ssl/gitlab.example.com.crt。如果需要,您可以使用不同的位置和证书名称

    您必须以正确的顺序使用完整的证书链,以防止客户端连接时出现 SSL 错误:首先是服务器证书,然后是所有中间证书,最后是根 CA。

  3. 可选。如果 certificate.key 文件受密码保护,当您重新配置极狐GitLab 时,NGINX 不会要求输入密码。在这种情况下,Omnibus GitLab 会静默失败,没有错误消息。

    要指定密钥文件的密码,请将密码存储在文本文件中(例如,/etc/gitlab/ssl/key_file_password.txt),并将以下内容添加到/etc/gitlab/gitlab.rb

    nginx['ssl_password_file'] = '/etc/gitlab/ssl/key_file_password.txt'
    
  4. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    
  5. 可选。如果您使用防火墙,则可能必须打开端口 443 以允许入站 HTTPS 流量:

    # UFW example (Debian, Ubuntu)
    sudo ufw allow https
    
    # lokkit example (RedHat, CentOS 6)
    sudo lokkit -s https
    
    # firewall-cmd (RedHat, Centos 7)
    sudo firewall-cmd --permanent --add-service=https
    sudo systemctl reload firewalld
    

如果您要更新现有证书,请遵循不同的流程

HTTP 请求重定向到 HTTPS

默认情况下,当您指定以 https 开头的 external_url 时,NGINX 不再侦听端口 80 上未加密的 HTTP 流量。要将所有 HTTP 流量重定向到 HTTPS:

  1. 编辑 /etc/gitlab/gitlab.rb

    nginx['redirect_http_to_https'] = true
    
  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    
note使用 Let’s Encrypt 集成时默认启用此行为。

更改默认 HTTPS 端口

如果您需要使用默认端口 (443) 以外的 HTTPS 端口,请将其指定为 external_url 的一部分:

  1. 编辑 /etc/gitlab/gitlab.rb

    external_url "https://gitlab.example.com:2443"
    
  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

更改默认 SSL 证书位置

如果您的主机名是 gitlab.example.com,Omnibus 会查找名为 /etc/gitlab/ssl/gitlab.example.com.key 的私钥和默认名为 /etc/gitlab/ssl/gitlab.example.com.crt 的公共证书。

要设置 SSL 证书的不同位置:

  1. 创建一个目录,给它适当的权限,并将.crt.key文件放在目录中:

    sudo mkdir -p /mnt/gitlab/ssl
    sudo chmod 755 /mnt/gitlab/ssl
    sudo cp gitlab.key gitlab.crt /mnt/gitlab/ssl/
    

    您必须以正确的顺序使用完整的证书链,以防止客户端连接时出现 SSL 错误:首先是服务器证书,然后是所有中间证书,最后是根 CA。

  2. 编辑 /etc/gitlab/gitlab.rb

    nginx['ssl_certificate'] = "/mnt/gitlab/ssl/gitlab.crt"
    nginx['ssl_certificate_key'] = "/mnt/gitlab/ssl/gitlab.key"
    
  3. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

更新 SSL 证书

如果您的 SSL 证书的内容已更新,但没有对 /etc/gitlab/gitlab.rb 进行配置更改,则重新配置极狐GitLab 不会影响 NGINX。相反,您必须使 NGINX 优雅地重新加载现有配置和新证书

sudo gitlab-ctl hup nginx registry

配置反向代理或负载均衡器 SSL 终止

默认情况下,如果 external_url 包含 https://,Omnibus 会自动检测是否使用 SSL,并为 SSL 终止配置 NGINX。 但是,如果您将极狐GitLab 配置为在反向代理或外部负载均衡器后面运行,某些环境可能希望在极狐GitLab 应用程序之外终止 SSL。

要防止捆绑的 NGINX 处理 SSL 终止:

  1. 编辑 /etc/gitlab/gitlab.rb

    nginx['listen_port'] = 80
    nginx['listen_https'] = false
    
  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

外部负载均衡器可能需要访问返回 200 状态码的极狐GitLab 端点(对于需要登录的安装实例,根页面返回 302 重定向到登录页面)。在这种情况下,建议利用健康检查端点

其他捆绑的组件,如 Container Registry、GitLab Pages 或 Mattermost,对代理 SSL 使用类似的策略。使用 https:// 设置特定组件的 *_external_url,并在 nginx[...] 配置前加上组件名称。例如,Container Registry 配置以 registry_ 为前缀:

  1. 编辑 /etc/gitlab/gitlab.rb
  registry_external_url 'https://registry.example.com'

  registry_nginx['listen_port'] = 80
  registry_nginx['listen_https'] = false

相同的格式可用于 Pages(pages_ 前缀)和 Mattermost(mattermost_ 前缀)。

  1. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    
  2. 可选。您可能需要配置反向代理或负载均衡器以将某些 headers(例如 HostX-Forwarded-SslX-Forwarded-ForX-Forwarded-Port)转发到极狐GitLab(和 Mattermost,如果您使用)。如果您忘记了这一步,您可能会看到不正确的重定向或错误,例如 “422 Unprocessable Entity” 或 “Can’t verify CSRF token authenticity”。

某些云提供商服务,例如 AWS Certificate Manager (ACM),并非都下载证书。这可以防止它们被用来终止极狐GitLab 实例。如果此类云服务和极狐GitLab 之间需要 SSL,则必须在极狐GitLab 实例上使用另一个证书。

使用自定义 SSL 密码

要更改 SSL 密码:

  1. 编辑 /etc/gitlab/gitlab.rb

    nginx['ssl_ciphers'] = "CIPHER:CIPHER1"
    
  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

要启用 ssl_dhparam 指令:

  1. 生成dhparams.pem

    openssl dhparam -out /etc/gitlab/ssl/dhparams.pem 2048
    
  2. 编辑 /etc/gitlab/gitlab.rb

    nginx['ssl_dhparam'] = "/etc/gitlab/ssl/dhparams.pem"
    
  3. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

配置 HTTP/2 协议

默认情况下,当您指定极狐GitLab 实例可通过 HTTPS 访问时,HTTP/2 协议也会启用。

Omnibus 包设置了与 HTTP/2 协议兼容的所需 SSL 密码。

如果您指定自己的自定义 SSL 密码,并且密码在 HTTP/2 密码黑名单,当您尝试访问极狐GitLab 实例时,您会在浏览器中看到 INADEQUATE_SECURITY 错误。在这种情况下,请考虑从密码列表中删除违规密码。仅当您有非常具体的自定义设置时,才需要更改密码。

有关为什么要启用 HTTP/2 协议的更多信息,请查看 NGINX HTTP/2 白皮书

如果更改密码不是一个选项,您可以禁用 HTTP/2 支持:

  1. 编辑 /etc/gitlab/gitlab.rb

    nginx['http2_enabled'] = false
    
  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    
noteHTTP/2 设置仅适用于极狐GitLab 主应用程序,不适用于其他服务,例如 GitLab Pages、Container Registry 和 Mattermost。

启用 2-way SSL 客户端身份验证

要要求 Web 客户端使用受信任的证书进行身份验证,您可以启用 2-way SSL:

  1. 编辑 /etc/gitlab/gitlab.rb

    nginx['ssl_verify_client'] = "on"
    nginx['ssl_client_certificate'] = "/etc/pki/tls/certs/root-certs.pem"
    
  2. 可选。您可以配置 NGINX,在确定客户端没有有效证书之前验证证书链的深度(默认为 1)。编辑 /etc/gitlab/gitlab.rb

    nginx['ssl_verify_depth'] = "2"
    
  3. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

配置 HTTP Strict Transport Security(HSTS)

noteHSTS 设置仅适用于 GitLab 主应用程序,不适用于其他服务,例如 GitLab Pages、Container Registry 和 Mattermost。

HTTP Strict Transport Security(HSTS)默认启用,它通知浏览器他们应该只使用 HTTPS 联系网站。当浏览器访问极狐GitLab 实例一次时,它会记住不再尝试不安全的连接,即使用户明确输入纯 HTTP URL (http://)。浏览器会自动将纯 HTTP URL 重定向到 https:// 变体。

默认情况下, max_age 设置为两年,这是浏览器记住只通过 HTTPS 连接的时间。

要更改最大 age 值:

  1. 编辑 /etc/gitlab/gitlab.rb

    nginx['hsts_max_age'] = 63072000
    nginx['hsts_include_subdomains'] = false
    

    Setting max_age to 0 disables HSTS.

  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

有关 HSTS 和 NGINX 的更多信息,请参阅 https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/

安装自定义公共证书

一些环境连接到外部资源以执行各种任务。Omnibus 允许这些连接使用 HTTPS,并支持使用自签名证书的连接。

Omnibus 附带了官方的 CAcert.org 可信根证书颁发机构集合,用于验证证书的真实性。

note对于使用自签名证书的安装实例,Omnibus 提供了一种管理这些证书的方法。有关其工作原理的更多技术细节,请参阅本页底部的详细信息
notec_rehash 依赖需要一个 perl 解释器来正确地符号链接证书。Perl 目前未捆绑在 Omnibus GitLab 中。
  1. 从您的私钥证书生成 PEMDER 编码的公共证书。
  2. 仅将公共证书文件复制到/etc/gitlab/trusted-certs 目录中。默认情况下,系统期望找到一个以您的 GitLab URL 为标题的证书,扩展名为 .crt。 例如,如果您的服务器地址是 https://gitlab.example.com,则证书应命名为 gitlab.example.com.crt。要指定不同的路径和文件名,您可以更改默认 SSL 证书位置
  3. 在 NGINX 上启用并手动配置 HTTPS,设置极狐GitLab 使用您自己的证书。
  4. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    
caution如果使用自定义证书链,由于 c_rehash 仅为第一个证书创建哈希,则必须将根证书和中间证书放入/etc/gitlab/trusted-certs 中的单独文件中。

极狐GitLab 和 SSL 的工作实现细节

Omnibus 包含自己的 OpenSSL 库,并将所有已编译的程序(例如 Ruby、PostgreSQL 等)链接到该库。该库编译为在 /opt/gitlab/embedded/ssl/certs 中查找证书。

Omnibus 通过使用 c_rehash 将添加到 /etc/gitlab/trusted-certs/ 的任何证书链接到 /opt/gitlab/embedded/ssl/certs 来管理自定义证书。例如,假设我们将 customcacert.pem 添加到 /etc/gitlab/trusted-certs/

$ sudo ls -al /opt/gitlab/embedded/ssl/certs
total 272
drwxr-xr-x 2 root root   4096 Jul 12 04:19 .
drwxr-xr-x 4 root root   4096 Jul  6 04:00 ..
lrwxrwxrwx 1 root root     42 Jul 12 04:19 7f279c95.0 -> /etc/gitlab/trusted-certs/customcacert.pem
-rw-r--r-- 1 root root 263781 Jul  5 17:52 cacert.pem
-rw-r--r-- 1 root root    147 Feb  6 20:48 README

证书的指纹为 7f279c95,它链接到自定义证书。

当我们发出 HTTPS 请求时会发生什么?让我们以一个简单的 Ruby 程序为例:

#!/opt/gitlab/embedded/bin/ruby
require 'openssl'
require 'net/http'

Net::HTTP.get(URI('https://www.google.com'))

以下是屏幕后面发生的事情:

  1. “require openssl”行导致解释器加载 /opt/gitlab/embedded/lib/ruby/2.3.0/x86_64-linux/openssl.so
  2. Net::HTTP 调用然后尝试读取 /opt/gitlab/embedded/ssl/certs/cacert.pem 中的默认证书包。
  3. SSL 协商。
  4. 服务器发送其 SSL 证书。
  5. 如果发送的证书包含在捆绑包中,则 SSL 将成功完成。
  6. 否则,OpenSSL 可能会通过在预定义的证书目录中,搜索与其指纹匹配的文件来验证其他证书。 例如,如果证书的指纹为“7f279c95”,OpenSSL 将尝试读取 /opt/gitlab/embedded/ssl/certs/7f279c95.0

请注意,OpenSSL 库支持 SSL_CERT_FILESSL_CERT_DIR 环境变量的定义。前者定义了要加载的默认证书包,而后者定义了一个用于搜索更多证书的目录。如果你已将证书添加到“trusted-certs”目录中,这些变量不是必需的。但是,如果由于某种原因需要设置它们,它们可以定义为环境变量。例如:

gitlab_rails['env'] = {"SSL_CERT_FILE" => "/usr/lib/ssl/private/customcacert.pem"}

故障排除

请查看我们的 SSL 故障排除指南