8.3 클라이언트 TLS/SSL 접속
앞 절에서 본 client CA를 이용하면, 클라이언트는 비밀번호 대신 TLS client certificate로 데이터베이스에 인증할 수 있습니다. 비밀번호가 오가지 않으므로 유출 위험이 줄어듭니다. 아래에서는 인증서 발급, psql 검증, 애플리케이션 Pod 마운트를 차례로 따라갑니다.
인증 흐름
1. client 인증서 발급
kubectl cnpg 플러그인으로 특정 사용자용 client 인증서를 발급합니다. Cluster의 client CA가 서명하며, 결과는 지정한 이름의 Secret으로 만들어집니다.
kubectl cnpg certificate cluster-app \
--cnpg-cluster cluster-example \
--cnpg-user app
발급된 인증서의 common name은 PostgreSQL 사용자명(app)과 같아야 합니다. cert 인증은 인증서 CN을 데이터베이스 롤로 매핑하기 때문입니다. 인증서 내용은 다음으로 확인합니다.
kubectl get secret cluster-app \
-o jsonpath="{.data['tls\.crt']}" \
| base64 -d | openssl x509 -text -noout | head -n 11
기본 유효기간은 90일이며 CERTIFICATE_DURATION·EXPIRING_CHECK_THRESHOLD로 조정합니다.
2. psql로 접속 검증
클라이언트는 세 개의 파일이 필요합니다.
| 파라미터 | 파일 | 역할 |
|---|---|---|
sslcert | tls.crt | client 공개 인증서 |
sslkey | tls.key | client 개인 키 |
sslrootcert | ca.crt | 서버 검증용 CA |
인증서를 마운트한 Pod 안에서 다음처럼 접속합니다. sslmode=verify-full은 서버 인증서와 호스트명까지 검증하는 가장 엄격한 모드입니다.
kubectl exec -it cert-test -- bash -c \
"psql 'sslkey=/etc/secrets/app/tls.key \
sslcert=/etc/secrets/app/tls.crt \
sslrootcert=/etc/secrets/ca/ca.crt \
host=cluster-example-rw.default.svc \
dbname=app user=app sslmode=verify-full' \
-c 'select version();'"
sslmode는 검증 강도를 정합니다. require는 암호화만 하고 서버 신원은 확인하지 않으며, verify-ca는 CA를, verify-full은 CA와 호스트명까지 확인합니다. 프로덕션에서는 verify-full을 기본으로 삼습니다.
3. 애플리케이션 Pod에 인증서 마운트
애플리케이션에서는 CA Secret과 client 인증서 Secret을 볼륨으로 마운트하고, 접속 문자열을 환경 변수로 넣습니다. 아래는 CloudNativePG 문서의 cert-test 예제를 간추린 형태입니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: cert-test
spec:
replicas: 1
selector:
matchLabels:
app: cert-test
template:
metadata:
labels:
app: cert-test
spec:
containers:
- name: cert-test
image: ghcr.io/cloudnative-pg/webtest:1.6.0
env:
- name: DATABASE_URL
value: >-
sslkey=/etc/secrets/app/tls.key
sslcert=/etc/secrets/app/tls.crt
sslrootcert=/etc/secrets/ca/ca.crt
host=cluster-example-rw.default.svc
dbname=app user=app sslmode=verify-full
volumeMounts:
- name: app-cert
mountPath: /etc/secrets/app
- name: ca-cert
mountPath: /etc/secrets/ca
volumes:
- name: app-cert
secret:
secretName: cluster-app
- name: ca-cert
secret:
secretName: cluster-example-ca
client 인증서 Secret(cluster-app)에는 tls.crt·tls.key가, CA Secret(cluster-example-ca)에는 ca.crt가 들어 있어, 위 마운트 경로가 그대로 psql 파라미터와 맞물립니다.
TLS 프로토콜 버전
CloudNativePG는 최소·최대 TLS 버전 모두 기본 TLSv1.3을 씁니다. 구형 클라이언트 라이브러리가 1.3을 지원하지 않으면 접속이 실패할 수 있으므로, 접속 오류가 나면 클라이언트의 TLS 지원 버전을 먼저 확인합니다.
정리
kubectl cnpg certificate는 사용자별 client 인증서를 Secret으로 발급합니다. 인증서의 CN이 곧 PostgreSQL 사용자명이며, cert 인증이 이 CN을 롤로 매핑합니다.
- 클라이언트는
sslcert·sslkey·sslrootcert세 파일로 접속하고, 프로덕션에서는sslmode=verify-full을 기본으로 삼습니다. - 애플리케이션은 CA·client Secret을 볼륨으로 마운트한 뒤 접속 문자열을 주입합니다.
기본 TLS 버전이 1.3이므로, 접속이 안 되면 구형 클라이언트의 TLS 지원 버전부터 확인합니다.