GitLab 차트 구성 요소 간 TLS 사용

GitLab 차트는 각 구성 요소 사이에 전송 계층 보안(TLS)을 사용할 수 있습니다. 이를 위해서는 사용하려는 서비스에 대한 인증서를 제공하고 해당 서비스가 이러한 인증서 및 인증 기관(CA)를 활용하도록 구성해야 합니다.

준비 작업

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

내부 용도로 인증서 생성

참고: GitLab은 고급 PKI 기반 또는 인증 기관을 제공하지 않습니다.

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

이 스크립트는 다음과 같은 작업을 수행합니다.

  • CA 키 페어 생성
  • GitLab 구성 요소 서비스 엔드포인트에 대한 인증서 서명
  • 두 개의 Kubernetes Secret 객체 생성:
    • 서버 인증서 및 키 페어가 포함된 kuberetes.io/tls 유형의 비밀
    • NGINX Ingress가 필요로 하는 CA의 공개 인증서인 ca.crt만을 포함하는 Opaque 유형의 비밀

사전 요구 사항:

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

이 스크립트 내용을 컴퓨터로 복사하고 결과 파일을 실행 가능하도록 만드십시오. poc-gitlab-internal-tls.sh를 권장합니다.

#!/bin/bash
set -e
#############
## 작업 디렉토리를 만들고 변경합니다
pushd $(mktemp -d)

#############
## 환경 설정
NAMESPACE=${NAMESPACE:-default}
RELEASE=${RELEASE:-gitlab}
## 이후 변수가 해제되지 않은 경우 중지
set -u
## SA에 대한 알려진 예상 패턴
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

#############
## 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

참고: 이 스크립트는 CA의 개인 키를 보호하지 않습니다. 이것은 개념 증명 보조 도구로, 실제 운영에는 사용하지 않아야 합니다.

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

  1. NAMESPACE: 나중에 GitLab을 설치할 Kubernetes 네임스페이스입니다. 이것은 kubectl과 동일하게 기본값은 default입니다.
  2. RELEASE: 나중에 GitLab을 설치할 때 사용할 Helm 릴리스 이름입니다. 이것은 gitlab과 동일하게 기본값은 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 및 SAN

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

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

이러한 SAN을 인증서에 보장하지 않으면 동작하지 않는 인스턴스가 발생하고 “연결 실패” 또는 “SSL 확인 실패”와 관련된 암호화된 로그가 나타날 수 있습니다.

모든 Service 객체 이름의 전체 목록을 검색하려면 helm template를 활용할 수 있습니다. TLS 없이 GitLab을 배포한 경우 Kubernetes에 해당 이름들을 조회할 수 있습니다.

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

구성

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

이 설명서의 목적을 위해, 우리는 shared-cert-values.yaml를 제공했습니다. 위의 스크립트로 생성된 인증서를 소비하도록 GitLab 구성 요소를 구성하는 것입니다. 내부 사용을 위해 인증서를 생성하는](#generating-certificates-for-internal-use) 것입니다.

구성할 중요한 항목:

  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 구성 요소 간의 모든 통신은 NGINX Ingress에서 각 GitLab 구성 요소로의 연결을 포함하여 TLS 보안을 통해 네트워크를 통해 이동합니다.

NGINX Ingress는 입방향 TLS를 종료하고 트래픽을 전달할 적절한 서비스를 결정한 후 GitLab 구성 요소로 새로운 TLS 연결을 형성합니다. 여기에 표시된대로 구성하면, GitLab 구성 요소가 제공하는 인증서도 검증합니다.

이것은 Toolbox 팟에 연결하여 확인할 수 있습니다. 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"

출력은 다음 예제와 유사해야 합니다:

*   10.60.0.237:8181에 연결하는 중...
* gitlab-webservice-default.testing.svc (10.60.0.237) 포트 8181에 연결되었습니다 (#0)
* ALPN, h2를 제공
* ALPN, http/1.1을 제공
* 인증서 확인 위치를 성공적으로 설정했습니다:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS 핸드쉐이크, 클라이언트 hello (1):
* TLSv1.3 (IN), TLS 핸드쉐이크, 서버 hello (2):
* TLSv1.3 (IN), TLS 핸드쉐이크, 암호화된 확장 (8):
* TLSv1.3 (IN), TLS 핸드쉐이크, 인증서 (11):
* TLSv1.3 (IN), TLS 핸드쉐이크, CERT 확인 (15):
* TLSv1.3 (IN), TLS 핸드쉐이크, 완료 (20):
* TLSv1.3 (OUT), TLS 변경 암호, 암호 변경 사양 (1):
* TLSv1.3 (OUT), TLS 핸드쉐이크, 완료 (20):
* TLSv1.3를 사용한 SSL 연결 / TLS_AES_128_GCM_SHA256
* ALPN, 서버가 프로토콜에 동의하지 않았습니다
* 서버 인증서:
*  주체: CN=gitlab.testing.internal
*  시작일: Jul 18 19:15:00 2022 GMT
*  만료일: Jul 18 19:15:00 2023 GMT
*  subjectAltName: 호스트 "gitlab-webservice-default.testing.svc" matchd cert's "*.testing.svc"
*  issuer: CN=gitlab.testing.internal.ca
*  SSL 인증서 확인 완료.
> 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의 메시지를 확인할 수 있습니다.

비교적 아래 예제에서 시크릿에 액세스할 수 없는 경우:

# 위치 거부됨. 이유: "error obtaining certificate: local SSL certificate
  testing/gitlab-internal-tls-ca was not found"
return 503;

이것을 일으키는 일반적인 문제:

  • CA 인증서가 시크릿 내의 ca.crt라는 키에 없음.
  • 시크릿이 제대로 제공되지 않았거나 네임스페이스 내에 존재하지 않을 수 있습니다.