본문으로 건너뛰기

9.5 SSL/TLS와 SCRAM

운영 클러스터의 네트워크 보안은 전송 암호화(SSL/TLS)와 비밀번호 해시 방식(SCRAM-SHA-256) 두 축으로 이뤄집니다. 둘은 독립적으로 동작하지만 함께 켜야 접속이 안전해집니다.

SCRAM-SHA-256

PostgreSQL의 비밀번호 인증은 두 가지가 표준이었습니다.

방식보안
md5 (PG 9.6 이전)MD5 challenge-response. 평문 노출은 안 되지만 rainbow table 위험
scram-sha-256 (PG 10+)SCRAM-SHA-256. 비밀번호를 서버가 저장 시점부터 모름

SCRAM의 핵심:

  • 서버는 비밀번호 자체가 아니라 salted hash만 저장
  • 인증 시 challenge-response — 비밀번호가 네트워크에 흐르지 않음
  • 평문·MD5보다 강력

pg_authid.rolpassword를 보면 시작 문자열로 어느 방식인지 압니다.

SELECT rolname, LEFT(rolpassword, 14) AS kind
  FROM pg_authid WHERE rolcanlogin;
-- kind = 'SCRAM-SHA-256' 또는 'md5...'

SCRAM으로 마이그레이션

ALTER SYSTEM SET password_encryption = 'scram-sha-256';
SELECT pg_reload_conf();

-- 각 사용자의 비밀번호를 다시 설정 (이때 SCRAM으로 저장됨)
ALTER ROLE alice PASSWORD 'new_secret';

password_encryption만 바꾸면 기존 비밀번호는 여전히 MD5로 남고, 새로 설정하는 비밀번호부터 SCRAM으로 저장됩니다. 모든 사용자가 갱신되면 pg_hba.confmd5scram-sha-256으로 교체합니다.

channel binding

SCRAM-SHA-256-PLUS는 SCRAM에 TLS 채널 바인딩을 결합해 TLS MITM 공격을 막습니다.

# pg_hba.conf
hostssl  app_main  all  10.0.0.0/8  scram-sha-256

PG 11+의 libpq는 channel_binding=require로 강제 가능합니다.

psql 'postgresql://user@host/db?sslmode=verify-full&channel_binding=require'

SSL/TLS

서버 측 — 인증서 생성

운영 환경에서는 PKI(사내 CA·Let’s Encrypt 등)를 씁니다. 개발용 자가 서명:

# 1. CA (조직의 root)
openssl req -new -x509 -days 3650 -nodes \
  -out ca.crt -keyout ca.key \
  -subj "/CN=My PG CA"

# 2. 서버 키·CSR
openssl req -new -nodes \
  -out server.csr -keyout server.key \
  -subj "/CN=db.example.com"

# 3. CA로 서버 인증서 서명
openssl x509 -req -in server.csr -days 365 \
  -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out server.crt

# 4. 파일 권한 (0600 — 안 그러면 PG가 거부)
chmod 0600 server.key
chown postgres:postgres server.{crt,key} ca.crt

PGDATA 안 또는 별도 디렉토리에 두고 postgresql.conf에서 경로 지정.

postgresql.conf

ssl = on
ssl_cert_file     = '/etc/postgresql/ssl/server.crt'
ssl_key_file      = '/etc/postgresql/ssl/server.key'
ssl_ca_file       = '/etc/postgresql/ssl/ca.crt'           # 클라이언트 인증서 검증 시
ssl_min_protocol_version = 'TLSv1.2'                        # 또는 TLSv1.3
ssl_ciphers       = 'HIGH:!aNULL:!MD5:!RC4'                 # 안전한 cipher만

reload 또는 restart 후:

SHOW ssl;          -- on

클라이언트 측 — verify-full

psql 'postgresql://app@db.example.com/app?sslmode=verify-full&sslrootcert=/etc/ssl/ca.crt'

sslmode 단계:

