TLS / 인증서 만료
증상
'certificate has expired', 'SSL handshake failed', 클라이언트가 갑자기 연결할 수 없다(코드 변경 없음).
1. 어디서 끊기는가: 서버, 클라이언트, CA?
만료된 것이 서버 인증서인가, 클라이언트 인증서인가, 체인의 CA인가? 증상은 대개 '어제는 됐는데 오늘은 안 되고, 코드는 바뀌지 않았다'이다.
2. 만료일을 확인한다
서버에서 인증서 만료일을 직접 읽는다(데이터베이스와 무관한 빠른 방법).
PostgreSQL
openssl s_client -connect host:5432 -starttls postgres </dev/null 2>/dev/null | openssl x509 -noout -datesMongoDB
openssl s_client -connect host:27017 </dev/null 2>/dev/null | openssl x509 -noout -enddateRedis
openssl s_client -connect host:6379 </dev/null 2>/dev/null | openssl x509 -noout -enddate3. 새 인증서를 설치하고 로드한다
인증서를 교체하고, 대부분의 경우 서비스를 재시작하지 않고 reload한다.
PostgreSQL
-- Renew ssl_cert_file/ssl_key_file, then:
SELECT pg_reload_conf();MySQL
ALTER INSTANCE RELOAD TLS;SQL Server
-- SQL Server Configuration Manager > Certificate; a service restart is requiredMongoDB
// Renew the net.tls.certificateKeyFile file (at the same path), then load it without a restart (5.0+):
db.adminCommand({rotateCertificates: 1})Redis
CONFIG SET tls-cert-file /path/new.crt
CONFIG SET tls-key-file /path/new.keyElasticsearch
# ES watches the certificate/key files (PEM, PKCS#12) defined under xpack.security.*.ssl and
# reloads them automatically when the file at the SAME path changes (no restart needed).
# If the path, file name or keystore password changes, a rolling restart is required.
# Note: POST _nodes/reload_secure_settings is only for reloadable keystore settings, not for TLS certificates.
# Verify: check the new expiry date with openssl s_client and look in the ES logs for
# an entry showing the certificate was reloaded.4. 검증한다
위의 openssl 명령으로 새 인증서로 TLS handshake가 성공하고 만료일이 연장되었는지 확인한다. 클라이언트로 end-to-end 연결한다.
5. 영구 조치: 다시는 없도록
인증서 만료 30일 전에 알림을 설정하고, 자동 갱신(ACME/Let's Encrypt, HashiCorp Vault, cert-manager)을 사용한다. 갱신 후 reload를 자동화한다.