Mutual TLS(mTLS)는 일반 TLS가 서버만 인증서로 검증하던 것을 확장해, 클라이언트도 자신의 X.509 인증서를 제시하여 양방향으로 서로를 검증하는 방식입니다. 인증이 애플리케이션 계층이 아니라 전송 계층(TLS 핸드셰이크)에서 이뤄지며, 서비스 간 통신·제로 트러스트 네트워크·금융/IoT에서 강력한 신원 보증 수단으로 쓰입니다.
TLS client certificate (transport layer, presented during the TLS handshake)TLS 핸드셰이크 중 서버가 CertificateRequest를 보내면, 클라이언트는 자신의 인증서와 함께 CertificateVerify(개인키로 서명)를 제출해 '이 인증서의 주인이 나'임을 증명합니다. 서버는 그 인증서가 신뢰하는 CA로 서명됐는지, 만료·폐기(CRL/OCSP)되지 않았는지, Subject/SAN이 기대한 값인지 검증합니다. 비밀번호나 토큰을 주고받지 않고, 개인키 소지 증명만으로 인증이 끝납니다.
리버스 프록시(nginx, Envoy, API Gateway)가 mTLS를 종단(terminate)하는 구성이 흔합니다. 이때 프록시가 검증한 클라이언트 신원을 `X-Client-Cert`·`X-Forwarded-Client-Cert` 같은 헤더로 백엔드에 전달합니다. 인증서 오류·부재 시 nginx는 495/496 같은 상태로 거절합니다.
사람 로그인보다는 서비스-투-서비스(mesh 내부 통신), 디바이스 인증, 파트너 API 연동에 적합합니다. 강력하지만 인증서 발급·배포·갱신·폐기(PKI 라이프사이클) 운영 부담이 크다는 것이 현실적인 트레이드오프입니다.
TLS handshake: server requests CertificateRequest → client sends its X.509 certificate + CertificateVerify (proves possession of the private key)curl --cert client.crt --key client.key --cacert ca.crt \
https://api.example.com/internalconst https = require('https');
https.request({
host: 'api.example.com', port: 443, path: '/internal',
cert: fs.readFileSync('client.crt'),
key: fs.readFileSync('client.key'),
ca: fs.readFileSync('ca.crt')
}, res => { /* ... */ }).end();ssl_client_certificate /etc/nginx/ca.crt;
ssl_verify_client on; # require a valid client certificate
# reject with 495/496 on cert error/absence