Mutual TLS (mTLS)

개요

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/internal
const 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

보안 고려사항

관련 헤더

X-Client-CertX-SSL-Client-VerifyX-Forwarded-Client-Cert

관련 상태코드