GitLab 차트 간 구성 요소 간 TLS 사용

GitLab 차트는 다양한 구성 요소 간에 전송 계층 보안(TLS)을 사용할 수 있습니다.

이를 통해 보안 인증서를 제공해야 하며, 해당 서비스가 이러한 인증서와 이를 서명한 인증 기관(CA)을 사용하도록 구성해야 합니다.

준비

각 차트는 해당 서비스에 대한 TLS 활성화 및 적절한 구성을 보장하기 위해 필요한 다양한 설정에 관한 문서를 가지고 있습니다.

내부 사용을 위한 인증서 생성

note
GitLab은 고급 PKI 인프라 또는 인증 기관을 제공한다고 주장하지 않습니다.

이 문서의 목적을 위해, 아래에 Proof of Concept 스크립트를 제공하며, 이는 Cloudflare의 CFSSL을 사용하여 자체 서명된 인증 기관과 모든 서비스에 사용할 수 있는 와일드카드 인증서를 생성합니다.

이 스크립트는 다음을 수행합니다:

  • CA 키 쌍을 생성합니다.
  • 모든 GitLab 구성 요소 서비스 엔드포인트에 서비스를 제공하기 위한 인증서를 서명합니다.
  • 두 개의 Kubernetes 비밀 객체를 생성합니다:
    • 서버 인증서와 키 쌍이 있는 kubernetes.io/tls 유형의 비밀입니다.
    • NGINX Ingress에서 필요로 하는 CA의 공개 인증서만 포함된 Opaque 유형의 비밀로 ca.crt입니다.

사전 요구 사항:

  • Bash 또는 호환 셸.
  • cfssl이 셸에서 사용 가능하고 PATH에 포함되어 있습니다.
  • kubectl이 사용 가능하며 나중에 GitLab이 설치될 Kubernetes 클러스터를 가리키도록 구성되어 있습니다.
    • 이 스크립트를 실행하기 전에 이러한 인증서를 설치할 네임스페이스를 생성했는지 확인하세요.

이 스크립트의 내용을 복사하여 귀하의 컴퓨터에 저장하고 결과 파일을 실행 가능하게 만들 수 있습니다. poc-gitlab-internal-tls.sh를 제안합니다.

#!/bin/bash
set -e
#############
## 작업 디렉토리 생성 및 이동
pushd $(mktemp -d)

#############
## 환경 설정
NAMESPACE=${NAMESPACE:-default}
RELEASE=${RELEASE:-gitlab}
## 이 시점 이후 변수에 값이 없으면 중단
set -u
## SAN에 대한 예상 패턴
CERT_SANS="*.${NAMESPACE}.svc,${RELEASE}-metrics.${NAMESPACE}.svc,*.${RELEASE}-gitaly.${NAMESPACE}.svc"

#############
## 기본 CA 구성 생성
cfssl print-defaults config > ca-config.json
## CA 생성
echo '{"CN":"'${RELEASE}.${NAMESPACE}.internal.ca'","key":{"algo":"ecdsa","size":256}}' | \
  cfssl gencert -initca - | \
  cfssljson -bare ca -
## 인증서 생성
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

#############
## Kubernetes에 인증서 로드
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의 개인 키를 유지하지 않습니다. 이것은 Proof-of-Concept 도우미이며, _프로덕션 사용_을 위한 것이 아닙니다.

이 스크립트는 두 개의 환경 변수 설정을 기대합니다:

  1. NAMESPACE: 나중에 GitLab을 설치할 Kubernetes 네임스페이스. 기본값은 default입니다.
  2. RELEASE: 나중에 GitLab을 설치하는 데 사용할 Helm 리리스 이름. 기본값은 gitlab입니다.

이 스크립트를 실행하려면 두 변수를 export하거나 스크립트 이름 앞에 값을 추가할 수 있습니다.

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 및 SANs

다양한 GitLab 구성 요소들이 각자의 서비스 DNS 이름을 통해 서로 통신합니다.

GitLab 차트에서 생성된 Ingress 객체는 tls.verify: true (기본값)일 때 확인할 이름을 NGINX에 제공해야 합니다. 따라서 각 GitLab 구성 요소는 자신의 서비스 이름이거나 Kubernetes 서비스 DNS 항목에 허용되는 와일드카드를 포함한 SAN이 있는 인증서를 받아야 합니다.

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

인증서 내 SAN을 보장하지 않을 경우 비기능적인 인스턴스가 발생하며, “연결 실패” 또는 “SSL 검증 실패”라는 다소 암호화된 로그가 출력됩니다.

필요한 경우, helm template를 사용하여 모든 서비스 객체 이름의 전체 목록을 검색할 수 있습니다. GitLab이 TLS 없이 배포된 경우 Kubernetes에 대해 이러한 이름을 쿼리할 수 있습니다:

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

구성

예제 구성은 examples/internal-tls에서 찾을 수 있습니다.

이 문서의 목적을 위해 shared-cert-values.yaml을 제공하였으며, 이는 위의 스크립트로 생성된 인증서를 사용하도록 GitLab 구성 요소를 구성합니다. 내부 사용을 위한 인증서 생성.

구성해야 할 주요 항목:

  1. 전역 사용자 지정 인증 기관.
  2. 서비스 리스너를 위한 구성 요소별 TLS. (각 차트의 문서를 참조하십시오, 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 # 기본값
          secretName: *internal-tls
          caSecretName: *internal-ca

결과

모든 구성 요소가 서비스 리스너에서 TLS를 제공하도록 구성되면, GitLab 구성 요소 간의 모든 통신은 TLS 보안으로 네트워크를 통과합니다. 여기에는 NGINX Ingress에서 각 GitLab 구성 요소로의 연결도 포함됩니다.

NGINX Ingress는 모든 수신 TLS를 종료하고, 트래픽을 전달할 적절한 서비스를 결정한 다음, GitLab 구성 요소에 대한 새 TLS 연결을 형성합니다. 여기와 같이 구성할 경우, GitLab 구성 요소가 제공하는 인증서를 CA에 대해 _검증_합니다.

이것은 Toolbox 포드에 연결하고 다양한 구성 요소 서비스에 대해 쿼리함으로써 검증할 수 있습니다. NGINX Ingress가 사용하는 웹 서비스 포드의 기본 서비스 포드에 연결하는 예는 다음과 같습니다:

$ 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 인그레스가 GitLab 구성 요소의 인증서를 확인하는 데 문제가 있을 가능성이 높습니다.

이 문제를 해결하기 위해 gitlab.webservice.workhorse.tls.verify를 일시적으로 false로 설정할 수 있습니다.

NGINX 인그레스 컨트롤러에 연결할 수 있으며, 인증서 확인 문제와 관련하여 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이 제대로 제공되지 않았거나, 네임스페이스 내에 존재하지 않음.