의미
disable평문 (절대 금지)
prefer (기본)가능하면 SSL, 안 되면 평문
requireSSL 강제, 인증서 검증 안 함
verify-caCA 검증
verify-fullCA + 호스트명 검증. 표준

verify-full이 운영 표준입니다. 자가 서명 CA의 경우 sslrootcert에 CA 인증서 경로 지정.

클라이언트 인증서 (mutual TLS)

비밀번호 대신 클라이언트 인증서로 인증.

# 클라이언트 인증서 발급 (CN = DB 사용자명)
openssl req -new -nodes -out alice.csr -keyout alice.key \
  -subj "/CN=alice"
openssl x509 -req -in alice.csr -days 365 \
  -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out alice.crt

서버 pg_hba.conf:

hostssl  all  all  10.0.0.0/8  cert  clientcert=verify-full

클라이언트 접속:

psql 'postgresql://alice@db.example.com/app?sslmode=verify-full&sslcert=/etc/ssl/alice.crt&sslkey=/etc/ssl/alice.key&sslrootcert=/etc/ssl/ca.crt'

pg_hba.confcert 메서드는 클라이언트 인증서의 CN이 user 컬럼과 일치해야 통과.

인증서 갱신 — pg_reload_conf()

PG 13+에서 SSL 설정 reload 시 기존 연결은 옛 인증서 유지, 새 연결은 새 인증서 사용합니다. 무중단 갱신 가능합니다.

# 인증서 파일 교체
sudo cp /tmp/new_server.crt /etc/postgresql/ssl/server.crt
sudo systemctl reload postgresql-17

# 새 연결로 검증
psql ... # 새 인증서로 접속됨

PG 12 이전은 restart 필요합니다.

TLS 정책 — postgresql.conf

파라미터권장
ssl_min_protocol_versionTLSv1.2 또는 TLSv1.3
ssl_max_protocol_version비워 둠 (최신)
ssl_prefer_server_cipherson
ssl_passphrase_command키가 암호화된 경우 — 자동화 어려움, 보통 평문 키 + 권한 0600

로깅 확인

SHOW ssl;
-- 현재 세션의 SSL 사용 여부
SELECT * FROM pg_stat_ssl WHERE pid = pg_backend_pid();
컬럼의미
ssltrue/false
versionTLSv1.2 / TLSv1.3
cipher사용된 cipher suite
client_dn클라이언트 인증서 DN (mutual TLS)

모니터링: pg_stat_ssl을 주기 점검해 평문 접속이 있는지 확인합니다.

-- 비-SSL 접속 추적
SELECT count(*) FROM pg_stat_ssl WHERE ssl IS NOT true;

안티패턴

안티패턴위험
ssl = off (운영)평문 전송
sslmode = require만 (인증서 검증 안 함)MITM 가능
자가 서명 인증서를 신뢰 chain 없이 클라이언트 배포검증 우회
MD5 비밀번호 유지rainbow table 위험
인증서 만료 알람 없음어느 날 모든 클라이언트 접속 실패
인증서 만료 모니터링 필수. 운영 사고 중 흔한 사례 — 인증서 1년 만료가 지나 어느 날 새벽에 모든 클라이언트가 접속 실패. Let’s Encrypt 같은 자동 갱신 또는 Vault·cert-manager 통합 권장합니다.

정리

SCRAM-SHA-256은 오늘날 비밀번호 인증의 표준이므로 PG 10 이상에서는 이 방식을 씁니다. md5에서 넘어올 때는 password_encryption을 바꾼 뒤 각 사용자의 비밀번호를 다시 설정합니다. 전송 구간은 서버 인증서와 클라이언트 sslmode=verify-full로 보호하고, 비밀번호 대신 인증서로 인증하려면 cert 메서드에 클라이언트 인증서를 씁니다.

  • PG 13+는 SSL reload로 인증서 무중단 갱신
  • pg_stat_ssl로 접속 보안 상태 점검
  • 인증서 만료 알람·자동 갱신은 필수