본문으로 건너뛰기

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·EXPIRE_CHECK_THRESHOLD로 조정한다.

2. psql로 접속 검증

클라이언트는 세 개의 파일이 필요하다.

파라미터파일역할
sslcerttls.crtclient 공개 인증서
sslkeytls.keyclient 개인 키
sslrootcertca.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 지원 버전부터 확인한다.