8.4 SSL
pg_auto_failover의 모든 연결은 PostgreSQL 프로토콜을 사용합니다. 따라서 암호화에도 PostgreSQL의 SSL 기능을 그대로 사용합니다. pg_autoctl create 명령의 SSL 관련 옵션은 세 부류입니다. 인증서를 자동으로 생성하는 --ssl-self-signed, 자체 CA 인증서를 지정하는 --ssl-ca-file과 --server-cert, 암호화를 끄는 --no-ssl입니다. 어떤 옵션을 선택하든 인증 방식은 8.3에서 별도로 정해야 합니다.
옵션과 기본 sslmode
| 옵션 | 서버 쪽 | 연결 문자열 기본 sslmode |
|---|---|---|
--ssl-self-signed | openssl req -new -x509 -days 365로 인증서 생성, CN은 --hostname | require |
--ssl-ca-file, --server-cert, --server-key (+--ssl-crl-file) | 주어진 파일을 ssl_*_file로 설정 | verify-full |
--no-ssl | SSL 끔 | prefer (v2.2 문서는 allow라고 설명) |
--ssl-mode를 지정하면 pg_autoctl이 생성하는 연결 문자열(monitor URI, primary_conninfo)의 sslmode가 해당 값으로 바뀝니다. 다만 예외가 있습니다. monitor가 데이터 노드에 여는 health check 연결은 sslmode, sslrootcert, sslcrl 없이 별도로 하드코딩되어 있습니다(health_check_worker.c). verify-full을 설정해도 이 연결은 CA와 호스트명을 검증하지 않습니다. 기존 host HBA를 그대로 두면 비SSL로도 연결할 수 있습니다.
self-signed는 도청만 막는다
실습에서는 --ssl-self-signed를 사용했습니다. 생성 직후 keeper가 다음과 같이 경고합니다.
INFO Using default --ssl-mode "require"
INFO Using --ssl-self-signed: pg_autoctl will create self-signed certificates, allowing for encrypted network traffic
WARN Self-signed certificates provide protection against eavesdropping; this setup does NOT protect against Man-In-The-Middle attacks nor Impersonation attacks.
sslmode=require는 암호화만 요구하며 서버 인증서를 검증하지 않습니다. 네트워크 경로에 개입한 공격자가 자신의 인증서를 제시해도 연결이 성립합니다. 실습 로그에 기록된 openssl 명령을 보면 인증서 유효기간은 365일입니다. 이 문서에서는 만료 후 동작과 갱신 절차를 실측하지 않았습니다.
자체 CA와 verify-full
보안 문서의 예시는 모든 노드에 동일한 CA 파일과 노드별 서버 인증서를 지정합니다.
pg_autoctl create monitor --ssl-ca-file root.crt --ssl-crl-file root.crl \
--server-cert server.crt --server-key server.key --ssl-mode verify-full ...
pg_autoctl create postgres --ssl-ca-file root.crt \
--server-cert server.crt --server-key server.key --ssl-mode verify-full ...
CA 파일과 CRL은 pg_autoctl 연결 문자열에서 sslrootcert, sslcrl로 사용됩니다. verify-full은 인증서의 호스트명도 확인합니다. 따라서 인증서의 CN이나 SAN이 --hostname으로 등록한 이름과 일치해야 합니다.
인증서 인증
비밀번호 대신 클라이언트 인증서로 인증할 수도 있습니다. pg_autoctl을 실행하는 시스템 사용자(postgres)의 ~/.postgresql/postgresql.crt와 postgresql.key에 클라이언트 인증서를 저장합니다. 인증서의 CN은 postgres입니다. 그러나 접속할 DB 사용자는 autoctl_node나 pgautofailover_replicator이므로, pg_ident.conf 맵으로 서로 연결합니다.
# monitor의 pg_ident.conf
pgautofailover postgres autoctl_node
# 데이터 노드의 pg_ident.conf
pgautofailover postgres pgautofailover_replicator
# monitor의 pg_hba.conf
hostssl pg_auto_failover autoctl_node 10.0.0.0/8 cert map=pgautofailover
# 데이터 노드의 pg_hba.conf
hostssl replication pgautofailover_replicator 10.0.0.0/8 cert map=pgautofailover
문서는 이 구성에서 --skip-pg-hba로 HBA를 직접 관리하도록 권장합니다. 위 CIDR은 문서의 예시 값입니다. 데이터 노드에는 문서가 예시로 제시한 replication 규칙 한 줄만으로는 부족합니다. monitor health check용 pgautofailover_monitor 규칙도 필요합니다. replicator의 --dbname 접속 규칙(replication slot 확인에 사용)과 postgres DB 접속 규칙(pg_rewind에 사용)도 추가해야 합니다. 그래야 초기화와 재합류가 실패하지 않습니다.
기존 구성에 SSL 켜기
--no-ssl로 시작한 구성은 pg_autoctl enable ssl로 변경할 수 있습니다. monitor부터 시작해 모든 노드에서 실행합니다.
pg_autoctl enable ssl --ssl-self-signed --ssl-mode require
pg_autoctl config get pg_autoctl.monitor # monitor URI의 sslmode 확인
enable ssl은 postgresql-auto-failover.conf와 pg_autoctl 설정을 변경하지만 HBA 파일은 수정하지 않습니다. 기존 host 규칙은 SSL과 비SSL 연결을 모두 허용합니다. 따라서 동작은 계속되지만 평문 연결도 여전히 허용합니다. 암호화를 강제하려면 pg_auto_failover 규칙을 host에서 hostssl로 직접 바꿔야 합니다. 문서는 실행 중인 데몬이 설정 reload에 실패할 수 있다고 경고합니다. 로그에서 reload 결과를 확인하고 필요하면 재시작합니다.
정리
--ssl-self-signed는 설치가 간편하지만 도청만 막을 뿐 서버 위장은 막지 못합니다. 운영 환경에서는 자체 CA 인증서와 verify-full을 사용합니다. 인증서의 호스트명은 --hostname과 일치시킵니다. 기존 구성에 SSL을 켠 뒤에는 HBA 규칙을 hostssl로 바꾸는 단계를 빠뜨리지 않아야 합니다.