在 chart 组件之间使用 TLS

极狐GitLab chart 可以在各种组件之间使用传输层安全性 (TLS),这要求您为要启用的服务提供证书,并配置这些服务使用这些证书和签署它们的证书颁发机构(CA)。

准备

每个 chart 都有关于为该服务启用 TLS 的文档,以及确保适当配置所需的各种设置。

生成供内部使用的证书

note 极狐GitLab 并不声称提供高级 PKI 基础设施或证书颁发机构。

出于本文档的目的,我们在下面提供了一个概念证明脚本,它利用 Cloudflare 的 CFSSL 生成自签名证书颁发机构,以及可用于所有服务的通配符证书。

该脚本将:

  • 生成 CA 密钥对。
  • 签署旨在为所有极狐GitLab 组件服务端点提供服务的证书。
  • 创建两个 Kubernetes Secret 对象:
    • 具有服务器证书和密钥对的 kuberetes.io/tls 类型的 secret。
    • Opaque 类型的 secret,包含 CA 的公共证书作为 NGINX Ingress 需要的 ca.crt

先决条件:

  • Bash,或兼容的 shell。
  • cfssl 可用于您的 shell,并且位于 PATH 中。
  • kubectl 可用,并配置为指向稍后将安装极狐GitLab 的 Kubernetes 集群。
    • 在运行脚本之前,请务必创建您希望将这些证书安装到的命名空间。

您可以将此脚本的内容复制到您的计算机,并使生成的文件可执行。我们建议使用 poc-gitlab-internal-tls.sh

#!/bin/bash
set -e
#############
## make and change into a working directory
pushd $(mktemp -d)

#############
## setup environment
NAMESPACE=${NAMESPACE:-default}
RELEASE=${RELEASE:-gitlab}
## stop if variable is unset beyond this point
set -u
## known expected patterns for SAN
CERT_SANS="*.${NAMESPACE}.svc,${RELEASE}-metrics.${NAMESPACE}.svc,*.${RELEASE}-gitaly.${NAMESPACE}.svc"

#############
## generate default CA config
cfssl print-defaults config > ca-config.json
## generate a CA
echo '{"CN":"'${RELEASE}.${NAMESPACE}.internal.ca'","key":{"algo":"ecdsa","size":256}}' | \
  cfssl gencert -initca - | \
  cfssljson -bare ca -
## generate certificate
echo '{"CN":"'${RELEASE}.${NAMESPACE}.internal'","key":{"algo":"ecdsa","size":256}}' | \
  cfssl gencert -config=ca-config.json -ca=ca.pem -ca-key=ca-key.pem -profile www -hostname="${CERT_SANS}" - |\
  cfssljson -bare ${RELEASE}-services

#############
## load certificates into K8s
kubectl -n ${NAMESPACE} create secret tls ${RELEASE}-internal-tls \
  --cert=${RELEASE}-services.pem \
  --key=${RELEASE}-services-key.pem
kubectl -n ${NAMESPACE} create secret generic ${RELEASE}-internal-tls-ca \
  --from-file=ca.crt=ca.pem
note 此脚本不保留 CA 的私钥。它是一个概念验证,不适用于生产用途。

该脚本需要设置两个环境变量:

  1. NAMESPACE:您稍后将极狐GitLab 安装到的 Kubernetes 命名空间。与 kubectl 一样,默认为 default
  2. RELEASE:您稍后将用于安装极狐GitLab 的 Helm Release 名称。默认为 gitlab

要运行此脚本,您可以“导出”这两个变量,或在脚本名称前加上它们的值。

export NAMESPACE=testing
export RELEASE=gitlab

./poc-gitlab-internal-tls.sh

脚本运行后,您会发现创建的两个密钥,临时工作目录包含所有证书及其密钥。

$ pwd
/tmp/tmp.swyMgf9mDs
$ kubectl -n ${NAMESPACE} get secret | grep internal-tls
testing-internal-tls      kubernetes.io/tls                     2      11s
testing-internal-tls-ca   Opaque                                1      10s
$ ls -1
ca-config.json
ca.csr
ca-key.pem
ca.pem
testing-services.csr
testing-services-key.pem
testing-services.pem

所需证书 CN 和 SAN

