GitLabチャートのコンポーネント間でTLSを使用します。

GitLabチャートでは、様々なコンポーネント間でトランスポート層のセキュリティ(TLS) 。そのためには、有効にしたいサービスの証明書を提供し、それらのサービスがそれらの証明書とそれに署名した認証局(CA) を利用するように設定する必要があります。

準備

各Chartには、そのサービスでTLSを有効にすること、および適切な設定を確保するために必要な各種設定に関する文書があります。

内部使用のための証明書の生成

note
GitLabはハイグレードなPKIインフラストラクチャや認証局を提供するものではありません。

この文書では、CloudflareのCFSSLを利用して自己署名の認証局を作成し、すべてのサービスで使えるワイルドカード証明書を作成するProof of Conceptスクリプトを以下に示します。

このスクリプトは

  • CA 鍵ペアを生成します。
  • すべてのGitLabコンポーネントサービスのエンドポイントをサービスするための証明書に署名します。
  • 2つのKubernetes Secretオブジェクトを作成します:
    • サーバ証明書とキーペアを持つkuberetes.io/tls 型のシークレット。
    • NGINX Ingressが必要とするca.crt 、CAの公開証明書のみを含むOpaque 型のシークレット。

前提条件:

  • Bash、または互換性のあるシェル。
  • 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の秘密鍵を保持_しません_。このスクリプトは概念実証用のヘルパーであり、本番環境での使用を_意図した_ものではありません。

このスクリプトは、2つの環境変数が設定されていることを想定しています:

  1. NAMESPACE:後で GitLab をインストールする Kubernetes Namespace。デフォルトはkubectl と同じくdefaultです。
  2. RELEASE:後にGitLabをインストールする際に使用するHelmリリース名。デフォルトはgitlabです。

このスクリプトをオペレーションするには、export この二つの変数を指定するか、スクリプト名の前にその値を指定します。

export NAMESPACE=testing
export RELEASE=gitlab

./poc-gitlab-internal-tls.sh

スクリプトが実行されると、2つのシークレットが作成され、一時作業ディレクトリにすべての証明書とその鍵が格納されます。

$ 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名を介して互いに話します。GitLabのChartによって生成されたIngressオブジェクトは、tls.verify: true (これはデフォルトです)、検証する名前をNGINXに提供しなければなりません。この結果、各GitLabコンポーネントは、そのサービス名、またはKubernetesサービスのDNSエントリに受け入れられるワイルドカードのいずれかを含むSANで証明書を受け取る必要があります。

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

証明書内のこれらのSANを確保しないと_、_インスタンスが機能しなくなり、”connection failure “や “SSL verification failed “といった不可解なログが出力されます。

必要であれば、helm template を使ってすべてのサービスオブジェクト名の完全なリストを取得することができます。GitLabがTLSなしでデプロイされている場合は、Kubernetesにそれらの名前をクエリできます:

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

設定

設定例はexamples/internal-tls にあります。

このドキュメントの目的のために、内部用の証明書を生成する際に、上記のスクリプトで生成された証明書を消費するようにGitLabコンポーネントを設定するshared-cert-values.yaml

設定する主な項目です:

  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を提供するように設定されると、NGINX Ingressから各GitLabコンポーネントへの接続を含め、GitLabコンポーネント間のすべての通信がTLSセキュリティでネットワークを通過するようになります。

NGINX Ingressは_インバウンドの_TLSを終了し、トラフィックを渡す適切なサービスを決定し、GitLabコンポーネントへの新しいTLS接続を形成します。このように設定すると、GitLabコンポーネントが提供する証明書をCAに対して_検証_します。

これは、Toolboxポッドに接続し、様々なコンテンツサービスにクエリすることで確認できます。そのような例として、NGINX Ingressが使用するWebserviceポッドのプライマリサービスポートに接続します:

$ 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.verifyfalseに設定することで、この問題を回避することができます。

NGINX Ingress コントローラは接続可能で、証明書の検証に関する問題がnginx.conf に表示されます。

シークレットに到達できないコンテンツ例:

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

これを引き起こす一般的な問題

  • CA証明書がシークレット内のca.crt という名前の鍵に含まれていない場合。
  • シークレットが適切に提供されていないか、ネームスペース内に存在しない可能性があります。