GitLab 차트 컴포넌트간의 TLS 사용
GitLab 차트는 다양한 컴포넌트 간에 전송 계층 보안(TLS)을 사용할 수 있습니다. 이를 위해서는 서비스에 대한 인증서를 제공하고, 해당 서비스를 그 인증서 및 인증서를 서명한 인증 기관(CA)을 사용하도록 구성해야 합니다.
준비사항
각 차트에는 해당 서비스를 위한 TLS를 활성화하고 적절한 구성을 보장하기 위한 설명서가 있습니다.
내부 사용을 위한 인증서 생성
본 설명서의 목적을 위해, Cloudflare’s CFSSL을 사용하는 Concept Proof 스크립트를 아래에 제공합니다. 이 스크립트를 사용하여 자체 서명된 인증 기관 및 모든 서비스에 사용할 수 있는 와일드카드 인증서를 생성합니다.
이 스크립트는 다음을 수행합니다.
- CA 키 쌍 생성
- GitLab 컴포넌트 서비스 엔드포인트에 사용될 인증서 서명
- 두 개의 쿠버네티스 시크릿 객체 생성
- 서버 인증서 및 키 페어를 포함하는
kubernetes.io/tls
유형의 시크릿 - NGINX Ingress에서 필요한
ca.crt
로서 public CA 인증서만을 포함하는Opaque
유형의 시크릿
- 서버 인증서 및 키 페어를 포함하는
필수 요구 사항:
- Bash 또는 호환 가능한 쉘
-
cfssl
이 쉘에서 사용 가능하고PATH
내에 있는지 확인 -
kubectl
이 사용 가능하고, 나중에 GitLab을 설치할 쿠버네티스 클러스터를 가리키도록 구성- 스크립트를 실행하기 전에 인증서를 설치할 원하는 네임스페이스를 만들었는지 확인하세요.
이 스크립트의 콘텐츠를 복사하여 컴퓨터에 저장하고, 결과 파일을 실행 가능하도록 만드는 것을 권장합니다. poc-gitlab-internal-tls.sh
로 저장하는 것을 제안합니다.
#!/bin/bash
set -e
#############
## 작업 디렉터리 만들고 이동
pushd $(mktemp -d)
#############
## 환경 설정
NAMESPACE=${NAMESPACE:-default}
RELEASE=${RELEASE:-gitlab}
## 이후의 변수가 설정되지 않으면 스크립트 중단
set -u
## SAN(SANitized)의 알려진 기대 패턴
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
#############
## 쿠버네티스에 인증서 로드
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
스크립트는 두 개의 환경 변수가 설정되어 있어야 합니다.
-
NAMESPACE
: 나중에 GitLab을 설치할 Kubernetes 네임스페이스. 기본값은kubectl
과 같이default
입니다. -
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 객체는 NGINX가 tls.verify: true
으로 설정될 때, 트래픽을 전달해야 하는 이름을 NGINX에 제공합니다. 따라서 각 GitLab 컴포넌트는 서비스의 이름 또는 Kubernetes 서비스 DNS 항목에서 허용되는 와일드카드를 포함하는 SAN을 갖는 인증서를 받아야 합니다.
service-name.namespace.svc
*.namespace.svc
인증서 내에서 이러한 SAN을 보장하지 않으면 기능하지 않는 인스턴스 및 “연결 실패” 또는 “SSL 검증 실패”와 같이 굉장히 난해한 로그가 나타납니다.
필요하다면, 모든 서비스 객체 이름의 전체 디렉터리을 가져오기 위해 helm template
을 사용할 수 있습니다. TLS 없이 GitLab을 배포한 경우, 해당 이름들을 조회할 수 있습니다.
kubectl -n ${NAMESPACE} get service -lrelease=${RELEASE}
구성
예제 구성은 examples/internal-tls에서 찾을 수 있습니다.
본 설명서의 목적을 위해, shared-cert-values.yaml
을 제공합니다. 이 파일은 내부 사용을 위한 인증서 생성에서 생성된 인증서를 사용하도록 GitLab 컴포넌트를 구성합니다.
구성할 중요 사항:
- 전역 사용자 정의 인증 기관.
- 서비스 리스너에 대한 각 컴포넌트 별 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 컴포넌트로부터의 연결에서 수신 TLS를 해제하고, 트래픽을 전달하고, 그런 다음 GitLab 컴포넌트로의 새로운 TLS 연결을 형성합니다. 여기에서 보여진대로 구성할 경우, NGINX Ingress는 또한 GitLab 컴포넌트로부터 제공되는 인증서를 _검증_합니다.
Toolbox pod에 연결하여 다양한 컴포넌트 서비스에 쿼리를 보내어 이를 확인할 수 있습니다. 여기에는 Webservice pod의 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"
출력은 다음과 같아야 합니다.
* 10.60.0.237:8181로 시도 중...
* 10.60.0.237의 gitlab-webservice-default.testing.svc에 연결되었습니다 (10.60.0.237) port 8181 (#0)
* ALPN, h2를 제공함
* ALPN, http/1.1을 제공함
* 인증서 확인 위치를 성공적으로 설정하였습니다:
* CA file: /etc/ssl/certs/ca-certificates.crt
* CA path: /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 verify (15):
* TLSv1.3 (IN), TLS 핸드셰이크, Finished (20):
* TLSv1.3 (OUT), TLS 암호 변경, Change cipher spec (1):
* TLSv1.3 (OUT), TLS 핸드셰이크, Finished (20):
* TLSv1.3를 사용하는 SSL 연결 / TLS_AES_128_GCM_SHA256
* ALPN, 서버가 프로토콜에 동의하지 않음
* 서버 인증서:
* subject: CN=gitlab.testing.internal
* 시작일: Jul 18 19:15:00 2022 GMT
* 만료일: Jul 18 19:15:00 2023 GMT
* subjectAltName: "*.testing.svc"에 매치되는 인증서의 "gitlab-webservice-default.testing.svc" 호스트
* 발행자: 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.verify
를 false
로 설정함으로써 이 문제를 해결할 수 있습니다.
NGINX Ingress 컨트롤러에 연결할 수 있으며, nginx.conf
에서 인증서 확인에 관련된 메시지가 나타납니다.
다음은 Secret에 접근할 수 없는 경우의 예시 내용입니다:
# 위치 거부됨. 이유: "인증서 획득 오류: 로컬 SSL 인증서 testing/gitlab-internal-tls-ca를 찾을 수 없음"
return 503;
이로 인해 발생할 수 있는 일반적인 문제들:
- CA 인증서가 Secret 내의
ca.crt
이라는 키에 없는 경우 - Secret이 제대로 제공되지 않았거나 네임스페이스 내에 존재하지 않을 수 있음