各种极狐GitLab 组件通过其服务的 DNS 名称相互通信。 当 tls.verify: true(这是默认值)时,极狐GitLab chart 生成的 Ingress 对象必须提供 NGINX 要验证的名称。因此,每个极狐GitLab 组件都应收到带有 SAN 的证书,其中包括其服务名称或 Kubernetes 服务 DNS 条目可接受的通配符。

  • service-name.namespace.svc
  • *.namespace.svc

如果需要,您可以使用 helm template 来检索所有服务对象名称的完整列表。如果您的极狐GitLab 是在没有 TLS 的情况下部署的,您可以向 Kubernetes 查询这些名称:

kubectl -n ${NAMESPACE} get service -lrelease=${RELEASE}

配置

您可以在 examples/internal-tls 中找到配置示例。

出于本文档的目的,提供了 shared-cert-values.yaml,在生成供内部使用的证书时,它将极狐GitLab 组件配置为使用上面脚本生成的证书。

要配置的关键项:

  1. 全局自定义证书颁发机构
  2. 服务监听器的每个组件的 TLS。(查看每个 chart 的文档,在 charts/ 目录下)

通过使用 YAML 的本地锚点功能,可以大大简化此过程。shared-cert-values.yaml 的截断片段如下:

.internal-ca: &internal-ca gitlab-internal-tls-ca
.internal-tls: &internal-tls gitlab-internal-tls

global:
  certificates:
    customCAs:
    - secret: *internal-ca
  workhorse:
    tls:
      enabled: true
gitlab:
  webservice:
    tls:
      secretName: *internal-tls
    workhorse:
       tls:
          verify: true # default
          secretName: *internal-tls
          caSecretName: *internal-ca

结果

当所有组件都配置为在其服务侦听器上提供 TLS 时,极狐GitLab 组件之间的所有通信都将通过 TLS 安全性遍历网络,包括从 NGINX Ingress 到每个极狐GitLab 组件的连接。

NGINX Ingress 将终止任何入站 TLS,确定将流量传递到哪里的适当服务,然后形成与极狐GitLab 组件的新 TLS 连接。当按此处所示配置时,它还将针对 CA 验证极狐GitLab 组件提供的证书。

这可以通过连接到 Toolbox pod 并查询各种组件服务来验证。连接到 NGINX Ingress 使用的 Webservice Pod 的主要服务端口,示例如下:

$ kubectl -n ${NAMESPACE} get pod -lapp=toolbox,release=${RELEASE}
NAME                              READY   STATUS    RESTARTS   AGE
gitlab-toolbox-5c447bfdb4-pfmpc   1/1     Running   0          65m
$ kubectl exec -ti gitlab-toolbox-5c447bfdb4-pfmpc -c toolbox -- \
    curl -Iv "https://gitlab-webservice-default.testing.svc:8181"

输出应类似于以下示例:

*   Trying 10.60.0.237:8181...
* Connected to gitlab-webservice-default.testing.svc (10.60.0.237) port 8181 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: CN=gitlab.testing.internal
*  start date: Jul 18 19:15:00 2022 GMT
*  expire date: Jul 18 19:15:00 2023 GMT
*  subjectAltName: host "gitlab-webservice-default.testing.svc" matched cert's "*.testing.svc"
*  issuer: CN=gitlab.testing.internal.ca
*  SSL certificate verify ok.
> HEAD / HTTP/1.1
> Host: gitlab-webservice-default.testing.svc:8181

故障排除

如果您的极狐GitLab 实例似乎无法从浏览器访问,通过呈现 HTTP 503 错误,NGINX Ingress 可能在验证极狐GitLab 组件的证书时遇到问题。

您可以通过暂时将 gitlab.webservice.workhorse.tls.verify 设置为 false 来解决这个问题。

可以连接 NGINX Ingress 控制器,并将在 nginx.conf 中显示一条关于证书验证问题的消息。

无法访问 Secret 的示例内容:

# Location denied. Reason: "error obtaining certificate: local SSL certificate
  testing/gitlab-internal-tls-ca was not found"
return 503;

导致这种情况的常见问题:

  • CA 证书不在 Secret 中名为 ca.crt 的密钥中。
  • Secret 未正确提供,或者命名空间中可能不存在。